pandas DataFrame colonnes mise à l'échelle avec sklearn

J'ai un DataFrame pandas avec des colonnes de type mixte, et je voudrais appliquer min_max_scaler de sklearn à certaines des colonnes. Idéalement, j'aimerais faire ces transformations en place, mais n'avez pas trouvé un moyen de le faire encore. J'ai écrit le code suivant qui fonctionne:

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

Je suis curieux de savoir si c'est le moyen préféré/le plus efficace de faire cette transformation. Y at-il un moyen que je pourrais utiliser df.appliquer ce serait mieux?

Je suis aussi surpris que je ne puisse pas obtenir ce qui suit code à travailler:

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

Si je passe un dataframe entier au scaler, cela fonctionne:

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

Je suis confus pourquoi passer une série au scaler échoue. Dans mon code de travail complet ci-dessus, j'avais espéré simplement passer une série au scaler puis définir la colonne dataframe = à la série mise à l'échelle. J'ai vu cette question posée à quelques autres endroits, mais je n'ai pas trouvé une bonne réponse. Toute aide à comprendre ce qui se passe ici serait grandement appréciée!

58
demandé sur flyingmeatball 2014-07-09 07:57:55

4 réponses

Je ne suis pas sûr si les versions précédentes de pandas l'ont empêché mais maintenant l'extrait suivant fonctionne parfaitement pour moi et produit exactement ce que vous voulez sans avoir à utiliser 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
76
répondu LetsPlayYahtzee 2016-06-20 09:04:33

Comme ça?

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
18
répondu Eric Czech 2016-05-15 13:43:17

Vous pouvez le faire en utilisant pandas seulement:

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
5
répondu CT Zhu 2014-07-09 04:07:25

Comme il est mentionné dans le commentaire de pir - La Méthode .apply(lambda el: scale.fit_transform(el)) produira l'avertissement suivant:

DeprecationWarning: passer des tableaux 1d car les données sont obsolètes dans 0.17 et augmentera ValueError dans 0.19. Remodelez vos données soit en utilisant X. reshape (-1, 1) si vos données ont une seule fonctionnalité ou X. reshape (1, -1) si elle contient un seul échantillon.

Convertir vos colonnes en tableaux numpy devrait faire le travail (je préfère StandardScaler):

from sklearn.preprocessing import StandardScaler
scale = StandardScaler()

dfTest[['A','B','C']] = scale.fit_transform(dfTest[['A','B','C']].as_matrix())
5
répondu Low Yield Bond 2016-05-25 10:44:29