R将逗号分隔的单元格分成行和笛卡尔积

R separate comma separated cells into rows and Cartesian product

我下面有 mydf 数据框。我想拆分任何包含逗号分隔数据的单元格并将其放入行中。我正在寻找类似于下面 y 的数据框。我怎样才能在几步内有效地做到这一点?目前我一次在一列上使用 cSplit 函数。

我试过 cSplit(mydf, c("name","new"), ",", direction = "long"),但没用

library(splitstackshape)
mydf=data.frame(name = c("AB,BW","x,y,z"), AB = c('A','B'), new=c("1,2,3","4,5,6,7"))
mydf

x=cSplit(mydf, c("name"), ",", direction = "long")
x
y=cSplit(x, c("new"), ",", direction = "long")
y

我们可以使用 包中的 separate_rows 函数。

library(tidyr)

mydf2 <- mydf %>%
  separate_rows("name") %>%
  separate_rows("new")
mydf2

#    AB name new
# 1   A   AB   1
# 2   A   AB   2
# 3   A   AB   3
# 4   A   BW   1
# 5   A   BW   2
# 6   A   BW   3
# 7   B    x   4
# 8   B    x   5
# 9   B    x   6
# 10  B    x   7
# 11  B    y   4
# 12  B    y   5
# 13  B    y   6
# 14  B    y   7
# 15  B    z   4
# 16  B    z   5
# 17  B    z   6
# 18  B    z   7 

如果你不会多次使用separate_rows函数,我们可以进一步设计一个函数来迭代应用separate_rows函数。

expand_fun <- function(df, vars){
  while (length(vars) > 0){
    df <- df %>% separate_rows(vars[1])
    vars <- vars[-1]
  }
  return(df)
}

expand_fun有两个参数。第一个参数 df 是原始数据框。第二个参数 vars 是一个字符串,其中包含我们要扩展的列名。这是使用该函数的示例。

mydf3 <- expand_fun(mydf, vars = c("name", "new"))
mydf3
#    AB name new
# 1   A   AB   1
# 2   A   AB   2
# 3   A   AB   3
# 4   A   BW   1
# 5   A   BW   2
# 6   A   BW   3
# 7   B    x   4
# 8   B    x   5
# 9   B    x   6
# 10  B    x   7
# 11  B    y   4
# 12  B    y   5
# 13  B    y   6
# 14  B    y   7
# 15  B    z   4
# 16  B    z   5
# 17  B    z   6
# 18  B    z   7

有时候 for 循环在 R 中完全可以使用。这就是其中之一。尝试:

library(splitstackshape)
cols <- c("name", "new")
for (i in cols) {
  mydf <- cSplit(mydf, i, ",", "long")
}

mydf
##     name AB new
##  1:   AB  A   1
##  2:   AB  A   2
##  3:   AB  A   3
##  4:   BW  A   1
##  5:   BW  A   2
##  6:   BW  A   3
##  7:    x  B   4
##  8:    x  B   5
##  9:    x  B   6
## 10:    x  B   7
## 11:    y  B   4
## 12:    y  B   5
## 13:    y  B   6
## 14:    y  B   7
## 15:    z  B   4
## 16:    z  B   5
## 17:    z  B   6
## 18:    z  B   7

这是一个使用稍大数据的小测试:

# concat.test = sample data from "splitstackshape"
test <- do.call(rbind, replicate(5000, concat.test, FALSE))

fun1 <- function() {
  cols <- c("Likes", "Siblings")
  for (i in cols) {
    test <- cSplit(test, i, ",", "long")
  }
  test
}

fun2 <- function() {
  test %>%
    separate_rows("Likes") %>%
    separate_rows("Siblings")
}

system.time(fun1())
#   user  system elapsed 
#  3.205   0.056   3.261 
system.time(fun2())
#   user  system elapsed 
# 11.598   0.066  11.662