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


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

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

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

и

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

без успеха.

5 99

5 ответов:

обновление

ix устарело, используйте .loc для индексирования на основе меток

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

попробуйте это:

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

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

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

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

здесь от Панды документы на дополнительное индексирование:

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

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

поэтому ответ Брена говорит: "Найдите мне все места, где df.A == 0 выберите столбец B и установить его в np.nan'

начиная с панд 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] by:

  • используя тот факт, что 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

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

в значительной степени увеличить скорость, использовать библиотеки numpy, где функция.

настройка

создайте Двухколоночный фрейм данных с 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 раза быстрее

для замены кратных столбцов преобразовать в массив numpy с помощью .values:

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