【发布时间】:2017-11-08 14:01:51
【问题描述】:
说,我有一个如下的数据框:
library(dplyr)
library(microbenchmark)
library(ggplot2)
dfr <- data.frame(name=c("bill","john","alice","sara"),
job=c("accounting","business","finance","business"),
stringsAsFactors=F)
name job
1 bill accounting
2 john business
3 alice finance
4 sara business
我有一个带有名称的查询(字符向量)。
qe <- c("john","bill","mark","bill")
我想在数据框位置“名称”中搜索查询的每个元素,并在某些条件下检索整行:
- 必须保留查询中的重复项
- 必须保留查询顺序
- 必须保留不匹配的查询(添加 NA)
我的尝试是以下功能:
loopy <- function(qe=NULL,dfr=NULL)
{
elist <- vector("list",length=length(qe))
for(i in 1:length(qe))
{
g <- grep(qe[i],dfr$name)
if(length(g)==0) {
elist[[i]] <- data.frame(name=qe[i],job=NA,stringsAsFactors=F)
}else{
elist[[i]] <- dfr[g,]
}
}
return(bind_rows(elist))
}
loopy(qe,dfr)
name job
1 john business
2 bill accounting
3 mark <NA>
4 bill accounting
它似乎可以工作,但是对于我有几千行的真实数据来说太慢了。我想我会尝试一种 dplyr 方法。
dp_lj <- function(qe=NULL,dfr=NULL)
{
edf <- data.frame(name=qe,stringsAsFactors=F)
edf <- left_join(edf,dfr,by="name")
return(edf)
}
dp_lj(qe,dfr)
name job
1 john business
2 bill accounting
3 mark <NA>
4 bill accounting
left_join 似乎给出了我想要的结果。但是,令人惊讶的是,这比我的循环函数要慢。摆弄着,我想出了一个匹配的方法。
matchy <- function(qe=NULL,dfr=NULL)
{
edf <- dfr[match(qe,dfr$name),]
pos <- match(NA,edf$name)
if(!is.na(pos)) edf[pos,]$name <- qe[pos]
rownames(edf) <- 1:nrow(edf)
return(edf)
}
matchy(qe,dfr)
name job
1 john business
2 bill accounting
3 mark <NA>
4 bill accounting
这是迄今为止最快的。尝试使用%in% 并没有真正奏效
dfr[dfr$name %in% q,].
autoplot(microbenchmark(loopy(qe,dfr),dp_lj(qe,dfr),matchy(qe,dfr),times=500))
Unit: microseconds
expr min lq mean median uq max neval cld
loopy(qe, dfr) 426.274 461.0390 528.1194 481.7795 518.915 2659.955 500 b
dp_lj(qe, dfr) 919.311 982.9155 1146.0196 1030.1260 1129.088 4589.438 500 c
matchy(qe, dfr) 128.396 154.4710 185.1209 169.0875 186.471 736.397 500 a
我很好奇是否有不需要太多努力的更快解决方案。此外,我还没有测试这里看到的性能在真正的大型数据集上运行时是否具有可比性。
编辑 ---------------------------------- --------------------------
按照建议添加了 data.table 方法。
dt <- function(qe=NULL,dfr=NULL)
{
setDT(dfr)
qe <- data.table(name=qe)
merge(qe, dfr, "name", all.x = TRUE, sort = FALSE)
}
使用长度为 18 的查询和 100,000 行的数据框进行了测试。更好地比较了现实生活中的表现。
mb <- microbenchmark(loopy(qe,dfr),dp_lj(qe,dfr),matchy(qe,dfr),dt(qe,dfr),times=200)
autoplot(mb)
【问题讨论】:
-
您可以查看
fastmatch包。这有一个用于match的插入功能,可以在多次搜索中粉碎match。 -
您是否使用这么小的样本数据运行了基准测试?如果是这样,结果不可靠
-
我也是这么想的。我将尝试一个大型数据集。
-
使用带键的 data.table,
DT[query]应该很快。 -
为了我的目的,表(数据框)没有重复的名称。只有查询可以。但是,我想,考虑一下这种情况也会很好。
标签: r performance