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)
欠損値を持ってるデータに対処する
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. ]]
データを正規化する
いつも正規化は自分で書いていた(と言っても 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...]])
データをスケーリングする
日本語がおかしい気もする.スケーリングって日本語ではなんて言うんだろう.
平均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が生えている).
モデルの検証
ラベルの比率を良い感じにしつつ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]
前処理 -> 学習 をシームレスに
前処理が必要なデータを扱うとき,前処理や素性の抽出を 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 が使える.
レールには積極的に乗って行きたい.