GitHubじゃ!Pythonじゃ!

GitHubからPython関係の優良リポジトリを探したかったのじゃー、でも英語は出来ないから日本語で読むのじゃー、英語社会世知辛いのじゃー

scikit-learn-contrib

sklearn-pandas – パンダとsklearnの統合

投稿日:

パンダとsklearnの統合

Sklearn-pandas

このモジュールは、 Scikit-Learnの機械学習方法とpandasスタイルのデータフレームとの間の橋渡しをします。

特に、以下を提供します。

  1. DataFrame列を変換にマップする方法。後でフィーチャに再結合されます。
  2. 古いscikit-learnバージョンがDataFrameを入力として使用するパイプラインを相互検証するための互換性シムです。 これはscikit-learn<0.16.0 (詳細は#11を参照)にのみ必要です。 これは非難され、おそらくskearn-pandas==2.0落とされskearn-pandas==2.0
  3. ヌルのような値をモードに置き換え、文字列をCategoricalImputer

インストール

pip sklearn-pandasをインストールすることができます:

# pip install sklearn-pandas

テスト

このファイルの例は基本的な健全性テストの2倍です。 それらを実行するには、 doctest使用しdoctest 。これはpythonに含まれています:

# python -m doctest README.rst

使用法

インポート

sklearn_pandasパッケージから必要なものをインポートします。 選択肢は次のとおりです。

  • DataFrameMapperDataFrameMapperデータフレーム列を異なるsklearn変換にマッピングするクラス
  • cross_val_scorecross_val_scoreと似ていsklearn.cross_validation.cross_val_scoreが、 sklearn.cross_validation.cross_val_scoreで作業しています

このデモンストレーションでは、両方をインポートします:

>>> from sklearn_pandas import DataFrameMapper, cross_val_score

これらの例では、pandas、numpy、およびsklearnも使用します。

>>> import pandas as pd
>>> import numpy as np
>>> import sklearn.preprocessing, sklearn.decomposition, \
...     sklearn.linear_model, sklearn.pipeline, sklearn.metrics
>>> from sklearn.feature_extraction.text import CountVectorizer

データを読み込む

通常はファイルからデータを読み込みますが、デモンストレーションの目的でPythonのdictからデータフレームを作成します:

>>> data = pd.DataFrame({'pet':      ['cat', 'dog', 'dog', 'fish', 'cat', 'dog', 'cat', 'fish'],
...                      'children': [4., 6, 3, 3, 2, 3, 5, 4],
...                      'salary':   [90, 24, 44, 27, 32, 59, 36, 27]})

変換マッピング

列を変換にマップする

マッパーはタプルのリストを取得します。 最初のものは、pandas DataFrameの列名、または1つまたは複数の列を含むリストです(後で複数の列を持つ例があります)。 2番目のオブジェクトは、その列に適用される変換を実行するオブジェクトです。 3番目はオプションで、該当する場合は変換オプションを含む辞書です(後述の「変換された機能のカスタム列名」を参照)。

例を見てみましょう:

>>> mapper = DataFrameMapper([
...     ('pet', sklearn.preprocessing.LabelBinarizer()),
...     (['children'], sklearn.preprocessing.StandardScaler())
... ])

'column' (単純な文字列として)と['column'] (1つの要素を持つリストとして)の列セレクタの指定の違いは、トランスフォーマに渡される配列の形です。 最初のケースでは、1次元配列が渡され、2番目のケースでは、1つの列、つまり列ベクトルを持つ2次元配列になります。

この振る舞いは、pandasの__getitem__フレーム__getitem__ indexingと同じパターンを模倣しています:

>>> data['children'].shape
(8,)
>>> data[['children']].shape
(8, 1)

OneHotEncoderImputerようなOneHotEncoderかのImputerでは、形状[n_samples, n_features] 2次元入力が必要な場合がありますが、一部のトランスは1次元の入力(ラベル指向の入力)を期待していることに注意してください。

変換をテストする

fit_transformショートカットを使用すると、モデルに合わせることができ、変換されたデータがどのように見えるかを見ることができます。 この例と他の例では、異なるハードウェアでの丸め誤差を考慮に入れて、出力をnp.round 2桁に丸めます。

>>> np.round(mapper.fit_transform(data.copy()), 2)
array([[ 1.  ,  0.  ,  0.  ,  0.21],
       [ 0.  ,  1.  ,  0.  ,  1.88],
       [ 0.  ,  1.  ,  0.  , -0.63],
       [ 0.  ,  0.  ,  1.  , -0.63],
       [ 1.  ,  0.  ,  0.  , -1.46],
       [ 0.  ,  1.  ,  0.  , -0.63],
       [ 1.  ,  0.  ,  0.  ,  1.04],
       [ 0.  ,  0.  ,  1.  ,  0.21]])

最初の3つの列はLabelBinarizer (それぞれcatdog 、およびfish対応)の出力であり、4番目の列は子の数の標準化された値です。 一般に、列は、 DataFrameMapper構築時に指定された順序に従って並べられます。

変換が訓練されたので、新しいデータで動作することを確認します。

>>> sample = pd.DataFrame({'pet': ['cat'], 'children': [5.]})
>>> np.round(mapper.transform(sample), 2)
array([[ 1.  ,  0.  ,  0.  ,  1.04]])

出力フィーチャー名

場合によっては、一部のモデルのフィーチャのインポートを調べるときと同じように、元のフィーチャをデータフレームマッパによって生成されたフィーチャに関連付けることができるようにしたいと考えています。 transformed_names_後に自動的に生成されたマッパーのtransformed_names_属性を調べることで、これを行うことができます。

>>> mapper.transformed_names_
['pet_cat', 'pet_dog', 'pet_fish', 'children']

変換されたフィーチャのカスタム列名

変換されたフィーチャのカスタム名を、フィーチャ定義の第3引数として指定することで、自動的に生成されたフィーチャの代わりに使用することができます。

>>> mapper_alias = DataFrameMapper([
...     (['children'], sklearn.preprocessing.StandardScaler(),
...      {'alias': 'children_scaled'})
... ])
>>> _ = mapper_alias.fit_transform(data.copy())
>>> mapper_alias.transformed_names_
['children_scaled']

シリーズ/データフレームをトランスフォーマに渡す

デフォルトでは、変圧器は入力として選択された列の数の少ない配列を渡されます。 これは、 sklearnトランスフォーマーが、基本的なインデックスインターフェイスが似ているにもかかわらず、パンダのデータフレームではなく、細かい配列で動作するように歴史的に設計されているためsklearn

ただし、データフレーム/シリーズをトランスフォーマに渡して、 input_df=Trueしてinput_df=Trueフレームマッパーを初期化するカスタムケースを処理することができinput_df=True

>>> from sklearn.base import TransformerMixin
>>> class DateEncoder(TransformerMixin):
...    def fit(self, X, y=None):
...        return self
...
...    def transform(self, X):
...        dt = X.dt
...        return pd.concat([dt.year, dt.month, dt.day], axis=1)
>>> dates_df = pd.DataFrame(
...     {'dates': pd.date_range('2015-10-30', '2015-11-02')})
>>> mapper_dates = DataFrameMapper([
...     ('dates', DateEncoder())
... ], input_df=True)
>>> mapper_dates.fit_transform(dates_df)
array([[2015,   10,   30],
       [2015,   10,   31],
       [2015,   11,    1],
       [2015,   11,    2]])

mapper全体ではなく、列のグループごとにこのオプションを指定することもできます。

>>> mapper_dates = DataFrameMapper([
...     ('dates', DateEncoder(), {'input_df': True})
... ])
>>> mapper_dates.fit_transform(dates_df)
array([[2015,   10,   30],
       [2015,   10,   31],
       [2015,   11,    1],
       [2015,   11,    2]])

データフレームの出力

デフォルトでは、データフレームマッパーの出力は数値配列です。 これは、ほとんどのsklearnの見積もりが数字の配列を入力として期待するためです。 ただし、マッパーの出力をdf_outにするには、マッパーを作成するときにパラメータdf_outを使用します。

>>> mapper_df = DataFrameMapper([
...     ('pet', sklearn.preprocessing.LabelBinarizer()),
...     (['children'], sklearn.preprocessing.StandardScaler())
... ], df_out=True)
>>> np.round(mapper_df.fit_transform(data.copy()), 2)
   pet_cat  pet_dog  pet_fish  children
0        1        0         0      0.21
1        0        1         0      1.88
2        0        1         0     -0.63
3        0        0         1     -0.63
4        1        0         0     -1.46
5        0        1         0     -0.63
6        1        0         0      1.04
7        0        0         1      0.21

列の名前はtransformed_names_属性に存在するものと同じです。

これは、マッパーのdefault=Trueまたはsparse=True引数と一緒には機能しません。

複数の列を変換する

変換には複数の入力列が必要な場合があります。 このような場合、列名はリストで指定できます。

>>> mapper2 = DataFrameMapper([
...     (['children', 'salary'], sklearn.decomposition.PCA(1))
... ])

今度はfit_transformを実行すると、 childrenおよびsalaryカラムでPCAが実行され、最初の主成分が返されます。

>>> np.round(mapper2.fit_transform(data.copy()), 1)
array([[ 47.6],
       [-18.4],
       [  1.6],
       [-15.4],
       [-10.4],
       [ 16.6],
       [ -6.4],
       [-15.4]])

同じ列の複数のトランス

複数の変圧器を同じ列に適用して、それらをリストで指定することができます。

>>> mapper3 = DataFrameMapper([
...     (['age'], [sklearn.preprocessing.Imputer(),
...                sklearn.preprocessing.StandardScaler()])])
>>> data_3 = pd.DataFrame({'age': [1, np.nan, 3]})
>>> mapper3.fit_transform(data_3)
array([[-1.22474487],
       [ 0.        ],
       [ 1.22474487]])

変換を必要としない列

DataFrameMapperに列挙されている列のみが保持されます。 列を保持し、変換を適用しない場合は、Noneを変圧器として使用します。

>>> mapper3 = DataFrameMapper([
...     ('pet', sklearn.preprocessing.LabelBinarizer()),
...     ('children', None)
... ])
>>> np.round(mapper3.fit_transform(data.copy()))
array([[ 1.,  0.,  0.,  4.],
       [ 0.,  1.,  0.,  6.],
       [ 0.,  1.,  0.,  3.],
       [ 0.,  0.,  1.,  3.],
       [ 1.,  0.,  0.,  2.],
       [ 0.,  1.,  0.,  3.],
       [ 1.,  0.,  0.,  5.],
       [ 0.,  0.,  1.,  4.]])

デフォルトのトランスを適用する

明示的に選択されていない列には、デフォルトのトランスフォーマーをマッパーのdefault引数として渡すことができます。

>>> mapper4 = DataFrameMapper([
...     ('pet', sklearn.preprocessing.LabelBinarizer()),
...     ('children', None)
... ], default=sklearn.preprocessing.StandardScaler())
>>> np.round(mapper4.fit_transform(data.copy()), 1)
array([[ 1. ,  0. ,  0. ,  4. ,  2.3],
       [ 0. ,  1. ,  0. ,  6. , -0.9],
       [ 0. ,  1. ,  0. ,  3. ,  0.1],
       [ 0. ,  0. ,  1. ,  3. , -0.7],
       [ 1. ,  0. ,  0. ,  2. , -0.5],
       [ 0. ,  1. ,  0. ,  3. ,  0.8],
       [ 1. ,  0. ,  0. ,  5. , -0.3],
       [ 0. ,  0. ,  1. ,  4. , -0.7]])

default=False (デフォルト)を使用すると、選択されていない列が削除されます。 default=Noneを使用すると、選択されていない列はそのまま渡されます。

複数の列の同じトランスフォーマー

場合によっては、複数のデータフレーム列に同じ変換を適用する必要があります。 このプロセスを単純化するために、パッケージは列と機能トランスフォーマ(またはクラスのリスト)のリストを受け取り、 DataFrameMapper許容するフィーチャ定義を生成するgen_features関数を提供します。

たとえば、 ‘col1’、 ‘col2’、および ‘col3’という3つのカテゴリの列を持つデータセットを考えてみましょう。それぞれを2進化するには、列名とLabelBinarizerトランスクラスをジェネレータに渡して、 DataFrameMapper

>>> from sklearn_pandas import gen_features
>>> feature_def = gen_features(
...     columns=['col1', 'col2', 'col3'],
...     classes=[sklearn.preprocessing.LabelEncoder]
... )
>>> feature_def
[('col1', [LabelEncoder()]), ('col2', [LabelEncoder()]), ('col3', [LabelEncoder()])]
>>> mapper5 = DataFrameMapper(feature_def)
>>> data5 = pd.DataFrame({
...     'col1': ['yes', 'no', 'yes'],
...     'col2': [True, False, False],
...     'col3': ['one', 'two', 'three']
... })
>>> mapper5.fit_transform(data5)
array([[1, 1, 0],
       [0, 0, 2],
       [1, 0, 1]])

変圧器パラメータのいくつかを無効にする必要がある場合は、 ‘class’キーと変圧器パラメータを含むdictを提供する必要があります。 たとえば、欠損値を持つデータセットを考えてみましょう。 次に、次のコードを使用して、デフォルトの代入戦略を上書きすることができます。

>>> feature_def = gen_features(
...     columns=[['col1'], ['col2'], ['col3']],
...     classes=[{'class': sklearn.preprocessing.Imputer, 'strategy': 'most_frequent'}]
... )
>>> mapper6 = DataFrameMapper(feature_def)
>>> data6 = pd.DataFrame({
...     'col1': [None, 1, 1, 2, 3],
...     'col2': [True, False, None, None, True],
...     'col3': [0, 0, 0, None, None]
... })
>>> mapper6.fit_transform(data6)
array([[ 1.,  1.,  0.],
       [ 1.,  0.,  0.],
       [ 1.,  1.,  0.],
       [ 2.,  1.,  0.],
       [ 3.,  1.,  0.]])

フィーチャ選択とその他の教師付き変換

DataFrameMapperは、XとYの両方の引数を必要とするトランスフォーマーをサポートしています。 これの例は機能の選択です。 「ペット」の列をターゲットとして、最もよく予測する列を選択します。

>>> from sklearn.feature_selection import SelectKBest, chi2
>>> mapper_fs = DataFrameMapper([(['children','salary'], SelectKBest(chi2, k=1))])
>>> mapper_fs.fit_transform(data[['children','salary']], data['pet'])
array([[ 90.],
       [ 24.],
       [ 44.],
       [ 27.],
       [ 32.],
       [ 59.],
       [ 36.],
       [ 27.]])

スパースな機能の操作

DataFrameMapperは、デフォルトで密なフィーチャ配列を返します。 マッパーでsparse=Trueを設定すると、抽出されたフィーチャのどれかがまばらな場合は常にスパース配列が返されます。 例:

>>> mapper5 = DataFrameMapper([
...     ('pet', CountVectorizer()),
... ], sparse=True)
>>> type(mapper5.fit_transform(data))
<class 'scipy.sparse.csr.csr_matrix'>

まばらなフィーチャの積み重ねは、それを高密度化することなく行われます。

相互検証

パンダのDataFramesの機能を組み合わせることができるようになったので、モデルが機能するかどうかを確認するために相互検証を使用することができます。 scikit-learn<0.16.0ではクロスバリデーションの機能が提供されていましたが、データ構造がDataFrameMapperDataFrameMapperでは機能しません。

この問題を回避するために、sklearn-pandasはsklearnのcross_val_score関数のラッパーを提供します。これは、パンダのDataFrameをnumpyの配列ではなく、見積もりに渡します。

>>> pipe = sklearn.pipeline.Pipeline([
...     ('featurize', mapper),
...     ('lm', sklearn.linear_model.LinearRegression())])
>>> np.round(cross_val_score(pipe, X=data.copy(), y=data.salary, scoring='r2'), 2)
array([ -1.09,  -5.3 , -15.38])

Sklearn- cross_val_score関数は、sklearnの同じ名前の関数とまったく同じインターフェイスを提供します。

CategoricalImputer

scikit-learn Imputerトランスフォーマーは現在のところ数字のみをImputerので、 sklearn-pandasは文字列をsklearn-pandas同等のヘルパートランスを提供し、ヌル値をその列の中で最も頻繁に値に置き換えます。 代わりに、使用する固定値を指定することもできます。

例:モードで入力する:

>>> from sklearn_pandas import CategoricalImputer
>>> data = np.array(['a', 'b', 'b', np.nan], dtype=object)
>>> imputer = CategoricalImputer()
>>> imputer.fit_transform(data)
array(['a', 'b', 'b', 'b'], dtype=object)

例:固定値で代入する:

>>> from sklearn_pandas import CategoricalImputer
>>> data = np.array(['a', 'b', 'b', np.nan], dtype=object)
>>> imputer = CategoricalImputer(strategy='fixed_value', replacement='a')
>>> imputer.fit_transform(data)
array(['a', 'b', 'b', 'a'], dtype=object)

変更ログ

開発

  • strategyreplacementパラメータをCategoricalImputerに追加して、モード以外の値で代入できるようにします。 (#144)
  • 変換が供給されない場合の入力データ型の保持(#138)

1.6.0(2017-10-28)

  • 適合/変換中に例外に列名を追加する(#110)。
  • gen_featureヘルパー関数を追加すると、複数の列に対して同じ変換を生成するのに役立ちます(#126)。

1.5.0(2017-06-24)

  • 列のグループごとにデータフレーム/系列を入力できるようにします。
  • もしあれば、 estimator.get_feature_names()からフィーチャー名を取得してください。
  • 変圧器のリストを適用するときに個々の変圧器からフィーチャー名を派生させようとする。
  • sklearn>=0.20 (#76)と互換性があるように、 sklearn>=0.20機能を変更しないでください。

1.4.0(2017-05-13)

  • 変換された列のカスタム名(エイリアス)の指定を許可する(#83)。
  • 出力列を生成した名前をtransformed_names_属性(#78)に取り込みます。
  • ヌルのような値を文字列のような列のモードに置き換えるCategoricalImputerを追加します。
  • input_df配列(#60)ではなく、トランスフォーマにデータフレーム/系列を入力できるように、 input_df init引数を追加します。

1.3.0(2017-01-21)

  • df_out=True (#70、#74)のときにマッパーがデータフレームを返すようにします。
  • sklearn 0.18(#68)の廃止予定の警告を避けるために輸入品を更新してください。

1.2.0(2016-10-02)

  • カスタムの相互検証シムクラスを非推奨にする。
  • scikit-learn>=0.15.0です。 #49を解決します。
  • マッパーで明示的に選択されていない列にデフォルトのトランスフォーマーを適用できるようにします。 #55を解決します。
  • 監督された変換の変換時にオプションのy引数を指定できるようにする。 #58を解決します。

1.1.0(2015-12-06)

  • 古いPassThroughTransformer削除します。 特定の列に対して変換が必要ない場合は、「 Noneをトランスとして使用します。
  • __init__.pyすべてを持つことを避けるために、いくつかのモジュールでコードを__init__.py
  • カスタムTransformerPipelineクラスを使用して、変換ステップがX引数のみを受け入れることができるようにします。 修正#46。
  • 1.0.0より前に作成されたトランスフォーマのリストを使用して、非マッピングマッパーの互換性シムを追加します。 #45を修正しました。

1.0.0(2015-11-28)

  • バージョン番号付けスキームをSemVerに変更します。
  • コードをコピーする代わりにsklearn.pipeline.Pipelineを使用します。 #43を解決します。
  • KeyErrorに存在しない列を選択する際にKeyErrorを発生させます。 #30を修正しました。
  • いずれかの特徴が疎でsparse引数がTrue場合は、疎な特徴配列を返しTrue 既存のコードが破損する可能性を避けるため、デフォルトはFalseに設定されています。 #34を解決します。
  • カスタムCVクラスのモデルと予測を返します。 修正#27。

0.0.12(2015-11-07)

  • 同じ列で順番に使用するトランスのリストを指定できるようにします。

クレジット

DataFrameMapperのコードは、もともとBen Hamnerによって書かれたコードに基づいています。

その他の寄稿者:

  • Arnau Gil Amat(@ arnau126)
  • Cal Paterson(@calpaterson)
  • @defvorfu
  • グスタボ・セナ・マフラ(@gsmafra)
  • イスラエル・セタ・ペレス(@dukebody)
  • ジェレミー・ハワード(@ jph00)
  • ジミーワン(@ジミーワン)
  • オリビエ・グリゼル(@グリゼル)
  • ポールバトラー(@ポールグ)
  • リチャードミラー(@rwjmiller)
  • Ritesh Agrawal(@ragrawal)
  • ティモシースウィーツター(@hacktuarial)
  • Vitaley Zaretskey(@vzaretsk)
  • ザック・スチュワート(ザックスチュワート)







-scikit-learn-contrib

執筆者: