Змінення підмножини рядків у фреймі даних панди


143

Припустимо, у мене є панди DataFrame з двома стовпцями, A і B. Я хотів би змінити цю DataFrame (або створити копію), щоб B завжди був NaN, коли A дорівнює 0. Як я це досягну?

Я спробував наступне

df['A'==0]['B'] = np.nan

і

df['A'==0]['B'].values.fill(np.nan)

без успіху.


Якщо ви шукаєте дуже швидке рішення, використовуйте NumPy, whereяк видно з цього рішення нижче
Тед Петру

Відповіді:


243

Використовувати .locдля індексування на основі міток:

df.loc[df.A==0, 'B'] = np.nan

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

df.loc[df.A==0, 'B'] = df.loc[df.A==0, 'B'] / 2

Я не знаю достатньо інтернетів панд, щоб точно знати, чому це працює, але основне питання полягає в тому, що іноді індексація в DataFrame повертає копію результату, а іноді повертає погляд на вихідний об'єкт. Згідно з документацією тут , така поведінка залежить від основної поведінки нумеру. Я виявив, що доступ до всього за одну операцію (а не [одна] [дві]) швидше спрацює для налаштування.


Друга частина цього приємного відповіді на питання, яке навіть не задавали ;-) Мені цікаво, чи це все-таки канонічна відповідь на панди, зокрема б / с, це очевидне порушення DRY, хоча я припускаю, що це в факт, необхідний для порушення DRY, враховуючи обмеження внутрішніх панд? (Я можу розмістити саме подібне запитання, більш докладно, але хотів побачити, чи була у вас швидка відповідь, перш ніж я це зробив)
JohnE

Як підмножити Dataframe, який не має назв стовпців, як підмножити df просто за індексом? df.loc [df [0] == 0] не працює ... Яка альтернатива? Дякую
amipro

89

Ось з документів pandas про розширену індексацію:

У розділі буде пояснено саме те, що вам потрібно! Виявляється df.loc(як .ix був застарілий - як багато вказувалося нижче) можна використовувати для прохолодного нарізання / вибивання фрейму даних. І. Його також можна використовувати для встановлення речей.

df.loc[selection criteria, columns I want] = value

Отже, відповідь Брена говорить: "знайди мені всі місця, де df.A == 0виберіть стовпчик Bі встановіть його np.nan"


2
Ти зробив мій день. Чітке пояснення.
TwinPenguins

1
Так, як - то loc[selection criteria, columns I want]зовсім прилипає до вашого виду ...
EMES

29

Починаючи з панд 0,20 ix застаріло . Правильний спосіб - використовувати df.loc

ось робочий приклад

>>> import pandas as pd 
>>> import numpy as np 
>>> df = pd.DataFrame({"A":[0,1,0], "B":[2,0,5]}, columns=list('AB'))
>>> df.loc[df.A == 0, 'B'] = np.nan
>>> df
   A   B
0  0 NaN
1  1   0
2  0 NaN
>>> 

Пояснення:

Як пояснено в документі, тут , .loc в основному, заснована мітка, але також може використовуватися з булевим масивом .

Отже, те, що ми робимо вище, застосовує df.loc[row_index, column_index]:

  • Використання факту, що locможе сприймати булевий масив як маску, яка повідомляє пандам, підмножину рядків яких ми хочемо змінитиrow_index
  • Експлуатацією факту locє також мітка на основі вибору стовпця з використанням мітки 'B'вcolumn_index

Ми можемо використовувати логічну, умовну або будь-яку операцію, яка повертає ряд булів, щоб побудувати масив булевих. У наведеному вище прикладі ми хочемо, щоб будь-який, rowsщо містить a 0, для цього ми можемо використовувати df.A == 0, як ви бачите в наведеному нижче прикладі, це повертає ряд булів.

>>> df = pd.DataFrame({"A":[0,1,0], "B":[2,0,5]}, columns=list('AB'))
>>> df 
   A  B
0  0  2
1  1  0
2  0  5
>>> df.A == 0 
0     True
1    False
2     True
Name: A, dtype: bool
>>> 

Потім ми використовуємо вищевказаний масив булевих, щоб вибрати та змінити необхідні рядки:

>>> df.loc[df.A == 0, 'B'] = np.nan
>>> df
   A   B
0  0 NaN
1  1   0
2  0 NaN

Для отримання додаткової інформації зверніться до документації по передовій індексації тут .


11

Для масового збільшення швидкості використовуйте функцію NumPy's where.

Налаштування

Створіть двоколонний DataFrame зі 100 000 рядків з деякими нулями.

df = pd.DataFrame(np.random.randint(0,3, (100000,2)), columns=list('ab'))

Швидке рішення з numpy.where

df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)

Хронометраж

%timeit df['b'] = np.where(df.a.values == 0, np.nan, df.b.values)
685 µs ± 6.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.loc[df['a'] == 0, 'b'] = np.nan
3.11 ms ± 17.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Numpy's whereприблизно в 4 рази швидший


Мені було цікаво з цього приводу, тому я сам перевірив це, і різниця була ще більшою, використовуючи інші параметри. Numpy був майже в 10 разів швидшим, замінивши 0 на ціле число замість np.nan. Цікаво, що займає додатковий час.
Олександр

Чи потрібно використовувати .valuesв np.where(df.a.values == 0, np.nan, df.b.values)? Схоже, np.where(df.a == 0, np.nan, df.b)також працює?
hsl

4

Для заміни декількох стовпців перетворіть на numpy масив, використовуючи .values:

df.loc[df.A==0, ['B', 'C']] = df.loc[df.A==0, ['B', 'C']].values / 2
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.