J'essaie de trouver dans un dataframe s'il y a au moins X opérations consécutives (j'ai déjà inclus une colonne "Filter_OK" qui calcule si la ligne répond aux critères) et d'extraire ce groupe de lignes. / pre>
Pour cet exemple, si je recherche 4 opérations.
SORTIE DÉSIRÉE:
TRN TRN_DATE FILTER_OK 4 9652 06/04/2017 20:32:00 True 5 965 07/04/2017 12:52:00 True 6 752 10/04/2017 17:40:00 True 7 9541 10/04/2017 19:29:00 True 8 7452 11/04/2017 12:20:00 True
Comment puis-je sous-définir les opérations dont j'ai besoin?
4 Réponses :
Vous pouvez le faire en utilisant cumsum , suivi de groupby et de transform:
v.groupby(v).transform('size').ge(4) & df['FILTER_OK']
0 False
1 False
2 False
3 False
4 True
5 True
6 True
7 True
8 True
9 False
Name: FILTER_OK, dtype: bool
Tout d'abord, utilisez cumsum pour séparer les lignes en groupes:
v.groupby(v).transform('size')
0 3
1 3
2 3
3 6
4 6
5 6
6 6
7 6
8 6
9 1
Name: FILTER_OK, dtype: int64
v.groupby(v).transform('size').ge(4)
0 False
1 False
2 False
3 True
4 True
5 True
6 True
7 True
8 True
9 False
Name: FILTER_OK, dtype: bool
Ensuite, trouvez la taille de chaque groupe, puis déterminez quels groupes ont au moins X lignes (dans votre cas, 4):
v = (~df.FILTER_OK).cumsum() v 0 0 1 0 2 0 3 1 4 1 5 1 6 1 7 1 8 1 9 2 Name: FILTER_OK, dtype: int64
ET ce masque avec "FILTER_OK" pour nous assurer que nous ne prenons que les lignes valides qui correspondent aux critères.
v = (~df.FILTER_OK).cumsum()
df[v.groupby(v).transform('size').ge(4) & df['FILTER_OK']]
TRN TRN_DATE FILTER_OK
4 9652 2017-06-04 20:32:00 True
5 965 2017-07-04 12:52:00 True
6 752 2017-10-04 17:40:00 True
7 9541 2017-10-04 19:29:00 True
8 7452 2017-11-04 12:20:00 True
Cela fait en fait partie d'une opération "group by" (par colonne CRD). S'il y a deux groupes consécutifs de lignes (Crd 111 et 333) et que le deuxième groupe de lignes ne remplit pas la condition (pas 4 consécutifs True), la première ligne du groupe est incluse (la ligne en gras), alors qu'elle ne devrait pas 't
Ceci considérera également 4 False
s=df.FILTER_OK.astype(int).diff().ne(0).cumsum()
df[s.isin(s.value_counts().loc[lambda x : x>4].index)]
Out[784]:
TRN TRN_DATE FILTER_OK
4 9652 06/04/201720:32:00 True
5 965 07/04/201712:52:00 True
6 752 10/04/201717:40:00 True
7 9541 10/04/201719:29:00 True
8 7452 11/04/201712:20:00 True
consécutifs
Une des options possibles est d'utiliser itertools.groupby appelé sur la source
df.values .
Une différence importante de cette méthode, par rapport à pd.groupby est
que si la clé de groupe change, un nouveau groupe est créé.
Vous pouvez donc essayer le code suivant:
import pandas as pd
import itertools
# Source DataFrame
df = pd.DataFrame(data=[
[ 5153, '04/04/2017 11:40:00', True ], [ 7542, '04/04/2017 17:18:00', True ],
[ 875, '04/04/2017 20:08:00', True ], [ 74, '05/04/2017 20:30:00', False ],
[ 9652, '06/04/2017 20:32:00', True ], [ 965, '07/04/2017 12:52:00', True ],
[ 752, '10/04/2017 17:40:00', True ], [ 9541, '10/04/2017 19:29:00', True ],
[ 7452, '11/04/2017 12:20:00', True ], [ 9651, '12/04/2017 13:57:00', False ]],
columns=[ 'TRN', 'TRN_DATE', 'FILTER_OK' ])
# Work list
xx = []
# Collect groups for 'True' key with at least 5 members
for key, group in itertools.groupby(df.values, lambda x: x[2]):
lst = list(group)
if key and len(lst) >= 5:
xx.extend(lst)
# Create result DataFrame with the same column names
df2 = pd.DataFrame(data=xx, columns=df.columns)
Cela fait en fait partie d'une opération "group by" (par colonne CRD). S'il y a deux groupes consécutifs de lignes (Crd 111 et 333) et que le deuxième groupe de lignes ne remplit pas la condition (pas 4 consécutifs True), la première ligne du groupe est incluse (la ligne en gras), alors qu'elle ne devrait pas 't
CRD TRN TRN_DATE FILTER_OK
0 111 5153 04/04/2017 11:40:00 True
1 111 7542 04/04/2017 17:18:00 True
2 256 875 04/04/2017 20:08:00 True
3 365 74 05/04/2017 20:30:00 False
4 111 9652 06/04/2017 20:32:00 True
5 111 965 07/04/2017 12:52:00 True
6 111 752 10/04/2017 17:40:00 True
7 111 9541 10/04/2017 19:29:00 True
**8 333 7452 11/04/2017 12:20:00 True**
9 333 9651 12/04/2017 13:57:00 False
10 333 961 12/04/2017 13:57:00 False
11 333 871 12/04/2017 13:57:00 False
Actual output:
CRD TRN TRN_DATE FILTER_OK
4 111 9652 06/04/2017 20:32:00 True
5 111 965 07/04/2017 12:52:00 True
6 111 752 10/04/2017 17:40:00 True
7 111 9541 10/04/2017 19:29:00 True
**8 333 7452 11/04/2017 12:20:00 True**
Desired output:
CRD TRN TRN_DATE FILTER_OK
4 111 9652 06/04/2017 20:32:00 True
5 111 965 07/04/2017 12:52:00 True
6 111 752 10/04/2017 17:40:00 True
7 111 9541 10/04/2017 19:29:00 True