Letakkan baris dengan semua nol dalam bingkai data panda


104

Saya dapat menggunakan pandas dropna()fungsionalitas untuk menghapus baris dengan beberapa atau semua kolom ditetapkan sebagai NA's. Apakah ada fungsi yang setara untuk menjatuhkan baris dengan semua kolom bernilai 0?

P   kt  b   tt  mky depth
1   0   0   0   0   0
2   0   0   0   0   0
3   0   0   0   0   0
4   0   0   0   0   0
5   1.1 3   4.5 2.3 9.0

Dalam contoh ini, kami ingin melepaskan 4 baris pertama dari bingkai data.

Terima kasih!


Sekadar klarifikasi, ini adalah dua pertanyaan. Satu, untuk menjatuhkan kolom dengan semua nilai sebagai 0. Tetapi juga, untuk fungsi yang setara dengan dropna () yang akan menghapus kolom dengan nilai apa pun sebagai 0.
alkimia

Jawaban:


114

Ternyata ini dapat diekspresikan dengan baik dalam mode vektor:

> df = pd.DataFrame({'a':[0,0,1,1], 'b':[0,1,0,1]})
> df = df[(df.T != 0).any()]
> df
   a  b
1  0  1
2  1  0
3  1  1

6
Bagus, tapi saya pikir Anda dapat menghindari negasi dengandf = df[(df.T != 0).any()]
Akavall

1
@Akavall Jauh lebih baik!
U2EF1

1
Sekadar catatan: OP ingin turun rows with all columns having value 0, tapi orang bisa menyimpulkan allmetode.
paulochf

1
Semua jawaban ini menjelaskan bagaimana kita bisa menjatuhkan baris dengan semua nol, Namun, saya ingin menjatuhkan baris, dengan 0 di kolom pertama. Dengan bantuan semua diskusi dan jawaban di posting ini, saya melakukan ini dengan melakukan df.loc [df.iloc [:, 0]! = 0]. Hanya ingin berbagi karena masalah ini terkait dengan pertanyaan ini !!
hemanta

2
Transpos tidak diperlukan, any () dapat menggunakan sumbu sebagai parameter. Jadi ini bekerja: df = df [df.any (axis = 1)]
Rahul Jha

130

Satu baris. Tidak diperlukan transpos:

df.loc[~(df==0).all(axis=1)]

Dan bagi mereka yang menyukai simetri, ini juga berfungsi ...

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

1
Untuk singkatnya (dan, menurut saya, kejelasan tujuan) menggabungkan ini dan komentar Akavall ini: df.loc[(df != 0).any(1)]. Kerja tim!
Dan Allan

1
+1, 30% lebih cepat dari transpose - 491 ke 614 mikrosec, dan saya suka axis=1karena eksplisit; lebih pythonic menurut saya
gt6989b

Beberapa penyebutan harus dibuat perbedaan antara menggunakan .all dan .any karena pertanyaan awal menyebutkan kesetaraan dropna. Jika Anda ingin menghapus semua baris dengan kolom yang berisi nol, Anda harus membalik .all dan .any pada jawaban di atas. Butuh beberapa saat untuk menyadari hal ini karena saya sedang mencari fungsi itu.
Zak Keirn

Ini tidak berhasil untuk saya, tetapi mengembalikan saya sama persisdf
Robvh

Apakah ada versi 'inplace' untuk ini? Saya melihat bahwa untuk menjatuhkan baris dalam df seperti yang diminta OP, ini perlu df = df.loc[(df!=0).all(axis=1)]dan df = df.loc[(df!=0).any(axis=1)]untuk menjatuhkan baris dengan nol seperti yang sebenarnya setara dengan dropna ().
alkimia

20

Saya mencari pertanyaan ini sebulan sekali dan selalu harus menggali jawaban terbaik dari komentar:

df.loc[(df!=0).any(1)]

Terima kasih Dan Allan!


2
Tidak perlu menggali. @ 8one6 telah memasukkan ini dalam jawabannya pada tahun 2014, bagian yang berbunyi: "Dan untuk mereka yang menyukai simetri ...".
Rahul Murmuria

15

Ganti nol dengan nandan kemudian jatuhkan baris dengan semua entri sebagai nan. Setelah itu ganti nandengan angka nol.

import numpy as np
df = df.replace(0, np.nan)
df = df.dropna(how='all', axis=0)
df = df.replace(np.nan, 0)

4
Ini akan gagal jika Anda memiliki NaN yang sudah ada sebelumnya dalam data.
OmerB

11

Saya pikir solusi ini adalah yang terpendek:

df= df[df['ColName'] != 0]

1
Dan itu juga ada di tempatnya!
Max Kleiner

@MaxKleiner di tempat berdasarkan penetapan ulang variabel
Lukas

7

Beberapa solusi yang menurut saya berguna saat mencari ini, terutama untuk kumpulan data yang lebih besar:

df[(df.sum(axis=1) != 0)]       # 30% faster 
df[df.values.sum(axis=1) != 0]  # 3X faster 

Melanjutkan contoh dari @ U2EF1:

In [88]: df = pd.DataFrame({'a':[0,0,1,1], 'b':[0,1,0,1]})

In [91]: %timeit df[(df.T != 0).any()]
1000 loops, best of 3: 686 µs per loop

In [92]: df[(df.sum(axis=1) != 0)]
Out[92]: 
   a  b
1  0  1
2  1  0
3  1  1

In [95]: %timeit df[(df.sum(axis=1) != 0)]
1000 loops, best of 3: 495 µs per loop

In [96]: %timeit df[df.values.sum(axis=1) != 0]
1000 loops, best of 3: 217 µs per loop

Pada kumpulan data yang lebih besar:

In [119]: bdf = pd.DataFrame(np.random.randint(0,2,size=(10000,4)))

In [120]: %timeit bdf[(bdf.T != 0).any()]
1000 loops, best of 3: 1.63 ms per loop

In [121]: %timeit bdf[(bdf.sum(axis=1) != 0)]
1000 loops, best of 3: 1.09 ms per loop

In [122]: %timeit bdf[bdf.values.sum(axis=1) != 0]
1000 loops, best of 3: 517 µs per loop

Apakah hal-hal buruk terjadi jika baris Anda berisi -1 dan 1?
Rhys Ulerich

Tentu saja, jumlahnya tidak akan berhasil jika Anda memiliki jumlah baris yang sama hingga 0. Berikut adalah solusi cepat untuk yang hanya sedikit lebih lambat: df[~(df.values.prod(axis=1) == 0) | ~(df.values.sum(axis=1)==0)]
clocker

Fungsi prod () tidak menyelesaikan apa pun. Jika Anda memiliki 0 di baris yang akan menghasilkan 0. Jika Anda harus menangani baris seperti ini: [-1, -0.5, 0, 0.5, 1], solusi Anda tidak akan berfungsi.
Rahul Murmuria

Berikut adalah versi yang benar yang bekerja 3x lebih cepat dari jawaban yang diterima:bdf[np.square(bdf.values).sum(axis=1) != 0]
Rahul Murmuria

5
import pandas as pd

df = pd.DataFrame({'a' : [0,0,1], 'b' : [0,0,-1]})

temp = df.abs().sum(axis=1) == 0      
df = df.drop(temp)

Hasil:

>>> df
   a  b
2  1 -1

Tidak berhasil untuk saya dengan kerangka data 1 kolom. DapatkanValueError: labels [True ... ] not contained in matrix
The Unfun Cat

alih-alih df = df.drop(temp)digunakandf = df.drop(df[temp].index)
Douglas Ferreira

3

Anda dapat menggunakan lambdafungsi cepat untuk memeriksa apakah semua nilai dalam baris tertentu adalah 0. Kemudian Anda bisa menggunakan hasil penerapan itu lambdasebagai cara untuk memilih hanya baris yang cocok atau tidak cocok dengan kondisi itu:

import pandas as pd
import numpy as np

np.random.seed(0)

df = pd.DataFrame(np.random.randn(5,3), 
                  index=['one', 'two', 'three', 'four', 'five'],
                  columns=list('abc'))

df.loc[['one', 'three']] = 0

print df
print df.loc[~df.apply(lambda row: (row==0).all(), axis=1)]

Hasil:

              a         b         c
one    0.000000  0.000000  0.000000
two    2.240893  1.867558 -0.977278
three  0.000000  0.000000  0.000000
four   0.410599  0.144044  1.454274
five   0.761038  0.121675  0.443863

[5 rows x 3 columns]
             a         b         c
two   2.240893  1.867558 -0.977278
four  0.410599  0.144044  1.454274
five  0.761038  0.121675  0.443863

[3 rows x 3 columns]

1

Alternatif lain:

# Is there anything in this row non-zero?
# df != 0 --> which entries are non-zero? T/F
# (df != 0).any(axis=1) --> are there 'any' entries non-zero row-wise? T/F of rows that return true to this statement.
# df.loc[all_zero_mask,:] --> mask your rows to only show the rows which contained a non-zero entry.
# df.shape to confirm a subset.

all_zero_mask=(df != 0).any(axis=1) # Is there anything in this row non-zero?
df.loc[all_zero_mask,:].shape

0

Bagi saya kode ini: df.loc[(df!=0).any(axis=0)] tidak berhasil. Ini mengembalikan set data yang tepat.

Sebagai gantinya, saya menggunakan df.loc[:, (df!=0).any(axis=0)] dan menjatuhkan semua kolom dengan nilai 0 dalam dataset

Fungsi .all()menjatuhkan semua kolom yang mana ada nilai nol dalam dataset saya.


-1
df = df [~( df [ ['kt'  'b'   'tt'  'mky' 'depth', ] ] == 0).all(axis=1) ]

Coba perintah ini bekerja dengan sempurna.


-2

Untuk menghapus semua kolom dengan nilai 0 di baris mana pun:

new_df = df[df.loc[:]!=0].dropna()
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.