我以为我有一个非常简单的数据帧转换,但由于一个我无法理解的原因,似乎需要一个永恒,这让我怀疑它可能没有做我所希望的.任何人都能解释一下吗?
第1部分 - 将源数据转换为单独的列(实际df具有2.6M行).
鉴于...
> V1 <- c("E11 2286 1", "ECAT 2286 1", "M11 2286 1", "M12 2286 1", "MCAT 2286 1", "C24 2287 1")
> df <- data.frame(V1)
> df
V1
1 E11 2286 1
2 ECAT 2286 1
3 M11 2286 1
4 M12 2286 1
5 MCAT 2286 1
6 C24 2287 1
Run Code Online (Sandbox Code Playgroud)
我想创建两个新列(itemID和主题)并使用V1中相应行的substr填充每个列.
这个我可以用;
> require(stringr)
> df$itemID <- sapply(1:nrow(df), function(i) str_split(df[i,"V1"]," ")[[1]][[2]] )
> df$topic <- sapply(1:nrow(df), function(i) str_split(df[i,"V1"]," ")[[1]][[1]] )
Run Code Online (Sandbox Code Playgroud)
但这需要几分钟,似乎应该有一个更有效的方式.所以我首先尝试使用sapply;
> sapply(1:nrow(df), function(i) {
t <- str_split(df[i,"V1"]," ")
df$itemID <- t[[1]][[2]]
df$topic <- t[[1]][[1]]
})
Run Code Online (Sandbox Code Playgroud)
一个多小时后,什么都没有.所以我保释,因为当个别命令不到20分钟时,这显然无处可去.
下一个选项是在一个任务上尝试ddply,这也失败了.
> require(plyr)
> require(stringr)
> df$itemID <- ddply(df, .(V1), str_split(df$V1," ")[[1]][[2]], .progress="text" )
Error in get(as.character(FUN), mode = "function", envir = envir) :
object '2286' of mode 'function' was not found
Run Code Online (Sandbox Code Playgroud)
因此,任何人都可以执行此任务的第一部分;
第2部分 - 收集itemID的所有主题 对于奖励积分......我需要的任务的第二部分是获取2.6M行(现在在3列中)并折叠每行的itemID,以便所有主题都是保持在一个单元格中.
输出应该看起来像......
itemID topic
1 2286 E11,ECAT,M11,M12,MCAT
2 2287 C24
Run Code Online (Sandbox Code Playgroud)
任何人都可以建议一种简单的方法来将行收集到一个单元格中吗?
我们可以使用几个选项来提高速度.
stringi
stringi包中的功能通常更快.我们可以使用stri_extract_all_regex适当的方法提取字母数字字符regex.在这里,我[[:alnum:]]{2,}根据示例显示使用. rbindlist elements(do.call(rbind.data.frame,..)),更改列名setNames,将'data.frame'转换为'data.table'(setDT),以及paste'itemID'分组的'topic'元素(toString- 是包装器paste(., collapse=', ')).
library(stringi)
library(data.table)
setDT(setNames(do.call(rbind.data.frame,stri_extract_all_regex(df$V1,
'[[:alnum:]]{2,}')), c('topic', 'itemID')))[,
list(topic=toString(topic)), itemID]
# itemID topic
#1: 2286 E11, ECAT, M11, M12, MCAT
#2: 2287 C24
Run Code Online (Sandbox Code Playgroud)
2. dplyr/tidyr
我们可以使用extractfrom tidyr将单列转换为多列,方法是指定适当的正则表达式和paste'itemID'分组的'topic'元素
library(dplyr)
library(tidyr)
extract(df, V1, into= c('topic', 'itemID'), '([^ ]+) ([^ ]+).*',
convert=TRUE) %>%
group_by(itemID) %>%
summarise(topic=toString(topic))
# itemID topic
#1 2286 E11, ECAT, M11, M12, MCAT
#2 2287 C24
Run Code Online (Sandbox Code Playgroud)