R普利尔赛普利似乎真的很慢

R普利尔赛普利似乎真的很慢,r,plyr,sapply,R,Plyr,Sapply,我以为我有一个非常简单的数据帧转换,但由于一个我无法理解的原因,它似乎需要一个永恒的时间,这使我怀疑它可能没有做我所希望的。有人能解释一下吗 第1部分-将源数据转换为单独的列(实际df有260万行)。 鉴于 > 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

我以为我有一个非常简单的数据帧转换,但由于一个我无法理解的原因,它似乎需要一个永恒的时间,这使我怀疑它可能没有做我所希望的。有人能解释一下吗

第1部分-将源数据转换为单独的列(实际df有260万行)。

鉴于

> 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

有人能推荐一种简单的方法将行聚集到单个单元格中吗?我们可以使用几个选项来提高速度

1。stringi

stringi
包中的函数通常更快。我们可以使用
stri\u extract\u all\u regex
和适当的
regex
提取字母数字字符。这里,我使用的是基于所示示例的
[[:alnum:]{2,}
rbind
列表元素(
do.call(rbind.data.frame,…)
),使用
setNames
更改列名,将'data.frame'转换为'data.table'(
setDT
),以及
粘贴按'itemID'(
toString
)分组的'topic'元素,是
粘贴(,,,,,'collapse=','的包装器。

2。dplyr/tidyr

我们可以使用
extract
from
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
这个怎么样?使用:


以260万行为基准:
N=2.6e6L
x=粘贴(代表(字母,长度,out=N),样本(1e4,N,真),“1”,sep=“”)
dat=data.frame(x,stringsAsFactors=FALSE)
挪威罗夫(dat)#260万
#dplyr+tidyr
系统时间({1%
分组依据(项目ID)%>%
摘要(topic=toString(topic))}
#用户系统运行时间
#  45.643   0.854  46.777 
#数据表
系统时间({
cols=c(“主题”、“项目ID”、“tmp”)
setDT(dat)[,c(cols):=tstrsplit(x,”,fixed=TRUE,type.convert=TRUE]

ans2哇…我只是刚刚试着理解第一个答案(这对我的问题的两个部分都有效)。因此stringi和stringr大致相等,使用str_extract_执行速度没有差别。我喜欢使用dplyr和tidyr的第二个示例,因为我一直在努力掌握项目中其他地方的示例,所以更多的示例更好。Super chap,非常有用。@BarneyC
stringi
函数非常快。您也可以尝试
提取
,它应该也很快。(虽然没有测试过)我会好好看看stringi包,因为它似乎有更多的方法。在这种情况下,没有速度优势(在2.6M行上,两个都以0.2s的速度执行!)但在其他地方可能更灵活。我坚持纠正…@akrun你是个天才!在第一种方法中对所有260万行进行了适当的计时。Stringr 5.37分钟vs Stringi 1.73分钟(因此快了3倍).现在检查dlypr/tidyrmethod@BarneyC感谢您回到基准测试。创建这些很棒的软件包的人都是天才,而不是我:-)我最初的想法是
tstrsplit
,但后来我认为
stringi
会很快。感谢基准测试。
> sapply(1:nrow(df), function(i) {
                                    t <- str_split(df[i,"V1"]," ")
                                    df$itemID <- t[[1]][[2]] 
                                    df$topic  <- t[[1]][[1]] 
                                  })
> 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
  itemID    topic
1 2286      E11,ECAT,M11,M12,MCAT
2 2287      C24
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
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
require(data.table)
cols = c("topic", "itemID", "tmp")
setDT(df)[, c(cols) := tstrsplit(V1, " ", fixed=TRUE, type.convert=TRUE)]
df[, .(topic=paste(topic, collapse=", ")), by=itemID]
#    itemID                     topic
# 1:   2286 E11, ECAT, M11, M12, MCAT
# 2:   2287                       C24
N = 2.6e6L
x = paste(rep(letters, length.out=N), sample(1e4, N, TRUE), "1", sep=" ")
dat = data.frame(x, stringsAsFactors=FALSE)
nrow(dat) # 2.6 million

# dplyr+tidyr
system.time({ans1 <- extract(dat, x, into= c('topic', 'itemID'), 
         '([^ ]+) ([^ ]+).*', convert=TRUE) %>% 
          group_by(itemID) %>% 
         summarise(topic=toString(topic))})
#    user  system elapsed 
#  45.643   0.854  46.777 

# data.table
system.time({
    cols = c("topic", "itemID", "tmp")
    setDT(dat)[, c(cols) := tstrsplit(x, " ", fixed=TRUE, type.convert=TRUE)]
    ans2 <- dat[, .(topic=paste(topic, collapse=", ")), by=itemID]
})    
#    user  system elapsed 
#   1.906   0.064   1.981 

identical(as.data.frame(ans1), setDF(ans2[order(itemID)]))
# [1] TRUE