Mam słownik, który wygląda następująco: di = {1: "A", 2: "B"}
Chciałbym zastosować go do kolumny „col1” ramki danych podobnej do:
col1 col2
0 w a
1 1 2
2 2 NaN
uzyskać:
col1 col2
0 w a
1 A 2
2 B NaN
Jak najlepiej to zrobić? Z jakiegoś powodu hasła google związane z tym pokazują tylko linki o tym, jak tworzyć kolumny z nagrań i odwrotnie: - /
python
dictionary
pandas
remap
TheChymera
źródło
źródło
col```` is tuple. The error info is
nie można porównać typów 'ndarray (dtype = object)' i 'tuple' '' ''3.6.1 |Anaconda custom (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)]'
map
może być znacznie szybszy niżreplace
Jeśli słownik zawiera więcej niż kilka kluczy, użycie
map
może być znacznie szybsze niżreplace
. Istnieją dwie wersje tego podejścia, w zależności od tego, czy słownik wyczerpująco odwzorowuje wszystkie możliwe wartości (a także od tego, czy chcesz, aby niezgodności zachowywały swoje wartości lub były konwertowane na NaN):Wyczerpujące mapowanie
W takim przypadku formularz jest bardzo prosty:
Chociaż
map
najczęściej przyjmuje funkcję jako argument, może alternatywnie wziąć słownik lub serię: Dokumentacja dla Pandas.series.mapNiewyczerpujące mapowanie
Jeśli masz niewyczerpujące odwzorowanie i chcesz zachować istniejące zmienne dla niepasujących, możesz dodać
fillna
:jak w odpowiedzi @ jpp tutaj: Efektywnie zamieniaj wartości w serii pand za pomocą słownika
Benchmarki
Używanie następujących danych z pandami w wersji 0.23.1:
i testowanie z
%timeit
, wydaje się, żemap
jest około 10 razy szybsze niżreplace
.Pamiętaj, że Twoje przyspieszenie
map
różni się w zależności od danych. Największe przyspieszenie wydaje się mieć duże słowniki i wyczerpujące zamienniki. Zobacz @jpp odpowiedź (link powyżej), aby uzyskać bardziej szczegółowe wyniki testów i dyskusji.źródło
df.replace
funkcja, chociaż uporządkowana i przydatna w przypadku małych nagrań, uległa awarii po około 20 minutach działania.map
działa również na indeksie, w którym nie mogłem znaleźć sposobu, aby to zrobićreplace
W twoim pytaniu jest trochę dwuznaczności. Istnieją co najmniej
trzydwie interpretacje:di
odnoszą się do wartości indeksudi
odnoszą się dodf['col1']
wartościdi
odnoszą się do lokalizacji indeksu (nie pytanie OP, ale rzucono dla zabawy).Poniżej znajduje się rozwiązanie dla każdego przypadku.
Przypadek 1: Jeśli klucze
di
mają odnosić się do wartości indeksu, możesz użyćupdate
metody:Na przykład,
daje
Zmodyfikowałem wartości z Twojego oryginalnego postu, aby było bardziej zrozumiałe
update
. Zwróć uwagę, w jaki sposób kluczedi
są powiązane z wartościami indeksu. Kolejność wartości indeksu - to znaczy lokalizacji indeksu - nie ma znaczenia.Przypadek 2: Jeśli klucze
di
odnoszą się dodf['col1']
wartości, wówczas @DanAllan i @DSM pokazują, jak to osiągnąć za pomocąreplace
:daje
Zwróć uwagę, jak w tym przypadku klucze w
di
zostały zmienione, aby pasowały do wartości wdf['col1']
.Przypadek 3: Jeśli klucze
di
odnoszą się do lokalizacji indeksu, możesz użyćod
daje
Tutaj zmieniono pierwszy i trzeci wiersz, ponieważ klucze w
di
są0
i2
, które przy indeksowaniu opartym na 0 w Pythonie odnoszą się do pierwszej i trzeciej lokalizacji.źródło
replace
jest równie dobre, a może lepsze słowo na to, co się tutaj dzieje.update()
wydaje się trochę niechlujny w porównaniu doreplace()
, ale przynajmniej działa.Dodanie do tego pytania, jeśli kiedykolwiek masz więcej niż jedną kolumnę do zmiany mapowania w ramce danych:
Mam nadzieję, że może się przydać komuś.
Twoje zdrowie
źródło
DataFrame.replace()
, chociaż nie wiem, kiedy została dodana.DSM ma zaakceptowaną odpowiedź, ale kodowanie nie działa dla wszystkich. Oto jedna, która działa z aktualną wersją pand (0.23.4 z 8/2018):
Zobaczysz, że wygląda to tak:
Dokumenty dotyczące pandas.DataFrame.replace są tutaj .
źródło
Series.map()
wydaje się bardziej elastyczne.Lub wykonaj
apply
:Próbny:
źródło
di
dyktando jest listą? Jak zmapować tylko jedną wartość na liście?Podanie
map
jest szybsze niż zastąpienie (rozwiązanie @ JohnE), należy zachować ostrożność przyNaN
niewyczerpujących mapowaniach, w których zamierza się mapować określone wartości . Właściwa metoda w tym przypadku wymaga, abyśmask
Series, kiedy ty.fillna
, w przeciwnym razie cofniesz mapowanieNaN
.źródło
Ładne, kompletne rozwiązanie, które utrzymuje mapę twoich etykiet klas:
W ten sposób możesz w dowolnym momencie odwołać się do oryginalnej etykiety klasy z label_dict.
źródło
Jako rozszerzenie do tego, co zaproponował Nico Coallier (stosuje się do wielu kolumn) i U10-Forward (stosując metody stylu zastosuj) i podsumowując je do jednowierszowej proponuję:
.transform()
Przetwarza każdą kolumnę jako serii. W przeciwieństwie do tego,.apply()
co przekazuje kolumny zagregowane w DataFrame.W związku z tym możesz zastosować metodę serii
map()
.Wreszcie i odkryłem to zachowanie dzięki U10, możesz użyć całej serii w wyrażeniu .get (). Chyba że źle zrozumiałem jego zachowanie i przetwarza serię sekwencyjnie zamiast bitowo.
Te
.get(x,x)
rachunki dla wartości nie wspomniałeś w swoim słowniku mapowania, które byłyby uznane za Nan inaczej.map()
metodyźródło
.transform()
Przetwarza każdą kolumnę jako serii. W przeciwieństwie do tego,.apply()
co przekazuje kolumny zagregowane w DataFrame. Właśnie próbowałem,apply()
działa dobrze. Nie ma też potrzeby korzystanialoc
, wydaje się to zbyt skomplikowane.df[["col1", "col2"]].apply(lambda col: col.map(lambda elem: my_dict.get(elem, elem)))
powinien działać dobrze. Na.get(x,x)
kontach o wartości nie wspomniałeś w swoim słowniku mapowania, które byłyby uznane za Nan inaczej.map()
metody Można również wykorzystaćfillna()
później.Bardziej natywnym podejściem do pand jest zastosowanie funkcji zamiany, jak poniżej:
Po zdefiniowaniu funkcji można zastosować ją do ramki danych.
źródło