Jak to zrobić w pandach:
Mam funkcję extract_text_features
w jednej kolumnie tekstowej, zwracającą wiele kolumn wyjściowych. W szczególności funkcja zwraca 6 wartości.
Funkcja działa, jednak wydaje się, że nie ma żadnego poprawnego typu zwracanego (pandy DataFrame / numpy array / Python list), aby można było poprawnie przypisać dane wyjściowe df.ix[: ,10:16] = df.textcol.map(extract_text_features)
Więc myślę, że muszę wrócić do iteracji df.iterrows()
, zgodnie z tym ?
AKTUALIZACJA: Iteracja z df.iterrows()
jest co najmniej 20x wolniejsza, więc poddałem się i podzieliłem funkcję na sześć różnych .map(lambda ...)
wywołań.
AKTUALIZACJA 2: to pytanie zostało zadane około v0.11.0 . Dlatego też większość pytań i odpowiedzi nie jest zbyt trafna.
df.ix[: ,10:16]
. Myślę, że będziesz musiał domerge
swoich funkcji do zestawu danych.apply
Odpowiedzi:
Opierając się na odpowiedzi użytkownika 1827356, możesz wykonać zadanie w jednym przebiegu, używając
df.merge
:EDYCJA: Należy pamiętać o ogromnym zużyciu pamięci i niskiej prędkości: https://ys-l.github.io/posts/2015/08/28/how-not-to-use-pandas-apply/ !
źródło
Zwykle robię to za pomocą
zip
:źródło
temp = list(zip(*df['num'].map(powers))); for i, c in enumerate(columns): df[c] = temp[c]
for i, c in enumerate(columns): df[c] = temp[i]
. Dzięki temu naprawdę mam celenumerate
: Dzip(*df['col'].map(function))
jest prawdopodobnie dobrym rozwiązaniem.Tak robiłem w przeszłości
Edycja dla kompletności
źródło
df[['col1', 'col2']] = df['col3'].apply(lambda x: pd.Series('val1', 'val2'))
Jest to poprawny i najłatwiejszy sposób na osiągnięcie tego w 95% przypadków użycia:
źródło
pd.Series({k:v})
i serializować przypisanie kolumny jak w odpowiedzi Ewana?W 2018 używam
apply()
z argumentamiresult_type='expand'
źródło
pd.Series
co zawsze jest miłe zdf.apply
zwraca adict
, wyjdą kolumny o nazwach zgodnych z kluczami.Po prostu użyj
result_type="expand"
źródło
Podsumowanie: Jeśli chcesz utworzyć tylko kilka kolumn, użyj
df[['new_col1','new_col2']] = df[['data1','data2']].apply( function_of_your_choosing(x), axis=1)
W tym rozwiązaniu liczba tworzonych nowych kolumn musi być równa liczbie kolumn używanych jako dane wejściowe do funkcji .apply (). Jeśli chcesz zrobić coś innego, spójrz na inne odpowiedzi.
Detale Załóżmy, że masz dwukolumnową ramkę danych. Pierwsza kolumna to wzrost osoby, która ma 10 lat; drugi to wzrost osoby, która ma 20 lat.
Załóżmy, że musisz obliczyć zarówno średnią wysokość każdej osoby, jak i sumę wysokości każdej osoby. To dwie wartości na każdy wiersz.
Możesz to zrobić za pomocą następującej funkcji, która zostanie wkrótce zastosowana:
Możesz użyć tej funkcji w następujący sposób:
(Dla jasności: ta funkcja wprowadzania pobiera wartości z każdego wiersza w podzestawowej ramce danych i zwraca listę.)
Jeśli jednak to zrobisz:
utworzysz 1 nową kolumnę, która zawiera listy [średnia, suma], których prawdopodobnie chcesz uniknąć, ponieważ wymagałoby to kolejnej Lambda / Apply.
Zamiast tego chcesz rozbić każdą wartość na osobną kolumnę. Aby to zrobić, możesz utworzyć dwie kolumny jednocześnie:
źródło
df["mean"], df["sum"] = df[['height_at_age_10','height_at_age_20']] .apply(mean_and_sum(x),axis=1)
return pd.Series([mean,sum])
Dla mnie to zadziałało:
Wpisz df
Funkcjonować
Utwórz 2 nowe kolumny:
Wynik:
źródło
Szukałem kilku sposobów na zrobienie tego, a pokazana tutaj metoda (zwracanie serii pand) nie wydaje się być najbardziej wydajna.
Jeśli zaczniemy od dużej ramki danych losowych:
Przykład pokazany tutaj:
Alternatywna metoda:
Według moich obliczeń, o wiele bardziej wydajne jest pobranie serii krotek, a następnie przekonwertowanie ich na ramkę danych. Chciałbym usłyszeć, jak ludzie myślą, jeśli w mojej pracy wystąpi błąd.
źródło
Przyjęte rozwiązanie będzie bardzo powolne dla wielu danych. Rozwiązanie z największą liczbą głosów upvotes jest trochę trudne do odczytania, a także powolne w przypadku danych liczbowych. Jeśli każdą nową kolumnę można obliczyć niezależnie od innych, po prostu przypisałbym każdą z nich bezpośrednio, bez użycia
apply
.Przykład z fałszywymi danymi postaci
Utwórz 100 000 ciągów w ramce danych
Powiedzmy, że chcieliśmy wyodrębnić niektóre funkcje tekstu, tak jak w pierwotnym pytaniu. Na przykład wyodrębnijmy pierwszy znak, policzmy występowanie litery „e” i wielką frazę.
Czasy
Zaskakujące jest to, że można uzyskać lepszą wydajność, zapętlając każdą wartość
Kolejny przykład z fałszywymi danymi liczbowymi
Utwórz 1 milion liczb losowych i przetestuj
powers
funkcję z góry.Przypisanie każdej kolumny jest 25 razy szybsze i bardzo czytelne:
Udzieliłem podobnej odpowiedzi, podając więcej szczegółów na temat tego, dlaczego
apply
zazwyczaj nie jest to dobra droga.źródło
Opublikowałem tę samą odpowiedź w dwóch innych podobnych pytaniach. Preferuję to, aby zawijać zwracane wartości funkcji w szeregu:
A następnie użyj zastosować w następujący sposób, aby utworzyć osobne kolumny:
źródło
możesz zwrócić cały wiersz zamiast wartości:
gdzie funkcja zwraca wiersz
źródło
extract_text_features
do każdej kolumny df, tylko do kolumny tekstowejdf.textcol
To zadziałało dla mnie. Nowa kolumna zostanie utworzona na podstawie przetworzonych danych starych kolumn.
źródło