サポートベクターマシン#

# 表形式のデータを操作するためのライブラリ
import pandas as pd

# 行列計算をおこなうためのライブラリ
import numpy as np

# データセット
from sklearn import datasets

# K近傍法を実行するためのクラス
from sklearn.neighbors import KNeighborsClassifier

# 決定木を実行するためのクラス
from sklearn.tree import DecisionTreeClassifier

# サポートベクターマシンを実行するためのモジュール
from sklearn import svm

# データ変換のためのクラス
import sklearn.preprocessing as preprocessing

# 交差検証を行うためのクラス
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_validate

# 評価指標(マクロ精度)
from sklearn.metrics import balanced_accuracy_score

クイズ#

Q1: 実行時間の計測#

機械学習モデルの交差検証を簡単に行ってくれるsklearnライブラリのcross_validate関数は,その返値(辞書)には

  • 学習の所要時間(fit_time

  • 評価(推論)の所要時間(score_time

に関する情報が格納されている(参考).

この情報を用いて,第6章の例題1におけるMNIST分類器を

  1. 多項式カーネル(kernel='poly')を用いたサポートベクターマシン

  2. K近傍法(K=5

  3. 決定木

の3つの機械学習手法で構築した際の

  • 分類器の性能

  • 分類器の構築(学習)にかかる時間

  • 分類器の評価(推論)にかかる時間

について比較を行いなさい.

mnist_dataset = datasets.load_digits()
X_mnist = mnist_dataset.data
y_mnist = mnist_dataset.target

# 5分割「層別化」交差検証の準備(乱数を固定)
k_fold = StratifiedKFold(n_splits=5, shuffle=True, random_state=12345)

# 評価指標(マクロ精度)
score_funcs = ['balanced_accuracy']

# K近傍法のモデルの定義(K=5で設定)
knn_model = KNeighborsClassifier(n_neighbors=5, metric="euclidean")

# SVMのモデルを定義(with 多項式カーネル)
svm_model = svm.SVC(kernel='poly')

# 決定木のモデルを定義
dt_model = DecisionTreeClassifier(criterion='entropy') 


# 交差検証をしながら分類器を構築・評価
results_knn = cross_validate(knn_model, X_mnist, y_mnist, cv=k_fold, scoring=score_funcs)
results_dt = cross_validate(dt_model, X_mnist, y_mnist, cv=k_fold, scoring=score_funcs)
results_svm = cross_validate(svm_model, X_mnist, y_mnist, cv=k_fold, scoring=score_funcs)


# 交差検証の結果 for K近傍法
print('\n====== K近傍法 ======')
print("マクロ精度: ", np.mean(results_knn['test_balanced_accuracy']))
print("学習にかかった時間: ", np.mean(results_knn['fit_time']))
print("推論にかかった時間: ", np.mean(results_knn['score_time']))

# 交差検証の結果 for 決定木
print('\n====== 決定木 ======')
print("マクロ精度: ", np.mean(results_dt['test_balanced_accuracy']))
print("学習にかかった時間: ", np.mean(results_dt['fit_time']))
print("推論にかかった時間: ", np.mean(results_dt['score_time']))

# 交差検証の結果 for SVM
print('\n====== SVM ======')
print("マクロ精度: ", np.mean(results_svm['test_balanced_accuracy']))
print("学習にかかった時間: ", np.mean(results_svm['fit_time']))
print("推論にかかった時間: ", np.mean(results_svm['score_time']))
====== K近傍法 ======
マクロ精度:  0.9870943800943801
学習にかかった時間:  0.0003855705261230469
推論にかかった時間:  0.02059464454650879

====== 決定木 ======
マクロ精度:  0.856150781033134
学習にかかった時間:  0.011775541305541991
推論にかかった時間:  0.0006442546844482421

====== SVM ======
マクロ精度:  0.9899356499356499
学習にかかった時間:  0.014054441452026367
推論にかかった時間:  0.004860019683837891

Q2: 年収カテゴリ分類の性能比較#

Q1で行った同様の比較を,第5章のクイズで取り組んだ年収カテゴリ分類問題に対して行いなさい.

adult_dataset_url = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data"

features = [
    "age",             # 年齢(数値)
    "workclass",       # 職業クラス(カテゴリカル)
    "fnlwgt",          # 不明
    "education",       # 最終学歴(カテゴリカル)
    "education_num",   # 教育年数(数値)
    "marital_status",  # 婚姻ステータス(カテゴリカル)
    "occupation",      # 職業(カテゴリカル)
    "relationship",    # 家族の構成(カテゴリカル)
    "race",            # 人種(カテゴリカル)
    "sex",             # 性別(カテゴリカル)
    "capital_gain",    # 資産売却益(数値)
    "capital_loss",    # 資産売却損(数値)
    "hours_per_week",  # 週の労働時間?(数値)
    "native_country",  # 母国(カテゴリカル)
    "annual_income"    # 年収(True of False)
]

adult_df = pd.read_table(
    adult_dataset_url, sep=", ", header=None,
    names=features, engine='python', na_values="?"
).assign(
    has_high_salary = lambda df: df["annual_income"].map({">50K": True, "<=50K": False})
).drop( # 不要 or 不明な特徴量を削除
    columns=['fnlwgt', 'annual_income']
)

# 最後の列の"has_high_salary"以外が特徴データ列
target_features = adult_df.columns[:-1]
X_adult = adult_df[target_features] 

# ターゲットラベルは"has_high_salary"
y_adult = adult_df["has_high_salary"] 

# ターゲットとなるカテゴリカルデータの特徴名(列名)
categorical_features = [
    "workclass",       # 職業クラス(カテゴリカル)
    "education",       # 最終学歴(カテゴリカル)
    "marital_status",  # 婚姻ステータス(カテゴリカル)
    "occupation",      # 職業(カテゴリカル)
    "relationship",    # 家族の構成(カテゴリカル)
    "race",            # 人種(カテゴリカル)
    "sex",             # 性別(カテゴリカル)
    "native_country",  # 母国(カテゴリカル)    
]

# Xのカテゴリカルデータ列をone-hotベクトル化
X_adult = pd.get_dummies(X_adult, columns=categorical_features, drop_first=True)

# 標準化のための変換器を用意
scaler = preprocessing.StandardScaler()

# 標準化
X_adult = pd.DataFrame(scaler.fit_transform(X_adult), columns=X_adult.columns)
# 5分割「層別化」交差検証の準備(乱数を固定)
k_fold = StratifiedKFold(n_splits=5, shuffle=True, random_state=12345)

# 評価指標(マクロ精度)
score_funcs = ['balanced_accuracy']

# K近傍法のモデルの定義(K=5で設定)
knn_model = KNeighborsClassifier(n_neighbors=5, metric="euclidean")

# SVMのモデルを定義(with 多項式カーネル)
svm_model = svm.SVC(kernel='poly')

# 決定木のモデルを定義
dt_model = DecisionTreeClassifier(criterion='entropy') 


# 交差検証をしながら分類器を構築・評価
results_knn = cross_validate(knn_model, X_adult, y_adult, cv=k_fold, scoring=score_funcs)
results_dt = cross_validate(dt_model, X_adult, y_adult, cv=k_fold, scoring=score_funcs)
results_svm = cross_validate(svm_model, X_adult, y_adult, cv=k_fold, scoring=score_funcs)


# 交差検証の結果 for K近傍法
print('\n====== K近傍法 ======')
print("マクロ精度: ", np.mean(results_knn['test_balanced_accuracy']))
print("学習にかかった時間: ", np.mean(results_knn['fit_time']))
print("推論にかかった時間: ", np.mean(results_knn['score_time']))

# 交差検証の結果 for 決定木
print('\n====== 決定木 ======')
print("マクロ精度: ", np.mean(results_dt['test_balanced_accuracy']))
print("学習にかかった時間: ", np.mean(results_dt['fit_time']))
print("推論にかかった時間: ", np.mean(results_dt['score_time']))

# 交差検証の結果 for SVM
print('\n====== SVM ======')
print("マクロ精度: ", np.mean(results_svm['test_balanced_accuracy']))
print("学習にかかった時間: ", np.mean(results_svm['fit_time']))
print("推論にかかった時間: ", np.mean(results_svm['score_time']))
====== K近傍法 ======
マクロ精度:  0.7388183077951892
学習にかかった時間:  0.0063113212585449215
推論にかかった時間:  0.1823986530303955

====== 決定木 ======
マクロ精度:  0.7460542297401241
学習にかかった時間:  0.07657160758972167
推論にかかった時間:  0.002299928665161133

====== SVM ======
マクロ精度:  0.7012037271887722
学習にかかった時間:  6.257583570480347
推論にかかった時間:  0.9678710460662842