機械学習チートシート
対象読者:機械学習に関する講義を履修済みの大学生や社会人の方
数式の導出過程に重きを置いていますが、細かい説明や背景は省いているので、これを最初の学習用としないでください
参考までにPythonでのデータ解析用コードを記しています
概要
教師あり学習
- 入力データと出力データから関数のパラメータを予測
教師なし学習
- 入力データだけから関数のパラメータを予測
強化学習
- 与えられた状態において報酬を最大化する行動を推定
データ前処理
標準化
- 平均が0、標準偏差が1となるように変換
- 単位や尺度の影響を取り除く
$$
z = \frac{x - \mu}{\sigma}
$$
from sklearn.preprocessing import StandardScaler
import numpy as np
X = np.array([[10, 20], [30, 40], [50, 60]])
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
print("標準化前:\n", X)
print("標準化後:\n", X_scaled)
多重共線性
- 説明変数同士の相関関係が高く、パラメータの推定が不安定になる
過学習
- 学習データに過剰に適合し、汎化性能が低下する
回帰(Regression)
最小二乗法
- 以下の損失関数を最小化
$$
L(\mathbf{w}) = | \mathbf{y} - X \mathbf{w} |^2
$$
$$
L(\mathbf{w}) = (\mathbf{y} - X \mathbf{w})^\top (\mathbf{y} - X \mathbf{w})
= \mathbf{y}^\top \mathbf{y} - 2 \mathbf{w}^\top X^\top \mathbf{y} + \mathbf{w}^\top X^\top X \mathbf{w}
$$
$$
\frac{\partial L}{\partial \mathbf{w}} = -2 X^\top \mathbf{y} + 2 X^\top X \mathbf{w} = 0
$$
$$
X^\top X \mathbf{w} = X^\top \mathbf{y}
$$
$$
\mathbf{w} = (X^\top X)^{-1} X^\top \mathbf{y}
$$
$X^\top X$ が正則である必要がある。多重共線性があると解が不安定になる
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.datasets import make_regression
X, y = make_regression(n_samples=100, n_features=1, noise=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
model = LinearRegression()
model.fit(X_train, y_train)
print("係数:", model.coef_)
print("切片:", model.intercept_)
print("決定係数 R2:", model.score(X_test, y_test))
正則化回帰
- 訓練データへの過剰な適合を防ぐため、パラメータの大きさにペナルティを与える
Ridge回帰(L2正則化)
$$
L(\mathbf{w}) = | \mathbf{y} - X \mathbf{w} |^2 + \lambda | \mathbf{w} |^2_2
$$
$$
\frac{\partial L}{\partial \mathbf{w}} = -2 X^\top \mathbf{y} + 2 X^\top X \mathbf{w} + 2 \lambda \mathbf{w} = 0
$$
$$
(X^\top X + \lambda I) \mathbf{w} = X^\top \mathbf{y}
$$
$$
\mathbf{w} = (X^\top X + \lambda I)^{-1} X^\top \mathbf{y}
$$
- 単位行列は正則化するパラメータに対応する対角成分のみ1とする
- 対角成分を足してランク落ちを防ぐことで、逆行列を安定に計算
Lasso回帰(L1正則化)
$$
L(\mathbf{w}) = | \mathbf{y} - X \mathbf{w} |^2 + \lambda | \mathbf{w} |_1
$$
- $\mathbf{w}$ の一部を0にする(特徴量選択)
- 解析的に解けないため、数値計算を行う
# Ridge回帰
from sklearn.linear_model import Ridge
ridge = Ridge(alpha=1.0)
ridge.fit(X_train, y_train)
print("Ridge回帰 R2:", ridge.score(X_test, y_test))
# Lasso回帰
from sklearn.linear_model import Lasso
lasso = Lasso(alpha=0.1)
lasso.fit(X_train, y_train)
print("Lasso回帰 R2:", lasso.score(X_test, y_test))
print("Lassoで選択された特徴量:", lasso.coef_)
評価指標
MSE(Mean Squared Error)
$$
\text{MSE} = \frac{1}{N} \sum_{n=1}^{N} (y_n - \hat{y}_n)^2
$$
MAE(Mean Absolute Error)
$$
\text{MAE} = \frac{1}{N} \sum_{n=1}^{N} |y_n - \hat{y}_n|
$$
R^2 スコア(決定係数)
$$
R^2 = 1 - \frac{\sum^N _{n-1} (y_i - \hat{y}_i)^2}{\sum^N _{n-1} (y_i - \bar{y})^2}
$$
- $R^2 = 1$:$y_i=\hat{y}_i$
完全に説明できている - $R^2 = 0$:$\hat{y}_i=\bar{y}$
平均を使うのと同等
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
y_pred = model.predict(X_test)
print("MSE:", mean_squared_error(y_test, y_pred))
print("MAE:", mean_absolute_error(y_test, y_pred))
print("R2:", r2_score(y_test, y_pred))
ホールドアウト法
- データを訓練用と検証用にランダムに分割し、汎化性能を検証
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)
交差検証法(Cross Validation)
- 元のデータから一つずつ検証用データとして選び、すべてのデータが訓練・検証に一度ずつ使われるように評価する
K-fold交差検証法
- データをK個の等しいサイズのサブセットに分割し、各サブセットを1回ずつ検証用データとし、残りを訓練用データに使ってK回モデルを評価
from sklearn.model_selection import KFold, cross_val_score
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
iris = load_iris()
X, y = iris.data, iris.target == 0
kf = KFold(n_splits=5, shuffle=True, random_state=1)
model = LogisticRegression()
scores = cross_val_score(model, X, y, cv=kf)
print("各Foldのスコア:", scores)
print("平均スコア:", scores.mean())
混同行列(Confusion Matrix)
真値\識別 | P | N |
---|---|---|
P | TP(True Positive) | FN(False Negative) |
N | FP(False Positive) | TN(True Negative) |
- TP: 正しく陽性と判定された数(真陽性)
- TN: 正しく陰性と判定された数(真陰性)
- FP: 本当は陰性なのに陽性と判定された数(偽陽性)
- FN: 本当は陽性なのに陰性と判定された数(偽陰性)
Recall(再現率)
$$
\text{Recall} = \frac{TP}{TP + FN}
$$
- 実際に陽性だったもののうち、陽性と正しく予測された割合
Precision(適合率)
$$
\text{Precision} = \frac{TP}{TP + FP}
$$
- 陽性と予測したもののうち、実際に陽性だった割合
Accuracy(正解率)
$$
\text{Accuracy} = \frac{TP + TN}{TP + TN + FP + FN}
$$
- 全体のうち、正しく分類できた割合。
F1 スコア
$$
F1 = \frac{2 \cdot \text{Precision} \cdot \text{Recall}}{\text{Precision} + \text{Recall}}
$$
- Precision と Recall の調和平均
from sklearn.metrics import confusion_matrix, classification_report
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
iris = load_iris()
X, y = iris.data, iris.target
# 2クラスに簡略化 (class 0 vs rest)
y_binary = (y == 0).astype(int)
X_train, X_test, y_train, y_test = train_test_split(X, y_binary, random_state=42)
model = LogisticRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print("Confusion Matrix:\n", confusion_matrix(y_test, y_pred))
print("Classification Report:\n", classification_report(y_test, y_pred))
ROC曲線・AUC
- ROC(Receiver Operating Characteristic)
横軸:False Positive Rate(FPR)
縦軸:True Positive Rate(TPR) - AUC:(Area Under the Curve)
ROC曲線の下の面積
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc
y_prob = model.predict_proba(X_test)[:,1]
fpr, tpr, thresholds = roc_curve(y_test, y_prob)
roc_auc = auc(fpr, tpr)
plt.plot(fpr, tpr, label=f'ROC curve (area = {roc_auc:.2f})')
plt.plot([0, 1], [0, 1], linestyle='--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.legend()
plt.show()
ロジスティック回帰
- $y \in {0,1}$ に対して、事後確率をシグモイド関数で表現:
$$
P(\mathbf{x}) = \frac{1}{1 + e^{-(w_0 + \mathbf{w}^T \mathbf{x})}}
$$
$$
L(\mathbf{w}) = \prod_{n=1} ^N P(\mathbf{x}) ^{y_n} (1 - P(\mathbf{x})) ^{1 - y_n}
$$
$$
\log L(\mathbf{w}) = \sum_{n=1}^N \left[ y_n \log P(\mathbf{x}) + (1 - y_n) \log (1 - P(\mathbf{x})) \right]
$$
$$
\mathcal{L}(\mathbf{w}) = -\sum_{n=1}^N \left[ y_n \log P(\mathbf{x}) + (1 - y_n) \log (1 - P(\mathbf{x})) \right]
$$
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
y_prob = model.predict_proba(X_test)[:, 1]
識別
最近傍法
$$
\hat{y} = \arg\min_y (\min_n d(\mathbf{x}-\mathbf{x^{(y)}_n}))
$$
- データのノイズに強く影響する
k-NN(k近傍法)
- 入力データに最も近い $k$ 個のサンプルを選び、多数決でクラスを決定
- 過学習を防止
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train, y_train)
print("k-NN 正解率:", knn.score(X_test, y_test))
サポートベクトルマシン(SVM)
ハードマージン
決定境界:
$$
\mathbf{w}^T \mathbf{x} + w_0 = 0
$$
ご分類なしの場合、ラベル $y_i \in {-1, +1}$に対して以下の式が成り立つ:
$$
y_i(\mathbf{w}^T \mathbf{x}_i + w_0) \geq 1 \quad
$$
サポートベクトル $\mathbf{x}_i$ から決定境界への距離:
$$
M = \frac{y_i (\mathbf{w}^T \mathbf{x}_i + w_0)}{|\mathbf{w}|}
$$
Mの最大化は$\mathbf{w}$の最小化と同値である
$$
\min_{\mathbf{w}, w_0} |\mathbf{w}|^2 , y_i (\mathbf{w}^T \mathbf{x}_i + w_0) \geq 1 \quad
$$
ソフトマージン
現実のデータは完全に線形分離できないので、スラック変数 $\xi_i$ を導入:
$$
\begin{align}
\min_{\mathbf{w}, w_0, \boldsymbol{\xi}} \quad & \frac{1}{2} |\mathbf{w}|^2 + C \sum_{i=1}^N \xi_i ,
y_i(\mathbf{w}^T \mathbf{x}_i + w_0) \geq 1 - \xi_i
\end{align}
$$
カーネルトリック(非線形分離)
入力 $\mathbf{x}$ を非線形写像 $\phi(\mathbf{x})$ で高次元空間に写像:
$$
K(\mathbf{x}_i, \mathbf{x}_j) = \phi(\mathbf{x}_i)^T \phi(\mathbf{x}_j)
$$
双対問題の内積をカーネルに置き換えれば非線形SVMが得られる:
$$
f(\mathbf{x}) = \sum_{i=1}^{N} \alpha_i y_i K(\mathbf{x}_i, \mathbf{x}) + b
$$
代表的なカーネル:
- 線形カーネル:
$K(\mathbf{x_i}, \mathbf{x_j}) = \mathbf{x_i}^T \mathbf{x_j}$ - 多項式カーネル:
$K(\mathbf{x_i}, \mathbf{x_j}) = (\mathbf{x_i}^T \mathbf{x_j} + c)^d$ - RBFカーネル:
$K(\mathbf{x_i}, \mathbf{x_j}) = \exp\left(-\gamma{|\mathbf{x_i} - \mathbf{x_j}|^2}\right)$
from sklearn.svm import SVC
svm = SVC(kernel='rbf', C=1.0, gamma='scale')
svm.fit(X_train, y_train)
print("SVM 正解率:", svm.score(X_test, y_test))
決定木
- 木構造を用いて、ルールに従った分類または回帰を行う
- $\log_2N$回の分岐でどのような入力データも分類可能
ジニ不純度(Gini Imprity)
- ある領域に相当するノード$t$において誤分類する確率
- 誤分類がないとき0で最小、異なるクラスで同じ数だけ誤分類されるとき最大
$$
G(t) = 1 - \sum_{k=1}^{K} P^2(C_k\mid t)
$$
$$
P^2(C_k\mid t) = \frac{N_k(t)}{N(t)}
$$
$$
P^2(C_k\mid t):ノードtでk番目のクラスが選ばれる確率
$$
- ジニ不純度の差分が最大となる境界値で分割
- 左右それぞれのノードにおけるジニ不純度を $G(t_L)$, $G(t_R)$ とすると、
$$
\Delta G(t) = G(t)-\left( \frac{N(t_L)}{N(t)} G(t_L) + \frac{N(t_R)}{N(t)} G(t_R) \right)
$$
剪定(Pruning)
-
決定木の部分木をいくつか削除することで過学習を防止
-
以下のコスト複雑度を最小化
$$
G_\alpha(T) = G(T) + \alpha |T|
$$
$G(T)$: 木 $T$ による誤分類率
$|T|$: 葉ノードの数(木のサイズ)
$\alpha$: 複雑度に対するペナルティ係数
from sklearn.tree import DecisionTreeClassifier
from sklearn import tree
import matplotlib.pyplot as plt
dt = DecisionTreeClassifier(max_depth=3, random_state=42)
dt.fit(X_train, y_train)
plt.figure(figsize=(12,8))
tree.plot_tree(dt, filled=True, feature_names=iris.feature_names, class_names=['Not class0','Class0'])
plt.show()
バイアス・バリアンス分解
$$
\mathbb{E} \left[ |\hat{\mathbf{y}} - \mathbf{y} |^2 \right]
=\mathbb{E}\left[|\hat{\mathbf{y}} - \mathbb{E}[\hat{\mathbf{y}}]|^2\right]+|\mathbb{E}[\hat{\mathbf{y}}] - \mathbf{y}|^2
$$
- 第1項はバリアンス
- 第2項はバイアスの二乗
- バリアンスとバイアスはトレードオフの関係
アンサンブル学習
- 複数のモデル(弱学習器)を組み合わせて、精度の向上や過学習の抑制を図る
バギング
- バリアンスが大きく、バイアスが小さい弱学習器を集めてモデルを作成
- 無相関な決定木の多数決や平均により予測
- 元の訓練データから重複ありの復元抽出を行うブートストラップ法を行う
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
bagging = BaggingClassifier(base_estimator=DecisionTreeClassifier(), n_estimators=10, random_state=42)
bagging.fit(X_train, y_train)
print("バギング 正解率:", bagging.score(X_test, y_test))
ブースティング
- バイアスが大きく、バリアンスが小さい弱学習器を集めてモデルを作成
from sklearn.ensemble import AdaBoostClassifier
ada = AdaBoostClassifier(n_estimators=50, random_state=42)
ada.fit(X_train, y_train)
print("AdaBoost 正解率:", ada.score(X_test, y_test))
ランダムフォレスト(Random Forest)
- バギングに説明変数のランダムサンプリングを加えることで、バリアンスを抑え、過学習を防ぐ
- 各決定木の分岐時に説明変数$p$個からランダムに$\sqrt{p}$ 個だけ選ぶ
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train, y_train)
print("ランダムフォレスト 正解率:", rf.score(X_test, y_test))
クラスタリング
k-meansクラスタリング
- 各データ点 $\mathbf{x}_i$ を $K$ 個のクラスタに分類する手法
以下の損失関数を最小化:
$$
L(\mu_k) = \sum_{k=1}^{K} \sum_{\mathbf{x}_n \in C_k} | \mathbf{x}_i - \boldsymbol{\mu}_k |^2
$$
$$
\mathbf{\mu_k} = \frac{1}{|C_k|} \sum^N_{n=1,\mathbf{x_n} \in C_k} \mathbf{x_n}
$$
- $C_k$: クラスタ $k$
- $\boldsymbol{\mu}_k$: クラスタ $k$ の中心(Centroid)
- ランダムな初期値に依存するため、局所解に陥ることがある
from sklearn.cluster import KMeans
import numpy as np
X = np.array([[1, 2], [1, 4], [1, 0],
[4, 2], [4, 4], [4, 0]])
kmeans = KMeans(n_clusters=2, random_state=42)
kmeans.fit(X)
print("クラスタ割当:", kmeans.labels_)
print("クラスタ中心:", kmeans.cluster_centers_)
エルボー法
- 最適なクラスタ数 $K$ を選ぶ方法
- クラスタ数の増加に伴う損失関数の減少度合いが緩やかになるKを選択する
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
# サンプルデータ作成
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)
# SSE (Within-Cluster Sum of Squares) の計算
sse = []
k_range = range(1, 11)
for k in k_range:
kmeans = KMeans(n_clusters=k, random_state=0)
kmeans.fit(X)
sse.append(kmeans.inertia_) # inertia_ はSSE
# プロット
plt.plot(k_range, sse, 'bx-')
plt.xlabel('クラスタ数 k')
plt.ylabel('SSE (Within-cluster sum of squares)')
plt.title('エルボー法によるクラスタ数決定')
plt.show()
生成モデル
- 観測データ$x$の母集団の確率分布をモデル化する
- モデルの表現力向上のため、潜在変数を導入
EMアルゴリズム(Expectation-Maximization Algorithm)
- 潜在変数を含む確率モデルのパラメータ推定に用いられる反復最適化手法
- Eステップ:隠れ変数の分布の期待値を計算
- Mステップ:期待値で得られた分布を用いてパラメータを最適化
- 局所最適に収束するが、大域最適とは限らない
\begin{aligned}
\ln p(\mathbf{x};\theta)
&= \sum_{\mathbf{z}} q(\mathbf{z}) \ln p(\mathbf{x};\theta) \\
&= \sum_{\mathbf{z}} q(\mathbf{z}) \ln \frac{p(\mathbf{x}, \mathbf{z};\theta)}{p(\mathbf{z}|\mathbf{x};\theta)} \\
&= \sum_{\mathbf{z}} q(\mathbf{z}) \ln \frac{p(\mathbf{x}, \mathbf{z};\theta)}{q(\mathbf{z})} \cdot \frac{q(\mathbf{z})}{p(\mathbf{z}|\mathbf{x};\theta)} \\
&= \sum_{\mathbf{z}} q(\mathbf{z}) \ln \frac{p(\mathbf{x}, \mathbf{z};\theta)}{q(\mathbf{z})} + \sum_{\mathbf{z}} q(\mathbf{z}) \ln \frac{q(\mathbf{z})}{p(\mathbf{z}|\mathbf{x};\theta)} \\
&= \underbrace{\mathcal{L}(q,\theta)}_{\text{ELBO}} + \underbrace{D(q\|p)}_{\text{KL - divergence}}
\end{aligned}
$D(q|p)=0$より$q(\mathbf{z}) = p(\mathbf{z}|\mathbf{x}; \theta)$
$$
\mathcal{L}(q, \theta) = \sum_{\mathbf{z}} p(\mathbf{z}|\mathbf{x}; \theta) \ln p(\mathbf{x}, \mathbf{z}; \theta) - \sum_{\mathbf{z}} p(\mathbf{z}|\mathbf{x}; \theta) \ln q(\mathbf{z})
$$
第二項は定数と見なせるため、第一項(完全データ対数尤度の期待値)を最大化する:
$$
Q(\theta, \theta^{\text{old}}) = p(\mathbf{z}|\mathbf{x}; \theta) \ln p(\mathbf{x}, \mathbf{z}; \theta)
$$
混合ガウス分布(GMM)
$$
p(\mathbf{x}) = \sum_{k=1}^{K} \pi_k \mathcal{N}(\mathbf{x} \mid \boldsymbol{\mu}_k, \boldsymbol{\Sigma}_k)
$$
- $\pi_k$: 混合比 $\sum_{k=1}^{K} \pi_k =1$
- $\mathcal{N}$: 多変量正規分布
import numpy as np
import matplotlib.pyplot as plt
from sklearn.mixture import GaussianMixture
from sklearn.datasets import make_blobs
# データ作成
X, y_true = make_blobs(n_samples=400, centers=3, cluster_std=0.60, random_state=42)
# GMM モデルの作成と学習
gmm = GaussianMixture(n_components=3, covariance_type='full', random_state=42)
gmm.fit(X)
# 各データ点のクラスタ予測
labels = gmm.predict(X)
# 結果の可視化
plt.scatter(X[:, 0], X[:, 1], c=labels, s=40, cmap='viridis')
plt.title("Gaussian Mixture Model (EMアルゴリズム)によるクラスタリング")
plt.show()
階層的クラスタリング(Hierarchical Clustering)
- クラスタ間距離が最も近いクラスタを段階的に統合
全てのペア $(i,j)$ に対して距離を計算し、$n \times n$ の距離行列 $\mathbf{D}$ を得る:
$$
\mathbf{D}_{ij} = d(\mathbf{x}_i, \mathbf{x}_j)
$$
クラスタ間距離
単連結(Single Linkag)
$$
D(C_i, C_j) = \min_{x \in C_i, y \in C_j} d(x_i, y_j)
$$
完全連結(Complete Linkage)
$$
D(C_i, C_j) = \max_{x \in C_i, y \in C_j} d(x_i, y_j)
$$
平均連結(Average Linkage)
$$
D(C_i, C_j) = \frac{1}{|C_i||C_j|} \sum_{x \in C_i,y \in C_j} d(x_i, y_j)
$$
ウォード連結(Ward Linkage)
$$
D(C_i, C_j) = \sum_{x \in C_i \cup C_j} ( x - \mu_{C_i \cup C_j} )^2 - \left( \sum_{x \in C_i} ( x - \mu_{C_i} )^2 + \sum_{x \in C_j} ( x - \mu_{C_j} )^2 \right)
$$
系統樹(dendrogram)
- 階層的クラスタリングにおける統合過程を視覚化
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt
import numpy as np
X = np.array([[1, 2], [3, 4], [5, 6], [8, 8]])
Z = linkage(X, 'ward')
plt.figure(figsize=(6, 4))
dendrogram(Z)
plt.show()
主成分分析(Principal Component Analysis: PCA)
- 多次元データをより少ない次元に射影して、元のデータの分散をできるだけ保持する次元削減
中心化(平均0)したデータの$\mathbf{w}$への射影の二乗が最大になるような$\mathbf{w}$を求める:
$$
|\mathbf{Xw}|^2 = (\mathbf{Xw})^T\mathbf{Xw}=\mathbf{w^T X^T}\mathbf{Xw}
$$
$$
|\mathbf{w}|^2 = \mathbf{w^T w} = 1
$$
Lagrange未定乗数を導入:
$$
L(\mathbf{w}, \lambda) = \mathbf{w}^T \mathbf{X}^T \mathbf{X} \mathbf{w} - \lambda (\mathbf{w}^T \mathbf{w} - 1)
$$
このラグランジュ関数を $\mathbf{w}$ で偏微分してゼロとおくと、
$$
\frac{L}{\partial \mathbf{w}} = 2 \mathbf{X}^T \mathbf{X} \mathbf{w} - 2 \lambda \mathbf{w} = \mathbf{0}
$$
$$
\mathbf{X}^T \mathbf{X} \mathbf{w} = \lambda \mathbf{w}
$$
$\mathbf{w}$ は 共分散行列$\mathbf{X}^T \mathbf{X}$ の固有ベクトル、$\lambda$ は対応する固有値となる
この固有値問題を解いて、最大の固有値に対応する固有ベクトルが第一主成分の射影方向
寄与率(Explained Variance Ratio)
- 各主成分がデータ全体の分散のうちどれだけを説明しているかを示す
$$
\frac{\lambda_i}{\sum_{i=1}^p \lambda_i}
$$
累積寄与率(Cumulative Explained Variance Ratio)
$$
\frac{\sum_{i=1}^{p'}\lambda_i}{\sum_{i=1}^p \lambda_i}\quad (q'\leq q)
$$
from sklearn.decomposition import PCA
import numpy as np
X = np.random.rand(100, 5)
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
print("寄与率:", pca.explained_variance_ratio_)
print("変換後データ形状:", X_pca.shape)
ニューラルネットワーク(Neural Networks)
- 多層のノードと活性化関数で構成されるモデル
活性化関数
- ReLU
$$
f(x) = \max(0, x)
$$ - Sigmoid
$$
f(x) = \frac{1}{1 + e^{-x}}
$$
出力は0から1の範囲
勾配消失問題あり - tanh
$$
f(x) = \tanh(x) = \frac{e^{x} - e^{-x}}{e^{x} + e^{-x}}
$$
出力範囲は -1 から 1
import torch
import torch.nn as nn
import torch.optim as optim
class SimpleNN(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(10, 5)
self.relu = nn.ReLU()
self.fc2 = nn.Linear(5, 1)
def forward(self, x):
x = self.relu(self.fc1(x))
x = self.fc2(x)
return x
model = SimpleNN()
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
# ダミーデータ
x = torch.randn(3, 10)
y = torch.randn(3, 1)
# 学習ステップ例
optimizer.zero_grad()
output = model(x)
loss = criterion(output, y)
loss.backward()
optimizer.step()
勾配降下法
- パラメータ $w$ を損失関数 $L(w)$ の勾配に沿って更新:
$$
w \leftarrow w - \eta \nabla L(w)
$$
$\eta$:学習率
誤差伝播法
- 多層ネットワークで出力層から入力層へ誤差を逆伝播し、各パラメータの勾配を効率的に計算
$$
\frac{\partial y}{\partial x} = \frac{\partial y}{\partial y} \cdot \frac{\partial y}{\partial a} \cdot \frac{\partial a}{\partial b} \cdot \frac{\partial b}{\partial x}
$$
$$
\delta_j^{(l)} = \sum_k \delta_k^{(l+1)} \frac{\partial u_k^{(l+1)}}{\partial u_j^(l)}
$$
確率勾配降下法
- データの一部をランダムにバッチとして選び、バッチを用いて勾配降下法を行う
- 局所解に陥ることを防ぐ
スキップ接続
- 深いネットワークで勾配消失を防ぐために、層をまたいで入力を後の層に直接渡す
- 出力 $y = F(x) + x$
Dropout
- 過学習防止のため、学習時にランダムに一部のニューロンの結合を削除
CNN(畳み込みニューラルネットワー)
- 画像や時系列データなどの局所特徴抽出に適したネットワーク
畳み込み演算(Convolution)
入力画像 $I$ とフィルタ $K$ の畳み込み:
$$
S(i,j) = (I * K)(i,j) = \sum_m \sum_n I(i-m, j-n) K(m,n)
$$
パディング
- 畳み込み時に画像の端を拡張し、ゼロパディングなどを施すことで出力サイズを調整
ストライド
- フィルタをスライドさせる移動幅
- 出力サイズの調整や計算効率の効率化を行う
プーリング
- 特徴マップの空間サイズを縮小し、計算負荷を削減
- 最大値プーリング、平均値プーリングなどが用いられる
VAE(変分オートエンコーダ)
- 入力 $x$ を潜在変数 $z$ にエンコードし、デコードする生成モデル
損失関数:
$$
ELBO(x;\theta,\phi) = -\frac{1}{2}\sum^D_{d=1}(x_d-\hat{x_d})^2 + \frac{1}{2}\sum^H_{h=1}(1+\log\delta_n^2-\mu_h^2-\delta_n^2)+condt
$$
第一項:再構成誤差
第二項:正則化項
ベイズ推論
- パラメータ $\theta$ に対する事後確率を計算して推論を行う:
$$
P(\theta|D) = \frac{P(D|\theta) P(\theta)}{P(D)}
$$
$P(D|\theta)$:尤度
$P(\theta)$:事前確率
$P(D)$:エビデンス
import torch.nn as nn
class SimpleCNN(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, padding=1)
self.relu = nn.ReLU()
self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
self.fc = nn.Linear(16 * 16 * 16, 10) # 例: 32x32画像の場合
def forward(self, x):
x = self.pool(self.relu(self.conv1(x)))
x = x.view(x.size(0), -1)
x = self.fc(x)
return x