Regularnie wykonuję operacje na pandach na ramkach danych w ponad 15 milionach wierszy i chciałbym mieć dostęp do wskaźnika postępu dla poszczególnych operacji.
Czy istnieje tekstowy wskaźnik postępu dla operacji pandy podziel-zastosuj-połącz?
Na przykład w czymś takim:
df_users.groupby(['userID', 'requestDate']).apply(feature_rollup)
gdzie feature_rollup
jest dość skomplikowaną funkcją, która pobiera wiele kolumn DF i tworzy nowe kolumny użytkowników różnymi metodami. Te operacje mogą zająć trochę czasu w przypadku dużych ramek danych, więc chciałbym wiedzieć, czy możliwe jest wyświetlenie tekstu w notatniku iPython, który aktualizuje mnie o postępie.
Do tej pory wypróbowałem wskaźniki postępu pętli kanonicznej dla Pythona, ale nie wchodzą one w interakcję z pandami w żaden znaczący sposób.
Mam nadzieję, że jest coś, co przeoczyłem w bibliotece / dokumentacji pand, co pozwala poznać postęp kombajnu z podziałem na aplikacje. Prosta implementacja może spojrzeć na całkowitą liczbę podzbiorów ramek danych, na których działa apply
funkcja i zgłosić postęp jako ukończony ułamek tych podzbiorów.
Czy to może coś, co trzeba dodać do biblioteki?
Odpowiedzi:
Ze względu na popularne zapotrzebowanie
tqdm
dodano obsługępandas
. W przeciwieństwie do innych odpowiedzi, nie spowolni to zauważalnie pand - oto przykład dlaDataFrameGroupBy.progress_apply
:Jeśli jesteś zainteresowany tym, jak to działa (i jak zmodyfikować to dla własnych wywołań zwrotnych), zobacz przykłady na github , pełną dokumentację na pypi lub zaimportuj moduł i uruchom
help(tqdm)
.EDYTOWAĆ
Aby bezpośrednio odpowiedzieć na oryginalne pytanie, zamień:
z:
Uwaga: tqdm <= v4.8 : W przypadku wersji tqdm poniżej 4.8 zamiast tego
tqdm.pandas()
trzeba było:źródło
tqdm
został stworzony dla zwykłych iterable pierwotnie:from tqdm import tqdm; for i in tqdm( range(int(1e8)) ): pass
Obsługa pand była niedawnymfrom tqdm import tqdm_notebook; tqdm_notebook().pandas(*args, **kwargs)
tutajtqdm
wersji 5, która sprawia, że rzeczy są bardziej zmodularyzowane.Aby poprawić odpowiedź Jeffa (i mieć to jako funkcję wielokrotnego użytku).
Uwaga: zastosowanie aktualizacji procentowych postępu w linii . Jeśli twoja funkcja ma standardowe ustawienia, to nie zadziała.
Jak zwykle możesz dodać to do swoich obiektów grupowania jako metodę:
Jak wspomniano w komentarzach, nie jest to funkcja, którą podstawowe pandy byłyby zainteresowane wdrożeniem. Ale python pozwala ci tworzyć je dla wielu obiektów / metod pand (zrobienie tego wymagałoby sporo pracy ... chociaż powinieneś być w stanie uogólnić to podejście).
źródło
Jeśli potrzebujesz pomocy, jak używać tego w notatniku Jupyter / ipython, tak jak ja, oto pomocny przewodnik i źródło odpowiedniego artykułu :
Zwróć uwagę na podkreślenie w instrukcji importu dla
_tqdm_notebook
. Jak wspomniano w przywołanym artykule, rozwój jest na późnym etapie beta.źródło
Dla każdego, kto chce zastosować tqdm w swoim niestandardowym kodzie równoległego pandy.
(Przez lata próbowałem zrównoleglenie niektórych bibliotek, ale nigdy nie znalazłem rozwiązania umożliwiającego zrównoleglenie w 100%, głównie dla funkcji stosującej, i zawsze musiałem wracać po mój „ręczny” kod).
df_multi_core - to ten, do którego dzwonisz. Akceptuje:
_df_split - jest to wewnętrzna funkcja pomocnicza, która musi być umieszczona globalnie względem działającego modułu (Pool.map jest „zależna od miejsca”), w przeciwnym razie zlokalizowałbym ją wewnętrznie.
oto kod z mojego sedna (dodam tam więcej testów funkcji pand):
Poniżej znajduje się kod testowy dla równoległego zastosowania z tqdm „progress_apply”.
W danych wyjściowych można zobaczyć 1 pasek postępu do pracy bez równoległości i paski postępu na rdzeń podczas pracy z równoległością. Występuje niewielki problem i czasami reszta rdzeni pojawia się od razu, ale nawet wtedy myślę, że jest to przydatne, ponieważ otrzymujesz statystyki postępu na rdzeń (it / s i całkowite rekordy, na przykład)
Dziękuję @abcdaa za tę wspaniałą bibliotekę!
źródło
try: splits = np.array_split(df[subset], njobs) except ValueError: splits = np.array_split(df, njobs)
powodu wyjątku KeyError zamiast ValueError, zmień na Exception, aby obsłużyć wszystkie przypadki.Możesz to łatwo zrobić za pomocą dekoratora
następnie po prostu użyj funkcji modified_function (i zmień, kiedy chcesz ją wydrukować)
źródło
logged_apply(g, func)
funkcję, w której miałbyś dostęp do zamówienia i mógłbyś logować od początku.Zmieniłem odpowiedź Jeffa, dodając sumę, abyś mógł śledzić postęp i zmienną, aby po prostu wydrukować każdą iterację X (to faktycznie znacznie poprawia wydajność, jeśli "print_at" jest rozsądnie wysoki)
funkcja clear_output () pochodzi z
jeśli nie na IPythonie, odpowiedź Andy'ego Haydena robi to bez niej
źródło