分類問題にも、多項式回帰で勉強した特徴量の増加をしてみたらどうなるか、やってみました。
確かに、境界線が二次元関数のように曲がると、良さそうだね。
回帰問題で、多項式回帰という物を学びました。これは特徴量の二乗、三乗を考えて、特徴量を増やして回帰線を増やすというもので、これを線形モデルの分類に当てはめるとどうなるのか、と思いました。
こんな人の役にたつかも
・機械学習プログラミングを勉強している人
・scikit-learnでサポートベクターマシンの分類をプログラミングする人
・scikit-learnでロジスティック回帰の分類をプログラミングする人
線形モデルのサポートベクターマシン
プログラムの準備
まずは、共通して利用するためのimportなどです。scikit-learnの2クラス分類問題用データの乳がんデータを読み込んで利用します。
#ホールドアウトのimport
from sklearn.model_selection import train_test_split,cross_val_score
#乳がんデータ
from sklearn.datasets import load_breast_cancer
#サポートベクターマシン
from sklearn import svm
import numpy as np
panda_box = load_breast_cancer()
X = panda_box.data
y = panda_box.target
#訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.25, stratify=y)
#データ数の確認
print(X_train.shape)
print(X_test.shape)
データ数は、それぞれ訓練「426個」テスト「143個」となります。特徴量は30次元あります。
(426, 30)
(143, 30)
久しぶりの乳がんデータ。
Linearカーネル
サポートベクターマシンは、分類でもよく使われるアルゴリズムです。カーネルというものを切り替えることで、境界線を直線にしたり、曲線にしたりできます。カーネルの違いによる分類線の違いについてはこちらの記事もご参考ください。
「cls = svm.SVC(kernel=’linear’)」のように、サポートベクターマシンのkernelを「linear」と指定することで、線形モデルのサポートベクターマシンを作成します。
#linearカーネル サポートベクターマシン
cls = svm.SVC(kernel='linear')
#訓練~テスト
cls.fit(X_train,y_train)
print("訓練データ")
print("{:.4f}".format(cls.score(X_train, y_train)))
print("テストデータ")
print("{:.4f}".format(cls.score(X_test, y_test)))
訓練データ
0.9765
テストデータ
0.9371
いい感じの精度出てます。
特徴量をPolynomialFeaturesで増やします
回帰の時と同じように、PolynomialFeaturesで変換したいデータを入れるだけでべき乗データが生成されるような関数を作成しておきます。
PolynomialFeaturesについては、こちらの記事もご参考ください。
#PolynomialFeaturesで特徴量を増やす関数
from sklearn.preprocessing import PolynomialFeatures
def Poly(deg, data):
PF = PolynomialFeatures(degree = deg, include_bias=False)
PF.fit(data)
trans_data = PF.transform(data)
return trans_data
「X_train」と「X_test」データを変換します。今回は、degを「2」としています。後に記載するようなデータの変換が行われます。
#データの変換
X_train_poly = Poly(2, X_train)
X_test_poly = Poly(2, X_test)
print("多次元化した時の特徴量数")
X_train_poly.shape[1]
多次元化した時の特徴量数
(426, 495)
(143, 495)
495次元の特徴量になりました。もとの30次元に加えて、次のような特徴量が追加されました。degを2としたので、それぞれの特徴量を二乗したものと、それぞれの特徴量と他の特徴量を2個まで組み合わせ、かけたものが追加されました。
例えばX0の特徴量は次のようになります。
‘x0^2’, ‘x0 x1’, ‘x0 x2’, ‘x0 x3’, ‘x0 x4’, ‘x0 x5’, ‘x0 x6’, ‘x0 x7’, ‘x0 x8’, ‘x0 x9’, ‘x0 x10’, ‘x0 x11’, ‘x0 x12’, ‘x0 x13’・・・
「特徴量1の二乗」、「特徴量1と特徴量2のかけたもの」・・・というような特徴量が追加されています。
この495次元の特徴量のデータを、Linearカーネルのサポートベクターマシンに学習させてみます。
ちょっとデータが大きいかな、訓練に時間がかかるよ。
#linearカーネル サポートベクターマシン
cls_poly = svm.SVC(kernel='linear')
cls_poly.fit(X_train_poly,y_train)
print("訓練データ")
print("{:.4f}".format(cls_poly.score(X_train_poly, y_train)))
print("テストデータ")
print("{:.4f}".format(cls_poly.score(X_test_poly, y_test)))
google colaboでは、この実行に10秒〜20秒程度かかっているような感じです。
訓練データ
0.9765
テストデータ
0.9441
まとめ:特徴量増加はよかった?
今回の乳がんデータのLinearカーネルへのサポートベクターマシンには、このPolynomialFeaturesで特徴量を増やした方が、テストデータへの正答率が上昇しています。
訓練データは特徴量を増やす前から変化がないということは、特徴量を増やすことによる過学習はおきていないような感じがします。
PolynomialFeaturesの導入はある意味の成功と言えると思います。ただ、一つネックなのは、学習時間が大幅に上昇してしまったことです。実用では、出来るだけシンプルな方が良いと思いますので、もっと違うモデルを適用させて精度が出るのであればそのほうが良いと考えました。
特徴量選択で特徴量を絞ったことはあったけど、増やしたことはなかったから、初めての試み。