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)