当名称在R中具有不同格式时,按名称合并数据集

时间:2014-05-27 01:59:41

标签: r merge fuzzy-search agrep

我在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)

2 个答案:

答案 0 :(得分: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

&#34;快速解决此问题&#34;

上述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

在我的计算机上,使用此?人工示例,我们比base方法获得 2.5秒。根据我的经验,sapply简化并且不能很好地扩展...当您增加firstsecond中的唯一群组数量时,这种差距可能会变大。

如果您能更有效地使用,请随时修改。我不会假装知道,但我总是试着学习一些东西。

答案 1 :(得分: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