Извлечь группы последовательных значений, имеющих размер больше указанного - PullRequest
0 голосов
/ 02 января 2019

Я пытаюсь найти в кадре данных, если есть хотя бы X последовательных операций (я уже включил столбец «Filter_OK», который вычисляет, соответствует ли строка критериям), и извлечь эту группу строк.

      TRN     TRN_DATE          FILTER_OK  
0   5153    04/04/2017 11:40:00      True
1   7542    04/04/2017 17:18:00      True
2   875     04/04/2017 20:08:00      True
3   74      05/04/2017 20:30:00     False
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
9   9651    12/04/2017 13:57:00     False

В этом примере, если я ищу 4 операции.
ТРЕБУЕТСЯ ВЫХОД:

    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

Как я могу поднастроить операции, которые мне нужны?

Ответы [ 4 ]

0 голосов
/ 30 мая 2019

На самом деле это часть операции «Группировать по» (по столбцу CRD). Если есть две последовательные группы строк (Crd 111 и 333), а вторая группа строк не удовлетворяет условию (не 4 последовательных True), первая строка группы включается (жирная линия), когда она должна «т

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
0 голосов
/ 02 января 2019

Это также будет считать 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
0 голосов
/ 02 января 2019

Один из возможных вариантов - использовать itertools.groupby, вызываемый по источнику. df.values.

Важным отличием этого метода от pd.groupby является что при изменении ключа группирования создается новая группа.

Так что вы можете попробовать следующий код:

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)
0 голосов
/ 02 января 2019

Вы можете сделать это, используя cumsum, затем groupby и transform:

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

Подробности
Сначала используйте cumsum чтобы разделить строки на группы:

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

Далее найдите размер каждой группы, а затем выясните, какие группы имеют хотя бы X строк (в вашем случае 4):

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

И эту маску с "FILTER_OK", чтобы гарантировать, что мы берем только допустимые строки, которые соответствуют критериям.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...