2016-09-08 21 views
8

pandas.factorize koduje wartości wejściowe jako typ wyliczeniowy lub zmienną kategoryczną.pandas.factorize na całej ramce danych

Ale jak mogę łatwo i wydajnie przekonwertować wiele kolumn ramki danych? A co z odwrotnym odwzorowaniem?

Przykład: Ta ramka danych zawiera kolumny z wartościami ciągu, np. "Typ 2", które chciałbym przekonwertować na wartości liczbowe - i ewentualnie przetłumaczyć je później.

enter image description here

Odpowiedz

18

Można użyć apply jeśli trzeba factorize każdą kolumnę oddzielnie:

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 

Jeśli potrzebujesz do tej samej wartości ciągu taka sama numeryczna jednego:

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 

Jeśli chcesz zastosować tę funkcję tylko do niektóre kolumny, użyj podzbiór:

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 

rozwiązanie z 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 

przełożyć je z powrotem jest możliwe poprzez map przez dict, gdzie trzeba usunąć duplikaty przez 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 
+0

A jeśli nie chcesz zastosować funkcję do każdej kolumny, po prostu do listy kolumn? – clstaudt

+0

Możesz użyć podzbioru, daj mi sekundę. – jezrael

0

Chciałbym przekierować moją odpowiedź: https://stackoverflow.com/a/32011969/1694714

Old odpowiedź

Innym czytelne rozwiązanie tego problemu, gdy chcesz zachować kategorie spójne w całej Powstały DataFrame korzysta wymienić:

def categorise(df): 
    categories = {k: v for v, k in enumerate(df.stack().unique())} 
    return df.replace(categories) 

Wykonuje nieco gorsze niż przykładowo przez @ jezrael, ale łatwiejsze do odczytania. Ponadto może być lepiej eskalowana w przypadku większych zestawów danych. Mogę przeprowadzić odpowiednie testy, jeśli ktoś jest zainteresowany.

2

Znalazłem również tę odpowiedź bardzo pomocne: https://stackoverflow.com/a/20051631/4643212

starałem się przyjmować wartości z istniejącej kolumny w Pandy DataFrame (lista adresów IP o nazwie „SrcIP”) i mapować je do wartości numerycznych w nowa kolumna (w tym przykładzie "ID").

Rozwiązanie:

df['ID'] = pd.factorize(df.SrcIP)[0] 

Wynik:

 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 
... 
Powiązane problemy