Умовно замініть панди


123

У мене є DataFrame, і я хочу замінити значення в певному стовпці, що перевищує значення на нуль. Я думав, що це спосіб досягти цього:

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

Якщо я скопіюю канал у новий кадр даних, це просто:

df2 = df.my_channel 

df2[df2 > 20000] = 0

Це робить саме те, що я хочу, але, здається, не працює з каналом як частина оригінальної DataFrame.


Знайшли те, що я думаю, ви шукали тут .
footwet

Відповіді:


181

.ixіндексатор працює нормально для версій панд до 0.20.0, але оскільки панди 0.20.0, .ixіндексатор застарілий , тому вам слід уникати його використання. Натомість ви можете використовувати .locабо ilocіндексатори. Ви можете вирішити цю проблему:

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

Або в одному рядку,

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

maskдопомагає вибрати рядки, в яких df.my_channel > 20000є True, при цьому df.loc[mask, column_name] = 0встановлює значення 0 вибраним рядкам, де maskміститься у стовпці, яке ім'я column_name.

Оновлення: у цьому випадку вам слід скористатися, locтому що якщо ви користуєтесь iloc, ви отримаєте NotImplementedErrorповідомлення про те, що булева індексація на основі iLocation на цілочисельний тип недоступна .


81

Спробуйте

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

Примітка. Починаючи з версії 0.20.0, ix застаріла на користь loc/ iloc.


8
Дякую. Я також знайшов своє власне рішення, яке було: df.my_channel [df.my_channel> 20000] = 0
BMichell

2
@BMichell Я думаю, що ваше рішення може почати попереджувати вас через 0,13, але ще не було шансу спробувати
lowtech

Помилка виходу: /opt/anaconda3/envs/python35/lib/python3.5/site-packages/ipykernel_launcher.py:1: SettingWithCopyWarning: Значення намагається встановити на копії фрагмента з DataFrame. документація: pandas.pydata.org/pandas-docs/stable/… "" "Точка входу для запуску ядра IPython.
Rutger Hofste

@RutgerHofste дякую, що згадуєте, що ще один аргумент ніколи не використовуйте Python3
lowtech

34

np.where функція працює наступним чином:

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

У вашому випадку ви хочете:

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

19

Причина, по якій ваш оригінальний фрейм даних не оновлюється, полягає в тому, що ланцюгова індексація може призвести до зміни копії, а не перегляду вашого фрейму даних. У документах дають таку пораду:

Встановлюючи значення в об'єкті панди, слід бути обережним, щоб уникнути того, що називається ланцюговим індексуванням.

У вас є кілька альтернатив: -

loc + Булева індексація

loc може використовуватися для встановлення значень та підтримує булеві маски:

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

mask + Булева індексація

Ви можете призначити для своєї серії:

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

Або ви можете оновити свою серію на місці:

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

np.where + Булева індексація

Ви можете використовувати NumPy, призначивши оригінальну серію, коли ваш стан не задоволений; однак перші два рішення є більш чистими, оскільки вони явно змінюють лише задані значення.

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

0

Я хотів би використовувати lambdaфункцію на Seriesоператорі А DataFrameяк це:

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

Я не запевняю, що це ефективний спосіб, але він працює чудово.


3
Це неефективно і не рекомендується, оскільки воно включає цикл рівня Python у послідовної операції.
jpp

Дякую, напевно, ми можемо використати locтут, як df.loc[: , 'my_column'] = df['my_column'].map(f). Я не знаю, чи це швидко, як ті, які ви додали нижче.
Озкан Серттас

2
Ні, все ще повільно, оскільки ви все ще керуєтесь рядками, а не стовпцями.
jpp

0

Спробуйте це:

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

або

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.