1

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出力はどこにありますか。DecodeSpectrummatrix

行のリストを操作する

各行は次のように処理されます。

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が初めてなので、これは正常である可能性は十分にありますが、明らかに間違っていることがあるかどうかを知りたいと思います。

更新:投稿されたサンプルデータ

プログラムのフルバージョンとここで使用するサンプルデータを ここに投稿しまし た。サンプルデータは、からの gziped出力です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つは次のようになります。ProcessSegmentProcessAllSegments

[1] 7139.682 4522.314 3435.512 5255.024 5947.999

画面に13,000の数字を表示したい場合を除いて、結果の数を制限したい場合があります:)最も簡単な方法はLIMIT 5、の最後に追加することですquery

4

1 に答える 1

0

私はそれを理解しました!

問題はsapply()電話にあった。sapplyこのサイズの配列では、かなりの量の名前変更とプロパティ設定が行われ、処理速度が大幅に低下します。次のコードに置き換えるDecodeSpectrumと、サンプル時間が14.66秒から秒に短縮され3.36、4倍になりました。

これがの新しい本体ですDecodeSpectrum

DecodeSpectrum <- function(array_length, mz_array, intensity_array) {
  ## needed to tell `vapply` how long the result should be. No, there isn't an
  ## easier way to do this.
  resultLength <- rep(1.0, array_length)

  vapply(list(mz_array=mz_array, intensity_array=intensity_array),
         readBin,
         resultLength,
         what="double",
         endian="little",
         n=array_length,
         USE.NAMES=FALSE)
}

出力は次のRprofようになります。

$by.self
               self.time self.pct total.time total.pct
"<Anonymous>"           0.64    19.75       2.14     66.05
"DecodeSpectrum"        0.46    14.20       1.12     34.57
".Call"                 0.42    12.96       0.42     12.96
"FUN"                   0.38    11.73       0.38     11.73
"&"                     0.16     4.94       0.16      4.94
">"                     0.14     4.32       0.14      4.32
"c"                     0.14     4.32       0.14      4.32
"list"                  0.14     4.32       0.14      4.32
"vapply"                0.12     3.70       0.66     20.37
"mapply"                0.10     3.09       2.54     78.40
"simplify2array"        0.10     3.09       0.30      9.26
"<"                     0.08     2.47       0.08      2.47
"t"                     0.04     1.23       2.72     83.95
"as.vector"             0.04     1.23       0.08      2.47
"unlist"                0.04     1.23       0.08      2.47
"lapply"                0.04     1.23       0.04      1.23
"unique.default"        0.04     1.23       0.04      1.23
"NextSegment"           0.02     0.62       0.50     15.43
"odbcFetchRows"         0.02     0.62       0.46     14.20
"unique"                0.02     0.62       0.10      3.09
"array"                 0.02     0.62       0.04      1.23
"attr"                  0.02     0.62       0.02      0.62
"match.fun"             0.02     0.62       0.02      0.62
"odbcValidChannel"      0.02     0.62       0.02      0.62
"parent.frame"          0.02     0.62       0.02      0.62

$by.total
                     total.time total.pct self.time self.pct
"ProcessAllSegments"       3.24    100.00      0.00     0.00
"t"                        2.72     83.95      0.04     1.23
"do.call"                  2.68     82.72      0.00     0.00
"mapply"                   2.54     78.40      0.10     3.09
"<Anonymous>"              2.14     66.05      0.64    19.75
"DecodeSpectrum"           1.12     34.57      0.46    14.20
"vapply"                   0.66     20.37      0.12     3.70
"NextSegment"              0.50     15.43      0.02     0.62
"odbcFetchRows"            0.46     14.20      0.02     0.62
".Call"                    0.42     12.96      0.42    12.96
"FUN"                      0.38     11.73      0.38    11.73
"simplify2array"           0.30      9.26      0.10     3.09
"&"                        0.16      4.94      0.16     4.94
">"                        0.14      4.32      0.14     4.32
"c"                        0.14      4.32      0.14     4.32
"list"                     0.14      4.32      0.14     4.32
"unique"                   0.10      3.09      0.02     0.62
"<"                        0.08      2.47      0.08     2.47
"as.vector"                0.08      2.47      0.04     1.23
"unlist"                   0.08      2.47      0.04     1.23
"lapply"                   0.04      1.23      0.04     1.23
"unique.default"           0.04      1.23      0.04     1.23
"array"                    0.04      1.23      0.02     0.62
"attr"                     0.02      0.62      0.02     0.62
"match.fun"                0.02      0.62      0.02     0.62
"odbcValidChannel"         0.02      0.62      0.02     0.62
"parent.frame"             0.02      0.62      0.02     0.62

$sample.interval
[1] 0.02

$sampling.time
[1] 3.24

通話をいじることでパフォーマンスが低下する可能性もありますがdo.call('mapply', ...)、時間を無駄にしたくないので、パフォーマンスには十分満足しています。

于 2012-07-26T17:28:29.270 に答える