Як видалити стовпець, який містить лише нулі в Pandas?


87

На даний момент у мене є фрейм даних, що складається зі стовпців із значеннями 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)]

У яких роках є список фреймів даних за різні роки, які я аналізую, вони складаються зі стовпців з одиницею в них, а нулі - це список стовпців, що містять усі нулі. Чи є кращий спосіб видалити стовпець на основі умови? З якоїсь причини мені доводиться перевіряти, чи є ті стовпці також у списку нулів, і видаляти їх зі списку нулів, щоб отримати список усіх нульових стовпців.


Відповіді:


214
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)]
морфей

1
df.loc[:, (~df.isin([0,1])).any(axis=0)]також спрацює.
unutbu

1
@IgorFobia: Багато речей хибні, не дорівнюючи 0. Наприклад, порожні рядки або None або NaN. Для того, щоб продемонструвати різницю, якщо df = pd.DataFrame([[np.nan]*10]), то df.loc[:, df.any(axis=0)]повертає порожню DataFrame, а df.loc[:, (df != 0).any(axis=0)]повертає DataFrame з 10 колонами.
unutbu

4
Я вважаю, що це легше зрозуміти, якщо ми перевіряємо, чи умова відповідає дійсності, замість того, щоб перевірити, чи умова, що не відповідає дійсності, ніколи не виконується. Я думаю, (df == 0).all(axis=0)це прямолінійніше.
Ryszard Cetnarski

2
Дякую за поломку. Це зробило речі дуже чіткими.
Регі Метью

7

Ось альтернативний спосіб використання

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

Порівняно з рішенням унутбу, цей шлях очевидно повільніший:

%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 ]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.