¿Cómo elimino una columna que contiene solo ceros en Pandas?

Actualmente tengo un dataframe que consta de columnas con 1 y 0 como valores, me gustaría iterar a través de las columnas y eliminar las que se componen de solo 0 Esto es lo que he intentado hasta ahora:

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

En qué años se encuentra una lista de marcos de datos para los distintos años que analizo, unos consisten en columnas con uno en ellos y ceros es una lista de columnas que contienen todos los ceros. ¿Hay una mejor manera de eliminar una columna basada en una condición? Por alguna razón, tengo que comprobar si las columnas de unos están también en la lista de ceros y eliminarlas de la lista de ceros para obtener una lista de todas las columnas de cero.

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

Aquí está un desglose de cómo funciona:

 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 crea un DataFrame booleano que es True donde df es distinto de cero:

 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) devuelve una serie booleana que indica qué columnas tienen entradas distintas de cero. (Las operaciones de any operación agregan valores a lo largo del eje 0, es decir, a lo largo de las filas, en un único valor booleano. Por lo tanto, el resultado es un valor booleano para cada columna).

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

Y df.loc se puede usar para seleccionar esas columnas:

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

Para “borrar” las columnas cero, reasigne df :

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

Aquí hay una forma alternativa de usar es

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

Comparado con la solución de unutbu, esta forma es obviamente más lenta:

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

En caso de que desee una forma más expresiva de obtener los nombres de cero columnas para poder imprimirlos / registrarlos y soltarlos, en el lugar, por sus nombres :

 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) 

Algunos se rompen:

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