はじめに|レポート
私が毎月開催している桜井進のPython・UNIX教室【数学プログラミングコース】3月のテーマは「Pythonでコサイン類似度」でした。
率直に言って、高校数学教科書に登場するベクトルはつまらない。とくに内積。受験数学では内積は問題のための問題でしかありません。
ところがデータサイエンスの現場では、ベクトルの内積は強力なツールとして登場します。それがコサイン類似度(Cosine Similarity)です。
例えば2つの文書がどれだけ似ているかを定量的に比較することが可能になります。
前編でPythonでベクトルを扱う方法、後編でコサイン類似度を紹介していきます。
目次
Numpyライブラリは配列をつくる
NumPyライブラリこそ、Pythonがデータサイエンスの分野で使われる大きな理由です。NumPyはNumerical Pythonの略であることからわかるように、数値計算ライブラリです。
NumPyのコア部分はC言語で実装することにより、効率的かつ高度な数値計算を高速実行できるように設計されています。
NumPyはndarrayと呼ばれる型付きの多次元配列をデータ構造の基本としていることで、ベクトルや行列を扱うのに適しています。
NumPyのインポート
>>> import numpy as np
NumPyを使うにはNumPyをインストールした後に、NumPyをインポートします。NumPyの省略名npは世界中で使われているものです。
コードを他人と共有することを考えると、NumPyのような標準ライブラリに対しては慣習的に使われている省略名を使った方がいいでしょう。
numpy.array()によるベクトルの表し方
>>> v = np.array([1, 2])
>>> w = np.array([1, 2, 3])
のようにnumpy.array()関数の引数に配列[1, 2]、[1, 2, 3]を渡すことで変数v、wはベクトルとして定義されます。
注意すべき点は、配列[1, 2]、[1, 2, 3]は横書きですが、ベクトルv、wは列ベクトルであることです。
ベクトルだけを扱う限りにおいて、列ベクトルと行ベクトルはどちらを使っても問題ありません。
これが、行列とベクトルをいっしょに扱う場合(線形代数学)には列ベクトルと行ベクトルの区別・使い分けが必要になります。
そこで、簡単な解決策として次のようにコードを記述する方法があります。
>>> v = np.array([1,
>>> 2])
>>> w = np.array([1,
>>> 2,
>>> 3])
こうすることで見た目も列ベクトルになります。
ベクトルの演算 和・差・スカラー倍
このベクトルの表し方を用いて、Pythonによるベクトル演算を確認していきましょう。
まずはベクトルの和・差・スカラー倍です。
次のように、和・差は等しい成分どうしの和・差として、スカラー倍はすべての成分のスカラー倍として定義されます。
計算例
>>> a = np.array([1,
>>> 2])
>>> b = np.array([3,
>>> 4])
>>> print(a + b)
>>> [4 6]
>>> print(a - b)
>>> [-2 -2]
>>> print(3*a)
>>> [3 6]
>>>
>>> c = np.array([1,
>>> 2,
>>> 3])
>>> d = np.array([4,
>>> 5,
>>> 6])
>>> print(c + d)
>>> [5 7 9]
>>> print(c - d)
>>> [-3 -3 -3]
>>> print(3*c)
>>> [3 6 9]
ベクトルのデータ取得
インデックス指定によるベクトルの成分取得
>>> a = np.array([1,
>>> 2])
>>> a[0] # 第1成分 = pythonでは0番目の成分
>>> 1
>>> a[1] # 第2成分 = pytyhonでは1番目の成分
>>> 2
ベクトルの次元取得の方法|len()関数を使う方法
これが一番簡単です。
>>> len(a)
>>> 2
>>> c = np.array([1,
>>> 2,
>>> 3])
>>> len(c)
>>> 3
ベクトルの次元取得の方法|インスタンス変数shapeを使う方法
ndarrayの格納されている要素数は、インスタンス変数ahapeを用いて取得できます。
>>> a.shape
>>> (2,)
>>> c.shape
>>> (3,)
>>> a.shape[0] # a.shapeの第0成分
>>> 2
>>> c.shape[0] # c.shapeの第0成分
>>> 3
ちなみに、ndarrayの格納されている次元数(インスタンス変数ndim)は、ベクトルの要素数=ベクトルの次元、とは異なるものです。
ndimについては行列のところで取り上げます。
ベクトルの内積
等しい次元どうしのベクトルに対し、ベクトルの内積は同じ成分どうしの積の総和として定義されます。
内積は英語でinner puductと呼ばれる他に記号・を用いることからドット積(dot product)とも呼ばれます。
Pythonでベクトルの内積を計算する方法は、関数、演算子、メソッドなどいくつもあります。
- numpy.dot(a, b)関数にベクトル(1次元配列)を渡す方法
- numpy.inner(a, b)関数にベクトル(多次元配列)を渡す方法
- 二項演算子@ a@b
- dotメソッド a.dot(b)
計算例
>>> np.dot(a, b)
>>> 11
>>> np.inner(a, b)
>>> 11
>>> a@b
>>> 11
>>> a.dot(b)
>>> 11
>>>
>>> np.dot(c, d)
>>> 32
>>> np.inner(c, d)
>>> 32
>>> c@d
>>> 32
>>> c.dot(d)
>>> 32
列ベクトルを列ベクトルとしてつくる
ここまで用いてきたa = np.array([1, 2])やc = np.array([1, 2, 3])はndarrayの1次元配列と呼ばれます。これが列ベクトルとして振る舞います。
先に説明したようにコードに改行をいれて見た目を列ベクトルにすることはできますが、出力は横のままです。
>>> a
>>> a.ndim
>>> 1 # 1次元配列
>>> len(a)
>>> 2 # 2次元ベクトル
>>> array([1, 2])
>>> print(a)
>>> [1, 2]
>>>
>>> c
>>> c.ndim
>>> 1 # 1次元配列
>>> len(c)
>>> 3 # 3次元ベクトル
>>> array([1, 2, 3])
>>> print(c)
>>> [1, 2, 3]
次のようにすることで出力も列として表示できます。
>>> a.reshape(-1,1) # 列数を1にする
>>> array([[1],
>>> [2]])
>>> print(a.reshape(-1,1))
>>> [[1]
>>> [2]]
>>>
>>> c.reshape(-1,1) # 列数を1にする
>>> array([[1],
>>> [2],
>>> [3]])
>>> print(c.reshape(-1,1))
>>> [[1]
>>> [2]
>>> [3]]
reshapeメソッドにより配列の形状を変えることができます。
配列A.reshape(行数m, 列数n)により配列Aをm×n行列に変形。
2次元列ベクトルは2×1行列なので、np.array([1, 2]).reshape(2,1)とすれば出力も列ベクトルになります。
配列A.reshape(-1, 列数)のように行数に-1を指定すると、列数に対して行数が自動で設定され便利です。
これでNumPyによるベクトルの扱い方の基本はOKです。
次回後編はベクトルの内積の応用であるコサイン類似度を紹介します。