查找匹配并追加到data.frame的更快方法?
我有代码工作。但速度很慢,我希望能够加快速度,这样我就可以扩展到几十万个观察值的数据集。查找匹配并追加到data.frame的更快方法?
我有两个数据帧,其中一个我使用data.table包转换为data.table包以便快速查找和连接。当3个字段与第二个数据集中的记录相匹配时,我想记录一个数据集中的记录。
Original.df(数据框)和LookHereForMatches.dt(带有a1,a2,a3上的键的data.table)。 Original.df将有10万到30万的观察值,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)
}
UPDATE
这里是大致的数据是什么样子。 (显然是R和StackExchange上的新手
我会弄清楚如何使表更漂亮并回来解决这个问题。
感谢@joran修复我的表。)表是非常基本的东西。我只想查找第一个表中的每一行,并将其与第一个表a1,a2和a3中所有适当的行进行匹配。在该示例中,来自Original.df的第一行应该与返回3行的LookHereForMatches.dt表中的行1,行2和行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"))
听起来像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秒和匹配和只需要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)))
谢谢。而已。后缀= c(“_ first”,“_ second”)或者与之相近的东西也有助于命名。仍尝试百分之%。但是这似乎有诀窍。我会在测试时发布一些时间细节,并让它们正常工作。 – user791770 2012-04-24 02:52:30
我仍然不完全清楚cbind如何正确匹配行,但由于merge()让我得到我需要去的地方,我会坚持。 时间: original.df中1,000行; LookHereForMatches.df中的3,000行 merge():0.015; for循环:3.1 10,000行; 30,000行 merge():0.25;循环74秒。 – user791770 2012-04-24 03:31:47
因为我不知道你的数据是什么样子,原谅我,如果这没有帮助......如果你能提供数据的一个小样本,您将得到更好的答案。但是,你不能使用像条件匹配的东西吗? 'Origional.df [Origion.df $ a1%in%LookHereForMatchers.dt $ a1&Origional.df $ a2%in%LookHereForMatches.dt $ a2,]'。 'for循环'很慢,但'rbind(cbind(...))'慢得多。理想情况下,您可以在分配之前分配全尺寸的'matched_data.df'。如果你不能,使用像我上面写的东西应该可以帮助一些...... – Justin 2012-04-23 22:13:49
我不明白(也许是因为你没有提供一个可重复的例子?)为什么你不能简单地在data.table之间做一个连接。 – joran 2012-04-23 22:33:41
更新后添加一些示例数据。我会查看%in%。至于我无法在data.tables之间进行连接的原因...我是R新手。我也会考虑加入。 – user791770 2012-04-23 22:38:48