R - 使用组合将数据从宽格式转换为长格式

3
假设我有以下数据库 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>

我希望创建一个数据框,其中Var1Var2ID中的元素结合起来,并与Var3中的元素相结合。
我期望得到的结果应该如下所示:
> 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 中的元素由竖线 | 分隔。
  • 因为对于那个 IDVar3NA,所以 ID == C 不在 outcome 中。

原始数据包含数百万个 ID。


这似乎是这个的复制:https://dev59.com/P2Yr5IYBdhLWcg3wTYq4,结合这个https://dev59.com/DXI95IYBdhLWcg3wtwb4 - markus
@markus 确实,有很多关于从宽格式转换为长格式以及如何拆分字符字符串的条目。我想这里棘手的部分是要通过ID正确地堆叠Var1-Var3和Var2-Var3,并且要高效地完成这个任务。 - wake_wake
library(tidyverse); df %>% filter(ID != "C") %>% separate_rows(Var3, sep = "\\|") %>% gather(key, Var2, -ID, -Var3) %>% select(-key) %>% arrange(ID)这个怎么样? - markus
@markus 我在刷新页面之前没有看到你写了一个类似的答案。如果你想发表你的答案,我会删除我的,因为我认为separate_rows是一个更合适的函数来解决这个问题,尽管str_splitunnest得到的结果是一样的。 - Mako212
2
@Mako212 不用担心。如果你愿意,可以编辑你的回答并包含 separate_rows - markus
2个回答

2
我们可以使用"tidyverse"来得到一个相当优雅的解决方案。总体思路是,我们可以使用"separate_rows"将"Var3"展开成行,只需要将"Var1/Var2"转换成适合的长格式,这样就不会不必要地重复值。"Original Answer"的翻译是"最初的回答"。
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
使用 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”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接