8

次の問題をエレガントに解決する方法についての提案を探しています。私の特定のケースではパフォーマンスは問題ではありませんが、良い慣行に関するコメントをいただければ幸いです。

前もって感謝します!

短いバージョン:

NaN 値を無視しながら、いくつかのロジックに従って行列の行を平均化しようとしています。私が現在持っているコードは、NaN 値を希望どおりに処理しません。

長いバージョン:

私のデータは次の方法で構築されています。

  • 「ビン」の 1 つの (最初の) 列。各ビンの行数は一定ではありません。ビンは整数である必要はありません。行は事前にソートされています。
  • おそらく NaN を含む可変数のデータ列。

次に例を示します。

DATA = [...
180     NaN     NaN     1.733
180     NaN     NaN     1.703
200     0.720   2.117   1.738
200     0.706   2.073   1.722
200     0.693   2.025   1.723
200     NaN     NaN     1.729
210     NaN     NaN     1.820
210     NaN     NaN     1.813
210     NaN     NaN     1.805
240     NaN     NaN     1.951
240     NaN     NaN     1.946
240     NaN     NaN     1.946
270     NaN     NaN     2.061
270     NaN     NaN     2.052
300     0.754   2.356   2.103
300     0.758   2.342   2.057
300     NaN     NaN     2.066
300     NaN     NaN     2.066 ];

望ましい結果は、最初の列に一意の「ビン」を含む行列であり、残りは「NaN によって損なわれていない」ことを意味します。たとえば、次のようになります。

  • 特定の列 + ビンに NaN しかない場合 (上記の例では、最初のデータ列 + ビン 210)、結果は NaN になります。
  • 特定の列とビンに NaN と数値が混在している場合、結果は有効な数値の平均になります。上記の例: 1 番目のデータ列 + ビン 200 が与える必要があります(0.720+0.706+0.693)/3=0.7063-- この列 + ビンの 3 (4 ではなく) による除算に注意してください。

上記の例の望ましい結果は次のとおりです。

RES = [...
180     NaN     NaN     1.718
200     0.7063  2.072   1.728
210     NaN     NaN     1.812
240     NaN     NaN     1.948
270     NaN     NaN     2.056
300     0.756   2.349   2.074 ];

私がこれまでに試したこと:

これは、いくつかのソースからコンパイルできたコードです。NaNまたは数値のみを含む列+ビンでうまく機能しています。

nDataCols=size(DATA,2)-1;
[u,m,n] = unique(DATA(:,1));
sz = size(m);
N=accumarray(n,1,sz);

RES(length(u),nDataCols) = 0; %Preallocation

for ind1 = 1:nDataCols
    RES(:,ind1)=accumarray(n,DATA(:,ind1+1),sz)./N;
end

RES= [u,RES];

これが私が現在得ているものです:

RES = [...
180     NaN     NaN     1.718
200     NaN     NaN     1.728
210     NaN     NaN     1.812
240     NaN     NaN     1.948
270     NaN     NaN     2.056
300     NaN     NaN     2.074 ];

ps

  1. 万が一、スプレッドシート ソフトウェア (MS Excel など) を使用したほうが簡単な場合は、アイデアをお待ちしております。
  2. 列ごとに計算を行うことは、これを処理する方法に関する私の現在の考えです。完全なマトリックスをすぐに取得するために一般化する方法があるかどうか疑問に思っていました。
4

2 に答える 2

5

考えられるアプローチの 1 つ: 最初の列の変更を見つけ (事前に並べ替えられているという事実を利用して)、nanmean行の各ブロックに適用します。

ind = find(diff([-inf; (DATA(:,1)); inf])~=0); %// value changed: start of block
r = arrayfun(@(n) nanmean(DATA(ind(n):ind(n+1)-1,:)), 1:numel(ind)-1, 'uni', 0);
RES = vertcat(r{:});

arrayfun明示的なループに置き換えることができます。これはより高速である可能性があり、セルによって導入されるオーバーヘッドを回避します。

ind = find(diff([-inf; (DATA(:,1)); inf])~=0); %// value changed: start of block
RES = zeros(numel(ind)-1, size(DATA,2)); %// preallocate
for n = 1:numel(ind)-1 %// loop over blocks
    RES(n,:) = nanmean(DATA(ind(n):ind(n+1)-1,:));
end

あなたのアプローチも使用できます。accumarray関数のハンドルを指定して呼び出すだけですnanmean。これには、最初の列を事前に並べ替える必要はありません。

nDataCols = size(DATA,2)-1;
[u, ~, n] = unique(DATA(:,1));
RES = zeros(length(u), nDataCols); %// Preallocation
for ind1 = 1:nDataCols
    RES(:,ind1) = accumarray(n, DATA(:,ind1+1), [], @nanmean);
end
RES = [u, RES];
于 2014-07-13T15:38:17.850 に答える
0

これは別の解決策ですが、非常に非効率的です。また、出力配列はすべてのNaN値を 0 に設定します。これは学術研究に適しているとだけ言っておきましょう。私が行った手順は次のとおりです。

  1. 最初の列にある ID ごとに、一意のリストを見つけます。
  2. 他の列については、各列を cell 配列に分割します。
  3. このセル配列の各要素の最初の列が各列に追加される新しいセル配列を作成します
  4. NaN値を含む各セル配列の行をフィルターで除外します
  5. フィルタリングされた結果の列ごとに、関数ハンドルとして実行accumarrayします。mean
  6. ステップ 1 の ID を使用して、各accumarray結果にインデックスを付け、マトリックスに変換します。

%// Step #1
num = unique(DATA(:,1));

%// Step #2
cells = mat2cell(DATA, size(DATA,1), ones(size(DATA,2),1));

%// Step #3
cellsAppend = cellfun(@(x) [DATA(:,1) x], cells(2:end), 'uni', false);

%// Step #4
cellsNonNaN = cellfun(@(x) x(~isnan(x(:,2)),:), cellsAppend , 'uni', false);

%// Step #5
cellsMean = cellfun(@(x) accumarray(x(:,1), x(:,2), [], @mean), cellsNonNaN, 'uni', false);

%// Step #6
selectCells = cellfun(@(x) x(num), append3, 'uni', false);
RES = [num cell2mat(selectCells)];

結果は次のとおりです。

RES = 

180.0000         0         0    1.7180
200.0000    0.7063    2.0717    1.7280
210.0000         0         0    1.8127
240.0000         0         0    1.9477
270.0000         0         0    2.0565
300.0000    0.7560    2.3490    2.0730

ご覧のとおり、かなり非効率的です - 特にcellfun私が行った呼び出しの量では、しかしそれでも私が推測する学術的な例です!

于 2014-07-13T17:33:19.140 に答える