6

私はRで古典的な分割-適用-再結合を行っています.私のデータセットは、時間の経過とともに多くの企業です. 私が行っている適用は、企業ごとに回帰を実行し、残差を返すことです。したがって、企業ごとに集計していません。 plyrこれには優れていますが、会社の数が多いと実行に非常に長い時間がかかります。これを行う方法はありdata.tableますか?

サンプルデータ:

dte, id, val1, val2
2001-10-02, 1, 10, 25
2001-10-03, 1, 11, 24
2001-10-04, 1, 12, 23
2001-10-02, 2, 13, 22
2001-10-03, 2, 14, 21

各 ID (つまり、1 と 2) で分割する必要があります。回帰を実行し、残差を返し、それを列としてデータに追加します。を使用してこれを行う方法はありdata.tableますか?

4

2 に答える 2

8

DWinの答えはv1.8.0で正しいです(現在CRAN上にあるように)。しかし、v1.8.1 (R-Forge リポジトリ上) では、:=グループ単位で動作するようになりました。setkey連続していないグループでも機能するため、最初に並べる必要はありません。

dtb <- as.data.table(dat)
dtb
           dte id val1 val2
1:  2001-10-02  1   10   25
2:  2001-10-03  1   11   24
3:  2001-10-04  1   12   23
4:  2001-10-02  2   13   22
5:  2001-10-03  2   14   21
dtb[, resid:=residuals(lm(val1 ~ val2)), by=id]
           dte id val1 val2         resid
1:  2001-10-02  1   10   25  1.631688e-15
2:  2001-10-03  1   11   24 -3.263376e-15
3:  2001-10-04  1   12   23  1.631688e-15
4:  2001-10-02  2   13   22  0.000000e+00
5:  2001-10-03  2   14   21  0.000000e+00

v1.8.1 にアップグレードするには、R-Forge リポジトリからインストールするだけです。(R-Forge からバイナリ パッケージをインストールする場合は、R 2.15.0+ が必要です):

install.packages("data.table", repos="http://R-Forge.R-project.org")

または、最新の R にアップグレードできない場合は、ソースからインストールします。 data.tableそれ自体には、R 2.12.0+ のみが必要です。

1MM ケースへの拡張:

DT = data.table(dte=Sys.Date()+1:1000000, 
                id=sample(1:2, 1000000, repl=TRUE),
                val1=runif(1000000),  val2=runif(1000000) )
setkey(DT, id)
system.time(ans1 <- cbind(DT, DT[, residuals(lm(val1 ~ val2)), by="id"]) )
   user  system elapsed 
 12.272   0.872  13.182 
ans1
                dte id      val1       val2 id           V1
      1: 2012-07-02  1 0.8369147 0.57553383  1  0.336647598
      2: 2012-07-05  1 0.0109102 0.02532214  1 -0.488633325
      3: 2012-07-06  1 0.4977762 0.16607786  1 -0.001952414
     ---                                                   
 999998: 4750-05-27  2 0.1296722 0.62645838  2 -0.370627034
 999999: 4750-05-28  2 0.2686352 0.04890710  2 -0.231952238
1000000: 4750-05-29  2 0.9981029 0.91626787  2  0.497948275

system.time(DT[, resid:=residuals(lm(val1 ~ val2)), by=id])
   user  system elapsed 
  7.436   0.648   8.107 
DT
                dte id      val1       val2        resid
      1: 2012-07-02  1 0.8369147 0.57553383  0.336647598
      2: 2012-07-05  1 0.0109102 0.02532214 -0.488633325
      3: 2012-07-06  1 0.4977762 0.16607786 -0.001952414
     ---                                                
 999998: 4750-05-27  2 0.1296722 0.62645838 -0.370627034
 999999: 4750-05-28  2 0.2686352 0.04890710 -0.231952238
1000000: 4750-05-29  2 0.9981029 0.91626787  0.497948275

上記の例には 2 つのグループしかなく、40MB 未満と非常に小さくRprof、時間の 96% が で費やされていることを示していlmます。したがって、これらの場合:=、グループごとは実際には速度の利点ではなく、利便性のためです。つまり、記述する必要のあるコードが少なくなり、余分な列が出力に追加されなくなります。サイズが大きくなるにつれて、コピーの回避が必要になり、速度の利点が現れ始めます。特にtransforminjは、グループ数が増えるほど遅くなります。

于 2012-07-01T17:06:15.183 に答える
6

正しく並べるには、これを「id」で並べ替える必要があると思います。幸いなことに、これはキーを設定すると自動的に行われます。

dat <-read.table(text="dte, id, val1, val2
 2001-10-02, 1, 10, 25
 2001-10-03, 1, 11, 24
 2001-10-04, 1, 12, 23
 2001-10-02, 2, 13, 22
 2001-10-03, 2, 14, 21
 ", header=TRUE, sep=",")
 dtb <- data.table(dat)
 setkey(dtb, "id")
 dtb[, residuals(lm(val1 ~ val2)), by="id"]
#---------------
cbind(dtb, dtb[, residuals(lm(val1 ~ val2)), by="id"])
#---------------
            dte id val1 val2 id.1            V1
[1,] 2001-10-02  1   10   25    1  1.631688e-15
[2,] 2001-10-03  1   11   24    1 -3.263376e-15
[3,] 2001-10-04  1   12   23    1  1.631688e-15
[4,] 2001-10-02  2   13   22    2  0.000000e+00
[5,] 2001-10-03  2   14   21    2  0.000000e+00



> dat <- data.frame(dte=Sys.Date()+1:1000000, 
                    id=sample(1:2, 1000000, repl=TRUE),  
                    val1=runif(1000000),  val2=runif(1000000) )
> dtb <- data.table(dat)
> setkey(dtb, "id")
> system.time(  cbind(dtb, dtb[, residuals(lm(val1 ~ val2)), by="id"]) )
   user  system elapsed 
  1.696   0.798   2.466 
> system.time( dtb[,transform(.SD,r = residuals(lm(val1~val2))),by = "id"] )
   user  system elapsed 
  1.757   0.908   2.690 

マシューからの編集:これは、CRANのv1.8.0ではすべて正しいです。data.table wikiポイント2の主題である小さな追加でtransform、 「スピードのために、後でグループごとにしないでください」。ただし、v1.8.1ではグループごとに機能するようになり、シンプルかつ高速になりました。説明のために私の答えを参照してください(ただし、投票する必要はありません)。jtransform()cbind():=

さて、私はそれに投票しました。Macにv1.8.1をインストールするためのコンソールコマンドは次のとおりです(適切なXCodeツールが利用できる場合は、ソースにのみ存在するため)。

install.packages("data.table", repos= "http://R-Forge.R-project.org", type="source", 
               lib="/Library/Frameworks/R.framework/Versions/2.14/Resources/lib")

(何らかの理由で、Mac GUIパッケージインストーラーにr-forgeをリポジトリとして読み取らせることができませんでした。)

于 2012-07-01T03:32:11.873 に答える