Pracuję z biblioteką pandy i chcę dodać dwie nowe kolumny do ramki danych df
z n kolumnami (n> 0).
Te nowe kolumny wynikają z zastosowania funkcji do jednej z kolumn w ramce danych.
Funkcja do zastosowania jest następująca:
def calculate(x):
...operate...
return z, y
Jedną z metod tworzenia nowej kolumny dla funkcji zwracającej tylko wartość jest:
df['new_col']) = df['column_A'].map(a_function)
Więc to, czego chcę i próbowałem bezskutecznie (*), to coś takiego:
(df['new_col_zetas'], df['new_col_ys']) = df['column_A'].map(calculate)
Jaki mógłby być najlepszy sposób na osiągnięcie tego? Zeskanowałem dokumentację bez pojęcia.
** df['column_A'].map(calculate)
zwraca serię pand, każdy element składający się z krotki z, y. Próba przypisania tego do dwóch kolumn ramek danych generuje błąd ValueError. *
Moim zdaniem najlepsza odpowiedź jest błędna. Miejmy nadzieję, że nikt nie importuje masowo wszystkich pand do swojej przestrzeni nazw z
from pandas import *
. Ponadtomap
metoda powinna być zarezerwowana dla tych czasów, gdy przekazujesz jej słownik lub serię. Może przyjąć funkcję, ale do tegoapply
służy.Jeśli więc musisz zastosować powyższe podejście, napisałbym to w ten sposób
Właściwie nie ma powodu, aby używać tutaj zip. Możesz to po prostu zrobić:
Ta druga metoda jest również znacznie szybsza w przypadku większych ramek DataFrame
DataFrame utworzona z 300 000 wierszy
60x szybciej niż zip
Ogólnie rzecz biorąc, unikaj stosowania aplikacji
Stosowanie jest ogólnie niewiele szybsze niż iterowanie po liście w Pythonie. Przetestujmy wydajność pętli for, aby zrobić to samo, co powyżej
Jest to więc dwukrotnie wolniejsze, co nie jest straszną regresją wydajności, ale jeśli zcytonujemy powyższe, otrzymamy znacznie lepszą wydajność. Zakładając, że używasz ipython:
Bezpośrednie przypisywanie bez zastosowania
Możesz uzyskać jeszcze większą poprawę szybkości, jeśli używasz bezpośrednich operacji wektoryzowanych.
Wykorzystuje to niezwykle szybkie operacje wektoryzacji NumPy zamiast naszych pętli. Mamy teraz 30-krotne przyspieszenie w stosunku do oryginału.
Najprostszy test szybkości z
apply
Powyższy przykład powinien jasno pokazać, jak wolno
apply
może być, ale właśnie dlatego jego wyjątkowo jasny, spójrzmy na najbardziej podstawowy przykład. Wyrównajmy do kwadratu serię 10 milionów liczb z zastosowaniem i bez zastosowaniaBez aplikacji jest 50x szybsze
źródło
applymap
przypadku, gdy musisz zaimplementować określoną funkcję do każdego elementu ramki danych?func(series)
zamiast,series.apply(func)
ma zastosowanie tylko wtedy, gdy funkcja jest w całości zdefiniowana przy użyciu operacji, które zachowują się podobnie zarówno na indywidualnej wartości, jak i na serii. Tak jest w przykładzie w pierwszej odpowiedzi, ale tak nie jest w pytaniu PO, który pyta bardziej ogólnie o zastosowanie funkcji do kolumn. 1/2DataFrame({'a': ['Aaron', 'Bert', 'Christopher'], 'b': ['Bold', 'Courageous', 'Distrusted']})
icalc
jest:def calc(x): return x[0], len(x)
totdf.a.apply(calc))
icalc(tdf.a)
zwraca bardzo różne rzeczy.