Pandas & NumPy Academy · レッスン

np.matmulと@による行列の乗算

np.matmulと@演算子で行列を正しく乗算し、要素ごとの*と通常の行列乗算を区別します。

レッスン 1/413 ステップ

「np.matmulと@による行列の乗算」はCoddyKit上の無料Pandas & NumPy Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPandas & NumPy Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

行列乗算が重要な理由

行列乗算は、データサイエンスと機械学習の中核をなす処理です。ニューラルネットワーク、次元削減、線形変換を支えています。Pythonでは、NumPyを使って行列を乗算する方法が2つあります。np.matmul()関数と、Python 3.5で導入された@演算子です。どちらも高速でベクトル化されており、Pythonのネストしたループよりはるかに効率的です。

行列乗算のルール

2つの行列AとBについて、積A @ Bが有効になるのは、Aの列数とBの行数が等しい場合だけです。Aの形状が(m, n)で、Bの形状が(n, k)なら、結果の形状は(m, k)です。このルールは内側の次元の制約と呼ばれ、どのNumPy関数を使う場合にも適用されます。

import numpy as np
A = np.array([[1, 2], [3, 4]])   # shape (2, 2)
B = np.array([[5, 6], [7, 8]])   # shape (2, 2)
C = A @ B
print(C)  # [[19 22] [43 50]]

np.matmulと@演算子の比較

2次元配列では、np.matmul(A, B)とA @ Bは同じ結果を返します。@演算子は単なるシンタックスシュガーです。内部では__matmul__を呼び出し、NumPyは同じCレベルのBLASルーチンを使って実装しています。読みやすさを重視する普段のコードでは@を使い、関数を呼び出し可能なオブジェクトとして渡したい場合や、エッジケースを明示的に扱いたい場合はnp.matmulを使います。

import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(np.matmul(A, B))   # same as A @ B
print(A @ B)             # same result

@、*、np.dotの違い

NumPyには、混同しやすい3つの乗算方法があります。A * Bは要素ごとの乗算(アダマール積)です。np.dot(A, B)は2次元配列ではnp.matmulと同じように動作しますが、高次元では意味が異なります。A @ Bは厳密な行列乗算であり、数学上の定義に正確に従います。行列を扱う場合はnp.dotよりこちらを優先してください。

import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print('element-wise:', A * B)    # [[5 12] [21 32]]
print('matmul:', A @ B)          # [[19 22] [43 50]]

行列乗算には交換法則が成り立たない

スカラーの乗算とは異なり、行列乗算には交換法則が成り立ちません。一般にA @ BとB @ Aは異なります。そもそも、両方向で形状が適合するとは限りません。これは変換処理を書く際に重要です。演算の順序によって結果が変わるためです。常に、どの行列が左側でどの行列が右側にあるかを把握しておきましょう。

import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[0, 1], [1, 0]])
print('A @ B:', A @ B)   # [[2 1] [4 3]]
print('B @ A:', B @ A)   # [[3 4] [1 2]]  -- different!

バッチ行列乗算

配列が3次元以上の場合、np.matmulと@は、先頭にある余分な次元をバッチ次元として扱い、行列を並列に乗算します。たとえば、形状(32, 3, 4)の配列と形状(32, 4, 5)の配列を乗算すると、形状(32, 3, 5)の結果が得られます。これは、3×4 @ 4×5の独立した乗算を32個、同時に実行するという意味です。ディープラーニングのフレームワークは、この仕組みによってミニバッチを効率的に処理しています。

import numpy as np
batch_A = np.random.rand(32, 3, 4)
batch_B = np.random.rand(32, 4, 5)
result = batch_A @ batch_B
print(result.shape)  # (32, 3, 5)

行列とベクトルの乗算

行列にベクトルを掛ける処理は、よく使われる特殊なケースです。Aの形状が(m, n)で、vが長さnの1次元配列なら、A @ vによって長さmの1次元配列が生成されます。NumPyが形状の整合を自動的に処理するため、vを列ベクトルに変形する必要はありません。このパターンは、線形回帰での重みの適用、特徴量の射影、各行の内積の同時計算など、さまざまな場面で登場します。

import numpy as np
A = np.array([[1, 2, 3], [4, 5, 6]])  # (2, 3)
v = np.array([1, 0, -1])              # (3,)
print(A @ v)   # [1-3, 4-6] = [-2, -2]

パフォーマンス:@とPythonのループ

NumPyの行列乗算は、最適化されたBLAS/LAPACKルーチンを呼び出し、コンパイル済みのCコードで実行されます。同じ処理を実装した純粋なPythonのネストしたループは、大きな行列では通常100~1000倍遅くなります。データパイプラインで特徴量変換、PCA射影、重みの更新などの行列積を繰り返し計算する必要がある場合は、必ず@またはnp.matmulを使い、内側のループを自分で実装しないでください。

import numpy as np, time
A = np.random.rand(500, 500)
B = np.random.rand(500, 500)
t0 = time.time()
C = A @ B
print(f'NumPy: {(time.time()-t0)*1000:.1f} ms')  # single-digit ms

複数の行列積を連結する

複数の@演算を1つの式に連結できます。A @ B @ Cは左から右に評価されます。NumPyは、MATLABのmtimesとは異なり、乗算の順序を自動的に最適化しません。そのため、行列のサイズが大きく異なる場合は、順序によって速度が変わることがあります。3つ以上の行列を扱う場合は、最も効率的な組み合わせを自動的に選択するnp.linalg.multi_dot([A, B, C])の利用を検討してください。

import numpy as np
A = np.random.rand(100, 20)
B = np.random.rand(20, 50)
C = np.random.rand(50, 10)
result = np.linalg.multi_dot([A, B, C])
print(result.shape)  # (100, 10)

よくある形状エラーと修正方法

行列の乗算で最もよくあるエラーは、形状の不一致です。ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0。この場合は、A.shapeで形状を確認し、内側の次元が一致していることを確認してください。形状(n,)の行ベクトルを形状(n, 1)の列ベクトルとして扱う必要がある場合は、v.reshape(-1, 1)を使用します。転置が必要な場合は、A.Tを使用します。

import numpy as np
A = np.ones((3, 4))
B = np.ones((3, 4))  # wrong -- inner dims 4 != 3
try:
    A @ B
except ValueError as e:
    print('Error:', e)
print('Fix:', (A @ B.T).shape)  # (3, 3)

実践例:特徴量変換

データサイエンスでよくある使用例を考えてみましょう。形状(n_samples, n_features)のデータセットXと、形状(n_features, n_outputs)の重み行列Wがあるとします。行列積X @ Wは、すべてのサンプルに対して線形変換を同時に適用し、形状(n_samples, n_outputs)の結果を生成します。これは、ニューラルネットワークの線形層や、線形回帰による予測の中心となる計算です。

import numpy as np
n_samples, n_features, n_outputs = 200, 10, 3
X = np.random.rand(n_samples, n_features)
W = np.random.rand(n_features, n_outputs)
b = np.zeros(n_outputs)
predictions = X @ W + b   # shape (200, 3)
print(predictions.shape)

理解度チェック

NumPyの行列乗算についての理解度を確認しましょう。

レッスンのまとめ

このレッスンでは、np.matmulと@は要素ごとの乗算ではなく、通常の行列乗算を実行すること、2つの行列の内側の次元は一致していなければならないこと、そして@は先頭の次元にわたるバッチ乗算をサポートすることを学びました。次は、行列を「元に戻せる」かどうかを判断する操作である、行列式、逆行列、転置について学びます。

無料で開始

AI チューターと学ぶ Python — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
30
レッスン
120

よくある質問

「np.matmulと@による行列の乗算」レッスンは無料ですか?

はい。「np.matmulと@による行列の乗算」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Pandas & NumPy Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

「np.matmulと@による行列の乗算」で何を学びますか?

np.matmulと@演算子で行列を正しく乗算し、要素ごとの*と通常の行列乗算を区別します。 ブラウザで直接実行するハンズオンコードでPandas & NumPy Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Pandas & NumPy Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのPandas & NumPy Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「np.matmulと@による行列の乗算」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このPandas & NumPy Academyレッスンでコードを書いて実行できますか?

はい。すべてのPandas & NumPy Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. np.matmulと@による行列の乗算
  2. 行列式、逆行列、転置行列
  3. 連立一次方程式を解く
  4. 固有値とSVDの概要
← Pandas & NumPy Academyに戻る