我知道data.table能够一次整理多个列,这与dplyr不同,后者取决于多个gather
和spread
步骤,这些步骤可能难以可视化。
这是tidyverse的一个棘手问题:
library(tidyverse)
df <- data_frame(month_1 = c("Jan", "Feb", "Mar", "Jun"),
score_1 = c(4, 5, 6, 4),
month_2 = c("Jan", "Mar", NA, NA),
score_2 = c(3, 2, NA, NA),
month_3 = c("Feb", "Mar", "Jun", NA),
score_3 = c(8, 7, 4, NA))
# A tibble: 4 x 6
month_1 score_1 month_2 score_2 month_3 score_3
<chr> <dbl> <chr> <dbl> <chr> <dbl>
1 Jan 4 Jan 3 Feb 8
2 Feb 5 Mar 2 Mar 7
3 Mar 6 NA NA Jun 4
4 Jun 4 NA NA NA NA
我想要的结果是:
id month score
1 Jan 4
1 Feb 5
1 Mar 6
1 Jun 4
2 Jan 3
2 Mar 2
3 Feb 8
3 Mar 7
3 Jun 4
data.table用户可以通过融合模式来解决此问题,例如:
melt(setDT(df), measure = patterns("^month", "^score"))
但是,由于没有等效的dplyr函数,我知道将需要多个spread
。看来我下面的解决方案应该可以用,但是第二个spread
却出问题了:
df %>%
gather(key, value) %>%
mutate(id = parse_number(key),
key = str_replace(key, "_[0-9]", "")) %>%
spread(key, value )
在将其标记为重复项之前,请尝试一下。类似的问题在现有列中具有唯一ID。此示例的标题中包含ID。
答案 0 :(得分:1)
您可以分别处理month
和score
列,然后将它们与purrr::map_dfc
连接起来:
map_dfc(c("month", "score"),
~ df %>%
select_at(vars(matches(.x))) %>%
gather(key, !!.x) %>%
separate(key, c("col", "id"), sep="_")) %>%
filter(complete.cases(.)) %>%
select(id, month, score)
# A tibble: 9 x 3
id month score
<chr> <chr> <chr>
1 1 Jan 4
2 1 Feb 5
3 1 Mar 6
4 1 Jun 4
5 2 Jan 3
6 2 Mar 2
7 3 Feb 8
8 3 Mar 7
9 3 Jun 4
说明:
map_dfc
遍历字符串值“ month”和“ score”,将当前值称为.x
。后缀dfc
在迭代输出上执行cbind
。 select_at
仅选择以.x
开头的列gather
从宽变长,并用values
字符串值命名.x
列。 separate
将key
分为两列,其中包含列类型(对应于.x
值)和id
号。 filter
删除缺失值,并select
我们的目标列。