如何有效地拆分1个数据框列以创建新的数据框,为类别列

时间:2016-08-09 00:44:50

标签: r

我的类别相当不整齐,有时单个字段中有多个类别。在拆分多类别条目后,我想为类别条目中的每个类别分配相同的值。例如,如果数据是

cat <- c("A,B,C", "B", "B,C", "A,E")
val <- c(300, 350, 400, 450)
mydf <- data.frame(cat, val, stringsAsFactors = FALSE)

        cat   val
        A,B,C 300
            B 350
          B,C 400
          A,E 450

从第一行开始,我需要为每个类别A,B和B分配300个。 C,然后从分配给B的第二行350,从第三行分配给每个B和C的400,然后分配给第四行中的A和E.

我想出了一个非常kludge-y for循环来完成这个,但我知道这不是内存效率,因为它在现有的数据帧上使用rbind。

resultsdf <- data.frame(temp_cats = character(0), 
             temp_vals = numeric(0), stringsAsFactors = FALSE)

for(i in 1:nrow(mydf)){
  temp_cats <- stringr::str_split(mydf$cat[i], ",")[[1]]
  temp_vals <- rep(val[i], length(temp_cats))
  temp_df <- data.frame(temp_cats, temp_vals, stringsAsFactors = FALSE)
   resultsdf <- rbind(resultsdf, temp_df)
}

只是好奇是否有人有更优雅的R语法方式来实现这一目标

  temp_cats temp_vals
1         A       300
2         B       300
3         C       300
4         B       350
5         B       400
6         C       400
7         A       450
8         E       450

2 个答案:

答案 0 :(得分:3)

1)stack / unstack 使用strsplit拆分字符串然后取消堆叠并堆叠它以获得所需的长格式s。最后修改名称并使temp_vals成为数字,因为unstack将它们强制转换为字符。没有包使用。

s <-  stack(unstack(transform(mydf, cat = strsplit(cat, ","))))
with(s, data.frame(temp_cats = values, temp_vals = as.numeric(as.character(ind))))

2)dplyr / tidyr 另一种方法是在tidyr包中使用unnest

library(dplyr)
library(tidyr)

mydf %>%
     mutate(cat = strsplit(cat, ",")) %>%
     unnest() %>%
     transmute(temp_cat = cat, temp_vals = val)

2a)使用tidyr 5.0或更高版本,这可能会更短(正如@aosmith在评论中指出的那样)。 separate_rows在内部使用unnest

mydf %>%
     separate_rows(cat) %>%
     transmute(temp_cat = cat, temp_vals = val)

答案 1 :(得分:1)

我们可以使用cSplit

中的splitstackshape
library(splitstackshape)
setnames(cSplit(mydf, "cat", ",", "long"), c("temp_cats", "temp_vals"))[]
#   temp_cats temp_vals
#1:         A       300
#2:         B       300
#3:         C       300
#4:         B       350
#5:         B       400
#6:         C       400
#7:         A       450
#8:         E       450