Подсчет значения в последовательной отметке времени в pandas - PullRequest
0 голосов
/ 19 января 2020
Hour              Site
01/08/2020 00:00    A
01/08/2020 00:00    B
01/08/2020 00:00    C
01/08/2020 00:00    D
01/08/2020 01:00    A
01/08/2020 01:00    B
01/08/2020 01:00    E
01/08/2020 01:00    F
01/08/2020 02:00    A
01/08/2020 02:00    E
01/08/2020 03:00    C
01/08/2020 03:00    G
 …..    
01/08/2020 04:00    x
01/08/2020 04:00    s

 …..    

01/08/2020 23:00    G
02/08/2020 00:00    G

У меня есть датафрейм, как указано выше. Я хочу посчитать, сколько раз сайт заходит в течение нескольких часов подряд, а также время начала и окончания. Где в каждом часе есть несколько сайтов. Например, сайт A появляется в 3-х последовательных временных метках, а затем снова в одной временной. Я хочу вывод, как показано ниже, или в более эффективном формате.

Hour              Site count    period_start    Period_end
01/08/2020 00:00    A   3   01/08/2020 00:00    01/08/2020 03:00
01/08/2020 00:00    B   2   01/08/2020 00:00    01/08/2020 01:00
01/08/2020 00:00    C   1   ….. …
01/08/2020 00:00    D   1   ….  ….
01/08/2020 01:00    A   3   01/08/2020 00:00    01/08/2020 03:00
01/08/2020 01:00    B   2   ….  ….
01/08/2020 01:00    E   2   ….  ….
01/08/2020 01:00    F   1   ….  ….
01/08/2020 02:00    A   3   01/08/2020 00:00    01/08/2020 03:00
01/08/2020 02:00    E   2   ….  ….
01/08/2020 03:00    C   1   ….  ….
01/08/2020 03:00    G   1   ….  ….
 …..            ….  ….
01/08/2020 04:00    x   1   01/08/2020 04:00    01/08/2020 04:00
01/08/2020 04:00    s   1   ….  ….
            ….  ….
 …..            ….  ….
            ….  ….
01/08/2020 23:00    G   2   ….  ….
02/08/2020 00:00    G   2   ….  ….

Спасибо!

Ответы [ 2 ]

1 голос
/ 19 января 2020

Исходный фрейм данных

print(df)
                  Hour Site
0  2020-01-08 00:00:00    A
1  2020-01-08 00:00:00    B
2  2020-01-08 00:00:00    C
3  2020-01-08 00:00:00    D
4  2020-01-08 01:00:00    A
5  2020-01-08 01:00:00    B
6  2020-01-08 01:00:00    E
7  2020-01-08 01:00:00    F
8  2020-01-08 02:00:00    A
9  2020-01-08 02:00:00    E
10 2020-01-08 03:00:00    C
11 2020-01-08 03:00:00    G
12 2020-01-08 04:00:00    X
13 2020-01-08 04:00:00    s
14 2020-01-08 23:00:00    G
15 2020-02-08 00:00:00    G

Мой подход

#if it is necesary
#df['Hour']=pd.to_datetime(df['Hour'])
#df=df.sort_values('Hour')

g=( df.groupby('Site')['Hour'].diff().ne(pd.Timedelta(hours=1))
      .groupby(df['Site']).cumsum() )

groups = df.groupby(['Site',g])['Hour']
new_df = df.assign(count = groups.transform('size'),
                   Period_start = groups.transform('first'),
                   Period_end = groups.transform('last'))

print(new_df)

Выход

                  Hour Site  count        Period_start          Period_end
0  2020-01-08 00:00:00    A      3 2020-01-08 00:00:00 2020-01-08 02:00:00
1  2020-01-08 00:00:00    B      2 2020-01-08 00:00:00 2020-01-08 01:00:00
2  2020-01-08 00:00:00    C      1 2020-01-08 00:00:00 2020-01-08 00:00:00
3  2020-01-08 00:00:00    D      1 2020-01-08 00:00:00 2020-01-08 00:00:00
4  2020-01-08 01:00:00    A      3 2020-01-08 00:00:00 2020-01-08 02:00:00
5  2020-01-08 01:00:00    B      2 2020-01-08 00:00:00 2020-01-08 01:00:00
6  2020-01-08 01:00:00    E      2 2020-01-08 01:00:00 2020-01-08 02:00:00
7  2020-01-08 01:00:00    F      1 2020-01-08 01:00:00 2020-01-08 01:00:00
8  2020-01-08 02:00:00    A      3 2020-01-08 00:00:00 2020-01-08 02:00:00
9  2020-01-08 02:00:00    E      2 2020-01-08 01:00:00 2020-01-08 02:00:00
10 2020-01-08 03:00:00    C      1 2020-01-08 03:00:00 2020-01-08 03:00:00
11 2020-01-08 03:00:00    G      1 2020-01-08 03:00:00 2020-01-08 03:00:00
12 2020-01-08 04:00:00    X      1 2020-01-08 04:00:00 2020-01-08 04:00:00
13 2020-01-08 04:00:00    s      1 2020-01-08 04:00:00 2020-01-08 04:00:00
14 2020-01-08 23:00:00    G      1 2020-01-08 23:00:00 2020-01-08 23:00:00
15 2020-02-08 00:00:00    G      1 2020-02-08 00:00:00 2020-02-08 00:00:00

Если вы хотите маску, если число равно 1

#if it is necesary
#df['Hour']=pd.to_datetime(df['Hour'])
#df=df.sort_values('Hour')

g=( df.groupby('Site')['Hour'].diff().ne(pd.Timedelta(hours=1))
      .groupby(df['Site']).cumsum() )

groups = df.groupby(['Site',g])['Hour']
new_df =( df.assign(count = groups.transform('size'))
            .assign(Period_start = lambda x: groups.transform('first')
                                                   .where(x['count'].gt(1)),
                   Period_end = lambda x: groups.transform('last')
                                                .where(x['count'].gt(1))) )
print(new_df)

Выход

                  Hour Site  count        Period_start          Period_end
0  2020-01-08 00:00:00    A      3 2020-01-08 00:00:00 2020-01-08 02:00:00
1  2020-01-08 00:00:00    B      2 2020-01-08 00:00:00 2020-01-08 01:00:00
2  2020-01-08 00:00:00    C      1                 NaT                 NaT
3  2020-01-08 00:00:00    D      1                 NaT                 NaT
4  2020-01-08 01:00:00    A      3 2020-01-08 00:00:00 2020-01-08 02:00:00
5  2020-01-08 01:00:00    B      2 2020-01-08 00:00:00 2020-01-08 01:00:00
6  2020-01-08 01:00:00    E      2 2020-01-08 01:00:00 2020-01-08 02:00:00
7  2020-01-08 01:00:00    F      1                 NaT                 NaT
8  2020-01-08 02:00:00    A      3 2020-01-08 00:00:00 2020-01-08 02:00:00
9  2020-01-08 02:00:00    E      2 2020-01-08 01:00:00 2020-01-08 02:00:00
10 2020-01-08 03:00:00    C      1                 NaT                 NaT
11 2020-01-08 03:00:00    G      1                 NaT                 NaT
12 2020-01-08 04:00:00    X      1                 NaT                 NaT
13 2020-01-08 04:00:00    s      1                 NaT                 NaT
14 2020-01-08 23:00:00    G      1                 NaT                 NaT
15 2020-02-08 00:00:00    G      1                 NaT                 NaT
0 голосов
/ 19 января 2020

Начните с определения 2 функций:

def cnt(grp):
    hr = grp.Hour
    return grp.assign(count=hr.size, period_start=hr.iloc[0], period_end=hr.iloc[-1])

def fn(grp):
    gr = grp.groupby((grp.Hour - grp.Hour.shift()).gt(pd.Timedelta('1H')).cumsum())
    return gr.apply(cnt)

Затем сгруппируйте и примените его:

df.groupby('Site').apply(fn).reset_index(level=[0, 1], drop=True).sort_index()

Вы должны начать чтение кода с конца.

Первый шаг - сгруппировать по Site (первый уровень группировки) и применить fn к каждой группе. В настоящее время пропустите остальную часть этой инструкции.

Затем функция fn выполняет группировку второго уровня. Идея состоит в том, чтобы разделить исходную группу (первый уровень) на группы строк для последовательных часов.

К каждой группе (второго уровня) применяется функция cnt . Его результатом является исходная группа с добавленными столбцами count , period_start и period_end .

И теперь есть время взглянуть на (пропущено) ) часть первой инструкции. Партия groupby (...). Apply (...) дает следующий результат (для краткости я включил только результат для Site == A и B .

                            Hour Site  count        period_start           period_end
Site Hour                                                                            
A    0    0  2020-08-01 00:00:00    A      3 2020-08-01 00:00:00  2020-08-01 02:00:00
          4  2020-08-01 01:00:00    A      3 2020-08-01 00:00:00  2020-08-01 02:00:00
          8  2020-08-01 02:00:00    A      3 2020-08-01 00:00:00  2020-08-01 02:00:00
     1    12 2020-08-01 04:00:00    A      2 2020-08-01 04:00:00  2020-08-01 05:00:00
          14 2020-08-01 05:00:00    A      2 2020-08-01 04:00:00  2020-08-01 05:00:00
     2    15 2020-08-01 08:00:00    A      1 2020-08-01 08:00:00  2020-08-01 08:00:00
B    0    1  2020-08-01 00:00:00    B      2 2020-08-01 00:00:00  2020-08-01 01:00:00
          5  2020-08-01 01:00:00    B      2 2020-08-01 00:00:00  2020-08-01 01:00:00

Чтобы получить окончательный результат, необходимо:

  • reset_index (...) - удалить первые 2 уровня индекса.
  • sort_index () - отсортировать строки по индексу.

Результат такой, как вы ожидали.

...