固有値と固有ベクトル

Ax = λEx
λを固有値、xを固有ベクトルと言う
(A – λE)x = 0
線形変換でベクトルの回転が起こらず、拡大・縮小のみで表現

2×2の行列の場合、固有値と固有ベクトルは必ず2ペア存在する。

import numpy as np

import numpy.linalg as LA
a = np.array([[1,0],[0,2]])
print(a)

print(LA.eig(a))

b = np.array([[2,5],[3, -8]])

print(b)
print(LA.eig(b))

[vagrant@localhost python]$ python app.py
[[1 0]
[0 2]]
(array([1., 2.]), array([[1., 0.],
[0., 1.]]))
[[ 2 5]
[ 3 -8]]
(array([ 3.32455532, -9.32455532]), array([[ 0.96665615, -0.40390206],
[ 0.25607791, 0.91480224]]))

なるほど、確かに2ペアあります。
LA.eig(x)が固有値、固有ベクトルの計算ですね。

c = np.random.randint(-10,10,size=(3,3))

w,v = LA.eig(c)
print(w)
print(v)

[vagrant@localhost python]$ python app.py
[ 4.97854958+7.44028681j 4.97854958-7.44028681j -9.95709916+0.j ]
[[ 0.08381118-0.45630028j 0.08381118+0.45630028j 0.41009134+0.j ]
[ 0.81099969+0.j 0.81099969-0.j -0.22863604+0.j ]
[ 0.30533936+0.18388344j 0.30533936-0.18388344j 0.88292166+0.j ]]

線形変換

線形変換とは、ベクトルに行数を掛けてベクトルを作る関数のこと

線形空間を構成するものの基準:標準規定e
標準規定とは、x軸、y軸、z軸の様に座標軸を定めるベクトルの組み

b1 = (3 2) = 3e[x] + 2e[y]

ニューラルネットワークのパラーメータと重みの掛け算は、線形変換

逆行列

A (a b
c d)

A^-1 = 1/ad – bc(b -d -c a)

行列の内積の計算の際に、右辺や左辺がx,yの時に逆行列を掛けて計算するのかな。
numpy.linalg.inv(X)で算出します。

import numpy as np

a = np.array([[1,2],[4,5]])
print(a)

print(np.linalg.inv(a))

[vagrant@localhost python]$ python app.py
[[1 2]
[4 5]]
[[-1.66666667 0.66666667]
[ 1.33333333 -0.33333333]]
おおおお、なんかすげーな、逆行列も一瞬だな。

で、逆行列だけど、
線形代数使う上では基礎の様。つまり、機械学習に逆行列は必須ってことですね。

行列の積

行列同士の要素ごとの積を計算する際はnumpy.multiplyを使う
np.multiply(arr1, arr2)
アダマール積と言うらしい。
頭悪い、みたいだな。。

やりたいのは要素同士ではなく、内積の方。
これは何度も出てきている numpy.dot()もしくはnumpy.matmul()を使う

import numpy as np

arr1 = np.arange(1,5).reshape((2,2))
arr2 = np.arange(3,9).reshape((2,3))

print(arr1)
print(arr2)
print(np.dot(arr1,arr2))
print(arr1.dot(arr2))

print(np.matmul(arr1,arr2))

[vagrant@localhost python]$ python app.py
[[1 2]
[3 4]]
[[3 4 5]
[6 7 8]]
[[15 18 21]
[33 40 47]]
[[15 18 21]
[33 40 47]]
[[15 18 21]
[33 40 47]]
おおおおおおおおおおお、素晴らしいですね、これは。
早く画像処理まで行きたいですな。

行列の足し算・引き算

import numpy as np

arr1 = np.arange(1, 5).reshape((2,2))
arr2 = np.arange(5, 9).reshape((2,2))

print(arr1)
print(arr2)
result = arr1 + arr2
print(result)

print(arr2 - arr1)
print(arr1 * arr2)	
print(arr1 // arr2)	

あれ、掛け算まではわかる。割り算がおかしなことになってる。1/5や1/3は0

コサイン類似度

cos(a,b) = 内積 / 絶対値|a|*|b| = /|a|*|b|

ベクトル向きが逆の時は -1
直行は 0
平行なら 1

Word2Vecやfasttextなどは、cos類似度で類似テキストを推定していましたね。
例えば、以下の様に、Y1とY2を用意して、X1とどちらが近いかという計算ができます。

import numpy as np

def cos_sim(v1, v2):
	return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2))

X1 = np.array([0.782,0.514,0.334,3])
Y1 = np.array([0.457,0.823,0.664,14])
Y2 = np.array([0.256,0.565,0.335,2.4])

print(cos_sim(X1,Y1))
print(cos_sim(X1,Y2))

[vagrant@localhost python]$ python app.py
0.9686648214589598
0.9870228673135825

Cos類似度はY2の方がY1よりも近いと計算できました。

あれ、なんかこれ相関係数に似てるなーと思ったら、、

相関係数とコサイン類似度は数学的にはほぼ等価であり、どちらもベクトルのノルムで正規化した内積です。

やっぱり。。ロジック自体はほぼ一緒でしょうね。

有向線分(矢印)の計算

要はベクトル計算です

from numpy import array

v1 = array([2,5])
v2 = array([3,9])

print(v1+v2)
print(v1-v2)
print(v1*v2)
print(v1.dot(v2))

掛け算(*)はarrayの要素同士の計算
内積を使うにはdotメソッドを使用する
[vagrant@localhost python]$ python app.py
[ 5 14]
[-1 -4]
[ 6 45]
51

スカラー倍だと、単純に係数を描ければOKですね。
print(v1*5)

内積: 対応する成分同士を掛け算してそれらの和を取る
a1b1 + a2b2 … + anbn = nΣi=1*aibi
内積の公式
= ||a|| ||b||*cosθ
a = (2,1), b = (1,3)の時、 = √5 * √10 * √2/2 = 5

内積が0のベクトルは直行
|a| |b| *cos90° = 0

fasttext

Word2Vecの延長線上として、Facebookが開発したのがfasttext
-> より精度の高い計算を高速に実行
-> 字面の近しい単語同士により意味のまとまりをもたせるという手法を提案

基本的なアルゴリズムはWord2Vecと一緒そうですね。。
毎回計算するのではなく、キャッシュ化して計算を高速化しているのでしょうか。

論文
Enriching Word Vectors with Subword Information
skip-gram model is to maximize the log-likelihood
TΣt=1 ΣceCt log[p](wc|wt)
where the context Ct is the set of indices of words surrounding wt

-> 自然言語処理の歴史やコミュニティの勉強をかなりしている
-> 論文読む予備知識がかなり必要
-> とは言え、論文も身近な存在

自然言語処理の論文って言うと、勝手に院卒エンジニアの専門領域って先入観があったけど、別に誰でも読めるしアクセスできるんだなー

Word2Vec

Word2Vecの使い方
-> テキストや発話を大規模に集めてデータベース化した言語資料の活用
-> それまでは、表現方法としてone-hotベクトルや単語文脈行列をSVDで次元圧縮したベクトルなどが使われていた
-> one-hotベクトルは単語の数だけ次元を持つ方法
-> 分散表現では単語の意味をベクトル化する

word2vec

It was recently shown that the word vectors capture many linguistic regularities, for example vector operations vector('Paris') - vector('France') + vector('Italy') results in a vector that is very close to vector('Rome'), and vector('king') - vector('man') + vector('woman') is close to vector('queen') 

Word Cosine distance と記載があるので、cosineの距離でしょう。
word2vecでは、単語が文中で交換可能かに注目している

Continuous Bag-of-Words
前後の単語から単語を推測する

Skip-gram
単語から周辺単語を推測する

なるほどー、アルゴリズムの仕組みとしては、”前後の関係性”で単語をベクトル化しているのか。。
それを膨大な量でやるのね。

ただし、日本語の場合は、形態素分析をしないといけない。あれ、mecabと組み合わせるのかな。

Gaussian function

ガウス関数は正規分布関数

a exp{-(x-b)^2 / 2C^2}

こちらもガウス関数の一種
1/√2πσ exp (- (x – μ)^2 / 2σ^2)

import numpy as np 
import matplotlib.pylab as plt 

def gauss(x, a = 1, mu = 0, sigma = 1):
	return a * np.exp(-(x - mu)**2 / (2*sigma**2))

fig = plt.figure(figsize = (8, 6))
ax = fig.add_subplot(111)

x = np.arange(-4, 8, 0.1)
f1 = gauss(x)
f2 = gauss(x, a = 0.5, mu=2, sigma= 2)

ax.plot(x, f1)
ax.plot(x, f2)

正規分布になってますね。

ガウス分布の微分は
– (x – μ)/√2πσ^3 (- (x – μ)^2 / 2σ^2) です。