Изменение подмножества строк в кадре данных pandas

Предположим, у меня есть DataFrame pandas с двумя столбцами, A и B. Я хотел бы изменить этот DataFrame (или создать копию), чтобы B всегда был NaN, когда A равно 0. Как мне этого добиться?

Я пробовал следующее

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

и

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

безуспешно.


person Arthur B.    schedule 06.09.2012    source источник
comment
Если вы ищете очень быстрое решение, используйте where от NumPy, как показано в это решение ниже   -  person Ted Petrou    schedule 03.11.2017


Ответы (5)


Используйте .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

Я недостаточно знаю о внутреннем устройстве pandas, чтобы точно знать, почему это работает, но основная проблема заключается в том, что иногда индексация в DataFrame возвращает копию результата, а иногда возвращает представление исходного объекта. Согласно документации, здесь, это поведение зависит от основного поведения numpy. Я обнаружил, что доступ ко всему за одну операцию (а не за [одну] [две]) с большей вероятностью будет работать для настройки.

person BrenBarn    schedule 06.09.2012
comment
Вторая часть этого - хороший ответ на вопрос, который даже не задавали ;-) Мне интересно, является ли это все еще каноническим ответом панд, в частности, b / c это очевидное нарушение DRY, хотя я предполагаю, что это в действительно ли необходимо нарушать DRY с учетом внутренних ограничений pandas? (Я могу опубликовать именно такой вопрос, более подробно, но хотел бы узнать, есть ли у вас быстрый ответ, прежде чем я это сделаю) - person JohnE; 12.03.2019
comment
Как выделить подмножество Dataframe, у которого нет имен столбцов, как создать подмножество df только по индексу? df.loc [df [0] == 0] не работает ... Какая альтернатива? Спасибо - person amipro; 10.04.2019

Здесь взято из документации pandas о расширенном индексировании:

Раздел объяснит, что именно вам нужно! Оказывается, df.loc (поскольку .ix устарел - как многие указывали ниже) можно использовать для классного нарезания / нарезки фрейма данных. И. Его также можно использовать для настройки вещей.

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

Итак, ответ Брена гласит: «Найди мне все места, где df.A == 0, выберите столбец B и установите его на np.nan».

person badgley    schedule 26.09.2012
comment
Ага, как-то loc[selection criteria, columns I want] отлично запоминается ... - person EmEs; 10.01.2019

Начиная с pandas 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, содержащие 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

Дополнительную информацию см. В документации по расширенному индексированию здесь.

person Mohamed Ali JAMAOUI    schedule 04.07.2017

Для значительного увеличения скорости используйте функцию NumPy 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)

where от Numpy примерно в 4 раза быстрее

person Ted Petrou    schedule 02.11.2017
comment
Мне это было любопытно, поэтому я проверил это сам, и по другим параметрам разница была еще больше. Numpy почти в 10 раз быстрее заменил 0 на целое число вместо np.nan. Интересно, на что нужно дополнительное время. - person Alexander; 21.08.2018
comment
Обязательно ли использовать .values в np.where(df.a.values == 0, np.nan, df.b.values)? Похоже, np.where(df.a == 0, np.nan, df.b) тоже работает? - person hsl; 03.02.2020

Чтобы заменить кратные столбцы, конвертируйте в массив numpy, используя .values:

df.loc[df.A==0, ['B', 'C']] = df.loc[df.A==0, ['B', 'C']].values / 2
person Adrien Renaud    schedule 25.10.2017