sklearnによるパンダデータフレーム列のスケーリング


137

混合型の列を持つpandasデータフレームがあり、sklearnのmin_max_scalerをいくつかの列に適用したいと思います。理想的には、これらの変換を適切に実行したいのですが、その方法をまだ理解していません。機能する次のコードを作成しました。

import pandas as pd
import numpy as np
from sklearn import preprocessing

scaler = preprocessing.MinMaxScaler()

dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],'B':[103.02,107.26,110.35,114.23,114.68], 'C':['big','small','big','small','small']})
min_max_scaler = preprocessing.MinMaxScaler()

def scaleColumns(df, cols_to_scale):
    for col in cols_to_scale:
        df[col] = pd.DataFrame(min_max_scaler.fit_transform(pd.DataFrame(dfTest[col])),columns=[col])
    return df

dfTest

    A   B   C
0    14.00   103.02  big
1    90.20   107.26  small
2    90.95   110.35  big
3    96.27   114.23  small
4    91.21   114.68  small

scaled_df = scaleColumns(dfTest,['A','B'])
scaled_df

A   B   C
0    0.000000    0.000000    big
1    0.926219    0.363636    small
2    0.935335    0.628645    big
3    1.000000    0.961407    small
4    0.938495    1.000000    small

これがこの変換を行うための好ましい/最も効率的な方法であるかどうか私は興味があります。私がdf.applyを使用できる方法はありますか?

また、次のコードが機能しないことにも驚いています。

bad_output = min_max_scaler.fit_transform(dfTest['A'])

データフレーム全体をスケーラーに渡すと、機能します。

dfTest2 = dfTest.drop('C', axis = 1) good_output = min_max_scaler.fit_transform(dfTest2) good_output

シリーズをスケーラーに渡すことが失敗する理由がわかりません。上記の完全に機能するコードでは、シリーズをスケーラーに渡し、データフレームのcolumn =をスケーリングされたシリーズに設定することを望んでいました。この質問が他のいくつかの場所で尋ねられるのを見たことがありますが、良い答えは見つかりませんでした。ここで何が起こっているのかを理解するための助けがあれば大歓迎です!


1
これを行うとうまくいきますbad_output = min_max_scaler.fit_transform(dfTest['A'].values)か?values属性にアクセスするとnumpy配列が返されます。何らかの理由でscikit learn apiが適切なメソッドを正しく呼び出して、pandasがnumpy配列を返す場合とそうでない場合があります。
EdChum 14

パンダのデータフレームは、scikit-learnの規則と一致しない規則を持つ非常に複雑なオブジェクトです。すべてをNumPy配列に変換すると、scikit-learnの操作がはるかに簡単になります。
Fred Foo

@edChum- bad_output = in_max_scaler.fit_transform(dfTest['A'].values)どちらも機能しませんでした。@larsmans-ええ、私はこの道を行くことを考えていました、それはちょうど面倒のようです。Pandasが完全なデータフレームをsklearn関数に渡すことができるが、シリーズではないことがバグかどうかはわかりません。データフレームについての私の理解は、それがシリーズの口述であるということでした。「Python for Data Analysis」の本を読んで、パンダはnumpy上に構築され、NumPy中心のアプリケーションで簡単に使用できるようになっていると述べています。
フライングミートボール2014

回答:


214

以前のバージョンがpandasこれを防止したかどうかはわかりませんが、次のスニペットが私にとって完璧に機能し、使用せずにあなたが望むものを正確に生成しますapply

>>> import pandas as pd
>>> from sklearn.preprocessing import MinMaxScaler


>>> scaler = MinMaxScaler()

>>> dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],
                           'B':[103.02,107.26,110.35,114.23,114.68],
                           'C':['big','small','big','small','small']})

>>> dfTest[['A', 'B']] = scaler.fit_transform(dfTest[['A', 'B']])

>>> dfTest
          A         B      C
0  0.000000  0.000000    big
1  0.926219  0.363636  small
2  0.935335  0.628645    big
3  1.000000  0.961407  small
4  0.938495  1.000000  small

80
きちんと!より一般化されたバージョンdf[df.columns] = scaler.fit_transform(df[df.columns])
citynorman 2017

6
@RajeshThevar外側のブラケットはパンダの典型的なセレクターブラケットであり、データフレームから列を選択するようにパンダに指示します。内側の括弧はリストを示します。リストをpandasセレクターに渡します。単一のブラケットを使用する場合-カンマで区切られた1つの列名の後に別の列名が続く場合-パンダは、マルチレベルの列(MultiIndex)を持つデータフレームから列を選択しようとしていると解釈し、キーエラーをスローします。

1
パンダがこのインデックス作成ロジックをどのように実装するか、そして値のタプルがリストとは異なる方法で解釈される理由を正確に知りたい場合は、@ kenの回答に追加して、DataFramesが__getitem__メソッドを実装する方法を確認できます。具体的にはpd.DataFrame.__getitem__??、ipythonを開いて実行できます。もちろん、パンダをpdとしてインポートした後;)
LetsPlayYahtzee

4
実際的な注意:トレーニング/テストデータの分割を使用している場合は、テストデータではなく、トレーニングデータのみに適合させる必要があります。
デビッドJ.

1
タイムスタンプ列以外のすべてをスケーリングするには、次と組み合わせる columns =df.columns.drop('timestamps') df[df.columns] = scaler.fit_transform(df[df.columns]
intotecho

19

このような?

dfTest = pd.DataFrame({
           'A':[14.00,90.20,90.95,96.27,91.21],
           'B':[103.02,107.26,110.35,114.23,114.68], 
           'C':['big','small','big','small','small']
         })
dfTest[['A','B']] = dfTest[['A','B']].apply(
                           lambda x: MinMaxScaler().fit_transform(x))
dfTest

    A           B           C
0   0.000000    0.000000    big
1   0.926219    0.363636    small
2   0.935335    0.628645    big
3   1.000000    0.961407    small
4   0.938495    1.000000    small

3
このスクリプトを実行すると、たくさんのDeprecationWarningsが表示されます。どのように更新する必要がありますか?
ピル2015年

以下の@LetsPlayYahtzeeの回答を参照してください
AJP

2
簡単なバージョン:dfTest [['A'、 'B']] = dfTest [['A'、 'B']]。apply(MinMaxScaler()。fit_transform)
Alexandre V.

12

pirのコメントで言及されているように、この.apply(lambda el: scale.fit_transform(el))メソッドは次の警告を生成します。

DeprecationWarning:データとして1d配列を渡すと0.17で非推奨になり、0.19でValueErrorが発生します。データに単一の特徴がある場合はX.reshape(-1、1)を使用し、単一のサンプルが含まれる場合はX.reshape(1、-1)を使用してデータを再形成します。

列をnumpy配列に変換することでうまくいくはずです(私はStandardScalerを好みます)。

from sklearn.preprocessing import StandardScaler
scale = StandardScaler()

dfTest[['A','B','C']] = scale.fit_transform(dfTest[['A','B','C']].as_matrix())

- 2018年11月を編集(パンダ0.23.4でテスト済み)-

Rob Murrayがコメントで言及しているように、現在の(v0.23.4)バージョンのパンダで.as_matrix()はが返されますFutureWarning。したがって、次のように置き換える必要があります.values

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()

scaler.fit_transform(dfTest[['A','B']].values)

- 2019年5月を編集(パンダ0.24.2でテスト済み)-

joelostblomがコメントで述べているように、「の代わりに0.24.0を使用することをお勧めします。」.to_numpy().values

更新された例:

import pandas as pd
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
dfTest = pd.DataFrame({
               'A':[14.00,90.20,90.95,96.27,91.21],
               'B':[103.02,107.26,110.35,114.23,114.68],
               'C':['big','small','big','small','small']
             })
dfTest[['A', 'B']] = scaler.fit_transform(dfTest[['A','B']].to_numpy())
dfTest
      A         B      C
0 -1.995290 -1.571117    big
1  0.436356 -0.603995  small
2  0.460289  0.100818    big
3  0.630058  0.985826  small
4  0.468586  1.088469  small

1
使用.valuesの代わりに.as_matrix()ようas_matrix()になりまし与えますFutureWarning
Rob Murray


10
df = pd.DataFrame(scale.fit_transform(df.values), columns=df.columns, index=df.index)

これは、減価償却の警告なしで機能するはずです。


7

あなたpandasだけを使用してそれを行うことができます :

In [235]:
dfTest = pd.DataFrame({'A':[14.00,90.20,90.95,96.27,91.21],'B':[103.02,107.26,110.35,114.23,114.68], 'C':['big','small','big','small','small']})
df = dfTest[['A', 'B']]
df_norm = (df - df.min()) / (df.max() - df.min())
print df_norm
print pd.concat((df_norm, dfTest.C),1)

          A         B
0  0.000000  0.000000
1  0.926219  0.363636
2  0.935335  0.628645
3  1.000000  0.961407
4  0.938495  1.000000
          A         B      C
0  0.000000  0.000000    big
1  0.926219  0.363636  small
2  0.935335  0.628645    big
3  1.000000  0.961407  small
4  0.938495  1.000000  small

6
パンダだけでもできることはわかっていますが、自分で書くのが簡単ではない別のsklearnメソッドを最終的に適用したい場合があります。厳密に単純なソリューションを考え出すよりも、シリーズへの適用が期待どおりに機能しない理由を理解することに興味があります。次のステップはRandomForestRegressorを実行することです。Pandasとsklearnがどのように連携するかを確実に理解したいと思います。
フライングミートボール2014

5
この回答はdf.max() - df.min() 0になる可能性があるため危険であり、例外が発生します。さらに、df.min()は2回計算されるため、非効率的です。df.ptp()と同等であることに注意してくださいdf.max() - df.min()
Acumenus 2018年

3

私はそれが非常に古いコメントであることを知っていますが、それでも:

単一のブラケット(dfTest['A'])を使用する代わりに、二重ブラケットを使用します(dfTest[['A']])

すなわち:min_max_scaler.fit_transform(dfTest[['A']])

これは望ましい結果をもたらすと信じています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.