分析するデータが大量にあるため、コードを記述するときに、単語や変数名の間にスペースを空ける傾向があります。問題は、効率が最優先事項である場合、空白にコストがかかるかどうかです。
c<-a+b は c <- a + b よりも効率的ですか?
分析するデータが大量にあるため、コードを記述するときに、単語や変数名の間にスペースを空ける傾向があります。問題は、効率が最優先事項である場合、空白にコストがかかるかどうかです。
c<-a+b は c <- a + b よりも効率的ですか?
1番目、2番目、3番目、...、概算、いいえ、まったく費用はかかりません。
スペースバーを押すのに費やす余分な時間は、実行時のコストよりも桁違いに高くなります(どちらも問題ではありません)。
スペースを省略した結果として読みやすさが低下すると、コードの解析が(人間にとって)困難になる可能性があるため、はるかに大きなコストが発生します。
一言で言えば、いや!
library(microbenchmark)
f1 <- function(x){
j <- rnorm( x , mean = 0 , sd = 1 ) ;
k <- j * 2 ;
return( k )
}
f2 <- function(x){j<-rnorm(x,mean=0,sd=1);k<-j*2;return(k)}
microbenchmark( f1(1e3) , f2(1e3) , times= 1e3 )
Unit: microseconds
expr min lq median uq max neval
f1(1000) 110.763 112.8430 113.554 114.319 677.996 1000
f2(1000) 110.386 112.6755 113.416 114.151 5717.811 1000
#Even more runs and longer sampling
microbenchmark( f1(1e4) , f2(1e4) , times= 1e4 )
Unit: milliseconds
expr min lq median uq max neval
f1(10000) 1.060010 1.074880 1.079174 1.083414 66.791782 10000
f2(10000) 1.058773 1.074186 1.078485 1.082866 7.491616 10000
式がループで実行される前に解析されるため、マイクロベンチマークの使用は不公平になるようです。ただし、使用source
するということは、反復ごとにソースコードを解析し、空白を削除する必要があることを意味します。そこで、関数を2つの別々のファイルに保存しました。ファイルの最後の行は関数の呼び出しです。たとえば、私のファイルf2.Rは次のようになります。
f2 <- function(x){j<-rnorm(x,mean=0,sd=1);k<-j*2;return(k)};f2(1e3)
そして、私はそれらを次のようにテストします:
microbenchmark( eval(source("~/Desktop/f2.R")) , eval(source("~/Desktop/f1.R")) , times = 1e3)
Unit: microseconds
expr min lq median uq max neval
eval(source("~/Desktop/f2.R")) 649.786 658.6225 663.6485 671.772 7025.662 1000
eval(source("~/Desktop/f1.R")) 687.023 697.2890 702.2315 710.111 19014.116 1000
そして、1e4レプリケーションとの違いを視覚的に表現します。
関数が繰り返し解析される状況では、おそらくそれはわずかな違いをもたらしますが、これは通常のユースケースでは発生しません。
TL;DR スクリプトを実行して空白を削除するだけで、空白を削除して節約できる時間よりも時間がかかる可能性があります。
@Josh O'Brienは本当に頭に釘を打ちました。しかし、私はベンチマークに抵抗できませんでした
ご覧のとおり、1 億行もの桁数を処理している場合、ごくわずかな障害が見られます。
しかしgrep
、それだけの数の行があると、少なくとも 1 つ (数百ではないにしても) のホットスポットである可能性が高くなり、これらの 1 つのコードを改善するだけで、すべての空白を削除する よりもはるかに高速になります。
library(microbenchmark)
microbenchmark(LottaSpace = eval(LottaSpace), NoSpace = eval(NoSpace), NormalSpace = eval(NormalSpace), times=10e7)
@ 100 times; Unit: microseconds
expr min lq median uq max
1 LottaSpace 7.526 7.9185 8.1065 8.4655 54.850
2 NormalSpace 7.504 7.9115 8.1465 8.5540 28.409
3 NoSpace 7.544 7.8645 8.0565 8.3270 12.241
@ 10,000 times; Unit: microseconds
expr min lq median uq max
1 LottaSpace 7.284 7.943 8.094 8.294 47888.24
2 NormalSpace 7.182 7.925 8.078 8.276 46318.20
3 NoSpace 7.246 7.921 8.073 8.271 48687.72
どこ:
LottaSpace <- quote({
a <- 3
b <- 4
c <- 5
for (i in 1:7)
i + i
})
NoSpace <- quote({
a<-3
b<-4
c<-5
for(i in 1:7)
i+i
})
NormalSpace <- quote({
a <- 3
b <- 4
c <- 5
for (i in 1:7)
i + i
})
これが影響する唯一の部分は、ソース コードのトークンへの解析です。解析時間の違いが大きくなるとは想像できません。ただし、パッケージのcompile
またはcmpfun
関数を使用して関数をコンパイルすることにより、この側面を排除できます。compiler
その後、解析は 1 回だけ行われ、空白の違いが実行時間に影響することはありません。
ただし、パフォーマンスに違いはありません。
fn1<-function(a,b) c<-a+b
fn2<-function(a,b) c <- a + b
library(rbenchmark)
> benchmark(fn1(1,2),fn2(1,2),replications=10000000)
test replications elapsed relative user.self sys.self user.child
1 fn1(1, 2) 10000000 53.87 1.212 53.4 0.37 NA
2 fn2(1, 2) 10000000 44.46 1.000 44.3 0.14 NA
と同じmicrobenchmark
:
Unit: nanoseconds
expr min lq median uq max neval
fn1(1, 2) 0 467 467 468 90397803 1e+07
fn2(1, 2) 0 467 467 468 85995868 1e+07
だから最初の結果は偽物だった..