scikit-learn – LogisticRegression

概要

scikit-learnLogisticRegressionモデルはLogistic回帰のモデルを提供する。利用方法の概要は以下の手順で、LinearRegressionなど他の線形モデルとほぼ同じだが、モデルインスタンス生成時に与える正則化パラメーターCRidge/Lassoalphaと逆で、正則化の効果を強くするにはCを小さくする(Cを大きくすると正則化が弱まり、訓練データに対する精度は高まるが過学習の可能性が高くなる)。

また、正則化の方法をL1正則化、L2正則化、Elastic netから選択できる。

  1. LogisticRegressのクラスをインポートする
  2. ハイパーパラメーターC、正則化方法、solver(収束計算方法)などを指定し、モデルのインスタンスを生成する
  3. fit()メソッドに訓練データを与えて学習させる

学習済みのモデルの利用方法は以下の通り。

  • score()メソッドにテストデータを与えて適合度を計算する
  • predict()メソッドに説明変数を与えてターゲットを予測
  • モデルインスタンスのプロパティーからモデルのパラメーターを利用
    • 切片はintercept_、重み係数はcoef_(末尾のアンダースコアに注意)

利用例

以下は、breast_cancerデータセットに対してLogisticRegressionを適用した例。デフォルトのsolver'lbfgs'でデフォルトの最大収束回数(100)では収束しなかったため、max_iter=3000を指定している。

利用方法

LogisticRgressionの主な利用方法はLineaRegressionとほとんど同じで、以下は特有の設定を中心にまとめる。

モデルクラスのインポート

scikit-learn.linear_modelパッケージからLogisticRegressonクラスをインポートする。

モデルのインスタンスの生成

LogisticRegressionでは、ハイパーパラメーターCによって正則化の強さを指定する。このCRidge/Lassoalphaと異なり、正則化の効果を強めるためには値を小さくする。デフォルトはC=1.0

以下、RidgeLassoに特有のパラメーターのみ説明。LinearRegressionと共通のパラメーターはLinearRegressionを参照。

penalty
'l1''l2''elasticnet', 'none'で正則化項のノルムのタイプを指定する。ソルバーの'newton-cg','sag','lbfgs'はL2正則化のみサポートし、'elasticnet''saga'のみがサポートする。デフォルトは'none'で正則化は適用されない('liblinear''none'に対応しない)。
tol
収束計算の解の精度で、デフォルトは1e-4。
C
正則化の強さの逆数。正の整数で指定し、デフォルトは1.0。
solver
'newton-cg''lbfgs''liblinear''sag''saga'のうちから選択される。デフォルトは'lbfgs'。小さなデータセットには'liblnear'が適し、大きなデータセットに対しては'sag''saga'の計算が速い。複数クラスの問題には、'newton-cg''sag''saga''lbfgs'が対応し、'liblinear'は一対他しか対応しない。その他ノルムの種類とソルバーの対応。
max_iter
収束計算の制限回数を指定する。デフォルト値は100。
random_state
データをシャッフルする際のランダム・シードで、solver='sag'の際に用いる。
l1_ratio
Elastic-Netのパラメーター。[0, 1]の値で、penalty='elasticnet'の時のみ使われる。

 モデルの学習

fit()メソッドに特徴量とターゲットの訓練データを与えてモデルに学習させる(回帰係数を決定する)。

X
特徴量の配列。2次元配列で、各列が各々の説明変数に対応し、行数はデータ数を想定している。変数が1つで1次元配列の時はreshape(-1, 1)かスライス([:, n:n+1])を使って1列の列ベクトルに変換する必要がある。
y
ターゲットの配列で、通常は1変数で1次元配列。

3つ目の引数sample_weightは省略。

適合度の計算

score()メソッドに特徴量とターゲットを与えて適合度を計算する。

その他のメソッド

  • decision_function(X)
  • densiffy()
  • predict_proba(X)
  • predict_log_proba()
  • sparsify()

 

Logistic回帰~forgeデータ~Pythonではじめる機械学習より

概要

O’REILLYの書籍”Pythonではじめる機械学習”の2.3.3.5、Logistic回帰でforgeデータの決定境界をトレースしてみたとき、収束計算のソルバーの違いや、元データと書籍のデータの違いなどから再現性に悩んだので記録しておく。

決定境界

mglearnのforgeデータセットに対してLogisticRegressionを適用してみる。

Cがかなり大きい場合、すなわち正則をほとんど行わない場合には、与えられたデータに対して可能な限り適合させようとしており、データに対する適合度は高い。Cが小さくなると正則化が効いてきて、データ全体に対して適合させようとしているように見える。

ここで上の図のC=1のケースは、書籍の図2-15右側と比べると決定境界の勾配が逆になっている。その理由は次のようであることが分かった。

  • 書籍ではLogisticRegression()の収束手法を指定せず、デフォルトのsolver='liblinear'が使用されている
  • 今回指定なしで実行したところ、以下のような警告が発生
    • FutureWarning: Default solver will be changed to ‘lbfgs’ in 0.22. Specify a solver to silence this warning.
      FutureWarning)
    • デフォルトのソルバーが(現在はliblinearだが)ver 0.22ではlbfgsになる/このwarningを黙らせるためにソルバーを指定せよ
  • そこでモデルのインスタンス生成時にLogisticRegression(solver='lbfgs')としたところ先の結果となった
  • 指定なし、あるいはsolver='liblinear'とすると書籍と同じ結果になる

liblinearによる結果が以下の通り。正則化の度合いに応じてlbfgsよりも傾きがダイナミックに変わっているように見える。

なお、これらの図の傾きについて、今度は書籍の図2-16と随分違っている。よく見てみると、同図のforgeデータは特に下側の〇印の点でオリジナルにはないデータがいくつか加わっているためと考えられる。

これらのコードは以下の通り。

3次元表示

2つのCの値について、二つの特徴量の組み合わせに対する青い点の確率分布を表示してみる(solver='lbfgs')。Cが小さいと確率分布がなだらかになる様子が見て取れるが、データに対する判別の適合度との関係はよくわからない。

 

scikit-learn – LinearRegression

概要

scikit-learnLinearRegressionは、最も単純な多重線形回帰モデルを提供する。

モデルの利用方法の概要は以下の手順。

  1. LinearRegressionのクラスをインポートする
  2. モデルのインスタンスを生成する
  3. fit()メソッドに訓練データを与えて学習させる

学習済みのモデルの利用方法は以下の通り。

  • score()メソッドにテストデータを与えて適合度を計算する
  • predict()メソッドに説明変数を与えてターゲットを予測
  • モデルインスタンスのプロパティーからモデルのパラメーターを利用
    • 切片はintercept_、重み係数はcoef_(末尾のアンダースコアに注意)

利用例

配列による場合

以下はscikit-learnのBoston hose pricesデータのうち、2つの特徴量RM(1戸あたり部屋数)とLSTAT(下位層の人口比率)を取り出して、線形回帰のモデルを適用している。

特徴量の一部をとりだすのに、ファンシー・インデックスでリストの要素に2つの変数のインデックスを指定している。また、特徴量データXとターゲットデータyをtrain_test_split()を使って訓練データとテストデータに分けている。

DataFrameによる場合

以下の例では、データセットの本体(data)をpandasのDataFrameとして構成し、2つの特徴量RMとLSTATを指定して取り出している。

利用方法

モデルクラスのインポート

scikit-learn.linear_modelパッケージからLinearRegressionクラスをインポートする。

モデルのインスタンスの生成

LinearRegressionの場合、ハイパーパラメーターの指定はない。

fit_intercept
切片を計算しない場合Falseを指定。デフォルトはTrueで切片も計算されるが、原点を通るべき場合にはFalseを指定する。
normalize
Trueを指定すると、特徴量Xが学習の前に正規化(normalize)される(平均を引いてL2ノルムで割る)。デフォルトはFalsefit_intercept=Falseにセットされた場合は無視される。説明変数を標準化(standardize)する場合はこの引数をFalseにしてsklearn.preprocessing.StandardScalerを使う。
copy_X
Trueを指定するとXはコピーされ、Falseの場合は上書きされる。デフォルトはTrue
n_jobs
計算のジョブの数を指定する。デフォルトはNoneで1に相当。n_targets > 1のときのみ適用される。

 モデルの学習

fit()メソッドに特徴量とターゲットの訓練データを与えてモデルに学習させる(回帰係数を決定する)。

X
特徴量の配列。2次元配列で、各列が各々の説明変数に対応し、行数はデータ数を想定している。変数が1つで1次元配列の時はreshape(-1, 1)かスライス([:, n:n+1])を使って1列の列ベクトルに変換する必要がある。
y
ターゲットの配列で、通常は1変数で1次元配列。

3つ目の引数sample_weightは省略。

適合度の計算

score()メソッドに特徴量とターゲットを与えて適合度を計算する。

戻り値は適合度を示す実数で、回帰計算の決定係数R2で計算される。

(1)    \begin{equation*} R^2 = 1 - \frac{RSS}{TSS} = 1 - \frac{\sum (y_i - \hat{y}_i)^2}{\sum (y_i - \overline{y})^2} \end{equation*}

モデルによる予測

predict()メソッドに特徴量を与えて、ターゲットの予測結果を得る。

ここで特徴量Xは複数のデータセットの2次元配列を想定しており、1組のデータの場合でも2次元配列とする必要がある。

また、結果は複数のデータセットに対する1次元配列で返されるため、ターゲットが1つの場合でも要素数1の1次元配列となる。

切片・係数の利用

fit()メソッドによる学習後、モデルの学習結果として切片と特徴量に対する重み係数を得ることができる。

各々モデル・インスタンスのプロパティーとして保持されており、切片はintercept_で1つの実数、重み係数はcoeff_で特徴量の数と同じ要素数の1次元配列となる(特徴量が1つの場合も要素数1の1次元配列)。

末尾のアンダースコアに注意。

実行例

 

ndarray – 行・列の抽出

例示用の配列

以下の配列を例示用に準備する。

単一の行・列の抽出

単一の行の抽出

単に1つ目のインデックスを指定すると、それに対応する行が抽出される。2つ目の引数を省略すると、全て':'を指定したことになる。

単一の列の抽出

1つ目の引数を':'とし、2つ目にインデックスを指定すると、対応する列が抽出される。ただし結果は1次元の配列となる。

これを列ベクトルとして取り出すのに2つの方法がある。

1つ目の方法はreshape(-1, 1)とする定石。2つ目の引数1は列数1を指定し、1つ目の引数を−1にすることで、列数とサイズから適切な行数が設定される。

2つ目の方法は、列数を指定するのに敢えて1列のスライスで指定する方法。後述するように、列をスライスで指定した場合は2次元の形状が保持されることを利用している。以下の例では、2列目から2列目までの「範囲」を指定している。

連続する複数の行・列の抽出

連続する複数行の抽出

1つ目の引数をスライスで指定して、連続する複数行を抽出。

連続する複数列の抽出

2つ目の引数をスライスで指定して、連続する複数列を抽出。

不連続な複数の行・列を抽出

不連続な複数の行を抽出

第1引数をリストで指定すると、その要素をインデックスとする複数の行が抽出される。このような指定方法のインデックスを、ファンシーインデックスと言う。

リストの要素は昇順である必要はなく、要素順に行が取り出される。

不連続な複数の列の抽出

1つ目の引数を':'とし、2つ目の引数をリストで指定して要素に対応する列を取り出せる。

列についても、要素の順番は任意。

 

matplotlib.patches – 図形の描画

概要

matplotlib.patchesパッケージに様々な図形クラスが準備されていて、Axesadd_patch()メソッドでそれらのオブジェクトを加えていく。

各種図形

以下の点は各図形において共通

  • ほとんどの図形は引数xyで基準点のx座標とy座標をタプルで与える
  • edgecolor/ecで外枠の色、facecolor/fcで塗りつぶし色を指定する
  • fill=True/Falseで塗りつぶしの有無を指定する
  • angleで傾きの角度を指定できる図形がある
Circle(xy[, radius=5])
中心点を指定して円を描く。
Ellipse(xy, width, height[, angle])
中心点と幅・高さを指定して楕円を描く。
Rectangle(xy, width, height[, angle])
左下の点と幅・高さを指定して楕円を描く。
CirclePolygon(x, y, rasius=5, resolution=20)
多角形を描画。辺/頂点の数をresolutionで指定する。
Polygon(xy, closed=True)
複数の点を指定して図形を描画する。xyはNx2配列(xy座標を要素とした2次元配列)。closedをFalseに指定すると図形の最初の点と最後の点を結ばない。
Arc(xy, width, height[, angle, theta1, theta2])
楕円の一部の弧を描く。扇形に中を塗りつぶすことはできない。
Wedge(center, r, theta1, theta2[, width=None])
円の一部を切出した図形を描く。widhを指定すると中心からその長さだけ除かれて描かれる。
Arrow(x, y, dx, dy[, width, ...])
矢印を描画する。
FancyArrow(x, y, dx, dy[, width, ...])
鏃を片側だけにしたり、鏃の大きさや形を設定したりできる。

 

waveデータセット – 線形回帰

O’Reillyの”Pythonではじめる機械学習”に載っている、scikit-learnの線形回帰waveデータセットへの適用の再現。

waveデータセットのサンプル数を60、train_test_split()random_satet=42として、書籍と同じグラフを得る。

また、訓練結果の係数、切片とスコアについても同じ結果を得ることができる。

 

Breast cancer データセット – Logistic回帰による学習率曲線

概要

breast-cancerデータセットにscikit-learnのLogisticRegressionクラスでLogistic回帰を適用した結果。

手法全般の適用の流れはLogistic回帰~cancer~Pythonではじめる機械学習よりを参照。

ここではハイパーパラメーターを変化させたときの学習率の違いをみている。

学習率曲線

scikit-learnのLogisticRegressionクラスで、正則化のパラメーターを変化させたときの学習率曲線。同クラスにはsolver引数で収束計算のいくつかの手法が選択できるが、収束手法の違いによって意外に学習率曲線に違いが出た。またtrain_test_split()random_stateを変えても違いがある。569のデータセットで訓練データとテストデータを分けてもいるが、その程度では結構ばらつきが出るということかもしれない。

まず、random_state=0とした場合の、4つの収束手法における学習率曲線を示す。L-BFGSは準ニュートン法の1つらしいので、Newton-CGと同じ傾向であるのは頷ける。SAG(Stochastic Average Gradient)はまた違った計算方法のようで、他の手法と随分挙動が異なる。収束回数はmax_iter=10000で設定していて、これくらいでも計算回数オーバーの警告がいくつか出る。回数をこれより2オーダー多くしても、状況はあまり変わらない。

random_state=11としてみると、liblinearでは大きく違わないが、他の3つの手法では傾向が違っていて、特にsagを用いた場合は訓練データの学習率の方がテストデータの学習率よりも低くなっている。

 

ndarray.reshape – 配列の形状変更

基本

配列の形状変更は、reshape()メソッドで行う。reshape()メソッドは、元の配列を破壊せず新たな配列を生成する。

具体のいろいろな使い方は、ndarray.reshapeの使い方を参照

以下の例では6個の要素の1次元配列を2×3の2次元配列に変更し、それをさらに3 ×2の2次元配列に変更している。要素は常に行を上から、各行の列要素を左からネストした形で埋めていく。

暗黙指定

サイズ変更の際、ある次元の要素数を-1とすると、他の要素数に合わせて適切に設定してくれる。

以下の例では2×3×2の3次元配列をつくり、それを3×2×2に変形しているが、2次元目を-1として1次元目と3次元目から設定させている。

この方法は、たとえば行ベクトルの配列を列ベクトルに変換するときに使われる。以下の例では1次元の配列をつくり、それを列ベクトルとするのに、列数を1で固定し、行数を-1として算出させている。

1次元化するときの注意

多次元配列や列ベクトルを1次元化するとき、行数を1、列数を-1で暗黙指定すると求める1次元配列を1つだけ含む2次元の配列になる。こうなってしまのはreshape()の引数で1行×n列の2次元で指定したため。

そこで、size属性で1つの整数だけを指定すると、1次元でその要素数の配列になってくれる。

さらには、引数を-1のみで指定すると、配列のサイズを適当に持ってきて適用してくれる。

これは列ベクトルを行ベクトル化するときのほか、pyplotで複数のAxesインスタンスを行×列の形で受け取った時に、全てのインスタンスに同じ設定を適用したいときなどに1次元化してループで回す、といったようなことにも使える。

 

ndarray – 配列の次元・形状・サイズ

ndim属性~配列の次元

ndim属性は配列の次元を整数で返す。

1次元配列を1つだけ要素に持つ配列や列ベクトルの次元が2となっている点に注意。とにかく[]のネストの数だと考えればよい。

shape属性~配列の形状

shape属性は配列の形状を返す。

1次元1行の単純な配列のときにはshapeが(1, n)とならないのが気になるがこれは結果が常にタプルで返されるためで、1次元とわかっているときには1つの整数が返ってくると考えてよい。

ndim=2となる形状の場合にはタプルも2要素となって、shape=(行数, 列数)となる。より多次元の場合、外側の次元の要素数からの順番になる。

size属性~配列のサイズ

size属性で得られる配列のサイズは配列の要素数。

 

Python – __file__

osパッケージのgetcwd()を使ってカレントディレクトリーを取得しようとして、Atomからの直接実行などのときにうまくいかなかった。

このような場合、__file__で実行ファイルの位置を得ることができる。また、os.path.dirname(__file__)でファイル名を除いたパスを、os.path.basename(__file__)でファイル名のみを得ることができる。

実行方法によってはエラーとなる。

Atomから実行した場合

コマンドラインから実行ファイル(__file__.py)のあるディレクトリーに移動し、直接ファイル名をタイプした場合

コマンドラインから実行ファイル(__file__.py)のあるディレクトリーに移動し、”python 実行ファイル名”で実行した場合

上記と同じだが、実行ファイル名を相対パスで指定した場合