J'ai un ensemble de cadres de données où l'une des colonnes contient une variable catégorique. J'aimerais le convertir en plusieurs variables factices, auquel cas j'utiliserais normalement get_dummies
.
Ce qui se passe, c’est que get_dummies
examine les données disponibles dans chaque cadre de données pour déterminer le nombre de catégories et créer ainsi le nombre approprié de variables nominales. Cependant, dans le problème sur lequel je travaille actuellement, je sais à l’avance quelles sont les catégories possibles. Mais lorsque vous examinez chaque image individuellement, toutes les catégories n'apparaissent pas nécessairement.
Ma question est la suivante: existe-t-il un moyen de transmettre à get_dummies
(ou une fonction équivalente) les noms des catégories afin que, pour les catégories n'apparaissant pas dans un cadre de données donné, il ne crée qu'une colonne de 0?
Quelque chose qui ferait ceci:
categories = ['a', 'b', 'c']
cat
1 a
2 b
3 a
Devenir ceci:
cat_a cat_b cat_c
1 1 0 0
2 0 1 0
3 1 0 0
Utiliser transposer et réindexer
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
existe-t-il un moyen de transmettre à get_dummies (ou une fonction équivalente) les noms des catégories, afin que, pour les catégories n'apparaissant pas dans un cadre de données donné, il crée simplement une colonne de 0?
Oui il y a! Les pandas ont un type spécial de série juste pour données catégorielles . L'un des attributs de cette série est les catégories possibles que get_dummies
prend en compte. Voici un exemple:
In [1]: import pandas as pd
In [2]: cat=pd.Series(list('aba'),index=range(1,4))
In [3]: cat=cat.astype('category',categories=list('abc'))
In [4]: cat
Out[4]:
1 a
2 b
3 a
dtype: category
Categories (3, object): [a, b, c]
Alors, get_dummies
fera exactement ce que vous voulez!
In [5]: pd.get_dummies(cat)
Out[5]:
a b c
1 1 0 0
2 0 1 0
3 1 0 0
Il existe de nombreuses autres manières de créer une Series
ou une DataFrame
catégorique, c’est celle que je trouve la plus pratique. Vous pouvez lire sur chacun d'eux dans la documentation sur les pandas .
MODIFIER:
Je n'ai pas suivi le versioning exact, mais il y avait un bug dans la façon dont les pandas traitent les matrices creuses, au moins jusqu'à la version 0.17.0. Il a été corrigé par la version 0.18.1.
Pour la version 0.17.0, si vous essayez de le faire avec l'option sparse=True
avec un DataFrame
, la colonne de zéros de la variable factice manquante sera une colonne de NaN
et sera convertie en dense.
Essaye ça:
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
Je ne pense pas que get_dummies
fournisse ceci dans la boîte, cela permet seulement de créer une column
supplémentaire qui met en valeur les valeurs NaN
.
Pour ajouter vous-même la variable columns
manquante, vous pouvez utiliser pd.concat
avec axis=0
pour «empiler» verticalement la DataFrames
(les colonnes factices plus une DataFrame
id
) et créer automatiquement toutes les colonnes manquantes, utiliser fillna(0)
pour remplacer les valeurs manquantes, puis utiliser .groupby('id')
pour séparer la divers DataFrame
encore.
Ajout de la catégorie manquante dans le jeu de test:
# 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]
Notez que ce code supprime également les colonnes résultant de la catégorie dans le jeu de données test mais non présentes dans le jeu de données d'apprentissage
Comme suggéré par d'autres personnes, la conversion de vos entités catégoriques en type de données "catégorie" devrait résoudre le problème des étiquettes invisibles à l'aide de " 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"])
J'ai demandé ceci sur le github de pandas. Il s’avère qu’il est très facile de contourner le problème lorsque vous définissez la colonne en tant que Categorical
où vous définissez toutes les catégories possibles.
df['col'] = pd.Categorical(df['col'], categories=['a', 'b', 'c', 'd'])
get_dummies()
fera le reste comme prévu.