Masowa konwersja kolumn kategorialnych w Pandach (bez kodowania pojedynczego)

12

Mam ramkę danych pand z mnóstwem kategorycznych kolumn, które planuję wykorzystać w drzewie decyzyjnym w scikit-learn. Muszę przekonwertować je na wartości liczbowe (nie jeden gorący wektor). Mogę to zrobić za pomocą LabelEncoder z scikit-learn. Problem polega na tym, że jest ich zbyt wiele i nie chcę ich konwertować ręcznie.

Jaki byłby łatwy sposób zautomatyzować ten proces.

użytkownik1700890
źródło
Funkcja get_dummies w pandach może ci pomóc. Sprawdź dokumentację tutaj, aby uzyskać więcej informacji . Myślę, że doskonale obejmuje ten przypadek użycia i możesz dalej poprawiać zachowanie, dostarczając niestandardowe prefiksy.
hssay

Odpowiedzi:

11

Jeśli twoje kategorie są obecnie znakami / obiektami, możesz użyć czegoś takiego:

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

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

Jeśli chcesz wrócić do kategorii, stworzę słownik, aby zapisać kodowanie; coś jak:

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])

Użycie mcve Juliena wyświetli:

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
źródło
Twój kod do znalezienia objectkolumn jest użyteczny.
javadba
6

Najpierw stwórzmy mcve do zabawy:

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

Teraz możemy użyć pd.get_dummies do zakodowania pierwszych trzech kolumn.

Zauważ, że używam tego drop_firstparametru, ponieważ N-1manekiny są wystarczające, aby w pełni opisać Nmożliwości (np .: jeśli a_Var2i a_Var3są 0, to jest a_Var1). Również mam konkretnie określenie kolumn, ale nie muszą, jak to będzie kolumn dtype albo objectlub categorical(więcej poniżej).

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

W konkretnej aplikacji będziesz musiał podać listę kategorii, które są kategoryczne, lub będziesz musiał wnioskować, które kolumny są kategoryczne.

Najlepszy scenariusz Twój dataframe ma już tych kolumn z dtype=categoryi można przejść columns=df.columns[df.dtypes == 'category']do get_dummies.

W przeciwnym razie proponuję ustawienie dtypewszystkich pozostałych kolumn odpowiednio (wskazówka: pd.to_numeric, pd.to_datetime itp.), A pozostaniesz z kolumnami, które mają typ dtype objecti powinny to być twoje kolumny kategoryczne.

Domyślne kolumny parametrów pd.get_dummies są następujące:

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
źródło
2

Aby przekonwertować typy wielu kolumn jednocześnie, użyłbym czegoś takiego:

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

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

Potem dołączyłem do nich z powrotem original df.

cybermatyka
źródło
Myślę, że df2[df2.columns] = df2[df2.columns].astype('category')robi to samo, nie apply, nie lambda.
paulperry