Próbuję użyć scikit-learn LabelEncoder
do zakodowania pand DataFrame
etykiet ciągów. Ponieważ ramka danych ma wiele (ponad 50) kolumn, chcę uniknąć tworzenia LabelEncoder
obiektu dla każdej kolumny; Wolałbym mieć tylko jeden duży LabelEncoder
obiekt, który działa we wszystkich moich kolumnach danych.
Wrzucenie całości DataFrame
w LabelEncoder
powoduje następujący błąd. Proszę pamiętać, że używam tutaj fałszywych danych; w rzeczywistości mam do czynienia z około 50 kolumnami danych znakowanych ciągiem, więc potrzebuję rozwiązania, które nie odwołuje się do żadnej kolumny według nazwy.
import pandas
from sklearn import preprocessing
df = pandas.DataFrame({
'pets': ['cat', 'dog', 'cat', 'monkey', 'dog', 'dog'],
'owner': ['Champ', 'Ron', 'Brick', 'Champ', 'Veronica', 'Ron'],
'location': ['San_Diego', 'New_York', 'New_York', 'San_Diego', 'San_Diego',
'New_York']
})
le = preprocessing.LabelEncoder()
le.fit(df)
Traceback (ostatnie ostatnie połączenie): Plik „”, wiersz 1, w pliku ”/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/preprocessing/label.py”, wiersz 103, w dopasowaniu y = column_or_1d (y, warn = True) Plik „/Users/bbalin/anaconda/lib/python2.7/site-packages/sklearn/utils/validation.py”, wiersz 306, w column_or_1d podnieś błąd ValueError („zły kształt wejścia { 0} ". Format (kształt)) Wartość Błąd: zły kształt wejściowy (6, 3)
Wszelkie przemyślenia na temat obejścia tego problemu?
źródło
dataframe
danych ciągu. Zbieram kodowane obiekty, więc chcę uniknąć kiszenia / usuwania 50 osobnych obiektów. Zastanawiam się również, czy istnieje sposób, aby enkoder uprościł dane, tzn. Po prostu zwraca jeden wiersz z identyfikatorem dla każdej unikalnej kombinacji zmiennych w każdej kolumnie.replace
. Zobacz odpowiedź poniżejOdpowiedzi:
Możesz to jednak łatwo zrobić,
EDYCJA 2:
W scikit-learn 0.20 zalecanym sposobem jest
ponieważ OneHotEncoder obsługuje teraz wprowadzanie ciągu. Zastosowanie OneHotEncoder tylko do niektórych kolumn jest możliwe dzięki ColumnTransformer.
EDYTOWAĆ:
Ponieważ ta odpowiedź jest ponad rok temu i wygenerowała wiele pozytywnych opinii (w tym nagrodę), prawdopodobnie powinienem ją rozszerzyć.
Aby uzyskać inverse_transform i transform, musisz trochę zhakować.
Dzięki temu zachowujesz teraz wszystkie kolumny
LabelEncoder
jako słownik.źródło
df.apply(LabelEncoder().fit_transform)
?LabelBinarizer
zamiast tego i ponownie użyć słownika dla zestawu testowego? Próbowałemd = defaultdict(LabelBinarizer)
i wtedyfit = df.apply(lambda x: d[x.name].fit_transform(x))
ale jest wyjątek:Exception: Data must be 1-dimensional
. Nie jestem pewien, jak mam wyglądać wynikowy DataFrame ... może każda kolumna powinna zawierać binarne wektory.Jak wspomniano przez larsmans, LabelEncoder () przyjmuje tylko argument 1-d jako argument . To powiedziawszy, dość łatwo jest rozwinąć własny koder etykiet, który działa na wielu wybranych kolumnach i zwraca przekształconą ramkę danych. Mój kod jest częściowo oparty na doskonałym wpisie na blogu Zac Stewarta, który można znaleźć tutaj .
Tworzenie niestandardowego koder polega po prostu tworząc klasę, która jest odpowiedzią na
fit()
,transform()
ifit_transform()
metod. W twoim przypadku dobry początek może wyglądać mniej więcej tak:Załóżmy, że chcemy zakodować nasze dwa atrybuty kategoryczne (
fruit
icolor
), pozostawiając jednocześnie atrybut numerycznyweight
. Możemy to zrobić w następujący sposób:Z którego przekształca się nasz
fruit_data
zestaw danychdo
Przekazanie jej ramki danych składającej się całkowicie ze zmiennych kategorialnych i pominięcie
columns
parametru spowoduje zakodowanie każdej kolumny (która, jak sądzę, była tym, czego początkowo szukałeś):To się zmienia
do
.
Zauważ, że prawdopodobnie będzie się dusił, gdy będzie próbował zakodować atrybuty, które są już numeryczne (jeśli chcesz, dodaj trochę kodu, aby to obsłużyć).
Kolejną miłą cechą tego jest to, że możemy użyć tego niestandardowego transformatora w potoku:
źródło
Od scikit-learn 0.20 możesz używać
sklearn.compose.ColumnTransformer
isklearn.preprocessing.OneHotEncoder
:Jeśli masz tylko zmienne kategoryczne,
OneHotEncoder
bezpośrednio:Jeśli masz heterogenicznie wpisane funkcje:
Więcej opcji w dokumentacji: http://scikit-learn.org/stable/modules/compose.html#columntransformer-for-heterogeneous-data
źródło
inverse_transform()
nie jest jednak obsługiwane w ColumnTransformer. Przynajmniej nie na razie: github.com/scikit-learn/scikit-learn/issues/11463 . To duża wada dla mojej aplikacji i prawdopodobnie będzie również dla innych.Nie potrzebujemy LabelEncodera.
Możesz przekonwertować kolumny na kategorie, a następnie uzyskać ich kody. Użyłem poniższego słownika, aby zastosować ten proces do każdej kolumny i zawinąć wynik z powrotem w ramkę danych o tym samym kształcie z identycznymi indeksami i nazwami kolumn.
Aby utworzyć słownik mapowania, możesz po prostu wyliczyć kategorie, korzystając ze słownika:
źródło
to nie odpowiada bezpośrednio na twoje pytanie (na które Naputipulu Jon i PriceHardman mają fantastyczne odpowiedzi)
Jednak do celów kilku zadań klasyfikacyjnych itp. Możesz użyć
może to wprowadzić ramkę danych z danymi kategorialnymi i zwrócić ramkę danych z wartościami binarnymi. wartości zmiennych są kodowane w nazwach kolumn w wynikowej ramce danych. więcej
źródło
Zakładając, że po prostu próbujesz uzyskać
sklearn.preprocessing.LabelEncoder()
obiekt, którego można użyć do przedstawienia kolumn, wszystko, co musisz zrobić, to:W powyższym kodzie będziesz mieć unikalny numer odpowiadający każdej kolumnie. Dokładniej, będziesz miał mapowanie 1 na 1
df.columns
dlale.transform(df.columns.get_values())
. Aby uzyskać kodowanie kolumny, po prostu przekaż jele.transform(...)
. Na przykład następujące kodowanie otrzyma kodowanie dla każdej kolumny:Zakładając, że chcesz utworzyć
sklearn.preprocessing.LabelEncoder()
obiekt dla wszystkich etykiet wierszy, możesz wykonać następujące czynności:W takim przypadku najprawdopodobniej masz nieunikalne etykiety wierszy (jak pokazano w pytaniu). Aby zobaczyć, jakie klasy utworzył koder, możesz zrobić
le.classes_
. Zauważysz, że powinny mieć takie same elementy jak wset(y for x in df.get_values() for y in x)
. Jeszcze raz przekonwertuj etykietę wiersza na użycie etykiety kodowanejle.transform(...)
. Na przykład, jeśli chcesz pobrać etykietę dla pierwszej kolumny wdf.columns
tablicy i pierwszego wiersza, możesz to zrobić:Pytanie, które miałeś w swoim komentarzu, jest nieco bardziej skomplikowane, ale nadal można je zrealizować:
Powyższy kod wykonuje następujące czynności:
LabelEncoder
klasy nieobsługującej krotek jako nazwy klasy.LabelEncoder
.Teraz korzystanie z tego nowego modelu jest nieco bardziej skomplikowane. Zakładając, że chcemy wyodrębnić reprezentację tego samego elementu, którego szukaliśmy w poprzednim przykładzie (pierwsza kolumna w df.columns i pierwszy wiersz), możemy to zrobić:
Pamiętaj, że każde wyszukiwanie jest teraz ciągiem reprezentującym krotkę zawierającą (kolumnę, wiersz).
źródło
Nie,
LabelEncoder
nie robi tego. Pobiera tablice 1-d etykiet klas i tworzy tablice 1-d. Został zaprojektowany do obsługi etykiet klas w problemach klasyfikacyjnych, a nie arbitralnych danych, a każda próba zmuszenia go do innych zastosowań wymaga kodu, aby przekształcić rzeczywisty problem w rozwiązywany przez niego problem (i rozwiązanie z powrotem do pierwotnej przestrzeni).źródło
DataFrame
jednocześnie?LabelEncoder
kod i dostosuj go. Sam nie używam Pand, więc nie wiem, jak trudne to będzie.pandas
ludziom również odpowiedzieć na to pytanie - jestem pewien, że nie jestem jedyną osobą z tym wyzwaniem, więc mam nadzieję, że może istnieć gotowe rozwiązanie.Jest to półtora roku po tym fakcie, ale ja również musiałem być w stanie połączyć
.transform()
wiele kolumn ramek danych pand jednocześnie (i mieć możliwość.inverse_transform()
ich również). Rozszerza to doskonałą sugestię @PriceHardman powyżej:Przykład:
Jeśli
df
idf_copy()
sąpandas
ramkami danych typu mieszanego, możesz zastosować jeMultiColumnLabelEncoder()
dodtype=object
kolumn w następujący sposób:Możesz uzyskać dostęp do poszczególnych klas kolumn, etykiet kolumn i koderów kolumn używanych do dopasowania każdej kolumny poprzez indeksowanie:
mcle.all_classes_
mcle.all_encoders_
mcle.all_labels_
źródło
fit
metody z góry, która nie wytworzy żadnych etykiet, dopóki jej nie zastosujesz (transform
/fit_transform
) do dane.Po komentarzach do rozwiązania @PriceHardman zaproponowałbym następującą wersję klasy:
Ta klasa pasuje do enkodera na zestawie treningowym i używa dopasowanej wersji podczas transformacji. Wstępną wersję kodu można znaleźć tutaj .
źródło
Krótka droga do
LabelEncoder()
wielu kolumn zdict()
:i możesz użyć tego
le_dict
do oznaczenia Zakoduj dowolną inną kolumnę:źródło
Można to zrobić bezpośrednio w pandach i jest to odpowiednie dla wyjątkowej zdolności tej
replace
metody.Najpierw stwórzmy słownik słowników odwzorowujących kolumny i ich wartości na nowe wartości zastępcze.
Ponieważ zawsze będzie to mapowanie jeden do jednego, możemy odwrócić wewnętrzny słownik, aby uzyskać mapowanie nowych wartości z powrotem do oryginału.
Teraz możemy wykorzystać unikalną zdolność
replace
metody do pobrania zagnieżdżonej listy słowników i użycia kluczy zewnętrznych jako kolumn, a kluczy wewnętrznych jako wartości, które chcielibyśmy zastąpić.Możemy łatwo wrócić do oryginału, ponownie łącząc
replace
metodęźródło
Po wielu poszukiwaniach i eksperymentach z niektórymi odpowiedziami tutaj i gdzie indziej, myślę, że twoja odpowiedź jest tutaj :
Pozwoli to zachować nazwy kategorii w kolumnach:
źródło
Sprawdziłem kod źródłowy ( https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/preprocessing/label.py ) LabelEncoder. Oparty był na zestawie transformacji numpy, którym jest np.unique (). Ta funkcja pobiera tylko dane z tablicy 1-d. (Popraw mnie, jeśli się mylę).
Bardzo zgrubne pomysły ... najpierw określ, które kolumny wymagają LabelEncoder, a następnie przejdź przez każdą kolumnę.
Zwrócony df byłby tym po kodowaniu, a etykieta_listy pokaże, co oznaczają wszystkie te wartości w odpowiedniej kolumnie. To jest fragment skryptu przetwarzania danych, który napisałem do pracy. Daj mi znać, jeśli uważasz, że można wprowadzić dalsze usprawnienia.
EDYCJA: Po prostu chcę tutaj wspomnieć, że powyższe metody działają z ramką danych, nie tracąc tego, co najlepsze. Nie wiem, jak to działa w kierunku ramki danych zawiera brakujące dane. (Miałem problem z brakującą procedurą przed wykonaniem powyższych metod)
źródło
jeśli mamy jedną kolumnę do kodowania etykiety, a jej odwrotna transformacja jest łatwa, jak to zrobić, gdy w pythonie jest wiele kolumn
źródło
Jeśli masz numeryczne i kategoryczne oba typy danych w ramce danych Możesz użyć: tutaj X jest moją ramką danych posiadającą zarówno zmienne jakościowe, jak i liczbowe
Uwaga: Ta technika jest dobra, jeśli nie jesteś zainteresowany jej konwersją.
źródło
Korzystanie z Neuraxle
Dzięki tej metodzie, twój enkoder etykiet będzie mógł zmieścić się i przekształcić w zwykłym Pipeline do nauki scikit . Po prostu zaimportuj:
Ten sam współużytkowany koder dla kolumn:
Oto jak jeden wspólny LabelEncoder zostanie zastosowany do wszystkich danych, aby go zakodować:
Wynik:
Różne enkodery na kolumnę:
Oto, w jaki sposób zostanie zastosowany pierwszy samodzielny LabelEncoder na zwierzętach domowych, a drugi zostanie udostępniony właścicielowi kolumny i lokalizacji. Mówiąc ściślej, mamy tutaj mieszankę różnych i współdzielonych koderów etykiet:
Wynik:
źródło
Używany głównie przez @Alexander, ale musiał wprowadzić pewne zmiany -
Następnie, aby ponownie użyć w przyszłości, możesz po prostu zapisać wynik w dokumencie json, a kiedy go potrzebujesz, wczytasz go i użyjesz
.map()
funkcji takiej jak ja powyżej.źródło
Problemem jest kształt danych (ramka danych pd) przekazywanych do funkcji dopasowania. Musisz przekazać listę 1d.
źródło
Tutaj czytam plik CSV z lokalizacji iw funkcji przekazuję listę kolumn, którą chcę nadać etykiecie kod i ramkę danych, którą chcę zastosować.
źródło
Co powiesz na to?
Nie jest to najbardziej wydajny, jednak działa i jest bardzo prosty.
źródło