3

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列)のすべてのレコードを検索し、統計からも取得した特定のタイムスタンプに従って最大評価を取得します。

4

4 に答える 4

6

私は大好きplyrで、Hadley Wickhamによって作成されたツールのほとんどが大好きですが、特にIDフィールドで分割しようとしている場合は、非常に遅くなる可能性があります。これが起こったとき、私はに目を向けsqldfます。私は通常20倍のスピードアップを得る。

最初に使用する必要があるのは、タイプが詰まっているlubridateためです。sqldfPOSIXlt

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")
于 2013-01-11T22:09:14.137 に答える
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))に追加するか、マッピングを作成するために1回使用する必要があり、速度が低下します。as.character()r[[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
})

if不一致がないことがわかっている場合は、を削除することもできます。

于 2013-01-11T19:37:02.083 に答える
3

同じ結果を得るために別のアプローチを使用しましたが、提供された回答に投票しました

マージデータセットでは、最初に条件付きの日付よりも古い日付を削除してから、次のように実行します。

aggregate (rating ~ id+primeid+period+user, data=new_stats, FUN = max)
于 2013-01-11T20:20:14.513 に答える
1

データ構造の観点からは、2つのテーブルをマージしてから、split-group-applyメソッドを実行する必要があるようです。

どの行がどの行に属しているかをループで確認する代わりに、2つのテーブルをマージして(SQLのJOINステートメントのように)、「aaply」タイプのメソッドを実行できます。'plyr'ライブラリをダウンロードすることをお勧めします。

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/ 。

于 2013-01-11T18:06:52.830 に答える