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

R - from wide to long format using combinations

假设我有以下数据库 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,其中 Var1Var2 通过 IDVar3 中的元素组合。

我正在寻找的结果应该如下所示:

> 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

注意:

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

我们可以使用 tidyverse 来获得一个相当优雅的解决方案。一般的想法是我们可以使用 separate_rowsVar3 扩展成行,我们只需要将 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

使用 tidyversesplitstackshape 你可以:

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".