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!

pengguna308827
sumber
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
U2EF1
sumber
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)]
8one6
sumber
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!

Kucing Unfun
sumber
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)
stackpopped
sumber
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]
ikbel benab
sumber
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
pencatat waktu
sumber
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
Akavall
sumber
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]
8one6
sumber
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
bmc
sumber
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.

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

Coba perintah ini bekerja dengan sempurna.

Kumar Prasanna
sumber
-2

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

new_df = df[df.loc[:]!=0].dropna()
Yapi
sumber