如何在 R 中按 dplyr/tidyverse 将分组行复制到列中?
How to copy grouped rows into column by dplyr/tidyverse in R?
我正在尝试使用 dplyr 将行集复制到列中。以下是我的数据框。
df <- data.frame(
hid=c(1,1,1,1,2,2,2,2,2,3,3,3,3),
mid=c(1,2,3,4,1,2,3,4,5,1,2,3,4),
tmid=c("010","01010","010","01020",
"010","0120","010","010","020",
"010","01010","010","01020"),
thid=c("010","02020","010","02020",
"000","0120","010","010","010",
"010","02020","010","02020"),
)
打印格式如下:
> df
hid mid tmid thid
1 1 1 010 010
2 1 2 01010 02020
3 1 3 010 010
4 1 4 01020 02020
5 2 1 010 000
6 2 2 0120 0120
7 2 3 010 010
8 2 4 010 010
9 2 5 020 010
10 3 1 010 010
11 3 2 01010 02020
12 3 3 010 010
13 3 4 01020 02020
我想要的输出如下所示:
hid mid tmid thid tmid1 tmid2 tmid3 tmid4 tmid5 thid1 thid2 thid3 thid4 thid5
* <dbl> <dbl> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr>
1 1 1 010 010 010 01010 010 01020 0 010 02020 010 02020 0
2 1 2 01010 02020 010 01010 010 01020 0 010 02020 010 02020 0
3 1 3 010 010 010 01010 010 01020 0 010 02020 010 02020 0
4 1 4 01020 02020 010 01010 010 01020 0 010 02020 010 02020 0
5 2 1 010 000 010 0120 010 010 020 000 0120 010 010 010
6 2 2 0120 0120 010 0120 010 010 020 000 0120 010 010 010
7 2 3 010 010 010 0120 010 010 020 000 0120 010 010 010
8 2 4 010 010 010 0120 010 010 020 000 0120 010 010 010
9 2 5 020 010 010 0120 010 010 020 000 0120 010 010 010
10 3 1 010 010 010 01010 010 01020 0 010 02020 010 02020 0
11 3 2 01010 02020 010 01010 010 01020 0 010 02020 010 02020 0
12 3 3 010 010 010 01010 010 01020 0 010 02020 010 02020 0
13 3 4 01020 02020 010 01010 010 01020 0 010 02020 010 02020 0
- 正在将
thid
和 tmid
转换为列
thid_x
和tmid_x
中的后缀由mid
定义;然而,mid
的最大数量是不可扩展的(在实际的大数据集中,它从 1 扩展到大约 8)
thid_x
和 tmid_x
的相同值由 hid
组设置
- 如果值不存在,应该用
0
填充
这个操作的思路如下图所示。
我目前正在尝试使用 spread
,但它 returns 特定的 mid
和 thid
或 tmid
对。我需要用一个值填充剩余的 <NA>s
,该值保留在按 hid
.
分组的输出中
> df %>% mutate(id1=str_c("tmid",mid)) %>% group_by(hid) %>% spread(key=id1,value=tmid)
# A tibble: 13 x 8
# Groups: hid [3]
hid mid thid tmid1 tmid2 tmid3 tmid4 tmid5
* <dbl> <dbl> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr>
1 1 1 010 010 <NA> <NA> <NA> <NA>
2 1 2 02020 <NA> 01010 <NA> <NA> <NA>
3 1 3 010 <NA> <NA> 010 <NA> <NA>
4 1 4 02020 <NA> <NA> <NA> 01020 <NA>
5 2 1 000 010 <NA> <NA> <NA> <NA>
6 2 2 0120 <NA> 0120 <NA> <NA> <NA>
7 2 3 010 <NA> <NA> 010 <NA> <NA>
8 2 4 010 <NA> <NA> <NA> 010 <NA>
9 2 5 010 <NA> <NA> <NA> <NA> 020
10 3 1 010 010 <NA> <NA> <NA> <NA>
11 3 2 02020 <NA> 01010 <NA> <NA> <NA>
12 3 3 010 <NA> <NA> 010 <NA> <NA>
13 3 4 02020 <NA> <NA> <NA> 01020 <NA>
有什么建议吗?
我们可以 gather
然后做一个 spread
library(tidyverse)
df1 %>%
select(-tdid, -tiid) %>%
gather(key, val, tmid:thid) %>%
unite(keyn, key, mid, sep="") %>%
spread(keyn, val, fill = '0') %>%
right_join(df1) %>%
select(names(df1), everything(), -tdid, -tiid)
# A tibble: 13 x 14
# hid mid tmid thid thid1 thid2 thid3 thid4 thid5 tmid1 tmid2 tmid3
# <dbl> <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
# 1 1 1 010 010 010 02020 010 02020 0 010 01010 010
# 2 1 2 01010 02020 010 02020 010 02020 0 010 01010 010
# 3 1 3 010 010 010 02020 010 02020 0 010 01010 010
# 4 1 4 01020 02020 010 02020 010 02020 0 010 01010 010
# 5 2 1 010 000 000 0120 010 010 010 010 0120 010
# 6 2 2 0120 0120 000 0120 010 010 010 010 0120 010
# 7 2 3 010 010 000 0120 010 010 010 010 0120 010
# 8 2 4 010 010 000 0120 010 010 010 010 0120 010
# 9 2 5 020 010 000 0120 010 010 010 010 0120 010
#10 3 1 010 010 010 02020 010 02020 0 010 01010 010
#11 3 2 01010 02020 010 02020 010 02020 0 010 01010 010
#12 3 3 010 010 010 02020 010 02020 0 010 01010 010
#13 3 4 01020 02020 010 02020 010 02020 0 010 01010 010
# ... with 2 more variables: tmid4 <chr>, tmid5 <chr>
数据
df1 <- structure(list(hid = c(1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3),
mid = c(1, 2, 3, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4), tmid = c("010",
"01010", "010", "01020", "010", "0120", "010", "010", "020",
"010", "01010", "010", "01020"), thid = c("010", "02020",
"010", "02020", "000", "0120", "010", "010", "010", "010",
"02020", "010", "02020"), tdid = c("000", "01010", "010",
"02020", "000", "0100", "010", "010", "010", "000", "01010",
"010", "02020"), tiid = c("010", "02020", "010", "01020",
"020", "0220", "020", "020", "020", "010", "02020", "010",
"01020")), .Names = c("hid", "mid", "tmid", "thid", "tdid",
"tiid"), row.names = c(NA, -13L), class = c("tbl_df", "tbl",
"data.frame"))
我正在尝试使用 dplyr 将行集复制到列中。以下是我的数据框。
df <- data.frame(
hid=c(1,1,1,1,2,2,2,2,2,3,3,3,3),
mid=c(1,2,3,4,1,2,3,4,5,1,2,3,4),
tmid=c("010","01010","010","01020",
"010","0120","010","010","020",
"010","01010","010","01020"),
thid=c("010","02020","010","02020",
"000","0120","010","010","010",
"010","02020","010","02020"),
)
打印格式如下:
> df
hid mid tmid thid
1 1 1 010 010
2 1 2 01010 02020
3 1 3 010 010
4 1 4 01020 02020
5 2 1 010 000
6 2 2 0120 0120
7 2 3 010 010
8 2 4 010 010
9 2 5 020 010
10 3 1 010 010
11 3 2 01010 02020
12 3 3 010 010
13 3 4 01020 02020
我想要的输出如下所示:
hid mid tmid thid tmid1 tmid2 tmid3 tmid4 tmid5 thid1 thid2 thid3 thid4 thid5
* <dbl> <dbl> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr>
1 1 1 010 010 010 01010 010 01020 0 010 02020 010 02020 0
2 1 2 01010 02020 010 01010 010 01020 0 010 02020 010 02020 0
3 1 3 010 010 010 01010 010 01020 0 010 02020 010 02020 0
4 1 4 01020 02020 010 01010 010 01020 0 010 02020 010 02020 0
5 2 1 010 000 010 0120 010 010 020 000 0120 010 010 010
6 2 2 0120 0120 010 0120 010 010 020 000 0120 010 010 010
7 2 3 010 010 010 0120 010 010 020 000 0120 010 010 010
8 2 4 010 010 010 0120 010 010 020 000 0120 010 010 010
9 2 5 020 010 010 0120 010 010 020 000 0120 010 010 010
10 3 1 010 010 010 01010 010 01020 0 010 02020 010 02020 0
11 3 2 01010 02020 010 01010 010 01020 0 010 02020 010 02020 0
12 3 3 010 010 010 01010 010 01020 0 010 02020 010 02020 0
13 3 4 01020 02020 010 01010 010 01020 0 010 02020 010 02020 0
- 正在将
thid
和tmid
转换为列 thid_x
和tmid_x
中的后缀由mid
定义;然而,mid
的最大数量是不可扩展的(在实际的大数据集中,它从 1 扩展到大约 8)thid_x
和tmid_x
的相同值由hid
组设置
- 如果值不存在,应该用
0
填充
这个操作的思路如下图所示。
我目前正在尝试使用 spread
,但它 returns 特定的 mid
和 thid
或 tmid
对。我需要用一个值填充剩余的 <NA>s
,该值保留在按 hid
.
> df %>% mutate(id1=str_c("tmid",mid)) %>% group_by(hid) %>% spread(key=id1,value=tmid)
# A tibble: 13 x 8
# Groups: hid [3]
hid mid thid tmid1 tmid2 tmid3 tmid4 tmid5
* <dbl> <dbl> <fctr> <fctr> <fctr> <fctr> <fctr> <fctr>
1 1 1 010 010 <NA> <NA> <NA> <NA>
2 1 2 02020 <NA> 01010 <NA> <NA> <NA>
3 1 3 010 <NA> <NA> 010 <NA> <NA>
4 1 4 02020 <NA> <NA> <NA> 01020 <NA>
5 2 1 000 010 <NA> <NA> <NA> <NA>
6 2 2 0120 <NA> 0120 <NA> <NA> <NA>
7 2 3 010 <NA> <NA> 010 <NA> <NA>
8 2 4 010 <NA> <NA> <NA> 010 <NA>
9 2 5 010 <NA> <NA> <NA> <NA> 020
10 3 1 010 010 <NA> <NA> <NA> <NA>
11 3 2 02020 <NA> 01010 <NA> <NA> <NA>
12 3 3 010 <NA> <NA> 010 <NA> <NA>
13 3 4 02020 <NA> <NA> <NA> 01020 <NA>
有什么建议吗?
我们可以 gather
然后做一个 spread
library(tidyverse)
df1 %>%
select(-tdid, -tiid) %>%
gather(key, val, tmid:thid) %>%
unite(keyn, key, mid, sep="") %>%
spread(keyn, val, fill = '0') %>%
right_join(df1) %>%
select(names(df1), everything(), -tdid, -tiid)
# A tibble: 13 x 14
# hid mid tmid thid thid1 thid2 thid3 thid4 thid5 tmid1 tmid2 tmid3
# <dbl> <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
# 1 1 1 010 010 010 02020 010 02020 0 010 01010 010
# 2 1 2 01010 02020 010 02020 010 02020 0 010 01010 010
# 3 1 3 010 010 010 02020 010 02020 0 010 01010 010
# 4 1 4 01020 02020 010 02020 010 02020 0 010 01010 010
# 5 2 1 010 000 000 0120 010 010 010 010 0120 010
# 6 2 2 0120 0120 000 0120 010 010 010 010 0120 010
# 7 2 3 010 010 000 0120 010 010 010 010 0120 010
# 8 2 4 010 010 000 0120 010 010 010 010 0120 010
# 9 2 5 020 010 000 0120 010 010 010 010 0120 010
#10 3 1 010 010 010 02020 010 02020 0 010 01010 010
#11 3 2 01010 02020 010 02020 010 02020 0 010 01010 010
#12 3 3 010 010 010 02020 010 02020 0 010 01010 010
#13 3 4 01020 02020 010 02020 010 02020 0 010 01010 010
# ... with 2 more variables: tmid4 <chr>, tmid5 <chr>
数据
df1 <- structure(list(hid = c(1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3),
mid = c(1, 2, 3, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4), tmid = c("010",
"01010", "010", "01020", "010", "0120", "010", "010", "020",
"010", "01010", "010", "01020"), thid = c("010", "02020",
"010", "02020", "000", "0120", "010", "010", "010", "010",
"02020", "010", "02020"), tdid = c("000", "01010", "010",
"02020", "000", "0100", "010", "010", "010", "000", "01010",
"010", "02020"), tiid = c("010", "02020", "010", "01020",
"020", "0220", "020", "020", "020", "010", "02020", "010",
"01020")), .Names = c("hid", "mid", "tmid", "thid", "tdid",
"tiid"), row.names = c(NA, -13L), class = c("tbl_df", "tbl",
"data.frame"))