今更ながら「scikit-learn」に入門してみる
ガッツリ理解するというよりは雰囲気というか概念を掴むためにやる。
GitHubレポジトリ
scikit-learn
scikit-learnはSciPyの上に構築された機械学習のためのPythonモジュールで、3-Clause BSDライセンスの下で配布されています。
このプロジェクトは2007年にGoogle Summer of CodeのプロジェクトとしてDavid Cournapeauによって開始されました。中心的な貢献者のリストは About us のページをご覧ください。
現在はボランティアチームによってメンテナンスされています。
ウェブサイト:https://scikit-learn.org
公式サイト
インストール
Colaboratoryで。
パッケージインストール
!pip install -U scikit-learn
!pip freeze | grep -i scikit-learn
scikit-learn==1.5.2
Getting Started
このガイドの目的は、scikit-learn が提供する主な機能のいくつかを説明することです。このガイドは、機械学習の実践(モデルフィッティング、予測、交差検証など)についてのごく基本的な実務知識を前提としています。scikit-learn のインストールについては、インストール手順を参照してください。
scikit-learnは、教師あり学習と教師なし学習をサポートするオープンソースの機械学習ライブラリです。また、モデルフィッティング、データ前処理、モデル選択、モデル評価、その他多くのユーティリティのための様々なツールを提供しています。
前提知識が足りないので、ChatGPTに聞いてみた。
機械学習の基本概念について簡単に説明します。scikit-learnを使用する上で知っておくと役立つものです。
1. 機械学習とは?
機械学習は、データからパターンを学習して、新しいデータに対して予測や判断を行うことです。大きく分けて2つの種類があります。
- 教師あり学習 (Supervised Learning)
- 正解ラベルがあるデータを使って学習し、未知のデータに対して予測を行います。
- 例:画像に「犬」や「猫」などのラベルが付いているデータセットから、画像に何が写っているかを予測する。
- 教師なし学習 (Unsupervised Learning)
- 正解ラベルがないデータからパターンを見つけることを目的としています。
- 例:似たデータをグループ化する(クラスタリング)。
2. モデルのフィッティング(Model Fitting)
データを使ってモデルを「フィット(学習)」させることです。フィッティングとは、モデルにデータを渡してそのパターンを学習させるプロセスを指します。たとえば、線形回帰モデルでは、データのパターンを基に最適な直線を見つけることが「フィッティング」です。
3. 予測(Prediction)
学習したモデルを使って、新しいデータに対して予測を行います。フィッティングされたモデルに入力データを渡すと、そのモデルが学習したルールに基づいて出力(予測)を返します。
4. 交差検証(Cross-Validation)
データを「トレーニングデータ」と「テストデータ」に分けて評価するだけでは、モデルが過学習(特定のデータにのみ強く適合すること)しているかどうかを正確に判断できません。交差検証は、データセットをいくつかの部分に分けて複数回の学習・評価を行い、モデルの性能をより正確に評価する方法です。
5. 過学習(Overfitting)
モデルがトレーニングデータに過度に適応してしまい、新しいデータに対してうまく予測できない現象です。これを避けるために、テストデータや交差検証を使用してモデルの性能を確認します。
6. モデル評価(Model Evaluation)
モデルの予測性能を測定する方法です。例えば、分類問題では「正解率(accuracy)」が、回帰問題では「平均二乗誤差(mean squared error)」などが用いられます。
7. 前処理(Preprocessing)
データをモデルに入力する前に、適切な形式に整えるステップです。例として、データのスケーリング(数値の範囲を正規化すること)や欠損値の補完などがあります。
これらの概念を抑えることで、scikit-learnの基本的な操作が理解しやすくなります。学習を進める際は、サンプルデータを使って実際に試してみると、さらに理解が深まるでしょう。
ざっくり雰囲気だけ掴んだところで、あとは進めながら学ぶこととする。
フィッティングと予測:estimatorの基本
estimator
(予測器)は、scikit-learnに組み込まれている機械学習アルゴリズムやモデルを指す。fit
メソッドを使ってデータにモデルを適合(学習)させる。
RandomForestClassifier
にデータを適合させるシンプルな例。
ランダムフォレストとは?ChatGPTによる説明
ランダムフォレスト(Random Forest) は、決定木(Decision Tree) を多数使った アンサンブル学習(Ensemble Learning) の手法です。決定木は、データを基に「Yes/No」で判断を繰り返していき、最終的なクラス(分類)や数値(回帰)を予測するアルゴリズムですが、1本の決定木だと、特定のデータに強く依存してしまうことがあります(これを 過学習 といいます)。
ランダムフォレストでは、たくさんの決定木を作り、それぞれに異なる部分データを使って学習させることで、1つの決定木よりも安定した予測を行います。
ランダムフォレストの専門用語とその意味
-
決定木(Decision Tree):
- データをツリー構造で分類するアルゴリズム。各ノードは特徴量を基にデータを「Yes/No」で分岐し、最終的に葉ノードに予測クラスや数値が割り当てられる。
-
アンサンブル学習(Ensemble Learning):
- 複数のモデルを組み合わせて、個々のモデルよりも優れた予測結果を得る手法。ランダムフォレストはその一例。
-
バギング(Bootstrap Aggregating, Bagging):
- データの一部をランダムに選び(リサンプリング)、各モデルに異なるデータを使って学習させる手法。ランダムフォレストでは、このバギングを使って複数の決定木を作成する。
-
特徴量のランダム選択:
- 各決定木が分岐(ノード)を作成するとき、全ての特徴量(変数)から最適なものを選ばず、ランダムに一部の特徴量だけを選んで最適な分岐を決める。これにより、決定木の多様性を高め、過学習を防ぐ。
-
過学習(Overfitting):
- モデルがトレーニングデータに過度に適応しすぎて、新しいデータに対する予測精度が低下する状態。ランダムフォレストは過学習を防ぎやすい。
-
n_estimators:
- ランダムフォレストで作成する決定木の数。一般的に、多くの決定木を使うほど精度が向上するが、計算コストも増加する。
-
max_depth:
- 各決定木の最大深さ(ツリーの高さ)。深すぎると過学習の原因になるが、浅すぎるとモデルが十分に学習できない。
ランダムフォレストの仕組み
- データの分割:
- 学習用データ(トレーニングデータ)を使って、ランダムにサブセット(部分データ)を複数回作成し、各決定木に異なるデータを渡します。
- 複数の決定木を学習:
- それぞれの決定木は、ランダムに選ばれたデータと特徴量を使って学習を行います。
- 予測の集約:
- 新しいデータが与えられたとき、各決定木が予測を行います。ランダムフォレストは、その予測を集計して、分類問題の場合は多数決、回帰問題の場合は平均を取って最終予測を決定します。
まとめ
- ランダムフォレストは、アンサンブル学習の一種で、たくさんの決定木を組み合わせて使います。
- ランダムにデータと特徴量を選んで木を作成し、過学習を防ぎつつ精度を高めます。
- 最終的な予測は、複数の決定木の予測結果を多数決(分類)や平均(回帰)で決定します。
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(random_state=0)
X = [
[ 1, 2, 3], # サンプル2, 特徴量3
[11, 12, 13]
]
y = [0, 1] # 各サンプルのクラス
clf.fit(X, y) # フィッティング
fitメソッドは通常2つの入力を受ける。
-
X
: サンプル行列(またはデザイン行列)- サイズは
(n_samples, n_features)
- サンプルは行、特徴量は列として表される。
- サイズは
-
y
: ターゲット値- 回帰タスクの場合は実数、分類タスクの場合は整数(またはその他の離散的な値の集合)。
- 教師なし学習タスクの場合は、yを指定する必要なし。
- yは通常1次元配列。i番目のエントリはXのi番目のサンプル(行)のターゲットに対応。
X
、y
ともに、通常はnumpy配列または配列ライクなデータ型が期待されるが、一部のestimator
はスパース行列などにも対応している。
上記を実行すると以下のように表示され、フィッティングされたということなのだと思われる。
estimator
がフィッティングされると、predict
メソッドを使用して新しいデータのターゲットを予測できる。
トレーニングデータ(X
)のクラスを予測
clf.predict(X)
array([0, 1])
新しいデータのクラスを予測
clf.predict([[4, 5, 6], [14, 15, 16]])
array([0, 1])
変換器と前処理器
機械学習のワークフローでは異なるパーツで構成されるのが一般的で、典型的なパイプラインは、
- データを変換または補完する前処理ステップ
- ターゲット値を予測する最終的な予測器(
estimators
)
で構成される。
scikit-learnでは、前処理器(pre-processors)と変換器(transformers)は、estimator
オブジェクトと同じBaseEstimator
クラスから継承されているので、同じAPIに従う。ただし、変換器オブジェクトはpredict
メソッドを持たず、その代わりにtransform
メソッドを持つ。transform
メソッドを使うと、新しく変換されたサンプル行列Xを出力する。
from sklearn.preprocessing import StandardScaler
X = [
[0, 15],
[1, -10]
]
# データをスケール(標準化)するための変換器を作成
scaler = StandardScaler()
# fitでデータのスケーリング情報を学習し、transformで変換
scaler.fit(X).transform(X)
array([[-1., 1.],
[ 1., -1.]])
場合によっては、データの中の各列(特徴量)に対して異なる変換を行いたい場合がある。例えば、ある列はスケーリングしたいが、別の列には別の変換を適用したいという場合。そういった場合にはColumnTransformer
を使う。
パイプライン:前処理器と予測器のチェーン
変換器(transformers)と予測器(estimator)を一つのオブジェクトに結びつけるのがパイプライン(Pipeline
)になる。
パイプラインも他のestimatorと同じAPIを持つので、fit
やpredict
を使ってフィッティングや予測ができる。また、パイプラインを使うことで、トレーニングと推論の一貫した処理ができるため、データリーク(テストデータが訓練に混ざってしまう)のを防ぐことができる。
以下は、Irisデータセットをロード、トレーニング用・テスト用に分割、そしてテストデータの正解率を計算するパイプラインの例。
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# パイプラインオブジェクトの作成
pipe = make_pipeline(
StandardScaler(), # 前処理:標準化
LogisticRegression() # モデル:ロジスティック回帰
)
# Irisデータセットを読み込み、訓練データとテストデータに分割
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# パイプライン全体を訓練
pipe.fit(X_train, y_train)
# パイプラインを使ってテストデータで予測し、正解率を計算
accuracy = accuracy_score(pipe.predict(X_test), y_test)
print(accuracy)
0.9736842105263158
モデルの評価
モデルをデータにフィットさせただけで、未知のデータに対して良い予測ができるわけではなく、これを直接評価する必要がある。上で書いたtrain_test_split
によるデータセットの分割(トレーニング用・テスト用)だけでなく、他にも多くのモデル評価ツール、特に交差検証(cross-validation)に役立つものがある。
以下は、cross_validate
を使用して、5分割の交差検証を行う例。他にも、手動で分割を繰り返す、異なるデータ分割戦略を使用する、カスタムの評価関数を使うということも可能。
from sklearn.datasets import make_regression
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_validate
# データセットの作成
X, y = make_regression(n_samples=1000, random_state=0)
# 線形回帰モデルの作成
lr = LinearRegression()
# 5分割の交差検証を実行
result = cross_validate(lr, X, y) # デフォルトでは5分割の交差検証
result['test_score'] # データセットが簡単なためr_squaredスコアは高い
array([1., 1., 1., 1., 1.])
自動パラメータ探索
すべての予測器(estimator)には、チューニング可能なパラメータ(「ハイパーパラメータ」と呼ばれることが多い)がある。予測器の汎化性能は、いくつかのパラメータに大きく依存することがよくある。
例えば、RandomForestRegressor
には以下のようなパラメータがある。
-
n_estimators
: ランダムフォレストの木の数を決定する -
max_depth
: 各木の最大深さを決定する
これらのパラメータの最適値はデータによって異なるため、scikit-learnは、これらのパラメータの最適な組み合わせを(交差検証を通じて)自動的に見つけるツールを提供している。
以下の例は、RandomizedSearchCV
オブジェクトを使って、ランダムフォレストのパラメータ空間をランダムに探索し、探索後は最適なパラメータでフィットされたRandomForestRegressor
として振る舞う。
from sklearn.datasets import fetch_california_housing
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import RandomizedSearchCV
from sklearn.model_selection import train_test_split
from scipy.stats import randint
# データセットのロード
X, y = fetch_california_housing(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# 探索するパラメータ空間を定義
param_distributions = {'n_estimators': randint(1, 5),
'max_depth': randint(5, 10)}
# searchCVオブジェクトを作成し、データにフィット
search = RandomizedSearchCV(estimator=RandomForestRegressor(random_state=0),
n_iter=5,
param_distributions=param_distributions,
random_state=0)
search.fit(X_train, y_train)
探索によって得られた最適なパラメータ
search.best_params_
{'max_depth': 9, 'n_estimators': 4}
探索後、search
オブジェクトは'max_depth=9、
n_estimators=4`のランダムフォレスト測定機として機能する。
# 最適なパラメータでフィットされたランダムフォレストモデルのスコアを取得
search.score(X_test, y_test)
0.735363411343253
ユーザガイドには多くのサンプルがある。
このあたりはチマチマやっていくこととしたい。