pandas.factorize
code les valeurs d'entrée sous forme de type énuméré ou de variable catégorique.
Mais comment puis-je convertir facilement et efficacement plusieurs colonnes d'un bloc de données? Qu'en est-il de l'étape de mappage inverse?
Exemple: Ce cadre de données contient des colonnes avec des valeurs de chaîne telles que "type 2" que je voudrais convertir en valeurs numériques - et éventuellement les traduire ultérieurement.
Vous pouvez utiliser apply
si vous devez factorize
chaque colonne séparément:
df = pd.DataFrame({'A':['type1','type2','type2'],
'B':['type1','type2','type3'],
'C':['type1','type3','type3']})
print (df)
A B C
0 type1 type1 type1
1 type2 type2 type3
2 type2 type3 type3
print (df.apply(lambda x: pd.factorize(x)[0]))
A B C
0 0 0 0
1 1 1 1
2 1 2 1
Si vous avez besoin de la même valeur numérique pour la même valeur de chaîne:
print (df.stack().rank(method='dense').unstack())
A B C
0 1.0 1.0 1.0
1 2.0 2.0 3.0
2 2.0 3.0 3.0
Si vous devez appliquer la fonction uniquement à certaines colonnes, utilisez un sous-ensemble:
df[['B','C']] = df[['B','C']].stack().rank(method='dense').unstack()
print (df)
A B C
0 type1 1.0 1.0
1 type2 2.0 3.0
2 type2 3.0 3.0
Solution avec factorize
:
stacked = df[['B','C']].stack()
df[['B','C']] = pd.Series(stacked.factorize()[0], index=stacked.index).unstack()
print (df)
A B C
0 type1 0 0
1 type2 1 2
2 type2 2 2
Les convertir en arrière est possible via map
by dict
, où vous devez supprimer les doublons par drop_duplicates
:
vals = df.stack().drop_duplicates().values
b = [x for x in df.stack().drop_duplicates().rank(method='dense')]
d1 = dict(Zip(b, vals))
print (d1)
{1.0: 'type1', 2.0: 'type2', 3.0: 'type3'}
df1 = df.stack().rank(method='dense').unstack()
print (df1)
A B C
0 1.0 1.0 1.0
1 2.0 2.0 3.0
2 2.0 3.0 3.0
print (df1.stack().map(d1).unstack())
A B C
0 type1 type1 type1
1 type2 type2 type3
2 type2 type3 type3
J'ai également trouvé cette réponse très utile: https://stackoverflow.com/a/20051631/4643212
J'essayais de prendre les valeurs d'une colonne existante d'un Pandas DataFrame (une liste d'adresses IP nommées "SrcIP") et de les mapper à des valeurs numériques dans une nouvelle colonne (nommée "ID" dans cet exemple).
Solution:
df['ID'] = pd.factorize(df.SrcIP)[0]
Résultat:
SrcIP | ID
192.168.1.112 | 0
192.168.1.112 | 0
192.168.4.118 | 1
192.168.1.112 | 0
192.168.4.118 | 1
192.168.5.122 | 2
192.168.5.122 | 2
...
Je voudrais rediriger ma réponse: https://stackoverflow.com/a/32011969/1694714
Ancienne réponse
Une autre solution lisible à ce problème, lorsque vous souhaitez conserver les catégories cohérentes dans le DataFrame résultant, est de remplacer:
def categorise(df):
categories = {k: v for v, k in enumerate(df.stack().unique())}
return df.replace(categories)
Effectue légèrement moins bien que l'exemple de @jezrael, mais plus facile à lire. En outre, il pourrait mieux s’aggraver pour de plus grands ensembles de données. Je peux faire des tests appropriés si quelqu'un est intéressé.