4

私はこの金融取引のデータセットを持っています。かなり大きいですが、メモリに保持するには十分小さいです..

R> str(trans)
'data.frame':   130000000 obs. of  5 variables:
 $ id    : int  5 5 5 5 6 11 11 11 11 11 ...
 $ kod   : int  2 3 2 3 38 2 3 6 7 6 ...
 $ ar    : int  329 329 330 330 7 329 329 329 329 329 ...
 $ belopp: num  1531 -229.3 324 -48.9 0 ...
 $ datum : int  36976 36976 37287 37287 37961 36976 36976 37236 37236 37281 ...

一意の ID ごとにトランザクションを抽出してループし、一連の計算を行う必要があります。問題は、データセットのサブセット化が遅すぎることです..

R> system.time(
+ sub <- trans[trans$id==15,]
+ )
   user  system elapsed 
   7.80    0.55    8.36


R> system.time(
+ sub <- subset(trans, id == 15)
+ )
   user  system elapsed 
   8.49    1.05    9.53 

このデータセットには約 10m の一意の ID があるため、このようなループには永遠に時間がかかります。どうすれば高速化できるでしょうか?

EDIT 私は「data.tables」、インデックス作成、ソートに手を出しましたが、あまり運がありません..

library(data.table)
trans2 <- as.data.table(trans)
trans2 <- trans2[order(id)]
trans2 <- setkey(trans2, id)

R> system.time(
+ sub <- trans2[trans2$id==15,]
+ )
   user  system elapsed 
   7.33    1.08    8.41 

R> system.time(
+ sub <- subset(trans2, id == 15)
+ )
   user  system elapsed 
   8.66    1.12    9.78

EDIT2すごい。

R> system.time(
+ sub <- trans2[J(15)]
+ )
   user  system elapsed 
      0       0       0 
4

2 に答える 2

3

Note:投稿は、計算される関数を からrowSumsに変更して編集されましたcolSums( lapplydata.table の場合に使用)

よりも早く結果を得ることができるとは思いませんdata.tableplyrとの間のベンチマークは次のとおりdata.tableです。もちろん、時間のかかる部分が関数である場合は、を使用doMCして並列実行できますplyr(多数のコアがあるか、クラスターで作業していると仮定します)。そうでなければ、私はに固執しdata.tableます。これは、巨大なテスト データとダミー関数を使用した分析です。

# create a huge data.frame with repeating id values
len <- 1e5
reps <- sample(1:20, len, replace = TRUE)
x <- data.frame(id = rep(1:len, reps))
x <- transform(x, v1 = rnorm(nrow(x)), v2 = rnorm(nrow(x)))

> nrow(x) 
[1] 1048534 # 1 million rows

# construct functions for data.table and plyr
# method 1
# using data.table
DATA.TABLE <- function() {
    require(data.table)
    x.dt <- data.table(x, key="id")
    x.dt.out <- x.dt[, lapply(.SD, sum), by=id]
}

# method 2
# using plyr
PLYR <- function() {
    require(plyr)
    x.plyr.out <- ddply(x, .(id), colSums)
}

# let's benchmark
> require(rbenchmark)
> benchmark(DATA.TABLE(), PLYR(), order = "elapsed", replications = 1)[1:5]
          test replications elapsed relative user.self
1 DATA.TABLE()           1  1.006     1.00    .992
2       PLYR()           1  67.755   67.351  67.688

100 万行の data.framedata.tableでは0.992 secondsdata.tableを使用した場合と比較してplyr(確かに、列の合計を計算する際に)速度が向上します68x。関数の計算時間に応じて、この高速化は異なります。しかし、data.tableそれでもずっと速くなります。plyr分割適用結合戦略です。base を使用して自分で分割、適用、および結合する場合と比較して、同等のスピードアップが得られるとは思いません。もちろんお試しいただけます。

1,000 万行のコードを実行しました。data.table5.893秒で走りました。plyr6300秒かかりました。

于 2013-01-03T13:49:05.857 に答える
0

分割、適用、結合戦略を使用してみませんか?

このようなもの(サンプルデータがないと、これが機能するかどうかはわかりません):

fastsplit <- function (df) {
  lista <- split(seq(nrow(df)), df$id)
  return(lista)
}

# function to split the data frame into a list by id

lista_split <- fastsplit(trans)

# now, assuming that one of the calculations is, for instance, to sum belopp
# apply the function to each subset

result1 <- lapply(lista_split, function(.indx){

  sum_bellop = sum(trans$belopp[.indx])})

# combine stage
r1 <- do.call(rbind, result1)

上記のコードを提供したので、SQLを使用できれば、より速く、より簡単になると思います。たぶん、パッケージsqldfはここであなたを助けることができますか?私はそれを試したことはありません。速いかどうかわかりません。SQLのコードは非常に単純です。上記のRコードと同じことを行うには、次のようなものを使用します。

select id
       , sum(belopp) as sum_bellop from trans
group by id

これにより、idとidによるbeloppの合計の2つの列を持つテーブルが返されます。

于 2013-01-03T14:03:52.143 に答える