在R中对数据框的列进行拆分和组合

3

我有一个非常大的数据集(大约500k行和15列)。其中一列以分号分隔多个字符,如下所示:

Date            a     b       c                  d  
01-01-2020     A1     B1     C1a;C1b            D1
30-12-2019     A2     B2     C2a;C2b;C2c        D2
33-5-2018      A3     B3     C3a;C3b;C3c;C3d    D3
20-11-2019     A4     B4     C4a;C4b            D4

我希望将列c拆分为仅有的两列(cA和cB)。当c中有超过两个因素时,例如在第2列和第3列中,我想要创建每个可能唯一组合的行数,其他条件均相等。结果应如下:

Date            a     b      c_01   c_02            d 
01-01-2020     A1     B1     C1a    C1b            D1
30-12-2019     A2     B2     C2a    C2b            D2
30-12-2019     A2     B2     C2a    C2c            D2
30-12-2019     A2     B2     C2b    C2c            D2
33-5-2018      A3     B3     C3a    C3b            D3
33-5-2018      A3     B3     C3a    C3c            D3
33-5-2018      A3     B3     C3a    C3d            D3
33-5-2018      A3     B3     C3b    C3c            D3
33-5-2018      A3     B3     C3b    C3d            D3
33-5-2018      A3     B3     C3c    C3d            D3
20-11-2019     A4     B4     C4a    C4b            D4

我尝试使用 csplit 创建每个因子的单一列,然后为每行创建一个 for loop 但它并没有真正起作用。我还尝试使用 apply 函数创建类似循环的东西,但数据集太大了,我一直收到错误信息。有人能帮忙吗?非常感谢!

2
正如akrun的回答所示,您正在寻找combn。由于您正在使用cSplit,因此您还可以使用data.table中的transpose。像这样的东西应该可以工作:cSplit(df1, "c", ";", "long")[, transpose(combn(c, 2, simplify = FALSE)), .(Date, a, b, d)] - A5C1D2H2I1M1N2O1R2T1
1个回答

1
我们可以使用strsplit函数将“c”列按“;”分割,然后使用map函数循环遍历list,获取combn函数的配对结果,转换为data.frame,并且将“data.frame”列的list进行展开(unnest)。
library(dplyr)
library(tidyr)
library(purrr)
df1 %>%
   mutate(c = map(strsplit(c, ";"), ~ combn(.x, 2) %>% 
           t %>% 
            as.data.frame %>%
            set_names(c('c_01', 'c_02')))) %>%
   unnest(c(c))
# A tibble: 11 x 6
#   Date       a     b     c_01  c_02  d    
#   <chr>      <chr> <chr> <chr> <chr> <chr>
# 1 01-01-2020 A1    B1    C1a   C1b   D1   
# 2 30-12-2019 A2    B2    C2a   C2b   D2   
# 3 30-12-2019 A2    B2    C2a   C2c   D2   
# 4 30-12-2019 A2    B2    C2b   C2c   D2   
# 5 33-5-2018  A3    B3    C3a   C3b   D3   
# 6 33-5-2018  A3    B3    C3a   C3c   D3   
# 7 33-5-2018  A3    B3    C3a   C3d   D3   
# 8 33-5-2018  A3    B3    C3b   C3c   D3   
# 9 33-5-2018  A3    B3    C3b   C3d   D3   
#10 33-5-2018  A3    B3    C3c   C3d   D3   
#11 20-11-2019 A4    B4    C4a   C4b   D4   

或者使用基本 R

lst1 <- lapply(strsplit(df1$c, ";"), 
          function(x) as.data.frame(t(combn(x, 2))))
l1 <- sapply(lst1, nrow)
out <- cbind(df1[rep(seq_len(nrow(df1)), l1),c('Date', 'a', 'b', 'd')], 
         do.call(rbind, lst1))
row.names(out) <- NULL
names(out)[5:6] <- c("c_01", "c_02")
out
#         Date  a  b  d c_01 c_02
#1  01-01-2020 A1 B1 D1  C1a  C1b
#2  30-12-2019 A2 B2 D2  C2a  C2b
#3  30-12-2019 A2 B2 D2  C2a  C2c
#4  30-12-2019 A2 B2 D2  C2b  C2c
#5   33-5-2018 A3 B3 D3  C3a  C3b
#6   33-5-2018 A3 B3 D3  C3a  C3c
#7   33-5-2018 A3 B3 D3  C3a  C3d
#8   33-5-2018 A3 B3 D3  C3b  C3c
#9   33-5-2018 A3 B3 D3  C3b  C3d
#10  33-5-2018 A3 B3 D3  C3c  C3d
#11 20-11-2019 A4 B4 D4  C4a  C4b

数据

df1 <- structure(list(Date = c("01-01-2020", "30-12-2019", "33-5-2018", 
"20-11-2019"), a = c("A1", "A2", "A3", "A4"), b = c("B1", "B2", 
"B3", "B4"), c = c("C1a;C1b", "C2a;C2b;C2c", "C3a;C3b;C3c;C3d", 
"C4a;C4b"), d = c("D1", "D2", "D3", "D4")), class = "data.frame",
row.names = c(NA, 
-4L))

谢谢您的回答!但是,它给了我这个错误:'Error in combn(x, 2) : n < m',无论我是在基本R中使用还是使用包,您知道这可能意味着什么吗? - Simon_W
@Simon_W 我也展示了一个示例数据,两种解决方案都能正常运行。 - akrun
1
@Simon_W 我认为错误不是基于这个例子。可能是因为在分割后有一些元素只有一个元素。一种选择是指定一个条件 lst1 <- lapply(strsplit(df1$c, ";"), function(x) if(length(x) > 1) as.data.frame(t(combn(x, 2))) else data.frame(V1 = x, V2 = NA_character_)) - akrun
@Simon_W 请使用前面评论中的if/else修复。 - akrun

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