web-dev-qa-db-ja.com

pandas sklearnを使用したデータフレーム列のスケーリング

混合型の列を持つ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

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

87
flyingmeatball

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
130
LetsPlayYahtzee

このような?

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
19
Eric Czech

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月(pandasについてテスト済み.23.4)-

Rob Murrayがコメントで述べているように、現在の(v0.23.4)バージョンのpandas .as_matrix()FutureWarningを返します。したがって、.valuesに置き換える必要があります。

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()

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

編集 2019年5月(pandasについてテスト済み.24.2)-

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

更新された例:

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
7
Low Yield Bond

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
CT Zhu
df = pd.DataFrame(scale.fit_transform(df.values), columns=df.columns, index=df.index)

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

6
athlonshi