Как удалить строки Pandas DataFrame, значение которых в определенном столбце равно NaN

754

Я имею это DataFrameи хочу только записи, EPSстолбец которых не NaN:

>>> df
                 STK_ID  EPS  cash
STK_ID RPT_Date                   
601166 20111231  601166  NaN   NaN
600036 20111231  600036  NaN    12
600016 20111231  600016  4.3   NaN
601009 20111231  601009  NaN   NaN
601939 20111231  601939  2.5   NaN
000001 20111231  000001  NaN   NaN

... то есть что-то вроде df.drop(....)этого результирующего кадра данных:

                  STK_ID  EPS  cash
STK_ID RPT_Date                   
600016 20111231  600016  4.3   NaN
601939 20111231  601939  2.5   NaN

Как я могу это сделать?

bigbug
источник
177
df.dropna(subset = ['column1_name', 'column2_name', 'column3_name'])
OSA

Ответы:

656

Не бросайте, просто возьмите строки, где EPS не NA:

df = df[df['EPS'].notna()]
eumiro
источник
470
Я бы порекомендовал использовать pandas.notnullвместоnp.isfinite
Wes McKinney
11
Есть ли какое-то преимущество в индексировании и копировании по сравнению с удалением?
Роберт Мюл
9
Создает ошибку: TypeError: ufunc 'isfinite' не поддерживается для типов ввода, и входные данные не могут быть безопасно приведены к каким-либо поддерживаемым типам в соответствии с правилом приведения типов 'safe' '
Филипп Шварц,
4
@ wes-mckinney, пожалуйста, дайте мне знать, является ли dropna () лучшим выбором по сравнению с pandas.notnull в этом случае? Если так, то почему?
штормовое поле
4
@PhilippSchwarz Эта ошибка возникает, если столбец ( EPSв примере) содержит строки или другие типы, которые не могут быть переварены np.isfinite(). Я рекомендую использовать pandas.notnull()это, чтобы справиться с этим более щедро.
норманиус
902

Этот вопрос уже решен, но ...

... также рассмотрите решение, предложенное Воутером в его первоначальном комментарии . Способность обрабатывать недостающие данные, в том числе dropna(), встроена в панды явно. Помимо потенциально улучшенной производительности по сравнению с выполнением вручную, эти функции также имеют множество опций, которые могут быть полезны.

In [24]: df = pd.DataFrame(np.random.randn(10,3))

In [25]: df.iloc[::2,0] = np.nan; df.iloc[::4,1] = np.nan; df.iloc[::3,2] = np.nan;

In [26]: df
Out[26]:
          0         1         2
0       NaN       NaN       NaN
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
4       NaN       NaN  0.050742
5 -1.250970  0.030561 -2.678622
6       NaN  1.036043       NaN
7  0.049896 -0.308003  0.823295
8       NaN       NaN  0.637482
9 -0.310130  0.078891       NaN

In [27]: df.dropna()     #drop all rows that have any NaN values
Out[27]:
          0         1         2
1  2.677677 -1.466923 -0.750366
5 -1.250970  0.030561 -2.678622
7  0.049896 -0.308003  0.823295

In [28]: df.dropna(how='all')     #drop only if ALL columns are NaN
Out[28]:
          0         1         2
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
4       NaN       NaN  0.050742
5 -1.250970  0.030561 -2.678622
6       NaN  1.036043       NaN
7  0.049896 -0.308003  0.823295
8       NaN       NaN  0.637482
9 -0.310130  0.078891       NaN

In [29]: df.dropna(thresh=2)   #Drop row if it does not have at least two values that are **not** NaN
Out[29]:
          0         1         2
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
5 -1.250970  0.030561 -2.678622
7  0.049896 -0.308003  0.823295
9 -0.310130  0.078891       NaN

In [30]: df.dropna(subset=[1])   #Drop only if NaN in specific column (as asked in the question)
Out[30]:
          0         1         2
1  2.677677 -1.466923 -0.750366
2       NaN  0.798002 -0.906038
3  0.672201  0.964789       NaN
5 -1.250970  0.030561 -2.678622
6       NaN  1.036043       NaN
7  0.049896 -0.308003  0.823295
9 -0.310130  0.078891       NaN

Есть и другие варианты (см. Документы на http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html ), включая удаление столбцов вместо строк.

Довольно удобно!

Человек
источник
282
Вы также можете использовать df.dropna(subset = ['column_name']). Надеюсь, это сэкономит как минимум одному человеку лишние 5 секунд «что я делаю неправильно». Отличный ответ, +1
Джеймс Тобин
10
@JamesTobin, я просто потратил 20 минут, чтобы написать функцию для этого! Официальная документация была очень загадочной: «Обозначать метки вдоль другой оси, например, если вы отбрасываете строки, это будет список включаемых столбцов». Я не мог понять, что они имели в виду ...
Оса
df.dropna(subset = ['column_name'])это именно то, что я искал! Спасибо!
amalik2205
123

Я знаю, что на этот вопрос уже был дан ответ, но только ради решения панд на этот конкретный вопрос, в отличие от общего описания от Амана (что было замечательно), и в случае, если кто-то еще случится с этим:

import pandas as pd
df = df[pd.notnull(df['EPS'])]
Кирк Хэдли
источник
10
На самом деле конкретный ответ будет таким: df.dropna(subset=['EPS'])(основываясь на общем описании Амана, конечно, это тоже работает)
joris
2
notnullэто также то, что Уэс (автор Панд) предложил в своем комментарии к другому ответу.
фанфол
Это может быть нубский вопрос. Но когда я делаю df [pd.notnull (...) или df.dropna, индекс сбрасывается. Так что, если в индексе строки 10 было нулевое значение в df длины 200. Кадр данных после запуска функции удаления имеет значения индекса от 1 до 9, а затем от 11 до 200. В любом случае, чтобы «переиндексировать» его
Аакаш Гупта
Вы также можете сделать, df[pd.notnull(df[df.columns[INDEX]])]где INDEXбудет нумерованный столбец, если вы не знаете имя
ocean800
60

Вы можете использовать это:

df.dropna(subset=['EPS'], how='all', inplace=True)
Джо
источник
18
how='all'здесь избыточно, потому что вы устанавливаете подкадр данных только с одним полем, чтобы оба 'all'и 'any'имели одинаковый эффект.
Антон Протопопов
35

Самое простое из всех решений:

filtered_df = df[df['EPS'].notnull()]

Приведенное выше решение лучше, чем использование np.isfinite ().

Джил Баджо
источник
22

Вы можете использовать метод dataframe notnull или inverse of isnull или numpy.isnan :

In [332]: df[df.EPS.notnull()]
Out[332]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN


In [334]: df[~df.EPS.isnull()]
Out[334]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN


In [347]: df[~np.isnan(df.EPS)]
Out[347]:
   STK_ID  RPT_Date  STK_ID.1  EPS  cash
2  600016  20111231    600016  4.3   NaN
4  601939  20111231    601939  2.5   NaN
Антон Протопопов
источник
18

Простой и легкий способ

df.dropna(subset=['EPS'],inplace=True)

источник: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html

Nursnaaz
источник
inplace=Trueэто странная тема, и не влияет на DataFrame.dropna(). См. Github.com/pandas-dev/pandas/issues/16529
AMC
Чем этот ответ отличается от ответа @ Джо? Кроме того, на месте это будет устареть в конечном итоге, лучше не использовать его вообще.
misantroop
10

еще одно решение, которое использует тот факт, что np.nan != np.nan:

In [149]: df.query("EPS == EPS")
Out[149]:
                 STK_ID  EPS  cash
STK_ID RPT_Date
600016 20111231  600016  4.3   NaN
601939 20111231  601939  2.5   NaN
MaxU
источник
2

Другая версия:

df[~df['EPS'].isna()]
keramat
источник
Зачем использовать это снова Series.notna()?
AMC
2

В наборах данных, имеющих большое количество столбцов, еще лучше увидеть, сколько столбцов содержат нулевые значения, а сколько нет.

print("No. of columns containing null values")
print(len(df.columns[df.isna().any()]))

print("No. of columns not containing null values")
print(len(df.columns[df.notna().all()]))

print("Total no. of columns in the dataframe")
print(len(df.columns))

Например, в моем фрейме данных он содержал 82 столбца, из которых 19 содержали хотя бы одно нулевое значение.

Кроме того, вы также можете автоматически удалять столбцы и строки в зависимости от того, какие значения больше нуля.
Вот код, который делает это разумно:

df = df.drop(df.columns[df.isna().sum()>len(df.columns)],axis = 1)
df = df.dropna(axis = 0).reset_index(drop=True)

Примечание. Приведенный выше код удаляет все ваши нулевые значения. Если вы хотите нулевые значения, обработайте их раньше.

Прадип Сингх
источник
Существует еще одна ссылка на
Прадип Сингх
0

Он может быть добавлен в том смысле, что '&' может использоваться для добавления дополнительных условий, например

df = df[(df.EPS > 2.0) & (df.EPS <4.0)]

Обратите внимание на то, что при оценке утверждений пандам нужна скобка.

Дэвид
источник
2
Извините, но ОП хочет чего-то еще. Кстати, ваш код неверен, вернитесь ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().. Вам нужно добавить скобки df = df[(df.EPS > 2.0) & (df.EPS <4.0)], но также это не ответ на этот вопрос.
Jezrael
-1

По какой-то причине ни один из ранее представленных ответов не работал для меня. Это основное решение сделало:

df = df[df.EPS >= 0]

Хотя, конечно, это также приведет к сбрасыванию строк с отрицательными числами. Так что, если вы хотите их, возможно, стоит добавить это и после.

df = df[df.EPS <= 0]
samthebrand
источник
Это делает что-то совершенно другое, нет?
AMC
-1

Одним из решений может быть

df = df[df.isnull().sum(axis=1) <= Cutoff Value]

Другой способ может быть

df= df.dropna(thresh=(df.shape[1] - Cutoff_value))

Я надеюсь, что это полезно.

Амит Гупта
источник