Як опустити рядки Pandas DataFrame, значення яких у певному стовпці - NaN


751

Я маю це 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

Як це зробити?



176
df.dropna(subset = ['column1_name', 'column2_name', 'column3_name'])
оса

Відповіді:


654

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

df = df[df['EPS'].notna()]

470
Я рекомендую використовувати pandas.notnullзамістьnp.isfinite
Уес Маккінні

11
Чи є якась перевага щодо індексації та копіювання над відміною?
Роберт Мюїл

9
Створює помилку: TypeError: ufunc 'isfinite' не підтримується для типів введення, і введення не можна було безпечно примусити до будь-яких підтримуваних типів відповідно до правила кастингу "безпечно"
Philipp Schwarz

4
@ wes-mckinney може, будь ласка, повідомте мене, чи кращий вибір у цій справі в порівнянні з 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 ), включаючи випадання стовпців замість рядків.

Досить зручно!


281
ви також можете використовувати df.dropna(subset = ['column_name']). Сподіваюсь, що врятує хоча б одній людині зайві 5 секунд "що я роблю не так". Чудова відповідь, +1
Джеймс Тобін

10
@JamesTobin, я щойно витратив 20 хвилин на написання функції для цього! Офіційна документація була дуже виразною: "Мітки уздовж іншої осі, які слід врахувати, наприклад, якщо ви опускаєте рядки, це буде список стовпців, який слід включити". Я не зміг зрозуміти, що вони означають ...
osa

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 було розміщено нульове значення довжиною 200 df. Рамка даних після запуску функції drop має значення індексу від 1 до 9, а потім від 11 до 200. Так чи інакше, щоб "переіндексувати" це
Aakash Gupta

Ви також можете зробити 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 або зворотний 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


inplace=Trueє химерною темою, і не впливає на неї DataFrame.dropna(). Дивіться: github.com/pandas-dev/pandas/isissue/16529
AMC

Чим ця відповідь відрізняється від відповіді @ Джо? Крім того, inplace буде зрештою застарілим, найкраще не використовувати його взагалі.
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


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]

Це робить щось зовсім інше, ні?
AMC

-1

Одним з рішень може бути

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

Інший спосіб може бути

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

Сподіваюся, вони корисні.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.