【问题标题】:Count of a value in consecutive timestamp in pandas熊猫连续时间戳中的值计数
【发布时间】:2020-01-19 23:21:34
【问题描述】:
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   ….  ….

谢谢!

【问题讨论】:

  • 看起来你是免费的代码,没有先自己尝试。这不是 Stackoverflow 的工作方式。请参考How to ask,并尝试首先开始编程您想要实现的目标,如果您遇到任何问题,那么我们会在这里提供帮助。
  • 我不明白...为什么站点 A 的计数是 3?它是 00:00,00:01,00:02 和 00:04。
  • @funie200 明白,我会添加我的版本
  • 我添加了一个答案,请查看:)

标签: python pandas data-analysis


【解决方案1】:

从定义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() - 按索引对行进行排序。

结果如你所愿。

【讨论】:

    【解决方案2】:

    初始数据帧

    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
    

    如果 count 等于 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
    

    【讨论】:

    • 这是一个错误
    • 我想是的,所以请在评论中提问 :)
    猜你喜欢
    • 2019-03-04
    • 1970-01-01
    • 2021-02-06
    • 1970-01-01
    • 2019-05-20
    • 1970-01-01
    • 2018-10-30
    • 1970-01-01
    • 2021-02-10
    相关资源
    最近更新 更多