ドキュメンテーション

最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

ベクトル化

ベクトル化の使用

MATLAB® は、行列とベクトルに関する操作に最適化されています。ループベースでスカラー指向のコードを、MATLAB 行列とベクトル操作を使用するように変更するプロセスは "ベクトル化" と呼ばれます。コードのベクトル化の利点は次のとおりです。

  • 外観: ベクトル化された数学的なコードは教科書の数式のように示されるので、コードが理解しやすくなります。

  • エラーの発生が少ない: ループがないため、ベクトル化コードはたいてい短くなります。コード行が少ないほど、プログラミング エラーが発生することも少なくなります。

  • パフォーマンス: 多くの場合、ベクトル化コードはループを含む同等のコードよりはるかに高速で実行されます。

一般計算のベクトル化コード

このコードは、0 ~ 10 の範囲で 1,001 個の値の正弦値を計算します。

i = 0;
for t = 0:.01:10
    i = i + 1;
    y(i) = sin(t);
end

これは、同じコードをベクトル化したものです。

t = 0:.01:10;
y = sin(t);

2 番目のコード サンプルは通常、最初のコードよりも高速で実行されるので、MATLAB をより効率的に使用できます。表示されているコードを含んだスクリプトを作成してシステム上で実行速度をテストしてから、関数 tictoc を使用して実行時間を測定します。

特定タスクのベクトル化コード

このコードは、5 番目の要素ごとにベクトルの累積和を計算します。

x = 1:10000;
ylength = (length(x) - mod(length(x),5))/5;
y(1:ylength) = 0;
for n= 5:5:length(x)
    y(n/5) = sum(x(1:n));
end 

ベクトル化を使用すると、これよりもはるかに簡潔な MATLAB プロセスを記述できます。このコードは、タスクを達成する 1 つの方法を示します。

x = 1:10000;
xsums = cumsum(x);
y = xsums(5:5:length(x)); 

ベクトル化のインデックス方法

ベクトル化の手法の多くは、柔軟な MATLAB インデックス方法に依存しています。インデックスには、次のような 3 つの基本タイプがあります。

添字インデックス

添字インデックスでは、インデックス値は行列内の位置を示します。A = 6:10 の場合、A([3 5]) はベクトル A の 3 番目と 5 番目の要素を示します。

A = 6:10;
A([3 5])
ans =

     8    10

多次元配列または行列では、添字インデックスに複数のインデックス パラメーターを使用します。

A = [11 12 13; 14 15 16; 17 18 19]
A(2:3,2:3)
A =

    11    12    13
    14    15    16
    17    18    19


ans =

    15    16
    18    19

線形インデックス操作

線形インデックスでは、MATLAB は行列構造全体を 1 つの列ベクトルに引き伸ばしたものとして、行列の各要素に 1 つのインデックスを割り当てます。

A = [11 12 13; 14 15 16; 17 18 19];
A(6)
A([3,1,8])
A([3;1;8])
ans =

    18


ans =

    17    11    16


ans =

    17
    11
    16

前の例では、返された行列要素はインデックス パラメーターで指定された形状を維持しています。インデックス パラメーターが行ベクトルの場合、MATLAB は指定要素を行ベクトルとして返します。

    メモ:   関数 sub2indind2sub を使用して添字インデックスと線形インデックス間の変換を行います。

論理インデックス

論理インデックスでは、インデックス パラメーターは A と同じサイズで 0 と 1 のみを含む論理行列です。

MATLAB は、論理行列の対応する位置が 1 である A の要素を選択します。

A = [11 12 13; 14 15 16; 17 18 19];
A(logical([0 0 1; 0 1 0; 1 1 1]))
ans =

    17
    15
    18
    13
    19

配列演算

配列演算は、データセットのすべての要素に同じ演算を実行します。このタイプの演算は計算を反復して行う場合に便利です。たとえば、さまざまな円錐の直径 (D) と高さ (H) を記録してその体積 (V) を収集するとします。円錐の情報を 1 つだけ収集する場合、その 1 つの円錐の体積を計算できます。

V = 1/12*pi*(D^2)*H;

次は、10,000 個の円錐の情報を収集する場合です。ベクトル DH はそれぞれ 10,000 の要素を含んでおり、10,000 の体積を計算します。多くのプログラミング言語では、この MATLAB コードと同様のループを設定する必要があります。

for n = 1:10000
   V(n) = 1/12*pi*(D(n)^2)*H(n));
end

MATLAB では、スカラーの場合と同様の構文を使ってベクトルの各要素の計算を実行できます。

% Vectorized Calculation
V = 1/12*pi*(D.^2).*H;

    メモ:   演算子 */^ の前にピリオド (.) を入れると、配列演算子に変換されます。

論理配列演算

配列のバルク処理を論理拡張したものが、比較と判定のベクトル化です。MATLAB 比較演算子はベクトル入力を受け取り、ベクトル出力を返します。

たとえば、10,000 の円錐からデータを収集中に負の直径の値をいくつか記録したとします。>= 演算子を使って、ベクトルのどの値が有効な値かを判定できます。

D = [-0.2 1.0 1.5 3.0 -1.0 4.2 3.14];
D >= 0
ans =

     0     1     1     1     0     1     1
MATLAB の論理インデックスを直接使用して、対応する D の要素が非負である有効な円錐体積 Vgood を選別できます。
Vgood = V(D >= 0);

MATLAB では、関数 all および any をそれぞれ使用して、ベクトル全体の要素に論理 AND または論理 OR を実行できます。D のすべての値が 0 未満の場合、警告をスローできます。

if all(D < 0)
   warning('All values of diameter are negative.')
   return
end

MATLAB は同じサイズの 2 つのベクトルを比較できるので、それを使ってさらに制限を設けることができます。このコードは、V が非負で DH より大きいすべての値を検出します。

V((V >= 0) & (D > H))
結果のベクトルは入力と同じサイズになります。

比較を支援するため、MATLAB には infnan など、オーバーフロー、アンダーフロー、未定義演算子を示す特別な値があります。論理演算子 isinf および isnan は、これらの特別な値で論理テストを実行するのに役立ちます。たとえば、NaN 値を計算から除外した方が便利なことがよくあります。

x = [2 -1 0 3 NaN 2 NaN 11 4 Inf];
xvalid = x(~isnan(x))
xvalid =

     2    -1     0     3     2    11     4   Inf

    メモ:   Inf == Inf は真を返しますが、NaN == NaN は常に偽を返します。

行列演算

行列演算は、線形代数の規則に従って行われます。これらの演算は、多次元データで作業をしている場合、ベクトル化に非常に有用です。

2 つの変数 x および y をもつ関数 F を評価するとします。

F(x,y) = x*exp(-x2 - y2)

この関数を xy の点の各組み合わせで評価するには、値のグリッドを定義する必要があります。

x = -2:0.2:2;
y = -1.5:0.2:1.5;
[X,Y] = meshgrid(x,y);
F = X.*exp(-X.^2-Y.^2);
meshgrid を使用しないと、2 つの for ループを使用してベクトルの組み合わせの中で反復処理するコードを記述しなければならないかもしれません。関数 ndgrid もベクトルから数値グリッドを作成しますが、3 次元を超えるグリッドを作成することができます。meshgrid は 2 次元または 3 次元のグリッドしか作成できません。

場合によっては、行数の乗算を使用して数値グリッドの作成に必要な中間手順を除外できます。

x = -2:2;
y = -1:0.5:1;
x'*y
ans =

    2.0000    1.0000         0   -1.0000   -2.0000
    1.0000    0.5000         0   -0.5000   -1.0000
         0         0         0         0         0
   -1.0000   -0.5000         0    0.5000    1.0000
   -2.0000   -1.0000         0    1.0000    2.0000

行列の作成

コードをベクトル化するとき、行列を特定のサイズまたは構造で作成しなければならない場合があります。一様の行列を作成する手法があります。たとえば、同じ要素をもつ 5 行 5 列の行列が必要だとします。

A = ones(5,5)*10;
または、値を反復する行列が必要なこともあります。
v = 1:5;
A = repmat(v,3,1)
A =

     1     2     3     4     5
     1     2     3     4     5
     1     2     3     4     5

関数 repmat は、小さい行列またはベクトルから行列を作成する柔軟性をもち合わせています。repmat は入力行列を反復して行列を作成します。

A = repmat(1:3,5,2)
B = repmat([1 2; 3 4],2,2)
A =

     1     2     3     1     2     3
     1     2     3     1     2     3
     1     2     3     1     2     3
     1     2     3     1     2     3
     1     2     3     1     2     3


B =

     1     2     1     2
     3     4     3     4
     1     2     1     2
     3     4     3     4

関数 bsxfun は異なる次元の行列を組み合わせる方法を提供します。行列 A はテストの点数を表し、行でさまざまなクラスを示すものとします。各クラスの平均点と個人の点数の差を計算する場合、単純に A - mean(A) と差を計算すればいい、とまず思うかもしれません。しかし、行列のサイズが同じでないため、このコードを実行しようとすると MATLAB でエラーがスローされます。代わりに bsxfun を使用すると、同じサイズになる入力行列を明示的に再作成することなく、演算を実行します。

A = [97 89 84; 95 82 92; 64 80 99;76 77 67;...
 88 59 74; 78 66 87; 55 93 85];
dev = bsxfun(@minus,A,mean(A))
dev =

    18    11     0
    16     4     8
   -15     2    15
    -3    -1   -17
     9   -19   -10
    -1   -12     3
   -24    15     1

演算の順序、設定、カウント

多くのアプリケーションでは、ベクトル上の要素に行う計算は同じベクトル内の他の要素に依存します。たとえば、ベクトル x はセットを表すかもしれません。for ループまたは while ループを使用せずにセット内を反復する処理は、わかりにくくなります。ベクトル化コードを使用すると、プロセスはより明確になり、構文はより単純になります。

冗長要素の除外

ベクトルの冗長要素を見つけるには、さまざまな方法があります。1 つの方法は、関数 diff を使用することです。ベクトル要素を並べ替えた後、そのベクトル上で関数 diff を使用する場合、隣接する要素が等しいとゼロ要素が生成されます。diff(x)x より 1 つ少ない要素をもつベクトルを生成するので、他のどの要素とも等しくない要素をセットに追加しなければなりません。NaN は常にこの条件を満たします。最後に、論理インデックスを使用してセット内の一意の要素を選別します。

x = [2 1 2 2 3 1 3 2 1 3];
x = sort(x);
difference  = diff([x,NaN]);
y = x(difference~=0)
y =

     1     2     3
あるいは、関数 unique を使用しても同じ演算を行うことができます。
y=unique(x);
ただし、関数 unique には必要以上の機能が備えられているため、コード実行速度が遅くなる可能性があります。各コード スニペットのパフォーマンスを測定する場合は、関数 tictoc を使用します。

ベクトル内での要素のカウント

x のセットまたはサブセットを返すだけではなく、ベクトル内のある要素の出現回数をカウントできます。ベクトルを並べ替えた後、関数 find を使用して diff(x) でのゼロ値のインデックスを判定し、要素の値が変化した場所を示すことができます。関数 find から出力された後続のインデックス間の差は、特定要素の出現数を示します。

x = [2 1 2 2 3 1 3 2 1 3];
x = sort(x);
difference  = diff([x,max(x)+1]);
count = diff(find([1,difference]))
y = x(find(difference))
count =

     3     4     3


y =

     1     2     3
関数 findNaN 要素のインデックスを返しません。関数 isnanisinf を使用して、NaN および Inf 値の数をカウントできます。

count_nans = sum(isnan(x(:)));
count_infs = sum(isinf(x(:)));

ベクトル化でよく使用する関数

関数説明
allすべての要素がゼロ以外であるかを判定する
anyゼロ以外があるかどうかを判定
cumsum累積合計を求める
diff差分と近似導関数を求める
find非ゼロの要素のインデックスと値を求める
ind2sub線形インデックスから添字への変換
ipermute多次元配列の次元の並べ替えの逆操作
logical数値を論理値に変換
meshgrid3 次元プロットのための配列 XY の作成
ndgrid多次元関数や内挿用の配列の作成
permute多次元配列の次元の並べ替え
prod配列の要素の積を求める
repmat配列の複製とタイル
reshape配列の形状の変更
shiftdim配列次元のシフト
sort配列要素を昇順または降順に並べ替え
squeeze配列から大きさが 1 の次元を削除
sub2ind添字から線形インデックスへの変換
sum配列要素の和を求める

詳細

外部の Web サイト

この情報は役に立ちましたか?