0

我在 R 中有两个不同的数据框,我试图将它们合并在一起。一个只是一组名称,另一个是一组名称,其中包含每个人的相应信息。

所以说我想采用第一个数据框:

Name
1. Blow, Joe
2. Smith, John
3. Jones, Tom 
etc....

并将其合并到这个:

   DonorName  CandidateName DonationAmount CandidateParty
1   blow joe Bush, George W          3,000     Republican
2   guy some  Obama, Barack          5,000       Democrat
3 smith john    Reid, Harry          4,000       Democrat

这样我就有一个新列表,其中仅包含我的第一个列表中的人员以及第二个列表中的信息。如果两个“名称”值的格式相同,我可以只使用merge(),但是有没有办法以某种方式使用agrep() 或pmatch() 来做到这一点?

此外,我正在使用的第二个数据帧中有大约 2500 万行和 6 列,所以制作一个 for 循环是最快的方法吗?

示例数据的可重现版本:

first <- data.frame(Name=c("Blow, Joe","Smith, John","Jones, Tom"),
         stringsAsFactors=FALSE)

second <- read.csv(text="
DonorName|CandidateName|DonationAmount|CandidateParty
blow joe|Bush, George W|3,000|Republican
guy some|Obama, Barack|5,000|Democrat
smith john|Reid, Harry|4,000|Democrat",header=TRUE,sep="|",
stringsAsFactors=FALSE)
4

2 回答 2

3

解决方案:

first$DonorName <- gsub(", "," ",tolower(first$Name),fixed=TRUE)

require(dplyr)

result <- inner_join(first,second,by="DonorName")

如果数据与您提供的一样,将为您提供所需的东西。

result
         Name  DonorName  CandidateName DonationAmount CandidateParty
1   Blow, Joe   blow joe Bush, George W          3,000     Republican
2 Smith, John smith john    Reid, Harry          4,000       Democrat

“快速解决这个问题”

dplyr方法如上:

f_dplyr <- function(left,right){
   left$DonorName <- gsub(", "," ",tolower(left$Name),fixed=TRUE)
   inner_join(left,right,by="DonorName")
}

data.table方法,首先设置键。

f_dt <- function(left,right){
   left[,DonorName :=  gsub(", "," ",tolower(Name),fixed=TRUE)]
   setkey(left,DonorName)
   left[right,nomatch=0L]
}

data.table方法,设置两个键。

f_dt2 <- function(left,right){
   left[,DonorName :=  gsub(", "," ",tolower(Name),fixed=TRUE)]
   setkey(left,DonorName)
   setkey(right,DonorName)
   left[right,nomatch=0L]
}

base方法依赖sapply

f_base <- function(){
  second[second$DonorName %in%
  sapply(tolower(first[[1]]), gsub, pattern = ",", replacement = "", fixed = TRUE), ]
}

让我们在 1M obs 处使第二个 df 更真实一些,以便进行公平的比较:

second <- cbind(second[rep(1:3,1000000),],data.frame(varn= 1:1000000))
left <- as.data.table(first)
right <- as.data.table(second)

library(microbenchmark)

microbenchmark(
          f_base(),
          f_dplyr(first,second),
          f_dt(left,right),
          f_dt2(left,right),
          times=20)

我们得到:

Unit: milliseconds
                   expr       min        lq    median        uq       max neval
               f_base() 2880.6152 3031.0345 3097.3776 3185.7903 3904.4649    20
 f_dplyr(first, second)  292.8271  362.7379  454.6864  533.9147  774.1897    20
      f_dt(left, right)  489.6288  531.4152  605.4148  788.9724 1340.0016    20
     f_dt2(left, right)  472.3126  515.4398  552.8019  659.7249  901.8133    20

在我的机器上,通过这个人为的例子,我们比方法多获得了大约2.5 秒basesapply根据我的经验,简化并且不能很好地扩展......当您增加 和 中的唯一组的数量时,这种差距可能会变得first更大second

如果您想出更有效的使用方法,请随时编辑。我不假装知道,但我总是试图学习一些东西。

于 2014-05-27T02:43:58.367 回答
0

没有dplyr

second[second$DonorName %in%
  sapply(tolower(first[[1]]), gsub, pattern = ",", replacement = "", fixed = TRUE), ]

结果:

#     DonorName  CandidateName DonationAmount CandidateParty
# 1   blow joe  Bush, George W          3,000     Republican
# 3 smith john     Reid, Harry          4,000       Democrat
于 2014-05-27T02:54:20.477 回答