我必须使用2个数据帧200万条记录和另外200万条记录。我使用for循环来获取彼此的数据,但它太慢了。我已经创建了一个示例来演示我需要做什么。
ratings = data.frame(id = c(1,2,2,3,3),
rating = c(1,2,3,4,5),
timestamp = c("2006-11-07 15:33:57","2007-04-22 09:09:16","2010-07-16 19:47:45","2010-07-16 19:47:45","2006-10-29 04:49:05"))
stats = data.frame(primeid = c(1,1,1,2),
period = c(1,2,3,4),
user = c(1,1,2,3),
id = c(1,2,3,2),
timestamp = c("2011-07-01 00:00:00","2011-07-01 00:00:00","2011-07-01 00:00:00","2011-07-01 00:00:00"))
ratings$timestamp = strptime(ratings$timestamp, "%Y-%m-%d %H:%M:%S")
stats$timestamp = strptime(stats$timestamp, "%Y-%m-%d %H:%M:%S")
for (i in(1:nrow(stats)))
{
cat("Processing ",i," ...\r\n")
temp = ratings[ratings$id == stats$id[i],]
stats$idrating[i] = max(temp$rating[temp$timestamp < stats$timestamp[i]])
}
有人可以为我提供替代方案吗?我知道apply可能有用,但我不知道如何翻译for函数。
更新:谢谢你的帮助。我正在提供更多信息。
表统计信息具有primeid,period,user,id的唯一组合。 表评级具有多个具有不同评级和时间戳的id记录。
我想做的是以下内容。对于在统计数据中找到的每个ID,查找评级表(id列)中的所有记录,然后根据从统计数据获得的特定时间戳获得最大评级。
答案 0 :(得分:6)
我喜欢plyr
,以及Hadley Wickham创造的大多数工具,但我发现它可能会非常缓慢,特别是如果我试图分裂ID字段。发生这种情况时,我转向sqldf
。我的速度通常是20倍。
首先我需要使用lubridate
,因为sqldf
类型上的POSIXlt
窒息:
library(lubridate)
ratings$timestamp = ymd_hms(ratings$timestamp)
stats$timestamp = ymd_hms(stats$timestamp)
像Vincent一样合并数据帧,并删除违反日期约束的数据框:
tmp <- merge(stats, ratings, by="id")
tmp <- subset(tmp, timestamp.y < timestamp.x )
最后,获取每个ID的最高评级:
library(sqldf)
sqldf("SELECT *, MAX(rating) AS rating FROM tmp GROUP BY id")
答案 1 :(得分:4)
根据id
s与数据点的比率,这可能会更好:
r = split(ratings, ratings$id)
stats$idrating = sapply(seq.int(nrow(stats)), function(i) {
rd = r[[stats$id[i]]]
if (length(rd))
max(rd$rating[rd$timestamp < stats$timestamp[i]])
else NA
})
如果您的ID 不是连续的整数(您可以使用all(names(r) == seq_along(r))
进行检查),则在引用as.character()
或使用{时,您必须添加r[[
{1}}一旦创建映射,它将花费你一些速度。
显然,你可以在没有分割的情况下做同样的事情,但这通常会更慢,但会占用更少的内存:
match
如果您知道不存在不匹配,也可以删除stats$idrating = sapply(seq.int(nrow(stats)), function(i) {
rd = ratings[ratings$id == stats$id[i],]
if (nrow(rd))
max(rd$rating[rd$timestamp < stats$timestamp[i]])
else NA
})
。
答案 2 :(得分:3)
虽然我使用了另一种方法来获得相同的结果,但我投了答案
在合并数据集中,我首先删除了早于条件日期的日期,然后运行:
aggregate (rating ~ id+primeid+period+user, data=new_stats, FUN = max)
答案 3 :(得分:1)
从数据结构的角度来看,您似乎想要合并两个表,然后执行split-group-apply方法。
您可以简单地合并两个表(非常类似于SQL中的JOIN语句),而不是循环检查哪一行属于哪一行,然后执行&#39; aaply&#39;方法类型。我建议你下载&#39; plyr&#39;图书馆。
new_stats = merge(stats, ratings, by='id')
library(plyr)
ddply(new_stats,
c('primeid', 'period', 'user'),
function(new_stats)
c( max(new_stats[as.Date(new_stats$timestamp.x) > as.Date(new_stats$timestamp.y)]$rating )))
如果使用plyr让您感到困惑,请访问本教程:http://www.creatapreneur.com/2013/01/split-group-apply/。