Tengo un marco de datos de pandas con columnas de tipo mixto, y me gustaría aplicar min_max_scaler de sklearn a algunas de las columnas. Idealmente, me gustaría hacer estas transformaciones en su lugar, pero aún no he encontrado una manera de hacerlo. He escrito el siguiente código que funciona:
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
Tengo curiosidad por saber si esta es la forma preferida / más eficiente de hacer esta transformación. ¿Hay alguna forma en que pueda usar df.apply que sería mejor?
También me sorprende no poder hacer funcionar el siguiente código:
bad_output = min_max_scaler.fit_transform(dfTest['A'])
Si paso un marco de datos completo al escalador, funciona:
dfTest2 = dfTest.drop('C', axis = 1)
good_output = min_max_scaler.fit_transform(dfTest2)
good_output
Estoy confundido por qué pasar una serie al escalador falla. En mi código de trabajo completo anterior, esperaba pasar una serie al escalador y luego establecer la columna del marco de datos = a la serie escalada. He visto esta pregunta en otros lugares, pero no he encontrado una buena respuesta. ¡Cualquier ayuda para entender lo que está pasando aquí sería muy apreciada!
fuente
bad_output = min_max_scaler.fit_transform(dfTest['A'].values)
? el acceso alvalues
atributo devuelve una matriz numpy, por alguna razón, la API de aprendizaje scikit llamará correctamente al método correcto que hace que los pandas devuelvan una matriz numpy y a veces no.bad_output = in_max_scaler.fit_transform(dfTest['A'].values)
tampoco funcionó. @larsmans: sí, había pensado en seguir esta ruta, parece una molestia. No sé si es un error o no, que Pandas puede pasar un marco de datos completo a una función sklearn, pero no una serie. Mi comprensión de un marco de datos fue que es un dict de serie. Leyendo en el libro "Python for Data Analysis", declara que pandas está construido sobre numpy para que sea fácil de usar en aplicaciones centradas en NumPy.Respuestas:
No estoy seguro de si las versiones anteriores de
pandas
previenen esto, pero ahora el siguiente fragmento funciona perfectamente para mí y produce exactamente lo que desea sin tener que usarapply
fuente
df[df.columns] = scaler.fit_transform(df[df.columns])
__getitem__
método. Específicamente puedes abrir tu ipython y hacerlopd.DataFrame.__getitem__??
; después de importar pandas como pd, por supuesto;)columns =df.columns.drop('timestamps') df[df.columns] = scaler.fit_transform(df[df.columns]
¿Me gusta esto?
fuente
Como se menciona en el comentario de pir, el
.apply(lambda el: scale.fit_transform(el))
método producirá la siguiente advertencia:La conversión de sus columnas a matrices numpy debería hacer el trabajo (prefiero StandardScaler):
- Edición de noviembre de 2018 (probado para pandas 0.23.4 ) -Como Rob Murray menciona en los comentarios, en la versión actual (v0.23.4) de los pandas
.as_matrix()
regresaFutureWarning
. Por lo tanto, debe ser reemplazado por.values
:- Editar mayo de 2019 (probado para pandas 0.24.2 ) -
Como joelostblom menciona en los comentarios, "desde entonces
0.24.0
, se recomienda usar en.to_numpy()
lugar de.values
".Ejemplo actualizado:
fuente
.values
en lugar de.as_matrix()
comoas_matrix()
ahora da unFutureWarning
.0.24.0
, se recomienda usar en.to_numpy()
lugar de.values
.Esto debería funcionar sin advertencias de depreciación.
fuente
Puedes hacerlo usando
pandas
solo:fuente
df.max() - df.min()
puede ser 0, lo que lleva a una excepción. Además,df.min()
se calcula dos veces, lo que es ineficiente. Tenga en cuenta quedf.ptp()
es equivalente adf.max() - df.min()
.Sé que es un comentario muy antiguo, pero aún así:
En lugar de usar un solo corchete
(dfTest['A'])
, use corchetes dobles(dfTest[['A']])
.es decir:
min_max_scaler.fit_transform(dfTest[['A']])
.Creo que esto dará el resultado deseado.
fuente