R / tidyr/dplyr - 按键将重复的行转置为具有新变量名称的列

R / tidyr/dplyr - transpose repeated rows by key into columns with new variable names

编辑:这是一个与 this one 类似的问题,但我明确采用 tidyr/dplyr 方法。

我很好奇是否有一种巧妙的 "tidyr/dplyr" 方式来进行这种移调?

我对目前以 "long" 格式的相同现象(关键)有不同的(按 ID)观察(v2、v2、v3),为了演示,我想要一个宽格式每行一个现象(键),但每组观察值(ID,v1,v2,v3)在重复的列集中具有适当递增的变量名称

在这种情况下,我知道只会有 2 个 ID,所以我将其拆分为两帧表并将它们连接起来。

我想要任何关于一般 tidyr 转弯方式的指示:

key ID      v1      v2      v3
32  blue    8.550   0.782   78.281
32  green   9.200   1.680   95.354
22  orange  6.100   -0.143  44.320
22  pink    6.500   0.672   74.920
100 green   4.500   -0.460  32.280
100 blue    8.000   0.506   69.372

进入:

key IDa     v1       v2     v3      IDb     v1b     v2b     v3b
32  blue    8.550    0.782  78.281  green   9.200   1.680   95.354
22  orange  6.100   -0.143  44.320  pink    6.500   0.672   74.920
100 green   4.500   -0.460  32.280  blue    8.000   0.506   69.372

谢谢!

您可以为每个 key 创建一个 id 列,然后使用能够旋转多个列的 data.table::dcast

df %>% 
    group_by(key) %>% 
    mutate(n = row_number()) %>% 
    {data.table::dcast(data = setDT(.), key ~ n, value.var = c('ID', 'v1', 'v2', 'v3'))}

#   key   ID_1  ID_2 v1_1 v1_2   v2_1  v2_2   v3_1   v3_2
#1:  22 orange  pink 6.10  6.5 -0.143 0.672 44.320 74.920
#2:  32   blue green 8.55  9.2  0.782 1.680 78.281 95.354
#3: 100  green  blue 4.50  8.0 -0.460 0.506 32.280 69.372

考虑使用反向重复连接(借用的 SQL 方法)merge 的基础 R 解决方案。但是,您需要为反向重复 subset 的行号创建一个辅助列,并产生不同的 IDa 值。 transform 下方用于删除助手 列。

txt = "key ID      v1      v2      v3
32  blue    8.550   0.782   78.281
32  green   9.200   1.680   95.354
22  orange  6.100   -0.143  44.320
22  pink    6.500   0.672   74.920
100 green   4.500   -0.460  32.280
100 blue    8.000   0.506   69.372"

df <- read.table(text=txt, header=TRUE, stringsAsFactors = FALSE)
df$row <- row.names(df)

mdf <- transform(subset(merge(df, df, by="key", suffixes=c("a", "b")), rowa < rowb), rowa=NULL, rowb=NULL)

mdf
#    key    IDa  v1a    v2a    v3a   IDb v1b   v2b    v3b
# 2   22 orange 6.10 -0.143 44.320  pink 6.5 0.672 74.920
# 6   32   blue 8.55  0.782 78.281 green 9.2 1.680 95.354
# 10 100  green 4.50 -0.460 32.280  blue 8.0 0.506 69.372

此解决方案仅依赖于 tidyrdplyr。这里的关键是使用 tidyr::unite 创建键变量给 spread with。

library(dplyr)
library(tidyr)

df %>% 
  group_by(key) %>% 
  mutate(suffix = letters[1:n()]) %>%
  gather(var, val, -c(key, suffix)) %>%
  unite(var_group, var, suffix, sep = "") %>%
  spread(var_group, val) %>%
  select(key, ends_with("a"), ends_with("b"))
#> # A tibble: 3 x 9
#> # Groups:   key [3]
#>     key    IDa   v1a    v2a    v3a   IDb   v1b   v2b    v3b
#> * <int>  <chr> <chr>  <chr>  <chr> <chr> <chr> <chr>  <chr>
#> 1    22 orange   6.1 -0.143  44.32  pink   6.5 0.672  74.92
#> 2    32   blue  8.55  0.782 78.281 green   9.2  1.68 95.354
#> 3   100  green   4.5  -0.46  32.28  blue     8 0.506 69.372