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

У меня есть этот 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

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


person bigbug    schedule 16.11.2012    source источник
comment
dropna: pandas.pydata.org/pandas-docs/ стабильный / сгенерированный /   -  person Wouter Overmeire    schedule 16.11.2012


Ответы (12)


Не роняйте, просто возьмите строки, в которых EPS не является NA:

df = df[df['EPS'].notna()]
person eumiro    schedule 16.11.2012
comment
Я бы рекомендовал использовать pandas.notnull вместо np.isfinite - person Wes McKinney; 21.11.2012
comment
Есть ли преимущество индексирования и копирования перед отбрасыванием? - person Robert Muil; 31.07.2015
comment
Создает ошибку: TypeError: ufunc 'isfinite' не поддерживается для входных типов, и входные данные не могут быть безопасно приведены к каким-либо поддерживаемым типам в соответствии с правилом приведения `` безопасно '' - person Philipp Schwarz; 07.10.2016
comment
@ wes-mckinney, пожалуйста, дайте мне знать, является ли dropna () лучшим выбором по сравнению с pandas.notnull в этом случае? Если да, то почему? - person stormfield; 07.09.2017
comment
@PhilippSchwarz Эта ошибка возникает, если столбец (EPS в примере) содержит строки или другие типы, которые не могут быть обработаны np.isfinite(). Я рекомендую использовать pandas.notnull(), который решит эту проблему более щедро. - person normanius; 05.04.2018
comment
Это не соответствует строке 3, где EPS равен 4,3 (действителен), а денежные средства - NaN. Я ожидаю, что OP тоже захочет отказаться от этого. - person Cadoiz; 08.06.2020
comment
мы также можем использовать df.dropna(subset=['EPS']) - person Mohith7548; 22.01.2021

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

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

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), включая удаление столбцов вместо строк.

Очень удобно!

person Aman    schedule 17.11.2012
comment
вы также можете использовать df.dropna(subset = ['column_name']). Надеюсь, что это сэкономит хотя бы одному человеку лишние 5 секунд на вопрос: «Что я делаю не так». Отличный ответ, +1 - person James Tobin; 18.06.2014
comment
@JamesTobin, я только что потратил 20 минут на то, чтобы написать для этого функцию! Официальная документация была очень загадочной: ярлыки вдоль другой оси для рассмотрения, например если вы отбрасываете строки, это будет список столбцов, которые нужно включить. Я не мог понять, что они имели в виду ... - person Sergey Orshanskiy; 06.09.2014
comment
df.dropna(subset = ['column_name']) это именно то, что я искал! Спасибо! - person amalik2205; 09.12.2019
comment
Этот ответ очень полезен, но на тот случай, если никому, кто читает, какие варианты полезны в каких ситуациях, непонятно, я собрал сообщение часто задаваемых вопросов dropna здесь. Надеюсь, это поможет людям, которые изо всех сил пытаются применить dropna к своим конкретным потребностям. - person cs95; 19.06.2020
comment
+1 этот ответ, кажется, также помогает избежать SettingWithCopyWarning позже, когда вы используете df.dropna(subset = ['column_name'], inplace=True) - person cookiemonster; 02.07.2021

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

import pandas as pd
df = df[pd.notnull(df['EPS'])]
person Kirk Hadley    schedule 23.04.2014
comment
На самом деле, конкретный ответ будет: df.dropna(subset=['EPS']) (на основе общего описания Aman, конечно, это тоже работает) - person joris; 23.04.2014
comment
notnull - это также то, что Уэс (автор Pandas) предложил в своем комментарии к другому ответу. - person fantabolous; 09.07.2014
comment
Это может быть вопрос новичка. Но когда я делаю df [pd.notnull (...) или df.dropna, индекс теряется. Итак, если в строке-индексе 10 было нулевое значение в df длиной 200. Фрейм данных после запуска функции перетаскивания имеет значения индекса от 1 до 9, а затем от 11 до 200. В любом случае, чтобы повторно проиндексировать его - person Aakash Gupta; 04.03.2016
comment
вы также можете сделать df[pd.notnull(df[df.columns[INDEX]])], где INDEX будет нумерованным столбцом, если вы не знаете имя - person ocean800; 31.10.2019
comment
По какой-то причине этот ответ сработал для меня, а df.dropna(subset=['column name'] - нет. - person Mian Asbat Ahmad; 24.06.2020

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

df.dropna(subset=['EPS'], how='all', inplace=True)
person Joe    schedule 02.08.2017
comment
how='all' здесь избыточен, потому что вы разделяете фрейм данных только с одним полем, поэтому и 'all', и 'any' будут иметь одинаковый эффект. - person Anton Protopopov; 16.01.2018

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

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

Вышеупомянутое решение намного лучше, чем использование np.isfinite ()

person Gil Baggio    schedule 23.11.2017

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

Это старый вопрос, который забили до смерти, но я верю, что в этой ветке можно найти более полезную информацию. Читайте дальше, если вы ищете ответ на любой из следующих вопросов:

  • Могу ли я отбросить строки, если какое-либо из его значений имеет NaN? А если все они NaN?
  • Могу ли я смотреть на NaN только в определенных столбцах при отбрасывании строк?
  • Могу ли я удалить строки с определенным количеством значений NaN?
  • Как удалить столбцы вместо строк?
  • Я пробовал все варианты выше, но мой DataFrame просто не обновляется!

DataFrame.dropna: использование и примеры

Уже было сказано, что df.dropna - это канонический метод удаления NaN из DataFrames, но нет ничего лучше нескольких визуальных подсказок, которые могут помочь на этом пути.

# Setup
df = pd.DataFrame({
    'A': [np.nan, 2, 3, 4],  
    'B': [np.nan, np.nan, 2, 3], 
    'C': [np.nan]*3 + [3]}) 

df                      
     A    B    C
0  NaN  NaN  NaN
1  2.0  NaN  NaN
2  3.0  2.0  NaN
3  4.0  3.0  3.0

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


Могу ли я отбросить строки, если какое-либо из его значений имеет NaN? А если все они NaN?

Здесь пригодится аргумент how=.... Это может быть один из

  • 'any' (по умолчанию) - отбрасывает строки, если хотя бы один столбец имеет NaN
  • 'all' - отбрасывает строки, только если все его столбцы имеют NaN

<!_ ->

# Removes all but the last row since there are no NaNs 
df.dropna()

     A    B    C
3  4.0  3.0  3.0

# Removes the first row only
df.dropna(how='all')

     A    B    C
1  2.0  NaN  NaN
2  3.0  2.0  NaN
3  4.0  3.0  3.0

Примечание
Если вы просто хотите увидеть, какие строки являются пустыми (IOW, если вам нужна логическая маска строк), используйте _ 8_:

df.isna()

       A      B      C
0   True   True   True
1  False   True   True
2  False  False   True
3  False  False  False

df.isna().any(axis=1)

0     True
1     True
2     True
3    False
dtype: bool

Чтобы получить инверсию этого результата, используйте _ 10_.


Могу ли я смотреть на NaN только в определенных столбцах при отбрасывании строк?

Это вариант использования аргумента subset=[...].

Укажите список столбцов (или индексов с axis=1), чтобы сообщить pandas, что вы хотите просматривать только эти столбцы (или строки с axis=1) при удалении строк (или столбцов с axis=1.

# Drop all rows with NaNs in A
df.dropna(subset=['A'])

     A    B    C
1  2.0  NaN  NaN
2  3.0  2.0  NaN
3  4.0  3.0  3.0

# Drop all rows with NaNs in A OR B
df.dropna(subset=['A', 'B'])

     A    B    C
2  3.0  2.0  NaN
3  4.0  3.0  3.0

Могу ли я удалить строки с определенным количеством значений NaN?

Это вариант использования аргумента thresh=.... Задайте минимальное количество значений NON-NULL как целое число.

df.dropna(thresh=1)  

     A    B    C
1  2.0  NaN  NaN
2  3.0  2.0  NaN
3  4.0  3.0  3.0

df.dropna(thresh=2)

     A    B    C
2  3.0  2.0  NaN
3  4.0  3.0  3.0

df.dropna(thresh=3)

     A    B    C
3  4.0  3.0  3.0

Здесь следует отметить, что вам нужно указать, сколько значений NON-NULL вы хотите сохранить, а не сколько значений NULL вы хотите отбросить. Это проблема для новых пользователей.

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

required_min_null_values_to_drop = 2 # drop rows with at least 2 NaN
df.dropna(thresh=df.shape[1] - required_min_null_values_to_drop + 1)

     A    B    C
2  3.0  2.0  NaN
3  4.0  3.0  3.0

Как удалить столбцы вместо строк?

Используйте аргумент axis=..., это может быть axis=0 или axis=1.

Сообщает функции, хотите ли вы удалить строки (axis=0) или столбцы (axis=1).

df.dropna()

     A    B    C
3  4.0  3.0  3.0

# All columns have rows, so the result is empty.
df.dropna(axis=1)

Empty DataFrame
Columns: []
Index: [0, 1, 2, 3]

# Here's a different example requiring the column to have all NaN rows
# to be dropped. In this case no columns satisfy the condition.
df.dropna(axis=1, how='all')

     A    B    C
0  NaN  NaN  NaN
1  2.0  NaN  NaN
2  3.0  2.0  NaN
3  4.0  3.0  3.0

# Here's a different example requiring a column to have at least 2 NON-NULL
# values. Column C has less than 2 NON-NULL values, so it should be dropped.
df.dropna(axis=1, thresh=2)

     A    B
0  NaN  NaN
1  2.0  NaN
2  3.0  2.0
3  4.0  3.0

Я пробовал все варианты выше, но мой DataFrame просто не обновляется!

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

df.dropna(...) # wrong
df.dropna(..., inplace=True) # right, but not recommended
df = df.dropna(...) # right

Ссылка

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.dropna.html.

DataFrame.dropna(
    self, axis=0, how='any', thresh=None, subset=None, inplace=False)

введите описание изображения здесь

person cs95    schedule 18.06.2020

Вы можете использовать метод dataframe notnull или обратный 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
person Anton Protopopov    schedule 04.12.2015

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

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

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

person Nursnaaz    schedule 22.01.2019
comment
inplace=True - странная тема, она не влияет на DataFrame.dropna(). См .: github.com/pandas-dev/pandas/issues/16529 - person AMC; 16.02.2020
comment
Чем этот ответ отличается от ответа @Jo? Кроме того, inplace is в конечном итоге будет устаревшим, лучше не использовать его вообще. - person misantroop; 28.03.2020

еще одно решение, использующее тот факт, что 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
person MaxU    schedule 20.04.2017

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

df[~df['EPS'].isna()]
person keramat    schedule 08.02.2020
comment
Зачем использовать это вместо Series.notna()? - person AMC; 16.02.2020

Здесь можно добавить '&', чтобы добавить дополнительные условия, например.

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

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

person David    schedule 15.03.2016
comment
Извините, но OP хочет чего-то еще. Кстати, ваш код неверен, верните 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)], но это также не ответ на этот вопрос. - person jezrael; 16.03.2016

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

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)

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

person Pradeep Singh    schedule 14.12.2019
comment
Есть еще один вопрос, ссылка - person Pradeep Singh; 14.12.2019