我正在寻找R中以下问题的简化解决方案:我有一个用逗号分隔的名称列表 - 但是,其中一些名称中也有逗号。为了分隔名称,我想首先用逗号替换所有名称,然后用逗号分隔。我的问题是我有大约26000个字符串,每个字符串有几个名字,我有一个大约130个带逗号的名字列表。我已经编写了一个嵌套的foreach循环(为了使用多个核心来加快速度),它可以工作,但速度非常慢。有没有更快的方法来搜索字符串并替换相关的名称?这是我的示例代码:
List_of_names<-as.data.frame(c("Fred, Heiko, Franz, Jr., Nice, LLC, Meike","Digital, Mike, John, Sr","Svenja, Sven"))
Comma_names<-as.data.frame(c("Franz, Jr.","Nice, LLC","John, Sr"))
colnames(Comma_names)<-"name"
Comma_names$replace_names<-gsub(",", "",Comma_names[,"name"])
library(doParallel)
library(foreach)
cl<-makeCluster(4) # Create cluster with desired number of cores
registerDoParallel(cl) # Register cluster
names_new<-foreach (i=1:nrow(List_of_names),.errorhandling="pass",.packages=c("foreach")) %dopar% {
name_2<-List_of_names[i,]
foreach (j=1:nrow(Comma_names),.combine=rbind,.errorhandling="pass") %do% {
if(length(grep(Comma_names[j,1],name_2))>0){
name_2<-gsub(Comma_names[j,1], Comma_names[j,2],name_2)
}
}
name_2
}
此外,foreach循环的结果是一个列表,但如果我尝试保存列表或替换原始数据框中的列,则需要永久。如何更改代码以使其更快?
感谢所有读过这篇文章的人,并且能够提供帮助!
答案 0 :(得分:2)
<强>原理强>
您可以使用来自Reduce
包的stri_replace_all
和stringi
的组合。
<强>代码强>
library(stringi)
Comma_names <- structure(list(name = c("Franz, Jr.", "Nice, LLC", "John, Sr"),
replace_names = c("Franz Jr.", "Nice LLC", "John Sr")),
.Names = c("name", "replace_names"),
row.names = c(NA, -3L), class = "data.frame")
List_of_names <- structure(list(name = c("Fred, Heiko, Franz, Jr., Nice, LLC, Meike",
"Digital, Mike, John, Sr", "Svenja, Sven")),
.Names = "name",
row.names = c(NA, -3L), class = "data.frame")
wrapper <- function(str, ind) stri_replace_all(str, Comma_names$replace_names[ind],
fixed = Comma_names$name[ind])
ind <- 1:NROW(Comma_names)
Reduce(wrapper, ind, init = List_of_names$name)
# [1] "Fred, Heiko, Franz Jr., Nice LLC, Meike"
# [2] "Digital, Mike, John Sr"
# [3] "Svenja, Sven"
<强>解释强>
stri_replace_all
是一个快速函数,它替换字符串中的所有匹配项。使用Reduce
,您可以将函数应用于上一个函数调用的结果。因此,我们将wrapper
应用于包含所有名称的列,并替换Comma_names
第一行中的字符串。我们现在再次将此字符串提供给wrapper
,目的是替换第二行的所有匹配项,依此类推。这段代码应该运行得很快,你不需要parallezie。很想听听您对执行时间的反馈。
<强>基准强>
只有一个基准,有300万行:
List_of_names <- List_of_names[rep(1:NROW(List_of_names), 1e6), , drop = FALSE]
system.time(invisible(Reduce(wrapper, ind, init = List_of_names$name)))
# user system elapsed
# 1.95 0.00 1.96