Atualmente, tenho um dataframe que consiste em colunas com valores de 1 e 0, gostaria de iterar pelas colunas e excluir aquelas que são compostas de apenas 0s. Aqui está o que tentei até agora:
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)]
Em que anos é uma lista de quadros de dados para os vários anos que estou analisando, uns consiste em colunas com um e zeros é uma lista de colunas contendo todos zeros. Existe uma maneira melhor de excluir uma coluna com base em uma condição? Por alguma razão, tenho que verificar se as colunas de uns estão na lista de zeros também e removê-las da lista de zeros para obter uma lista de todas as colunas de zero.
Respostas:
df.loc[:, (df != 0).any(axis=0)]
Aqui está um resumo de como 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
cria um DataFrame booleano que é True, ondedf
é diferente de zero: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)
retorna uma série booleana indicando quais colunas têm entradas diferentes de zero. (Aany
operação agrega valores ao longo do eixo 0 - ou seja, ao longo das linhas - em um único valor booleano. Portanto, o resultado é um valor booleano para cada coluna.)In [78]: (df != 0).any(axis=0) Out[78]: 0 True 1 False 2 True 3 False dtype: bool
E
df.loc
pode ser usado para selecionar essas colunas: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 "excluir" as colunas zero, reatribua
df
:df = df.loc[:, (df != 0).any(axis=0)]
fonte
df.loc[:, (~df.isin([0,1])).any(axis=0)]
também funcionaria.df = pd.DataFrame([[np.nan]*10])
, thendf.loc[:, df.any(axis=0)]
retorna um DataFrame vazio, enquantodf.loc[:, (df != 0).any(axis=0)]
retorna um DataFrame com 10 colunas.(df == 0).all(axis=0)
é mais direto.Aqui está uma maneira alternativa de usar
df.replace(0,np.nan).dropna(axis=1,how="all")
Comparado com a solução do unutbu, este caminho é obviamente mais lento:
%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)
fonte
Caso você queira uma maneira mais expressiva de obter os nomes de coluna zero, para poder imprimi-los / registrá-los e soltá-los no local pelos nomes :
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)
Alguns quebram:
# 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 ]
fonte