J'ai actuellement un dataframe composé de colonnes avec 1 et 0 comme valeurs, je voudrais parcourir les colonnes et supprimer celles qui ne sont composées que de 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)]
Dans quelles années est une liste de dataframes pour les différentes années que j'analyse, les uns se compose de colonnes avec un un en eux et les zéros est 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 les colonnes des unités 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.
Réponses:
df.loc[:, (df != 0).any(axis=0)]
Voici un aperçu de son fonctionnement:
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 différentes de zéro. (L'any
opération regroupe les valeurs le long de l'axe 0 - c'est-à-dire le long 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 zéro, réattribuez
df
:df = df.loc[:, (df != 0).any(axis=0)]
la source
df.loc[:, (~df.isin([0,1])).any(axis=0)]
fonctionnerait également.df = pd.DataFrame([[np.nan]*10])
,df.loc[:, df.any(axis=0)]
renvoie alors un DataFrame vide, tandis quedf.loc[:, (df != 0).any(axis=0)]
renvoie un DataFrame avec 10 colonnes.(df == 0).all(axis=0)
c'est plus simple.Voici une autre façon d'utiliser
df.replace(0,np.nan).dropna(axis=1,how="all")
Par rapport à la solution de unutbu, cette méthode est évidemment plus lente:
%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)
la source
Au cas où vous souhaiteriez une manière plus expressive d'obtenir les noms de colonne zéro afin que vous puissiez les imprimer / les enregistrer, et les déposer, sur place, par leurs 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 se décomposent:
# 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 ]
la source