をプログラムとして見たときに注意・検討すべきところを学んでおきたい、ということで
を読んでいく。
前回
14. パフォーマンス強化
プログラムで一般的な問題である時間と空間のトレードオフは、だと以下の理由からより一層関心が集まる:
14.1 高速なRコードの記述
コードを高速化するための主な方法は以下のとおりである:
ここでは1番目を取り上げる。
14.2 ループに対する恐れ
ループを回避するだけでは必ずしもパフォーマンス改善につながらないものの、ベクトル化によって劇的なパフォーマンス改善が図れる場合がある。
14.2.1 高速化のためのベクトル化
ループの代わりにベクトル化を用いることができる。
ループを用いると速度低下をもたらすのは、以下の原因がある:
- 構文上はループは無害のように見えるものの、では関数である。
- もまた関数である。
- ベクトルの添字演算は関数呼び出しを表しており、読込のための[]の呼び出しおよび書き込みの<-で関数呼び出しが生じる。
他にはおよび関数が改善に寄与し得る。
14.3 関数型プログラミングとメモリに関する問題
ほとんどのオブジェクトは不変である。そのため、の演算は特定のオブジェクトに再割り当てする関数として実装されており、パフォーマンスに影響がある。
14.3.1 ベクトル割り当ての問題
例として、ベクトルのある要素に値を割り当てる
z[3] <- 8 # これは正確にはz <- "[<-"(z,3,value=8)である
を考える。これは内部でをコピーし、コピーの要素をに変更し、その結果のベクトルをに再割り当てする。このように表面上はベクトルの1要素を変更しているにもかかわらず、内部的にはベクトル全体を再計算しているのに他ならない。
14.3.2 変更時コピーの問題
は(通常)「変更時コピー」という方針に従う。たとえば
y <- z
を実行すると、当初はと同じメモリ領域を共有する。しかしどちらかを変更すると、メモリの異なる領域にコピーが作成され、変更された変数は新しいメモリを占有する。しかし変更された変数のメモリを再配置すると共有問題が無くなるため、最初の変更のみが影響を受ける。はこうしたメモリ再配置を報告する。
# メモリ配置変更動作を行なわない例 z <- runif(10) tracemem(z) z[3] <- 8 tracemem(z)
14.4 Rprof()の動作
コードの動作が不必要に遅いと感じた場合、を用いる。
x <- runif(1000000) Rprof() invisible(powers1(x,8)) Rprof(NULL) summaryRprof()
14.5 バイトコードコンパイル
バイトコードコンパイラを用いると、コードの高速化を図ることができる。
# z <- x +yは # z[i] <- x[i] + y[i]よりも高速 library(compiler) f <- function() for (i in 1:length(x)) z[i] <<- x[i] + y[i] cf <- cmpfun(f) system.time(cf())
14.6 データがメモリに収まらない
はマシンのワードサイズ(32ビットか64ビットか)や要領にかかわらずオブジェクトのサイズをに制限している。しかし注意を払えば大量のメモリを必要とするアプリケーションにも適切に対応できる。
14.6.1 チャンキング
パッケージを追加する必要のないのは、ディスクファイルからデータを一度にチャンクとして読み込む方法である。たとえば変数の平均や割合を求めることが目的ならば、の引数を用いる。
14.6.2 メモリ管理のためのRパッケージ
やにより、大規模なデータに対して操作を行う方法がある。
またやにより、大規模なデータセットを用いる方法がある。