はじめに
機械学習において、特徴量の離散化とは、データセット内の連続変数の数を減らすために、ビンまたは区間を作成して表現する方法です。この方法は、連続変数の数が多く、アルゴリズムを簡略化して分析を容易にする必要がある場合に役立ちます。この実験では、合成分類データセットに対する特徴量の離散化を示します。
VM のヒント
VM の起動が完了したら、左上隅をクリックしてノートブックタブに切り替え、Jupyter Notebook を使って練習しましょう。
Jupyter Notebook が読み込み終わるまで数秒待つことがあります。Jupyter Notebook の制限により、操作の検証は自動化できません。
学習中に問題がある場合は、Labby にお問い合わせください。セッション後にフィードバックを提供してください。すぐに問題を解決いたします。
ライブラリのインポート
このステップでは、実験に必要なライブラリをインポートします。機械学習タスクには scikit - learn ライブラリを、数学的演算には numpy を、データ可視化には matplotlib を使用します。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_moons, make_circles, make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import KBinsDiscretizer
from sklearn.svm import SVC, LinearSVC
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.utils._testing import ignore_warnings
from sklearn.exceptions import ConvergenceWarning
データの準備
このステップでは、特徴量の離散化のための合成分類データセットを準備します。scikit - learn ライブラリを使って、3 種類の異なるデータセット:月型、同心円型、線形に分離可能なデータを生成します。
h = 0.02 ## メッシュのステップサイズ
n_samples = 100
datasets = [
make_moons(n_samples=n_samples, noise=0.2, random_state=0),
make_circles(n_samples=n_samples, noise=0.2, factor=0.5, random_state=1),
make_classification(
n_samples=n_samples,
n_features=2,
n_redundant=0,
n_informative=2,
random_state=2,
n_clusters_per_class=1,
),
]
分類器とパラメータの定義
このステップでは、特徴量の離散化プロセスで使用する分類器とパラメータを定義します。ロジスティック回帰、線形サポートベクターマシン(SVM)、勾配ブースティング分類器、およびラジアルベーシス関数カーネルを持つ SVM を含む分類器のリストを作成します。また、GridSearchCV アルゴリズムで使用する各分類器のパラメータセットも定義します。
## (推定器,パラメータグリッド) のリストで、パラメータグリッドは GridSearchCV で使用されます
## この例では、実行時間を短縮するためにパラメータ空間を狭い範囲に限定しています。
## 実際の使用例では、アルゴリズムのためのより広い探索空間を使用する必要があります。
classifiers = [
(
make_pipeline(StandardScaler(), LogisticRegression(random_state=0)),
{"logisticregression__C": np.logspace(-1, 1, 3)},
),
(
make_pipeline(StandardScaler(), LinearSVC(random_state=0, dual="auto")),
{"linearsvc__C": np.logspace(-1, 1, 3)},
),
(
make_pipeline(
StandardScaler(),
KBinsDiscretizer(encode="onehot"),
LogisticRegression(random_state=0),
),
{
"kbinsdiscretizer__n_bins": np.arange(5, 8),
"logisticregression__C": np.logspace(-1, 1, 3),
},
),
(
make_pipeline(
StandardScaler(),
KBinsDiscretizer(encode="onehot"),
LinearSVC(random_state=0, dual="auto"),
),
{
"kbinsdiscretizer__n_bins": np.arange(5, 8),
"linearsvc__C": np.logspace(-1, 1, 3),
},
),
(
make_pipeline(
StandardScaler(), GradientBoostingClassifier(n_estimators=5, random_state=0)
),
{"gradientboostingclassifier__learning_rate": np.logspace(-2, 0, 5)},
),
(
make_pipeline(StandardScaler(), SVC(random_state=0)),
{"svc__C": np.logspace(-1, 1, 3)},
),
]
names = [get_name(e).replace("StandardScaler + ", "") for e, _ in classifiers]
データの可視化
このステップでは、特徴量の離散化の前の合成分類データセットを可視化します。各データセットの学習用とテスト用のポイントをプロットします。
fig, axes = plt.subplots(
nrows=len(datasets), ncols=len(classifiers) + 1, figsize=(21, 9)
)
cm_piyg = plt.cm.PiYG
cm_bright = ListedColormap(["#b30065", "#178000"])
## データセットを反復処理
for ds_cnt, (X, y) in enumerate(datasets):
print(f"\ndataset {ds_cnt}\n---------")
## 学習用とテスト用に分割
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.5, random_state=42
)
## 背景色用のグリッドを作成
x_min, x_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5
y_min, y_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
## まずデータセットをプロット
ax = axes[ds_cnt, 0]
if ds_cnt == 0:
ax.set_title("Input data")
## 学習用のポイントをプロット
ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright, edgecolors="k")
## そしてテスト用のポイントをプロット
ax.scatter(
X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_bright, alpha=0.6, edgecolors="k"
)
ax.set_xlim(xx.min(), xx.max())
ax.set_ylim(yy.min(), yy.max())
ax.set_xticks(())
ax.set_yticks(())
特徴量の離散化を実装する
このステップでは、scikit - learn の KBinsDiscretizer クラスを使って、データセットに対して特徴量の離散化を実装します。これは、ビンのセットを作成することで特徴量を離散化し、次に離散値を one - hot エンコードします。その後、データを線形分類器に適合させ、性能を評価します。
## 分類器を反復処理
for est_idx, (name, (estimator, param_grid)) in enumerate(zip(names, classifiers)):
ax = axes[ds_cnt, est_idx + 1]
clf = GridSearchCV(estimator=estimator, param_grid=param_grid)
with ignore_warnings(category=ConvergenceWarning):
clf.fit(X_train, y_train)
score = clf.score(X_test, y_test)
print(f"{name}: {score:.2f}")
## 決定境界をプロットします。そのために、メッシュ [x_min, x_max]*[y_min, y_max] 内の各点に色を割り当てます。
if hasattr(clf, "decision_function"):
Z = clf.decision_function(np.column_stack([xx.ravel(), yy.ravel()]))
else:
Z = clf.predict_proba(np.column_stack([xx.ravel(), yy.ravel()]))[:, 1]
## 結果をカラープロットに入れます
Z = Z.reshape(xx.shape)
ax.contourf(xx, yy, Z, cmap=cm_piyg, alpha=0.8)
## 学習用のポイントをプロット
ax.scatter(
X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright, edgecolors="k"
)
## そしてテスト用のポイントをプロット
ax.scatter(
X_test[:, 0],
X_test[:, 1],
c=y_test,
cmap=cm_bright,
edgecolors="k",
alpha=0.6,
)
ax.set_xlim(xx.min(), xx.max())
ax.set_ylim(yy.min(), yy.max())
ax.set_xticks(())
ax.set_yticks(())
if ds_cnt == 0:
ax.set_title(name.replace(" + ", "\n"))
ax.text(
0.95,
0.06,
(f"{score:.2f}").lstrip("0"),
size=15,
bbox=dict(boxstyle="round", alpha=0.8, facecolor="white"),
transform=ax.transAxes,
horizontalalignment="right",
)
結果を可視化する
このステップでは、特徴量の離散化プロセスの結果を可視化します。各分類器とデータセットに対するテストセット上の分類精度をプロットします。
plt.tight_layout()
## グラフの上にサブタイトルを追加
plt.subplots_adjust(top=0.90)
suptitles = [
"線形分類器",
"特徴量の離散化と線形分類器",
"非線形分類器",
]
for i, suptitle in zip([1, 3, 5], suptitles):
ax = axes[0, i]
ax.text(
1.05,
1.25,
suptitle,
transform=ax.transAxes,
horizontalalignment="center",
size="x-large",
)
plt.show()
まとめ
この実験では、scikit - learn を使って合成分類データセットに対する特徴量の離散化を示しました。データの準備、分類器とパラメータの定義、特徴量の離散化の実装、および結果の可視化を行いました。この前処理技術は、データセットの複雑さを軽減し、線形分類器の性能を向上させるのに役立つ場合があります。ただし、過学習を回避するためには、他の技術と併用して注意深く使用する必要があります。