2

Excel で非常に単純な配列数式を使用していくつかのデータセットを処理していますが、計算を更新するたびにデータセットが大きくなりすぎて、コンピューターのパフォーマンスが完全に破壊されています。

Excel シートと MySQL データベースは次のように配置されています。

+-Timestamp-+-value-+
| 1340816430|  .02  |
---------------------

x600,000 行

以下がエクセルの数式です。

{=AVERAGEIFS(B:B,A:A,"<"&A1+1000,A:A,">"&A1-1000)}

これは値の平均を返し、Excel シートの 3 番目の列です。同様の操作を実行し、Excel の数式を実行した場合に 3 番目の列にあった値を含む列を返す MySQL クエリを作成するもっともらしい方法はありますか?

4

4 に答える 4

4

Excel の数式を使用することに満足している場合は、この計算を大幅に高速化できます (私のシステムでは 3000 倍以上)。列 A に ASCENDING ORDER のタイムスタンプが含まれ、列 B に値が含まれていると仮定します (まだ並べ替えられていない場合は、Excel の並べ替えを使用します)。
列 C に =IFERROR(MATCH(A1-1000,$A:$A,1),1) を入力し、下にコピーします。これは、1000 タイムスタンプを引いた行の行番号を計算します。
列 D に =IFERROR(MATCH(A1+1000,$A:$A,1),1048576) を入力し、下にコピーします。これにより、行番号 1000 のタイムスタンプがさらに計算されます。
列 E に =AVERAGE(OFFSET(B1,C1-ROW(),0,D1-C1+1,1)) を入力し、下にコピーします。これにより、最初の行から最後の行までのサブセット範囲の平均が計算されます。

私のシステムでは、これは 20 秒で 1000K 行を完全に計算します。
この方法の欠点は、揮発性であるため、変更を加えるたびに再計算されることですが、とにかく手動計算モードになっていると想定しています。

于 2012-07-09T14:07:39.560 に答える
2

MySQL コード:

select
  a.timestamp t1,
  avg(x.value) average_value
from
  mydata a inner join (
    select 
      timestamp, 
      value
    from mydata
    ) x
    on x.timestamp between a.timestamp - 1000 and a.timestamp + 1000
group by 
  a.timestamp
order by
  t1
;

Excel のオーバーヘッドがなければ、これははるかに優れたパフォーマンスを発揮すると思いますが、60 万行で超高速になるとは約束できません。あなたは間違いなく索引付けしたいと思うでしょうTimestamp。私が作成したSQL Fiddleも参照してください。

于 2012-07-08T22:29:54.360 に答える
0

@Peter必要に応じて、Excelを使い続けることができます。http://xllarray.codeplex.comを使用してください。求める式は です=AVERAGE(ARRAY.MASK((A:A>A1 + 1000)*(A:A<A1 - 1000), B:B)。ジャンキーなラップトップで 100 万行を 1 秒以内に計算します。配列数式として必ず Ctrl-Shift-Enter を押してください。

コードをビルドしたくない場合は、SkyDrive からアドインとヘルプ ファイルを取得できます: http://sdrv.ms/JtaMIV

于 2012-07-09T18:26:28.180 に答える
0

@チャールズ。いいえ。1式のみです。仕様を読み違える。

計算を C++ にプッシュして xll として公開する場合は、次のようにします。

#include <algorithm>
#include <numeric>
#include "xll/xll.h"

using namespace xll;

typedef traits<XLOPER12>::xword xword;

static AddIn12 xai_windowed_average(
    L"?xll_windowed_average", XLL_FP12 XLL_FP12 XLL_FP12 XLL_DOUBLE12,
    L"WINDOWED.AVERAGE", L"Time, Value, Window"
);
_FP12* WINAPI
xll_windowed_average(_FP12* pt, _FP12* pv, double dt)
{
#pragma XLLEXPORT
static xll::FP12 a(size(*pt), 1);

double* bt0 = &pt->array[0];
double* bv0 = &pv->array[0];
double* bt = std::lower_bound(begin(*pt), end(*pt), *bt0 - dt);
double* et = std::lower_bound(begin(*pt), end(*pt), *bt0 + dt);

for (xword i = 0; i < size(*pt); ++i) {
    a[i] = (bt == et) ? 0 : std::accumulate(bv0 + (bt - bt0), bv0 + (et - bt0), 0)/(et - bt); 

    // update the window
    bt = std::lower_bound(bt, end(*pt), pt->array[i] - dt);
    et = std::lower_bound(bt, end(*pt), pt->array[i] + dt);
}

return a.get();
}   
于 2012-07-10T14:33:40.180 に答える