Letakkan baris yang berisi sel kosong dari DataFrame pandas

91

Saya memiliki pd.DataFrameyang dibuat dengan mengurai beberapa spreadsheet excel. Kolom yang selnya kosong. Misalnya, di bawah ini adalah output untuk frekuensi kolom itu, 32320 record memiliki nilai yang hilang untuk Penyewa .

>>> value_counts(Tenant, normalize=False)
                              32320
    Thunderhead                8170
    Big Data Others            5700
    Cloud Cruiser              5700
    Partnerpedia               5700
    Comcast                    5700
    SDP                        5700
    Agora                      5700
    dtype: int64

Saya mencoba untuk menjatuhkan baris di mana Penyewa hilang, namun .isnull()opsi tidak mengenali nilai yang hilang.

>>> df['Tenant'].isnull().sum()
    0

Kolom memiliki tipe data "Objek". Apa yang terjadi dalam kasus ini? Bagaimana saya bisa melepaskan catatan di mana Penyewa hilang?

Amrita Sawant
sumber

Jawaban:

179

Panda akan mengenali nilai sebagai null jika itu adalah sebuah np.nanobjek, yang akan dicetak seperti NaNpada DataFrame. Nilai Anda yang hilang mungkin berupa string kosong, yang tidak dikenali Pandas sebagai null. Untuk memperbaikinya, Anda bisa mengonversi sengatan kosong (atau apa pun yang ada di sel kosong Anda) menjadi np.nanobjek menggunakan replace(), lalu panggil dropna()DataFrame Anda untuk menghapus baris dengan penyewa null.

Untuk mendemonstrasikan, kami membuat DataFrame dengan beberapa nilai acak dan beberapa string kosong di Tenantskolom:

>>> import pandas as pd
>>> import numpy as np
>>> 
>>> df = pd.DataFrame(np.random.randn(10, 2), columns=list('AB'))
>>> df['Tenant'] = np.random.choice(['Babar', 'Rataxes', ''], 10)
>>> print df

          A         B   Tenant
0 -0.588412 -1.179306    Babar
1 -0.008562  0.725239         
2  0.282146  0.421721  Rataxes
3  0.627611 -0.661126    Babar
4  0.805304 -0.834214         
5 -0.514568  1.890647    Babar
6 -1.188436  0.294792  Rataxes
7  1.471766 -0.267807    Babar
8 -1.730745  1.358165  Rataxes
9  0.066946  0.375640         

Sekarang kami mengganti string kosong apa pun di Tenantskolom dengan np.nanobjek, seperti:

>>> df['Tenant'].replace('', np.nan, inplace=True)
>>> print df

          A         B   Tenant
0 -0.588412 -1.179306    Babar
1 -0.008562  0.725239      NaN
2  0.282146  0.421721  Rataxes
3  0.627611 -0.661126    Babar
4  0.805304 -0.834214      NaN
5 -0.514568  1.890647    Babar
6 -1.188436  0.294792  Rataxes
7  1.471766 -0.267807    Babar
8 -1.730745  1.358165  Rataxes
9  0.066946  0.375640      NaN

Sekarang kita bisa menghilangkan nilai null:

>>> df.dropna(subset=['Tenant'], inplace=True)
>>> print df

          A         B   Tenant
0 -0.588412 -1.179306    Babar
2  0.282146  0.421721  Rataxes
3  0.627611 -0.661126    Babar
5 -0.514568  1.890647    Babar
6 -1.188436  0.294792  Rataxes
7  1.471766 -0.267807    Babar
8 -1.730745  1.358165  Rataxes
McMath
sumber
Terima kasih banyak, saya akan mencoba ini dan kembali!
Amrita Sawant
2
@mcmath, sedikit penasaran. Mengapa Anda mengimpor numpy dan menggunakan np.nansaat Anda bisa melakukannya pd.np.nan?
propjk007
3
@ propjk007, seperti banyak hal dalam hidup, ada banyak cara untuk melakukan banyak hal
andrew
Dari pengujian saya , tampaknya melakukan df[df['Tenant'].astype(bool)](dengan asumsi tidak ada karakter spasi - hanya string kosong) lebih cepat daripadadf.replace('', np.nan).dropna(subset=['Tenant'])
cs95
52

Pythonic + Pandorable: df[df['col'].astype(bool)]

String kosong adalah falsy, yang berarti Anda dapat memfilter nilai bool seperti ini:

df = pd.DataFrame({
    'A': range(5),
    'B': ['foo', '', 'bar', '', 'xyz']
})
df
   A    B
0  0  foo
1  1     
2  2  bar
3  3     
4  4  xyz
df['B'].astype(bool)                                                                                                                      
0     True
1    False
2     True
3    False
4     True
Name: B, dtype: bool

df[df['B'].astype(bool)]                                                                                                                  
   A    B
0  0  foo
2  2  bar
4  4  xyz

Jika tujuan Anda adalah untuk menghapus tidak hanya string kosong, tetapi juga string yang hanya berisi spasi, gunakan str.stripsebelumnya:

df[df['B'].str.strip().astype(bool)]
   A    B
0  0  foo
2  2  bar
4  4  xyz

Lebih cepat dari yang Anda Pikirkan

.astypeadalah operasi vektorisasi, ini lebih cepat daripada setiap opsi yang disajikan sejauh ini. Setidaknya, dari tes saya. YMMV.

Berikut adalah perbandingan waktu, saya telah memasukkan beberapa metode lain yang dapat saya pikirkan.

masukkan deskripsi gambar di sini

Kode pembandingan, untuk referensi:

import pandas as pd
import perfplot

df1 = pd.DataFrame({
    'A': range(5),
    'B': ['foo', '', 'bar', '', 'xyz']
})

perfplot.show(
    setup=lambda n: pd.concat([df1] * n, ignore_index=True),
    kernels=[
        lambda df: df[df['B'].astype(bool)],
        lambda df: df[df['B'] != ''],
        lambda df: df[df['B'].replace('', np.nan).notna()],  # optimized 1-col
        lambda df: df.replace({'B': {'': np.nan}}).dropna(subset=['B']),  
    ],
    labels=['astype', "!= ''", "replace + notna", "replace + dropna", ],
    n_range=[2**k for k in range(1, 15)],
    xlabel='N',
    logx=True,
    logy=True,
    equality_check=pd.DataFrame.equals)
cs95
sumber
34

value_counts menghilangkan NaN secara default jadi kemungkinan besar Anda berurusan dengan "".

Jadi Anda bisa memfilternya seperti

filter = df["Tenant"] != ""
dfNew = df[filter]
Bob Haffner
sumber
1
Solusi @Bobs tidak berhasil untuk saya. df.dropna (subset = ['tenant'], inplace = True) berfungsi.
Amrita Sawant
1
Maaf soal itu. Saya pikir Anda berurusan dengan "". Anda harus memposting solusi Anda sebagai jawaban
Bob Haffner
9

Ada situasi di mana sel memiliki ruang putih, Anda tidak dapat melihatnya, gunakan

df['col'].replace('  ', np.nan, inplace=True)

untuk mengganti spasi putih sebagai NaN, lalu

df= df.dropna(subset=['col'])
Belajar
sumber
5

Anda dapat menggunakan variasi ini:

import pandas as pd
vals = {
    'name' : ['n1', 'n2', 'n3', 'n4', 'n5', 'n6', 'n7'],
    'gender' : ['m', 'f', 'f', 'f',  'f', 'c', 'c'],
    'age' : [39, 12, 27, 13, 36, 29, 10],
    'education' : ['ma', None, 'school', None, 'ba', None, None]
}
df_vals = pd.DataFrame(vals) #converting dict to dataframe

Ini akan menghasilkan (** - hanya menyoroti baris yang diinginkan):

   age education gender name
0   39        ma      m   n1 **
1   12      None      f   n2    
2   27    school      f   n3 **
3   13      None      f   n4
4   36        ba      f   n5 **
5   29      None      c   n6
6   10      None      c   n7

Jadi untuk membuang semua yang tidak memiliki nilai 'pendidikan', gunakan kode di bawah ini:

df_vals = df_vals[~df_vals['education'].isnull()] 

('~' menunjukkan TIDAK)

Hasil:

   age education gender name
0   39        ma      m   n1
2   27    school      f   n3
4   36        ba      f   n5
Amir F
sumber