NumPyでは2つの異なる配列から外積を求めるには、numpy.outer()を使います。この関数は基本的に2つの1次元配列(ベクトル)から外積を計算します。多次元配列を渡した場合は1次元配列化してから計算します。そのため複数のベクトルの外積を一度に取得するには不向きです。そのような場合は、np.multiply.outer()を使います。
このページではこれらについて詳しく解説します。
なお外積は、例えば a = [a0, a1, …, an] と b = [b0, b1, …, bm] という2つのベクトルがある場合、次のように算出されます。
|a x b| =
[[a0*b0, a0*b1, ..., a0*bm],
[a1* b0, a1* b1, ..., a1* bm],
......
[an* b0, an* b1, ..., an* bm]]
それでは始めましょう。
1. numpy.outer()関数の使い方
まずは、numpy.outer()の書式を確認しましょう。
書き方:
np.outer(a, b, out=None)
パラメーター:
引数 | 型 | 解説 |
---|---|---|
a | array_like (M, ) |
ベクトル。多次元配列の場合1次元配列のフラット化される。 |
b | array_like (N, ) |
同上 |
out* | ndarray (M, N) |
これを指定した場合、指定した配列を関数の戻り値で上書きします。 |
* はオプション引数であることを示します。 |
戻り値:
out: shape(M, N)の配列 aとbの外積を要素とした配列を戻します。out[i, j] = a[i] * b[j] です。 |
一緒に確認したい関数:
- inner
- einsum
- tensordot
- ufunc.outer
サンプルコード
それではサンプルコードを見てみましょう。
numpy.outer()は、引数に渡した2つの1次元配列(ベクトル)a とb の外積を算出します。
import numpy as np
a = np.array([1, 5, 3])
b = np.array([2, 4, 6])
np.outer(a, b)
多次元配列を渡した場合もベクトル化(1次元配列化)して処理します。
# 多次元配列を渡した場合も1次元化して計算
a = np.array([1, 5, 3, 2]).reshape(2, 2)
b = np.array([2, 4, 6])
np.outer(a, b)
このように、numpy.outer()は1次元配列(ベクトル)同士の外積を算出します。
単純に2つのベクトルの外積を求めるだけなら、これを使えば十分です。しかし、複数のベクトルを格納した多次元配列から、外積を一括で取得したい場合はnumpy.outer()は不向きです。その場合は、次に解説するufunc.outer()を使います。
2. ufunc.outer()メソッドの使い方
結論から言うと、複数のベクトルデータを格納している多次元配列(例えば1次元軸要素に1つのベクトルというように)から、それぞれの外積を一括で取得したいような場合は、ufunc.outer()メソッドを使って、np.multiply.outer()と書く方が遥かに適しています。
ufunc というと見慣れない方も多いかもしれません。簡単に言うと、これは関数のことです。つまり、ufunc.outer() とは np.multiply() やnp.add() などの関数の後につなげて、np.multiply.outer() やnp.add.outer() というように使うメソッドであるということを意味します。
この ufunc.outer()メソッドは、次のようにfor文を回すのと同じことをします。配列A と B の次元数によってfor文を回す回数が異なりますが、以下では1次元配列同士の場合と2次元配列同士の場合を示しています。
# 1次元配列同士の場合
r = np.empty((A.size,B.size))
for i in range(A.size):
for j in range(B.size):
r[i,j] = op(A[i], B[j]) # op は任意の関数
# 2次元配列同士の場合
r = np.empty(a.shape + b.shape)
for i in range(a.shape[0]):
for j in range(a.shape[1]):
for k in range(b.shape[0]):
for l in range(b.shape[1]):
r[i, j, k, l] = op(a[i, j], b[k, l]) # op は任意の関数
以上のコードの最後の行の op は任意の関数です。ここでnp.multiply()を使うと、それぞれの配列から外積を取得するのと同じ処理になります。
つまり、np.multiply.outer(A, B)と書くことで、配列A, B のいずれかの軸に格納されているベクトルデータa やb から外積を算出することができます。
先に解説したnp.outer()との具体的な違いは、戻り値である外積を要素とした配列のshapeにあります。np.outer()は引数に渡した配列を1次元化して計算を行います。そのため、戻り値の配列のshapeは常に(a.size, b.size)です。一方で、np.multiply.outer()では、戻り値の配列のshape は常に a.shape + b.shape になります。例えば、前者がshape(2, 3) で後者がshape(4, 5) ならshape(2, 3, 4, 5) となります。
このようなわけでnp.multiply.outer()では、複数のベクトルデータセットから外積を一括で取得することができます。
それでは、ufunc.outer()の書式は次の通りです。
書き方:
ufunc.outer(A, B, **kwargs)
パラメーター:
引数 | 型 | 解説 |
---|---|---|
A | array_like | 配列 |
B | array_like | 配列 |
kwargs* | any | dtype やout などのキーワード引数を設定可能です。 |
** はキーワード引数であることを示します。 |
戻り値:
配列:上のコードのfor文を回した後のr |
一緒に確認したい関数:
- numpy.outer:
- tensordot:
サンプルコード
解説は上で十分に行ったので、ここでは多次元配列同士の場合の処理を確認しておきましょう。
以下の2つの2次元配列を使います。
import numpy as np
a = np.array([1, 5, 3, 2]).reshape(2, 2)
a
b = np.array([2, 4, 6, 7, 8, 9]).reshape(2, 3)
b
np.multiply.outer()では、それぞれの外積をshape(2, 2, 2, 3)の形で返します。
# np.multiply.outer()は、
# shape(a.shape, b.shape)で
# 外積を戻す。
np.multiply.outer(a, b)
ご覧のように、これを使うと、複数のベクトルの外積を一度に取得しているのと同じことになります。任意の外積はスライスで取り出すことができます。
np.multiply.outer(a, b)[0, 0]
一方で、np.outer()は1次元化して計算するため、使い勝手の面では劣ります。
# np.outer()は、
# shape(a.size, b.size)で
# 外積を戻す。
np.outer(a, b)
3. まとめ
以上が、NumPyにおいてベクトルの外積を取得する方法です。
まとめると、1次元配列同士(1つのベクトルデータを格納している配列同士)の外積を知りたいだけであれば、numpy.outer()を使います。
しかし、例えば2次元配列(横軸に1つのベクトルデータが格納されており、それが縦軸の数だけ存在するようなデータ)を使って、一括で外積を取得したいような場合は、numpy.multiply.outer()を使います。
一見難しく感じるかもしれませんが、慣れれば簡単なので、ぜひ参考にして頂ければと思います。
コメントを残す