Перекиньте рядки з усіма нулями у фрейм даних pandas


104

Я можу використовувати pandas dropna()функціональність для видалення рядків з деякими або всіма стовпцями, встановленими як NA's. Чи існує еквівалентна функція для скидання рядків із усіма стовпцями, що мають значення 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

У цьому прикладі ми хотіли б видалити перші 4 рядки з кадру даних.

Дякую!


Тільки для уточнення, це два питання. Перший - скинути стовпці з усіма значеннями як 0. Але також для функції, еквівалентної dropna (), яка скидає стовпці з будь-яким значенням як 0.
алхімія

Відповіді:


113

Виявляється, це можна гарно виразити векторизованим способом:

> 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
Приємно, але я думаю, що ви можете уникнути заперечення за допомогоюdf = df[(df.T != 0).any()]
Акавалл

1
@Akavall Набагато краще!
U2EF1,

1
Тільки примітка: OP хотів відмовитись rows with all columns having value 0, але можна зробити висновок про allметод.
paulochf

1
Усі ці відповіді пояснюють, як ми можемо скидати рядки з усіма нулями. Однак я хотів скинути рядки з 0 у першому стовпці. За допомогою усіх обговорень та відповідей у ​​цій публікації я зробив це, виконавши df.loc [df.iloc [:, 0]! = 0]. Просто хотів поділитися, оскільки ця проблема пов’язана з цим питанням !!
hemanta

2
Транспонування не є необхідним, будь-який () може взяти вісь як параметр. Отже, це працює: df = df [df.any (вісь = 1)]
Рахул Джа

130

Однокласний. Транспонування не потрібне:

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

І для тих, хто любить симетрію, це також працює ...

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

1
Для стислості (і, на мій погляд, ясність мети) поєднати це і коментар Akavall в: df.loc[(df != 0).any(1)]. Командна робота!
Ден Аллан,

1
+1, 30% швидше транспонування - від 491 до 614 мікросекунд, і мені подобається axis=1явність; на мій погляд більш пітонічний
gt6989b

Деякі згадки слід зробити про різницю між використанням .all та .any, оскільки в оригінальному питанні згадувалося про еквівалентність dropna. Якщо ви хочете скинути всі рядки з будь-яким стовпцем, що містить нуль, вам доведеться змінити .all та .any у відповіді вище. Мені знадобився деякий час, щоб усвідомити це, коли я шукав цю функціональність.
Zak Keirn

Це не працює для мене, але повертає мені точно те самеdf
Робвх

Чи існує "вбудована" версія цього? Я бачу, що для скидання рядків у df, як вимагав OP, це повинно було б бути df = df.loc[(df!=0).all(axis=1)]і df = df.loc[(df!=0).any(axis=1)]скидання рядків з будь-якими нулями, що було б фактичним еквівалентом dropna ().
алхімія

20

Я дивлюся це питання приблизно раз на місяць і завжди повинен витягувати найкращу відповідь із коментарів:

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

Дякую Ден Аллан!


2
Копати не потрібно. @ 8one6 включив це у свою відповідь ще у 2014 році, таку частину, яка говорить: "І для тих, хто любить симетрію ...".
Рахул Мурмурія,

14

Замініть нулі на, nanа потім опустіть рядки з усіма записами як nan. Після цього замінити nanнулями.

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

4
Це не вдасться, якщо у вас є будь-які раніше існуючі NaN-і в даних.
OmerB


7

Кілька рішень, які я виявив корисними, шукаючи це, особливо для більших наборів даних:

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

Продовжуючи приклад з @ 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

На більшому наборі даних:

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

Чи трапляються погані речі, якщо ваш рядок містить -1 і 1?
Rhys Ulerich

Звичайно, сума не працювала б, якщо б у вас були рівні рядки, що додавали б до 0. Ось короткий обхідний шлях до того, що лише трохи повільніше: df[~(df.values.prod(axis=1) == 0) | ~(df.values.sum(axis=1)==0)]
clocker 17.03.17

Функція prod () нічого не вирішує. Якщо у вас є 0 у рядку, який поверне 0. Якщо вам потрібно обробити такий рядок: [-1, -0,5, 0, 0,5, 1], жодне з ваших рішень не буде працювати.
Рахул Мурмурія,

Ось правильна версія, яка працює втричі швидше прийнятої відповіді:bdf[np.square(bdf.values).sum(axis=1) != 0]
Рахул Мурмурія

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)

Результат:

>>> df
   a  b
2  1 -1

Не працював у мене з 1-стовпчастим фреймом даних. ПотрапивValueError: labels [True ... ] not contained in matrix
Незручний кіт

замість df = df.drop(temp)використанняdf = df.drop(df[temp].index)
Дуглас Феррейра

3

Ви можете скористатися швидкою lambdaфункцією, щоб перевірити, чи всі значення в даному рядку 0. Тоді ви можете використовувати результат застосування цього lambdaяк спосіб вибрати лише ті рядки, які відповідають або не відповідають цій умові:

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

Урожайність:

              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

Інша альтернатива:

# 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

Для мене цей код: df.loc[(df!=0).any(axis=0)] не працював. Він повернув точний набір даних.

Натомість я використав df.loc[:, (df!=0).any(axis=0)]і скинув усі стовпці зі значеннями 0 у наборі даних

Функція .all()скинула всі стовпці, у яких є будь-які нульові значення в моєму наборі даних.



-2

Щоб скинути всі стовпці зі значеннями 0 у будь-який рядок:

new_df = df[df.loc[:]!=0].dropna()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.