ループ演算とベクトル演算
一般的なプログラミング言語では、次のような構文がよく使用されます。
※例:a_1 = 1, a_2 = 2, ... という数列をつくり、a_1+a_2,a_2+a_3,...という数列を計算する
コード断片(C#)
//初期化
int[] a = new a[20000];
for(int i = 0;i < 20000; i++){
a[i] = i;
}
//計算
int[] b = new b[20000];
for(int i = 0;i < 19999; i++){
b[i] = a[i] + a[i + 1];
}
これを、「愚直に」Rでやった場合には、次のようなソースになります。
loop.r
#初期化
df <- data.frame(a=1:20000)
#計算(aには1でアクセスできる)
for(i in 1:19999){
df[i,2] <- df[i,1] + df[i+1,1]
}
これは結構時間がかかります。
Rでは、配列についてforなどのループを明示的に記入するよりも、ベクトル演算を駆使した方が処理が速くなります。
vector.r
#初期化
df <- data.frame(a=1:20000)
#計算
df$b <- df$a + c(df$a[2:20000],1)
ポイントは、
・ベクトル演算は同じ長さでないと行えない
・df\$aは(1列)20000行のベクトル
・df\$a[2:20000]はdf\$aの2行目の要素から20000行目の要素までのベクトル
・df\$a[2:20000]の後ろに要素を一つ追加するためにcを利用する
といったところです。
性能比較
性能の比較をするために、次のようなコードを実行してみます。
test.r
df <- data.frame(a=1:20000)
print("for loop test")
date()
for(i in 1:19999){
df[i,2] <- df[i,1]+df[i+1,1]
}
date()
print("vector test")
df$b <- df$a + c(df$a[2:20000],1)
date()
print("test was over")
実行結果
[1] "for loop test"
[1] "Sat Oct 17 17:11:43 2015"
[1] "Sat Oct 17 17:11:45 2015"
[1] "vector test"
[1] "Sat Oct 17 17:11:45 2015"
[1] "test was over"
forでループする処理では2秒程度の処理時間がかかっていますが、vectorの場合は1秒未満であることがわかります。(core i5 4300U)
いまは20000個でテストしていますが、100000個になると、forのものは数分応答無し、vectorのものは相変わらず一瞬で応答があります。
ということで、ベクトル演算を有効活用しましょう。