post Image
再訪scikit-learn

scikit-learnの便利なAPIについて,新しく知ったことをメモする.

$HOME/Desktop/memo.mdにメモを書き溜めていたが誤ってrmしてしまったのでQiitaを使ってみる.

新しく学びを得たら随時追加していく.

(間違いがあったらご指摘頂けると幸いです.どうかよろしくお願いします.)


データの前処理

ライブラリの Preprocessing モジュールには神が宿っており, import する際にはコミッターに感謝を捧げる必要がある.


素性の次元削減

k個の素性を選択する.

SelectKBestの第一引数は関数でchi2のほかにもf_classifなどが使える.

素性の次元削減には他にも RFECV などがあるけれど,どう違うのかよく分かっていないので今後調べたい.

from sklearn.feature_selection.univariate_selection import SelectKBest, chi2

fselect = SelectKBest(chi2 , k=2000)

参考: How do I properly use SelectKBest, GridSearchCV, and cross-validation in the sklearn package together?


欠損値を持ってるデータに対処する

Pandasという近代兵器はデータの前処理を飛躍的に楽にしてくれた.

Jupyter notebookと相性が良く,1行でNaNを含むデータを除去してくれる.

NaNや場合によっては0などは,欠損値と呼ばれる.

欠損値の除去は, scikit-learn でもできる.

参考記事(公式トキュメント)のサンプルを抜粋する.

imp.fit() をしたときに平均値や中央値を計算しておいて, imp.transform() したときには欠損値の値を平均値や中央値に置き換える.

import numpy as np

from sklearn.preprocessing import Imputer
imp = Imputer(missing_values='NaN', strategy='mean', axis=0)
imp.fit([[1, 2], [np.nan, 3], [7, 6]])

X = [[np.nan, 2], [6, np.nan], [7, 6]]
print(imp.transform(X))
# [[ 4. 2. ]
# [ 6. 3.666...]
# [ 7. 6. ]]

参考: scikit-learn公式ドキュメント


データを正規化する

いつも正規化は自分で書いていた(と言っても numpy のメソッドをいくつか呼ぶだけだけど)が,scikit-learnがやってくれる.

L1ノルムとL2ノルムが使える.ドキュメントのサンプルコードを抜粋する.

X = [[ 1., -1.,  2.],

[ 2., 0., 0.],
[ 0., 1., -1.]]
X_normalized = preprocessing.normalize(X, norm='l2')

print(X_normalized)
# array([[ 0.40..., -0.40..., 0.81...],
# [ 1. ..., 0. ..., 0. ...],
# [ 0. ..., 0.70..., -0.70...]])

参考: scikit-learn公式ドキュメント


データをスケーリングする

日本語がおかしい気もする.スケーリングって日本語ではなんて言うんだろう.

平均0,分散1になるようにデータを加工する.

サンプルを(ry

ドキュメントにも書いてあるが,Pipelineと組み合わせることができる.

from sklearn import preprocessing

import numpy as np
X = np.array([[ 1., -1., 2.],
[ 2., 0., 0.],
[ 0., 1., -1.]])
X_scaled = preprocessing.scale(X)

print(X_scaled)
# array([[ 0. ..., -1.22..., 1.33...],
# [ 1.22..., 0. ..., -0.26...],
# [-1.22..., 1.22..., -1.06...]])

StandardScaler とか MinMaxScaler とか色々あります.

下記のドキュメントを読んでください(fit, transformなAPIが生えている).

参考: scikit-learn公式ドキュメント


モデルの検証


ラベルの比率を良い感じにしつつKFold

KFold は split() を呼ぶとき,サンプル数次元の配列を入力すれば良いが, StratifiedKFold はラベルの配列を入力する必要がある.

それはなぜか?教師データのラベルの比率を良い感じにしてくれるからである.

from sklearn.model_selection import StratifiedKFold

X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
y = np.array([0, 0, 1, 1])
skf = StratifiedKFold(n_splits=2)
skf.get_n_splits(X, y)

print(skf)

for train_index, test_index in skf.split(X, y):
print("TRAIN:", train_index, "TEST:", test_index)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]

参考: scikit-learn 公式ドキュメント


前処理 -> 学習 をシームレスに

前処理が必要なデータを扱うとき,前処理や素性の抽出を model.fit() の中でできるとコードが綺麗になりそう.

Pipelineというシステムがこれを実現してくれる.名前のままである.


Before

from sklearn.feature_extraction.text import CountVectorizer

from sklearn.svm import LinearSVC

# build the feature matrices
ngram_counter = CountVectorizer(ngram_range=(1, 4), analyzer='char')
X_train = ngram_counter.fit_transform(data_train)
X_test = ngram_counter.transform(data_test)

# train the classifier
classifier = LinearSVC()
model = classifier.fit(X_train, y_train)

# test the classifier
y_test = model.predict(X_test)


After

from sklearn.feature_extraction.text import CountVectorizer

from sklearn.svm import LinearSVC

# build the pipeline
ppl = Pipeline([
('ngram', CountVectorizer(ngram_range=(1, 4), analyzer='char')),
('clf', LinearSVC())
])

# train the classifier
model = ppl.fit(data_train)

# test the classifier
y_test = model.predict(data_test)

コードは下記のブログ記事から引用したが,記事の下のほうにFeatureUnionというのもある.

参考: Using Pipelines and FeatureUnions in scikit-learn


評価指標


ロジスティックロス


自作学習器でもscikit-learnのエコシステムに乗りたい

scikit-learn が提供していないモデルを使う必要が出てきたら,自分で実装をしなければならない.

モデルを実装したあと,評価するために cross validation や grid search をする必要がある.

scikit-learn の model_selectionのレールに乗れたらこのへんの実装をさぼることができる.

これは,モデルの実装の際に BaseEstimator を継承することで達成できる.

下記の参考記事で示されているコードを引用する.

from sklearn.base import BaseEstimator

class MyEstimator(BaseEstimator):
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2

def fit(self, x, y):
return self

def predict(self, x):
return [1.0]*len(x)

def score(self, x, y):
return 1

def get_params(self, deep=True):
return {'param1': self.param1, 'param2': self.param2}

def set_params(self, **parameters):
for parameter, value in parameters.items():
setattr(self,parameter, value)
return self

ちなみに, ClassifierMixin , RegressorMixin を継承するとscikit-learn側で実装された model.score が使える.

レールには積極的に乗って行きたい.

参考: scikit-learn で最低限の自作推定器(Estimator)を実装する


『 Python 』Article List