平行pivot_longer 两组列

parallel pivot_longer of two sets of columns

我有以下数据框:

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 组?感觉这是重塑数据集时的基本任务之一,但我无法让它工作。

预期输出:

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" 只是示例,我'如果其他列名更容易即时生成,我可以使用它们。

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

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

是您要找的吗?

我在 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 参数中给它 两个 列名:一个是你所说的这些objects(在本例中为 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 在这里都是数字,但一个可能是数字,一个是字符)。

出乎意料的困难。我认为也许最简单的方法是将数据转换为最长格式,然后再重组为 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 两列的宽格式。

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

#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")