👌

ラビット・チャレンジ レポート 機械学習

2022/03/20に公開

線形回帰モデル

1-1 要点

  • 回帰問題を解くための機械学習モデルの一つであり、教師あり学習(教師データから学習)に該当する
  • 入力とm次元パラメータの線形結合を出力するモデルである
    • 慣例として予測値にはハットを付ける(正解データとは異なる)
  • 線形結合とは?
    • 入力ベクトルと未知のパラメータの各要素を掛け算し足し合わせたもの
    • 入力ベクトルとの線形結合に加え、切片も足し合わせる
    • (入力のベクトルが多次元でも)出力は1次元(スカラ)となる

パラメータ
$$
\begin{align}
\textbf{w} = (w_1, w_2,\cdots, w_m)^T \in R
\end{align}
$$

線形結合

\begin{align} \hat y = \textbf{w}^T\textbf{x} + w_0 = \sum _{j=1} ^{m} {w_j x_j + w_0} \end{align}
  • 通常パラメータは未知のため、平均二乗誤差が最小となるような探索を行う最小二乗法を用いて推定する

1-2 実装

  • ボストンの住宅データセットを線形回帰モデルで分析
    • 部屋数が4で犯罪率が0.3の物件はいくらになるか?
import pandas as pd
from sklearn.datasets import load_boston
from sklearn.linear_model import LinearRegression

boston = load_boston()
df = pd.DataFrame(data=boston.data, columns = boston.feature_names)
df['PRICE'] = np.array(boston.target)

X = df.loc[:, ['CRIM', 'RM']].values
Y = df.loc[:, 'PRICE'].values

model = LinearRegression()
model.fit(X, Y)
model.predict([[0.3, 4]])

結果
array([4.24007956]) ≒ $4,240

非線形回帰モデル

2-1 要点

  • データの構造を線形で捉えられる場合は限られており、非線形な構造を捉えられる仕組みが必要
  • 基底展開法
    • 回帰関数として、基底関数と呼ばれる既知の非線形関数とパラメータベクトルの線型結合を使用
    • 未知パラメータは線形回帰モデルと同様に最小2乗法や最尤法により推定
  • よく使われる基底関数
    • 多項式関数
    • ガウス型基底関数
    • スプライン関数/ Bスプライン関数

2-2 実装

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.linear_model import LinearRegression
from sklearn.kernel_ridge import KernelRidge
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline

sns.set()
sns.set_style("darkgrid", {'grid.linestyle': '--'})
sns.set_context("paper")

n=100

def true_func(x):
    z = 1-48*x+218*x**2-315*x**3+145*x**4
    return z 

def linear_func(x):
    z = x
    return z 

data = np.random.rand(n).astype(np.float32)
data = np.sort(data)
target = true_func(data)

noise = 0.5 * np.random.randn(n) 
target = target  + noise
plt.scatter(data, target)

plt.title('NonLinear Regression')
plt.legend(loc=2)
clf = LinearRegression()
data = data.reshape(-1,1)
target = target.reshape(-1,1)
clf.fit(data, target)

p_lin = clf.predict(data)

plt.scatter(data, target, label='data')
plt.plot(data, p_lin, color='darkorange', marker='', linestyle='-', linewidth=1, markersize=6, label='linear regression')
plt.legend()
print(clf.score(data, target))
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()
deg = [1,2,3,4,5,6,7,8,9,10]
for d in deg:
    regr = Pipeline([
        ('poly', PolynomialFeatures(degree=d)),
        ('linear', LinearRegression())
    ])
    regr.fit(data, target)
    p_poly = regr.predict(data)
    plt.scatter(data, target, label='data')
    plt.plot(data, p_poly, label='polynomial of degree %d' % (d))

ロジスティック回帰

3-1 要点

  • 分類問題を解くための教師あり機械学習モデル(教師データから学習)である

    • 入力とm次元パラメータの線形結合をシグモイド関数に入力
    • 出力はy=1になる確率の値になる
  • シグモイド関数

    • 入力は実数・出力は必ず0~1の値
    • (クラス1に分類される)確率を表現
    • 単調増加関数
  • シグモイド関数の出力をY=1になる確率に対応させる

    • データの線形結合を計算
    • シグモイド関数に入力▶️出力が確率に対応
    • i番目データを与えた時のシグモイド関数の出力をi番目のデータがY=1になる確率とする

シグモイド関数
$$
\begin{align}
\sigma = \frac{1}{1 + exp(-\alpha x)}
\end{align}
$$

求めたい値
$$
\begin{align}
P( Y=1 | \textbf{x}) = \sigma (w_0 + w_1 x_1 + \cdots + w_m x_m)
\end{align}
$$

3-3 実装

タイタニックの乗客データを用いて、30歳・男の乗客は生き残れるか予測

import pandas as pd
from sklearn.linear_model import LogisticRegression

titanic = pd.read_csv("/content/drive/My Drive/titanic_train.csv")
titanic["AgeFill"] = titanic["Age"].fillna(titanic["Age"].mean())
titanic["Gender"] = titanic["Sex"].map({"female" : 0, "male" : 1}).astype(int)

X = titanic.loc[:, ["AgeFill", "Gender"]]
y = titanic.loc[:, "Survived"]

logistic = LogisticRegression()
logistic.fit(X, y)
logistic.predict_proba([[30, 1]])

結果
array([[0.80668102, 0.19331898]]) ≒ 19.3%

主成分分析

4-1 要点

  • 多変量データの持つ構造をより少数個の指標に圧縮 = データの次元を削減する手法

    • 変量の個数を減らすことに伴う、情報の損失はなるべく小さくしたい
    • 少数変数を利用した分析や可視化(2・3次元の場合)が実現可能
  • 係数ベクトルが変われば線形変換後の値が変化

    • 情報の量を分散の大きさと捉える
    • 線形変換後の変数の分散が最大となる射影軸を探索

4-2 実装

  • 設定
    • 乳がん検査データを利用しロジスティック回帰モデルを作成
    • 主成分を利用し2次元空間上に次元圧縮
  • 課題
    • 32次元のデータを2次元上に次元圧縮した際に、うまく判別できるかを確認
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegressionCV
from sklearn.decomposition import PCA

cancer_df = pd.read_csv('/content/drive/My Drive/study_ai_ml/data/cancer.csv')
X = cancer_df.loc[:, 'radius_mean':]
y = cancer_df.diagnosis.apply(lambda d: 1 if d == 'M' else 0)

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)

pca = PCA(n_components=2)
X_train_pca = pca.fit_transform(X_train_scaled)
X_test_pca = pca.fit_transform(X_test_scaled)

logistic.fit(X_train_pca, y_train)

print('主成分分析未実施: {:.3f}'.format(logistic.score(X_test_scaled, y_test)))
print('主成分分析実施: {:.3f}'.format(logistic.score(X_test_pca, y_test)))

主成分分析未実施:0.972
主成分分析実施:0.944

特徴量を2次元に削減しても、予測精度は2.8%しか変わらない

サポートベクターマシン

5-1 要約

  • 回帰または分類に適用できる教師あり学習の機械学習手法に該当する
  • 2クラス分類として扱う場合、分類境界に最も近いデータをサポートベクトル、分類境界とサポートベクトルの距離をマージンという
  • マージンを最大化するような分類境界面を探索する
  • 分類誤りを許容しない分類(完全分離可能な問題のみ対応)をハードマージンというのに対し、多少の分類誤りを許容して使い勝手を上げた分類をソフトマージンという

5-2 実装

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt

def gen_data():
    x0 = np.random.normal(size=50).reshape(-1, 2) - 2.
    x1 = np.random.normal(size=50).reshape(-1, 2) + 2.
    X_train = np.concatenate([x0, x1])
    ys_train = np.concatenate([np.zeros(25), np.ones(25)]).astype(np.int)
    return X_train, ys_train

X_train, ys_train = gen_data()

t = np.where(ys_train == 1.0, 1.0, -1.0)

n_samples = len(X_train)

K = X_train.dot(X_train.T)

eta1 = 0.01
eta2 = 0.001
n_iter = 500

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)

index = a > 1e-6
support_vectors = X_train[index]
support_vector_t = t[index]
support_vector_a = a[index]

term2 = K[index][:, index].dot(support_vector_a * support_vector_t)
b = (support_vector_t - term2).mean()

xx0, xx1 = np.meshgrid(np.linspace(-5, 5, 100), np.linspace(-5, 5, 100))
xx = np.array([xx0, xx1]).reshape(2, -1).T

X_test = xx
y_project = np.ones(len(X_test)) * b
for i in range(len(X_test)):
    for a, sv_t, sv in zip(support_vector_a, support_vector_t, support_vectors):
        y_project[i] += a * sv_t * sv.dot(X_test[i])
y_pred = np.sign(y_project)


plt.scatter(X_train[:, 0], X_train[:, 1], c=ys_train)
plt.scatter(support_vectors[:, 0], support_vectors[:, 1],
                    s=100, facecolors='none', edgecolors='k')

plt.contour(xx0, xx1, y_project.reshape(100, 100), colors='k',
                     levels=[-1, 0, 1], alpha=0.5, linestyles=['--', '-', '--'])

plt.quiver(0, 0, 0.1, 0.35, width=0.01, scale=1, color='pink')

Discussion

ログインするとコメントできます