Warunkowe zamień pandy


123

Mam DataFrame i chcę zamienić wartości w określonej kolumnie, które przekraczają wartość zerem. Myślałem, że jest to sposób na osiągnięcie tego:

df[df.my_channel > 20000].my_channel = 0

Jeśli skopiuję kanał do nowej ramki danych, to proste:

df2 = df.my_channel 

df2[df2 > 20000] = 0

Robi dokładnie to, czego chcę, ale wydaje się, że nie działa z kanałem jako częścią oryginalnej ramki DataFrame.


Znalazłem to, czego myślę, że szukałeś tutaj .
mokre stopy

Odpowiedzi:


181

.ixindeksator działa dobrze dla pand w wersji wcześniejszej niż 0.20.0, ale od pandy 0.20.0 .ixindeksator jest przestarzały , więc należy go unikać. Zamiast tego możesz użyć indeksatorów .loclub iloc. Możesz rozwiązać ten problem poprzez:

mask = df.my_channel > 20000
column_name = 'my_channel'
df.loc[mask, column_name] = 0

Lub w jednej linii

df.loc[df.my_channel > 20000, 'my_channel'] = 0

maskpomaga wybrać wiersze, w których df.my_channel > 20000jest True, podczas gdy df.loc[mask, column_name] = 0ustawia wartość 0 na wybrane wiersze, w których znajdują się maskblokady w kolumnie o nazwie column_name.

Aktualizacja: w tym przypadku należy użyć, locponieważ jeśli go użyjesz iloc, otrzymasz NotImplementedErrorinformację, że indeksowanie boolowskie oparte na iLocation na typie całkowitym nie jest dostępne .


81

Próbować

df.loc[df.my_channel > 20000, 'my_channel'] = 0

Uwaga: Ponieważ v0.20.0, ix została zaniechana na korzyść loc/ iloc.


8
Dziękuję Ci. Znalazłem również własne rozwiązanie, które było: df.my_channel [df.my_channel> 20000] = 0
BMichell,

2
@BMichell Myślę, że twoje rozwiązanie może zacząć dawać ostrzeżenia w 0.13, nie miałem jeszcze szansy spróbować
lowtech

błąd wydajności: /opt/anaconda3/envs/python35/lib/python3.5/site-packages/ipykernel_launcher.py:1: SettingWithCopyWarning: Próba ustawienia wartości na kopii wycinka z DataFrame Zapoznaj się z zastrzeżeniami w dokumentacja: pandas.pydata.org/pandas-docs/stable/… "" "Punkt wejścia do uruchomienia jądra IPython.
Rutger Hofste

@RutgerHofste dzięki za wspomnienie o tym, kolejny argument nigdy nie korzysta z Pythona3
lowtech

34

np.where funkcja działa w następujący sposób:

df['X'] = np.where(df['Y']>=50, 'yes', 'no')

W twoim przypadku chciałbyś:

import numpy as np
df['my_channel'] = np.where(df.my_channel > 20000, 0, df.my_channel)

19

Powodem, dla którego oryginalna ramka danych nie jest aktualizowana, jest to, że indeksowanie łańcuchowe może spowodować zmodyfikowanie kopii zamiast widoku ramki danych. W docs dać tej rady:

Podczas ustawiania wartości w obiekcie pandy należy zachować ostrożność, aby uniknąć tak zwanego indeksowania łańcuchowego.

Masz kilka alternatyw: -

loc + Indeksowanie logiczne

loc może służyć do ustawiania wartości i obsługuje maski boolowskie:

df.loc[df['my_channel'] > 20000, 'my_channel'] = 0

mask + Indeksowanie logiczne

Do swojej serii możesz przypisać:

df['my_channel'] = df['my_channel'].mask(df['my_channel'] > 20000, 0)

Możesz też zaktualizować swoją serię na miejscu:

df['my_channel'].mask(df['my_channel'] > 20000, 0, inplace=True)

np.where + Indeksowanie logiczne

Państwo może używać NumPy przypisując swój oryginalnej serii, gdy warunek nie spełnione; jednak pierwsze dwa rozwiązania są bardziej przejrzyste, ponieważ jawnie zmieniają tylko określone wartości.

df['my_channel'] = np.where(df['my_channel'] > 20000, 0, df['my_channel'])

0

Użyłbym lambdafunkcji na Seriestakiej DataFramejak ta:

f = lambda x: 0 if x>100 else 1
df['my_column'] = df['my_column'].map(f)

Nie twierdzę, że jest to skuteczny sposób, ale działa dobrze.


3
Jest to nieefektywne i nie jest zalecane, ponieważ obejmuje pętlę na poziomie języka Python w operacji wierszowej.
jpp

Dziękuję, myślę, że możemy loctutaj użyć df.loc[: , 'my_column'] = df['my_column'].map(f). Nie wiem, czy jest szybki jak te, które dodałeś poniżej.
Ozkan Serttas

2
Nie, nadal wolno, ponieważ nadal pracujesz w wierszach, a nie w kolumnach.
jpp

0

Spróbuj tego:

df.my_channel = df.my_channel.where(df.my_channel <= 20000, other= 0)

lub

df.my_channel = df.my_channel.mask(df.my_channel > 20000, other= 0)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.