Estoy aprendiendo diferentes métodos para convertir variables categóricas en numéricas para clasificadores de aprendizaje automático. Encontré el pd.get_dummies
método y sklearn.preprocessing.OneHotEncoder()
quería ver cómo se diferenciaban en términos de rendimiento y uso.
Encontré un tutorial sobre cómo usar OneHotEncoder()
en https://xgdgsc.wordpress.com/2015/03/20/note-on-using-onehotencoder-in-scikit-learn-to-work-on-categorical-features/ desde la sklearn
documentación no fue muy útil sobre esta función. Tengo la sensación de que no lo estoy haciendo correctamente ... pero
¿Pueden algunos explicar los pros y los contras de usar pd.dummies
over sklearn.preprocessing.OneHotEncoder()
y viceversa? Sé que OneHotEncoder()
le da una matriz dispersa, pero aparte de eso, no estoy seguro de cómo se usa y cuáles son los beneficios del pandas
método. ¿Lo estoy usando de manera ineficiente?
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
sns.set()
%matplotlib inline
#Iris Plot
iris = load_iris()
n_samples, m_features = iris.data.shape
#Load Data
X, y = iris.data, iris.target
D_target_dummy = dict(zip(np.arange(iris.target_names.shape[0]), iris.target_names))
DF_data = pd.DataFrame(X,columns=iris.feature_names)
DF_data["target"] = pd.Series(y).map(D_target_dummy)
#sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) \
#0 5.1 3.5 1.4 0.2
#1 4.9 3.0 1.4 0.2
#2 4.7 3.2 1.3 0.2
#3 4.6 3.1 1.5 0.2
#4 5.0 3.6 1.4 0.2
#5 5.4 3.9 1.7 0.4
DF_dummies = pd.get_dummies(DF_data["target"])
#setosa versicolor virginica
#0 1 0 0
#1 1 0 0
#2 1 0 0
#3 1 0 0
#4 1 0 0
#5 1 0 0
from sklearn.preprocessing import OneHotEncoder, LabelEncoder
def f1(DF_data):
Enc_ohe, Enc_label = OneHotEncoder(), LabelEncoder()
DF_data["Dummies"] = Enc_label.fit_transform(DF_data["target"])
DF_dummies2 = pd.DataFrame(Enc_ohe.fit_transform(DF_data[["Dummies"]]).todense(), columns = Enc_label.classes_)
return(DF_dummies2)
%timeit pd.get_dummies(DF_data["target"])
#1000 loops, best of 3: 777 µs per loop
%timeit f1(DF_data)
#100 loops, best of 3: 2.91 ms per loop
OneHotEncoder
no se puede aplicar en cadenas también en la versión 0.20.0.OneHotEncoder(sparse=False).fit_transform(pd.DataFrame(pd.Series(['good','bad','worst','good', 'good', 'bad'])))
funciona, lo que significa queOneHotEncoder
se pueden aplicar en agitaciones.pd.get_dummies
.Para el aprendizaje automático, es casi seguro que desea utilizar
sklearn.OneHotEncoder
. Para otras tareas como análisis simples, es posible que pueda usarpd.get_dummies
, lo cual es un poco más conveniente.Tenga en cuenta que
sklearn.OneHotEncoder
se ha actualizado en la última versión para que acepte cadenas para variables categóricas, así como enteros.El quid de esto es que el
sklearn
codificador crea una función que persiste y luego se puede aplicar a nuevos conjuntos de datos que usan las mismas variables categóricas, con resultados consistentes .from sklearn.preprocessing import OneHotEncoder # Create the encoder. encoder = OneHotEncoder(handle_unknown="ignore") encoder.fit(X_train) # Assume for simplicity all features are categorical. # Apply the encoder. X_train = encoder.transform(X_train) X_test = encoder.transform(X_test)
Observe cómo aplicamos el mismo codificador que creamos a través
X_train
del nuevo conjunto de datosX_test
.Considere lo que sucede si
X_test
contiene niveles diferentes a losX_train
de una de sus variables. Por ejemplo, digamos queX_train["color"]
contiene solo"red"
y"green"
, pero además de esos, aX_test["color"]
veces contiene"blue"
.Si usamos
pd.get_dummies
,X_test
terminará con una"color_blue"
columna adicional queX_train
no tiene, y la inconsistencia probablemente romperá nuestro código más adelante, especialmente si estamos alimentandoX_test
unsklearn
modelo en el que entrenamosX_train
.Y si queremos procesar los datos como este en producción, donde estamos recibiendo un solo ejemplo a la vez,
pd.get_dummies
no será útil.Por
sklearn.OneHotEncoder
otro lado, una vez que hemos creado el codificador, podemos reutilizarlo para producir la misma salida cada vez, con columnas solo para"red"
y"green"
. Y podemos controlar explícitamente lo que sucede cuando se encuentra con el nuevo nivel"blue"
: si creemos que eso es imposible, entonces podemos decirle que arroje un errorhandle_unknown="error"
; de lo contrario, podemos decirle que continúe y simplemente establecer las columnas roja y verde en 0, conhandle_unknown="ignore"
.fuente
¿Por qué no almacenar en caché o guardar las columnas como variable col_list del get_dummies resultante y luego usar pd.reindex para alinear los conjuntos de datos de tren vs prueba ... ejemplo:
df = pd.get_dummies(data) col_list = df.columns.tolist() new_df = pd.get_dummies(new_data) new_df = new_df.reindex(columns=col_list).fillna(0.00)
fuente
Realmente me gustó la respuesta de Carl y la voté a favor. Simplemente ampliaré un poco el ejemplo de Carl para que, con suerte, más personas aprecien que pd.get_dummies puede manejar unknown. Los dos ejemplos siguientes muestran que pd.get_dummies puede lograr lo mismo en el manejo de desconocido que OHE.
# data is from @dzieciou's comment above >>> data =pd.DataFrame(pd.Series(['good','bad','worst','good', 'good', 'bad'])) # new_data has two values that data does not have. >>> new_data= pd.DataFrame( pd.Series(['good','bad','worst','good', 'good', 'bad','excellent', 'perfect']))
Usando pd.get_dummies
>>> df = pd.get_dummies(data) >>> col_list = df.columns.tolist() >>> print(df) 0_bad 0_good 0_worst 0 0 1 0 1 1 0 0 2 0 0 1 3 0 1 0 4 0 1 0 5 1 0 0 6 0 0 0 7 0 0 0 >>> new_df = pd.get_dummies(new_data) # handle unknow by using .reindex and .fillna() >>> new_df = new_df.reindex(columns=col_list).fillna(0.00) >>> print(new_df) # 0_bad 0_good 0_worst # 0 0 1 0 # 1 1 0 0 # 2 0 0 1 # 3 0 1 0 # 4 0 1 0 # 5 1 0 0 # 6 0 0 0 # 7 0 0 0
Usando OneHotEncoder
>>> encoder = OneHotEncoder(handle_unknown="ignore", sparse=False) >>> encoder.fit(data) >>> encoder.transform(new_data) # array([[0., 1., 0.], # [1., 0., 0.], # [0., 0., 1.], # [0., 1., 0.], # [0., 1., 0.], # [1., 0., 0.], # [0., 0., 0.], # [0., 0., 0.]])
fuente