R-使用组合从宽格式到长格式

R-使用组合从宽格式到长格式,r,dataframe,reshape,R,Dataframe,Reshape,假设我有以下数据库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

假设我有以下数据库
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>
请注意:

  • Var3
    中的元素由竖条隔开
    |
  • ID==C
    不在
    outcome
    中,因为
    Var3
    对于该
    ID
    NA

原始数据由数百万个ID组成

我们可以使用
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

使用
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”。

这似乎是一个重复:与@markus相结合,确实存在大量从宽到长的条目,以及如何拆分字符串。我想,这里棘手的部分是通过ID正确地堆叠Var1-Var3和Var2-Var3,并高效地完成这项工作;df%%>%filter(ID!=“C”)%%>%sep=“\\\\\””%%>%gather(key,Var2,-ID,-Var3)%%>%select(-key)%%>%arrange(ID)?@markus在发布刷新页面之前,我没有看到你给我写过类似的答案。如果你想发布你的,我会删除我的,因为我认为
separate_rows
是解决这个问题的更合理的函数,即使
str_split
unnest
有相同的结果。@Mako212别担心。编辑您的答案并包括
单独的行
(如果您愿意)。
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