Massenkonvertierung kategorialer Spalten in Pandas (keine One-Hot-Codierung)

12

Ich habe einen Pandas-Datenrahmen mit Tonnen von kategorialen Spalten, die ich im Entscheidungsbaum mit Scikit-Learn verwenden möchte. Ich muss sie in numerische Werte konvertieren (nicht einen heißen Vektor). Ich kann es mit LabelEncoder von scikit-learn machen. Das Problem ist, dass es zu viele davon gibt und ich sie nicht manuell konvertieren möchte.

Was wäre ein einfacher Weg, um diesen Prozess zu automatisieren.

user1700890
quelle
Die Funktion get_dummies in Pandas kann Ihnen helfen. Weitere Informationen finden Sie in der Dokumentation hier . Ich denke, es deckt diesen Anwendungsfall perfekt ab, und Sie können das Verhalten weiter optimieren, indem Sie benutzerdefinierte Präfixe angeben.
hssay

Antworten:

11

Wenn Ihre kategorialen Spalten derzeit Zeichen / Objekte sind, können Sie Folgendes verwenden:

char_cols = df.dtypes.pipe(lambda x: x[x == 'object']).index

for c in char_cols:
    df[c] = pd.factorize(df[c])[0]

Wenn Sie in der Lage sein müssen, zu den Kategorien zurückzukehren, würde ich ein Wörterbuch erstellen, um die Codierung zu speichern. etwas wie:

char_cols = df.dtypes.pipe(lambda x: x[x == 'object']).index
label_mapping = {}

for c in char_cols:
    df[c], label_mapping[c] = pd.factorize(df[c])

Wenn Sie Juliens mcve verwenden, wird Folgendes ausgegeben:

In [3]: print(df)
Out[3]: 
    a   b   c   d
0   0   0   0   0.155463
1   1   1   1   0.496427
2   0   0   2   0.168625
3   2   0   1   0.209681
4   0   2   1   0.661857

In [4]: print(label_mapping)
Out[4]:
{'a': Index(['Var2', 'Var3', 'Var1'], dtype='object'),
 'b': Index(['Var2', 'Var1', 'Var3'], dtype='object'),
 'c': Index(['Var3', 'Var2', 'Var1'], dtype='object')}
george_w_kush
quelle
Ihr Code zum Auffinden der objectSpalten ist sehr nützlich.
Javadba
6

Lassen Sie uns zunächst ein mcve erstellen, mit dem Sie spielen können:

import pandas as pd
import numpy as np

In [1]: categorical_array = np.random.choice(['Var1','Var2','Var3'],
                                             size=(5,3), p=[0.25,0.5,0.25])
        df = pd.DataFrame(categorical_array,
               columns=map(lambda x:chr(97+x), range(categorical_array.shape[1])))
        # Add another column that isn't categorical but float
        df['d'] = np.random.rand(len(df))
        print(df)

Out[1]:
      a     b     c         d
0  Var3  Var3  Var3  0.953153
1  Var1  Var2  Var1  0.924896
2  Var2  Var2  Var2  0.273205
3  Var2  Var1  Var3  0.459676
4  Var2  Var1  Var1  0.114358

Jetzt können wir pd.get_dummies verwenden , um die ersten drei Spalten zu codieren.

Beachten Sie, dass ich den drop_firstParameter verwende, da N-1Dummies ausreichen, um die NMöglichkeiten vollständig zu beschreiben (z. B. wenn a_Var2und a_Var30 sind, dann ist es a_Var1). Außerdem spezifiziere ich speziell die Spalten, muss dies aber nicht, da es sich entweder um Spalten mit dtype objectoder categorical(weiter unten) handelt.

In [2]: df_encoded = pd.get_dummies(df, columns=['a','b', 'c'], drop_first=True)
        print(df_encoded]
Out[2]:
          d  a_Var2  a_Var3  b_Var2  b_Var3  c_Var2  c_Var3
0  0.953153       0       1       0       1       0       1
1  0.924896       0       0       1       0       0       0
2  0.273205       1       0       1       0       1       0
3  0.459676       1       0       0       0       0       1
4  0.114358       1       0       0       0       0       0

In Ihrer spezifischen Anwendung müssen Sie eine Liste der Spalten bereitstellen, die kategorisch sind, oder Sie müssen ableiten, welche Spalten kategorisch sind.

Im besten Fall hat Ihr Datenrahmen diese Spalten bereits mit einem dtype=categoryund Sie können columns=df.columns[df.dtypes == 'category']an übergeben get_dummies.

Andernfalls schlage ich vor, die dtypeAnzahl aller anderen Spalten entsprechend festzulegen (Hinweis: pd.to_numeric, pd.to_datetime usw.), und es objectverbleiben Spalten mit einem d- Typ, die Ihre kategorialen Spalten sein sollten.

Die Parameterspalten pd.get_dummies lauten standardmäßig wie folgt:

columns : list-like, default None
    Column names in the DataFrame to be encoded.
    If `columns` is None then all the columns with
    `object` or `category` dtype will be converted.
Julien Marrec
quelle
2

Um Typen mehrerer Spalten gleichzeitig zu konvertieren, würde ich Folgendes verwenden:

df2 = df.select_dtypes(include = ['type_of_insterest'])

df2[df2.columns].apply(lambda x:x.astype('category'))

Dann würde ich mich ihnen wieder anschließen original df.

Cyber-Mathematik
quelle
Ich denke df2[df2.columns] = df2[df2.columns].astype('category')macht das gleiche, nein apply, nein lambda.
Paulperry