python - multiple - Variables ficticias cuando no todas las categorías están presentes
pandas join (7)
Tengo un conjunto de marcos de datos donde una de las columnas contiene una variable categórica.
Me gustaría convertirlo a varias variables ficticias, en cuyo caso normalmente usaría
get_dummies
.
Lo que sucede es que
get_dummies
analiza los datos disponibles en cada marco de datos para averiguar cuántas categorías hay y, por lo tanto, crea el número apropiado de variables ficticias.
Sin embargo, en el problema en el que estoy trabajando ahora, sé de antemano cuáles son las categorías posibles.
Pero al mirar cada marco de datos individualmente, no todas las categorías aparecen necesariamente.
Mi pregunta es: ¿hay alguna forma de pasar a
get_dummies
(o una función equivalente) los nombres de las categorías, de modo que, para las categorías que no aparecen en un marco de datos dado, simplemente crearía una columna de 0?
Algo que haría esto:
categories = [''a'', ''b'', ''c'']
cat
1 a
2 b
3 a
Conviértete en esto:
cat_a cat_b cat_c
1 1 0 0
2 0 1 0
3 1 0 0
¿hay alguna manera de pasar a get_dummies (o una función equivalente) los nombres de las categorías, de modo que, para las categorías que no aparecen en un marco de datos dado, solo crearía una columna de 0?
¡Sí hay!
Pandas tiene un tipo especial de serie solo para
datos categóricos
.
Uno de los atributos de esta serie son las posibles categorías, que
get_dummies
tiene en cuenta.
Aquí hay un ejemplo:
In [1]: import pandas as pd
In [2]: possible_categories = list(''abc'')
In [3]: cat = pd.Series(list(''aba''))
In [4]: cat = cat.astype(''category'', categories=possible_categories)
In [5]: cat
Out[5]:
0 a
1 b
2 a
dtype: category
Categories (3, object): [a, b, c]
¡Entonces,
get_dummies
hará exactamente lo que quieras!
In [6]: pd.get_dummies(cat)
Out[6]:
a b c
0 1 0 0
1 0 1 0
2 1 0 0
Hay muchas otras formas de crear una
Series
o un
DataFrame
, esta es la que me parece más conveniente.
Puedes leer sobre todos ellos en
la documentación de los pandas
.
EDITAR:
No he seguido las versiones exactas, pero hubo un bug en cómo los pandas tratan las matrices dispersas, al menos hasta la versión 0.17.0. Fue corregido por la versión 0.18.1 (lanzada en mayo de 2016).
Para la versión 0.17.0, si intenta hacer esto con la opción
sparse=True
con un
DataFrame
, la columna de ceros para la variable ficticia faltante será una columna de
NaN
y se convertirá en densa.
Agregar la categoría que falta en el conjunto de prueba:
# Get missing columns in the training test
missing_cols = set( train.columns ) - set( test.columns )
# Add a missing column in test set with default value equal to 0
for c in missing_cols:
test[c] = 0
# Ensure the order of column in the test set is in the same order than in train set
test = test[train.columns]
Tenga en cuenta que este código también elimina la columna resultante de la categoría en el conjunto de datos de prueba pero no está presente en el conjunto de datos de entrenamiento
No creo que
get_dummies
proporcione esto fuera de la caja, solo permite crear una
column
adicional que resalta los valores de
NaN
.
Para agregar las
columns
faltan, puede usar
pd.concat
largo de
axis=0
para ''apilar'' verticalmente los
DataFrames
(las columnas ficticias más un
id
DataFrame
) y crear automáticamente las columnas faltantes, use
fillna(0)
para reemplazar los valores faltantes y luego use
.groupby(''id'')
para separar nuevamente los distintos
DataFrame
.
Pregunté esto en los pandas github.
Resulta que es muy fácil evitarlo cuando define la columna como
Categorical
donde define todas las categorías posibles.
df[''col''] = pd.Categorical(df[''col''], categories=[''a'', ''b'', ''c'', ''d''])
get_dummies()
hará el resto como se esperaba.
Prueba esto:
In[1]: import pandas as pd
cats = ["a", "b", "c"]
In[2]: df = pd.DataFrame({"cat": ["a", "b", "a"]})
In[3]: pd.concat((pd.get_dummies(df.cat, columns=cats), pd.DataFrame(columns=cats))).fillna(0)
Out[3]:
a b c
0 1.0 0.0 0
1 0.0 1.0 0
2 1.0 0.0 0
Según lo sugerido por otros, la conversión de sus características categóricas al tipo de datos ''categoría'' debería resolver el problema de la etiqueta invisible usando '' get_dummies ''.
# Your Data frame(df)
from sklearn.model_selection import train_test_split
X = df.loc[:,df.columns !=''label'']
Y = df.loc[:,df.columns ==''label'']
# Split the data into 70% training and 30% test
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.3)
# Convert Categorical Columns in your data frame to type ''category''
for col in df.select_dtypes(include=[np.object]).columns:
X_train[col] = X_train[col].astype(''category'', categories = df[col].unique())
X_test[col] = X_test[col].astype(''category'', categories = df[col].unique())
# Now, use get_dummies on training, test data and we will get same set of columns
X_train = pd.get_dummies(X_train,columns = ["Categorical_Columns"])
X_test = pd.get_dummies(X_test,columns = ["Categorical_Columns"])
Usar transposición y reindexar
import pandas as pd
cats = [''a'', ''b'', ''c'']
df = pd.DataFrame({''cat'': [''a'', ''b'', ''a'']})
dummies = pd.get_dummies(df, prefix='''', prefix_sep='''')
dummies = dummies.T.reindex(cats).T.fillna(0)
print dummies
a b c
0 1.0 0.0 0.0
1 0.0 1.0 0.0
2 1.0 0.0 0.0