MySQLデータベースからデータを引き出し、バイナリ列のペアをデコードしてから、バイナリ列のペア内の行のサブセットを合計するプログラムがあります。サンプルデータセットでプログラムを実行するには12〜14秒かかり、そのうちの9〜10秒が。によって使用されunlist
ます。物事をスピードアップする方法はないかと思います。
テーブルの構造
データベースから取得している行は次のようになります。
| array_length | mz_array | intensity_array |
|--------------+-----------------+-----------------|
| 98 | 00c077e66340... | 002091c37240... |
| 74 | c04a7c7340... | db87734000... |
ここarray_length
で、は2つの配列のリトルエンディアンdoubleの数です(同じ長さであることが保証されています)。したがって、最初の行には、とのそれぞれに98のdoubleがmz_array
ありintensity_array
ます。array_length
平均は825、中央値は620、行数は13,000です。
バイナリ配列のデコード
各行は、次の関数に渡されることによってデコードされます。バイナリ配列がデコードされると、array_length
は不要になります。
DecodeSpectrum <- function(array_length, mz_array, intensity_array) {
sapply(list(mz_array=mz_array, intensity_array=intensity_array),
readBin,
what="double",
endian="little",
n=array_length)
}
配列の合計
次のステップは、の値を合計することですがintensity_array
、の対応するエントリがmz_array
特定のウィンドウ内にある場合に限ります。配列はmz_array
、昇順で並べ替えられます。次の関数を使用してintensity_array
値を合計しています。
SumInWindow <- function(spectrum, lower, upper) {
sum(spectrum[spectrum[,1] > lower & spectrum[,1] < upper, 2])
}
、、からのspectrum
出力はどこにありますか。DecodeSpectrum
matrix
行のリストを操作する
各行は次のように処理されます。
ProcessSegment <- function(spectra, window_bounds) {
lower <- window_bounds[1]
upper <- window_bounds[2]
## Decode a single spectrum and sum the intensities within the window.
SumDecode <- function (...) {
SumInWindow(DecodeSpectrum(...), lower, upper)
}
do.call("mapply", c(SumDecode, spectra))
}
ProcessSegment
そして最後に、行がフェッチされ、この関数で渡されます。
ProcessAllSegments <- function(conn, window_bounds) {
nextSeg <- function() odbcFetchRows(conn, max=batchSize, buffsize=batchSize)
while ((res <- nextSeg())$stat == 1 && res$data[[1]] > 0) {
print(ProcessSegment(res$data, window_bounds))
}
}
Rがデータセット全体を一度にメモリにロードする必要がないように、セグメントでフェッチを実行しています(メモリ不足エラーが発生していました)。ドライバーは(私が知る限り)汚されていないバイナリ値を返すことができないRODBC
ため、私はドライバーを使用してい
ます。RMySQL
パフォーマンス
約140MiBのサンプルデータセットの場合、プロセス全体が完了するまでに約14秒かかります。これは、13,000行の場合はそれほど悪くありません。Rprof
それでも、特に出力を見ると、改善の余地があると思います。
$by.self
self.time self.pct total.time total.pct
"unlist" 10.26 69.99 10.30 70.26
"SumInWindow" 1.06 7.23 13.92 94.95
"mapply" 0.48 3.27 14.44 98.50
"as.vector" 0.44 3.00 10.60 72.31
"array" 0.40 2.73 0.40 2.73
"FUN" 0.40 2.73 0.40 2.73
"list" 0.30 2.05 0.30 2.05
"<" 0.22 1.50 0.22 1.50
"unique" 0.18 1.23 0.36 2.46
">" 0.18 1.23 0.18 1.23
".Call" 0.16 1.09 0.16 1.09
"lapply" 0.14 0.95 0.86 5.87
"simplify2array" 0.10 0.68 11.48 78.31
"&" 0.10 0.68 0.10 0.68
"sapply" 0.06 0.41 12.36 84.31
"c" 0.06 0.41 0.06 0.41
"is.factor" 0.04 0.27 0.04 0.27
"match.fun" 0.04 0.27 0.04 0.27
"<Anonymous>" 0.02 0.14 13.94 95.09
"unique.default" 0.02 0.14 0.06 0.41
$by.total
total.time total.pct self.time self.pct
"ProcessAllSegments" 14.66 100.00 0.00 0.00
"do.call" 14.50 98.91 0.00 0.00
"ProcessSegment" 14.50 98.91 0.00 0.00
"mapply" 14.44 98.50 0.48 3.27
"<Anonymous>" 13.94 95.09 0.02 0.14
"SumInWindow" 13.92 94.95 1.06 7.23
"sapply" 12.36 84.31 0.06 0.41
"DecodeSpectrum" 12.36 84.31 0.00 0.00
"simplify2array" 11.48 78.31 0.10 0.68
"as.vector" 10.60 72.31 0.44 3.00
"unlist" 10.30 70.26 10.26 69.99
"lapply" 0.86 5.87 0.14 0.95
"array" 0.40 2.73 0.40 2.73
"FUN" 0.40 2.73 0.40 2.73
"unique" 0.36 2.46 0.18 1.23
"list" 0.30 2.05 0.30 2.05
"<" 0.22 1.50 0.22 1.50
">" 0.18 1.23 0.18 1.23
".Call" 0.16 1.09 0.16 1.09
"nextSeg" 0.16 1.09 0.00 0.00
"odbcFetchRows" 0.16 1.09 0.00 0.00
"&" 0.10 0.68 0.10 0.68
"c" 0.06 0.41 0.06 0.41
"unique.default" 0.06 0.41 0.02 0.14
"is.factor" 0.04 0.27 0.04 0.27
"match.fun" 0.04 0.27 0.04 0.27
$sample.interval
[1] 0.02
$sampling.time
[1] 14.66
unlist
こんなに時間がかかるのを見て驚いています。これは、冗長なコピーまたは再配置が行われている可能性があることを私に伝えています。私はRが初めてなので、これは正常である可能性は十分にありますが、明らかに間違っていることがあるかどうかを知りたいと思います。
更新:投稿されたサンプルデータ
プログラムのフルバージョンとここで使用するサンプルデータを
ここに投稿しまし
た。サンプルデータは、からの
gzip
ed出力ですmysqldump
。スクリプトがデータベースに接続するには、適切な環境変数を設定する必要があります。
MZDB_HOST
MZDB_DB
MZDB_USER
MZDB_PW
スクリプトを実行するには、run_id
とウィンドウの境界を指定する必要があります。私はこのようにプログラムを実行します:
Rscript ChromatoGen.R -i 1 -m 600 -M 1200
これらのウィンドウ境界はかなり任意ですが、範囲の約2分の1から3分の1を選択します。結果を印刷する場合は、内print()
への呼び出しを囲みます。これらのパラメーターを使用すると、最初の5つは次のようになります。ProcessSegment
ProcessAllSegments
[1] 7139.682 4522.314 3435.512 5255.024 5947.999
画面に13,000の数字を表示したい場合を除いて、結果の数を制限したい場合があります:)最も簡単な方法はLIMIT 5
、の最後に追加することですquery
。