11

私は32gのRAMを搭載した64ビットのmatlabを使用しています(ご存知のとおり)。

130 万個の数値 (整数) のファイル (ベクトル) があります。同じ長さの別のベクトルを作成したいのですが、各ポイントは最初のベクトル全体の加重平均であり、その位置からの逆距離で加重されています(実際には、^-1ではなく位置^-0.1ですが、例として) . 現在のポイントより前のものしか平均化できないため、matlab の「フィルター」関数を使用できません。より明確に説明するために、3 つの要素の例を次に示します。

data = [ 2 6 9 ]
weights = [ 1 1/2 1/3; 1/2 1 1/2; 1/3 1/2 1 ]
results=data*weights= [ 8 11.5 12.666 ]
i.e.
8 = 2*1 + 6*1/2 + 9*1/3
11.5 = 2*1/2 + 6*1 + 9*1/2
12.666 = 2*1/3 + 6*1/2 + 9*1

したがって、新しいベクトルの各ポイントは、最初のベクトル全体の加重平均であり、1/(その位置からの距離 + 1) で加重されます。

各ポイントの重みベクトルを作り直して、要素ごとに結果ベクトルを計算することもできますが、これには for ループの 130 万回の反復が必要で、それぞれに 130 万回の乗算が含まれます。1x1.3mil を 1.3milx1.3mil で乗算する単純な行列乗算を使用したいと思いますが、これは理論的には機能しますが、それほど大きな行列をロードすることはできません。

次に、シェル スクリプトを使用してマトリックスを作成し、matlab でインデックスを作成しようとしています。これにより、マトリックスの関連する列のみが一度に呼び出されますが、これにも非常に長い時間がかかります。

私はこれをmatlabで行う必要はないので、このような多数の数値を利用して平均を取得することについて人々が持っているアドバイスをいただければ幸いです。^-1 ではなく ^-0.1 の重みを使用しているため、それほど速くは落ちません。元のポイントの重み付け 1 と比較して、100 万番目のポイントはまだ 0.25 に重み付けされているため、単純にカットすることはできません。大きくなったらオフ。

これが十分に明確だったことを願っていますか?

以下の回答のコードは次のとおりです(書式設定できますか?):

data = load('/Users/mmanary/Documents/test/insertion.txt');
data=data.';
total=length(data);
x=1:total;
datapad=[zeros(1,total) data];
weights = ([(total+1):-1:2 1:total]).^(-.4);
weights = weights/sum(weights);
Fdata = fft(datapad);
Fweights = fft(weights);
Fresults = Fdata .* Fweights;
results = ifft(Fresults);
results = results(1:total);
plot(x,results)
4

5 に答える 5

11

これを行う唯一の賢明な方法は、関数などを支えるFFT convolutionを使用することです。filter手動で行うのは非常に簡単です。

% Simulate some data
n = 10^6;
x = randi(10,1,n);
xpad = [zeros(1,n) x];

% Setup smoothing kernel
k = 1 ./ [(n+1):-1:2 1:n];

% FFT convolution
Fx = fft(xpad);
Fk = fft(k);

Fxk = Fx .* Fk;

xk = ifft(Fxk);
xk = xk(1:n);

の所要時間は 0.5 秒未満ですn=10^6

于 2011-10-25T07:40:47.503 に答える
3

これはおそらく最善の方法ではありませんが、大量のメモリがあればプロセスを確実に並列化できます。

i^(-1)元の行列の値(ここで)を持つエントリで構成されるスパース行列を作成i = 1 .. 1.3 millionし、それらを元のベクトルで乗算し、すべての結果を合計することができます。

したがって、あなたの例では、製品は基本的に次のようになります。

a = rand(3,1);
b1 = [1 0 0;
      0 1 0;
      0 0 1];
b2 = [0 1 0;
      1 0 1;
      0 1 0] / 2;
b3 = [0 0 1;
      0 0 0;
      1 0 0] / 3;

c = sparse(b1) * a + sparse(b2) * a + sparse(b3) * a;

もちろん、この方法で疎行列を構築することはありません。内部ループの繰り返しを少なくしたい場合はi、各行列に複数の を含めることができます。

MATLABでparforループを調べます: http://www.mathworks.com/help/toolbox/distcomp/parfor.html

于 2011-10-25T05:37:46.340 に答える
2

I can't use matlab's 'filter' function, because it can only average things before the current point, right?

That is not correct. You can always add samples (i.e, adding or removing zeros) from your data or from the filtered data. Since filtering with filter (you can also use conv by the way) is a linear action, it won't change the result (it's like adding and removing zeros, which does nothing, and then filtering. Then linearity allows you to swap the order to add samples -> filter -> remove sample).

Anyway, in your example, you can take the averaging kernel to be:

weights = 1 ./ [3 2 1 2 3]; % this kernel introduces a delay of 2 samples

and then simply:

result =  filter(w,1,[data, zeros(1,3)]); % or conv (data, w)
% removing the delay introduced by the kernel
result = result (3:end-1);
于 2011-10-25T07:35:35.173 に答える
0

You considered only 2 options: Multiplying 1.3M*1.3M matrix with a vector once or multiplying 2 1.3M vectors 1.3M times.

But you can divide your weight matrix to as many sub-matrices as you wish and do a multiplication of n*1.3M matrix with the vector 1.3M/n times.

I assume that the fastest will be when there will be the smallest number of iterations and n is such that creates the largest sub-matrix that fits in your memory, without making your computer start swapping pages to your hard drive.

with your memory size you should start with n=5000.

you can also make it faster by using parfor (with n divided by the number of processors).

于 2011-10-25T07:35:51.897 に答える
0

力ずくの方法は、ミックスに 1 つのマイナーな最適化があれば、おそらくうまくいくでしょう。

重みを作成する ^-0.1 演算は、加重平均を計算する + および * 演算よりもはるかに時間がかかりますが、100 万回の加重平均演算すべてで重みを再利用します。アルゴリズムは次のようになります。

  • 計算に必要なすべての重みで重み付けベクトルを作成します。 weights = (-n:n).^-0.1

  • ベクトルの各要素について:

    • ベクトルの関連部分にインデックスを付けweightsて、現在の要素を「中心」と見なします。

    • 重み部分とベクトル全体で加重平均を実行します。これは、高速ベクトル ドット乗算の後にスカラー除算を行うことで実行できます。

メイン ループはn ^2 回の加算と減算を行います。nが 130 万に等しい場合、3.4 兆回の操作になります。最新の 3 GHz CPU のシングル コアは、1 秒間に 60 億回の加算/乗算を実行できるため、約 10 分かかります。ベクトルとオーバーヘッドのインデックス作成の時間を追加してweightsも、30 分以内に到着できると推定されます。

于 2011-10-25T07:43:18.460 に答える