web-dev-qa-db-fra.com

Supprimer la colonne dans les pandas s'il s'agit de zéros

Actuellement, j'ai une base de données composée de colonnes avec des valeurs de 1 et de 0, j'aimerais parcourir les colonnes et supprimer celles qui ne contiennent que des 0. Voici ce que j'ai essayé jusqu'à présent:

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 quelles années est une liste de trames de données pour les différentes années que j'analyse, les colonnes sont constituées de colonnes avec un et les zéros sont une liste de colonnes contenant tous les zéros. Existe-t-il un meilleur moyen de supprimer une colonne en fonction d'une condition? Pour une raison quelconque, je dois vérifier si ces colonnes sont également dans la liste des zéros et les supprimer de la liste des zéros pour obtenir une liste de toutes les colonnes zéro. 

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

Voici un aperçu de la façon dont cela fonctionne:

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 crée un DataFrame booléen qui est True, où df est différent de zéro:

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) renvoie une série booléenne indiquant quelles colonnes ont des entrées non nulles. (L’opération any agrège les valeurs de l’axe 0, c’est-à-dire des lignes, en une seule valeur booléenne. Le résultat est donc une valeur booléenne pour chaque colonne.)

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

Et df.loc peut être utilisé pour sélectionner ces colonnes:

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

[2 rows x 2 columns]

Pour "supprimer" les colonnes nuls, réaffectez df:

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

Au cas où vous souhaiteriez un moyen plus expressif d'obtenir les noms de colonne zéro afin que vous puissiez les imprimer/les consigner et les supprimer, sur place, par leur noms :

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)

Certains tombent en panne:

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