使用另一列的值将 R 列值扩展到列 Headers

Expand an R Column Values To Column Headers with Another Column's values

我正在尝试扩展如下所示的 R 数据 table:

a   step_num   duration 

1          1          5 
1          2          4
1          3          1
2          1          7
2          2          2
2          3          9
3          1          1
3          2          1
3          3          3

进入看起来像这样的东西:

a | step_num | duration | 1_duration | 2_duration | 3_duration |
----------------------------------------------------------------
1          1          5            5           -            -
1          2          4            -           4            -
1          3          1            -           -            1
2          1          7            7           -            -
2          2          2            -           2            -
2          3          9            -           -            9
3          1          1            1           -            -
3          2          1            -           1            -
3          3          3            -           -            3

我想知道是否有 'expand' 函数可以做到这一点。

谢谢!

这是使用 dplyrtidyr 的方法。

我们获取原始数据并通过首先添加一个新列 col 添加一些列,该列包含我们想要的列 header,基于 step_num。然后我们使用 tidyr::spread 将持续时间放入不同的列中,具体取决于它们与哪个 col 一起使用。 fill = "-" 用破折号填充所有空列。最后,我们删除 astep_num 列,因为它们已经存在于原始数据中,我们不想拥有它们的副本。

(注意,我们需要 step_num 仍然存在于 spread 步骤,因为我们希望保持每一行与原始行对齐。没有 step_num,数据将分散成更宽、更短的格式,这样行就会错位。)

library(dplyr); library(tidyr)
df %>%  
  mutate(col = paste0(step_num, "_duration")) %>%
  spread(col, duration, fill = "-") %>%
  select(-a, -step_num)) %>% 
  bind_cols(df, .)  # Edit, per excellent suggestion from M-M


  a step_num duration 1_duration 2_duration 3_duration
1 1        1        5          5          -          -
2 1        2        4          -          4          -
3 1        3        1          -          -          1
4 2        1        7          7          -          -
5 2        2        2          -          2          -
6 2        3        9          -          -          9
7 3        1        1          1          -          -
8 3        2        1          -          1          -
9 3        3        3          -          -          3

我们可以在 base r 中做到这一点。

cbind(df,
      reshape(df, idvar = c("a","step_num"), timevar = "step_num", direction = "wide")[,-1])

#>   a step_num duration duration.1 duration.2 duration.3
#> 1 1        1        5          5         NA         NA
#> 2 1        2        4         NA          4         NA
#> 3 1        3        1         NA         NA          1
#> 4 2        1        7          7         NA         NA
#> 5 2        2        2         NA          2         NA
#> 6 2        3        9         NA         NA          9
#> 7 3        1        1          1         NA         NA
#> 8 3        2        1         NA          1         NA
#> 9 3        3        3         NA         NA          3

reprex package (v0.2.1)

于 2019-05-21 创建

简单tidyverse解决方案:

library(tidyverse)

df %>%
  mutate(step = step_num) %>%
  spread(step, duration, fill = '-') %>%
  rename_all( ~ gsub('(\d+)', 'duration_\1', .))

#   a step_num duration_1 duration_2 duration_3
# 1 1        1          5          -          -
# 2 1        2          -          4          -
# 3 1        3          -          -          1
# 4 2        1          7          -          -
# 5 2        2          -          2          -
# 6 2        3          -          -          9
# 7 3        1          1          -          -
# 8 3        2          -          1          -
# 9 3        3          -          -          3

或者 dcast 来自 data.table

的选项
library(data.table)
dcast(setDT(df),  a + step_num ~  
        paste0("duration_", step_num), value.var = 'duration')
#    a step_num duration_1 duration_2 duration_3
#1: 1        1          5         NA         NA
#2: 1        2         NA          4         NA
#3: 1        3         NA         NA          1
#4: 2        1          7         NA         NA
#5: 2        2         NA          2         NA
#6: 2        3         NA         NA          9
#7: 3        1          1         NA         NA
#8: 3        2         NA          1         NA
#9: 3        3         NA         NA          3

注意:最好使用 NA 而不是 -,因为 NA 很容易用 is.na/complete.cases/na.omit 移除,并且不会改变 class 到 character

数据

df <- structure(list(a = c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 3L, 3L), step_num = c(1L, 
2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), duration = c(5L, 4L, 1L, 7L, 
2L, 9L, 1L, 1L, 3L)), class = "data.frame", row.names = c(NA, 
-9L))