假设我有以下数据库df
。
df <- data.frame(ID= c("A", "B", "C"),
Var1 = c(234, 12, 345),
Var2 = c(4, 555, 325),
Var3 = c("45|221|2", "982", NA))
> df
ID Var1 Var2 Var3
1 A 234 4 45|221|2
2 B 12 555 982
3 C 345 325 <NA>
我想创建一个data.frame,其中Var1
将Var2
和Var3
与ID
中的元素组合在一起。
我正在寻找的结果应如下所示:
> outcome
ID VarA VarB
1 A 234 45
2 A 234 221
3 A 234 2
4 A 4 45
5 A 4 221
6 A 4 2
7 B 12 982
8 B 555 982
请注意:
Var3
中的元素由竖线|
隔开ID == C
不在outcome
中,因为Var3
是该NA
的{{1}}。原始数据包含数百万个ID。
答案 0 :(得分:2)
我们可以使用tidyverse
来获得一个相当优雅的解决方案。总体思路是,我们可以使用separate_rows
将Var3
扩展为行,我们只需要将Var1/Var2
转换为合适的长格式即可,这样就不必重复复制值。
library(tidyverse)
library(stringr)
df %>% gather(variable, value, -ID, -Var3) %>% # pull Var1 and Var2 into
# a single pair of key/value columns
separate_rows(Var3, sep = "\\|") %>% # split Var3 into rows for each value
drop_na(Var3) %>% # drop the NA rows
select(ID, VarA = value, VarB = Var3, -variable) %>%
arrange(ID)
ID VarA VarB
1 A 234 45
2 A 234 221
3 A 234 2
4 A 4 45
5 A 4 221
6 A 4 2
7 B 12 982
8 B 555 982
答案 1 :(得分:1)
使用tidyverse
和splitstackshape
,您可以执行以下操作:
df %>%
filter(!is.na(Var3)) %>%
select(-Var3) %>%
gather(var, VarA, -ID) %>%
select(-var) %>%
full_join(df %>%
filter(!is.na(Var3)) %>%
cSplit("Var3", sep = "|") %>%
select(-Var1, -Var2) %>%
gather(var, VarB, -ID, na.rm = TRUE) %>%
select(-var), by = c("ID" = "ID")) %>%
arrange(ID, VarA, VarB)
ID VarA VarB
1 A 4 2
2 A 4 45
3 A 4 221
4 A 234 2
5 A 234 45
6 A 234 221
7 B 12 982
8 B 555 982
首先,它过滤掉“ Var3”上没有NA的行。其次,它将数据从宽格式转换为长格式,而没有变量“ Var3”。最后,它与df进行完全连接,其中过滤掉了“ Var3”上带有NA的行,并根据“ |”分割了“ Var3”然后转换为宽到长格式,而没有“ Var1”和“ Var2”。