Załóżmy, że mam df
co ma kolumny 'ID', 'col_1', 'col_2'
. I definiuję funkcję:
f = lambda x, y : my_function_expression
.
Teraz chcę zastosować f
do df
„s dwie kolumny 'col_1', 'col_2'
do elementu mądry obliczy nową kolumnę 'col_3'
, trochę jak:
df['col_3'] = df[['col_1','col_2']].apply(f)
# Pandas gives : TypeError: ('<lambda>() takes exactly 2 arguments (1 given)'
Jak zrobić ?
** Dodaj próbkę szczegółową jak poniżej ***
import pandas as pd
df = pd.DataFrame({'ID':['1','2','3'], 'col_1': [0,2,3], 'col_2':[1,4,5]})
mylist = ['a','b','c','d','e','f']
def get_sublist(sta,end):
return mylist[sta:end+1]
#df['col_3'] = df[['col_1','col_2']].apply(get_sublist,axis=1)
# expect above to output df as below
ID col_1 col_2 col_3
0 1 0 1 ['a', 'b']
1 2 2 4 ['c', 'd', 'e']
2 3 3 5 ['d', 'e', 'f']
f
się dziejeOdpowiedzi:
Oto przykład użycia
apply
w ramce danych, z którą dzwonięaxis = 1
.Zauważ, że różnica polega na tym, że zamiast próbować przekazać dwie wartości do funkcji
f
, przepisz funkcję, aby zaakceptować obiekt serii pandy, a następnie indeksuj serię, aby uzyskać potrzebne wartości.W zależności od przypadku użycia czasem pomocne jest utworzenie
group
obiektu pandy , a następnie użycieapply
go w grupie.źródło
sum
została pomyślnie rozwiązana za pomocą dowolnej z sugerowanych dotychczas metod.df
zdefiniowany obiekt, inne podejście (z równoważnymi wynikami) todf.apply(lambda x: x[0] + x[1], axis = 1)
.W Pandach istnieje czysty, jednowierszowy sposób:
Pozwala
f
to być funkcją zdefiniowaną przez użytkownika z wieloma wartościami wejściowymi i używa (bezpiecznych) nazw kolumn zamiast (niebezpiecznych) indeksów numerycznych w celu uzyskania dostępu do kolumn.Przykład z danymi (na podstawie oryginalnego pytania):
Wyjście
print(df)
:Jeśli nazwy kolumn zawierają spacje lub mają wspólną nazwę z istniejącym atrybutem ramki danych, możesz indeksować za pomocą nawiasów kwadratowych:
źródło
axis=1
a twoja kolumna jest nazywananame
, tak naprawdę nie zwróci danych kolumny, aleindex
. Podobne do uzyskiwanianame
wgroupby()
. Rozwiązałem to, zmieniając nazwę mojej kolumny..loc
w tym przykładzie istniał jakiś powód . Może to być potrzebne, jeśli dostosujesz to do innego ustawienia problemu (np. Praca z plasterkami).Prostym rozwiązaniem jest:
źródło
Ciekawe pytanie! moja odpowiedź jak poniżej:
Wynik:
Zmieniłem nazwę kolumny na ID, J1, J2, J3, aby zapewnić ID <J1 <J2 <J3, więc kolumna wyświetla się we właściwej kolejności.
Jeszcze jedna krótka wersja:
źródło
Metoda, której szukasz, to Series.combine. Wydaje się jednak, że należy zachować ostrożność przy typach danych. W twoim przykładzie zadzwoniłbyś (tak jak ja podczas testowania odpowiedzi) naiwnie
Powoduje to jednak błąd:
Domyślam się, że oczekuje, że wynik będzie tego samego typu, co seria wywołująca metodę (tutaj df.col_1). Jednak następujące prace:
źródło
Sposób, w jaki napisałeś, wymaga dwóch danych wejściowych. Jeśli spojrzysz na komunikat o błędzie, to znaczy, że nie podajesz dwóch danych wejściowych dla f, tylko jedno. Komunikat o błędzie jest poprawny.
Niedopasowanie jest spowodowane tym, że df [['col1', 'col2']] zwraca pojedynczą ramkę danych z dwiema kolumnami, a nie dwiema osobnymi kolumnami.
Musisz zmienić swój f, aby wymagał pojedynczego wejścia, zachowaj powyższą ramkę danych jako wejście, a następnie podziel ją na x, y wewnątrz ciała funkcji. Następnie zrób wszystko, czego potrzebujesz i zwróć jedną wartość.
Potrzebujesz tej sygnatury funkcji, ponieważ składnia to .apply (f) Więc f musi wziąć jedną rzecz = ramkę danych, a nie dwie rzeczy, czego oczekuje twój obecny f.
Ponieważ nie podałeś jeszcze części f, nie mogę pomóc w szczegółach - ale powinno to dać wyjście bez fundamentalnej zmiany kodu lub użycia innych metod zamiast zastosowania
źródło
Zagłosuję na np. Wektor. Pozwala strzelać ponad x liczby kolumn i nie zajmować się ramką danych w funkcji, więc świetnie nadaje się do funkcji, których nie kontrolujesz lub nie robisz czegoś takiego jak wysyłanie 2 kolumn i stałej do funkcji (np. Col_1, col_2, 'bla').
źródło
Zwracanie listy
apply
jest niebezpieczną operacją, ponieważ nie można zagwarantować, że wynikowy obiekt będzie Serią lub ramką danych. W niektórych przypadkach mogą pojawić się wyjątki. Przejdźmy przez prosty przykład:Istnieją trzy możliwe wyniki przy zwrocie listy
apply
1) Jeśli długość zwracanej listy nie jest równa liczbie kolumn, zwracana jest seria list.
2) Gdy długość zwracanej listy jest równa liczbie kolumn, wówczas zwracana jest ramka danych i każda kolumna otrzymuje odpowiednią wartość z listy.
3) Jeśli długość zwracanej listy jest równa liczbie kolumn dla pierwszego wiersza, ale ma co najmniej jeden wiersz, w którym lista ma inną liczbę elementów niż liczba kolumn, wywoływany jest błąd ValueError.
Rozwiązanie problemu bez zastosowania
Korzystanie
apply
z osi = 1 jest bardzo wolne. Możliwe jest uzyskanie znacznie lepszej wydajności (szczególnie w przypadku większych zestawów danych) za pomocą podstawowych metod iteracyjnych.Utwórz większą ramkę danych
Czasy
@Thomas answer
źródło
Jestem pewien, że nie jest to tak szybkie, jak rozwiązania wykorzystujące operacje Pandas lub Numpy, ale jeśli nie chcesz przepisać swojej funkcji, możesz użyć mapy. Wykorzystując oryginalne przykładowe dane -
W ten sposób moglibyśmy przekazać dowolną liczbę argumentów do funkcji. Wynik jest tym, czego chcieliśmy
źródło
apply
zaxis=1
Mój przykład na twoje pytania:
źródło
Jeśli masz duży zestaw danych, możesz użyć łatwego, ale szybszego (czasu wykonania) sposobu, aby to zrobić za pomocą przełącznika szybszego:
źródło
Przypuszczam, że nie chcesz zmieniać
get_sublist
funkcji, a po prostu chcesz użyćapply
metody DataFrame do wykonania zadania. Aby uzyskać pożądany rezultat, napisałem dwie funkcje pomocy:get_sublist_list
iunlist
. Jak sugeruje nazwa funkcji, najpierw uzyskaj listę podlisty, a następnie wypakuj podlistę z tej listy. Na koniec musimy wywołaćapply
funkcję, aby następnie zastosować te dwie funkcje dodf[['col_1','col_2']]
DataFrame.Jeśli nie użyjesz
[]
do załączeniaget_sublist
funkcji,get_sublist_list
funkcja zwróci prostą listę, podniesie sięValueError: could not broadcast input array from shape (3) into shape (2)
, jak wspomniał @Ted Petrou.źródło