応用数学・機械学習 Applied Mathematics and Machine Learning

**<font size='7'>線形代数</font>**

この辺はほとんど知っている事なので、ポイントのみ書きます。

【掃き出し法】
下記の行列の逆行列を掃き出し法で求めよ。


```math
A=
\begin{pmatrix}
1 & 4 \\
2 & 6
\end{pmatrix}
```
2 x 2の単位行列 I を用意して、これを与えられた行列の右横に並べ、元々の行列を掃き出し法で単位行列にすれば、右側の行列は、逆行列になる。元々の行列に$A^{-1}$を掛けるのだから、右側の行列は $I A^{-1}$すなわち、$A^{-1}$になる。

【行列式】
行列式を考える。

```math

\begin{vmatrix}
a & b & c \\
d & e & f \\
g & h & i
\end{vmatrix}
=
a
\begin{vmatrix}
e & f \\
h & i
\end{vmatrix}
-d
\begin{vmatrix}
b & c \\
h & i
\end{vmatrix}
+g
\begin{vmatrix}
b & c \\
e & f
\end{vmatrix}
```

3 x 3 の行列式の場合、一般に次の式が成立する。

```math

\begin{vmatrix}
a_1+a_2 & b_1+b_2 & c_1 +c_2 \\
d & e & f \\
g & h & i
\end{vmatrix}
= 
\begin{vmatrix}
a_1 & b_1 & c_1 \\
d & e & f \\
g & h & i
\end{vmatrix}
=
\begin{vmatrix}
a_2 & b_2 & c_2 \\
d & e & f \\
g & h & i
\end{vmatrix}
```


この事から、行列式の一行を他の行と入れ替えた行列式は元の行列式の-1倍になることがわかる。

【固有値分解の例】
$\lambda$,$\vec{x}$を行列Aの固有値、固有ベクトルとする。この固有値を対角線上にならべた$\Lambda$ をつくる。対応する固有ベクトル$\vec{x}$を列にして行列Vをつくる。すると、$A=V$$\Lambda V^{-1}$となる行列$\Lambda$をとることができる。これを行列Aの固有値分解という。

例えば、次の行列の固有分解を考える。

```math
A=
\begin{pmatrix}
2 & 1 \\
0 & 6
\end{pmatrix}
```

暗算で、固有値が２、６と出る。固有ベクトルは、それぞれ、

```math
\begin{pmatrix}
1 \\
0
\end{pmatrix},
\begin{pmatrix}
1 \\
4
\end{pmatrix}
```
の定数倍となる。よって

```math
\begin{pmatrix}
2 & 1 \\
0 & 6
\end{pmatrix}
=
\begin{pmatrix}
1 & 1 \\
0 & 4 
\end{pmatrix}
\begin{pmatrix}
2 & 0 \\
0 & 6 
\end{pmatrix}
\begin{pmatrix}
1 & -1/4 \\
0 & 1/4 
\end{pmatrix}
```
【特異値分解の例】
Mが正方行列以外でも、特別な条件で、固有値分解と似たようなことが出来る。これは、$MM^{T}$と$M^{T}M$が固有値分解できることを利用する。$M\vec{v}=\sigma\vec{u}$, $M\vec{u}=\sigma\vec{v}$となるような単位ベクトル$\vec{u}$,$\vec{v}$が存在するとき、成立する。このとき、$M=USV^{T}$と特異値分解出来る。ただしU,Vは、$\vec{u}$, $\vec{v}$を並べたものである。

【特異値分解の応用】
画像認識で、画像を 960 x 720 pixelとすると、この画像は数字が並んだ行列と見ることが出来る。特異値分解して、特異値の大きい方から $k = 128,64,32,16,4,2,1$個順々取ってやると、kが十分小さくなると、画像がぼやけてくる。画像の圧縮や機械学習の前処理に利用できる。

これだけ見ると、主成分分析の寄与率に似ていると思う。寄与率が高ければ、データの持っていた情報量の多くが説明されるように、特異値の数が大きいうちは、全体の画像をうまく説明できている。主成分分析の問題も特異値分解をして確かめてみたい。

**<font size='7'>確率・統計</font>**

頻度確率(客観確率):発生する頻度
ベイズ確率(主観確率):信念の度合い

【ベイズ則】
$P(X=x|Y=y)P(Y=y)=P(Y=y|X=x)P(X=x)$
 
(問題）ある街の子どもたちは毎日1/4の確率で飴玉をもらうことができ，飴玉をもらうと1/2の確率で笑顔になるという。その街の，笑顔な子どもが飴玉をもらっている確率を求めよ。(ただし，この街の子どもたちが笑顔でいる確率は1/3である。)

（解）
ただの公式に当てはめる問題であるが、上の式を
P(X=x|Y=y)/P(Y=y|X=x)=P(X=x)/P(Y=y)はなかなか興味深い式だという事を発見した。
つまり条件付き確率の比が、条件なしの確率の比に変わっている。これを利用して、笑顔な子どもが飴玉をもらっている確率は、1/4 ÷1/3 x 1/2 = 3/8と求めることが出来る。

（別解）別にベイズの定理を知らなくても、小学生でも解ける解法を発見したので書いておく。ある街の子どもたちは毎日1/4の確率で飴玉をもらうことができ，飴玉をもらうと1/2の確率で笑顔になるということは、1/8 = 3/24 の確率で、飴玉をもらい笑顔になる。この街の子どもたちが笑顔でいる確率は1/3であるということは、子供の 1/3 - 1/8 = 5/24 が飴玉を貰わなくて笑顔。つまり 3/(3+5) = 3/8 が答えである。

【分散、共分散】
分散: データの散らばり具合
共分散:２つのデータ系列の傾向の違い
$Cov(f,g)=E(fg)−E(f)E(g)$
共分散がゼロであっても、必ずしも「関係性がゼロ」とは言えない。

【確率分布】ここはほとんど知っているので要点だけ書く。
ベルヌーイ分布:コイントスのイメージ
マルチヌーイ分布:さいころを転がすイメージ
「カテゴリカル分布」とも呼ばれる。
ガウス分布(正規分布):釣鐘型の連続分布

**<font size='7'>情報理論</font>**

【自己情報量】
$I(x)=−log(P(x))$
P(x)は確率。P(x)の逆数をとって、I(x)=log(W(x))と表記できる。
底を2とした場合の単位はbit
底をeとした場合の単位はnat

【シャノンエントロピー】
自己情報量の期待値である。
$H(x)=E(I(x))=−E(log(P(x)))=−∑(P(x)log(P(x)))$
 
【カルバック・ライブラー ダイバージェンス】
同じ事象・確率変数における異なる確率分布P,Qの違いを表す
$D_{KL}(P||Q)$=$E_{x～P}[logP(x)/Q(x)]=E_{x～P}[logP(x)−logQ(x)]$
PとQを逆にすると値が異なるため、距離ではない。

【交差エントロピー】
KLダイバージェンスの一部分を取り出したもの
Qについての自己情報量をPの分布で平均している
$H(P,Q)=H(P)+DKL(P||Q)$
$H(P,Q)=-E_{x～P}logQ(x)$


**<font size='7'>機械学習</font>**

【機械学習モデル】
 トム・ミッチェル:コンピュータプログラムは、タスクT(アプリケーションにさせたいこと)を性能指標Pで測定し、その性能が経験E(データ)により改善される場合、タスクTおよび性能指標Pに関して経験Eから学習すると言われている。

結果が起こったときの原因の確率を求めるベイズの定理と相性が良いと思う。

【線形回帰】
・回帰はある入力(離散あるいは連続値)から出力(連続値)を予測する問題
・線形回帰の場合、説明変数と目的変数の間に線形の関係がある
・教師あり学習
・慣例として予測値にはハットを付け事が多い

行列表現で、 y = Xw + $\epsilon$と書ける。Xは説明変数のベクトル。ｗは重みのベクトル。$\epsilon$は誤差のベクトル。

【データ分割】
汎化性能を高めるため

【最小二乗法】
学習データの平均二乗誤差を最小とするパラメータを探索
学習データの平均二乗誤差の最小化は、その勾配が0になる点を求める

【ハンズオンサマリーと考察】

```
data = df.loc[:, ['RM']].values
```
1. 説明変数 data = df.loc[:, ['RM']].values を設定するところで、この形式だとtype(data):numpy.ndarray  だが、data = df.loc[:, ['RM']]にしても結果は変わらず出力でき、type(data):pandas.core.frame.DataFrameになる。
2. model.predict([[3]])と出すと、-7.36429383、つまりマイナスの値が出てくる。これは部屋数が３以下の小さな家がないため、部屋数の少ない家の価格をうまく学習できなかったためと考えられる。

【非線形回帰モデル】
・データの構造を線形で捉えられる場合は限られるので、複雑な非線形構造を内在する現象に対して、非線形回帰モデリングを実施
・基底関数を選択し、その関数と推定パラメータの線形結合を考える

【正則化】
過学習や未学習を防ぐため、モデルの複雑さに伴って、その値が大きくなる正則化項(罰則項)を課した関数を考え、それを最小化する

【正則化項(罰則項)】
L1ノルム: いくつかのパラメータを0に推定する。スパース推定。Lasso推定量
L2ノルム: パラメータを0に近づけるよう推定。縮小推定。Ridge推定量 

【データの分割とモデルの汎化性能測定】
ホールドアウト法: 有限のデータを学習用とテスト用の2つに分割し、「予測精度」や「誤り率」を推定する為に使用する。学習用を多くすればテスト用が減り学習精度は良くなるが、性能評価の精度は悪くなる。

クロスバリデーション法: K-分割交差検証は、データをK個に分割してそのうち1つをテストデータに残りのK-1個を学習データとして正解率の評価を行う。K個のデータすべてが1回ずつテストデータになるようにK回学習を行なって精度の平均をとる手法。

【ハンズオンサマリーと考察】

<B>KernelRidge Regression (KRR):非線形モデル、カーネル回帰にリッジ推定量を追加したモデル Kernel + Ridge<B>

```
from sklearn.kernel_ridge import KernelRidge

clf = KernelRidge(alpha=0.0002, kernel='rbf')
clf.fit(data, target)

p_kridge = clf.predict(data)

plt.scatter(data, target, color='blue', label='data')

plt.plot(data, p_kridge, color='orange', linestyle='-', linewidth=3, markersize=6, label='kernel ridge')
plt.legend()
```
alpha: Small positive values of alpha improve the conditioning of the problem and reduce the variance of the estimates.
kernel='rbf': RBFカーネル

alpha=0.0002で、
print(clf.score(data,target))を実行すると、0.8263979137762469
alphaを1.0に変えると、当てはまりが悪くなり、0.3704397984555686と出た。
alphaを0.0001に変えると0.7783217084672633と出た。大きすぎても小さすぎても駄目で、最適なalphaがあるようである。

<B>Ridge Regression<B>

```
from sklearn.metrics.pairwise import rbf_kernel
from sklearn.linear_model import Ridge

kx = rbf_kernel(X=data, Y=data, gamma=50)
#KX = rbf_kernel(X, x)

#clf = LinearRegression()
clf = Ridge(alpha=30)
clf.fit(kx, target)

p_ridge = clf.predict(kx)

plt.scatter(data, target,label='data')
for i in range(len(kx)):
    plt.plot(data, kx[i], color='black', linestyle='-', linewidth=1, markersize=3, label='rbf', alpha=0.2)

#plt.plot(data, p, color='green', marker='o', linestyle='-', linewidth=0.1, markersize=3)
plt.plot(data, p_ridge, color='green', linestyle='-', linewidth=1, markersize=3,label='ridge regression')
#plt.legend()
```
The function rbf_kernel computes the radial basis function (RBF) kernel between two vectors. 類似度を計算するカーネルの一種。
Ridge(alpha=30)のalphaは何か？: Regularization strength; must be a positive float. Regularization improves the conditioning of the problem and reduces the variance of the estimates. Larger values specify stronger regularization. 

ここで、clf = LinearRegression()、#clf = Ridge(alpha=30)とコードを変え実行してみたが、決定係数は上がるものの、グラフが凸凹になり過学習が起きているのが見られる。

<B>Lasso Regression<B>

```
from sklearn.metrics.pairwise import rbf_kernel
from sklearn.linear_model import Lasso

kx = rbf_kernel(X=data, Y=data, gamma=5)
#KX = rbf_kernel(X, x)

#lasso_clf = LinearRegression()
lasso_clf = Lasso(alpha=10000, max_iter=1000)
lasso_clf.fit(kx, target)

p_lasso = lasso_clf.predict(kx)

plt.scatter(data, target)

#plt.plot(data, p, color='green', marker='o', linestyle='-', linewidth=0.1, markersize=3)
plt.plot(data, p_lasso, color='green', linestyle='-', linewidth=3, markersize=3)

print(lasso_clf.score(kx, target))
```
ラッソ回帰、L１ノルム ここで、
print(lasso_clf.coef_)を実行すると、ゼロがいっぱいあり、スパース推定と言われる所以である。

【ロジスティック回帰】
・ある入力(数値)からクラスに分類する。
・教師あり機械学習モデル
・シグモイド関数出力に利用する。
・シグモイド関数の値が 0.5以上であれば分類は1、そうでなければ 0とする。

【尤度関数】
・データは固定し、パラメータを変化させる
・尤度関数を最大化するようなパラメータを選ぶ推定方法が最尤推定

【勾配降下法】
ロジスティック回帰の場合、尤度関数が最小となるパラメータを数学的に求めるのは困難。よって勾配降下によって逐次的にパラメータを更新する。

【確率的勾配法】
・データを一つずつランダムに(「確率的」に)選んでパラメータを更新
・勾配降下法でパラメータを1回更新するのと同じ計算量でパラメータをn回更新できるので効率よく最適な解を探索可能

【混同行列】
正解率:(TP+TN)/(TP+TN+FP+FN)
再現率:TP/(TP+FN)
適合率:TP/TP+FP
F値:再現率と適合率の調和平均

再現率の分母は結果をポジティブにそろえ、適合率の分母は予想をポジティブにそろえると覚えやすいのを発見した。

【ハンズオンサマリーと考察】
<B>タイタニック号にのっていた人の生死確率（ロジステック回帰）<B>

```
data2 = titanic_df.loc[:, ["AgeFill", "Pclass_Gender"]].values
label2 =  titanic_df.loc[:,["Survived"]].values
```
元々は、説明変数が"AgeFill", "Pclass_Gender"、目的変数が"Survived"であったが、"Embarked"も説明変数に加えることにした。Sの欠損値を最頻値で補って、アルファベットから数字に変換した。

```
Embarked = titanic_df.groupby('Embarked').size()
titanic_df['Embarked'] = titanic_df['Embarked'].fillna('S')
titanic_df['Embarked'] = titanic_df['Embarked'].map({'Q':2,'S':3,'C':1})
```
この条件で決定係数は、0.7789001122334456（訓練用）、mapの部分をmap({'Q':1,'S':2, 'C':3})とか色々かえ実験したが、決定係数はあまり違わなかった。mapを使わなくても、factorizeを使えば、同じことが出来ると思う。

```
labels, uniques = pd.factorize(titanic_df['Embarked'])
```

【主成分分析】
・次元の縮小に関する手法
・相関のある多数の変数から相関のない少数で全体のばらつきを最もよく表す主成分と呼ばれる変数を合成する多変量解析の一手法
・射影先の分散は固有値に一致する。
・元のデータの分散と固有値の和が等しい。

【寄与率】
・第k主成分の分散の全分散に対する割合(第k主成分が持つ情報量の割合)

【累積寄与率】
・第1-k主成分まで圧縮した際の情報損失量の割合

【ハンズオンサマリーと考察】
<B>癌である確率をロジステック回帰で求めた後、主成分分析する。<B>

```
y = cancer_df.diagnosis.apply(lambda d: 1 if d == 'M' else 0)
X = cancer_df.loc[:, 'radius_mean':]
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

# 標準化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# ロジスティック回帰で学習
logistic = LogisticRegressionCV(cv=10, random_state=0)
logistic.fit(X_train_scaled, y_train)

# 検証
print('Train score: {:.3f}'.format(logistic.score(X_train_scaled, y_train)))
print('Test score: {:.3f}'.format(logistic.score(X_test_scaled, y_test)))
print('Confustion matrix:\n{}'.format(confusion_matrix(y_true=y_test, y_pred=logistic.predict(X_test_scaled))))

```
一行目は、y = cancer_df.diagnosis.map({'M':1, 'B':0})で代用可。標準化の後に、訓練用のデータとテスト用のデータを分けた場合も、Train score: 0.988
Test score: 0.972は変化しなかった。順序はどっちでもいいと思われる。交差検証でロジステック回帰をやるので、LogisticRegressionの代わりに、LogisticRegressionCVを使い、train_test_split(data, label, test_size=0.2)みたいに、テストサイズを指定しなく、train_test_split(X, y, random_state=0)のように書く。

```
pca = PCA(n_components=2)
pca.fit(X_train_scaled)
plt.bar([n for n in range(1, len(pca.explained_variance_ratio_)+1)], pca.explained_variance_ratio_)
```
array([0.43315126, 0.19586506])となるので、一番大きい固有値で約43%説明でき、次の固有値で約19.6%説明できる。

【k近傍法(k-NN)】
・最近傍のデータを個取ってきて、それらがもっとも多く所属するクラスに識別。
・教師あり学習

【k平均法(k-means)】
・クラスタリング手法
・与えられたデータをk個のクラスタに分類する
・教師なし学習
1) 各クラスタ中心の初期値を設定する
2) 各データ点に対して、各クラスタ中心との距離を計算し、最も距離が近いクラスタを割り当てる
3) 各クラスタの平均ベクトル（中心）を計算する
4) 収束するまで2, 3の処理を繰り返す次から各手順の詳細を説明するk-平均法(k-means)

【ハンズオンサマリーと考察】

<B>K近傍法<B>

```
from sklearn.neighbors import KNeighborsClassifier
knc = KNeighborsClassifier(n_neighbors=n_neighbors).fit(X_train, ys_train)
plt_resut(X_train, ys_train, knc.predict(xx))
```
コーディングを切り出したところになる。n_neighborsの値に1,2,3..と異なる値を入れたり、print(knc.predict_proba([[0,0]]))みたいなものを入れて遊んでみたが、ｋが小さい値だと、境界線の近くの値を予測するとき、100%でこのラベルという風に出してしまい、あまりいい予測ではないと感じた。

<B>K平均法<B>

```
from sklearn.cluster import KMeans
X = wine.data
model = KMeans(n_clusters=3)
labels = model.fit_predict(X)
labels
```
ワィンを三種類に分ける問題。見にくいので、pd.DataFrame(wine.data, columns=wine.feature_names)で確認。wine.targetで答えがあるようである。ｋ平均法は、教師無し学習であるが、それを使わず予測して、予測と結果があってるかを照合するようである。StandardScalerとMinMaxScalerを使って前処理してみたが、予測の精度は上がってないように思える。下記は、MinMaxScalerの例であるが、MinMaxをStandardに置き換えれば、ほぼ同じである。

```
from sklearn.cluster import KMeans
from sklearn.preprocessing import MinMaxScaler
X = wine.data
model = KMeans(n_clusters=3)
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)
labels = model.fit_predict(X_scaled)
```

【ハンズオンサマリーと考察】

<B>サポートベクターマシーン<B>

・教師あり学習を用いるパターン認識モデルの一つである。分類や回帰へ適用できる。
・線形カーネルとは、単純にデータ間$x_{i},x_{j}$の内積を計算したものである。
・RBFカーネルを用いたSVMでは、コストパラメータを調整する。コストパラメータCは誤分類をどの程度許容するかを決めるパラメータ。大きくなるほど、誤りに厳しくなる。データ空間では線形分離は出来ないが、特徴空間上で線形分離することを考える。RBFカーネルのパラメータγの値が小さいほど単純な決定境界となり, 大きいほど歪なな形の決定境界となる。
・SVMでデータ点が境界の反対側に食い込むことを許容する制約緩和をソフトマージンと呼ぶ。許容する代わりに対して、ペナルティを与え修正する。

```
def rbf(u, v):
        sigma = 0.8
        return np.exp(-0.5 * ((u - v)**2).sum() / sigma**2)
    
X_train = x_train
t = np.where(y_train == 1.0, 1.0, -1.0)

n_samples = len(X_train)
# RBFカーネル
K = np.zeros((n_samples, n_samples))
for i in range(n_samples):
    for j in range(n_samples):
        K[i, j] = rbf(X_train[i], X_train[j])

eta1 = 0.01
eta2 = 0.001
n_iter = 5000

H = np.outer(t, t) * K

a = np.ones(n_samples)
for _ in range(n_iter):
    grad = 1 - H.dot(a)
    a += eta1 * grad
    a -= eta2 * a.dot(t) * t
    a = np.where(a > 0, a, 0)
```
このケースの場合、ある一定の範囲の乱数を発生させているので、前処理としてデータの標準をする意味はない。sigmaの値を0.01, 0.1, 1, 10と変えてみたが、0.01なら分類できず、0.1なら歪な境界で、1は良い境界で、10はおかしな境界だった。先程のγの説明と合っているのが分かった。

参考として、Support vector machinesの事が書かれたリンクをあげておく。ただし、英語で書かれている。
<a href="https://www.jeremyjordan.me/support-vector-machines/">Support vector machines</a>