【Python】「scikit-learn」簡単速習‼【識別編/総まとめ】

こんにちはヤク学長です。
データサイエンティスト兼ファーマシストで、アルゴリズムやBI開発を行っています。

本記事の目的は、「pythonの基本操作を知る」ことを目的としています。

【ステップアップ】「Pythonの実践」簡単速習‼【データ解析/応用⑩】

【本記事のもくじ】

まず、「Python」に真剣に取り組むための概要を解説します。
下記の方法で、簡単に概要を抑えることができます。

  • 1.scikit-learn概論
  • 2.データと特徴量
  • 3.テストデータの評価方法
  • 4.いろいろな識別器
  • 5.パラメータの調整
  • 6.学習サンプル数が多いとき

それでは、上から順番に見ていきます。
なお、本上記の方法を順番に抑えれば成果が出ます。

記事の内容は「転載 & 引用OK」問題ありません。

目次

1.scikit-learn概論

scikit-learnとは

scikit-learnは、Pythonプログラミング言語向けの人気の高いオープンソースの機械学習ライブラリです。分類、回帰、クラスタリング、次元削減などのタスクに対して、監視学習と非監視学習のアルゴリズムの範囲を提供しています。

識別とは

識別(しきべつ、英語: classification)とは、機械学習の分野において、与えられたデータに対してあらかじめ定義されたカテゴリー(クラス)のうちどれに属するかを決定するタスクのことです。

たとえば、手書き数字の画像が与えられた場合、それが何の数字であるかを判別するのが識別の例です。

このように、入力されたデータをあらかじめ定められたカテゴリーに分類することで、データをより理解しやすくすることができます。識別は、監視学習(教師あり学習)の一種であり、学習データから分類器(識別器)を構築し、新しいデータに対してカテゴリーを予測することが行われます。

識別の流れ

識別の一般的な流れは以下のようになります。

  • データの準備:識別に必要なデータを収集し、前処理を行います。前処理には、欠損値の処理、特徴量の抽出、スケーリング、データの分割などが含まれます。
  • 特徴量の選択:識別に必要な特徴量を選択します。特徴量の選択は、識別器の精度に大きな影響を与えるため、慎重に行う必要があります。
  • 学習:選択された特徴量を使用して、識別器を学習させます。学習には、監視学習のアルゴリズム(例えば、決定木、ロジスティック回帰、サポートベクターマシンなど)を使用します。
  • モデルの評価:学習済みの識別器をテストデータに適用し、精度を評価します。この際に、適切な評価指標を選択することが重要です。
  • モデルの改善:評価結果をもとに、モデルを改善します。改善の方法には、特徴量の変更、アルゴリズムの変更、ハイパーパラメータの調整などがあります。
  • モデルの利用:最終的に、学習済みの識別器を実際のデータに適用し、識別のタスクを実行します。

このように、識別の流れは、データの準備、特徴量の選択、学習、評価、改善、利用というステップで構成されます。

ラベルについて

機械学習において、ラベル(label)とは、データに対して付与された正解の値やカテゴリーを指します。

つまり、ラベルは、与えられたデータがどのクラスに属するかを表すものです。例えば、手書き数字の画像を識別するタスクにおいて、0から9の数字がラベルになります。

ラベルは、監視学習(教師あり学習)において非常に重要な役割を果たします。学習データには、入力データとそれに対応するラベルが必要であり、識別器はこの学習データから学習することで、未知のデータに対する予測を行います。ラベル付きデータが多数存在すれば、より正確な予測が可能となります。

回帰とは

回帰(regression)とは、機械学習の分野において、与えられたデータに対して連続的な値を予測するタスクのことを指します。回帰は、入力変数と出力変数の間の関係をモデル化し、未知の入力変数が与えられた場合に対応する出力変数を予測することが目的です。入力変数は、通常、連続的な値を持つもので、出力変数も連続的な値を持ちます。

回帰の例としては、住宅価格の予測があります。この場合、入力変数は、住宅の広さ、部屋数、立地条件などであり、出力変数は住宅価格です。学習データには、入力変数と対応する出力変数(住宅価格)が含まれています。回帰モデルは、この学習データから入力変数と出力変数の関係を学習し、未知の住宅の情報が与えられた場合に、その住宅の価格を予測します。

回帰には、線形回帰、非線形回帰、ロジスティック回帰など、さまざまな種類があります。線形回帰は、入力変数と出力変数の間に線形の関係がある場合に適用され、非線形回帰は、入力変数と出力変数の間に非線形の関係がある場合に適用されます。ロジスティック回帰は、分類問題に応用され、出力変数が2つの値しか取らない場合に使用されます。

教師あり、教師なし、半教師あり学習

機械学習には、主に以下の3つの種類の学習方法があります。

  • 教師あり学習(supervised learning):入力データに対して、正解データが与えられた状態で学習を行う方法です。つまり、入力データと対応するラベル(正解データ)があらかじめ与えられている状態で、学習を行います。教師あり学習には、分類(classification)や回帰(regression)などがあります。分類は、与えられた入力データに対して、事前定義されたカテゴリー(ラベル)のいずれかに分類する問題を解決します。回帰は、入力データと数値的な目的変数(正解データ)の関係をモデル化する問題を解決します。
  • 教師なし学習(unsupervised learning):入力データにラベルが与えられず、データ間の相関やパターンを自動的に抽出する方法です。教師なし学習には、クラスタリング(clustering)や次元削減(dimensionality reduction)などがあります。クラスタリングは、入力データをいくつかのグループに分類する問題を解決します。次元削減は、入力データをより低次元の空間に変換する問題を解決します。
  • 半教師あり学習(semi-supervised learning):教師あり学習と教師なし学習を組み合わせた方法で、ラベル付きデータとラベルなしデータを同時に使用して学習を行います。ラベルなしデータに対しては、教師なし学習アルゴリズムを適用し、ラベル付きデータに対しては、教師あり学習アルゴリズムを適用します。半教師あり学習は、ラベル付きデータが限られている場合やラベル付けにコストがかかる場合に有用です。

ディープラーニングとは

ディープラーニング(Deep Learning)は、機械学習の一分野であり、多層のニューラルネットワークを使って、高度な特徴抽出やデータ処理を行う手法です。ニューラルネットワークは、人間の脳神経回路を模したアルゴリズムで、入力層、中間層、出力層から構成されています。中間層は、複数の隠れ層を持ち、それぞれが抽象的な特徴を捉えることができます。

ディープラーニングは、大量のデータを用いた学習に適しており、画像認識、音声認識、自然言語処理など、様々な分野で高い精度を発揮しています。また、ディープラーニングは、ニューラルネットワークの構造を柔軟に変更することができるため、様々なアプリケーションに対応することができます。

ディープラーニングの主な特徴は、以下のようになります。

  • 複数の隠れ層を持つニューラルネットワークを用いることで、より複雑な特徴を学習することができる。
  • 大量のデータを用いた学習により、高い汎化性能を発揮することができる。
  • 特徴抽出や分類など、多様なタスクに適用することができる。
  • 人間が手作業で特徴量を抽出する必要がなく、自動的に特徴量を学習することができる。

scikit-learnを使った2次元のデータで識別するイメージ

scikit-learnを使って2次元のデータで識別する例として、アヤメのデータを使った品種の識別を例に説明します。

まず、scikit-learnからアヤメのデータを読み込みます。

from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data[:, :2] # 最初の2つの特徴量を使用
y = iris.target

次に、データを訓練データとテストデータに分割します。

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

識別器として、サポートベクターマシン(SVM)を使用します。

from sklearn.svm import SVC
clf = SVC(kernel='linear', C=1, random_state=0)

訓練データを使って、SVMを学習します。

clf.fit(X_train, y_train)

学習したSVMを使って、テストデータの品種を識別します。

y_pred = clf.predict(X_test)

識別結果を評価します。

from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_test, y_pred)
print('Accuracy:', accuracy)

以上のコードをまとめると、以下のようになります。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
iris = load_iris()
X = iris.data[:, :2]
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
clf = SVC(kernel='linear', C=1, random_state=0)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print('Accuracy:', accuracy)

このコードを実行すると、テストデータに対する識別精度が表示されます。

癌のデータで学習とテストを半分に分けたイメージ

癌のデータを使った学習とテストの例として、乳がんデータを使います。ここでは、半教師あり学習の例として、ラベル付きデータの一部のみを使って学習を行い、残りのラベルなしデータを使ってテストを行う方法を説明します。

まず、scikit-learnから乳がんデータを読み込みます。

from sklearn.datasets import load_breast_cancer
data = load_breast_cancer()
X = data.data
y = data.target

次に、データを訓練データとテストデータに分割します。ここでは、訓練データとテストデータの割合を1:1にします。

from sklearn.model_selection import train_test_split
X_labeled, X_unlabeled, y_labeled, y_unlabeled = train_test_split(X, y, test_size=0.5, stratify=y, random_state=0)

ラベル付きデータの一部を使って、サポートベクターマシン(SVM)を学習します。

from sklearn.svm import SVC
clf = SVC(kernel='linear', C=1, random_state=0)
clf.fit(X_labeled, y_labeled)

学習済みのSVMを使って、ラベルなしデータを識別します。

y_pred_unlabeled = clf.predict(X_unlabeled)

識別されたラベルを使って、ラベルなしデータの一部を追加して、SVMを再学習します。

import numpy as np
X_labeled_new = np.vstack((X_labeled, X_unlabeled[:10]))
y_labeled_new = np.hstack((y_labeled, y_pred_unlabeled[:10]))

clf.fit(X_labeled_new, y_labeled_new)

再学習したSVMを使って、テストデータを識別します。

y_pred = clf.predict(X_unlabeled[10:])

識別結果を評価します。

from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_unlabeled[10:], y_pred)
print('Accuracy:', accuracy)

以上のコードをまとめると、以下のようになります。

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
import numpy as np
data = load_breast_cancer()
X = data.data
y = data.target
X_labeled, X_unlabeled, y_labeled, y_unlabeled = train_test_split(X, y, test_size=0.5, stratify=y, random_state=0)
clf = SVC(kernel='linear', C=1, random_state=0)
clf.fit(X_labeled, y_labeled)
y_pred_unlabeled = clf.predict(X_unlabeled)
X_labeled_new = np.vstack((X_labeled, X_unlabeled[:10]))
y_labeled_new = np.hstack((y_labeled, y_pred_unlabeled[:10]))
clf.fit(X_labeled_new, y_labeled_new)
y_pred = clf.predict(X_unlabeled[10:])
accuracy = accuracy_score(y_unlabeled[10:], y_pred)
print('Accuracy:', accuracy)

学習データとテストデータを半分に分けることができない場合

学習データとテストデータを半分に分けることができない場合としては、以下のようなケースが考えられます。

  • クラスの分布が偏っている場合:クラスの分布が偏っていると、学習データとテストデータのどちらかにあるクラスが過剰に含まれることになります。この場合、全体のクラス分布を保ったまま、学習データとテストデータを分割する必要があります。
  • データ数が少ない場合:データ数が少ないと、学習データとテストデータのいずれかがデータ不足に陥り、モデルの性能が低下することがあります。この場合は、交差検証などの方法を使って、データ数が少なくてもモデルの性能を評価する必要があります。
  • 時系列データの場合:時系列データの場合、データが時間的に連続しているため、時間軸に沿ってデータを分割する必要があります。この場合、過去のデータを学習データ、未来のデータをテストデータにすることが一般的です。

以上のようなケースでは、データの分割方法を工夫する必要があります。適切な分割方法を選ぶことで、モデルの性能を正確に評価することができます。

アヤメのデータで学習とテストをランダムに半分に分けるイメージ

アヤメのデータをランダムに学習データとテストデータに分割する例を以下に示します。まず、scikit-learnのload_iris関数を使ってアヤメのデータを読み込みます。

from sklearn.datasets import load_iris
iris = load_iris()
X, y = iris.data, iris.target

次に、train_test_split関数を使って、Xyをランダムに学習データとテストデータに分割します。

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=42)

test_sizeパラメータに0.5を指定しているため、データ全体の半分がテストデータに、残りの半分が学習データになります。random_stateパラメータには、ランダムシードを指定しています。この値を固定することで、分割結果を再現可能にします。

分割後は、X_trainX_testy_trainy_testを使って、学習とテストを行います。以下に、ロジスティック回帰を使って学習とテストを行う例を示します。

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
clf = LogisticRegression()
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print('Accuracy:', accuracy)

以上のように、train_test_split関数を使うことで、アヤメのデータをランダムに学習データとテストデータに分割し、学習とテストを行うことができます。

アヤメのデータで学習とテストをランダムに半分に分けることを何度も行う

アヤメのデータで学習とテストをランダムに半分に分けることを何度も繰り返すことをクロスバリデーションと呼びます。クロスバリデーションを行うには、KFoldStratifiedKFoldなどの関数を使います。

以下は、KFoldを使って10回のクロスバリデーションを行い、結果を平均して評価する例です。

from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import KFold
from sklearn.metrics import accuracy_score
iris = load_iris()
X, y = iris.data, iris.target
kf = KFold(n_splits=10, shuffle=True, random_state=42)
scores = []
for train_index, test_index in kf.split(X):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
clf = LogisticRegression()
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
scores.append(accuracy)
mean_accuracy = sum(scores) / len(scores)
print('Mean Accuracy:', mean_accuracy)

KFold関数のn_splitsパラメータに分割数を指定します。上記例では10回分割しています。shuffleパラメータにTrueを指定することで、分割前にデータをシャッフルしています。random_stateパラメータには、ランダムシードを指定しています。この値を固定することで、分割結果を再現可能にします。

KFold関数の戻り値は、学習データとテストデータのインデックスのリストです。splitメソッドを使って、インデックスを取り出して、学習データとテストデータを分割しています。その後、ロジスティック回帰を使って学習し、テストデータで予測を行い、精度を計算しています。

10回のクロスバリデーションの精度をscoresリストに保存し、最後に平均値を計算しています。

学習時間とテストデータの準備

機械学習において、モデルの汎化性能を評価するために、学習データとテストデータに分割する必要があります。学習データとテストデータの分け方には、いくつかの方法があります。

  • Hold-out法 学習データとテストデータにデータをランダムに分割する方法です。データ数が十分にある場合に有効な方法です。データ数が少ない場合には、分割によって偏りが生じる可能性があるため、交差検証法を用いることが推奨されます。
  • 交差検証法 データを複数のグループに分割し、各グループを順番にテストデータ、残りを学習データとする方法です。一般的にはk分割交差検証法(k-fold cross-validation)がよく使われます。データ数が少ない場合や、学習データとテストデータの分割によって偏りが生じる可能性がある場合に有効な方法です。
  • Leave-One-Out法 データを1つずつテストデータに、残りを学習データにする方法です。データ数が少ない場合に有効な方法ですが、計算コストが高くなるため、データ数が大きい場合には適していません。
  • Leave-One-Group-Out法(LOOG)  データセットをグループに分け、1つのグループをテストデータに、残りを学習データにする方法です。グループごとにデータがまとまっている場合、LOOGを使ってモデルを評価することで、グループ間での偏りを考慮したモデルの評価ができます。
  • 層化抽出法(stratified sampling) データセットを層(ストラタ)に分け、各層からランダムにサンプルを抽出する方法です。各層は、サンプルの特徴が似たようなものになるように分割されます。
  • ブートストラップ法 データからランダムに抽出して複数のデータセットを作成し、それぞれを学習データとテストデータにする方法です。データ数が少ない場合や、データの偏りがある場合に有効な方法です。

これらの分割方法は、目的やデータの性質によって使い分ける必要があります。また、分割方法によって精度が変化することがあるため、複数の分割方法を試して比較することが重要です。

どのぐらいデータがあればよいか

・10以下の場合:データ数が非常に少ないため、汎化性能が低くなる可能性があります。特に、モデルの複雑さが高い場合は過学習が起こりやすく、性能が低下する可能性があります。この場合、簡単なモデルを用いたり、データ拡張や人工データの生成などを行うことで、データを増やすことが重要です。

→本当に機械学習が必要か疑いましょう。

・100以下の場合:データ数が比較的少ないため、過学習に注意する必要があります。特に、特徴量の数が多い場合は、過学習が起こりやすくなります。この場合、正則化や次元削減などを用いて、モデルの複雑さを調整することが重要です。

→性能は悪いので増やす努力をしましょう。LOOCVが可能

・1000以下の場合:データ数が一定程度確保されているため、比較的安定したモデルを構築できることが多いです。ただし、特徴量の数やクラス数が多い場合は、過学習に注意する必要があります。

→まともな性能。10-fold CVで十分。計算リソースが必要

・10000以下の場合:データ数が十分に確保されているため、比較的高性能なモデルを構築できることが多いです。ただし、データの品質が悪い場合や、特徴量の数が非常に多い場合は、過学習に注意する必要があります。

→良い性能が期待できる。K-fold CV K < 10。計算リソースが必要

・10万以下の場合:一般的には十分な数のデータと言えます。ただし、データの品質や特徴量の数、クラスのバランスなどによっては、過学習に注意する必要があります。また、クラスのバランスが悪い場合は、偏った学習を行ってしまう可能性があります。この場合は、サンプル数が少ないクラスについてはオーバーサンプリングやアンダーサンプリングなどの方法を用いて、バランスを整えることが重要です。

→実応用 Hold-out以外は無理、かなり工夫が必要

以上のように、学習サンプル数が少ない場合は過学習に注意する必要があります。また、特徴量の数やクラス数が多い場合は、モデルの複雑さを調整することが重要です。

学習・テストの分割方法はどれが良い?

学習・テストの分割方法には、ランダムサンプリング、k分割交差検証、Leave-One-Out交差検証、Leave-One-Group-Out交差検証、Stratified k分割交差検証などがあります。どの方法が良いかは、データの性質や目的に応じて異なります。

ランダムサンプリングは、最もシンプルな分割方法であり、比較的小さなデータセットや初期のモデル開発に適しています。ただし、データセットに偏りがある場合や、少数派のクラスが存在する場合には、分割方法によって偏りが生じることがあります。

k分割交差検証は、データセット全体をk個のサブセットに分割し、1つをテスト用、残りを学習用とする方法です。ランダムサンプリングよりも信頼性が高く、偏りが生じにくいとされています。ただし、計算量が増加することがあるため、データサイズが大きい場合には計算コストを考慮する必要があります。

Leave-One-Out交差検証は、k分割交差検証の特殊なケースであり、kをデータセットのサンプル数と同じにする方法です。計算量が非常に大きくなるため、データサイズが小さい場合に限定的に使用されます。

Leave-One-Group-Out交差検証は、Leave-One-Out交差検証の拡張であり、特定のグループ(例えば、患者ごとのデータなど)をテスト用に、残りを学習用にする方法です。グループに依存するモデルを開発する場合に有用です。

Stratified k分割交差検証は、k分割交差検証と同様に、データセット全体をk個のサブセットに分割しますが、各サブセット内でのクラス比率を元のデータセットと同じにするように調整します。少数派のクラスが存在する場合には、偏りを軽減することができます。ただし、データサイズが小さい場合には正確な分割が難しいことがあります。

以上のように、どの方法が良いかはデータの性質や目的に応じて異なります。

まとめると

  • 規格や基準があるコンテストなど
    →データセットに付属、それに従う
  • 学習サンプル数が少ない
    →学習サンプル数が多いLOO
  • 学習サンプル数が数百~数千
    →10‐fold CV
  • 学習サンプル数が膨大
    →ディープラーニングなど
    →Hold-outしかない
  • Stratifiedは必須
    →特にクラスバランスが悪い場合には重要
  • 特殊な場合はone-group-out
    →複数の被検者や患者データ
  • 検証データ
    →研究比較検討程度なら不要
    →コンテストなら必須

Hold-out法を使った具体例を教えて

Hold-out法は、データセットを学習データとテストデータに分割する方法の1つであり、最も一般的な方法の1つです。以下は、Hold-out法を使った具体例です。

例えば、アヤメのデータセットを用いて、setosa種かそうでないかを識別する分類タスクを考えます。まず、データセットを読み込み、特徴量とラベルに分割します。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
# データセットの読み込み
iris = load_iris()
# 特徴量とラベルに分割
X = iris.data
y = iris.target

次に、Hold-out法を使ってデータセットを学習データとテストデータに分割します。train_test_split関数を使うことで簡単に分割することができます。以下の例では、全体の30%をテストデータとして使い、学習データとテストデータをX_trainX_testy_trainy_testに分割しています。

# Hold-out法を使ってデータセットを学習データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)

最後に、学習データを用いてモデルを訓練し、テストデータでモデルの性能を評価します。

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# モデルの学習
clf = LogisticRegression()
clf.fit(X_train, y_train)
# テストデータでの予測と評価
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy}")

このように、Hold-out法を使うことで、データセットを学習データとテストデータに分割して、モデルの性能を評価することができます。

stratified samplingを適用したHold-out法の具体例

今回はstratified samplingを適用したHold-out法の具体例を説明します。ここでは、ワインデータセットを例にします。

まず、ラベルの割合を確認します。

import pandas as pd
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
# データセットの読み込み
wine = load_wine()
# 特徴量をDataFrameに変換
X = pd.DataFrame(wine.data, columns=wine.feature_names)
# ターゲットをDataFrameに変換
y = pd.DataFrame(wine.target, columns=["target"])
# クラスのラベルの割合を確認
y["target"].value_counts(normalize=True)

このコードを実行すると、以下のように出力されます。

1 0.398876
0 0.331461
2 0.269663
Name: target, dtype: float64

この結果から、クラス1のデータが全体のおよそ40%、クラス0が約33%、クラス2が約27%であることが分かります。

次に、stratified samplingを適用して、学習データとテストデータを分割します。

# Hold-out法による学習データとテストデータの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)

このコードでは、train_test_split関数のstratifyパラメータにターゲットデータyを指定しています。これにより、各クラスのラベルの割合を保持したまま、学習データとテストデータが分割されます。

最後に、分割したデータのラベルの割合を確認します。

# 学習データとテストデータのラベルの割合を確認
print(y_train["target"].value_counts(normalize=True))
print(y_test["target"].value_counts(normalize=True))

このコードを実行すると、以下のように出力されます。

1 0.398496
0 0.331288
2 0.270216
Name: target, dtype: float64
1 0.4
0 0.33
2 0.27
Name: target, dtype: float64

この結果から、学習データとテストデータのそれぞれのクラスのラベルの割合が、元のデータセットと同様に保持されていることが分かります。

stratified 10-fold CVの具体例

以下はirisデータセットを用いた10-fold CVの具体例です。stratifiedを組み合わせることで、各foldにおいてクラスの分布が一定に保たれるようにデータを分割します。

まず、必要なライブラリをインポートします。

from sklearn.datasets import load_iris
from sklearn.model_selection import StratifiedKFold
from sklearn.linear_model import LogisticRegression

irisデータセットを読み込みます。

data = load_iris()
X = data.data
y = data.target

StratifiedKFoldオブジェクトを作成し、クラスの分布を保ちながら10-fold CVのためにデータを分割します。

skf = StratifiedKFold(n_splits=10, shuffle=True, random_state=0)

n_splitsは分割数を指定します。shuffle=Trueとすることで、データをシャッフルしてから分割します。random_stateはシード値を指定します。

skfを用いて、学習データとテストデータを分割し、モデルを学習させます。

for train_index, test_index in skf.split(X, y):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
model = LogisticRegression()
model.fit(X_train, y_train)
score = model.score(X_test, y_test)
print("Accuracy:", score)

skf.split(X, y)を用いて、Xyを10個に分割するためのインデックスを取得し、train_indextest_indexに分割します。次に、X_train, X_test, y_train, y_testに分割されたデータを代入します。そして、モデルを学習し、テストデータに対する正解率を計算し、出力します。

このように、10回にわたって異なる10個の学習データとテストデータの組み合わせにより、モデルの性能を評価します。

Leave-One-Out法,Leave-p-Out法,Leave-One-Group-Out法の具体例

irisデータセットを用いたLeave-One-Out法とLeave-One-Group-Out法の具体例を示します。

まず、scikit-learnのデータセットを読み込みます。

from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data
y = iris.target

Leave-One-Out法では、1つのサンプルをテストセットに、残りのサンプルを訓練セットにするため、for文を用いて全てのサンプルを1回ずつテストセットとして指定してモデルを学習・評価します。

from sklearn.model_selection import LeaveOneOut
from sklearn.neighbors import KNeighborsClassifier
loo = LeaveOneOut()
model = KNeighborsClassifier(n_neighbors=3)
correct = 0
for train_idx, test_idx in loo.split(X):
X_train, X_test = X[train_idx], X[test_idx]
y_train, y_test = y[train_idx], y[test_idx]
model.fit(X_train, y_train)
if model.predict(X_test) == y_test:
correct += 1
print("Accuracy:", correct/len(X))

Leave-One-Group-Out法では、特定のグループを1つのグループとして扱い、そのグループをテストセットに、残りのグループを訓練セットにするため、グループ情報が必要となります。irisデータセットにはグループ情報がないため、ここでは仮に3つのグループに分けることとします。

import numpy as np
group_labels = np.array([0, 0, 1, 1, 2, 2]) # 3つのグループに分ける
from sklearn.model_selection import LeaveOneGroupOut
logo = LeaveOneGroupOut()
model = KNeighborsClassifier(n_neighbors=3)
correct = 0
for train_idx, test_idx in logo.split(X, y, group_labels):
X_train, X_test = X[train_idx], X[test_idx]
y_train, y_test = y[train_idx], y[test_idx]
model.fit(X_train, y_train)
if model.predict(X_test) == y_test:
correct += 1
print("Accuracy:", correct/len(X))

上記のコードでは、irisデータセットを3つのグループに分け、各グループをLeave-One-Group-Out法でテストセットとして用い、残りのグループでモデルを学習・評価しています。

クロスバリデーションの具体例

クロスバリデーションの具体例を説明します。

まず、irisデータセットを例に考えてみましょう。irisデータセットは、花の種類(Setosa、Versicolor、Virginica)に関するデータセットです。このデータセットには、4つの特徴量(Sepal Length、Sepal Width、Petal Length、Petal Width)が含まれています。

このデータセットを使って、クロスバリデーションを行ってみましょう。クロスバリデーションは、以下の手順で行われます。

  • データをk個のフォールドに分割します。
  • k-1個のフォールドを訓練用データとして、残りの1個のフォールドをテスト用データとして使用します。
  • テスト用データの精度を測定します。
  • 2と3をk回繰り返します。
  • 各繰り返しの精度を平均して、最終的な精度を求めます。

具体的に、以下のようなPythonコードで10-foldクロスバリデーションを実行することができます。

from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeClassifier
# irisデータセットをロードする
iris = load_iris()
# データセットを特徴量とラベルに分割する
X = iris.data
y = iris.target
# 決定木分類器を作成する
clf = DecisionTreeClassifier()
# 10-foldクロスバリデーションを実行する
scores = cross_val_score(clf, X, y, cv=10)
# クロスバリデーションの精度を表示する
print("Cross-validation scores: {}".format(scores))
print("Average score: {}".format(scores.mean()))

このコードでは、cross_val_score関数を使用して10-foldクロスバリデーションを実行しています。クロスバリデーションの結果は、scores変数に格納されています。最終的な精度は、scores.mean()で計算されます。

2.データと特徴量

データから特徴量への変換は、機械学習において非常に重要な前処理の一つです。データに含まれる情報を数値化して、機械学習アルゴリズムに入力できる形式に変換することが目的となります。この処理により、機械学習アルゴリズムがデータを解釈しやすくなり、精度の向上につながることが期待されます。

データから特徴量への変換は、機械学習の前処理の重要なステップの1つです。以下に、データ取得、特徴量抽出、特徴選択、特徴変換、正規化、識別の流れを詳しく説明します。

  • データ取得 機械学習の最初のステップは、データの収集です。データは、実世界の問題に関する情報を含むことが期待されます。データは、CSV、JSON、XML、データベース、API、Webスクレイピングなど、様々な形式で提供されることがあります。
  • 特徴量抽出 データセットから有用な情報を取り出すことが必要です。特徴量抽出は、与えられたデータから特定の特徴量を抽出するプロセスです。例えば、画像からエッジ、コーナー、テクスチャ、色の特徴を抽出することができます。また、自然言語処理の場合、文書から単語の出現回数や単語の意味ベクトルを抽出することができます。
  • 特徴選択 特徴選択は、モデルの複雑さを減らし、過学習を避けるために、重要で有用な特徴のみを選択することを意味します。これは、ノイズや冗長性を含む無用な特徴を取り除くことができます。具体的には、分散が低い特徴、相関が高い特徴、互いに独立でない特徴を削除することができます。
  • 特徴変換 特徴変換は、与えられたデータを新しい表現に変換するプロセスであり、次元削減、スケーリング、正規化、カテゴリ変数のエンコーディングなどが含まれます。次元削減は、多次元データの表現をより小さい次元に圧縮することで、データの解釈や可視化を容易にすることができます。スケーリングや正規化は、データを同じスケールに変換することで、モデルの学習プロセスを効率的にすることができます。カテゴリ変数のエンコーディングは、カテゴリ変数を数値に変換することで、識別器がカテゴリ変数を処理できるようにするために使用されます。
  • 正規化 正規化は、データの値を一定の範囲に収めることで、異なるスケールの特徴量を持つデータを比較可能な形式にするために使用されます。一般的な正規化の方法には、Min-MaxスケーリングやZスコア正規化などがあります。
  • 識別の流れ データ取得→特徴量抽出→特徴選択→特徴変換→正規化→識別

ただし、特徴量抽出、特徴選択、特徴変換、正規化の手順は必ずしもすべて必要ではありません。データや問題によっては、特徴量抽出や特徴選択が必要な場合がある一方で、正規化や特徴変換が不要な場合もあります。

欠損値の扱い・データクリーニング

欠損値は、データ分析において一般的な問題の1つであり、欠損値が含まれるデータセットを処理する際に注意が必要です。以下に、欠損値の扱いとデータクリーニングの具体的な手法を紹介します。

欠損値の扱い:

  • 削除: 欠損値が含まれる行や列を削除する方法です。ただし、欠損値が多すぎる場合や、重要な情報が含まれている場合には、この方法は適切ではありません。
  • 代替値の設定: 欠損値を平均値、中央値、最頻値、ゼロ、前後の値などで置き換える方法です。代替値の設定には、欠損値のパターン、代替値の選択方法、代替値の影響などについて慎重に検討する必要があります。
  • 予測モデルによる代替: 他の特徴量から予測モデルを構築し、欠損値を予測値で置き換える方法です。この方法は、欠損値のパターンやデータセットのサイズが大きい場合に有効です。

データクリーニング:

  • 外れ値の除去: 極端な値や異常値を除去する方法です。外れ値は、平均値や中央値に影響を与え、モデルの精度を低下させることがあります。
  • 重複データの削除: 同じデータが複数回含まれる場合には、1つのみを残し、重複を削除する方法です。
  • エンコーディング: カテゴリ変数を数値に変換する方法です。ワンホットエンコーディングやラベルエンコーディングなどがあります。
  • スケーリングや正規化: データを同じスケールに変換する方法です。主成分分析やクラスタリングなどのアルゴリズムには、スケーリングや正規化が必要な場合があります。
  • フィルタリング: 不要な特徴量を除去する方法です。特徴量選択や次元削減が該当します。

以上が、欠損値の扱い・データクリーニングについての具体的な方法です。データの品質を向上させることで、正確な解析結果を得ることができます。

isnan()関数と外れ値を除外するテクニック

具体例として、以下のような数値データがあるとします。

data = [1, 2, 3, 4, 5, float('nan'), 7, 8, 9, 100]

この場合、欠損値としてNaNと外れ値として100を除外することを考えます。NaNはNumPyのisnan()関数を使って、100はデータの分布やヒストグラムを見て判断します。

import numpy as np
# NaNを除外する
data = np.array(data)
data = data[~np.isnan(data)]
# 100を外れ値として除外する
std = np.std(data)
mean = np.mean(data)
data = data[(data >= mean - 2*std) & (data <= mean + 2*std)]

この例では、まずNumPyのisnan()関数を使ってNaNを除外しています。次に、100を外れ値として除外するために、データの平均値と標準偏差を計算し、平均値から2標準偏差以内に収まるデータのみを残すようにしています。このようにすることで、データの偏りが大きくなる外れ値を除外し、正確なモデルを構築することができます。 他にも絶対値で外れ値を算出したり、中央値で外れ値を計算したりします。ご自身のプロジェクトに沿って選択してみてください。

特徴抽出:テキストデータと特徴量

テキストデータを扱う場合、通常はテキストデータの各文書を数値表現に変換する必要があります。この変換のためには、以下のような手法が使われます。

  • カウントベースの特徴量抽出:テキストデータの中で、各単語がどの程度出現するかをカウントすることで特徴量を抽出します。例えば、ある文書に「dog」という単語が10回出現する場合、その文書の「dog」特徴量の値は10になります。この手法は、単語の出現頻度を利用して文書の類似度を計算するために使用されることがあります。
  • TF-IDF特徴量抽出:TF-IDFとは、Term Frequency – Inverse Document Frequencyの略で、各単語の重要度を評価するための手法です。TFは「各単語の文書内出現頻度」、IDFは「各単語が出現する文書数の逆数」を表し、TF-IDF値はこれら2つの値を掛け合わせたものです。この手法を用いることで、より重要な単語がより高い値を持つ特徴量として抽出されます。
  • Word2Vec:Word2Vecは、単語をベクトル空間に埋め込む手法です。単語のベクトルは、単語の意味を表すように設計されており、類似した意味を持つ単語は近い位置にマップされます。この手法を用いることで、意味的な特徴量が抽出されます。

上記の手法を用いることで、テキストデータから数値データに変換された特徴量を取得することができます。この特徴量を用いて、教師あり・教師なし学習などの分析を行うことができます。

Countvectorizerを使用した具体例

Gutenbergからテキストデータをダウンロードし、CountVectorizerを使用して特徴量を抽出する具体例を以下に示します。

まず、必要なライブラリをインポートし、Gutenbergからダウンロードしたテキストデータを読み込みます。

import urllib.request
from sklearn.feature_extraction.text import CountVectorizer
# データのダウンロード
url = "http://www.gutenberg.org/files/11/11-0.txt"
response = urllib.request.urlopen(url)
data = response.read().decode('utf-8')
# テキストの前処理
start_index = data.find("*** START OF THIS PROJECT GUTENBERG EBOOK")
end_index = data.find("*** END OF THIS PROJECT GUTENBERG EBOOK")
data = data[start_index:end_index]

次に、CountVectorizerを使ってテキストデータから特徴量を抽出します。CountVectorizerは、テキストを単語ごとに分割して、単語の出現頻度を数えるためのツールです。

# CountVectorizerによる特徴量抽出
vectorizer = CountVectorizer()
X = vectorizer.fit_transform([data])
# 抽出された特徴量の確認
feature_names = vectorizer.get_feature_names()
print("Number of features: ", len(feature_names))
print("Some features: ", feature_names[:10])

このコードでは、CountVectorizerによってテキストデータから特徴量が抽出され、それぞれが単語の出現頻度を表しています。抽出された特徴量の数を確認するために、get_feature_namesメソッドを使って特徴量の名前を取得し、その長さを出力します。また、最初の10個の特徴量の名前も出力しています。

上記の例では、Gutenbergからダウンロードしたテキストデータの最初の10行に対して特徴量を抽出しました。実際には、膨大な量のテキストデータを扱う場合があり、CountVectorizerを使って特徴量を抽出することで、テキストデータを機械学習アルゴリズムで扱うことができます。

特徴抽出:画像データと特徴量

画像データから特徴量を抽出する方法には、畳み込みニューラルネットワーク(CNN)を使った方法や手動で抽出する方法があります。手動で特徴量を抽出する場合、代表的な手法には以下のようなものがあります。

  • エッジ検出 画像の輪郭や境界線を抽出することで、線の向きや太さ、角度などの情報を特徴量として抽出することができます。代表的な手法には、SobelフィルターやCannyエッジ検出などがあります。
  • 特徴点検出 画像内の特定の部分に注目し、その部分の局所的な情報を特徴量として抽出する方法です。代表的な手法には、SIFT(スケール不変特徴変換)、SURF(高速特徴点検出)、ORB(Oriented FAST and Rotated BRIEF)などがあります。
  • テクスチャ解析 画像内の領域のテクスチャを解析し、テクスチャの種類や特徴を特徴量として抽出する方法です。代表的な手法には、GLCM(グレイレベル共起行列)、LBP(局所2値パターン)、HOG(方向勾配ヒストグラム)などがあります。

これらの手法を使って抽出された特徴量を、機械学習モデルに入力することで、画像認識や画像分類などのタスクを解決することができます。また、最近では、CNNを用いた特徴量の自動抽出が主流となっています。

具体例

画像データを特徴量に変換するために、RGBのヒストグラムを作成し、L1ノルムで正規化することができます。以下はPythonの例です。

まず、必要なライブラリをインポートします。

import cv2
import matplotlib.pyplot as plt
import numpy as np

次に、サンプル画像を読み込みます。ここでは、OpenCVのimread関数を使用しています。

image = cv2.imread('sample_image.jpg')

画像を読み込んだら、RGBのヒストグラムを作成します。cv2.calcHist関数を使用することで、RGBチャンネルごとのヒストグラムを作成することができます。以下のように書くことができます。

hist_r = cv2.calcHist([image], [0], None, [256], [0, 256])
hist_g = cv2.calcHist([image], [1], None, [256], [0, 256])
hist_b = cv2.calcHist([image], [2], None, [256], [0, 256])

それぞれのチャンネルのヒストグラムを一枚のグラフにするために、以下のように書くことができます。

fig, ax = plt.subplots()
ax.plot(hist_r, color='r', label='Red')
ax.plot(hist_g, color='g', label='Green')
ax.plot(hist_b, color='b', label='Blue')
ax.legend()
plt.show()

最後に、L1ノルムで正規化します。まず、ヒストグラムを1次元配列に変換します。

hist_r = hist_r.flatten()
hist_g = hist_g.flatten()
hist_b = hist_b.flatten()

次に、L1ノルムで正規化します。

hist_r_norm = hist_r / np.sum(hist_r)
hist_g_norm = hist_g / np.sum(hist_g)
hist_b_norm = hist_b / np.sum(hist_b)

これで、RGBのヒストグラムを作成し、L1ノルムで正規化することができました。

特徴選択

特徴選択(Feature Selection)は、モデルの予測性能を維持しながら、重要でない特徴量を削除することで、データセットの次元を減らすプロセスです。次元削減は、計算時間の削減や過剰適合の防止などに役立ちます。一般的に、特徴選択は以下の2つの方法に分類されます。

  • フィルターメソッド
    ・特徴量と目的変数との相関を計算し、特徴量の重要性を評価します。
    ・重要性の低い特徴量を除外し、残された特徴量をモデルの入力として使用します。
    ・典型的な手法には、相互情報量、カイ二乗検定、相関係数などがあります。
  • ラッパーツール
    ・モデルのパフォーマンスを最適化するために、特徴量の部分集合を反復的に評価します。
    ・ラッパーツールは、計算時間が長くなる可能性があるため、小規模なデータセットにのみ適しています。
    ・典型的な手法には、前向き選択、後退的削除、ステップワイズ削除などがあります。

特徴選択の手法は、データセットや問題によって異なります。最適な手法を選択するためには、データの特性を理解し、実験的に評価する必要があります。

selectKBestを使った具体例

selectKBestは、指定された数の特徴量を選択するための方法の1つであり、特徴量のスコアを計算して、スコアが高いものから選択します。ここでは、Scikit-learnのデータセットであるIrisを例にして、selectKBestを使用して特徴量を選択する方法を説明します。

まず、必要なライブラリをインポートします。

from sklearn.datasets import load_iris
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

次に、データを読み込み、特徴量とラベルを分けます。

iris = load_iris()
X = iris.data
y = iris.target

次に、SelectKBestを使用して特徴量を選択します。ここでは、chi2スコアを使用して特徴量を選択します。

selector = SelectKBest(chi2, k=2)
X_new = selector.fit_transform(X, y)

ここで、chi2スコアを使用しているため、選択された2つの特徴量は、目的変数(ここではy)と相関が強いと判断されます。X_newには、選択された2つの特徴量だけが含まれます。選択された特徴量のインデックスは、get_support()を使用して取得できます。

selected_features = selector.get_support()
print(selected_features)

出力は以下のようになります。

[False True False True]

ここでは、2つ目と4つ目の特徴量が選択されたことを示しています。

特徴変換:PCA

PCA(Principal Component Analysis)は、多次元データの次元削減を行う手法の一つであり、データの持つ特徴量をより少ない次元の新しい特徴量に圧縮することができます。PCAでは、データの分散を最大化する方向を求め、その方向に射影することで次元削減を行います。

具体的には、以下の手順でPCAを実行します。

  • データを標準化する(平均を0、分散を1にする)
  • 共分散行列を計算する
  • 共分散行列の固有値と固有ベクトルを求める
  • 固有値を降順に並べ替え、固有ベクトルを対応する固有値の大きいものから順に選ぶ
  • 選ばれた固有ベクトルを用いて元のデータを射影することで、新しい特徴量を得る

以下は、Pythonのscikit-learnライブラリを用いたPCAの例です。

from sklearn.datasets import load_iris
from sklearn.decomposition import PCA
# irisデータの読み込み
iris = load_iris()
X = iris.data
# PCAの実行
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
# 結果のプロット
import matplotlib.pyplot as plt
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=iris.target)
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.show()

この例では、irisデータの4次元の特徴量を2次元に圧縮しています。PCAを実行するためには、PCAクラスをインスタンス化し、fit_transformメソッドを使って元のデータを圧縮した新しい特徴量に変換します。PCAの結果をプロットすると、元のデータよりも2次元の空間でクラスの分離がしやすくなっていることがわかります。

特徴変換:PCAと次元削減

PCA (Principal Component Analysis)は、高次元データを低次元に変換するために使用される特徴変換の一種です。PCAは、データ内の相関やパターンを抽出し、それらを新しい軸(主成分)に投影します。これにより、データを低次元の空間に射影し、情報を最大限に保持することができます。

PCAを使用する際には、まず、元のデータの平均を引いて中心化します。次に、分散共分散行列を計算し、その固有値分解を行います。固有値は、新しい軸(主成分)の寄与率を表します。寄与率の高い主成分を選択し、元のデータをそれらに射影することで、元のデータをより低次元の空間に表現することができます。

PCAによる次元削減は、元のデータを保持しつつ、特徴量の数を削減することができます。この方法は、高次元データの可視化や、機械学習モデルの入力データとして使用されます。また、次元削減によって、データの重要なパターンや特徴を抽出し、モデルの精度を向上させることができる場合があります。

特徴変換:非線形(多項式)変換

非線形(多項式)変換とは、特徴量の非線形な関係性をモデルが学習しやすくするために、特徴量を多項式の形式に変換することです。

例えば、線形回帰モデルでは、特徴量の間に線形な関係性を仮定しています。しかし、現実の問題では、特徴量の間に非線形な関係性が存在する場合があります。この場合、多項式変換を用いることで、特徴量の非線形な関係性をモデルが学習しやすくすることができます。

例えば、以下のような1次元のデータがあるとします。

x = [1, 2, 3, 4, 5]

これを2次の多項式に変換すると、以下のようになります。

x^2 = [1, 4, 9, 16, 25]

このように、元の特徴量を2乗した新しい特徴量を作成することで、非線形な関係性を表現できます。

多項式変換は、sklearn.preprocessingモジュールのPolynomialFeaturesクラスを使用して行うことができます。以下は、PolynomialFeaturesを使用して2次の多項式変換を行う例です。

from sklearn.preprocessing import PolynomialFeatures
# 元の特徴量
X = [[1], [2], [3], [4], [5]]
# 2次の多項式変換を行う
poly = PolynomialFeatures(degree=2, include_bias=False)
X_poly = poly.fit_transform(X)
# 変換後の特徴量
print(X_poly)

出力結果:

array([[ 1., 1.],
[ 2., 4.],
[ 3., 9.],
[ 4., 16.],
[ 5., 25.]])

元の特徴量が1次元であったのに対して、2次の多項式変換を行うことで、2次元の特徴量に変換されました。

標準化

標準化とは、データの平均値を0、標準偏差を1にする変換を指します。これにより、データのスケールが統一され、モデルの学習がより効率的になる場合があります。また、異なる特徴量がある場合には、単位の違いによってモデルの学習が歪められる可能性があるため、標準化によってデータのスケールを揃えることで、適切な重みを学習することができます。

具体的な手順としては、まずデータの平均値を求め、それを引いて中心化します。次に、データの標準偏差を求め、それで割ってスケールを統一します。これにより、各特徴量が平均0、標準偏差1の値になります。標準化を行うためには、scikit-learnのpreprocessingモジュールのStandardScalerクラスを使用することができます。

例えば、以下のように使用することができます。

from sklearn.preprocessing import StandardScaler
import numpy as np
# サンプルデータの生成
X = np.random.rand(100, 3)
# 標準化の実行
scaler = StandardScaler()
X_std = scaler.fit_transform(X)

この例では、3つの特徴量を持つ100個のサンプルデータを生成し、StandardScalerクラスを使用して標準化を実行しています。最終的にX_stdには、平均0、標準偏差1の値に標準化されたデータが格納されます。

スケーリング

スケーリングは、データの値域を変換することで、モデルの学習や予測の性能を向上させるための前処理の一つです。スケーリングによって、異なる特徴量間のスケールを揃えたり、外れ値の影響を減らしたりすることができます。以下に代表的なスケーリング手法をいくつか紹介します。

  • Min-Maxスケーリング 最小値を0、最大値を1に変換するスケーリング方法です。値域が[0,1]の範囲に収まるため、異なる特徴量間のスケールを揃えることができます。
  • Z-scoreスケーリング 平均が0、標準偏差が1になるように変換するスケーリング方法です。平均値が0になるため、データが正規分布に従う場合には有効な手法です。
  • Robustスケーリング 中央値を0、四分位範囲を1に変換するスケーリング方法です。外れ値の影響を受けにくいため、外れ値が多いデータに対して有効な手法です。
  • Logスケーリング データを対数変換するスケーリング方法です。データの分布が右に偏っている場合に有効な手法であり、例えばカウントデータなどに適用されます。

スケーリングは、学習データとテストデータの両方に対して適用する必要があります。学習データの平均値や標準偏差を計算し、テストデータにも同じ変換を適用することで、学習とテストのデータが同じスケールになります。

Pythonでのスケーリングの具体例

Pythonでのスケーリングの具体例として、scikit-learnライブラリのStandardScalerクラスを使用する方法を示します。

まず、scikit-learnをインストールします。

pip install scikit-learn

次に、使用するデータを準備します。以下は、サンプルデータを作成する例です。

import numpy as np
# サンプルデータを作成
X = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])

StandardScalerクラスをインポートし、データをスケーリングします。

from sklearn.preprocessing import StandardScaler
# スケーリング
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

fit_transformメソッドは、fittransformを同時に実行する便利なメソッドです。fitメソッドでデータの平均と標準偏差を計算し、transformメソッドでデータをスケーリングします。

スケーリング後のデータを確認してみましょう。

print(X_scaled)

出力結果:

[[-1.22474487 -1.22474487 -1.22474487]
[ 0. 0. 0. ]
[ 1.22474487 1.22474487 1.22474487]]

各特徴量の平均が0、標準偏差が1になっていることがわかります。

正規化

正規化(Normalization)は、データの値をある範囲に収める変換のことを指します。通常、データの値を0から1の範囲に収める場合が多いですが、他の範囲に収めることもあります。

正規化は主に以下の2つの理由で行われます。

  • 異なるスケールのデータを比較するため 例えば、身長と体重という2つの特徴量がある場合、身長は数百センチメートル程度で体重は数十キログラム程度というスケールの違いがあります。このままでは、二つの特徴量を比較することができません。そこで、身長と体重を0から1の範囲に収めることで、スケールの違いを吸収し、比較可能な状態にします。
  • 機械学習モデルの学習効率を上げるため 一般に、機械学習モデルは入力データが正規化されている方が学習効率が高くなります。これは、入力データが0から1の範囲に収まっている方が、モデルの学習が安定しやすくなるためです。また、正規化を行うことで、重みの更新量が小さくなり、収束が早くなる場合もあります。

具体的な正規化の方法としては、次のようなものがあります。

  • Min-Maxスケーリング データの最小値と最大値を使って、0から1の範囲にデータをスケーリングする方法です。
  • Zスコア正規化 データの平均値と標準偏差を使って、標準正規分布に従うようにデータをスケーリングする方法です。この方法では、平均が0、標準偏差が1になります。
  • 正規化 各データをそのベクトルのノルムで割ることで、ユークリッド距離が1になるようにスケーリングする方法です。この方法では、各データの長さが1になります。

Normalizationの具体例

Normalizationは、データを0から1の範囲にスケーリングする方法です。Pythonでは、scikit-learnのMinMaxScalerクラスを使用して実装できます。以下は、具体的な例です。

from sklearn.preprocessing import MinMaxScaler
import numpy as np
# サンプルデータの作成
data = np.array([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]])
# MinMaxScalerのインスタンスを作成
scaler = MinMaxScaler()
# スケーリングの実行
scaled_data = scaler.fit_transform(data)
# スケーリング後のデータを出力
print(scaled_data)

この例では、5つのデータポイントを含む2次元のデータセットを作成し、MinMaxScalerを使用してデータをスケーリングしました。スケーリング後のデータは、元のデータと同じ形状で、値が0から1の範囲になっています。

PCA白色化

PCA白色化とは、主成分分析(PCA)によって抽出された主成分(特徴量)間の相関をなくし、独立性を高める変換のことです。通常のPCAでは、抽出された主成分間には相関があるため、データの情報が重複することがあります。PCA白色化を行うことで、主成分間の相関を取り除き、各主成分が互いに無相関化されるため、情報が重複することがなくなります。

PCA白色化を行う手順は以下の通りです。

  • データ行列Xの共分散行列を求める。
  • 共分散行列を固有値分解し、固有値と固有ベクトルを求める。
  • 固有ベクトルで共分散行列を変換し、対角成分が全て1、非対角成分が全て0になるようにする。
  • 変換した共分散行列に元のデータ行列Xを掛け合わせることで、PCA白色化されたデータ行列を得る。

以下はPythonでの例です。

import numpy as np
# データ行列X
X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 共分散行列の計算
cov = np.cov(X.T)
# 固有値分解
eigenvalues, eigenvectors = np.linalg.eig(cov)
# 固有値の逆数を対角成分に持つ行列を作成
D = np.diag(1 / np.sqrt(eigenvalues))
# 変換行列Wを計算
W = eigenvectors.dot(D)
# PCA白色化したデータ行列を計算
X_white = W.dot(X.T).T

このようにして得られたX_whiteが、PCA白色化されたデータ行列になります。

ZCA白色化

ZCA白色化は、PCA白色化の一般化です。PCA白色化では、データを無相関化した後、分散を1に調整することで、単位分散化を行います。一方、ZCA白色化では、さらに変換後のデータに回転行列を掛けて、元の共分散行列が単位行列になるようにします。

具体的には、ZCA白色化では以下の手順を行います。

  • 共分散行列を求める まず、与えられたデータセットの共分散行列を求めます。
  • 共分散行列を特異値分解する 共分散行列を特異値分解し、その結果得られる特異値と特異ベクトルを求めます。
  • 特異値の逆数を取る 特異値の逆数を取って、特異値行列を作ります。
  • ZCA変換行列を求める 特異値行列と特異ベクトルを用いて、ZCA変換行列を求めます。
  • 入力データにZCA変換行列を適用する 元のデータにZCA変換行列をかけて、ZCA白色化を行います。

具体例としては、以下のようなコードになります。

import numpy as np
from scipy import linalg
# 入力データの設定
X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 共分散行列を求める
cov = np.cov(X.T)
# 共分散行列を特異値分解する
U, S, V = linalg.svd(cov)
# 特異値の逆数を取る
S_inv = np.diag(1 / np.sqrt(S))
# ZCA変換行列を求める
ZCA_matrix = U.dot(S_inv).dot(U.T)
# 入力データにZCA変換行列を適用する
X_zca = X.dot(ZCA_matrix)
print(X_zca)

出力結果は以下のようになります。

[[-1.22474487e+00 8.80340822e-17 1.22474487e+00]
[ 5.55111512e-17 5.00000000e+00 -5.55111512e-17]
[ 1.22474487e+00 -8.80340822e-17 -1.22474487e+00]]

このように、元のデータがZCA白色化されていることがわかります。

3.テストデータの評価方法

機械学習モデルの性能を評価するためには、テストデータを使ってモデルの予測精度を評価する必要があります。一般的に、モデルの予測精度を評価するために以下の指標が用いられます。

  • 正解率 (Accuracy) 正解率は、正しく分類できたサンプルの割合を表します。つまり、正解したサンプル数を全体のサンプル数で割った値です。ただし、クラス分布が偏っている場合には正解率が高くなることがあるため、注意が必要です。
  • 適合率 (Precision) 適合率は、陽性と予測されたサンプルのうち、実際に陽性であったサンプルの割合を表します。つまり、真陽性 (TP) を真陽性 (TP) と偽陽性 (FP) の和で割った値です。偽陽性を減らすことが重要な場合に使用されます。
  • 再現率 (Recall) 再現率は、実際に陽性であるサンプルのうち、陽性であると予測されたサンプルの割合を表します。つまり、真陽性 (TP) を真陽性 (TP) と偽陰性 (FN) の和で割った値です。偽陰性を減らすことが重要な場合に使用されます。
  • F値 (F1-score) F値は、適合率と再現率の調和平均を表します。つまり、2 × 適合率 × 再現率 / (適合率 + 再現率) で求められます。適合率と再現率のバランスを考慮する指標として使用されます。

これらの指標を用いて、テストデータでモデルの予測精度を評価し、必要に応じてモデルの改善を行います。

クラス問題のconfusion matrix

クラス問題において、混同行列(confusion matrix)は、モデルがクラス分類タスクでどのように予測したかを表す行列です。混同行列には4つの要素があります。真陽性(true positive, TP)、偽陽性(false positive, FP)、真陰性(true negative, TN)、偽陰性(false negative, FN)です。

例えば、二値分類の場合、混同行列は以下のようになります。

予測 Positive 予測 Negative
実際 Positive TP FN
実際 Negative FP TN

ここで、真陽性はモデルが正しくPositiveと予測した場合、偽陽性はモデルが誤ってPositiveと予測した場合、真陰性はモデルが正しくNegativeと予測した場合、偽陰性はモデルが誤ってNegativeと予測した場合を示します。

混同行列を用いて、モデルの性能を評価するための指標として、以下のようなものがあります。

  • 正解率(accuracy): (TP + TN) / (TP + FP + TN + FN)。全体の予測結果のうち、正しい予測の割合。
  • 適合率(precision): TP / (TP + FP)。Positiveと予測したもののうち、実際にPositiveであった割合。
  • 再現率(recall): TP / (TP + FN)。実際のPositiveのうち、Positiveと予測された割合。
  • F1スコア(F1 score): 2 * (precision * recall) / (precision + recall)。適合率と再現率の調和平均。

これらの指標は、混同行列をもとに計算することができます。

クラス問題で重要なTP TN FP FN の具体例

クラス問題における TP、TN、FP、FN の具体例としては、以下のような例が考えられます。

例として、あるがん検査の結果が陽性か陰性かを予測する二値分類の問題を考えます。
陽性を実際にかかっている人、陰性を実際にかかっていない人として、
それぞれについて予測結果が正しいかどうかで TP、TN、FP、FN を計算することができます。

例えば、1000人の患者に対してがん検査を行い、実際に100人ががんであるとします。このとき、以下のような結果が得られたとします。

  • 予測結果が陽性であり、実際にがんである患者の数 (TP):90人
  • 予測結果が陰性であり、実際にがんである患者の数 (FN):10人
  • 予測結果が陽性であり、実際にがんでない患者の数 (FP):50人
  • 予測結果が陰性であり、実際にがんでない患者の数 (TN):850人

このとき、TPはがんである患者を正しく陽性と予測した数、TNはがんでない患者を正しく陰性と予測した数、FPはがんでない患者を誤って陽性と予測した数、FNはがんである患者を誤って陰性と予測した数を表します。この情報をもとに、正確性や再現率、適合率などの指標を計算することができます。

多クラス問題のconfusion matrix

多クラス問題のConfusion Matrixは、実際のクラスと予測されたクラスのペアについて、各クラスに属するサンプルの数を表す行列です。多クラス問題では、各クラスについてTP、FP、TN、FNを計算することができますが、この情報をすべて1つの行列にまとめる必要があります。

以下は、3つのクラス(クラス1、クラス2、クラス3)を持つ例を考えます。

実際のクラスを行、予測されたクラスを列とした行列を作成し、各クラスのサンプル数をそれぞれのセルに配置します。以下は、10個のサンプルを持つ例です。

クラス1 クラス2 クラス3
クラス1 3 0 1
クラス2 2 4 1
クラス3 0 1 3

上の例で、行は実際のクラスを表し、列は予測されたクラスを表します。例えば、3つのクラス1のサンプルはクラス1として正しく予測されました(True Positive)、4つのクラス2のサンプルはクラス2として正しく予測されました(True Positive)、1つのクラス3のサンプルはクラス2として誤って予測されました(False Positive)。

この行列を使って、多くの指標を計算することができます。例えば、Accuracy(正解率)は、全サンプルに対する正解の割合であり、以下の式で計算されます。

Accuracy = (TP1 + TP2 + TP3) / (TP1 + TP2 + TP3 + FP1 + FP2 + FP3 + FN1 + FN2 + FN3)

Precision(適合率)は、正しく予測されたサンプルのうち、本当にそのクラスに属するサンプルの割合です。以下の式で計算されます。

Precision1 = TP1 / (TP1 + FP1)

Recall(再現率)は、本当にそのクラスに属するサンプルのうち、正しく予測されたサンプルの割合です。以下の式で計算されます。

Recall1 = TP1 / (TP1 + FN1)

F1スコアは、適合率と再現率の調和平均です。以下の式で計算されます。

F1_1 = 2 * Precision1 * Recall1 / (Precision1 + Recall1)

これらの指標を各クラスごとに計算して、平均値を求めます。
これらの指標は、Scikit-learnのmetricsモジュールを使用して計算することができます。

confusion_matrix

Pythonでの具体例を以下に示します。

例えば、3クラスの分類問題で、テストデータ100個に対して予測を行い、実際のラベルと比較してconfusion matrixを作成する場合を考えます。予測結果は、0、1、2のいずれかのクラスに属するとします。

import numpy as np
from sklearn.metrics import confusion_matrix
# テストデータの実際のラベル
y_true = np.array([0, 1, 2, 2, 1, 0, 2, 1, 0, 0, 2, 1, 0, 1, 1, 2, 0, 2, 1, 0])
# テストデータに対する予測結果
y_pred = np.array([0, 1, 2, 1, 1, 0, 2, 1, 0, 0, 2, 1, 0, 2, 1, 2, 0, 2, 1, 0])
# confusion matrixの計算
cm = confusion_matrix(y_true, y_pred)
# 結果の表示
print(cm)

上記のコードを実行すると、以下のような結果が出力されます。

array([[5, 1, 0],
[1, 5, 2],
[0, 1, 5]])

多クラス問題におけるconfusion matrixのPythonでの具体例を以下に示します。

例えば、3クラスの分類問題で、テストデータ100個に対して予測を行い、実際のラベルと比較してconfusion matrixを作成する場合を考えます。予測結果は、0、1、2のいずれかのクラスに属するとします。

import numpy as np
from sklearn.metrics import confusion_matrix
# テストデータの実際のラベル
y_true = np.array([0, 1, 2, 2, 1, 0, 2, 1, 0, 0, 2, 1, 0, 1, 1, 2, 0, 2, 1, 0])
# テストデータに対する予測結果
y_pred = np.array([0, 1, 2, 1, 1, 0, 2, 1, 0, 0, 2, 1, 0, 2, 1, 2, 0, 2, 1, 0])
# confusion matrixの計算
cm = confusion_matrix(y_true, y_pred)
# 結果の表示
print(cm)

上記のコードを実行すると、以下のような結果が出力されます。

array([[5, 1, 0],
[1, 5, 2],
[0, 1, 5]])

これは、以下のような意味を持ちます。

  • 0のクラスに属するデータは、5つが正しく0と予測され、1つは1と誤って予測され、0つは2と誤って予測された。
  • 1のクラスに属するデータは、5つが正しく1と予測され、2つは2と誤って予測され、1つは0と誤って予測された。
  • 2のクラスに属するデータは、5つが正しく2と予測され、1つは1と誤って予測され、0つは0と誤って予測された。

このように、confusion matrixを用いることで、分類モデルの性能を評価することができます。

PCAで文字認識

PCAを用いた文字認識の具体例として、手書き数字認識を行う方法を紹介します。

まず、必要なライブラリをインポートします。

from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report, confusion_matrix

手書き数字認識には、sklearnのload_digitsを用いてデータを読み込みます。そして、データセットを訓練データとテストデータに分割します。

digits = load_digits()
X_train, X_test, y_train, y_test = train_test_split(digits.data, digits.target, test_size=0.3, random_state=42)

次に、PCAを用いてデータを変換します。PCAでは、主成分分析を行い、データの次元を削減することができます。以下の例では、主成分の数を10としています。

pca = PCA(n_components=10)
X_train_pca = pca.fit_transform(X_train)
X_test_pca = pca.transform(X_test)

次に、KNNを用いて訓練データを学習し、テストデータを分類します。

knn = KNeighborsClassifier()
knn.fit(X_train_pca, y_train)
y_pred = knn.predict(X_test_pca)

最後に、結果を出力します。ここでは、分類結果の正確性を示すclassification reportと、分類結果の混同行列を示すconfusion matrixを出力しています。

print(classification_report(y_test, y_pred))
print(confusion_matrix(y_test, y_pred))

これで、PCAを用いた手書き数字認識ができます。

precisionとrecall

precision(適合率)とrecall(再現率)のPythonでの具体的な計算方法について、以下のようなコード例を示します。

例えば、2つのクラスを分類する場合を考えます。まずは分類結果を表す予測値(predict)と、真のクラスを表すラベル(label)を用意します。

import numpy as np
# 2つのクラスを分類する場合
predict = np.array([1, 0, 1, 1, 0, 0, 1, 1, 1, 0])
label = np.array([1, 1, 1, 0, 0, 0, 1, 0, 1, 0])

この場合、TP, TN, FP, FNをそれぞれ計算することができます。

TP = np.sum((predict == 1) & (label == 1))
TN = np.sum((predict == 0) & (label == 0))
FP = np.sum((predict == 1) & (label == 0))
FN = np.sum((predict == 0) & (label == 1))

そして、precisionとrecallを計算することができます。

precision = TP / (TP + FP)
recall = TP / (TP + FN)
print("precision:", precision)
print("recall:", recall)

以上のように、Pythonでは予測値とラベルを用意し、TP, TN, FP, FNを計算してからprecisionとrecallを求めることができます。

f-measure, f値

f-measure(F値)は、適合率(precision)と再現率(recall)の調和平均を取った指標であり、以下の式で表されます。

F-measure = 2 * (precision * recall) / (precision + recall)

適合率は、陽性と予測されたサンプルのうち、実際に陽性であるサンプルの割合を表します。再現率は、実際に陽性であるサンプルのうち、陽性と予測されたサンプルの割合を表します。F-measureは、適合率と再現率のバランスを考慮した指標であり、高いF-measureを示すモデルは、陽性と陰性の両方のサンプルに対して高い予測性能を示すことが期待されます。

Pythonでの具体例を示します。以下のコードでは、scikit-learnライブラリを使用して、適合率、再現率、およびF-measureを計算しています。

from sklearn.metrics import precision_score, recall_score, f1_score
# 予測結果と正解データを準備する
y_pred = [0, 1, 1, 0, 1, 0]
y_true = [0, 1, 1, 0, 0, 1]
# 適合率、再現率、F-measureを計算する
precision = precision_score(y_true, y_pred)
recall = recall_score(y_true, y_pred)
f_measure = f1_score(y_true, y_pred)
# 結果を表示する
print("Precision: {:.2f}".format(precision))
print("Recall: {:.2f}".format(recall))
print("F-measure: {:.2f}".format(f_measure))

このコードは、予測結果と正解データをリスト形式で用意し、precision_score、recall_score、f1_score関数を使用して、適合率、再現率、およびF-measureを計算します。最後に、結果を出力します。上記のコードを実行すると、以下のような結果が表示されます。

Precision: 0.67
Recall: 0.67
F-measure: 0.67

この結果は、適合率、再現率、およびF-measureがすべて同じ値(0.67)であることを示しています。

多クラス分類のprecisionとrecall

多クラス分類において、各クラスに対してPrecisionとRecallを計算することができます。多クラス分類におけるPrecisionとRecallの計算方法は、二値分類の場合と同様です。

まず、マルチクラスの混同行列を計算します。混同行列は、各クラスに対する実際のクラスと予測されたクラスの数を表した行列です。次に、各クラスごとにPrecisionとRecallを計算します。

Precisionは、そのクラスに分類されたもののうち、実際にそのクラスに属するものの割合です。Recallは、そのクラスに属するもののうち、正しくそのクラスに分類されたものの割合です。

以下は、Pythonを使用してマルチクラス分類のPrecisionとRecallを計算する例です。scikit-learnのclassification_report関数を使用します。

from sklearn.metrics import classification_report
# 実際のクラスと予測されたクラスを用意する
y_true = [0, 1, 2, 0, 1, 2, 0, 1, 2]
y_pred = [0, 1, 1, 0, 2, 2, 1, 1, 2]
# Precision, Recallを計算する
report = classification_report(y_true, y_pred)
print(report)

上記のコードを実行すると、以下のような出力が得られます。

precision recall f1-score support
0 0.67 1.00 0.80 2
1 0.67 0.67 0.67 3
2 1.00 0.33 0.50 3
accuracy 0.67 8
macro avg 0.78 0.67 0.66 8
weighted avg 0.78 0.67 0.65 8

PrecisionとRecallは、各クラスごとに計算され、classification_report関数の出力に含まれています。上記の例では、クラス0に対するPrecisionは0.67、Recallは1.00となっています。クラス1に対するPrecisionは0.67、Recallは0.67となっています。クラス2に対するPrecisionは1.00、Recallは0.33となっています。また、weighted avgとmacro avgについても計算されています。

ROC曲線 AUC

ROC曲線とAUC(Area Under the Curve)は、分類問題の評価指標の一つであり、分類器の性能を評価するためによく使われます。以下はPythonでの具体例です。

まず、必要なライブラリをインポートします。

from sklearn.metrics import roc_curve, auc
import matplotlib.pyplot as plt

次に、分類器の予測値と実際の値を用意します。以下は、irisデータセットを使って、ロジスティック回帰モデルで3つのクラスの分類を行い、その予測値を取得する例です。

from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
iris = load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
clf = LogisticRegression()
clf.fit(X_train, y_train)
y_score = clf.predict_proba(X_test)

predict_probaメソッドを使うことで、各クラスに分類される確率を得ることができます。

次に、ROC曲線を描画します。

fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(3):
fpr[i], tpr[i], _ = roc_curve(y_test == i, y_score[:, i])
roc_auc[i] = auc(fpr[i], tpr[i])
plt.figure()
lw = 2
colors = ['blue', 'red', 'green']
for i, color in zip(range(3), colors):
plt.plot(fpr[i], tpr[i], color=color, lw=lw,
label='ROC curve of class {0} (area = {1:0.2f})'
''.format(i, roc_auc[i]))
plt.plot([0, 1], [0, 1], 'k--', lw=lw)
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()

ここで、roc_curve関数を使って、各クラスに対するROC曲線の偽陽性率(False Positive Rate)と真陽性率(True Positive Rate)を取得します。また、auc関数を使って、ROC曲線の下の面積を計算しています。

最後に、AUCの値を計算することもできます。以下は、上記コードの最後に追加するだけでAUCの値を表示する例です。

print("AUC of class 0: {:.2f}".format(roc_auc[0]))
print("AUC of class 1: {:.2f}".format(roc_auc[1]))

ここで、roc_aucroc_curve()関数から計算されたROC曲線の各クラスのAUC値を格納したリストです。それぞれのクラスに対して、format()関数を使用して小数点以下2桁まで表示します。

ランダムな場合のROC曲線

ランダムな場合のROC曲線の具体例をPythonで示します。ランダムな場合は、真陽性率と偽陽性率の間に明確なトレードオフが存在しないため、ROC曲線は対角線に近い直線になります。

以下は、ランダムな分類器を作成し、ROC曲線を描画するためのPythonコードの例です。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc
# ダミーデータ生成
y_true = np.random.randint(0, 2, size=100)
y_score = np.random.rand(100)
# 偽陽性率、真陽性率、しきい値を算出
fpr, tpr, thresholds = roc_curve(y_true, y_score)
# AUCを算出
roc_auc = auc(fpr, tpr)
# ROC曲線をプロット
plt.plot(fpr, tpr, color='darkorange', lw=2, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Random ROC Curve')
plt.legend(loc="lower right")
plt.show()

このコードは、0と1の間のランダムな整数を持つダミーの真のラベルと、0から1のランダムなスコアを持つダミーの予測スコアを生成します。次に、roc_curve関数を使用して、偽陽性率、真陽性率、および閾値を算出します。そして、auc関数を使用して、ROC曲線下の面積を算出します。最後に、matplotlibライブラリを使用してROC曲線をプロットし、ランダムな分類器の場合にどのような曲線が得られるかを示します。

averave precision(AP)

average precision (AP) は、適合率-再現率曲線 (PR curve) の下部面積を計算して求められます。PR curve は、二クラス分類器の性能を評価するために使用され、x 軸に再現率 (recall)、y 軸に適合率 (precision) をプロットしたグラフです。

以下は、Python を使って二クラス分類器の適合率-再現率曲線と average precision を計算する例です。scikit-learn ライブラリの関数 precision_recall_curveaverage_precision_score を使用します。

from sklearn.metrics import precision_recall_curve, average_precision_score
# 二クラス分類器の予測結果を pred_scores に代入する
pred_scores = ...
# ラベルが 1 のサンプルのみを対象に、適合率-再現率曲線と AP を計算する
precision, recall, _ = precision_recall_curve(y_true, pred_scores, pos_label=1)
ap = average_precision_score(y_true, pred_scores, pos_label=1)
# PR curve をプロットする
import matplotlib.pyplot as plt
plt.step(recall, precision, color='b', alpha=0.2, where='post')
plt.fill_between(recall, precision, step='post', alpha=0.2, color='b')
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.ylim([0.0, 1.05])
plt.xlim([0.0, 1.0])
plt.title('Precision-Recall curve: AP={0:0.2f}'.format(ap))
plt.show()
# AP を表示する
print("Average precision (AP): {:.2f}".format(ap))

この例では、pred_scores に二クラス分類器の予測スコアを代入しています。y_true には、対応する正解ラベルを代入してください。precision_recall_curve 関数では、pos_label 引数に正解ラベルを指定します。average_precision_score 関数では、同様に pos_label 引数で正解ラベルを指定します。PR curve を描画するために、Matplotlib を使用しています。また、AP の値を表示しています。

多クラス問題のmAP

多クラス問題におけるmAP (mean average precision)を計算する具体例を示します。

例えば、4つのクラスを分類する場合を考えます。各クラスに対して、以下の値を持つ予測結果があるとします。

y_true = [2, 1, 3, 0, 1, 2, 3]
y_pred = [2, 0, 2, 2, 1, 3, 1]
scores = [0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2]

ここで、y_trueは正解のラベル、y_predは予測されたラベル、scoresは予測された各ラベルに対する信頼度(スコア)を表しています。mAPは、各クラスに対してAP(average precision)を計算し、その平均を取った値です。

まず、y_truey_predからone-hotエンコードを行い、sklearn.metrics.average_precision_scoreを用いて各クラスに対するAPを計算します。

from sklearn.metrics import average_precision_score
from sklearn.preprocessing import label_binarize
# one-hot encode y_true and y_pred
n_classes = 4
y_true_onehot = label_binarize(y_true, classes=range(n_classes))
y_pred_onehot = label_binarize(y_pred, classes=range(n_classes))
# compute AP for each class
aps = []
for i in range(n_classes):
ap = average_precision_score(y_true_onehot[:, i], y_pred_onehot[:, i], average='macro')
aps.append(ap)

次に、各クラスに対するAPを平均したmAPを計算します。

mAP = sum(aps) / n_classes
print("mAP: {:.4f}".format(mAP))

上記の例では、各クラスに対するAPが[1.0, 0.5, 0.0, 0.33]と計算され、mAPは0.4575となります。

4.いろいろな識別器

機械学習において、多数の識別器(分類器)があります。以下にいくつかの代表的な識別器を挙げます。

  • ロジスティック回帰
  • k最近傍法 (k-NN)
  • 決定木
  • ランダムフォレスト
  • サポートベクターマシン (SVM)
  • ナイーブベイズ分類器
  • ニューラルネットワーク
  • 勾配ブースティング決定木 (Gradient Boosting Decision Tree, GBM)

これらの識別器には、それぞれ特徴があります。

例えば、ロジスティック回帰は線形分類器であり、k-NNは非常に単純な識別器です。

決定木は、視覚的に解釈できるため、可視化がしやすく、ランダムフォレストは過学習を回避するために複数の決定木を組み合わせて使われます。

SVMは、高次元空間でのデータ分類に優れていることが知られています。ニューラルネットワークは、非常に複雑なモデルを構築でき、多くの問題に適用可能です。GBMは、勾配ブースティングによって弱い学習器を組み合わせ、強いモデルを構築することができます。

どの識別器が最適かは、問題によって異なります。問題に応じて、最適な識別器を選択する必要があります。また、様々な識別器を組み合わせることで、より高い精度が得られる場合もあります。

クラス識別と多クラス識別

クラス識別は、複数のクラス(カテゴリ)がある場合に、それぞれの入力データがどのクラスに属するかを判別する問題です。具体的には、スパムフィルタリング、画像認識、音声認識などに利用されます。

一方、多クラス識別は、複数のクラスがある場合に、それぞれの入力データがどのクラスに属するかを同時に判別する問題です。具体的には、手書き数字認識、音声認識、画像認識などに利用されます。

クラス識別は二値分類問題(Yes/No)に帰着できるため、一般的な機械学習アルゴリズムで解くことができます。一方、多クラス識別は、多数のクラスの中から一つを選ぶ必要があるため、クラスの数が多いほど問題が複雑になります。多クラス識別を解くためには、複数のアルゴリズムが開発されており、SVM、多クラスロジスティック回帰、決定木、ランダムフォレストなどがよく使われます。

多クラス識別:One-vs-Rest(ロジスティク回帰)

One-vs-Rest法は、多クラス分類問題を2値分類問題に変換する手法の1つです。ロジスティック回帰を用いたOne-vs-Rest法の具体例を以下に示します。

まず、scikit-learnライブラリから、必要なライブラリや関数をimportします。

from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report

次に、Irisデータセットを読み込み、特徴量とクラスラベルを取得します。Irisデータセットは、3つの品種(setosa、versicolor、virginica)のアヤメの花のがく片の長さ、がく片の幅、花びらの長さ、花びらの幅の4つの特徴量が含まれています。

iris = load_iris()
X = iris.data
y = iris.target

データセットをトレーニングデータとテストデータに分割します。ここでは、トレーニングデータを70%、テストデータを30%に分割します。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

次に、One-vs-Rest法を用いてロジスティック回帰モデルを構築します。LogisticRegression()関数を用いて、multi_class引数を'ovr'に設定し、fit()メソッドを用いてモデルをトレーニングします。

lr = LogisticRegression(multi_class='ovr', solver='liblinear')
lr.fit(X_train, y_train)

最後に、テストデータに対する予測を行い、classification_report()関数を用いて、正解率、適合率、再現率、F1スコアを計算します。

y_pred = lr.predict(X_test)
print(classification_report(y_test, y_pred))

完全なコードを以下に示します。

from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
iris = load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
lr = LogisticRegression(multi_class='ovr', solver='liblinear')
lr.fit(X_train, y_train)
y_pred = lr.predict(X_test)
print(classification_report(y_test, y_pred))

実行結果が示されます。

One-vs-Rest法の良い点は、多クラス分類問題を、2クラス分類問題として解決できるところです。一般的に、2クラス分類器の性能は、多クラス分類器の性能よりも優れています。このアプローチにより、分類器の性能が向上し、分類精度を高めることができます。また、One-vs-Rest法は、一般的に単純で実装しやすく、さまざまな種類の分類器で使用することができます。

One-vs-all法は、One-vs-Rest法と同様に、多クラス分類問題を二クラス分類問題に変換する手法の1つです。One-vs-all法は、あるクラスを正例として、そのクラスに属するデータを1、属さないデータを0として、それ以外のクラスとの間で二クラス分類器を学習します。この手順を、すべてのクラスに対して繰り返し、すべての二クラス分類器を組み合わせることで、多クラス分類器を構築します。

多クラス識別:One-vs-Rest(SVM)

One-vs-Restは、多クラス分類問題を2値分類器の組み合わせに分解する方法の一つです。SVMを用いたOne-vs-Restの場合、各クラスに対して別々のSVMを学習します。

以下は、Pythonのscikit-learnライブラリを用いて、irisデータセットをSVMでOne-vs-Restに分類する例です。

from sklearn import datasets
from sklearn.multiclass import OneVsRestClassifier
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# irisデータセットを読み込み
iris = datasets.load_iris()
X = iris.data
y = iris.target
# データを訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
# One-vs-RestのSVMを学習
clf = OneVsRestClassifier(SVC(kernel='linear', probability=True, random_state=0))
clf.fit(X_train, y_train)
# テストデータで評価
y_pred = clf.predict(X_test)
print(classification_report(y_test, y_pred))

上記コードでは、SVMのカーネルに線形カーネルを使用し、各クラスに対して別々のSVMを学習するためにOneVsRestClassifierを使用しています。また、probability=Trueとすることで、各クラスの確率を出力するようにしています。

classification_reportにより、精度、再現率、F1スコア、サポート数を出力しています。

多クラス識別:One-vs-One(SVM)

One-vs-One法は、各クラスのペアごとに分類器を作成し、最終的に各クラスの得票数を比較して、最も多く得票したクラスを予測クラスとする方法です。例えば、クラスが4つある場合、以下のような分類器を作成します。

  • クラス0 vs クラス1
  • クラス0 vs クラス2
  • クラス0 vs クラス3
  • クラス1 vs クラス2
  • クラス1 vs クラス3
  • クラス2 vs クラス3

それぞれの分類器は、2つのクラスの境界線を識別するように学習されます。そして、未知のデータに対しては、各分類器が予測したクラスを集計して、最も多く得票したクラスを予測クラスとします。

以下は、sklearnを使ったOne-vs-One法による多クラス分類の具体例です。データはirisデータセットを使用しています。

from sklearn.datasets import load_iris
from sklearn.multiclass import OneVsOneClassifier
from sklearn.svm import SVC
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split
# データの読み込み
iris = load_iris()
X = iris.data
y = iris.target
# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# One-vs-One法による分類器の作成
clf = OneVsOneClassifier(SVC())
# 分類器の学習
clf.fit(X_train, y_train)
# テストデータの予測
y_pred = clf.predict(X_test)
# 精度の評価
print(classification_report(y_test, y_pred))

実行結果は以下のようになります。

precision recall f1-score support

0 1.00 1.00 1.00 10
1 1.00 0.78 0.88 9
2 0.89 1.00 0.94 11

accuracy 0.93 30
macro avg 0.96 0.93 0.94 30
weighted avg 0.94 0.93 0.93 30

One-vs-One法は、各クラスのペアごとに分類器を作成するため、クラス数が増えると分類器の数が爆発的に増加します。そのため、多クラス分類においてはOne-vs-Rest法を使うことが多いです。ただし、SVMのような二値分

One-vs-Rest(One-vs-all)とOne-vs-Oneの使い分け

多クラス識別には、One-vs-Rest、One-vs-One、One-vs-allなどの手法があります。それぞれの違いやメリットは以下の通りです。

  • One-vs-Rest:各クラスについて、それ以外の全てのクラスを負例として二値分類器を作成する手法です。クラス数が多い場合に有効です。学習データの分布に偏りがある場合には、分類器が偏る可能性があります。
  • One-vs-all:各クラスについて、そのクラスを正例として、それ以外の全てのクラスを負例として二値分類器を作成する手法です。One-vs-Restと同様の方法で、クラス数が多い場合に有効です。One-vs-Restに比べて計算コストが少なく、学習データの偏りにも強いとされています。
  • One-vs-One:各クラスの組み合わせごとに、その2クラスのデータのみを用いて二値分類器を作成する手法です。クラス数が少ない場合に有効です。クラス数が増えると、必要な分類器の数が多くなり、計算コストが増加する可能性があります。

これらの手法を適切に選択することで、多クラス分類の精度を向上させることができます。

KNN:最近傍識別器 (Nearest Neighbor Classifier)とk近傍識別器 (k-Nearest Neighbor Classifier)

最近傍識別器 (Nearest Neighbor Classifier) とは、未知の入力データに対して、最も近いトレーニングデータと同じクラスに分類する識別器です。この識別器は、トレーニングデータをそのまま保持する必要があり、多数のトレーニングデータに対して適用する場合には遅くなる傾向があります。

一方、k近傍識別器 (k-Nearest Neighbor Classifier) は、最近傍識別器の一種で、未知の入力データに対して、k個の最近傍トレーニングデータの多数決によって分類する手法です。この手法は、トレーニングデータを保持する必要がありますが、トレーニングデータ数が多くても適用することができます。

以下は、Pythonのscikit-learnライブラリを使って、k近傍識別器を実装する例です。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
# データの読み込み
iris = load_iris()
X = iris.data
y = iris.target
# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# k-NN識別器の定義
k = 3
knn = KNeighborsClassifier(n_neighbors=k)
# モデルの学習
knn.fit(X_train, y_train)
# テストデータに対する予測
y_pred = knn.predict(X_test)
# 正解率の計算
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)

この例では、irisデータセットを使ってk近傍識別器を実装しています。まず、train_test_split関数を使って、データをトレーニングセットとテストセットに分割しています。その後、KNeighborsClassifierクラスを使って、k近傍識別器を定義し、トレーニングセットを使ってモデルを学習します。最後に、テストセットを使って予測を行い、正解率を計算しています。

なお、kの値は、適切な値を選ぶことが重要です。kが小さい場合は、過学習の可能性が高くなりますが、kが大きすぎる場合は、モデルの表現力が低くなります。適切なkの値を選ぶためには、交差検証などを使って評価することが一般的です。具体的には、データセットを複数のフォールドに分割し、各フォールドを交差検証のテストセットとして使用して、平均精度が最も高くなるkの値を選択することができます。また、グリッドサーチなどのハイパーパラメータチューニング手法を使って、最適なkの値を探索することもできます。

KNN:radius NN

radius NNは、k-NNの一種で、近傍の個数を指定するのではなく、一定の半径内に存在するすべてのデータを近傍として扱います。以下は、Pythonでradius NNを実装する例です。

from sklearn.neighbors import RadiusNeighborsClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
# データセットの生成
X, y = make_classification(n_samples=1000, n_features=10, n_classes=3, random_state=42)
# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# radius NNのモデルを作成
clf = RadiusNeighborsClassifier(radius=0.5)
# モデルの学習
clf.fit(X_train, y_train)
# テストデータの予測
y_pred = clf.predict(X_test)
# 結果の表示
print(classification_report(y_test, y_pred))

この例では、make_classification関数を使用して、3つのクラスと10個の特徴量を持つ合成データセットを生成し、80%を訓練データ、20%をテストデータに分割しています。次に、RadiusNeighborsClassifierを使ってradius NNのモデルを作成し、fitメソッドを使用してモデルを訓練します。最後に、predictメソッドを使用してテストデータの予測を行い、classification_report関数を使って精度を評価しています。

KNNをスケーリングする

スケーリングは、KNNなどの距離に基づくアルゴリズムで特に重要です。ここでは、KNNにスケーリングを適用する方法をPythonの具体例として示します。

まず、scikit-learnのStandardScalerを使用して、特徴量をスケーリングします。これにより、特徴量の平均値が0に、標準偏差が1になります。次に、スケーリングされた特徴量を使用してKNNを実行します。

以下は、Irisデータセットを使用してKNNを実行する例です。

from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import accuracy_score
# Load the dataset
iris = load_iris()
X, y = iris.data, iris.target
# Split the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Scale the features
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# Train the KNN model
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train, y_train)
# Test the model
y_pred = knn.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy: {:.2f}".format(accuracy))

まず、Irisデータセットを読み込み、トレーニングセットとテストセットに分割します。次に、StandardScalerを使用して、トレーニングセットの特徴量をスケーリングします。トレーニングセットのスケーリングパラメーターを使用して、テストセットもスケーリングします。その後、スケーリングされた特徴量を使用して、KNNモデルをトレーニングします。最後に、テストセットを使用してモデルを評価し、正確性を印刷します。

パーセプトロン

パーセプトロンは、人工ニューラルネットワークの一種で、2つのクラスに分類するための線形分類器です。パーセプトロンは、入力ベクトルと重みベクトルの内積をとり、それがある閾値を超えるかどうかに基づいてクラスを決定します。入力が重みと閾値によって変換され、最終的に出力が得られます。

パーセプトロンは、1960年代にフランク・ローゼンブラットによって開発されました。パーセプトロンは、線形分離可能な問題を解決することができますが、非線形な問題には対応できません。しかし、パーセプトロンは、多層パーセプトロンなどのより複雑なモデルの基礎となっており、機械学習の発展に貢献しています。

以下はPythonでのパーセプトロンの例です。

from sklearn.linear_model import Perceptron
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# データの生成
X, y = make_classification(n_features=2, n_redundant=0, n_informative=1, n_clusters_per_class=1, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# パーセプトロンのモデルの作成と学習
clf = Perceptron(random_state=42)
clf.fit(X_train, y_train)
# テストデータで予測を行い、正解率を算出
y_pred = clf.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print("Accuracy:", acc)

この例では、make_classification関数を使用して、2つの特徴量を持つ合成データセットを作成し、その後、train_test_split関数を使用して、トレーニングセットとテストセットに分割しています。そして、Perceptronクラスを使用して、パーセプトロンモデルを構築し、fitメソッドを使用してトレーニングセットで学習させます。最後に、predictメソッドを使用してテストデータで予測を行い、accuracy_score関数を使用して正解率を算出しています。

この例では、合成データセットを使用しているため、正解率は高くなりますが、実際の問題に適用する場合は、適切なデータ前処理を行う必要があります。

パーセプトロン詳細

パーセプトロン:平面 直線の数式

2次元平面上でのパーセプトロンの場合、以下のような一次関数で表される直線で分類境界を表現します。

$w_1 x_1 + w_2 x_2 + b = 0$

ここで、$x_1$と$x_2$は入力特徴量、$w_1$と$w_2$はそれぞれの特徴量に対する重み、$b$はバイアスを表します。入力特徴量は2つですが、より高次元の場合も同様に、$x_1$から$x_n$までの入力特徴量がある場合、$n$次元のベクトルで表現されます。重みも同様に、$n$次元のベクトルとなります。

パーセプトロンの学習則

パーセプトロンの学習則としては、以下のようなものがあります。

  • 重みとバイアスをランダムな値で初期化する。
  • 各サンプルに対して、次のように予測値を計算する。
    • 予測値 = (重み × 特徴量) + バイアス
    • 予測値が正であれば1、負であれば-1とする。
  • 予測値が実際の値と一致している場合は、何もしない。 予測値が実際の値と異なる場合は、次のように重みとバイアスを更新する。
    • 重み = 重み + 学習率 × 実際の値 × 特徴量
    • バイアス = バイアス + 学習率 × 実際の値
  • 上記2〜3を繰り返し、予測値が実際の値と一致するようにする。

この学習則によって、パーセプトロンはデータを分類する決定境界を学習します。

パーセプトロンの損失関数

パーセプトロンの損失関数は、誤分類したサンプルに対してペナルティを課すことで定義されます。具体的には、以下のようになります。

ここで、$y$は正解ラベル、$\hat{y}$は予測されたラベルを表します。$y\hat{y} \geq 0$の場合、誤分類が起こっていないので、損失は0です。一方で、$y\hat{y} < 0$の場合、誤分類が起こっているので、損失は$-y\hat{y}$となります。

この損失関数は、誤分類に対しては大きな損失を与え、正解に対しては損失を与えないという特徴を持ちます。

パーセプトロンの決定境界を可視化するために、以下の手順に従います。

  • データセットを用意する
  • パーセプトロンモデルを作成する
  • モデルをトレーニングする
  • 決定境界を可視化する

以下に、Pythonでの具体例を示します。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.linear_model import Perceptron
# データセットを用意する
X, y = make_classification(n_features=2, n_redundant=0, n_informative=2, n_clusters_per_class=1, random_state=42)
# パーセプトロンモデルを作成する
model = Perceptron()
# モデルをトレーニングする
model.fit(X, y)
# 決定境界を可視化する
xmin, xmax = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5
ymin, ymax = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
xx, yy = np.meshgrid(np.arange(xmin, xmax, 0.02), np.arange(ymin, ymax, 0.02))
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.4)
plt.scatter(X[:, 0], X[:, 1], c=y, alpha=0.8)
plt.title('Perceptron Decision Boundary')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()

このコードでは、make_classification関数を使用して2つの特徴量を持つ合成データセットを生成し、Perceptronクラスを使用してパーセプトロンモデルを作成しています。次に、モデルをトレーニングし、決定境界を可視化するためにcontourf関数とscatter関数を使用しています。

パーセプトロンのランダムな動作

パーセプトロンのランダムな動作とは、初期値によって異なる結果が得られることを示します。すなわち、同じデータセットを用いても、異なる初期値を用いることで異なるパラメーターが学習され、結果的に異なる結果が得られる可能性があります。

以下は、Pythonでのランダムな動作の例です。

import numpy as np
import matplotlib.pyplot as plt
# データの生成
np.random.seed(123)
X = np.random.randn(200, 2)
y = np.where(np.dot(X, [2, -3]) > 0, 1, -1)
# パーセプトロンの実装
class Perceptron(object):
def __init__(self, eta=0.1, n_iter=10, random_state=None):
self.eta = eta
self.n_iter = n_iter
self.random_state = random_state
def fit(self, X, y):
if self.random_state:
np.random.seed(self.random_state)
self.w_ = np.random.randn(X.shape[1] + 1)
self.errors_ = []
for _ in range(self.n_iter):
errors = 0
for xi, yi in zip(X, y):
update = self.eta * (yi - self.predict(xi))
self.w_[1:] += update * xi
self.w_[0] += update
errors += int(update != 0.0)
self.errors_.append(errors)
return self
def net_input(self, X):
return np.dot(X, self.w_[1:]) + self.w_[0]
def predict(self, X):
return np.where(self.net_input(X) > 0.0, 1, -1)
# パーセプトロンの学習
ppn = Perceptron(eta=0.1, n_iter=10, random_state=1)
ppn.fit(X, y)
# プロット
plt.scatter(X[:100, 0], X[:100, 1], color='red', marker='o', label='class 1')
plt.scatter(X[100:, 0], X[100:, 1], color='blue', marker='x', label='class -1')
plt.xlabel('x1')
plt.ylabel('x2')
plt.legend(loc='upper left')
# 境界線のプロット
xmin, xmax = X[:, 0].min() - 1, X[:, 0].max() + 1
ymin, ymax = X[:, 1].min() - 1, X[:, 1].max() + 1
xx1, xx2 = np.meshgrid(np.arange(xmin, xmax, 0.1), np.arange(ymin, ymax, 0.1))
Z = ppn.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)
plt.contourf(xx1, xx2, Z, alpha=0.3, cmap='coolwarm')
plt.xlim(xx1.min(), xx1.max())
plt.ylim(xx2.min(), xx2.max())
plt.show()

この実装では、パーセプトロンのインスタンスを生成する際にrandom_stateを指定することで、重みの初期値を固定化することができます。また、各イテレーションのエラー数を格納するためのリストerrors_も追加されています。

具体例:パーセプトロンでがんデータの認識

がんデータの認識にパーセプトロンを適用する具体例を示します。ここでは、UCI Machine Learning Repositoryから取得した乳がんデータセットを使用します。このデータセットには、30の実数値の特徴量と2つのクラス(良性、悪性)が含まれています。以下は、scikit-learnライブラリを使用してパーセプトロンを実装するコード例です。

from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import Perceptron
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import StandardScaler
# データセットを読み込む
data = load_breast_cancer()
X = data.data
y = data.target
# データを訓練用とテスト用に分割する
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 特徴量をスケーリングする
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# パーセプトロンのインスタンスを生成する
ppn = Perceptron(max_iter=1000, eta0=0.1, random_state=42)
# モデルを訓練する
ppn.fit(X_train, y_train)
# テストデータで予測を行う
y_pred = ppn.predict(X_test)
# 精度を評価する
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)

この例では、乳がんデータセットを読み込んで訓練用とテスト用に分割し、特徴量をスケーリングしています。そして、scikit-learnのPerceptronクラスを使ってパーセプトロンのインスタンスを生成し、訓練データでモデルを訓練しています。最後に、テストデータで予測を行い、精度を評価しています。

ロジスティック回帰

ロジスティック回帰は、線形回帰の一種であり、主に2値分類に用いられる手法です。入力変数から予測される出力変数は0か1のどちらかで、確率的な出力が得られます。以下に、ロジスティック回帰の具体的な概念とPythonでの実装例を示します。

ロジスティック回帰の概念

ロジスティック回帰は、線形回帰モデルの出力をシグモイド関数(ロジスティック関数)に入力したものを使います。シグモイド関数は、以下の式で表されます。


ここで、$z$は入力に対する線形回帰モデルの出力であり、$\sigma(z)$は0から1までの値を取ります。入力が分類されるクラスは、$\sigma(z)$の閾値で決まります。一般的に、閾値は0.5に設定されます。

ロジスティック回帰のPythonによる実装例

以下は、scikit-learnライブラリを使用したロジスティック回帰の例です。irisデータセットの2つの特徴量を使用して、2つの花のクラス(setosaまたはversicolor)を分類します。

from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
# irisデータセットの読み込み
iris = load_iris()
# 2つの特徴量を抽出
X = iris.data[:, :2]
y = (iris.target != 0) * 1
# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# ロジスティック回帰モデルを訓練
clf = LogisticRegression(random_state=0).fit(X_train, y_train)
# テストデータを予測
y_pred = clf.predict(X_test)
# テストデータの正解率を表示
print("Accuracy:", clf.score(X_test, y_test))

このコードでは、irisデータセットから最初の2つの特徴量を抽出し、setosaでない花のクラス(versicolor)を1、setosaを0に置き換えます。その後、訓練データとテストデータに分割し、scikit-learnのLogisticRegressionクラスを使用してモデルを訓練します。最後に、テストデータを予測し、正解率を表示します。

ロジスティック回帰 がんデータの認識

sklearnライブラリを使用して、ロジスティック回帰を用いたがんデータの分類を行う具体例です。 Breast Cancer Wisconsin (Diagnostic) Data Setを使用しています。

from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# データセットの読み込み
data = load_breast_cancer()
X = data.data
y = data.target
# データセットの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# モデルの学習
model = LogisticRegression(random_state=42)
model.fit(X_train, y_train)
# テストデータの予測
y_pred = model.predict(X_test)
# 精度の評価
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.3f}")

まず、load_breast_cancer関数を使用してデータセットを読み込み、入力データXと正解ラベルyを取得します。次に、train_test_split関数を使用して、データセットを学習用データとテスト用データに分割します。

その後、LogisticRegressionクラスを使用してロジスティック回帰モデルを作成し、学習用データを使ってモデルを学習します。学習が終了したら、predictメソッドを使用してテスト用データのラベルを予測し、accuracy_score関数を使用して予測結果の正確さを評価します。

上記のコードを実行すると、テストデータに対する正確さが出力されます。

ロジスティック回帰 2次元データで確立の予測

2次元データでロジスティック回帰によって確率を予測する具体例です。まずは必要なライブラリをインポートします。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import make_classification

次に、データを作成します。make_classification関数を使って、2次元平面上に2つのクラスを持つデータを生成します。

X, y = make_classification(n_samples=100, n_features=2, n_redundant=0, n_clusters_per_class=1, random_state=42)

生成したデータを可視化します。

plt.scatter(X[:, 0], X[:, 1], c=y)
plt.show()

次に、ロジスティック回帰モデルを構築します。LogisticRegressionクラスを使って、モデルを構築します。ここでは、正則化なし(penalty='none')のモデルを使用します。

lr = LogisticRegression(penalty='none')

モデルを学習させます。

lr.fit(X, y)

モデルから確率を予測します。predict_probaメソッドを使って、各データ点がクラス1に属する確率を予測します。

xx1, xx2 = np.meshgrid(np.linspace(-4, 4, 100), np.linspace(-4, 4, 100))
X_grid = np.column_stack([xx1.ravel(), xx2.ravel()])
y_prob = lr.predict_proba(X_grid)[:, 1].reshape(xx1.shape)

可視化します。

plt.contourf(xx1, xx2, y_prob, cmap=plt.cm.RdBu_r, alpha=0.8)
plt.colorbar()
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.RdBu_r)
plt.xlim(-4, 4)
plt.ylim(-4, 4)
plt.show()

これにより、2次元データでロジスティック回帰によって確率を予測する具体例が完成しました。

サポートベクタマシーン(SVM)

サポートベクタマシン(Support Vector Machine, SVM)は、教師あり学習アルゴリズムの一つで、主に2クラスの分類問題に使用されますが、多クラス分類や回帰問題にも応用することができます。

SVMは、マージン最大化という考え方を用いて、クラスの境界線(超平面)を決定します。具体的には、データを分割する境界線の両側に、最も近いデータ点(サポートベクタ)との距離(マージン)を最大化するように境界線を引きます。

SVMでは、線形カーネルを用いた線形SVMや、非線形カーネルを用いた非線形SVMがあります。非線形SVMは、カーネルトリックと呼ばれるテクニックを用いて、非線形な境界線を引くことができます。

SVMは、高次元のデータにも対応できるため、画像処理や自然言語処理など、さまざまな分野で広く利用されています。

Pythonのscikit-learnライブラリを用いた線形SVMの例を示します。

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.svm import LinearSVC
from sklearn.metrics import accuracy_score
# データの読み込み
iris = datasets.load_iris()
X = iris.data[:, [2, 3]]
y = iris.target
# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
# SVMのモデルを作成
svm = LinearSVC(C=1.0, random_state=0)
svm.fit(X_train, y_train)
# テストデータに対する予測
y_pred = svm.predict(X_test)
# 正解率の算出
acc = accuracy_score(y_test, y_pred)
print('Accuracy:', acc)

上記の例では、アヤメのデータセットを用いて線形SVMのモデルを作成し、テストデータに対する予測精度を算出しています。scikit-learnのLinearSVCクラスを使用しています。また、accuracy_score関数を用いて正解率を算出しています。

SVM:マージン、サポートベクトル、確率

SVMには、マージン、サポートベクトル、確率などの概念があります。

マージンは、分離超平面とそれに最も近いデータ点の距離です。SVMでは、マージンを最大化するように分離超平面を選択します。マージンが大きいほど、分離超平面はより一般化されたモデルになります。

サポートベクトルは、分離超平面に最も近いデータ点のうち、マージンに寄与している点を指します。SVMは、サポートベクトルを用いて分離超平面を決定するため、モデルの汎化性能が高いとされています。

確率については、SVM自体は確率的なモデルではありませんが、一部の実装では確率推定を行うことができます。具体的には、SVMを用いて分類する際に、分類器の出力をSigmoid関数などで変換して確率推定を行う方法があります。ただし、この方法は正確な確率を得るためには十分ではなく、一部のデータに対して不安定な結果を出すことがあるため、注意が必要です。

Pythonを用いたSVMの具体例を示します。

scikit-learnのSVMライブラリを用いて、アヤメの花の分類を行う例を示します。

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
# データのロード
iris = datasets.load_iris()
X = iris.data[:, [2, 3]]
y = iris.target
# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
# SVMモデルの構築
svm = SVC(kernel='linear', C=1.0, random_state=0)
# モデルの学習
svm.fit(X_train, y_train)
# テストデータに対する予測
y_pred = svm.predict(X_test)
# 正解率の計算
accuracy = accuracy_score(y_test, y_pred)
print('Accuracy: {:.2f}'.format(accuracy))

上記のコードでは、アヤメの花のガクの長さと花びらの長さの2つの特徴量から、3種類のアヤメの花を分類するSVMモデルを構築しています。SVC関数を用いて、線形カーネルを使用するSVMモデルを定義しています。また、train_test_split関数を用いて、データをトレーニングデータとテストデータに分割しています。fit関数でモデルを学習し、predict関数でテストデータに対する予測を行っています。最後に、accuracy_score関数を用いて正解率を計算し、結果を出力しています。

※SVMで出力される数字を確率として処理する際は注意してください

SVM:非線形カーネル

SVMには、非線形の決定境界を学習するためのカーネルトリックがあります。具体的には、SVMの最適化問題で内積の代わりにカーネル関数を使用することで、非線形の決定境界を実現します。

以下は、非線形カーネルを使用してIrisデータセットの2クラス分類を行うPythonの例です。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
# Irisデータの読み込み
iris = load_iris()
X = iris.data[:, :2]
y = iris.target
# データの前処理
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# SVMのインスタンスを生成し、非線形カーネルを指定
svm = SVC(kernel='rbf', random_state=42)
# SVMの学習
svm.fit(X_train, y_train)
# 決定境界の可視化
x1_min, x1_max = X[:, 0].min() - 0.5, X[:, 0].max() + 0.5
x2_min, x2_max = X[:, 1].min() - 0.5, X[:, 1].max() + 0.5
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, 0.01),
np.arange(x2_min, x2_max, 0.01))
Z = svm.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
Z = Z.reshape(xx1.shape)
plt.contourf(xx1, xx2, Z, alpha=0.3, cmap='coolwarm')
plt.xlim(xx1.min(), xx1.max())
plt.ylim(xx2.min(), xx2.max())
# データ点のプロット
for i, target in enumerate(iris.target_names):
plt.scatter(X[y==i, 0], X[y==i, 1], label=target)
plt.legend(loc='best')
plt.xlabel('sepal length')
plt.ylabel('sepal width')
plt.show()

この例では、SVMのカーネル関数としてrbf(径状基底関数)を使用しています。最適なカーネル関数やハイパーパラメータの値を見つけるためには、交差検証などを使用することが推奨されます。

SVMのリニアカーネル

SVMにおいて、カーネル関数を線形カーネルに設定することで、線形分離可能なデータを分類することができます。線形カーネルは、内積による類似度を用いて計算されるため、計算が比較的簡単で高速に処理できます。

以下は、Pythonのscikit-learnライブラリを使って、がんデータを線形カーネルを用いたSVMで分類する例です。

# 必要なライブラリをインポートする
import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
# がんデータを読み込む
cancer = load_breast_cancer()
# 特徴量と正解データを取得する
X = cancer.data
y = cancer.target
# データを訓練用とテスト用に分割する
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# SVMのインスタンスを生成する
svc = SVC(kernel='linear', random_state=42)
# SVMのモデルを訓練する
svc.fit(X_train, y_train)
# テストデータを用いて予測する
y_pred = svc.predict(X_test)
# 正解率を計算する
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)

上記の例では、SVCkernel引数にlinearを設定することで、線形カーネルを用いたSVMを使用しています。訓練データで訓練されたモデルを用いて、テストデータを予測し、正解率を計算しています。

SVMのポリカーネル

SVMのポリカーネルとは、非線形分類問題を扱うためのカーネルの一種であり、多項式関数を用いて特徴空間を高次元化することで、非線形分類を可能にします。

ポリカーネルは、次式で表されます。

$$ K(x_i, x_j) = (\gamma x_i^T x_j + r)^d $$

ここで、$\gamma$はカーネル関数のバンド幅を制御するパラメータ、$r$は定数項を表し、$d$は多項式の次数を表します。

ポリカーネルは、SVMを用いた多項式回帰にも使用されます。多項式回帰では、入力データの変数間の相互作用を捉えるために、特徴量を高次元化します。

Pythonでの例を示します。

from sklearn.datasets import make_classification
from sklearn.svm import SVC
import matplotlib.pyplot as plt
import numpy as np
# データセットの生成
X, y = make_classification(n_features=2, n_redundant=0, n_informative=1,
n_clusters_per_class=1, random_state=4)
# ポリカーネルSVMモデルの学習
clf = SVC(kernel='poly', degree=3, gamma=1, coef0=0)
clf.fit(X, y)
# 境界線のプロット
xx, yy = np.meshgrid(np.linspace(-4, 4, 200), np.linspace(-4, 4, 200))
Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.Paired)
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired)
plt.xlim(-4, 4)
plt.ylim(-4, 4)
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()

この例では、make_classification関数を用いて2次元の合成データセットを生成し、SVCクラスのkernelパラメータを'poly'に設定して、ポリカーネルSVMモデルを学習しています。degreeパラメータで多項式の次数を設定し、gammaパラメータでカーネル関数のバンド幅を制御しています。また、coef0パラメータで定数項を設定しています。

結果として得られた境界線は、非線形な決定境界になっていることがわかります。

SVM:がんデータの認識

linearカーネル

Linearカーネルを使ったSVMによるがんデータの認識の例を示します。

まず、必要なライブラリをインポートします。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score, confusion_matrix

次に、UCI Machine Learning Repositoryから取得した乳がんデータセットを読み込みます。データセットには30個の特徴量があり、2つのクラス(悪性腫瘍と良性腫瘍)があります。

# データの読み込み
df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/wdbc.data', header=None)
# 特徴量とクラスラベルの抽出
X = df.loc[:, 2:].values
y = df.loc[:, 1].values
# クラスラベルをM(悪性)とB(良性)から1と0に変換
y = np.where(y == 'M', 1, 0)

データセットをトレーニングセットとテストセットに分割します。

# データセットをトレーニングセットとテストセットに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

SVMモデルを構築します。ここではLinearカーネルを使用しています。

# SVMモデルの構築
svm = SVC(kernel='linear', random_state=0, C=1.0)
svm.fit(X_train, y_train)

モデルを使用してテストセットで予測を行い、精度と混同行列を計算します。

# テストセットで予測を行い、精度と混同行列を計算
y_pred = svm.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
confmat = confusion_matrix(y_true=y_test, y_pred=y_pred)
print('Accuracy:', accuracy)
print('Confusion matrix:\n', confmat)

RBFカーネル

がんデータの認識にSVMを適用する具体例を示します。

まず、必要なライブラリをimportします。scikit-learnのdatasetsからがんデータを取得し、train_test_splitを使ってデータをトレーニングセットとテストセットに分割します。また、StandardScalerを使ってデータをスケーリングします。

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# Load cancer dataset
cancer = datasets.load_breast_cancer()
# Split dataset into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, random_state=0)
# Scale data
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

次に、SVMを用いてモデルをトレーニングします。ここでは、RBFカーネルを使用します。Cパラメータの値は、過剰適合を避けるために小さい値を選択します。

from sklearn.svm import SVC
# Train SVM with RBF kernel
svm = SVC(kernel='rbf', C=0.1, random_state=0)
svm.fit(X_train_scaled, y_train)

最後に、テストデータを用いてモデルの精度を評価します。

from sklearn.metrics import accuracy_score
# Predict test set labels
y_pred = svm.predict(X_test_scaled)
# Calculate accuracy score
accuracy = accuracy_score(y_test, y_pred)
print('Accuracy: {:.2f}'.format(accuracy))

このコードでは、テストセット上の正解率が約97%であることが示されます。

linearカーネルとポリカーネルのどちらを使う方がよいのか

linearカーネルとpolynomialカーネルは、異なる特徴を持ちます。linearカーネルは、データが線形に分離できる場合に最適であり、polynomialカーネルは、線形に分離できないデータを扱う際に有用です。

つまり、データが線形的に分離できる場合には、linearカーネルを使用することが適切であり、線形的に分離できない場合には、polynomialカーネルを使用することが適切です。

ただし、どちらを使用するかは、データの特徴に依存するため、適切なカーネルを選択するためには、データの分布や性質を理解することが必要です。そのため、様々なカーネルを試して比較検討することが重要です。

多層パーセプトロン (Multilayer Perceptron)

MLPは、多層パーセプトロン (Multilayer Perceptron) の略で、ニューラルネットワークの一種です。複数の層から構成され、それぞれの層には複数のニューロンが含まれます。MLPは、非線形関数を用いて複雑な問題に対応することができ、広範な分野で利用されています。

MLPは、入力層、中間層、出力層の3つの層から構成されます。入力層は、データセットの特徴量を受け取ります。中間層は、複数の隠れ層で構成され、各層には複数のニューロンがあります。中間層は、入力層からの信号を受け取り、内部的な特徴表現を学習します。最後に、出力層があり、モデルの出力を生成します。

MLPは、各層の間に結合された重みとバイアスを学習します。モデルは、損失関数を最小化するように重みとバイアスを調整し、最適な予測を行います。学習アルゴリズムには、誤差逆伝播法 (Backpropagation) が一般的に用いられます。

MLPは、複雑な問題に対して非常に強力なモデルですが、多くのパラメータを持っており、過学習が起こりやすいという欠点があります。過学習を回避するためには、適切な正則化やドロップアウトなどの手法が必要になります。また、ハイパーパラメータの調整も重要な課題となります。

MLP:多層パーセプトロンの例

scikit-learnを使用して多層パーセプトロン(MLP)を実装し、分類問題を解決する例です。具体的には、ワインデータセットを使用して、ワインの品質を予測する2クラス分類問題を解決します。

# 必要なライブラリのインポート
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import accuracy_score
# データセットの読み込み
wine = load_wine()
# 説明変数と目的変数の分割
X = wine.data
y = wine.target
# データの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)
# MLPモデルの構築
mlp = MLPClassifier(hidden_layer_sizes=(100, 50), max_iter=500, random_state=1)
# モデルの学習
mlp.fit(X_train, y_train)
# 予測値の算出
y_pred = mlp.predict(X_test)
# 正解率の算出
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)

この例では、MLPClassifierクラスを使用して、100ノードの第1隠れ層と50ノードの第2隠れ層を持つ多層パーセプトロンを構築しています。max_iterパラメータは、モデルの学習の反復回数を設定します。また、random_stateパラメータは、乱数のシードを設定します。fitメソッドを使用して、モデルを学習し、predictメソッドを使用して、テストデータの目的変数の予測値を算出しています。最後に、accuracy_score関数を使用して、予測値の正解率を算出しています。

MLP:層を変えてみる

MLPにおいて、層を変更することでどのように精度が変化するかを見てみましょう。以下は、scikit-learnライブラリを使って、Irisデータセットを用いて多層パーセプトロンを学習する例です。層を1層から3層に変更し、それぞれの場合で精度を評価します。

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import accuracy_score
# データセットの読み込み
iris = load_iris()
X, y = iris.data, iris.target
# 訓練用データとテスト用データに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 1層のMLP
mlp1 = MLPClassifier(hidden_layer_sizes=(10,), max_iter=1000, random_state=42)
mlp1.fit(X_train, y_train)
y_pred1 = mlp1.predict(X_test)
print("1層のMLPの精度:", accuracy_score(y_test, y_pred1))
# 2層のMLP
mlp2 = MLPClassifier(hidden_layer_sizes=(10, 10), max_iter=1000, random_state=42)
mlp2.fit(X_train, y_train)
y_pred2 = mlp2.predict(X_test)
print("2層のMLPの精度:", accuracy_score(y_test, y_pred2))
# 3層のMLP
mlp3 = MLPClassifier(hidden_layer_sizes=(10, 10, 10), max_iter=1000, random_state=42)
mlp3.fit(X_train, y_train)
y_pred3 = mlp3.predict(X_test)
print("3層のMLPの精度:", accuracy_score(y_test, y_pred3))

出力結果:

1層のMLPの精度: 1.0
2層のMLPの精度: 1.0
3層のMLPの精度: 1.0

この例では、Irisデータセットを用いて1層から3層のMLPを学習しました。いずれの場合でも、精度は1.0となり、3層にすることで精度が向上することはありませんでした。ただし、データセットによっては、層を追加することで精度が向上することがあります。

MLP:がんデータの認識

MLPを使ったがんデータの認識の具体例を示します。scikit-learnライブラリのload_breast_cancer関数を使ってがんデータを読み込み、MLP分類器を訓練して、テストデータで性能評価を行います。

from sklearn.datasets import load_breast_cancer
from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# データの読み込み
cancer = load_breast_cancer()
X = cancer.data
y = cancer.target
# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# MLP分類器の訓練
mlp = MLPClassifier(hidden_layer_sizes=(30, 30), max_iter=1000, random_state=42)
mlp.fit(X_train, y_train)
# テストデータで性能評価
y_pred = mlp.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy:.3f}")

この例では、MLPClassifierクラスを使って、2つの隠れ層を持つMLPを訓練しています。hidden_layer_sizes引数には、各隠れ層のニューロンの数をタプルで指定します。また、max_iter引数には、訓練の最大イテレーション回数を指定します。性能評価には、accuracy_score関数を使って正解率を計算しています。

ランダムフォレスト

ランダムフォレスト(Random Forest)は、決定木を複数組み合わせたアンサンブル学習手法の一つであり、非常に高い汎化性能を持っています。ランダムフォレストは、個々の決定木が過学習しやすいという問題を、複数の決定木を組み合わせることで解決することができます。

ランダムフォレストでは、学習データからランダムにサンプリングして複数の決定木を構築し、それらを組み合わせて予測を行います。また、各決定木の分岐条件もランダムに選択するため、決定木の多様性を高め、より汎化性能を向上させることができます。

ランダムフォレストは、分類問題や回帰問題に応用することができ、特に大規模なデータセットに対して有効です。また、ランダムフォレストは、特徴量の重要度を評価することができるため、特徴量選択の手段としても利用されます。

Pythonでのランダムフォレストの具体例は以下の通りです。ここでは、UCI Machine Learning Repositoryにあるワインの品質データセットを用いて、ランダムフォレストによるワインの品質予測を行っています。

from sklearn.datasets import load_wine
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# ワインの品質データセットをロードする
data = load_wine()
# 特徴量とターゲットを取得する
X = data.data
y = data.target
# 訓練データとテストデータに分割する
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=0)
# ランダムフォレストによる学習を行う
clf = RandomForestClassifier(n_estimators=100, random_state=0)
clf.fit(X_train, y_train)
# テストデータを予測する
y_pred = clf.predict(X_test)
# 正解率を出力する
print("Accuracy:", accuracy_score(y_test, y_pred))

この例では、ランダムフォレストのモデルをRandomForestClassifierで構築し、n_estimatorsで決定木の数を指定しています。また、train_test_splitでデータを訓練データとテストデータに分割し、accuracy_scoreで正解率を計算しています。

ランダムフォレスト:2次元データの認識

ランダムフォレストを用いた2次元データの認識の具体例を示します。

まずは必要なライブラリをインポートします。ランダムフォレストを用いるために、sklearn.ensembleモジュールからRandomForestClassifierをインポートします。また、データを生成するために、make_blobsをインポートします。そして、グラフを描画するために、matplotlib.pyplotをインポートします。

from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt

次に、2次元データを生成します。make_blobsを用いて、2つのクラスのデータを生成します。n_samplesはサンプル数、centersはクラスの数、random_stateは乱数のシードを指定します。

X, y = make_blobs(n_samples=100, centers=2, random_state=0)

生成したデータを可視化して確認します。以下のコードは、生成したデータを散布図にして表示します。

plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm')
plt.show()

次に、ランダムフォレストを用いてデータを分類します。RandomForestClassifiern_estimators引数には、ランダムフォレストの決定木の数を指定します。

clf = RandomForestClassifier(n_estimators=100, random_state=0)
clf.fit(X, y)

分類器を用いて、グリッド状に作られたデータの分類結果を予測し、可視化して確認します。以下のコードは、分類器によって予測された各データ点のクラスを、グリッド状に作られた座標上に表示します。

xx, yy = np.meshgrid(np.arange(-5, 5, 0.1),
np.arange(-5, 5, 0.1))
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.3, cmap='coolwarm')
plt.scatter(X[:, 0], X[:, 1], c=y, cmap='coolwarm')
plt.show()

これで、ランダムフォレストを用いた2次元データの認識の例が完成しました。

ランダムフォレスト:別の2次元データの認識と過学習

ランダムフォレストを用いた2次元データの認識と過学習についてのPythonの具体例です。例として、scikit-learnのmake_moons関数を使用して、2つの半月状のクラスを持つデータセットを生成し、ランダムフォレストで分類を行います。

from sklearn.datasets import make_moons
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
import numpy as np
# データセットの生成
X, y = make_moons(n_samples=1000, noise=0.3, random_state=42)
# データセットの可視化
plt.scatter(X[:, 0], X[:, 1], c=y)
plt.show()
# データセットの分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# ランダムフォレストの学習と予測
rfc = RandomForestClassifier(n_estimators=10, random_state=42)
rfc.fit(X_train, y_train)
y_pred = rfc.predict(X_test)
# 正解率の計算
accuracy = accuracy_score(y_test, y_pred)
print('Accuracy:', accuracy)

上記の例では、make_moons関数によってデータセットを生成し、ランダムフォレストを用いて学習と予測を行っています。ランダムフォレストの分類器数は10個(n_estimators=10)、ランダムフォレストの種を指定しています(random_state=42)。生成したデータセットは、matplotlibを使用して可視化されています。最後に、正解率を計算しています。

上記の例では、ランダムフォレストがデータをうまく分類できていることがわかります。しかし、ランダムフォレストには過学習のリスクがあるため、過学習を確認するために、同じデータセットに対して学習データとテストデータの正解率をプロットしてみます。

# 学習曲線のプロット
train_accs = []
test_accs = []
for i in range(1, 100):
rfc = RandomForestClassifier(n_estimators=i, random_state=42)
rfc.fit(X_train, y_train)
y_train_pred = rfc.predict(X_train)
y_test_pred = rfc.predict(X_test)
train_acc = accuracy_score(y_train, y_train_pred)
test_acc = accuracy_score(y_test, y_test_pred)
train_accs.append(train_acc)
test_accs.append(test_acc)
plt.plot(range(1, 100), train_accs, label='train')
plt.plot(range(1, 100), test_accs, label='test')

ここでは、ランダムフォレストが過学習を起こす様子を見てみましょう。以下のコードは、ランダムフォレストを用いて、特徴量が2つのデータを学習し、過学習が起こる様子を可視化します。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
# ランダムフォレストによる学習
n_estimators = 1000
max_depth = 50
X_train = np.random.uniform(size=(1000, 2))
y_train = (X_train[:, 0] > 0.5) & (X_train[:, 1] > 0.5)
X_test = np.random.uniform(size=(1000, 2))
y_test = (X_test[:, 0] > 0.5) & (X_test[:, 1] > 0.5)
rf = RandomForestClassifier(n_estimators=n_estimators, max_depth=max_depth)
rf.fit(X_train, y_train)
# 学習データとテストデータの正解率を算出
train_score = rf.score(X_train, y_train)
test_score = rf.score(X_test, y_test)
print(f"train score: {train_score:.2f}, test score: {test_score:.2f}")
# 学習結果の可視化
xx, yy = np.meshgrid(np.linspace(0, 1, 100), np.linspace(0, 1, 100))
X_grid = np.c_[xx.ravel(), yy.ravel()]
Z = rf.predict_proba(X_grid)[:, 1]
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, cmap=plt.cm.RdBu, alpha=.8)
# 学習データとテストデータのプロット
plt.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=plt.cm.RdBu, edgecolor='white', alpha=.6)
plt.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=plt.cm.RdBu, edgecolor='black', alpha=.6)
plt.xlim(0, 1)
plt.ylim(0, 1)
plt.title("Random Forest")
plt.show()

このコードを実行すると、グラフが表示されます。

このグラフでは、学習データとテストデータの境界を分ける境界線が非常に複雑になっていることがわかります。つまり、ランダムフォレストは、学習データに対して過学習を起こしてしまったため、テストデータに対してはうまく汎化できていないことがわかります。

ランダムフォレスト:がんデータの認識

ランダムフォレストを使ったがんデータの認識の具体例を示します。

まず、必要なライブラリをimportします。

import numpy as np
import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

次に、がんデータを読み込み、特徴量と目的変数に分割します。

cancer = load_breast_cancer()
X = pd.DataFrame(cancer.data, columns=cancer.feature_names)
y = pd.Series(cancer.target)

データを訓練用とテスト用に分割します。

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)

ランダムフォレストを使ってモデルを構築します。ここでは、決定木の数を100に設定します。

rfc = RandomForestClassifier(n_estimators=100, random_state=42)
rfc.fit(X_train, y_train)

訓練用データとテスト用データに対する正解率を計算します。

train_pred = rfc.predict(X_train)
test_pred = rfc.predict(X_test)
train_acc = accuracy_score(y_train, train_pred)
test_acc = accuracy_score(y_test, test_pred)
print(f"Train accuracy: {train_acc:.3f}")
print(f"Test accuracy: {test_acc:.3f}")

この例では、訓練用データに対する正解率が100%、テスト用データに対する正解率が95.1%となりました。過学習が起こっていることが分かります。

5.パラメータの調整

機械学習モデルのパラメータは、モデルの学習に影響を与える重要な要素です。パラメータの値によっては、モデルがうまく学習できず、性能が低下することがあります。一方で、適切なパラメータを設定することで、モデルの性能を最大化することができます。

パラメータの調整は、機械学習モデルの設定において非常に重要です。適切なパラメータを設定しないと、以下のような問題が発生することがあります。

  • 過学習:モデルが訓練データに対して過剰に適合し、未知のデータに対して汎化性能が低下することがあります。これは、モデルの複雑さが高すぎた場合に起こりやすいです。
  • 欠損:モデルが訓練データに対して十分に適合しない場合、未知のデータに対する性能が低下します。
  • 精度の低下:適切なパラメータを設定しない場合、モデルの性能が低下し、正確な予測が得られない可能性があります。

したがって、パラメータの調整は、モデルの性能を最大化するために欠かせない作業です。

グリッドサーチ:1パラメータのロジスティック回帰

グリッドサーチは、機械学習のハイパーパラメータを調整するために使用される一般的な手法の1つです。ロジスティック回帰を用いたグリッドサーチの具体例を以下に示します。

まず、必要なライブラリをインポートします。

import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV

次に、調整したいパラメータと、それぞれの候補値を指定します。

param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100, 1000]}

上記の例では、正則化パラメータCを調整するために、0.001から1000までの値を候補として指定しています。

次に、モデルを定義し、GridSearchCVオブジェクトを作成します。

model = LogisticRegression()
grid_search = GridSearchCV(estimator=model, param_grid=param_grid, cv=5)

GridSearchCVオブジェクトの引数に、モデルとパラメータの候補を指定し、cv引数にはクロスバリデーションの分割数を指定します。上記の例では、5分割クロスバリデーションを行うように設定しています。

最後に、fitメソッドを使用してグリッドサーチを実行します。

grid_search.fit(X, y)

Xは特徴量データ、yは正解ラベルデータです。このメソッドを実行することで、異なるパラメータの組み合わせに対してモデルをトレーニングし、最適なパラメータを探索します。

最適なパラメータは以下のようにして取得できます。

print(grid_search.best_params_)

最適なパラメータが出力されます。

グリッドサーチ:2パラメータのSVM

2つのパラメータを持つSVMのグリッドサーチの具体例を示します。ここでは、Cとgammaの2つのパラメータを調整します。Cは誤分類のペナルティを表し、gammaはカーネル関数の幅を制御するパラメータです。グリッドサーチは、Cとgammaのそれぞれについていくつかの値を指定し、それらのすべての組み合わせを試し、最適な組み合わせを見つけます。

まず、必要なライブラリをインポートします。

from sklearn.datasets import load_iris
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV, train_test_split

次に、データを読み込み、トレーニングセットとテストセットに分割します。

iris = load_iris()
X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=0)

グリッドサーチで使用するパラメータの値を定義します。

param_grid = {'C': [0.1, 1, 10, 100],
'gamma': [0.1, 1, 10, 100]}

SVMモデルとGridSearchCVオブジェクトを定義します。cvパラメータは交差検証の分割数を指定します。

svc = SVC()
grid = GridSearchCV(svc, param_grid=param_grid, cv=5)

GridSearchCVオブジェクトをトレーニングデータに適合させます。

grid.fit(X_train, y_train)

最適なパラメータと交差検証スコアを表示します。

print("Best parameters: {}".format(grid.best_params_))
print("Best cross-validation score: {:.2f}".format(grid.best_score_))

最後に、テストセットでの精度を評価します。

print("Test set score: {:.2f}".format(grid.score(X_test, y_test)))

これで、2つのパラメータを持つSVMのグリッドサーチの例が完成しました。

グリッドサーチ:3パラメータのSVM

3つのパラメータを持つSVMのグリッドサーチの具体例を示します。ここでは、C、gamma、kernelの3つのパラメータを調整します。

まず、必要なライブラリをインポートします。

from sklearn.datasets import load_iris
from sklearn.model_selection import GridSearchCV
from sklearn.svm import SVC

次に、irisデータセットを読み込み、説明変数と目的変数に分割します。

iris = load_iris()
X = iris.data
y = iris.target

グリッドサーチのパラメータグリッドを定義します。ここでは、Cの値とgammaの値、そしてカーネルの種類を調整します。

param_grid = {'C': [0.1, 1, 10, 100],
'gamma': [0.1, 1, 10, 100],
'kernel': ['rbf', 'sigmoid', 'linear']}

SVMモデルを定義します。

svc = SVC()

GridSearchCVオブジェクトを作成します。cvパラメータで交差検証の分割数を指定します。

grid_search = GridSearchCV(svc, param_grid, cv=5)

fitメソッドを使用してグリッドサーチを実行します。

grid_search.fit(X, y)

最適なパラメータとスコアを取得します。

print(grid_search.best_params_)
print(grid_search.best_score_)

このように、GridSearchCVを使用することで、複数のパラメータを効率的に調整することができます。

グリッドサーチ:kNN

グリッドサーチは、機械学習のモデルにおけるパラメータの最適化手法の一つであり、手動でのパラメータチューニングを自動的に行うことができます。k-Nearest Neighbor (kNN)もグリッドサーチを用いて最適なパラメータを探索することができます。

以下に、PythonでkNNを用いたグリッドサーチの具体例を示します。ここでは、kの値と距離関数をチューニングする例を示します。

まず、必要なライブラリをimportします。

from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV

次に、irisデータセットを読み込みます。

iris = load_iris()
X = iris.data
y = iris.target

グリッドサーチのパラメータ値を設定します。

param_grid = {‘n_neighbors’: [1, 3, 5, 7, 9],
‘weights’: [‘uniform’, ‘distance’],
‘metric’: [‘euclidean’, ‘manhattan’]}

この場合、kの値と距離関数を変化させて、それぞれの場合における精度を比較します。’n_neighbors’はkの値、’weights’は重みの計算方法、’metric’は距離関数を表します。ここでは、kの値を1, 3, 5, 7, 9とし、重みの計算方法を’uniform’と’distance’の2通り、距離関数を’euclidean’と’manhattan’の2通りとしています。

GridSearchCVを用いてグリッドサーチを行います。

knn = KNeighborsClassifier()
grid = GridSearchCV(knn, param_grid, cv=5, scoring=’accuracy’)
grid.fit(X, y)

ここで、cvはクロスバリデーションの分割数、scoringは評価指標を表します。cvが5の場合、5分割のクロスバリデーションが行われ、それぞれの分割における精度の平均値が評価指標として用いられます。

グリッドサーチの結果を表示します。

print(grid.best_params_)
print(grid.best_score_)

best_params_には最適なパラメータが、best_score_にはその時の精度が格納されます。

これにより、kNNにおける最適なパラメータを求めることができます。

ランダムサーチ:多層パーセプトロン

ランダムサーチは、ハイパーパラメータの探索範囲を指定し、その範囲内でランダムにパラメータを選択することにより、最適なモデルのパラメータを探索する手法です。グリッドサーチに比べ、パラメータ数が多く探索空間が大きい場合でも、効率的に最適解に近づくことができます。

ここでは、ランダムサーチを用いて多層パーセプトロン(MLP)のハイパーパラメータを探索する方法について説明します。具体的には、ランダムサーチを用いて、隠れ層のユニット数や学習率などのハイパーパラメータを探索し、最適なMLPモデルを構築します。

以下は、Scikit-learnを用いたランダムサーチによるMLPのハイパーパラメータ探索の例です。

from sklearn.neural_network import MLPClassifier
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import randint, uniform
# パラメータの範囲を指定
param_dist = {
'hidden_layer_sizes': randint(10, 200),
'alpha': uniform(0.0001, 0.1),
'learning_rate_init': uniform(0.0001, 0.1),
}
# MLPモデルを定義
mlp = MLPClassifier(random_state=0)
# ランダムサーチを定義
random_search = RandomizedSearchCV(
mlp, param_distributions=param_dist, n_iter=100, cv=5, random_state=0, n_jobs=-1)
# ランダムサーチを実行
random_search.fit(X_train, y_train)
# 最適なパラメータを取得
print('Best parameters: {}'.format(random_search.best_params_))
# 最適なモデルで予測
y_pred = random_search.predict(X_test)

ここでは、Scikit-learnのMLPClassifierを使用し、隠れ層のユニット数、正則化パラメータ(alpha)、学習率(learning_rate_init)の3つのハイパーパラメータを探索します。パラメータの範囲はparam_distに指定され、それぞれrandintuniformといった関数を使用して、範囲内でランダムに探索されます。n_iterで探索回数を指定し、cvでクロスバリデーションの分割数を指定します。最適なハイパーパラメータは、random_search.best_params_で取得できます。

パイプライン:PCAとロジスティック回帰

PCA(Principal Component Analysis)とロジスティック回帰をパイプラインで結合する方法をPythonの具体例を交えて説明します。

まず、必要なライブラリをインポートします。

from sklearn.datasets import load_breast_cancer
from sklearn.decomposition import PCA
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

次に、乳がんデータセットを読み込みます。

data = load_breast_cancer()
X, y = data.data, data.target

乳がんデータセットは30の特徴量からなりますが、PCAを使用して次元削減を行います。次元削減を行う前に、データセットをトレーニングセットとテストセットに分割します。

X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=42)

パイプラインを作成します。PCAのn_componentsパラメータを2に設定し、特徴量を2つに削減し、ロジスティック回帰で分類を行います。

pipe = make_pipeline(
PCA(n_components=2),
LogisticRegression(random_state=42)
)

乳がんデータセットに対して、fitメソッドを使用してパイプラインをトレーニングします。

pipe.fit(X_train, y_train)

テストセットに対して、predictメソッドを使用して予測を行います。

y_pred = pipe.predict(X_test)

分類の精度を計算します。

accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)

このように、パイプラインを使用することで、複数のステップを一度に処理できます。これにより、コードが簡素化されます。

パイプライン:スケーリングとSVM

パイプラインを用いることで、複数の前処理ステップを連結し、最終的なモデルの構築と評価を簡単に行うことができます。例えば、データのスケーリングとSVMを一緒に行う場合、以下のようにパイプラインを構築することができます。

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
# スケーリングとSVMをパイプラインにまとめる
svm_pipeline = Pipeline([
('scaler', StandardScaler()),
('svm', SVC())
])
# ハイパーパラメータのグリッドサーチ
param_grid = {
'svm__C': [0.1, 1, 10],
'svm__kernel': ['linear', 'rbf', 'poly']
}
# グリッドサーチを行う
from sklearn.model_selection import GridSearchCV
grid_search = GridSearchCV(svm_pipeline, param_grid=param_grid, cv=5)
grid_search.fit(X, y)

この例では、StandardScalerを使ってデータのスケーリングを行い、SVCを使ってSVMを実行するパイプラインを作成し、GridSearchCVを用いてパラメータ探索を行っています。パイプライン内の各ステップは、(‘ステップ名’, ステップオブジェクト)の形式で指定されます。ここでは、ステップ名は’scaler’と’svm’になっています。また、パイプライン内のステップにアクセスするには、ステップ名に続けて’__’をつけ、パラメータ名を指定します。例えば、SVCのCパラメータにアクセスするには、’svm__C’という名前を使います。

パイプライン:前処理もグリッドサーチ

パイプラインとグリッドサーチを組み合わせて、データの前処理とハイパーパラメータチューニングを同時に行うことができます。以下は、スケーリングとSVMによるがんデータの認識を例に説明します。

まず、必要なライブラリをインポートします。

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.pipeline import Pipeline

次に、がんデータをロードし、トレーニングデータとテストデータに分割します。

data = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, random_state=0)

パイプラインを構築します。スケーリングとSVMを一緒に行うため、StandardScalerSVCをパイプラインで結合します。また、SVMのハイパーパラメータチューニングを行うために、グリッドサーチを使用します。

pipe = Pipeline([
('scaler', StandardScaler()),
('svm', SVC())
])
param_grid = {
'svm__C': [0.1, 1, 10],
'svm__gamma': [0.1, 1, 10]
}
grid = GridSearchCV(pipe, param_grid=param_grid, cv=5)

Pipelineオブジェクトには、scalersvmの2つのステップが含まれています。scalerStandardScalerオブジェクトであり、svmSVCオブジェクトです。パイプライン内のステップは、名前を付けることができます。svm__Cおよびsvm__gammaは、それぞれSVCオブジェクトのCおよびgammaハイパーパラメータの値を指定するために使用されます。param_gridは、グリッドサーチの候補値のセットを指定します。

最後に、グリッドサーチを実行します。

grid.fit(X_train, y_train)

グリッドサーチの結果は、best_params_属性を介してアクセスできます。

print("Best parameters: ", grid.best_params_)
print("Best cross-validation score: {:.2f}".format(grid.best_score_))
print("Test set score: {:.2f}".format(grid.score(X_test, y_test)))

以上で、スケーリングとSVMによるがんデータの認識をパイプラインとグリッドサーチで行う方法を説明しました。

正規化パラメータC

正規化パラメータCは、SVMで使用されるハイパーパラメータの一つで、正則化の強度を制御します。正則化は、モデルが過剰適合を起こすことを防ぐために使用される手法で、Cの値が小さいほど強い正則化がかかります。つまり、Cの値が小さいほどモデルはシンプルになりますが、逆に大きくなると複雑なモデルになります。

Pythonでの具体例を示します。scikit-learnのSVMモデルのクラスであるSVCを使用します。以下の例では、SVMのCパラメータを変化させながら、がんデータを分類するためのSVMモデルをトレーニングし、最も良いCパラメータを選択します。

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.svm import SVC
# データの読み込み
data = load_breast_cancer()
# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, random_state=0)
# ハイパーパラメータの候補を定義
param_grid = {'C': [0.001, 0.01, 0.1, 1, 10, 100, 1000]}
# グリッドサーチで最適なパラメータを探索
grid_search = GridSearchCV(SVC(kernel='linear'), param_grid, cv=5)
grid_search.fit(X_train, y_train)
# 最適なパラメータでモデルをトレーニング
best_svc = grid_search.best_estimator_
best_svc.fit(X_train, y_train)
# テストデータで評価
accuracy = best_svc.score(X_test, y_test)
print('Accuracy:', accuracy)

ここでは、0.001から1000までのCの値を持つグリッドを設定し、GridSearchCVを使用して最適なCパラメータを探索しています。最良のCパラメータでトレーニングされたモデルは、テストデータで評価され、精度が表示されます。

正規化パラメータと過学習

正規化パラメータは、SVMにおいて訓練誤差と汎化誤差のトレードオフを調整するために使用されます。正規化パラメータが大きすぎると、汎化性能が低下し、訓練セットに対して過学習する可能性があります。一方、正規化パラメータが小さすぎると、訓練誤差が大きくなり、未知のデータに対する汎化性能が低下する可能性があります。

以下はPythonでの具体例です。Breast Cancer Wisconsinデータセットを使用し、SVMの正規化パラメータCを調整して過学習を確認します。

まず、必要なライブラリをインポートし、データをロードします。

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
data = load_breast_cancer()
X = data.data
y = data.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

次に、正規化パラメータを変えながらSVMのモデルを訓練し、訓練セットとテストセットに対する精度を計算します。

import matplotlib.pyplot as plt
train_scores = []
test_scores = []
Cs = [0.001, 0.01, 0.1, 1, 10, 100, 1000]
for C in Cs:
svm = SVC(kernel='linear', C=C)
svm.fit(X_train, y_train)
train_score = accuracy_score(y_train, svm.predict(X_train))
test_score = accuracy_score(y_test, svm.predict(X_test))
train_scores.append(train_score)
test_scores.append(test_score)
plt.plot(Cs, train_scores, label='Train')
plt.plot(Cs, test_scores, label='Test')
plt.xscale('log')
plt.xlabel('C')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

上記のコードを実行すると、正規化パラメータCを変化させたときの訓練セットとテストセットに対する精度がプロットされます。

Cが小さい場合、訓練セットとテストセットの精度が低下していることがわかります。これは、モデルが訓練セットに対して過剰に適合しているため、汎化性能が低下していることを示しています。一方、Cが大きい場合、訓練セットに対する精度が向上していますが、テストセットに対する精度は一定に保たれています。この場合、過剰適合が起こっていないことを示しています。

適切なCの値を選ぶためには、交差検証を行うことが一般的です。具体的には、データセットを複数のフォールドに分割し、各フォールドをテストセットとして使用し、残りのフォールドを訓練セットとして使用して精度を評価します。これを各フォールドで交互に行い、最終的な精度を算出します。この方法により、モデルの汎化性能をより正確に評価し、最適なCの値を選択することができます。

以下は、PythonでのCの調整と交差検証の例です。

from sklearn.model_selection import GridSearchCV
from sklearn import svm, datasets
# データの読み込み
iris = datasets.load_iris()
X = iris.data
y = iris.target
# モデルの定義
svc = svm.SVC(kernel='linear')
# パラメータグリッドの定義
parameters = {'C': [0.1, 1, 10, 100]}
# グリッドサーチの定義
clf = GridSearchCV(svc, parameters, cv=5)
# モデルの学習
clf.fit(X, y)
# 最適なパラメータの表示
print(clf.best_params_)

この例では、irisデータセットを使用して、線形SVMの正規化パラメータCを調整しています。GridSearchCV関数を使用して、Cの値を0.1、1、10、100に設定し、5分割交差検証を行っています。最適なCの値は、clf.best_params_で表示されます。

※並列計算のn_jobsの指定

ランダムフォレストやSVMなどの機械学習モデルの学習には、膨大な計算量が必要な場合があります。このような場合、並列処理を利用することで、計算時間を大幅に短縮できます。

Pythonの機械学習ライブラリであるscikit-learnでは、n_jobsパラメータを使って、並列計算の数を指定することができます。n_jobsパラメータには、以下のような指定方法があります。

  • n_jobs=-1: 使用可能なすべてのCPUを利用する
  • n_jobs=1: 1つのCPUだけを利用する
  • n_jobs=2: 2つのCPUを利用する
  • n_jobs=n: nつのCPUを利用する

n_jobsの指定方法は、CPUコア数やメモリ容量に合わせて適切に設定する必要があります。また、n_jobsに大きな値を指定した場合には、CPUやメモリの使用状況によってはシステムが不安定になる場合があります。適切な値を選択するためには、実行環境に合わせたチューニングが必要です。

6.学習サンプル数が多いとき

学習サンプル数が多い場合、正規化パラメータCの値が小さいほど良い結果が得られる傾向があります。これは、サンプル数が多い場合、過学習のリスクが低くなり、Cを小さく設定しても過学習が起こりにくくなるためです。

ただし、学習サンプル数が非常に多い場合、Cの値が小さいと適切な汎化性能を得られない可能性があります。その場合は、Cの値を大きくすることで性能を改善できます。また、正規化パラメータCの値を決定するためにグリッドサーチや交差検証を行うことが推奨されます。

linear SVM(lib linear)

linear SVM (liblinear)をPythonで実装するには、scikit-learnライブラリを使用します。以下は、単純な例です。

まず、scikit-learnから必要なモジュールをインポートします。

from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.svm import LinearSVC
from sklearn.metrics import accuracy_score

次に、irisデータセットを読み込み、データとラベルに分割します。

iris = datasets.load_iris()
X = iris.data
y = iris.target

データを訓練セットとテストセットに分割します。

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

線形SVMモデルをインスタンス化し、fitメソッドを使用してモデルを訓練します。

svm = LinearSVC()
svm.fit(X_train, y_train)

最後に、predictメソッドを使用してテストデータの予測を行い、accuracy_score関数を使用して精度を計算します。

これで、linear SVM (liblinear)モデルを訓練し、テストデータで精度を評価することができます。

SVCとLinearSVCの主な違い

SVCとLinearSVCの主な違いは、最適化アルゴリズムによるものです。SVCは一般的により多くの計算リソースを必要とし、大規模なデータセットに対しては非常に時間がかかります。一方、LinearSVCは最適化アルゴリズムが線形であるため、より効率的に動作し、大規模なデータセットでも比較的高速に処理できます。

Cの値が大きいほど、モデルはトレーニングデータにより適合し、汎化能力が低下するため、過学習を引き起こす可能性があります。したがって、大規模なデータセットに対しては、Cの値を十分に調整することが重要です。

以下の例は、SVCとLinearSVCのCの値を変更した場合の、irisデータセットを用いた二値分類タスクの処理時間を比較したものです。Cの値は、10の指数関数を変化させています。

from sklearn.datasets import load_iris
from sklearn.svm import SVC, LinearSVC
from sklearn.model_selection import train_test_split
import time
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
C = [10**i for i in range(-3, 5)]
for c in C:
svc_start = time.time()
svc = SVC(kernel='linear', C=c)
svc.fit(X_train, y_train)
svc_end = time.time()
lin_svc_start = time.time()
lin_svc = LinearSVC(C=c)
lin_svc.fit(X_train, y_train)
lin_svc_end = time.time()
print(f"C = {c}")
print(f"SVC: {svc_end - svc_start}")
print(f"LinearSVC: {lin_svc_end - lin_svc_start}")

実行結果は以下のようになります。

C = 0.001
SVC: 0.00599980354309082
LinearSVC: 0.002000570297241211
C = 0.01
SVC: 0.0070002079010009766
LinearSVC: 0.002000570297241211
C = 0.1
SVC: 0.006999969482421875
LinearSVC: 0.0019996166229248047
C = 1
SVC: 0.0070002079010009766
LinearSVC: 0.0020008087158203125
C = 10
SVC: 0.009999990463256836
LinearSVC: 0.003000497817993164
C = 100
SVC: 0.02400040626525879
LinearSVC: 0.003000497817993164
C = 1

以上の結果から、LinearSVCはSVCよりも計算時間が短く、またCを大きくすると、SVCの計算時間が急激に増加することがわかります。しかし、SVCはLinearSVCよりも高い精度を出すことができるため、データセットに合わせて適切なモデルを選択する必要があります。また、計算時間が重要な場合はLinearSVCを使用することができます。

linear SVM(lib linear):primalソルバ

SVMにおいて、データの次元数が非常に高く、特徴量が多い場合、データの次元数に依存するため、計算コストが非常に高くなるという問題があります。これを解決するため、特徴量の数に依存しない形で解が求められるprimalソルバという手法が存在します。

primalソルバでは、データセットを直接扱うため、データの次元数に依存しないため、非常に高速に計算ができます。また、大量のデータに対しても適用することができます。

一方で、データの次元数が非常に高くなると、解の精度が低下する可能性があるため、実際にはデータの次元数が非常に高い場合には、primalソルバを適用する前に、次元削減などの前処理を行うことが推奨されます。

linear SVM(lib linear):primalソルバ

linear SVMでprimalソルバを使用するためには、LinearSVCdualパラメータをFalseに設定します。具体的な例を以下に示します。

from sklearn.datasets import make_classification
from sklearn.svm import LinearSVC
from sklearn.model_selection import train_test_split
import time

# ダミーデータの生成
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=0, random_state=42)

# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# LinearSVCのインスタンス化(primalソルバを使用)
clf = LinearSVC(dual=False, random_state=42)

# Cの値を変えながら学習時間を計測
for C in [0.001, 0.01, 0.1, 1, 10]:
clf.set_params(C=C)
start = time.time()
clf.fit(X_train, y_train)
end = time.time()
print("C = {}: {:.9f}".format(C, end - start))

この例では、LinearSVCdualパラメータをFalseに設定し、Cの値を変えながら学習時間を計測しています。Cの値が大きくなるにつれて、学習時間が増加することがわかります。

linear SVMとprimalソルバの違い

linear SVMのliblinearパッケージでCを大きくすると、DualソルバとPrimalソルバの両方で処理時間が長くなる傾向があります。ここではPrimalソルバに焦点を当て、具体例を示します。

まずは、Cを小さくした場合のPrimalソルバの処理時間を見てみます。

from sklearn.datasets import make_classification
from sklearn.svm import LinearSVC
import time

# ランダムに2値分類のためのサンプルデータを生成
X, y = make_classification(n_samples=1000, n_features=20, n_informative=10, n_classes=2, random_state=1)

# C=0.01でPrimalソルバを使用した場合の処理時間を計測
start = time.time()
clf = LinearSVC(C=0.01, dual=False, random_state=1)
clf.fit(X, y)
end = time.time()
print('Primal solver, C=0.01: {}'.format(end - start))

この場合、Primalソルバを使用した場合の処理時間は約0.03秒でした。次に、Cを大きくした場合のPrimalソルバの処理時間を計測してみます。

# C=10でPrimalソルバを使用した場合の処理時間を計測
start = time.time()
clf = LinearSVC(C=10, dual=False, random_state=1)
clf.fit(X, y)
end = time.time()
print('Primal solver, C=10: {}'.format(end - start))

この場合、Primalソルバを使用した場合の処理時間は約0.08秒でした。Cを大きくすると、Primalソルバでも処理時間が長くなることがわかります。ただし、Dualソルバを使用した場合と比較すると、Primalソルバの方が大幅に高速であることが多いため、大規模なデータセットや高次元のデータセットを扱う場合は、Primalソルバがより効率的な選択肢となります。

linear SVM(lib linear):グリッドサーチ

linear SVMにおいて、正則化パラメータCを適切に設定することが重要です。グリッドサーチを使用することで、最適なCの値を見つけることができます。

以下は、Pythonのscikit-learnライブラリを使用してlinear SVMのグリッドサーチを行う例です。

from sklearn import datasets
from sklearn.model_selection import GridSearchCV
from sklearn.svm import LinearSVC

# データセットの読み込み
iris = datasets.load_iris()
X = iris.data
y = iris.target

# グリッドサーチのパラメータ範囲の設定
param_grid = {'C': [0.1, 1, 10, 100]}

# LinearSVCのインスタンスを生成
svm = LinearSVC(max_iter=10000, dual=False)

# グリッドサーチの実行
grid_search = GridSearchCV(svm, param_grid, cv=5)
grid_search.fit(X, y)

# 最適なパラメータの表示
print("Best parameter: ", grid_search.best_params_)

この例では、irisデータセットを使用しています。グリッドサーチのパラメータ範囲として、正則化パラメータCの値を[0.1, 1, 10, 100]と設定しています。LinearSVCのインスタンスを生成し、グリッドサーチを実行します。最適なパラメータを表示するために、best_params_属性を使用しています。

なお、この例ではmax_iterパラメータを指定しています。これは、収束しない場合に備えて、最大イテレーション回数を設定するものです。dualパラメータも指定していますが、これはLinearSVCの実装において、特徴量数がサンプル数よりも多い場合に使用するアルゴリズムを指定するものです。dual=Falseとすることで、特徴量数が多い場合でも高速な計算ができるアルゴリズムを使用するようにしています。

グリッドサーチのかかる時間の見積の仕方

グリッドサーチを行う際にかかる時間の見積もりにはいくつかの方法がありますが、以下のようなものが挙げられます。

  • 実行時間の推定:まず、一つのモデルの実行時間を測定し、グリッドサーチで試行するすべてのモデルの実行時間をこれに基づいて推定します。ただし、すべてのモデルの実行時間が同じであるとは限らないため、モデルごとに異なる実行時間を測定することが望ましいです。また、CPUのスペックやデータセットの大きさによっても実行時間が異なるため、これらの要因を考慮する必要があります。
  • サンプリング:グリッドサーチで試行するパラメータの候補をランダムに抽出して、そのサンプルで実行時間を測定します。その実行時間をもとに、グリッドサーチ全体の実行時間を推定します。ただし、サンプリング数が少ない場合、推定値が不正確になる可能性があるため、十分なサンプリング数を確保する必要があります。
  • ベンチマーク結果の利用:同じ問題に対して以前にグリッドサーチを実行した結果をもとに、実行時間を推定する方法です。ただし、以前のベンチマークとは条件が異なるため、そのまま利用すると誤差が生じる可能性があります。また、以前の実行結果は新しいデータセットには適用できない場合もあるため、注意が必要です。

これらの方法を組み合わせることで、より正確な実行時間の見積もりを行うことができます。ただし、グリッドサーチは非常に計算量が多いため、実行時間についての適切な見積もりは非常に重要です。

確率勾配法(SGD)

確率勾配法(Stochastic Gradient Descent: SGD)を使った分類器のPythonの具体例を以下に示します。

まず、必要なライブラリをインポートします。

from sklearn.linear_model import SGDClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

次に、サンプルデータを生成し、データを訓練用とテスト用に分割します。

X, y = make_classification(n_samples=1000, n_features=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

SGDClassifierを使って、モデルを訓練します。

sgd = SGDClassifier(loss='log', random_state=42)
sgd.fit(X_train, y_train)

ここでは、損失関数(loss)には’log’(対数尤度)を指定し、乱数シード(random_state)には42を指定しました。その後、fit()メソッドを呼び出して、訓練データでモデルを訓練します。

最後に、テストデータを使ってモデルの性能を評価します。

y_pred = sgd.predict(X_test)
acc = accuracy_score(y_test, y_pred)
print("Accuracy:", acc)

以上のコードでSGDを使った分類器の訓練と評価ができます。

確率勾配法(Stochastic Gradient Descent, SGD)の優れている点

確率勾配法(Stochastic Gradient Descent, SGD)の優れている点は、以下の通りです。

  • 大規模なデータセットに対応できる: データセットが大きい場合でも、ランダムサンプリングによって少数のデータを用いて重みを更新することで、処理時間を短縮することができます。
  • オンライン学習に適している: 新しいデータが追加された場合や、データがストリーミング形式で入力される場合でも、即座にモデルの更新を行うことができます。
  • ハイパーパラメータの最適化が容易: パラメータの更新が一回ごとに行われるため、ハイパーパラメータの最適化を簡単に行うことができます。
  • スパースなデータにも対応可能: データの次元数が大きく、かつスパースな場合でも、SGDによって高速に学習することができます。
  • ディープラーニングにも応用できる: ニューラルネットワークの学習にも適用され、特に深層学習では非常に大きなデータセットが扱われることから、SGDの有用性が高まっています。

以上のように、SGDは大規模なデータセットに対応できるだけでなく、オンライン学習やハイパーパラメータの最適化、スパースなデータへの対応など、様々な点で優れたアルゴリズムです。

確率勾配法(SGD)の数式の説明

確率勾配法(Stochastic Gradient Descent: SGD)は、最適化アルゴリズムの1つであり、機械学習においてよく使われます。SGDは、目的関数を最小化することによって、モデルパラメータを最適化します。

SGDの目的は、与えられた損失関数を最小化することです。損失関数は、通常は訓練セット内のデータポイントとモデル予測の差を計算する関数です。例えば、二乗誤差損失関数を用いた回帰問題の場合、損失関数は以下のように定義されます。


ここで、$y$は実際のターゲット値、$\hat{y}$はモデルの予測値です。

SGDでは、損失関数の勾配(グラデーション)を計算し、その勾配に従ってモデルパラメータを更新します。この際、勾配を計算する際に使用するサンプル数は1つ(あるいは、少数のサンプル)であり、そのため確率的勾配降下法と呼ばれます。

以下がSGDの基本的なアルゴリズムです。

  • 初期値を設定する
  • データセットからランダムに1つまたは少数のサンプルを選択する
  • 選択されたサンプルに対する損失関数の勾配を計算する
  • モデルパラメータを勾配に従って更新する
  • 繰り返す

SGDの更新式は以下のようになります。

ここで、$\theta$はモデルパラメータ、$\eta$は学習率、$\nabla L(\theta;x_i,y_i)$は損失関数$L$の勾配($x_i$は入力データ、$y_i$はターゲット値)です。

LinearSVCより勾配法が早い理由

SGDは、大規模なデータセットに適用することができ、計算時間が比較的短くて済むため、よく使われます。しかし、SGDは最適化に時間がかかることがあり、局所最適解に陥ることがあるという欠点もあります。

LinearSVCは、デフォルトでは内部で非常に効率的な最適化アルゴリズムであるLIBLINEARを使用していますが、データセットが大きくなると処理に時間がかかる場合があります。一方、確率的勾配降下法(SGD)は、一度に1つのサンプルまたは少数のサンプルを使用して勾配を計算するため、大規模なデータセットでも効率的に動作することができます。さらに、SGDは、学習率を調整することで、学習過程の収束を改善することができます。

そのため、LinearSVCよりも大規模なデータセットや高次元のデータに適しています。ただし、SGDは最適な学習率を選択する必要があるため、ハイパーパラメータの調整が必要になる場合があります。

確率勾配法(SGD):グリッドサーチ

確率勾配法(SGD)におけるグリッドサーチの具体例を以下に示します。

まず、scikit-learnからデータセットを読み込みます。

from sklearn.datasets import load_digits
digits = load_digits()
X, y = digits.data, digits.target

次に、SGDClassifierとGridSearchCVをインポートします。

from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import GridSearchCV

SGDClassifierで使用するパラメータを指定します。ここでは、損失関数にはロジスティック回帰を、正則化にはL2を使用し、学習率には定数を設定します。

param_grid = {
'alpha': [0.0001, 0.001, 0.01],
'penalty': ['l2'],
'loss': ['log'],
'learning_rate': ['constant'],
}

GridSearchCVを用いて、指定したパラメータの組み合わせでモデルを評価します。

clf = SGDClassifier(random_state=42)
grid_search = GridSearchCV(clf, param_grid=param_grid, cv=3, n_jobs=-1)
grid_search.fit(X, y)

最適なパラメータとそのときのスコアを出力します。

print(grid_search.best_params_)
print(grid_search.best_score_)

以上で、確率勾配法におけるグリッドサーチの具体例を示しました。

確率勾配法(SGD):スモールデータの認識

確率的勾配降下法(Stochastic Gradient Descent; SGD)は、大規模データの場合にLinearSVCよりも優れた速度で学習が可能ですが、ランダム性によって結果が変動するため、小規模データの場合にはLinearSVCの方が安定した結果を出しやすいとされています。しかし、ランダム性がない場合にはSGDも安定して良い結果を出すことができます。ここでは、ランダム性がない場合の小規模データでのSGDの例を示します。

例えば、scikit-learnのmake_classification関数を使用して、2クラス分類の小規模な合成データセットを作成します。

from sklearn.datasets import make_classification
X, y = make_classification(n_samples=100, n_features=10, n_informative=5, n_redundant=0, random_state=42)

次に、データをスケーリングし、train_test_split関数で訓練データとテストデータに分割します。

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)


from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import GridSearchCV

clf = SGDClassifier(random_state=42)

param_grid = {'penalty': ['l1', 'l2'], 'learning_rate': ['constant', 'invscaling', 'adaptive']}

grid = GridSearchCV(clf, param_grid, cv=5, n_jobs=-1)
grid.fit(X_train, y_train)

print("Best parameters: ", grid.best_params_)
print("Training accuracy: ", grid.best_score_)
print("Test accuracy: ", grid.score(X_test, y_test))

この例では、ランダム性がない場合にも、SGDClassifierを使用したグリッドサーチによって、最適なパラメータと精度を見つけることができました。ただし、データが小規模でランダム性がない場合は、LinearSVCの方が高速かつ安定した結果を出すことが期待できます。


というわけで、今回は以上です。大変大変お疲れ様でした。
引き続きで、徐々に発信していきます。

コメントや感想を受け付けています。ちょっとした感想でもいいので嬉しいです。

それでは、以上です。

最新情報をチェックしよう!