有没有更好的方法将带有多个列的“长”表散布为“宽”表?

时间:2018-12-07 06:21:53

标签: r tidyverse

我想将一个长的数据框重塑成一个宽的数据框。也就是说,我想从这里开始:

   file label val1 val2
1   red     A   12    3
2   red     B    4    2
3   red     C    5    8
4 green     A    3    3
5 green     B    6    5
6 green     C    9    6
7  blue     A    3    3
8  blue     B    1    2
9  blue     C    4    6

对此:

   file value1_A value1_B value1_C value2_A value2_B value2_C
1   red       12        4        5        3        2        8
2 green        3        6        9        3        5        6
3  blue        3        1        4        3        2        6

到目前为止,我最大的尝试是:

library(tidyverse)

dat <- 
  structure(list(file = structure(c(3L, 3L, 3L, 2L, 2L, 2L, 1L, 1L, 1L),
                                .Label = c("blue", "green", "red"),
                                class = "factor"), 
               label = structure(c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L),
                                 .Label = c("A", "B", "C"),
                                 class = "factor"),
               val1 = c(12L, 4L, 5L, 3L, 6L, 9L, 3L, 1L, 4L),
               val2 = c(3L, 2L, 8L, 3L, 5L, 6L, 3L, 2L, 6L)),
          class = "data.frame", row.names = c(NA, -9L))

dat %>%
  group_by(file) %>%
  mutate(values1 = paste('value1', label, sep='_'),
         values2 = paste('value2', label, sep='_')) %>%
  spread(values1, val1) %>%
  spread(values2, val2) %>%
  select(-label)
# # A tibble: 9 x 7
# # Groups:   file [3]
#   file  value1_A value1_B value1_C value2_A value2_B value2_C
#   <fct>    <int>    <int>    <int>    <int>    <int>    <int>
# 1 blue         3       NA       NA        3       NA       NA
# 2 blue        NA        1       NA       NA        2       NA
# 3 blue        NA       NA        4       NA       NA        6
# 4 green        3       NA       NA        3       NA       NA
# 5 green       NA        6       NA       NA        5       NA
# 6 green       NA       NA        9       NA       NA        6
# 7 red         12       NA       NA        3       NA       NA
# 8 red         NA        4       NA       NA        2       NA
# 9 red         NA       NA        5       NA       NA        8

输出不令人满意,因为应排的一行占据了三行,并带有多个“ NA”。这似乎是由于两次使用spread造成的,但是我不知道还有什么其他方法可以达到我想要的结果。非常感谢您提供有关此操作的建议。

非常感谢, -R

2 个答案:

答案 0 :(得分:3)

这是一种方式

library(tidyverse)
dat %>%
  # first move to long form so we can
  # see the original column names as strings
  gather("variable_name", "value", contains("val")) %>%
  # create the new column names from the variable name and the label
  mutate(new_column_name = paste(variable_name, label, sep="_")) %>%
  # get rid of the pieces we used to make the column names
  select(-label, -variable_name) %>%
  # now spread
  spread(new_column_name, value)

答案 1 :(得分:3)

这是data.table的方式。只需一行代码...

library( data.table )
dcast( setDT( dat ), file ~ label, value.var = c("val1", "val2"))

#     file val1_A val1_B val1_C val2_A val2_B val2_C
# 1:  blue      3      1      4      3      2      6
# 2: green      3      6      9      3      5      6
# 3:   red     12      4      5      3      2      8