3

私は df を持っています:

head(df):

  Year              Asset1       Asset2        Asset3 Asset4    Asset5 
1 1857              1729900        32570       288482 1251642      0                     0     67374            89832
2 1858              1870213        35255       312262 1354817      0                     0     71948            95931
3 1859              1937622        36418       322562 1399505      0                     0     76773           102364
4 1860              1969257       207557        83393 1484403      0                     0     83102           110802
5 1861              2107481       222969        89585 1594627      0                     0     85843           114457
6 1862              2306227       235498        94619 1684234      0                     0     80613           211263

ddplyAsset 2:5 を Asset1 で割った新しい df を作成するために使用します。

dft<-ddply(df,.(Year),transform, 

              Asset2=Asset2/Asset1,
              Asset3=Asset3/Asset1,
              Asset4=Asset4/Asset1,
              Asset5=Asset5/Asset1)

しかし、多くのコラムがある場合、それは静かな仕事です...何か提案はありますか?

よろしくお願いします!

4

4 に答える 4

8

これは、次のようなものsweepです。

データの (変更された) バージョンを読み込みます。

m <- read.table(text = " Year              Asset1       Asset2        Asset3 Asset4    Asset5 
+  1857              1729900        32570       288482 1251642      0                     
+  1858              1870213        35255       312262 1354817      0                     
+  1859              1937622        36418       322562 1399505      0                     
+  1860              1969257       207557        83393 1484403      0                     
+  1861              2107481       222969        89585 1594627      0            
+  1862              2306227       235498        94619 1684234      0   ",header = TRUE,sep = "")
> m
  Year  Asset1 Asset2 Asset3  Asset4 Asset5
1 1857 1729900  32570 288482 1251642      0
2 1858 1870213  35255 312262 1354817      0
3 1859 1937622  36418 322562 1399505      0
4 1860 1969257 207557  83393 1484403      0
5 1861 2107481 222969  89585 1594627      0
6 1862 2306227 235498  94619 1684234      0


> m[,3:6] <- sweep(m[,3:6],1,m[,2],"/")
> m
  Year  Asset1     Asset2     Asset3    Asset4 Asset5
1 1857 1729900 0.01882768 0.16676224 0.7235343      0
2 1858 1870213 0.01885079 0.16696601 0.7244186      0
3 1859 1937622 0.01879520 0.16647313 0.7222797      0
4 1860 1969257 0.10539864 0.04234744 0.7537884      0
5 1861 2107481 0.10579882 0.04250809 0.7566507      0
6 1862 2306227 0.10211397 0.04102762 0.7302984      0
于 2012-10-16T15:15:51.753 に答える
5

2つlapplyの解決策があります。上記のソリューションに注目しましたが、ループは実際にはベクトル化されたソリューションよりも高速です。なんで?

編集:nograpesの回答を参照してください。

lapply解決:

m[, 3:6] <- do.call(cbind, lapply(m[, 3:6], function(x) x/m[, 2]))
m

そしてlapply2:

lapply(3:6, function(i) {
    m[, i] <<- m[, i]/m[, 2]
})

#   Year  Asset1     Asset2     Asset3    Asset4 Asset5
# 1 1857 1729900 0.01882768 0.16676224 0.7235343      0
# 2 1858 1870213 0.01885079 0.16696601 0.7244186      0
# 3 1859 1937622 0.01879520 0.16647313 0.7222797      0
# 4 1860 1969257 0.10539864 0.04234744 0.7537884      0
# 5 1861 2107481 0.10579882 0.04250809 0.7566507      0
# 6 1862 2306227 0.10211397 0.04102762 0.7302984      0

1000 回のレプリケーションを行う i7 Windows マシンでのマイクロベンチマークによるベンチング:

セットアップ:

LAPPLY <- function() {
    m[, 3:6] <- do.call(cbind, lapply(m[, 3:6], function(x) x/m[, 2]))
    m
}

LOOP <- function() {
    for(i in 3:ncol(m)) {
      m[ ,i] <- m[ , i]/m[ ,2]
    }
    m
}

SWEEP <- function(){
    m[,3:6] <- sweep(m[,3:6],1,m[,2],"/")
    m
}

LAPPLY2 <- function() {
    lapply(3:6, function(i) {
        m[, i] <<- m[, i]/m[, 2]
    })
        m
}

VECTORIZED <- function(){
    m[,3:6]<-m[,3:6] / m[,2]
    m
}

VECTORIZED2 <- function(){
    m[,3:6]<-unlist(m[,3:6])/m[,2]
    m
}

microbenchmark( 
    SWEEP(),
    LAPPLY(),
    LOOP(), 
    VECTORIZED(),
    VECTORIZED2(),
    LAPPLY2(),
    times=1000L)  

結果:

Unit: microseconds
           expr      min       lq    median        uq       max
1      LAPPLY() 7483.059 7577.758 7649.3655 7839.9290 41808.754
2     LAPPLY2()  563.061  602.713  618.3405  661.9585  7535.308
3        LOOP()  540.669  581.254  594.7820  626.5050 35505.929
4       SWEEP() 2544.735 2602.581 2645.9650 2735.5320  8335.814
5  VECTORIZED() 2409.452 2454.235 2494.5870 2585.5535 37313.134
6 VECTORIZED2() 8952.055 9063.081 9153.8150 9352.3085 45742.247

ここに画像の説明を入力

編集:インデックスを渡してlapplyグローバルに割り当てることでスピードアップしますが、これはとにかくループが行っていることです(lapply私が信じているループのラッパーです):

注: LAPPLY2 は m にグローバルな変更を行うため、最後にベンチマークする必要があります (LAPPLY2 の実行後に m をリセットする必要があります)。グローバル割り当てが危険な理由のデモンストレーション。

また、OP からのデータ フレームを 100 回 (nrow x 100) 繰り返して、ソリューションのより良いシミュレーションを行いました。

EDIT 37 partB: データ フレームを複製しない場合の結果と、データ フレームを複製する方法は次のとおりです。

# Unit: microseconds
#            expr     min       lq  median       uq       max
# 1      LAPPLY() 428.710 451.5680 468.362 485.6220  1497.452
# 2     LAPPLY2() 331.212 355.9365 368.532 386.7260  1361.235
# 3        LOOP() 326.547 355.0040 369.465 383.9260  1361.235
# 4       SWEEP() 828.497 868.1490 890.541 924.5950 31512.726
# 5  VECTORIZED() 764.587 809.8370 828.497 859.9855  3042.486
# 6 VECTORIZED2() 374.596 394.6560 408.884 424.0460  1399.954


dfdup <- function(dataframe, repeats=10){
    DF <- dataframe[rep(seq_len(nrow(dataframe)), repeats), ]
    rownames(DF) <-NULL
    DF
}

m <- dfdup(m, 100)

于 2012-10-16T15:36:54.193 に答える
2

私はこれが素晴らしく、読みやすい代替手段だと思います:

df[,3:6]<-df[,3:6] / df[,2]

もう少し読みやすくしたい場合は、次のことができます

df[,paste0('Asset',2:5)]<-df[,paste0('Asset',2:5)] / df[,'Asset1']

Ops.data.frame上記の関数は(私が思うに) に渡されるため遅いことがわかりました。それは遅いです。これを回避するには:

df[,3:6]<-unlist(df[,3:6])/df[,2]

しかし、それは他のループやlapplyバージョンと同じ速さしかありません。

于 2012-10-16T15:37:18.643 に答える
1

これは実際にddplyは意図されたものではなく、この場合は必要ありません。 ddply列の 1 つの値に基づいて、データ フレームを行に分割するのに適しています。通常、データ フレームの分割に使用する列 (この場合はYear) には、同じ値を持つ複数の行があります。

ここでは、ある列を別の列で分割しているだけです。これは次のように行うことができます。

df$Asset2 <- df$Asset2/df$Asset1 #more human-readable

また

df[ ,3] <- df[ ,3]/df[ ,2] #numbered columns are useful in loops

あなたが望むことを行うためのベクトル化された方法があると思いますが、速度が大きな問題でない限り、この計算をループするのは非常に簡単です:

#[hide under desk to avoid vectorization police]
for(i in 3:ncol(df) {
  df[ ,i] <- df[ , i]/df[ ,2]
}

IMO 列に比率が含まれているか元の値が含まれているかについて混乱しないように、列の名前を変更するか、古い列を保持して新しい列を作成することをお勧めします。新しい列を作成したい場合は、単に使用してくださいdf[ ,ncol(df)+1] <- df[ , i]/df[ ,2]

于 2012-10-16T15:02:55.090 に答える