Help us understand the problem. What is going on with this article?

再訪scikit-learn

More than 1 year has passed since last update.

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)を実装する

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away