julia で、n×m の Array で平均等の計算の速度を上げる方法
先日、juliaDB は、早いという話しを書きました。しかしながら、Array を、しっかりと使いこなすと、Array はとても早いです。
先日の DataFrame を作ってみましょう。
julia> df = DataFrame(
col1 = randn(10^5),
col2 = randn(10^5),
col3 = randn(10^5)
);
この DataFrame の横方向の合計等を調べようというお話しです。
単純に、横方向の合計を求める場合は、まず、Array に変換して、sum(A::Array,2) とするだけで良いようです。
julia 1.0 の人は、sum(A::Array, dims=2) なので注意です。
julia> A = Array(df);
julia> sum(A,2) # julia 1.0 のひとは、"sum(A, dims=2)" です
100000×1 Array{Float64,2}:
0.339824
-0.711329
5.8185
-1.94555
0.535156
-0.670403
-1.56872
0.534236
-1.98732
-2.90369
⋮
略
これで1撃です。mean(), std()なども、この方法が使えます。
では、先日の関数、
julia> function summary_row(df::DataFrame)
array_selected = Array(df[collect(df[:,2].>0) .& collect(df[:,2].>0),:])
row_sum=Array{Float64,1}[]
row_mean=Array{Float64,1}[]
for i in 1:size(array_selected)[1]
if i==1
row_sum = sum(array_selected[i,:])
row_mean = mean(array_selected[i,:])
else
row_sum = vcat(row_sum, sum(array_selected[i,:]) )
row_mean = vcat(row_mean, mean(array_selected[i,:]) )
end
end
return DataFrame(sum=row_sum, mean=row_mean)
end
上記のかなり正直な組み方だと、10秒以上かかっていました。個人的には、現在、一番時間を取るのは、vcat() のところだと考えています。
これを組み変えてみます。
function summary_row_A(df::DataFrame)
array_selected = Array(df[collect(df[:,2].>0) .& collect(df[:,2].>0),:])
row_sum = sum(array_selected, 2)
row_mean = mean(array_selected, 2)
row_std = std(array_selected, 2)
return DataFrame(sum=row_sum[1:end], mean=row_mean[1:end], std=row_std[1:end])
end
こうなります。
では、これを動かしてみましょう。
julia> @time summary_row_A(df); 0.075172 seconds (18.31 k allocations: 6.151 MiB) julia> @time summary_row_A(df); 0.007241 seconds (220 allocations: 5.213 MiB)
すばらしく早くなりました。Array の使い方は難しいですね。
では、10^6 個に増やしてやってみます。
julia> df = DataFrame(
col1 = randn(10^6),
col2 = randn(10^6),
col3 = randn(10^6)
);
julia> @time summary_row_A(df);
0.099327 seconds (223 allocations: 51.933 MiB, 30.86% gc time)
julia> @time summary_row_A(df);
0.213423 seconds (223 allocations: 51.933 MiB, 68.19% gc time)
julia> @time summary_row_A(df);
0.071288 seconds (223 allocations: 51.933 MiB, 16.10% gc time)
とても早いです。
ようやく julia 1.0.0 の公式マニュアルから mean() などで、計算の方向が2番目の引数で指定できることが記載されるようになりました。しかし、こうも、Array と DataFrame で速度が異ると、どうしても csv 形式で保存したい時以外は、Array のまま、列名は別の Array か Dictionary でも良いか? なんて気になってしまいます。