[英]R: Split unbalanced list in data.frame column
Suppose you have a data frame with the following structure: 假设您有一个具有以下结构的数据框:
df <- data.frame(a=c(1,2,3,4), b=c("job1;job2", "job1a", "job4;job5;job6", "job9;job10;job11"))
where the column b
is a semicolon-delimited list (unbalanced by row). 其中列
b
是以分号分隔的列表(按行不平衡)。 The ideal data.frame would be: 理想的data.frame将是:
id,job,jobNum
1,job1,1
1,job2,2
...
3,job6,3
4,job9,1
4,job10,2
4,job11,3
I have a partial solution that takes almost 2 hours (170K rows): 我有一个部分解决方案,需要将近2小时(170K行):
# Split the column by the semicolon. Results in a list.
df$allJobs <- strsplit(df$b, ";", fixed=TRUE)
# Function to reshape column that is a list as a data.frame
simpleStack <- function(data){
start <- as.data.frame.list(data)
names(start) <-c("id", "job")
return(start)
}
# pylr!
system.time(df2 <- ddply(df, .(id), simpleStack))
It appears to be a size issue, because if I run 这似乎是一个大小问题,因为如果我跑
system.time(df2 <- ddply(df[1:4000,c("id", "allJobs")], .(id), simpleStack))
it only takes 9 seconds. 它只需要9秒钟。 First converting to a set of data.frames with sapply (with a different function) is fast, but the required `rbind' takes even longer.
首先使用sapply(使用不同的函数)转换为一组data.frames很快,但所需的`rbind'需要更长的时间。
#Split by ; as before
allJobs <- strsplit(df$b, ";", fixed=TRUE)
#Replicate a by the number of jobs in each case
n <- sapply(allJobs, length)
id <- rep(df$a, times = n)
#Turn allJobs into a vector
job <- unlist(allJobs)
#Retrieve position of each job
jobNum <- unlist(lapply(n, seq_len))
#Combine into a data frame
df2 <- data.frame(id = id, job = job, jobNum = jobNum)
cSplit
from my "splitstacksahpe" package is designed to handle this sort of data manipulation. cSplit
从我的“splitstacksahpe”包装设计来处理这类数据操作。
Here it is in action on this question: 这是针对这个问题的行动:
df <- data.frame(a=c(1,2,3,4),
b=c("job1;job2", "job1a", "job4;job5;job6", "job9;job10;job11"))
# install.packages("splitstackshape")
library(splitstackshape)
cSplit(df, "b", ";", "long", makeEqual = FALSE)
# a b_new
# 1: 1 job1
# 2: 1 job2
# 3: 2 job1a
# 4: 3 job4
# 5: 3 job5
# 6: 3 job6
# 7: 4 job9
# 8: 4 job10
# 9: 4 job11
You can also use strsplit
within "dplyr", and then follow up with unnest
from "tidyr", like this: 您还可以使用
strsplit
内“dplyr”,然后跟进unnest
从“tidyr”,就像这样:
library(dplyr)
library(tidyr)
df %>%
mutate(b = strsplit(as.character(b), ";", fixed = TRUE)) %>%
unnest(b)
# a b
# 1 1 job1
# 2 1 job2
# 3 2 job1a
# 4 3 job4
# 5 3 job5
# 6 3 job6
# 7 4 job9
# 8 4 job10
# 9 4 job11
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.