6
votes

Compter le nombre de fois qu'un booléen passe de True à False dans une colonne

J'ai une colonne dans un dataframe qui est rempli de booléens et je veux compter combien de fois il passe de True à False.

Je peux faire cela en convertissant les booléens en 1 et en 0, puis en utilisant df.diff et en divisant cette réponse par 2

import pandas as pd

d = {'Col1': [True, True, True, False, False, False, True, True, True, True, False, False, False, True, True, False, False, True, ]}


df = pd.DataFrame(data=d)


print(df)

0    True
1    True
2    True
3   False
4   False
5   False
6    True
7    True
8    True
9    True
10  False
11  False
12  False
13   True
14   True
15  False
16  False

Mon résultat attendu serait Le nombre de fois où False est apparu est de 3


1 commentaires

C'est une dupe. À la recherche du meilleur lien. En attendant, essayez ceci ou ceci ou ceci ou ceci .


5 Réponses :


5
votes

Vous pouvez effectuer un bit à bit et du Col1 avec un masque indiquant où les changements se produisent dans les lignes successives:

(df & (df != df.shift(1))).sum()

Col1    3
Col2    3
dtype: int64

Où le masque, est obtenu en comparant Col1 avec une version décalée de lui-même ( pd.shift ):

df.Col1 != df.Col1.shift(1)

0      True
1     False
2     False
3      True
4     False
5     False
6      True
7     False
8     False
9     False
10     True
11    False
12    False
13     True
14    False
15    False
16    False
17    False
Name: Col1, dtype: bool

Pour plusieurs colonnes, vous pouvez faire exactement la même chose (Ici j'ai testé avec un col2 identique à col1 )

(df.Col1 & (df.Col1 != df.Col1.shift(1))).sum()
3


3 commentaires

Existe-t-il un moyen d'appliquer cela à l'ensemble du dataframe? (j'aurais dû dire que j'avais plusieurs colonnes comme celle-ci)


Ne sera-t-il pas également capturé lorsque False passe à True au début d'une série? Il suffit de vérifier puisque OP a spécifié True à False uniquement.


Non, parce que cela fait une logique et avec la série. Ainsi, les seuls True restants seront ceux qui étaient déjà True dans df



2
votes

Donnez simplement une idée différente

df.cumsum()[~df.Col1].nunique()
Out[408]: 
Col1    3
dtype: int64


0 commentaires

3
votes

Notez que soustraire True ( 1 ) de False ( 0 ) en termes entiers donne -1 :

res = df.astype(int).diff().eq(-1).sum()

Pour appliquer à travers un dataframe booléen, vous pouvez construire une étiquette de mappage de série pour compter:

res = df['Col1'].astype(int).diff().eq(-1).sum()  # 3

p >


0 commentaires

1
votes

Ma stratégie consistait à trouver où se situait la différence d'une ligne à l'autre. (En considérant que les vrais sont des 1 et que les faux sont des 0, bien sûr.)

Ainsi, Colm1 - Colm1.shift () représente la valeur Delta où un 1 est un passage de False à True, 0 No Change, et -1 shift de Vrai à Faux.

import pandas as pd

d = {'Col1': [True, True, True, False, False, False, True, True, True, True, False, False, False, True, True, False, False, True, ]}

df = pd.DataFrame(data=d)
df['delta'] = df['Col1'] - df['Col1'].shift()
BooleanShifts = df['delta'].value_counts()
print(BooleanShifts[-1])

Après avoir obtenu la valeur compte comme un dict de ces [1, 0, -1] valeurs, vous pouvez sélectionner uniquement les -1 et obtenir le nombre de fois DF est passé à une valeur fausse à partir d'une valeur vraie. J'espère que cela a aidé à répondre à votre question!


0 commentaires

1
votes

Moins concise mais peut-être une approche plus lisible serait:

count = 0
for item in zip(d['Col1'], d['Col1'][1:]):
    if item == (True, False):
        count += 1
print(count)


4 commentaires

Le bouclage sur un dataframe n'est-il pas considéré comme une mauvaise pratique?


Cela pourrait être plus lent peut-être, mais je ne vois pas ce qui pourrait mal tourner. Pourquoi diriez-vous que c'est une mauvaise pratique?


Je ne suis en aucun cas un expert dans l'utilisation des pandas, mais lorsque je cherchais une solution à l'un de mes problèmes, la plupart des commentaires et des réponses suggéraient de ne pas utiliser une boucle for pour faire des choses. Parce que comme vous l'avez dit, c'est plus lent, j'ai récemment compris comment faire quelque chose sans utiliser une boucle for et cette partie est environ 3 fois plus rapide maintenant, ce qui n'a pas vraiment d'importance pour les petits ensembles de données


En effet. Si la trame de données n'est pas énorme et que la vitesse n'est pas un problème, cette solution fonctionnera très bien. Personnellement, je préfère la lisibilité à la rapidité. Cette boucle peut être facilement comprise par n'importe qui, même sans expérience avec les Pandas.