Cara menjatuhkan baris Pandas DataFrame yang nilainya dalam kolom tertentu adalah NaN

754

Saya memiliki ini DataFramedan hanya ingin catatan yang EPSkolomnya bukan 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

... Yaitu sesuatu yang ingin df.drop(....)mendapatkan kerangka data yang dihasilkan ini:

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

Bagaimana aku melakukan itu?

bigbug
sumber
177
df.dropna(subset = ['column1_name', 'column2_name', 'column3_name'])
Osa

Jawaban:

655

Jangan jatuhkan, ambil saja baris di mana EPS bukan NA:

df = df[df['EPS'].notna()]
eumiro
sumber
470
Saya akan merekomendasikan penggunaan pandas.notnulldaripadanp.isfinite
Wes McKinney
11
Apakah ada manfaat untuk mengindeks dan menyalin lebih dari menjatuhkan?
Robert Muil
9
Kesalahan Pembuatan: TypeError: ufunc 'isfinite' tidak didukung untuk tipe input, dan input tidak dapat dengan aman dipaksa untuk jenis yang didukung sesuai dengan aturan casting '' aman ''
Philipp Schwarz
4
@ wes-mckinney bisa tolong beri tahu saya jika dropna () adalah pilihan yang lebih baik daripada panda. notnull dalam kasus ini? Jika demikian, lalu mengapa?
stormfield
4
@ PhilippSchwarz Kesalahan ini terjadi jika kolom ( EPSdalam contoh) berisi string atau tipe lain yang tidak dapat dicerna oleh np.isfinite(). Saya sarankan untuk menggunakan pandas.notnull()yang akan menangani ini dengan lebih murah hati.
normanius
902

Pertanyaan ini sudah diselesaikan, tetapi ...

... juga pertimbangkan solusi yang disarankan oleh Wouter dalam komentar aslinya . Kemampuan untuk menangani data yang hilang, termasuk dropna(), dibangun ke dalam panda secara eksplisit. Selain berpotensi meningkatkan kinerja daripada melakukannya secara manual, fungsi-fungsi ini juga dilengkapi dengan berbagai opsi yang mungkin berguna.

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

Ada juga opsi lain (Lihat dokumen di http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.dropna.html ), termasuk menjatuhkan kolom alih-alih baris.

Cukup berguna!

Seorang pria
sumber
282
Anda juga bisa menggunakan df.dropna(subset = ['column_name']). Harapan yang menyelamatkan setidaknya satu orang ekstra 5 detik dari 'apa yang saya lakukan salah'. Jawaban yang bagus, +1
James Tobin
10
@ JamesTobin, saya hanya menghabiskan 20 menit untuk menulis fungsi untuk itu! Dokumentasi resmi sangat samar: "Label di sepanjang sumbu lain untuk dipertimbangkan, misalnya jika Anda menjatuhkan baris, ini akan menjadi daftar kolom untuk dimasukkan". Saya tidak dapat mengerti, apa artinya ...
osa 5'14
df.dropna(subset = ['column_name'])persis apa yang saya cari! Terima kasih!
amalik2205
123

Saya tahu ini sudah dijawab, tetapi hanya demi solusi panda murni untuk pertanyaan khusus ini yang bertentangan dengan deskripsi umum dari Aman (yang luar biasa) dan jika ada orang lain yang mengalami hal ini:

import pandas as pd
df = df[pd.notnull(df['EPS'])]
Kirk Hadley
sumber
10
Sebenarnya, jawaban spesifiknya adalah: df.dropna(subset=['EPS'])(berdasarkan pada deskripsi umum Aman, tentu saja ini juga berfungsi)
joris
2
notnulljuga apa yang Wes (penulis Pandas) sarankan dalam komentarnya pada jawaban lain.
fantabolous
Ini mungkin pertanyaan noob. Tetapi ketika saya melakukan df [pd.notnull (...) atau df.dropna indeks akan turun. Jadi jika ada nilai nol di baris-indeks 10 dalam df dengan panjang 200. Dataframe setelah menjalankan fungsi drop memiliki nilai indeks dari 1 hingga 9 dan kemudian 11 hingga 200. Pokoknya untuk "indeks ulang" itu
Aakash Gupta
Anda juga bisa melakukan di df[pd.notnull(df[df.columns[INDEX]])]mana INDEXkolom bernomor jika Anda tidak tahu nama
ocean800
60

Anda bisa menggunakan ini:

df.dropna(subset=['EPS'], how='all', inplace=True)
Joe
sumber
18
how='all'redundan di sini, karena Anda menset dataframe hanya dengan satu bidang sehingga keduanya 'all'dan 'any'akan memiliki efek yang sama.
Anton Protopopov
35

Sederhana dari semua solusi:

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

Solusi di atas jauh lebih baik daripada menggunakan np.isfinite ()

Gil Baggio
sumber
22

Anda bisa menggunakan metode dataframe notnull atau kebalikan dari isnull , atau 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
Anton Protopopov
sumber
10

solusi lain yang menggunakan fakta bahwa 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
sumber
2

Versi lain:

df[~df['EPS'].isna()]
keramat
sumber
Mengapa menggunakan ini Series.notna()?
AMC
2

Dalam kumpulan data yang memiliki jumlah kolom yang besar, lebih baik untuk melihat berapa banyak kolom yang mengandung nilai nol dan berapa banyak yang tidak.

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))

Sebagai contoh dalam dataframe saya itu berisi 82 ​​kolom, dimana 19 berisi setidaknya satu nilai nol.

Lebih lanjut Anda juga dapat secara otomatis menghapus cols dan rows bergantung pada yang memiliki lebih banyak nilai null
Berikut adalah kode yang melakukan ini dengan cerdas:

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

Catatan: Kode di atas menghapus semua nilai nol Anda. Jika Anda ingin nilai nol, proses sebelumnya.

Pradeep Singh
sumber
Ada tautan
Pradeep Singh
0

Dapat ditambahkan pada saat itu '&' dapat digunakan untuk menambahkan kondisi tambahan misalnya

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

Perhatikan bahwa ketika mengevaluasi pernyataan, panda membutuhkan tanda kurung.

David
sumber
2
Maaf, tapi OP ingin yang lain. Btw, kodemu salah, kembalikan ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().. Anda perlu menambahkan tanda kurung - df = df[(df.EPS > 2.0) & (df.EPS <4.0)], tetapi juga bukan jawaban untuk pertanyaan ini.
jezrael
-1

Untuk beberapa alasan tidak ada jawaban yang dikirimkan sebelumnya bekerja untuk saya. Solusi dasar ini:

df = df[df.EPS >= 0]

Padahal tentu saja itu akan menjatuhkan baris dengan angka negatif juga. Jadi, jika Anda menginginkannya, mungkin pintar untuk menambahkan ini juga.

df = df[df.EPS <= 0]
samthebrand
sumber
Ini melakukan sesuatu yang sama sekali berbeda, bukan?
AMC
-1

Salah satu solusinya bisa

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

Cara lain bisa jadi

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

Saya harap ini bermanfaat.

Amit Gupta
sumber