J'ai un pandas dataframe avec des colonnes de type mixte, et j'aimerais appliquer le min_max_scaler de sklearn à certaines des colonnes. Idéalement, j'aimerais effectuer ces transformations sur place, mais je n'ai pas encore trouvé le moyen de le faire. 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. Existe-t-il un moyen d'utiliser df.apply qui serait mieux?
Je suis également surpris de ne pas pouvoir utiliser le code suivant:
bad_output = min_max_scaler.fit_transform(dfTest['A'])
Si je passe un cadre de données entier au scaler, cela fonctionne:
dfTest2 = dfTest.drop('C', axis = 1) good_output = min_max_scaler.fit_transform(dfTest2) good_output
Je ne comprends pas 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 = sur la série mise à l'échelle. J'ai vu cette question posée à quelques autres endroits, mais je n'ai pas trouvé de bonne réponse. Toute aide pour comprendre ce qui se passe ici serait grandement appréciée!
Je ne suis pas sûr que les versions précédentes de pandas
l'aient empêché, mais 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
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
Comme cela est mentionné dans le commentaire de pir - la méthode .apply(lambda el: scale.fit_transform(el))
produira l'avertissement suivant:
DeprecationWarning: le passage de tableaux 1d en tant que données est obsolète en 0.17 et augmentera ValueError en 0.19. Modifiez la forme de vos données en utilisant X.reshape (-1, 1) si vos données ont une seule fonctionnalité ou X.reshape (1, -1) si elles contiennent un seul échantillon.
La conversion de vos colonnes en tableaux numpy devrait faire l'affaire (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())
- Modifier Nov 2018 (testé pour pandas .23.4) -
Comme Rob Murray le mentionne dans les commentaires, dans la version actuelle (v0.23.4) de pandas .as_matrix()
renvoie FutureWarning
. Par conséquent, il devrait être remplacé par .values
:
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit_transform(dfTest[['A','B']].values)
- Modifier Mai 2019 (testé pour pandas .24.2) -
Comme joelostblom le mentionne dans les commentaires, "Depuis 0.24.0
, il est recommandé d’utiliser .to_numpy()
au lieu de .values
."
Exemple mis à jour:
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
Vous pouvez le faire en utilisant pandas
uniquement:
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
df = pd.DataFrame(scale.fit_transform(df.values), columns=df.columns, index=df.index)
Cela devrait fonctionner sans avertissements de dépréciation.