web-dev-qa-db-fra.com

Variables factices lorsque toutes les catégories ne sont pas présentes

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
27
Berne

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
19
piRSquared

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.

29
T.C. Proctor

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
4
Kapil Sharma

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 DataFrameid) 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.

3
Stefan

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

1
Thibault Clement

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"])
1
Rudr

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.

1
andre