【问题标题】:parallel pivot_longer of two sets of columns两组列的平行 pivot_longer
【发布时间】:2020-04-02 20:35:42
【问题描述】:

我有以下数据框:

library(tidyverse)
dat <- tribble(
  ~Scenario,     ~V1,    ~V2,    ~V3,    ~V4,
  1,    0.97,   0.46,   0.79,   0.25,
  1,    0.21,   0.45,   0.23,   0.63,
  1,    0.95,   0.97,   0.07,   0.61,
  1,    0.93,   0.79,   0.23,   0.86,
  2,    0.22,   0.01,   0.42,   0.47,
  2,    0.71,   0.17,   0.16,   0.88,
  3,    0.73,   0.38,   0.10,   0.77,
  3,    0.49,   0.37,   0.90,   0.52,
  3,    0.99,   0.71,   0.66,   0.05,
  3,    0.72,   0.75,   0.69,   0.01,
  3,    0.15,   0.87,   0.12,   0.02,
  4,    0.94,   0.30,   0.91,   0.99)

我正在向该数据添加四个新列,其中每个新列代表按 Scenario 分组的每个 V1:V4 列的总和:

dat_new <- dat %>%
  group_by(Scenario) %>%
  mutate_at(vars(-group_cols()), .funs = list(sum = sum))

现在我想将这些数据转换为长格式,其中一组是我的 V1:V4 列,第二组是我的 V1_sum:V4_sum 列。普通的pivot_longer 不起作用,因为它只接受一个值列,但是,我需要两个。

我在 tidyverse 参考资料(最底部的示例)中找到了一个潜在的解决方案,但我未能定义正确的 names_patternhttps://tidyr.tidyverse.org/reference/pivot_longer.html

有没有一种简单直接的方法(理想情况下是 tidyverse),我可以只做这两个 pivot_longer 集?感觉这是reshaping数据集时的基本任务之一,但是我无法让它工作。

预期输出:

Scenario    set    V    sum
1           1      0.97 3.06
1           2      0.46 2.67
1           3      0.79 1.32
1           4      0.25 2.35
...
4           4      0.99 0.99

注意:列名“set”、“V”和“sum”只是示例,如果是其他列名,我也可以更容易即时生成。

【问题讨论】:

    标签: r pivot reshape tidyr


    【解决方案1】:

    也许您应该在计算总和之前尝试旋转:

    dat %>% pivot_longer(., -Scenario, names_to = "V", values_to = "Value") %>% 
      group_by(Scenario, V) %>%
      mutate(Sum = sum(Value))
    
    
    # A tibble: 48 x 4
    # Groups:   Scenario, V [16]
       Scenario V     Value   Sum
          <dbl> <chr> <dbl> <dbl>
     1        1 V1     0.97  3.06
     2        1 V2     0.46  2.67
     3        1 V3     0.79  1.32
     4        1 V4     0.25  2.35
     5        1 V1     0.21  3.06
     6        1 V2     0.45  2.67
     7        1 V3     0.23  1.32
     8        1 V4     0.63  2.35
     9        1 V1     0.95  3.06
    10        1 V2     0.97  2.67
    # … with 38 more rows
    

    这是你要找的吗?

    【讨论】:

    • 哦,我的...是的,这是有道理的并且有效。但出于好奇。如果我没有我的原始数据并且只有我的四个 V 列和我的 4 个总和列的预计算版本,并且无法对原始数据应用 pivot_longer,该怎么办?
    • 其实,这是一个非常好的问题......到目前为止,我还没有答案。
    • 好的,我并不孤单。查看 tidyvese 参考资料,我唯一要做的就是将我的所有 V1:V4 列重命名为 x1:x4 并将我所有的总和列重命名为 y1:y4 并准确应用最后一个参考示例中的代码(链接在我的帖子中)。但这并不是很优雅。我想归结为找到正确的命名模式,但我失败了。
    【解决方案2】:

    我在 vignette("pivot") 的“每行多次观察”标题下找到了这个解决方案。

    每组变量都需要一个并行的命名结构,并且需要一个分隔符。

    在您的情况下(这不是很普遍),从 mutate_at 函数中出来,您将 _sum 附加到每个变量。但是你需要在前四个变量的下划线后面加上一些东西。我用标签_orig 重命名了您原来的四个变量,并且相当不雅地将总和变量的名称从V1_orig_sum 简化为V1_sum,以避免出现双下划线。

    dat <- tribble(
      ~Scenario,     ~V1_orig,    ~V2_orig,    ~V3_orig,    ~V4_orig,
      1,    0.97,   0.46,   0.79,   0.25,
      1,    0.21,   0.45,   0.23,   0.63,
      1,    0.95,   0.97,   0.07,   0.61,
      1,    0.93,   0.79,   0.23,   0.86,
      2,    0.22,   0.01,   0.42,   0.47,
      2,    0.71,   0.17,   0.16,   0.88,
      3,    0.73,   0.38,   0.10,   0.77,
      3,    0.49,   0.37,   0.90,   0.52,
      3,    0.99,   0.71,   0.66,   0.05,
      3,    0.72,   0.75,   0.69,   0.01,
      3,    0.15,   0.87,   0.12,   0.02,
      4,    0.94,   0.30,   0.91,   0.99)
    
    dat_new <- dat %>%
      group_by(Scenario) %>%
      mutate_at(vars(-group_cols()), .funs = list(sum = sum))%>%
      rename(V1_sum=V1_orig_sum, V2_sum=V2_orig_sum, V3_sum=V3_orig_sum, V4_sum=V4_orig_sum)
    

    所以这里dat_new看起来有两组,每组四个变量,变量名在_之前,描述符在之后:

    > head(dat_new)
    # A tibble: 6 x 9
    # Groups:   Scenario [2]
      Scenario V1_orig V2_orig V3_orig V4_orig V1_orig_sum V2_orig_sum V3_orig_sum V4_orig_sum
         <dbl>   <dbl>   <dbl>   <dbl>   <dbl>       <dbl>       <dbl>       <dbl>       <dbl>
    1        1    0.97    0.46    0.79    0.25        3.06        2.67        1.32        2.35
    2        1    0.21    0.45    0.23    0.63        3.06        2.67        1.32        2.35
    3        1    0.95    0.97    0.07    0.61        3.06        2.67        1.32        2.35
    4        1    0.93    0.79    0.23    0.86        3.06        2.67        1.32        2.35
    5        2    0.22    0.01    0.42    0.47        0.93        0.18        0.58        1.35
    6        2    0.71    0.17    0.16    0.88        0.93        0.18        0.58        1.35
    

    然后您调用pivot_longer,但在names_to 参数中给它两个 列名称:一个用于您调用这些对象的对象(在本例中为Var),并且".value" 表示应该有尽可能多的新列_ 分隔符后有唯一标签:

    dat_new %>% 
      pivot_longer(-Scenario, 
                   names_to = c("Var", ".value"), 
                   names_sep="_" )
    # A tibble: 48 x 4
    # Groups:   Scenario [4]
       Scenario Var    orig   sum
          <dbl> <chr> <dbl> <dbl>
     1        1 V1     0.97  3.06
     2        1 V2     0.46  2.67
     3        1 V3     0.79  1.32
     4        1 V4     0.25  2.35
     5        1 V1     0.21  3.06
     6        1 V2     0.45  2.67
     7        1 V3     0.23  1.32
     8        1 V4     0.63  2.35
     9        1 V1     0.95  3.06
    10        1 V2     0.97  2.67
    # ... with 38 more rows
    

    请注意,如果您使用反向命名系统设置了 8 个变量(即 orig_V1、sum_V1 等),您可以反转命名参数中的顺序:names_to=c(".value", "Var)。此解决方案不要求值是同一类型(即,这里的 orig 和 sum 都是数字,但一个可能是数字,一个是字符)。

    【讨论】:

    • 谢谢!是的,通过更结构化的列名,您可以使用 .value 和 names_sep。然而,在我的实际用例中,我转而创建一个 pivot_longer_spec 数据框 (tidyr.tidyverse.org/reference/pivot_longer_spec.html) 并将其输入到 pivot_longer 函数中。这比尝试创建可以用上述方法分隔的列名更容易和更通用。我当时不知道这个选项,但它真的很有帮助。
    【解决方案3】:

    这出乎意料的困难。我认为也许最简单的方法是将数据转换为最长的格式,然后在此之后重组为 2 组。这是 R 中给出的Anscombe's quartet 示例:

    > anscombe
       x1 x2 x3 x4   y1  y2   y3   y4
    1  10 10 10  8  8.0 9.1  7.5  6.6
    2   8  8  8  8  7.0 8.1  6.8  5.8
    3  13 13 13  8  7.6 8.7 12.7  7.7
    4   9  9  9  8  8.8 8.8  7.1  8.8
    5  11 11 11  8  8.3 9.3  7.8  8.5
    6  14 14 14  8 10.0 8.1  8.8  7.0
    7   6  6  6  8  7.2 6.1  6.1  5.2
    8   4  4  4 19  4.3 3.1  5.4 12.5
    9  12 12 12  8 10.8 9.1  8.2  5.6
    10  7  7  7  8  4.8 7.3  6.4  7.9
    11  5  5  5  8  5.7 4.7  5.7  6.9
    

    所以我们看到有 2 组变量,每组 4 个。我们想要一个只有 3 个变量的数据集:x、y 和系列,后者仅指示值属于 4 个集合中的哪一组。我是这样做的:

    > anscombe %>% 
    +   mutate(row = 1:n()) %>% 
    +   pivot_longer(cols = -row) %>% 
    +   separate(col = name, into = c("var", "series"), sep = 1) %>% 
    +   pivot_wider(id_cols = c(row, series), names_from = "var", values_from = "value") %>% print(n=Inf)
    # A tibble: 44 × 4
         row series     x     y
       <int> <chr>  <dbl> <dbl>
     1     1 1         10  8.04
     2     1 2         10  9.14
     3     1 3         10  7.46
     4     1 4          8  6.58
     5     2 1          8  6.95
     6     2 2          8  8.14
     7     2 3          8  6.77
     8     2 4          8  5.76
     9     3 1         13  7.58
    10     3 2         13  8.74
    11     3 3         13 12.7 
    12     3 4          8  7.71
    13     4 1          9  8.81
    14     4 2          9  8.77
    15     4 3          9  7.11
    16     4 4          8  8.84
    17     5 1         11  8.33
    18     5 2         11  9.26
    19     5 3         11  7.81
    20     5 4          8  8.47
    21     6 1         14  9.96
    22     6 2         14  8.1 
    23     6 3         14  8.84
    24     6 4          8  7.04
    25     7 1          6  7.24
    26     7 2          6  6.13
    27     7 3          6  6.08
    28     7 4          8  5.25
    29     8 1          4  4.26
    30     8 2          4  3.1 
    31     8 3          4  5.39
    32     8 4         19 12.5 
    33     9 1         12 10.8 
    34     9 2         12  9.13
    35     9 3         12  8.15
    36     9 4          8  5.56
    37    10 1          7  4.82
    38    10 2          7  7.26
    39    10 3          7  6.42
    40    10 4          8  7.91
    41    11 1          5  5.68
    42    11 2          5  4.74
    43    11 3          5  5.73
    44    11 4          8  6.89
    

    一步一步:

    1. 添加一个 id 列,它只是行号。
    2. 将除 id 之外的所有内容都转为长格式。
    3. 将 x1...x4 和 y1...y4 分成两列。
    4. 恢复为宽格式,x 和 y 有 2 列。

    我们可以绘制数据以确保我们做对了:

    #data from above)
    ggplot(aes(x, y)) +
    geom_point() +
    geom_smooth(method = "lm", se = F) +
    facet_wrap("series") +
    ggtitle("Anscombe's quartlet: Same correlations but different data")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-11-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多