Konwertuj dane kategoryczne w ramce danych pandy

103

Mam ramkę danych z tego typu danymi (za dużo kolumn):

col1        int64
col2        int64
col3        category
col4        category
col5        category

Kolumny wyglądają tak:

Name: col3, dtype: category
Categories (8, object): [B, C, E, G, H, N, S, W]

Chcę przekonwertować wszystkie wartości w kolumnach na liczbę całkowitą w następujący sposób:

[1, 2, 3, 4, 5, 6, 7, 8]

Rozwiązałem to dla jednej kolumny w ten sposób:

dataframe['c'] = pandas.Categorical.from_array(dataframe.col3).codes

Teraz mam dwie kolumny w mojej ramce danych - starą col3i nową ci muszę usunąć stare kolumny.

To zła praktyka. To działa, ale w mojej ramce danych jest wiele kolumn i nie chcę tego robić ręcznie.

Jak to pythonowe i po prostu sprytnie?

Gilaztdinov Rustam
źródło

Odpowiedzi:

166

Po pierwsze, aby przekonwertować kolumnę kategoryczne do swoich kodów numerycznych, można zrobić to łatwiej z: dataframe['c'].cat.codes.
Ponadto możliwe jest automatyczne wybranie wszystkich kolumn o określonym typie w ramce danych za pomocą select_dtypes. W ten sposób możesz zastosować powyższą operację na wielu i automatycznie wybranych kolumnach.

Najpierw wykonuję przykładową ramkę danych:

In [75]: df = pd.DataFrame({'col1':[1,2,3,4,5], 'col2':list('abcab'),  'col3':list('ababb')})

In [76]: df['col2'] = df['col2'].astype('category')

In [77]: df['col3'] = df['col3'].astype('category')

In [78]: df.dtypes
Out[78]:
col1       int64
col2    category
col3    category
dtype: object

Następnie używając select_dtypesdo zaznaczenia kolumn, a następnie stosując .cat.codessię do każdej z tych kolumn, można uzyskać następujący wynik:

In [80]: cat_columns = df.select_dtypes(['category']).columns

In [81]: cat_columns
Out[81]: Index([u'col2', u'col3'], dtype='object')

In [83]: df[cat_columns] = df[cat_columns].apply(lambda x: x.cat.codes)

In [84]: df
Out[84]:
   col1  col2  col3
0     1     0     0
1     2     1     1
2     3     2     0
3     4     0     1
4     5     1     1
joris
źródło
14
czy istnieje prosty sposób na uzyskanie odwzorowania między kodem kategorii a wartościami ciągu kategorii?
Allan Ruin
5
Możesz użyć: df['col2'].cat.categoriesna przykład.
ogrisel
13
Zwracając uwagę każdemu, kto jest zaniepokojony, że będzie NaNto wyjątkowo -1
mapowane
2
Uwielbiam 2 wkładki;)
Jose A
Uważaj, jeśli kategoria jest uporządkowana (porządkowa), wówczas kody numeryczne zwracane przez cat.codesmogą NIE być tymi, które widzisz w serii!
paulperry
27

To działa dla mnie:

pandas.factorize( ['B', 'C', 'D', 'B'] )[0]

Wynik:

[0, 1, 2, 0]
scottlittle
źródło
20

Jeśli obawiałeś się tylko tego, że tworzysz dodatkową kolumnę i usuwasz ją później, po prostu dun użyj najpierw nowej kolumny.

dataframe = pd.DataFrame({'col1':[1,2,3,4,5], 'col2':list('abcab'),  'col3':list('ababb')})
dataframe.col3 = pd.Categorical.from_array(dataframe.col3).codes

Skończyłeś. Teraz, gdy Categorical.from_arrayjest przestarzałe, użyj Categoricalbezpośrednio

dataframe.col3 = pd.Categorical(dataframe.col3).codes

Jeśli potrzebujesz również mapowania z powrotem z indeksu na etykietę, istnieje jeszcze lepszy sposób na to samo

dataframe.col3, mapping_index = pd.Series(dataframe.col3).factorize()

sprawdź poniżej

print(dataframe)
print(mapping_index.get_loc("c"))
Abhishek
źródło
11

Tutaj należy przekonwertować wiele kolumn. Więc jedno podejście, którego użyłem, to ...

for col_name in df.columns:
    if(df[col_name].dtype == 'object'):
        df[col_name]= df[col_name].astype('category')
        df[col_name] = df[col_name].cat.codes

Spowoduje to konwersję wszystkich kolumn typu łańcuchowego / obiektowego na kategoryczne. Następnie stosuje kody do każdego typu kategorii.

shantanu pathak
źródło
3

Aby przekonwertować dane kategoryczne w kolumnie C danych zestawu danych , musimy wykonać następujące czynności:

from sklearn.preprocessing import LabelEncoder 
labelencoder= LabelEncoder() #initializing an object of class LabelEncoder
data['C'] = labelencoder.fit_transform(data['C']) #fitting and transforming the desired categorical column.
Fatemeh Asgarinejad
źródło
2

To, co robię, replaceceni.

Lubię to-

df['col'].replace(to_replace=['category_1', 'category_2', 'category_3'], value=[1, 2, 3], inplace=True)

W ten sposób, jeśli colkolumna zawiera wartości jakościowe, zostaną one zastąpione wartościami liczbowymi.

prawda
źródło
1

@ Quickbeam2k1, patrz poniżej -

dataset=pd.read_csv('Data2.csv')
np.set_printoptions(threshold=np.nan)
X = dataset.iloc[:,:].values

Używanie sklearn wprowadź opis obrazu tutaj

from sklearn.preprocessing import LabelEncoder
labelencoder_X=LabelEncoder()
X[:,0] = labelencoder_X.fit_transform(X[:,0])
Prohadoopian
źródło
3
Dlaczego po prostu nie poprawiłeś poprzedniej odpowiedzi? Zaskakujące jest, że używasz fit_transformteraz zamiast transform_fiti poprawiłeś definicję labelencodera. Dlaczego używasz iloc[:,:]? to jest bezużyteczne. Jaki jest powód tego obrazu? Na wypadek, gdybyś chciał udowodnić mnie i @theGtknerd skrzywdzić, zawiodłeś.
Quickbeam2k1
0

W przypadku określonej kolumny, jeśli nie zależy Ci na kolejności, użyj tego

df['col1_num'] = df['col1'].apply(lambda x: np.where(df['col1'].unique()==x)[0][0])

Jeśli zależy Ci na kolejności, podaj je jako listę i użyj tego

df['col1_num'] = df['col1'].apply(lambda x: ['first', 'second', 'third'].index(x))
SaTa
źródło