ฉันจะลบคอลัมน์ที่มีเฉพาะเลขศูนย์ใน Pandas ได้อย่างไร


90

ปัจจุบันฉันมี dataframe ซึ่งประกอบด้วยคอลัมน์ที่มี 1 และ 0 เป็นค่าฉันต้องการวนซ้ำในคอลัมน์และลบคอลัมน์ที่ประกอบด้วย 0 เท่านั้น นี่คือสิ่งที่ฉันได้ลองแล้ว:

ones = []
zeros = []
for year in years:
    for i in range(0,599):
        if year[str(i)].values.any() == 1:
            ones.append(i)
        if year[str(i)].values.all() == 0:
            zeros.append(i)
    for j in ones:
        if j in zeros:
            zeros.remove(j)
    for q in zeros:
        del year[str(q)]

ในปีใดที่เป็นรายการของดาต้าเฟรมสำหรับปีต่างๆที่ฉันกำลังวิเคราะห์ซึ่งประกอบด้วยคอลัมน์ที่มีคอลัมน์อยู่ในนั้นและศูนย์คือรายการคอลัมน์ที่มีศูนย์ทั้งหมด มีวิธีที่ดีกว่าในการลบคอลัมน์ตามเงื่อนไขหรือไม่? ด้วยเหตุผลบางอย่างฉันต้องตรวจสอบว่าคอลัมน์นั้นอยู่ในรายการศูนย์หรือไม่และลบออกจากรายการศูนย์เพื่อรับรายการคอลัมน์ศูนย์ทั้งหมด


คำตอบ:


220
df.loc[:, (df != 0).any(axis=0)]

รายละเอียดวิธีการทำงานมีดังนี้

In [74]: import pandas as pd

In [75]: df = pd.DataFrame([[1,0,0,0], [0,0,1,0]])

In [76]: df
Out[76]: 
   0  1  2  3
0  1  0  0  0
1  0  0  1  0

[2 rows x 4 columns]

df != 0สร้างบูลีน DataFrame ซึ่งเป็น True โดยที่dfไม่ใช่ศูนย์:

In [77]: df != 0
Out[77]: 
       0      1      2      3
0   True  False  False  False
1  False  False   True  False

[2 rows x 4 columns]

(df != 0).any(axis=0)ส่งคืนชุดบูลีนที่ระบุว่าคอลัมน์ใดมีรายการที่ไม่ใช่ศูนย์ (การanyดำเนินการจะรวมค่าตามแกน 0 - เช่นตามแถว - เป็นค่าบูลีนเดียวดังนั้นผลลัพธ์คือค่าบูลีนหนึ่งค่าสำหรับแต่ละคอลัมน์

In [78]: (df != 0).any(axis=0)
Out[78]: 
0     True
1    False
2     True
3    False
dtype: bool

และdf.locสามารถใช้เพื่อเลือกคอลัมน์เหล่านั้น:

In [79]: df.loc[:, (df != 0).any(axis=0)]
Out[79]: 
   0  2
0  1  0
1  0  1

[2 rows x 2 columns]

ในการ "ลบ" คอลัมน์ศูนย์ให้กำหนดใหม่df:

df = df.loc[:, (df != 0).any(axis=0)]

ฉันกำลังพยายามที่จะวางคอลัมน์หากมี 0 หรือ 1 อยู่ในนั้นและทำให้เกิดข้อผิดพลาด: df = df.loc [:, (df! = 0 & df! = 1) .any (แกน = 0)]
morpheus

1
df.loc[:, (~df.isin([0,1])).any(axis=0)]ก็ใช้ได้เช่นกัน
unutbu

1
@IgorFobia: สิ่งต่างๆมากมายเป็น False-ish โดยไม่ต้องเป็น 0 ตัวอย่างเช่นสตริงว่างหรือไม่มีหรือ NaN เพื่อแสดงให้เห็นถึงความแตกต่างถ้าdf = pd.DataFrame([[np.nan]*10])จากนั้นdf.loc[:, df.any(axis=0)]จะส่งคืน DataFrame ที่ว่างเปล่าในขณะที่df.loc[:, (df != 0).any(axis=0)]ส่งคืน DataFrame ที่มี 10 คอลัมน์
unutbu

5
ฉันเชื่อว่ามันง่ายกว่าที่จะเข้าใจหากเราตรวจสอบว่าเงื่อนไขเป็นจริงแทนที่จะตรวจสอบว่าเงื่อนไขไม่เป็นจริงหรือไม่ก็ไม่เป็นที่พอใจ ผมว่า(df == 0).all(axis=0)ตรงไปตรงมามากกว่า
Ryszard Cetnarski

2
ขอบคุณสำหรับรายละเอียด มันทำให้สิ่งต่างๆชัดเจนมาก
Regi Mathew

7

นี่คือทางเลือกอื่นในการใช้งานคือ

df.replace(0,np.nan).dropna(axis=1,how="all")

เมื่อเทียบกับการแก้ปัญหาของ unutbu วิธีนี้จะช้ากว่าอย่างเห็นได้ชัด:

%timeit df.loc[:, (df != 0).any(axis=0)]
652 µs ± 5.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit df.replace(0,np.nan).dropna(axis=1,how="all")
1.75 ms ± 9.49 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

0

ในกรณีที่คุณต้องการวิธีที่ชัดเจนยิ่งขึ้นในการรับชื่อศูนย์คอลัมน์เพื่อให้คุณสามารถพิมพ์ / บันทึกและวางลงในสถานที่ตามชื่อ :

zero_cols = [ col for col, is_zero in ((df == 0).sum() == df.shape[0]).items() if is_zero ]
df.drop(zero_cols, axis=1, inplace=True)

บางส่วนพัง:

# a pandas Series with {col: is_zero} items
# is_zero is True when the number of zero items in that column == num_all_rows
(df == 0).sum() == df.shape[0])

# a list comprehension of zero_col_names is built from the_series
[ col for col, is_zero in the_series.items() if is_zero ]

0

ในกรณีที่มีค่า NaN ในคอลัมน์ของคุณคุณอาจต้องการใช้วิธีนี้หากคุณต้องการลบคอลัมน์ที่มีทั้ง 0 และ NaN:

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