วางแถวที่มีเซลล์ว่างจาก DataFrame แพนด้า


92

ฉันมีpd.DataFrameที่สร้างขึ้นโดยการแยกวิเคราะห์สเปรดชีต excel คอลัมน์ที่มีเซลล์ว่าง ตัวอย่างด้านล่างเป็นผลลัพธ์สำหรับความถี่ของคอลัมน์นั้น 32320 ระเบียนมีค่าที่ขาดหายไปสำหรับผู้เช่า

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

ฉันพยายามวางแถวที่ไม่มีผู้เช่า แต่.isnull()ตัวเลือกไม่รู้จักค่าที่ขาดหายไป

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

คอลัมน์นี้มีข้อมูลประเภท "Object" เกิดอะไรขึ้นในกรณีนี้? ฉันจะทิ้งบันทึกที่ผู้เช่าหายไปได้อย่างไร

คำตอบ:


179

Pandas จะรับรู้ค่าเป็นโมฆะหากเป็นnp.nanวัตถุซึ่งจะพิมพ์NaNใน DataFrame ค่าที่หายไปของคุณน่าจะเป็นสตริงว่างเปล่าซึ่งนุ่นไม่รับรู้ว่าเป็นโมฆะ ในการแก้ไขปัญหานี้คุณสามารถแปลง Stings ว่าง (หรืออะไรก็ตามที่อยู่ในเซลล์ว่างของคุณ) เป็นnp.nanวัตถุโดยใช้replace()จากนั้นเรียกdropna()ใช้ DataFrame ของคุณเพื่อลบแถวที่มีผู้เช่าว่าง

เพื่อแสดงให้เห็นเราสร้าง DataFrame ที่มีค่าสุ่มและสตริงว่างบางส่วนในTenantsคอลัมน์:

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

ตอนนี้เราแทนที่สตริงว่างในTenantsคอลัมน์ด้วยnp.nanวัตถุดังนี้:

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

ตอนนี้เราสามารถปล่อยค่า 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

ขอบคุณมากฉันจะลองดูและกลับไป!
Amrita Sawant

2
@mcmath สงสัยนิดนึง. ทำไมคุณถึงนำเข้า numpy และใช้np.nanเมื่อคุณสามารถทำได้pd.np.nan?
propjk007

3
@ propjk007 เช่นเดียวกับหลาย ๆ สิ่งในชีวิตมีหลายวิธีในการทำสิ่งต่างๆมากมาย
แอนดรู

จากการทดสอบของฉันดูเหมือนว่าการทำdf[df['Tenant'].astype(bool)](สมมติว่าไม่มีอักขระเว้นวรรค - สตริงว่างเท่านั้น) เร็วกว่าdf.replace('', np.nan).dropna(subset=['Tenant'])
cs95

53

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

สตริงที่ว่างเปล่าเป็นเท็จซึ่งหมายความว่าคุณสามารถกรองค่าบูลได้ดังนี้:

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

หากเป้าหมายของคุณคือการลบไม่เพียง แต่สตริงว่าง แต่ยังรวมถึงสตริงที่มีช่องว่างเท่านั้นให้ใช้str.stripล่วงหน้า:

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

เร็วกว่าที่คุณคิด

.astypeเป็นการดำเนินการแบบ vectorised ซึ่งเร็วกว่าทุกตัวเลือกที่นำเสนอจนถึงตอนนี้ อย่างน้อยจากการทดสอบของฉัน YMMV.

นี่คือการเปรียบเทียบเวลาฉันได้ใช้วิธีอื่น ๆ ที่ฉันคิดได้

ป้อนคำอธิบายภาพที่นี่

รหัสเปรียบเทียบสำหรับการอ้างอิง:

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)

34

value_counts ละเว้น NaN โดยค่าเริ่มต้นดังนั้นคุณจึงมีแนวโน้มที่จะจัดการกับ "" มากที่สุด

ดังนั้นคุณสามารถกรองออกได้เช่น

filter = df["Tenant"] != ""
dfNew = df[filter]

1
โซลูชัน @Bobs ไม่ได้ผลสำหรับฉัน df.dropna (subset = ['tenant'], inplace = True) ใช้งานได้
Amrita Sawant

1
ขอโทษสำหรับเรื่องนั้น. ฉันคิดว่าคุณกำลังจัดการกับ "" อยู่ คุณควรโพสต์วิธีแก้ปัญหาของคุณเป็นคำตอบ
Bob Haffner

9

มีสถานการณ์ที่เซลล์มีพื้นที่สีขาวคุณไม่สามารถมองเห็นได้ใช้

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

เพื่อแทนที่พื้นที่สีขาวเป็น NaN จากนั้น

df= df.dropna(subset=['col'])

5

คุณสามารถใช้รูปแบบนี้:

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

สิ่งนี้จะแสดงผล (** - เน้นเฉพาะแถวที่ต้องการ):

   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

ดังนั้นหากต้องการทิ้งทุกอย่างที่ไม่มีค่า 'การศึกษา' ให้ใช้รหัสด้านล่าง:

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

('~' แสดงว่าไม่)

ผลลัพธ์:

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

0

หากคุณไม่สนใจเกี่ยวกับคอลัมน์ที่มีไฟล์ที่หายไปโดยพิจารณาว่าดาต้าเฟรมมีชื่อNewและต้องการกำหนดดาต้าเฟรมใหม่ให้กับตัวแปรเดียวกันเพียงแค่เรียกใช้

New = New.drop_duplicates()

หากคุณต้องการลบแถวสำหรับค่าว่างในคอลัมน์โดยเฉพาะTenantสิ่งนี้จะได้ผล

New = New[New.Tenant != '']

นอกจากนี้ยังอาจใช้สำหรับการลบแถวที่มีค่าเฉพาะ - เพียงแค่เปลี่ยนสตริงเป็นค่าที่ต้องการ

หมายเหตุ : หากแทนที่จะเป็นหนึ่งสตริงที่ว่างเปล่ามีNaNแล้ว

New = New.dropna(subset=['Tenant'])
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.