Изменение подмножества строк в фрейме pandas
Предположим, что у меня есть pandas DataFrame с двумя столбцами: A и B. Я бы хотел изменить этот DataFrame (или создать копию), чтобы B всегда был NaN, когда A равен 0. Как бы я мог это достичь?
Я попробовал следующее
df['A'==0]['B'] = np.nan
и
df['A'==0]['B'].values.fill(np.nan)
без успеха.
Ответы
Ответ 1
Используйте .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 возвращает копию результата, а иногда возвращает представление об исходном объекте. Согласно документации здесь, это поведение зависит от основного поведения numpy. Я обнаружил, что доступ ко всему за одну операцию (а не [один] [два]), скорее всего, будет работать для настройки.
Ответ 2
Здесь из pandas docs для расширенной индексации:
В этом разделе вы узнаете, что вам нужно! Выключается df.loc
(поскольку .ix был устаревшим - как указывали многие из ниже), можно использовать для крутого среза/наложения фрейма данных. А также. Его также можно использовать для установки вещей.
df.loc[selection criteria, columns I want] = value
Итак, ответ Брен говорит: "Найдите мне все места, где df.A == 0
, выберите столбец B
и установите его на np.nan
'
Ответ 3
Начиная с панды 0,20 IX устарела. Правильный путь - использовать 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
Для получения дополнительной информации обратитесь к документации по передовой индексации здесь.
Ответ 4
Для массового увеличения скорости используйте функцию NumPy, где функция.
Настройка
Создайте двухколоночный 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 where
примерно в 4 раза быстрее
Ответ 5
Чтобы заменить многократные столбцы, преобразуйте в массив numpy с помощью .values
:
df.loc[df.A==0, ['B', 'C']] = df.loc[df.A==0, ['B', 'C']].values / 2