更快地找到匹配并附加到data.frame?

时间:2012-04-23 22:03:52

标签: r

我的代码有效。但它很慢,我希望加快速度,这样我就可以扩展到几万个观测数据集。

我有两个数据框,其中一个我使用data.table包转换为data.table以进行快速查找和连接。当3个字段与第二个数据集中的记录匹配时,我想记录来自一个数据集的记录。

Original.df(数据框)和LookHereForMatches.dt(带有键a1,a2,a3的data.table)。 Original.df将有100,000到300,000个观测值,LookHereForMatches.dt可能是2倍。

我遍历Original.df中的每个观察,并在LookHereForMatches.dt中查找符合某些条件的观察结果。我想要来自LookHereForMatches.dt的几个字段和来自Original.df的几个字段。我使用subset()来获取我想要的列。

也许有人可以告诉我我的代码的哪一部分是最差/最慢的。我必须相信它是rbind(cbind())的一部分。看起来这不是正确的做法。

matched_data.df <- data.frame()
for( i in 1:nrow(Original.df)){
  a1 <- Original.df$col1
  a2 <- Original.df$col2
  a3 <- Original.df$col3
  # Use data.table library "join" functionality to get matches (will find at least 1 and up to 4 matches, usually only 1 or 2)
  match.df <- data.frame(LookHereForMatches.dt[J(a1, a2, a3)], stringsAsFactors=FALSE)

  # combine matches with original data and add to data.frame to create big list of data with matches
  matched_data.df <- rbind(cbind(match.df, Original.df[i,], stringsAsFactors=FALSE), matched_data.df)
}

更新

这大致是数据的样子。 (显然是R和StackExchange的新手。我会弄清楚如何使表更漂亮并回来修复它。感谢@joran修复我的表。)这些表是非常基本的东西。我只想找到第一个表中的每一行,并将它与a1,a2和a3上第二个表中的所有相应行匹配。在该示例中,Original.df的第一行应该与LookHereForMatches.dt表中的行1,2和3配对,返回3行。

Original.df <- read.table(textConnection('
a1  a2  a3  text.field  numeric.field
123 abc 2011-12-01  "some text"    1.0 
124 abc 2011-11-12  "some other text"  0.1 
125 bcd 2011-12-01  "more text"   1.2
'), header=TRUE)

LookHereForMatches.df <- read.table(textConnection('
a1  a2  a3  text.field  numeric.field   Status_Ind   
123 abc 2011-12-01  "some text"    10.5   0
123 abc 2011-12-01  "different text"   0.1    1
123 abc 2011-12-01  "more text"    0.1    1
125 bcd 2011-12-01  "other text"   4.3    0
125 bcd 2011-12-01  "text"     2.2    0
'), header=TRUE)

LookHereForMatches.dt <- data.table(LookHereForMatches.df, key=c("a1","a2","a3"))

1 个答案:

答案 0 :(得分:3)

听起来merge会做你正在寻找的事情;有关详细信息,请参阅?merge

> merge(Original.df, LookHereForMatches.df, by=c("a1","a2","a3"))
   a1  a2         a3 text.field.x numeric.field.x   text.field.y
1 123 abc 2011-12-01    some text             1.0      some text
2 123 abc 2011-12-01    some text             1.0 different text
3 123 abc 2011-12-01    some text             1.0      more text
4 125 bcd 2011-12-01    more text             1.2     other text
5 125 bcd 2011-12-01    more text             1.2           text
  numeric.field.y Status_Ind
1            10.5          0
2             0.1          1
3             0.1          1
4             4.3          0
5             2.2          0

如果你想要更多控制,它在幕后使用match,如下所示:

a <- with(Original.df, paste(a1, a2, a3, sep="\b"))
b <- with(LookHereForMatches.df, paste(a1, a2, a3, sep="\b"))
m <- match(b, a)
cbind(Original.df[m,], LookHereForMatches.df)

同时查看all选项,以控制当两个数据集中都没有显示内容时的操作。

merge(Original.df, LookHereForMatches.df, by=c("a1","a2","a3"), all=TRUE)

对于大数据集的速度,你可以使用data.table获得一些加速,但每个都有1e5和3e5行(如下所示),在我的系统上,合并只需要2.6秒,匹配和cbind只有1.5秒。

set.seed(5)
N <- 1e5
Original.df <- data.frame(a1=1:N, a2=1, a3=1, text1=paste("hi",1:N))
LookHereForMatches.df <- data.frame(a1=sample(1:N, 3*N, replace=TRUE), 
                                    a2=1, a3=1, text2=paste("hi", 1:(3*N)))