Bagaimana cara menghapus kolom yang hanya berisi nol di Pandas?

90

Saat ini saya memiliki kerangka data yang terdiri dari kolom dengan nilai 1 dan 0, saya ingin mengulang melalui kolom dan menghapus yang hanya terdiri dari 0. Inilah yang telah saya coba sejauh ini:

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

Di mana tahun adalah daftar kerangka data untuk berbagai tahun yang saya analisis, yang terdiri dari kolom dengan satu di dalamnya dan nol adalah daftar kolom yang berisi semua nol. Apakah ada cara yang lebih baik untuk menghapus kolom berdasarkan kondisi? Untuk beberapa alasan saya harus memeriksa apakah kolom satu ada di daftar nol juga dan menghapusnya dari daftar nol untuk mendapatkan daftar semua kolom nol.

pengguna2587593
sumber
Kemungkinan duplikat dari Menghapus baris DataFrame di Pandas berdasarkan nilai kolom
Shihe Zhang

Jawaban:

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

Berikut ini rincian cara kerjanya:

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 != 0membuat DataFrame boolean yang True di mana dfbukan nol:

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)mengembalikan Seri boolean yang menunjukkan kolom mana yang memiliki entri bukan nol. ( anyOperasi menggabungkan nilai sepanjang sumbu 0 - yaitu di sepanjang baris - menjadi satu nilai boolean. Karenanya hasilnya adalah satu nilai boolean untuk setiap kolom.)

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

Dan df.locdapat digunakan untuk memilih kolom tersebut:

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

[2 rows x 2 columns]

Untuk "menghapus" kolom nol, tetapkan kembali df:

df = df.loc[:, (df != 0).any(axis=0)]
unutbu
sumber
Saya mencoba ini untuk menjatuhkan kolom jika memiliki 0 atau 1 di dalamnya dan memberikan kesalahan: df = df.loc [:, (df! = 0 & df! = 1) .any (axis = 0)]
morpheus
1
df.loc[:, (~df.isin([0,1])).any(axis=0)]juga akan berhasil.
unutbu
1
@IgorFobia: Banyak hal adalah False-ish tanpa 0. Misalnya, string kosong atau None atau NaN. Untuk mendemonstrasikan perbedaannya, jika df = pd.DataFrame([[np.nan]*10]), maka df.loc[:, df.any(axis=0)]kembalikan DataFrame kosong, sementara df.loc[:, (df != 0).any(axis=0)]kembalikan DataFrame dengan 10 kolom.
unutbu
5
Saya percaya lebih mudah untuk memahami jika kita memeriksa suatu kondisi benar, daripada memeriksa apakah kondisi tidak benar tidak pernah tidak puas. Saya pikir (df == 0).all(axis=0)lebih mudah.
Ryszard Cetnarski
2
Terima kasih atas kerusakannya. Itu membuat segalanya menjadi sangat jelas.
Regi Mathew
7

Berikut adalah cara alternatif yang bisa digunakan

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

Dibandingkan dengan solusi unutbu, cara ini jelas lebih lambat:

%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)
Jeremy Z
sumber
0

Jika Anda menginginkan cara yang lebih ekspresif untuk mendapatkan nama kolom nol sehingga Anda dapat mencetak / mencatatnya, dan meletakkannya, di tempat, dengan namanya :

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)

Beberapa rusak:

# 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 ]
mork
sumber
0

Jika ada beberapa nilai NaN di kolom Anda, Anda mungkin ingin menggunakan pendekatan ini jika Anda ingin menghapus kolom yang memiliki 0 dan NaN:

df.loc[:, df.sum() != 0]
cyrilb38
sumber