Main Content

matlab.tall.reduce

データ ブロックへの削減アルゴリズムの適用による配列の削減

説明

tA = matlab.tall.reduce(fcn,reducefcn,tX) は関数 fcn を配列 tX の各ブロックに適用し、結果の一部を生成します。次に、この関数は、1 つの最終結果 tA が得られるまで reducefcn を結果の一部の垂直連結に繰り返し適用します。

tA = matlab.tall.reduce(fcn,reducefcn,tX,tY,...) は、fcn への入力である複数の配列 tX,tY,... を指定します。各配列の同じ行は、fcn(tX(n:m,:),tY(n:m,:)) など、fcn によって演算されます。高さ 1 の入力はすべての fcn の呼び出しに渡されます。この構文では、fcn は 1 つの出力を返さなければなりません。また、reducefcn は 1 つの入力を受け入れて 1 つの出力を返さなければなりません。

[tA,tB,...] = matlab.tall.reduce(fcn,reducefcn,tX,tY,...) (ここで、fcnreducefcn は複数の出力を返す関数) は、それぞれが fcnreducefcn の出力引数のいずれかに対応する配列 tA,tB,... を返します。この構文には以下の要件があります。

  • fcnmatlab.tall.reduce から要求された出力と同じ数の出力を返さなければならない。

  • reducefcnmatlab.tall.reduce から要求された出力と同じ数の入力および出力をもたなければならない。

  • fcnreducefcn の各出力は、最初の入力 tX と同じタイプでなければならない。

  • fcnreducefcn の対応する出力は同じ高さでなければならない。

[tA,tB,...] = matlab.tall.reduce(___,'OutputsLike',{PA,PB,...}) は出力 tA,tB,... にプロトタイプ配列 PA,PB,... と同じデータ型をそれぞれ指定します。前述の構文にある任意の入力引数の組み合わせが使用できます。

すべて折りたたむ

tall table を作成し、table から tall ベクトルを抽出して、ベクトル内の要素の合計数を求めます。

airlinesmall.csv データ セットの tall table を作成します。このデータには米国のフライトの到着時刻と出発時刻に関する情報が含まれています。変数 ArrDelay を抽出します。これは到着遅延のベクトルです。

ds = tabularTextDatastore('airlinesmall.csv','TreatAsMissing','NA');
ds.SelectedVariableNames = {'ArrDelay' 'DepDelay'};
tt = tall(ds);
tX = tt.ArrDelay;

matlab.tall.reduce を使用して tall ベクトル内の非 NaN 要素の合計数をカウントします。最初の関数 numel はデータの各ブロックにある要素数をカウントし、2 番目の関数 sum は各ブロックのカウントすべてを合計してスカラーの結果を生成します。

s = matlab.tall.reduce(@numel,@sum,tX)
s =

  MxNx... tall double array

    ?    ?    ?    ...
    ?    ?    ?    ...
    ?    ?    ?    ...
    :    :    :
    :    :    :

結果をメモリに収集します。

s = gather(s)
Evaluating tall expression using the Local MATLAB Session:
- Pass 1 of 1: Completed in 0.66 sec
Evaluation completed in 0.81 sec
s = 123523

tall table を作成し、その table から 2 つの tall ベクトルを抽出してから各ベクトルの平均値を計算します。

airlinesmall.csv データ セットの tall table を作成します。このデータには米国のフライトの到着時刻と出発時刻に関する情報が含まれています。変数 ArrDelayDepDelay を抽出します。これらは到着遅延時間と出発遅延時間のベクトルです。

ds = tabularTextDatastore('airlinesmall.csv','TreatAsMissing','NA');
ds.SelectedVariableNames = {'ArrDelay' 'DepDelay'};
tt = tall(ds);
tt = rmmissing(tt);
tX = tt.ArrDelay;
tY = tt.DepDelay;

アルゴリズムの最初の段階では、ベクトル内の各データ ブロックの合計と要素数を計算します。このために、2 つの入力を受け入れ、各入力の合計と要素数を含む 1 つの出力を返す関数を作成できます。この関数は、ローカル関数として例の最後にリストされています。

function bx = sumcount(tx,ty)
  bx = [sum(tx) numel(tx) sum(ty) numel(ty)];
end

アルゴリズムの削減段階では、中間の合計と要素数をすべて合算する必要があります。したがって、matlab.tall.reduce は、各入力ベクトルの要素全体の合計と要素数を返すため、平均の計算は単純な除算になります。この段階で、最初の段階で得られた 1 行 4 列のベクトル出力の最初の次元に関数 sum を適用できます。

 reducefcn = @(x) sum(x,1);
 s = matlab.tall.reduce(@sumcount,reducefcn,tX,tY)
s =

  MxNx... tall double array

    ?    ?    ?    ...
    ?    ?    ?    ...
    ?    ?    ?    ...
    :    :    :
    :    :    :
 s = gather(s)
Evaluating tall expression using the Local MATLAB Session:
- Pass 1 of 1: Completed in 1.3 sec
Evaluation completed in 1.5 sec
s = 1×4

      860584      120866      982764      120866

s の最初の 2 つの要素は tX の合計と要素数で、2 番目の 2 つの要素は tY の合計と要素数です。これらの合計を要素数で除算することにより平均値が得られ、関数 mean によって返される答えと比較できます。

 my_mean = [s(1)/s(2) s(3)/s(4)]
my_mean = 1×2

    7.1201    8.1310

 m = gather(mean([tX tY]))
Evaluating tall expression using the Local MATLAB Session:
- Pass 1 of 1: Completed in 0.29 sec
Evaluation completed in 0.39 sec
m = 1×2

    7.1201    8.1310

ローカル関数

以下に、中間の合計と要素数を計算するために matlab.tall.reduce が呼び出す関数 sumcount を示します。

function bx = sumcount(tx,ty)
  bx = [sum(tx) numel(tx) sum(ty) numel(ty)];
end

tall table を作成し、そのデータで各年の平均フライト遅延時間を計算します。

airlinesmall.csv データ セットの tall table を作成します。このデータには米国のフライトの到着時刻と出発時刻に関する情報が含まれています。table から欠損データの行を削除し、変数 ArrDelay、変数 DepDelay、および変数 Year を抽出します。これらの変数は、到着遅延と出発遅延のベクトルと、データ セット上でフライトごとに関連付けられた年のベクトルです。

ds = tabularTextDatastore('airlinesmall.csv','TreatAsMissing','NA');
ds.SelectedVariableNames = {'ArrDelay' 'DepDelay' 'Year'};
tt = tall(ds);
tt = rmmissing(tt);

matlab.tall.reduce を使用して 2 つの関数を tall table に適用します。最初の関数は変数 ArrDelay と変数 DepDelay を結合して、各フライトの合計平均遅延時間を求めます。関数は、データの各チャンクにある一意の年の数を特定してから、各年を繰り返し処理し、その年のフライトの平均合計遅延時間を計算します。この結果、年と平均合計遅延時間が含まれる 2 変数テーブルが得られます。この中間データは、年あたりの平均遅延時間になるようにさらに削減する必要があります。この関数を現在のフォルダーに transform_fcn.m として保存します。

type transform_fcn
function t = transform_fcn(a,b,c)
ii = gather(unique(c));

for k = 1:length(ii)
    jj = (c == ii(k));
    d = mean([a(jj) b(jj)], 2);
    
    if k == 1
        t = table(c(jj),d,'VariableNames',{'Year' 'MeanDelay'});
    else
        t = [t; table(c(jj),d,'VariableNames',{'Year' 'MeanDelay'})];
    end
end

end

2 番目の関数は最初の関数の結果を使用して、各年の平均合計遅延時間を計算します。reduce_fcn からの出力は transform_fcn からの出力と互換性があるため、データのブロックは任意の順番で連結でき、各年につき 1 行のみになるまで継続的に削減できます。

type reduce_fcn
function TT = reduce_fcn(t)
[groups,Y] = findgroups(t.Year);
D = splitapply(@mean, t.MeanDelay, groups);

TT = table(Y,D,'VariableNames',{'Year' 'MeanDelay'});
end

変換関数と reduce 関数を tall ベクトルに適用します。入力 (double 型) と出力 (table 型) には異なるデータ型があるため、'OutputsLike' の名前と値のペアを使用して出力が table であることを指定します。出力の型を指定する簡単な方法は、ダミー入力を使用した変換関数の呼び出しです。

a = tt.ArrDelay;
b = tt.DepDelay;
c = tt.Year;
d1 = matlab.tall.reduce(@transform_fcn, @reduce_fcn, a, b, c, 'OutputsLike',{transform_fcn(0,0,0)})
d1 =

  Mx2 tall table

    Year    MeanDelay
    ____    _________

     ?          ?    
     ?          ?    
     ?          ?    
     :          :
     :          :

結果をメモリに収集して、年あたりの平均合計フライト遅延時間を確認します。

d1 = gather(d1)
Evaluating tall expression using the Local MATLAB Session:
- Pass 1 of 1: Completed in 1.2 sec
Evaluation completed in 1.4 sec
d1=22×2 table
    Year    MeanDelay
    ____    _________

    1987     7.6889  
    1988     6.7918  
    1989     8.0757  
    1990     7.1548  
    1991     4.0134  
    1992     5.1767  
    1993     5.4941  
    1994     6.0303  
    1995     8.4284  
    1996     9.6981  
    1997     8.4346  
    1998     8.3789  
    1999     8.9121  
    2000     10.595  
    2001     6.8975  
    2002     3.4325  
      ⋮

別のアプローチ

同じ統計をグループ別に計算する別の方法は、splitapply を使用して matlab.tall.reduce を呼び出すことです (matlab.tall.reduce を使用して splitapply を呼び出すのではなく)。

このアプローチを使用して、findgroupssplitapply をデータに対して直接呼び出します。データの各グループで演算を行う関数 mySplitFcn には matlab.tall.reduce への呼び出しが含まれます。matlab.tall.reduce に採用される変換関数と reduce 関数はデータをグループ化する必要がないため、これらの関数は splitapply によって渡される、事前にグループ化されたデータで計算を実行するだけです。

type mySplitFcn
function T = mySplitFcn(a,b,c)
T = matlab.tall.reduce(@non_group_transform_fcn, @non_group_reduce_fcn, ...
    a, b, c, 'OutputsLike', {non_group_transform_fcn(0,0,0)});

    function t = non_group_transform_fcn(a,b,c)
        d = mean([a b], 2);
        t = table(c,d,'VariableNames',{'Year' 'MeanDelay'});
    end

    function TT = non_group_reduce_fcn(t)
        D = mean(t.MeanDelay);
        TT = table(t.Year(1),D,'VariableNames',{'Year' 'MeanDelay'});
    end

end

findgroupssplitapply を呼び出してデータで演算を行い、mySplitFcn をデータの各グループに適用します。

groups = findgroups(c);
d2 = splitapply(@mySplitFcn, a, b, c, groups);
d2 = gather(d2)
Evaluating tall expression using the Local MATLAB Session:
- Pass 1 of 2: Completed in 0.59 sec
- Pass 2 of 2: Completed in 1.1 sec
Evaluation completed in 2.4 sec
d2=22×2 table
    Year    MeanDelay
    ____    _________

    1987     7.6889  
    1988     6.7918  
    1989     8.0757  
    1990     7.1548  
    1991     4.0134  
    1992     5.1767  
    1993     5.4941  
    1994     6.0303  
    1995     8.4284  
    1996     9.6981  
    1997     8.4346  
    1998     8.3789  
    1999     8.9121  
    2000     10.595  
    2001     6.8975  
    2002     3.4325  
      ⋮

重みのベクトルを使用して、tall 配列の重み付け標準偏差と分散を計算します。これは、matlab.tall.reduce を使用して tall 配列でまだサポートされていない機能を回避する一例です。

ランダム データの 2 つの tall ベクトルを作成します。tX にはランダム データ、tP には対応する確率 (sum(tP)1 など) が含まれます。これらの確率はデータへの重み付けに適しています。

rng default
tX = tall(rand(1e4,1));
p = rand(1e4,1);
tP = tall(normalize(p,'scale',sum(p)));

入力と等しい出力を返す関数 identity を記述します。このアプローチは、matlab.tall.reduce の変換ステップを省略し、データ サイズ削減のためにリダクション関数が繰り返し適用される、削減ステップに直接データを渡します。

type identityTransform.m
function [A,B] = identityTransform(X,Y)
  A = X;
  B = Y;
end

次に、tall ベクトルのブロックで演算を行うリダクション関数を記述し、重み付け分散と標準偏差を計算します。

type weightedStats.m
function [wvar, wstd] = weightedStats(X, P)
  wvar = var(X,P);
  wstd = std(X,P);
end

matlab.tall.reduce を使用してこれらの関数を tall ベクトルでデータのブロックに適用します。

[tX_var_weighted, tX_std_weighted] = matlab.tall.reduce(@identityTransform, @weightedStats, tX, tP)
tX_var_weighted =

  MxNx... tall double array

    ?    ?    ?    ...
    ?    ?    ?    ...
    ?    ?    ?    ...
    :    :    :
    :    :    :


tX_std_weighted =

  MxNx... tall double array

    ?    ?    ?    ...
    ?    ?    ?    ...
    ?    ?    ?    ...
    :    :    :
    :    :    :

入力引数

すべて折りたたむ

適用する変換関数。関数ハンドルまたは無名関数として指定します。fcn の各出力は最初の入力 tX と同じタイプでなければなりません。'OutputsLike' オプションを使用してさまざまなデータ型の出力を返すことができます。fcn が複数の出力を返す場合、それらの出力はすべて同じ高さをもたなければなりません。

fcn の一般的な関数シグネチャは、次のとおりです。

[a, b, c, ...] = fcn(x, y, z, ...)
fcn は以下の要件を満たさなければなりません。

  1. 入力引数 — 入力 [x, y, z, ...] は、メモリに収まるデータのブロックです。ブロックは、tall 配列の入力 [tX, tY, tZ, ...] それぞれからデータを抽出することによって生成されます。入力 [x, y, z, ...] は次の特性を満たします。

    • [x, y, z, ...] はすべて、任意の可能な拡張後の最初の次元が同じサイズをもつ。

    • [x, y, z, ...] のデータ ブロックは、tall 配列の tall 次元が 1 ではないと仮定した場合、tall 次元の同じインデックスから得られる。たとえば、tXtY の tall 次元が 1 ではない場合、ブロックの最初のセットは x = tX(1:20000,:) および y = tY(1:20000,:) になる可能性があります。

    • [tX, tY, tZ, ...] のいずれかの最初の次元がサイズ 1 である場合、対応するブロック [x, y, z, ...] は、その tall 配列内のすべてのデータで構成される。

  2. 出力引数 — 出力 [a, b, c, ...] はメモリに収まるブロックで、それぞれの出力 [tA, tB, tC, ...] に送信されます。出力 [a, b, c, ...] は以下の特性を満たします。

    • [a, b, c, ...] はすべて、最初の次元が同じサイズでなければならない。

    • [a, b, c, ...] はすべて、fcn の以前の呼び出しの結果とそれぞれ垂直方向に連結される。

    • [a, b, c, ...] はすべて、それぞれの出力先で、出力配列の最初の次元にある同じインデックスに送信される。

  3. 関数ルールfcn は関数ルールを満たさなければなりません。

    • F([inputs1; inputs2]) == [F(inputs1); F(inputs2)]:入力の連結に関数を適用することは、入力に関数を個別に適用してから結果を連結する場合と同じでなければならない。

  4. 空の入力fcn が高さ 0 の入力を処理できることを確認します。空の入力は、ファイルが空の場合や、データに対して数多くのフィルター処理を行った場合に発生することがあります。

たとえば、この関数は 2 つの入力配列を受け入れて、二乗し、2 つの出力配列を返します。

function [xx,yy] = sqInputs(x,y)
xx = x.^2;
yy = y.^2;
end 
この関数をアクセス可能なフォルダーに保存した後、この関数を呼び出して tXtY を二乗し、次のコマンドで最大値を求めることができます。
tA = matlab.tall.reduce(@sqInputs, @max, tX, tY)

例: tC = matlab.tall.reduce(@numel,@sum,tX,tY) は、各ブロック内の要素数を検出し、結果を合計して要素の合計数をカウントします。

データ型: function_handle

適用するリダクション関数。関数ハンドルまたは無名関数として指定します。reducefcn の各出力は最初の入力 tX と同じタイプでなければなりません。'OutputsLike' オプションを使用してさまざまなデータ型の出力を返すことができます。reducefcn が複数の出力を返す場合、それらの出力はすべて同じ高さをもたなければなりません。

reducefcn の一般的な関数シグネチャは、次のとおりです。

[rA, rB, rC, ...] = reducefcn(a, b, c, ...)
reducefcn は以下の要件を満たさなければなりません。

  1. 入力引数 — 入力 [a, b, c, ...] はメモリに収まるブロックです。データのブロックは、fcn によって返される出力か、さらなる縮小のために再度処理される、ある程度縮小された reducefcn からの出力のいずれかです。入力 [a, b, c, ...] は次の特性を満たします。

    • 入力 [a, b, c, ...] は、最初の次元が同じサイズとなる。

    • 最初の次元の特定インデックスについて、データ [a, b, c, ...] のブロックの各行は入力から派生するか、または reducefcn に対する以前の同じ呼び出しから派生する。

    • 最初の次元の特定インデックスについて、そのインデックスの入力 [a, b, c, ...] の各行は、最初の次元の同じインデックスから派生する。

  2. 出力引数 — すべての出力 [rA, rB, rC, ...] は、最初の次元が同じサイズでなければなりません。さらに、必要に応じて縮小を繰り返すことができるように、それぞれの入力 [a, b, c, ...] と垂直方向に結合可能でなければなりません。

  3. 関数ルールreducefcn は、以下の関数ルールを満たさなければなりません (丸め誤差を除く)。

    • F(input) == F(F(input)):同じ入力に繰り返し関数を適用しても、結果が変わってはならない。

    • F([input1; input2]) == F([input2; input1]):結果が、連結の順序に依存することがあってはならない。

    • F([input1; input2]) == F([F(input1); F(input2)]):いくつかの中間結果の連結に関数を 1 回適用することは、それを別々に適用し、連結し、再び適用することと同じでなければならない。

  4. 空の入力reducefcn が高さ 0 の入力を処理できることを確認します。空の入力は、ファイルが空の場合や、データに対して数多くのフィルター処理を行った場合に発生することがあります。この呼び出しでは、すべての入力ブロックは、最初の次元以外で正しい型とサイズをもつ空の配列となります。

適切なリダクション関数の例には、sumprodmax などの組み込みの次元リダクション関数があります。これらの関数は fcn で生成された中間結果を操作し、single スカラーを返すことができます。これらの関数には、連結の行われる順序とリダクション演算の適用回数によって最終的な答えは変化しないという特性があります。meanvar などの一部の関数は、リダクション演算の適用回数によって最終的な答えが変化する可能性があるため、通常はリダクション関数として使用しないでください。

例: tC = matlab.tall.reduce(@numel,@sum,tX) は、各ブロック内の要素数を検出し、結果を合計して要素の合計数をカウントします。

データ型: function_handle

入力配列。スカラー、ベクトル、行列または多次元配列として指定します。入力配列は変換関数 fcn の入力として使用されます。各入力配列 tX,tY,... の高さに互換性がなければなりません。高さが同じであるか、一方の入力が高さ 1 である場合、2 つの入力の高さは互換性があります。

出力配列のプロトタイプ。配列として指定します。'OutputsLike' を指定する場合、matlab.tall.reduce で返される出力配列 tA,tB,... は、指定した配列 {PA,PB,...} と同じデータ型と属性をもちます。

例: tA = matlab.tall.reduce(fcn,reducefcn,tX,'OutputsLike',{int8(1)}); の場合、tX は倍精度 tall 配列であり、tAdouble ではなく int8 として返します。

出力引数

すべて折りたたむ

出力配列。スカラー、ベクトル、行列、または多次元配列として返されます。matlab.tall.reduce へのいずれかの入力が tall の場合、すべての出力引数も tall となります。それ以外の場合、すべての出力引数はインメモリ配列になります。

出力配列のサイズとデータ型は指定した関数 fcnreducefcn によって異なります。一般的に、出力 tA,tB,... はすべて、最初の入力 tX と同じデータ型をもたなければなりません。ただし、'OutputsLike' を指定して異なるデータ型を返すことができます。出力配列 tA,tB,... はすべて同じ高さをもちます。

詳細

すべて折りたたむ

tall 配列ブロック

データストアから tall 配列を作成すると、基となるデータストアによって、計算中のデータの移動が容易になります。データは "ブロック" または "チャンク" と呼ばれる別々の要素に分かれて移動します。各ブロックはメモリに収容可能な連続する行のセットです。たとえば、2 次元配列の 1 ブロック (table など) は、一部の添字 n および m について X(n:m,:) です。各ブロックのサイズはデータストアの ReadSize プロパティの値に基づいていますが、ブロックは厳密にそのサイズではない場合があります。matlab.tall.reduce の目的において、tall 配列は該当する多くのブロックの垂直連結であるとみなされます。

Illustration of an array broken into vertical blocks.

たとえば、関数 sum を変換関数として使用する場合、中間結果は "ブロックごとの" 合計になります。そのため、要素の合計として単一のスカラー値を返すのではなく、結果はブロック数と等しい長さをもつベクトルになります。

ds = tabularTextDatastore('airlinesmall.csv','TreatAsMissing','NA');
ds.SelectedVariableNames = {'ArrDelay' 'DepDelay'};
tt = tall(ds);
tX = tt.ArrDelay;

f = @(x) sum(x,'omitnan');
s = matlab.tall.reduce(f, @(x) x, tX);
s = gather(s)
s =

      140467
      101065
      164355
      135920
      111182
      186274
       21321

バージョン履歴

R2018b で導入