我的类别相当不整齐,有时单个字段中有多个类别。在拆分多类别条目后,我想为类别条目中的每个类别分配相同的值。例如,如果数据是
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
答案 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