使用dplyr / tidyr将与分类变量关联的列扩展为多个列,同时保留id变量

时间:2017-08-24 22:54:39

标签: r dplyr tidyr

我的data.frame看起来像这样:

dfTall <- frame_data(
    ~id, ~x, ~y, ~z,
      1, "a", 4, 5,
      1, "b", 6, 5,
      2, "a", 5, 4,
      2, "b", 1, 9)

我想把它变成这个:

dfWide <- frame_data(
    ~id, ~y_a, ~y_b, ~z_a, ~z_b,
      1,    4,    6,    5,    5,
      2,    5,    1,    4,    9)

目前,我正在这样做

dfTall %>%
    split(., .$x) %>%
    mapply(function(df,name) 
        {df$x <- NULL; names(df) <- paste(names(df), name, sep='_'); df}, 
        SIMPLIFY=FALSE, ., names(.)) %>%
    bind_cols() %>%
    select(-id_b) %>%
    rename(id = id_a)

实际上,我需要扩展更多的数字列(即,不只是yz)。我当前的解决方案有效,但它存在问题,例如id变量的多个副本被添加到最终data.frame并需要删除。

可以使用tidyr中的函数(例如spread

)完成此扩展

1 个答案:

答案 0 :(得分:4)

可以使用spread完成,但不能在一个步骤中完成,因为它涉及多个列作为值;您可以首先gather值列,unite手动标题,然后spread

library(dplyr)
library(tidyr)

dfTall %>% 
    gather(col, val, -id, -x) %>% 
    unite(key, col, x) %>% 
    spread(key, val)

# A tibble: 2 x 5
#     id   y_a   y_b   z_a   z_b
#* <dbl> <dbl> <dbl> <dbl> <dbl>
#1     1     4     6     5     5
#2     2     5     1     4     9

如果您使用data.table,则dcast支持投放多个值列:

library(data.table)
dcast(setDT(dfTall), id ~ x, value.var = c('y', 'z'))

#   id y_a y_b z_a z_b
#1:  1   4   6   5   5
#2:  2   5   1   4   9