本ページでは入門-1~3のまとめです。
本ページでは以下のページを要約するとともに、個人的な解説も記載しています。独特な解釈をしている部分があるので、誤りなどの指摘はtwitterまでお願いします。
参考ページ
はじめに — scikit-learn 1.1.2 ドキュメント
https://scikit-learn.org/stable/getting_started.html
閲覧日:2022年10月5日
はじめに
このガイドはscikit-learnで提供される主な機能を紹介しています。
機械学習の前提知識をある程度持っていることを前提としています。※のように記載がありますが、なるべく誰でもわかるようにコメントを挟みます。
scikit-learnのインストール方法については、こちらに掲載されています。本ページでも、今後掲載する予定です。
Scikit-learnは教師あり学習と教師なし学習をサポートするオープンソースの機械学習ライブラリです。また、前処理、モデルの選択、モデルの評価、その他の多くのツールを提供します。
Fitting と predicting: estimator の基本
※プログラム中にこちらの単語がよく使われるので、あえて英単語を残しました。fitting、predicting,estimatorについて簡単に解説します。
「fitting,fit」 :学習データと教師データを組み合わせ、任意のアルゴリズムにて学習させることを指します。教師なし学習の場合は教師データは必要ありません。
「predicting,predict」:学習させたAIモデルに、未知のデータを読み込ませ結果を予測させることを指します。
「estimator」:学習するときのアルゴリズムのこと。AIモデルには決定木や回帰モデルなど様々なアルゴリズムがあるが、どれを使うかで精度なども変わってきます。
推定や推論、推定器などの日本語訳はありますが、漢字が似ているせいで使い分けが難しいです。英語の方が区別がつきやすいですし、直接コードの中で使われますので覚えるならこちらで覚えたほうをおすすめします。
実際にRandomForestClassifier
というアルゴリズムを使用して、未知の値を予測するAIを作ってみます。
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(random_state=0)
X = [[ 1, 2, 3], # 3つの特徴量を持つ2つのデータ(学習データ)
[11, 12, 13]]
y = [0, 1] # それぞれの分類 (教師データ)
clf.fit(X, y) #学習データと教師データを使用してモデルに学習させる。
fit
メソッドは通常2つの引数を使用します。
学習データ:特徴量が列で表現され、2つめ3つめのデータは行として表現されています。今回のXの行列だと[1,2,3]と[11,12,13]という特徴量を持ったデータを学習データとして使用していることになります。
教師データ:教師データは回帰の場合は実数で、分類の場合は分類用の数値で表されます。今回使用したRandomForestClassifier
は分類を行うためのアルゴリズムなので、教師データであるy
は[0]か[1]のグループに分類しています。通常は学習データの行に対応する教師データが1次元配列で格納されます。
学習データX,教師データyはnumpy形式の配列や配列であることが多いですが、一部のestimatorでは要素がほとんどゼロの行列である「疎行列」が使われることがあります。(※疎行列が具体的に何を指すのかは、今後の記事で明らかになる予定です。)
学習が終わると未知の値の分類を予測することができます。再度学習、「fit」させる必要はありません。
以下のコードで予測をすることができます。
clf.predict(X) # predict classes of the training data
#array([0, 1]) と表示
clf.predict([[4, 5, 6], [14, 15, 16],[2,3,5]]) # predict classes of new data
#array([0, 1, 0]) と表示)
基本的にはこのような流れでどのestimatorも未知の値を予測するAIモデルを作成し予測を行うことができます。今回は配列を直接指定しましたが、CSV形式などでインポートすることにより大量のデータを使って学習したり、予測したりすることが可能になります。
トランスフォーマーとプリプロセッサー
※うまい訳し方が思いつかなかったので、そのまま記載していますがこちらでは前処理について解説を行います。
AIに予測をさせるということは様々な要素を組み合わせて行います。多くは、データの変換、前処理を行い、estimatorに予測をさせるという流れになっています。
scikit-learnでできる前処理の方法も、前回扱ったestimatorと同様に使用できます。(実際にこれらは全てBaseEstimator
というクラスを継承しています。)
前処理を行なうオブジェクトには、前回暑かったような予測結果を求めるpredict
メソッドはありませんが、代わりに変換結果を出力するtransform
メソッドがあります。
※サンプルのコードでは、前処理として特徴量同士のスケールを標準化によってそろえます。
from sklearn.preprocessing import StandardScaler
X = [[0, 15],
[1, -10]]
# .fit(X)でXの標準偏差などを計算します。.transform(x)でデータを標準化しています。
StandardScaler().fit(X).transform(X)
#array([[-1., 1.],
# [ 1., -1.]])
X2 =[[0.5,5]]
StandardScaler().fit(X).transform(X2) #未知のデータをXの標準偏差などを使用して、標準化を行います。
#array([[0. , 0.2]])
ColumnTransformerを使用すると他にも様々な変換方法を行うことができます。また、本ブログでも解説を行う予定です。
パイプライン: プリプロセッサとestimatorの結合
パイプラインとは未知のデータを予測するときの流れについてです。未知のデータを予測するには、データの前処理部分(プリプロセッサ)とestimatorに予測させる部分に分かれます。その2つを合わせた一連の流れをパイプラインと表現しています。
前処理とestimator部分をパイプラインとして一纏めにすることで、データリーケージを防げるということです。
※データリーケージは、AIモデルの性能を確認する際に学習データに、性能を確認するためのテストデータが含まれてしまっているがために本来の性能よりも良い結果が出てしまうことを指します。パイプラインを使うことで処理を簡潔にすることで、そのようなミスを減らせます。
他のメリットとしては、AIを使い続けていくときのプログラムを完結に記載できるということがあります。
次の例では、sickit-learnに標準で含まれるアヤメ(lris)のデータセットを使用し、ロジスティック回帰を使用した品種の分類するモデルをパイプラインで作成し、スコアまで求めます。
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() #ロジスティック回帰のオブジェクト
)
# アヤメのデータセットを呼び出します。
X, y = load_iris(return_X_y=True)
# 学習データとテストデータに分割します。
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# パイプラインオブジェクトに学習させます。
# 標準化→モデルに学習させる という流れが1行でできます。
pipe.fit(X_train, y_train)
#Pipeline(steps=[('standardscaler', StandardScaler()),
# ('logisticregression', LogisticRegression())])
# テストデータを使って予測精度を確認します。
#pipe.predict(X_test)でテストデータの予測を求めています。
#テストデータの予測結果とy_test(答え)を比較し、スコアを求めています。
accuracy_score(pipe.predict(X_test), y_test)
#0.97...
このように、データの前処理から学習、スコアの算出までを1つのオブジェクトでできるので、完結に記載できデータリーケージも抑えることができます。
パイプラインのメリットで検索しても、日本語のサイトには簡潔に記載できる、ということしか書いていないことがほとんどです。パイプライン化することでデータリーケージを防ぐことができるということも念頭におき使ってみると良いでしょう。
モデル評価
AIモデルを作成した際に、未知のデータを正確に予測できるとは限りません。しかし、実際にAIモデルを作成した際はどのくらい信用できるのかを評価を行わなかればなりません。
前回のコードにはtrain_test_split
という仕組みを使って、学習データと訓練データに分割する手法が出てきましたが、scikit-learnには他にも様々なツールを提供します。
ここでは、cross_validate
を使用して、交差検証(クロスバリデーション)を実際を試してみましょう。
詳細は別のブログ記事で記載予定です。(公式はこちらユーザー ガイド)
from sklearn.datasets import make_regression
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_validate
#回帰用のランダムな乱数を生成。1000個のデータを直線上に分布するように生成しています。
X, y = make_regression(n_samples=1000, random_state=0)
lr = LinearRegression()
result = cross_validate(lr, X, y) # デフォルトでは5つのデータに分割を行います。
result['test_score'] # 今回は5つに分割したので、それぞれのパターンでスコアを出力します。
#array([1., 1., 1., 1., 1.]) #出力したランダム値は完全に直線上に並ぶ値なので全て1になっています。
ハイパーパラメータ探索
全てのestimatorには調整可能なパラメータ(多くはハイパーパラメータと表記されています。)があります。AIモデルの汎化能力(未知のデータに対する性能)は、ハイパーパラメータの値に大きく左右されます。例えば、ランダムフォレストでは決定木の数を決めるパラメータや深さを決めるパラメータがあります。これらのパラメータは学習データによって最適な値が変わるため、何を指定したら良いか明確ではありません。
scikit-learnではパラメータの組み合わせを自動的に見つける仕組みを提供しています。今回は、ランダムフォレストのパラメータの組み合わせをRandomizedSearchCV
という仕組みを使用して検索する例を紹介します。
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)}
# ハイパーパラメータ探索用のオブジェクトを設定します。
search = RandomizedSearchCV(estimator=RandomForestRegressor(random_state=0),
n_iter=5,
param_distributions=param_distributions,
random_state=0)
search.fit(X_train, y_train)
RandomizedSearchCV(estimator=RandomForestRegressor(random_state=0), n_iter=5,
param_distributions={'max_depth': ...,
'n_estimators': ...},
random_state=0)
#一番性能の良かったパラメータを表示します。
search.best_params_
#{'max_depth': 9, 'n_estimators': 4}
# 検索に使用したオブジェクトは通常のランダムフォレストの学習済モデルと同様に使用できます。
# with max_depth=9 and n_estimators=4
search.score(X_test, y_test)
#0.73...
ノート:このような使用方法をするとデータリーケージが起こることがあります。データリーケージを防ぐために、多くの場合パイプラインを使用することが多いです。なぜデータリーケージが起こるかを知りたい場合はこちら(今後記事にする予定です。)
次のステップ
機械学習についての前処理、パイプライン、検証、ハイパーパラメータ探索などについて説明しました。これら以外の機能をscikit-learnは備えています。
今後解説記事にしていく予定です。