Pythonマシン学習のLogistic回帰


ビッグデータ時代、データは巨大な金鉱のように、私たちが発掘するのを待っています.機械学習とデータマイニングに関する技術は、間違いなくあなたが鉱山を掘る宝の必須の利器です.仕事をして善いことをしようとすると,必ず先にその器を利する.この分野に初めて関わった多くの人が、最初に困惑した問題の一つは、データマイニングと機械学習のためにどの「ツール」を選ぶべきかということです.私のツールは主に「言語、システム、プラットフォーム」を指しています.機械学習にとって、言語とプラットフォームは核心的な問題ではありませんが、あなたがよく知っている言語と環境を選ぶことで、確かに仕事を半分にすることができます.
Matlab、R、Wekaなど、データ・マイニングや機械学習の実践に使用できるようになりました.中でもMatlabはよく知られているビジネスソフトウェアであり、RもWekaも無料ソフトウェアである.Rは統計とデータ分析に応用される屈指のコンピュータ言語とプラットフォームであり、数学や統計学に関する専門的な背景を持っている人であれば、Rを使ってデータマイニングを行うのはかなり良い選択です.R言語によるデータマイニングについては、以下のように説明しています.
  • Rではサポートベクトルマシン(SVM)を使用してデータマイニング
  • を行う.
  • 機械学習におけるEMアルゴリズムの詳細およびR言語例
  • Wekaのフルネームはワイカトインテリジェント分析環境(Waikato Environment for Knowledge Analysis)で、Java環境下でオープンソースの機械学習(machine learning)およびデータマイニング(data mining)ソフトウェアに基づいて無料で非商業化されている.2005年8月、第11回ACM SIGKDD国際会議で、ワイカト大学のWekaグループがデータマイニングと知識探求分野の最高サービス賞を受賞し、Wekaシステムは広く認められ、データマイニングと機械学習の歴史上のマイルストーンと呼ばれ、現在最も完備しているデータマイニングツールの一つである.もしあなたが忠実なJava擁護者であれば、Wekaを使用してデータマイニングを行うのは賢明です.
    RとWeka(またはJava)にあまり詳しくない場合は、今日はマシン学習とデータマイニングを行う別の利器であるPythonをお勧めします.Pythonは現在非常に流行しているコンピュータプログラミング言語であり、C、C++に比べてPythonの敷居は極めて低く、簡単にマスターすることができる.More importantly,Pythonは数え切れないほど多く、機能的な拡張を実現するためにかなり完備したパッケージ、ツールボックスに使用されています.この点はR言語とよく似ています(Rの拡張パッケージも想像以上に多くなります).
    Pythonでの機械学習に必要なパッケージは主にScikit-Liarnです.Scikit-Liarnの公式サイトはhttp://scikit-learn.org/stable/、上に関連するScikit-Liarnのリソース、モジュールダウンロード、ドキュメント、ルーチンなどを見つけることができます.Scikit-learnの基本機能は主に6つの部分に分けられ,分類,回帰,クラスタリング,データ降次元,モデル選択,データ前処理である.
    一例として、今日はPython(バージョン3.5.1)においてScikit-Liarnが提供する関数に基づいてLogistic Regressionを実装することを実証する.名前から見ると、Logistic回帰は回帰方法に属するべきである(実際には回帰分析にも使用できる)が、実際には「分類器」(Classifier)として使用されることが多い.また,機械学習では分類技術が回帰技術よりも確かに大きな陣営である.
    Scikit-Liarnのリソースには、次のリンクを持つLogistic Regressionを使用したデータ分類の例が用意されています.
    http://scikit-learn.org/stable/auto_examples/linear_model/plot_iris_logistic.html
    しかし、このプログラムの多くの内容はmatplotlibを利用して絵を描くことを示しています.これは私が今日話したい内容ではないかもしれません.次の例では、Scikit-Liarnにのみ属する関数を使用してタスクを完了することをさらに多くします.
    次の例のデータは1936年に統計学分野の一代の宗師フェヒルが発表した重要な論文に由来している.その時、彼は3種類のアヤメ(setosa、versicolor、virginicaとそれぞれマークされている)の花萼と花弁のデータを収集した.萼の長さと幅、花弁の長さと幅が含まれています.この4つの特徴(うち2つ)に基づいてLogistic Regressionモデルを構築し,3種類のアヤメの分類判別タスクを実現する.
    まず、必要なヘッダファイルをいくつか導入し、データを読み込みます(最初の2つの特徴のみを使用することに注意してください).
    import numpy as npy
    from sklearn import linear_model, datasets
    from sklearn.cross_validation import train_test_split
    from sklearn.feature_extraction import DictVectorizer
    from sklearn.metrics import accuracy_score, classification_report
    
    iris = datasets.load_iris()
    X = iris.data[:, :2]  # we only take the first two features.
    Y = iris.target

    プレゼンテーションとして、フィーチャーとラベルを含む最初の5行のデータを抽出し、次のように出力します.前述のデータには3種類のアヤメ(setosa、versicolor、virginicaと表記されている)が含まれているため、ここのラベルは0、1、2の3つの数字で対応するアヤメ品種をそれぞれ表しており、明らかに前の5行はいずれもラベルが0のアヤメに属している.そして全部で150個のサンプルデータがあります.
    >>> for n in range(5):
    	print(X[n], Y[n])
    
    	
    [ 5.1  3.5] 0
    [ 4.9  3. ] 0
    [ 4.7  3.2] 0
    [ 4.6  3.1] 0
    [ 5.   3.6] 0
    
    >>> len(X)
    150
    

    trainを利用してtest_split関数は、元のデータセットを分類サンプリングし、そのうち20%をテストデータセットとし、そのうち80%をトレーニングデータセットとする.
    X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, random_state=42)

    その後、LogisticRegression関数を使用して分類器を訓練することができます.
    logreg = linear_model.LogisticRegression(C=1e5, , solver='lbfgs', multi_class='multinomial')
    logreg.fit(X_train, y_train)
    

    パラメータsolverとmulti_classの説明.このうちsolverのオプション値は、「newton-cg」、「lbfgs」、「liblinear」、「sag」の4つです.

  • For small datasets, ‘liblinear’ is a good choice, whereas ‘sag’ is
    faster for large ones.

  • For multiclass problems, only ‘newton-cg’ and ‘lbfgs’ handle
    multinomial loss; ‘sag’ and ‘liblinear’ are limited toone-versus-rest schemes.

  • パラメータmulti_classのオプション値は、「ovr」、「multinomial」の2つです.多分類問題は使用可能
    「ovr」は、「multinomial」も使用できます.しかし、あなたのオプションが「ovr」であれば、各ラベルに対して2分類処理を実行することに相当します.Else the loss minimised is the multinomial loss fit acrossthe entire probability distribution. オプション「multinomial」は、パラメータsolverを「lbfgs」に設定した場合にのみ適用されます.
    そして,得られた分類器を再利用してテストデータセットを予測する.
    prediction = logreg.predict(X_test)
    print("accuracy score: ")
    print(accuracy_score(y_test, prediction))
    print(classification_report(y_test, prediction))

    予測結果は以下の通りで,全体の精度は90%以上であり,分類器が実行するのはかなりよいことが分かった.
    accuracy score: 
    0.9
                 precision    recall  f1-score   support
    
              0       1.00      1.00      1.00        10
              1       0.88      0.78      0.82         9
              2       0.83      0.91      0.87        11
    
    avg / total       0.90      0.90      0.90        30

    In detail、predictも利用できますproba()関数とpredict()関数は、Logistic Regressionの分類判別結果を1つずつチェックします.次の例のコードを参照してください.
    logreg_proba = logreg.predict_proba(X_test)
    logreg_pred = logreg.predict(X_test)
    for index in range (5):
        print(logreg_proba[index])
        print("Predict label:", logreg_pred[index])
        print("Correct label:", y_test[index])
    
    

    最初の5つの試験例の分類結果のみを出力し,この5つのサンプルの予測結果のうち最初の4つが正しいことを示した.
    [  8.86511110e-26   5.64775369e-01   4.35224631e-01]
    Predict label: 1
    Correct label: 1
    [  9.99999942e-01   3.78533501e-08   2.02808786e-08]
    Predict label: 0
    Correct label: 0
    [  9.92889585e-70   8.98623548e-02   9.10137645e-01]
    Predict label: 2
    Correct label: 2
    [  4.40394856e-21   5.97659713e-01   4.02340287e-01]
    Predict label: 1
    Correct label: 1
    [  5.68223824e-43   2.90652338e-01   7.09347662e-01]
    Predict label: 2
    Correct label: 1

    もちろん,Logistic Regressionの原理はネット上で多くの資料が解釈されているため,本稿の重点は明らかにここにあるわけではない.しかし、このアルゴリズムの原理をよく知っていれば、自分でいくつかの関数を実現することもできます.以下のコードは筆者自身が実現したpredit_を示している.proba()関数とpredict()関数、興味があれば試してみてください.
    class MyLogisticRegression:
        
        def __init__(self, weights, constants, labels):
            self.weights = weights
            self.constants = constants
            self.labels = labels
    
        def predict_proba(self,X):
            proba_list = []
            len_label = len(self.labels)
            for n in X: #.toarray():
                pb = []
                count = 0
                for i in range(len_label):
                    value = npy.exp(npy.dot(n, self.weights[i]) + self.constants[i])
                    count = count + value
                    pb.append(value)
                proba_list.append([x/count for x in pb])
            return npy.asarray(proba_list)
        
        def predict(self,X):
            proba_list = self.predict_proba(X)
            predicts = []
            for n in proba_list.tolist():
                i = n.index(max(n))
                predicts.append(self.labels[i])
            return npy.asarray(predicts)

    以前の実行と似ていますが、今回は自分で書いた関数に変えます.
    # Print the result based on my functions 
    print('
    ') my_logreg = MyLogisticRegression(logreg.coef_, logreg.intercept_, logreg.classes_) my_logreg_proba = my_logreg.predict_proba(X_test) my_logreg_pred = my_logreg.predict(X_test) for index in range (5): print(my_logreg_proba[index]) print("Predict label:",logreg_pred[index]) print("Correct label:", y_test[index])

    最後に実行結果を比較してみると,我々自身が実装した関数はScikit−Liarnの関数を直接呼び出した結果と全く同じであることがわかる.
    [  8.86511110e-26   5.64775369e-01   4.35224631e-01]
    Predict label: 1
    Correct label: 1
    [  9.99999942e-01   3.78533501e-08   2.02808786e-08]
    Predict label: 0
    Correct label: 0
    [  9.92889585e-70   8.98623548e-02   9.10137645e-01]
    Predict label: 2
    Correct label: 2
    [  4.40394856e-21   5.97659713e-01   4.02340287e-01]
    Predict label: 1
    Correct label: 1
    [  5.68223824e-43   2.90652338e-01   7.09347662e-01]
    Predict label: 2
    Correct label: 1

    最後に補足する必要があるのは、私たちが自分で書いた関数にこの文が存在することです.
    for n in X: #.toarray():

    注記した内容に注意してください.この文章では、私たちが使用しているデータセットは標準データセットに属しており、Feature extractionをする必要はありません.しかし、他の場合、例えば自然言語処理を行う場合、特徴辞書を大きな疎行列に変換することがよくあります.この場合、上記の関数を記述するときは、次の文を使用して疎行列を逐行復元します.
    for n in X.toarray():

    機械学習(特にNLP)におけるFeature extractionと疎行列のいくつかの特定の応用について後述する.