イテレーターは再利用不可

イテレーターで生成されたオブジェクトを変数にセットして実行できるが、これをそのまま再度利用することはできない。

イテレーターはインスタンス生成時に__init__()メソッドにより初期化され、その後イテレーターとして使用が終わった直後の値を保持している。正確には、再利用が禁止されているのではなく初期状態から再度実行することができない、ということになる。

たとえば次の例を見ると、最初の実行が終わったのちに再度利用することは不可能ではない。ただし結果を見るとわかるように、2度目の実行の初期値が1度目の終了判定時の値4ではなく5から始まっている。

おそらくcountイテレーターの__next__()メソッドの最初で内部カウンターをインクリメントしていると考えられる。

このようにイテレーターの再利用は予想外の動作をすることがあるので控えた方がよさそうだ。

 

preprocessor – 異常値に対する頑健性

機械学習モデルにデータを適用するための前処理としていくつかのアルゴリズムによっては、異常値の影響を受けやすいことがある。

たとえば下図の左のような分布のデータがあるとする(平均が1、分散が1の正規分布に従う500個のランダムデータ)。そしてこのデータに値20の異常値が10個発生したとすると、全体の分布は右のようになる。

このデータに対して、MinMaxScalerStandardScalerRobustScalerで変換した結果を以下に示す。ただしStandardScalerRobustScalerについては、異常値は表示させず元の正規分布に係る範囲のみを表示している。

まず左側のMinMaxScalerについては、異常値を含めてレンジが0~1となるので、本体の正規分布のデータが0付近の小さな値に集中する。このため、本来学習の精度に効いてくるべき本体部分のデータの分離が十分でない可能性が出てくる。

真ん中のStandardScalerと右側のRobustScalerについては、本体部分の形は元の正規分布の形と大きく変わらず、頑健であることがわかる。

ここで異常値の個数を10個から20個に増やして、同じく3種類の変換を施してみる。

左側のMinMaxScalerについては、異常値の個数とは関係なくその値のみでレンジが決まり、元の分布が0付近に押し込められている状況は同じ。

真ん中のStandardScalerについては、10個の時に比べて少し分布の形が変わっていて、レンジが狭くなっている。

右側のRobustScalerについては、元の分布の形は大きくは変わっていない。

以上のことから、少なくとも3つの変換器について以下のような特徴があることがわかる。

  • MinMaxScalerは異常値によって本来分析したいデータのレンジが狭くなる可能性がある
  • StandardScalerは異常値の影響を受けにくいが、その大きさや頻度によって若干本体部分の分布が影響を受ける
  • RobustScalerは異常値の個数が極端に多くなければ、本来のデータの特性を頑健に保持する

なお、上記の作図のコードは以下の通り。

 

RobustScaler

概要

sklearn.preprocessingモジュールのRobustScalerは、各特徴量の中央値(medi)と第1-4分位数(q1i)、第3-4分位数(q3i)を用いて特徴量を標準化する。

(1)    \begin{equation*} {F_i}^* = \frac{F_i - med_i}{q_{3i} - q_{1i}} \end{equation*}

挙動

それぞれ異なる正規分布に従う2つの特徴量について、RobustScalerを適用したときの挙動を以下に示す。異なる大きさとレンジの特徴量が、変換後には原点を中心としてほぼ同じような広がりになっているのがわかる。

コードは以下の通りで、データに対してfit()メソッドでスケールパラメーターを決定し、transform()メソッドで変換を行うところを、これらを連続して実行するfit_transform()メソッドを使っている。

簡単なデータでRobustScalerの計算過程を確認しておく。以下の例では5個のデータにRobustScalerを適用している。これは1つの特徴量を持つ5個のデータを模していることになる。

インスタンス内に保持されたパラメーターのうち、center_は特徴量の標本平均、scale_が第3-4分位数-第1-4分位数となっていて、これらで各特徴量が標準化されているのが確認できる。

特徴

RobustScalerは異常値に対して頑健であり、StandardScalerより頑健性が高い。

 

StandardScaler

概要

sklearn.preprocessingモジュールのStandardScalerは、各特徴量の標本平均と標本分散を用いて特徴量を標準化する。

具体的には、特徴量Fiの標本平均(mi)と標本分散(vi)から以下の式により各特徴量FiFi*に変換する。

(1)    \begin{equation*} {F_i}^* = \frac{F_i -m_i}{\sqrt{v_i}} \end{equation*}

挙動

それぞれ異なる正規分布に従う2つの特徴量について、StandardScalerを適用したときの挙動を以下に示す。異なる大きさとレンジの特徴量が、変換後には原点を中心としてほぼ同じような広がりになっているのがわかる。

コードは以下の通りで、データに対してfit()メソッドでスケールパラメーターを決定し、transform()メソッドで変換を行うところを、これらを連続して実行するfit_transform()メソッドを使っている。

簡単なデータでStandardScalerの計算過程を確認しておく。以下の例では5個のデータにStandardScalerを適用している。これは1つの特徴量を持つ5個のデータを模していることになる。

インスタンス内に保持されたパラメーターのうち、mean_は特徴量の標本平均、var_は標本分散(不偏分散ではない)となっている。scale_はvar_の平方根。

各データの特徴量は次式で標準化されているのが計算で確認できる。

(2)    \begin{equation*} {F_i}^* = \frac{F_i - \rm{mean\_}}{\rm{scale\_}} = \frac{F_i - \rm{mean\_}}{\sqrt{\rm{var\_}}} \end{equation*}

特徴

StandardScalerは異常値の影響に対して比較的頑健である

 

MinMaxScaler

概要

sklearn.preprocessingモジュールのMinMaxScalerは、各特徴量が0~1の範囲に納まるように変換する。具体的には、特徴量Fiの最小値(mini)と最大値(maxi)から以下の式により各特徴量FiFi*に変換する。

(1)    \begin{equation*} {F_i}^* = \frac{F_i - min_i}{max_i - min_i} \end{equation*}

挙動

それぞれ異なる正規分布に従う2つの特徴量について、MinMaxScalerを適用したときの挙動を以下に示す。異なる大きさとレンジの特徴量が、変換後にはいずれも0~1の間に納まっているのが確認できる。

コードは以下の通りで、データに対してfit()メソッドでスケールパラメーターを決定し、transform()メソッドで変換を行うところを、これらを連続して実行するfit_transform()メソッドを使っている。

特徴

MinMaxScalerは簡明な方法だが、極端に値が離れた異常値が発生すると本来のデータがその影響を受ける場合がある。

matplot.pyplot – 格子でないグラフの組み合わせ

通常、Figure.subplots()pyplot.add_subplot()でグラフの描画領域を指定するとき、m行n列の格子状のグラフエリアが生成される

これに対して、たとえば1行目に2つのグラフエリアを表示して2行目に全幅のグラフを1つ、だとか、1列目に2列ぶち抜きのグラフエリアを表示して2列目に縦2つのグラフエリアを表示したいときがある。

このような場合の1つの方法が、Figure.add_subplotで加えたいグラフエリアの構成自体を変える方法がある。

以下の例は、1行目に2つのグラフを並べ、2行目は全幅で1つのグラフエリアを表示させる方法。

また、1列目に2行分を占有する一つのグラフエリアと、2列目に2つのグラフエリアを縦に並べる方法。

 

ndarrayの書式設定 – printoptions

概要

配列をprintで表示させようとして、書式設定でよく間違える。たとえば以下のように。

配列の各要素の書式を指定して表示させたい場合、formatメソッドではなく、Numpyのset_printoptionsを使う必要がある。

get_printoptions()

配列の書式オプションの一覧は、numpy.get_printoptions()で得られる。各オプションは辞書形式で保存されている。

set_printoptions()

これらのオプションを個別に設定するにはnumpy.set_printoptions()メソッドでキーと値を指定する。

numpy.set_printoptions([キー]=[値])

よく使いそうないくつかのオプションについてまとめる。

省略表示

thresholdedgeitems

要素数(列数・行数)がthresholdに指定した値を越えた場合に省略表示する。

edgeitemsは省略時に表示する要素数(列数・行数)を指定する。

threshold=0を指定すると、edgeitemsの値を超えると常に省略表示する(デフォルトの場合、edgeitems=3を越えると省略表示)。

2次元配列の行も同じ条件で省略表示される。

数値の書式

supress

デフォルトでは要素にオーダーが小さい数値が含まれていると浮動小数点表示となり、1つの要素でも浮動小数点表示になるとすべての要素が浮動小数点表示になる。

オプションで'supress=True'を指定すると、強制的に固定小数点で表示される。

precision

precisionで精度の桁数を指定する。固定小数点数の場合は小数点以下の桁数、浮動小数点数の場合は仮数部の桁数。

floatmode

floatmodeでキーワードを指定し、あらかじめ定められた書式を設定する。

次のような配列でキーワードごとの挙動を確認する。配列aは最大でもprecision設定より低い精度、配列bprecisionを超える精度の要素を持ち、デフォルトのprecision=8で表示が丸められている。

maxprec

デフォルトの設定。各要素がそれぞれ最大の精度で表示される。いずれの配列も、最大精度となる最後尾の要素の桁幅に統一されていて、0埋めはされない。デフォルトはこの設定なので、結果は上と同じ。

maxprec_equal

maxplecは0埋めされなかったが、maxprec_equalは最大精度の桁数に統一された上で0で埋められる(equalの意味が曖昧、maxprec_zeroとでもしてくれればよかったのに)。

fixed

全ての要素の精度がprecisionに統一され、それより低い精度の場合は0で埋められる。下の例では、2つの配列のすべての要素が小数点以下8桁に統一され、0で埋められている。

unique

precisionは無視され、各要素で必要な分だけの精度が保たれ、桁数は最大精度に統一される。配列bの最後の要素が丸められていないことに注意。

formatter

書式設定文字列とformatを渡して、任意の書式を設定する。渡し方は以下の通り。

formatter={'型名' : "{:書式}".format }

型名としては'int''float'のほか'numpystr'で文字列も指定できる。

 

scikit-learn – predict_proba

概要

decision_function()は各データが推測したクラスに属する確信度(confidence)を表すが、超平面のパラメータに依存し、そのレンジや値の大きさと確信度の関係が明確ではない。

これに対してpredict_probaは、それぞれのターゲットが予測されたクラスに属する確率を0~1の実数で表す。2クラス分類では、結果の配列の形状は(n_sumples, 2)となる。

predict_proba()の挙動

以下はmake_circles()で生成した2クラスのデータをGradient Boostingによって分類したときの確信度。各データに対応した2要素の配列の1つ目がクラス0(blue)、2つ目がクラス1(orange)に属する確率を表し、2つの和は1となる。なお16行目でsuppress=Trueとすることで、ndarrayの表示を常に固定小数点としている。

decision_function()との比較

先のコードに以下を続けて、predict_proba()による確率、予測されたクラス、decsion_function()の値と、各データの正解クラスを並べて表示する。予測されたクラスの方の確率が大きいこと、その予測結果とdecision_function()の符号が一致していることが確認できる。

このデータをクラス0(blue)に対する確率(prob0)でソートし、decision_function()との関係を見てみると、以下のことがわかる。

  • blueクラスの確率が高いとdecision_functionの確信度はマイナスで絶対値が大きくなり、orangeクラスの確率が高いと確信度はプラスで絶対値が大きくなる
  • blueクラスの確率とorangeクラスの確率が同程度の時、確信度の絶対値が同程度になり、符号が逆になる
  • 確率に対して確信度は線形ではない

クラス0(blue)に対する確率とdecision_function()の確信度の関係を図示すると以下のようになり、確率に対して確信度が必ずしも線形になっていないことがわかる。

コードはmatplotlib.pyplotをインポートした上で、以下を追加。

決定境界

以下は、predict_proba()で計算された確率を可視化したもので、decision_function()の場合に比べて、直感的にも分かりやすい分布となっている。

コンターに表す値として、30行目でpredict_proba()の結果の0列目、すなわちClass0の確率を取り出している。

3クラス以上の場合

3クラスのirisデータセットにGradientBoostingClassifierを適用し、predict_proba()の出力を見てみる。

このコードの出力結果は以下の通り。3つのクラスに対する確率が得られ、合計は1になる。こちらはdecision_function()が2クラスの時だけ配列が1次元となるのと違って、どのような場合でも行数×列数=データ数×クラス数の配列になる。

なお17行目で、argmaxを使って各データで確率が最大となるクラスを探している。

 

Axes.set_xlabel/ylabel~軸のラベル

概要

Axesに描いたグラフの軸にラベルを付けるには、set_xlabel()set_ylabel()を使う。

位置等の調整

ラベルの位置はlocパラメーターで調整する。x軸とy軸では設定値が異なる(matplotlibのバージョンが3.1.1ではエラーになるので、3.3.1にアップグレード)。

set_xlabel("labelname", loc='left'/'center'/'right')
set_ylabel("labelname", loc='bottom'/'center'/'top')

以下の例では、set_ylabel()のパラメーターにTextのプロパティーとしてrotationを指定している(そのままだと横にしたラベルがエリア外に切れてしまうので、8行目でsubplots_adjustを指定している)。

scikit-learn – decision_function

概要

decision_function()は、超平面によってクラス分類をするモデルにおける、各予測データの確信度を表す。

2クラス分類の場合は(n_samples, )の1次元配列、マルチクラスの場合は(n_samples, n_classes)の2次元配列になる。2クラス分類の場合、符号の正負がそれぞれのクラスに対応する。

decision_function()を持つモデルは、LogisticRegressionSVCGladientBoostClassifierなどで、RandomForestはこのメソッドを持っていない。

decision_function()の挙動

decision_function()の挙動をGradientBoostingClassifierで確認する。

まずmake_circles()で2クラスのデータを生成し、外側のクラス0をblue、内側のクラス1をorangeとして再定義する。

次に、データを訓練データとテストデータに分割し、訓練データによって学習する。データ分割にあたって、Xyに加えて文字列に置き換えたy_namedを分割している。学習の際にはXy_namedの訓練データとテストデータのみを用いるのでyについては特に含める必要ないが、ここではtrain_test_split()が3つ以上のデータでも分割可能なことを示している。

学習後の分類器のclasses_プロパティーを参照すると、クラスがどのように表現されるかを確認できる。上のfit()メソッドでy_train_namedを与えたのでクラスの表現が文字列になっているが、代わりにy_trainを用いると[0, 1]のように元のyに対応したクラス表現が返される。

次に、学習済みモデルにテストデータを与えて、decision_function()の結果とpredict()の結果を並べてみる。decision_function()fit()で与えたテストデータ数の1次元配列を返し、各要素の負の値に対してクラス0のblueが、正の値に対してはクラス1のorangeがpredict()で予測されていることがわかる。

decision_function()の各要素の符号に応じてpredict()と同じ結果を得たいなら、次のように処理していくとよい。

最後に、上記のデータと正解であるy_test_namedのデータを先ほどのデータフレームに追加して全体を確認する。predit()メソッドの結果とdecision_function()の符号による判定結果は等しく、y_testと異なるデータがあることがわかる。

decision_function()の意味

decusuib_function()のレベルは超平面上の高さになるが、これはデータ、モデルパラメーターにより変化し、このスケールの解釈は難しい。それはpredict_proba()で得られる予測確率とdecision_function()で計算される確信度の非線形性からも予想される。

circlesデータに対するGradientBoostingClassifierの決定境界とdecision_function()の値の分布を表示したのが以下の図。コンターが交錯していてわかりにくく、直感的にはpredict_proba()の方がわかりやすい

3クラス以上の場合

3クラスのirisデータセットにGradientBoostingClassifierを適用して、decision_function()の出力を見てみる。

このコードの出力結果は以下の通り。2クラスの場合は1次元配列だったが、3クラスになると行数×列数がデータ数×クラス数の配列になる。predict_proba()は2クラスでも2列の配列になるので、decision_function()の2クラスの場合だけ特に1次元配列になると言える。

なお、19行目で各データごとに最大の値をとる列をargmaxで探して、そのサフィックスを”decision”のクラス番号として表示している。