Python 计算特定标签在滑动窗口中的出现次数

Python 计算特定标签在滑动窗口中的出现次数,python,pandas,dataframe,data-manipulation,Python,Pandas,Dataframe,Data Manipulation,我有下面的数据框 t_msec ID 0 1.1 0200 1 1.4 020a 2 8.9 01f4 3 11.1 0200 4 13.2 02e2 ... ... ... 85454 189915.3 02e4 85455 189915.6 02e6 85456 189921.8 0200 85457 189922.3 01f4

我有下面的数据框

         t_msec    ID
0           1.1  0200
1           1.4  020a
2           8.9  01f4
3          11.1  0200
4          13.2  02e2
...         ...   ...
85454  189915.3  02e4
85455  189915.6  02e6
85456  189921.8  0200
85457  189922.3  01f4
85458  189924.0  020a
我想运行一个滑动窗口,该窗口提前1秒统计特定标签的出现次数

only_id_df = df[df.ID == id]
counts = Counter()
for index, row in only_id_df.iterrows():
    mask = (only_id_df.t_msec< row.t_msec + 1000) & (only_id_df.t_msec> row.t_msec)
    counts.update([len(only_id_df[mask])])
only_id_df=df[df.id==id]
计数=计数器()
对于索引,仅为_id_df.iterrows()中的行:
掩码=(仅限id测向t_msecrow.t_msec)
计数。更新([len(仅\u id\u df[mask]))
然而,这是非常缓慢的,我知道必须有一种方法来执行它,而不必手动迭代每一行和过滤(我知道这是低效的)


实现这一目标的正确途径是什么?如何加快计算速度?

在测试中,我使用了以下数据帧:

   t_msec    ID
0      60  0200
1      70  020a
2     445  01f4
3     555  0200
4     660  02e2
5    1005  0200
6    1510  02e2
7    2105  0200
8    2260  02e2
因此,如果我们在距初始行1s内查找例如ID='0200' (t_msec==60)向前,则在 t_msec==[605551005]

要计算整个结果,我们必须执行一些技巧:

  • 为了执行基于时间序列的滚动计算, 我们必须计算一个临时列,包括pd.to_datetime和 将其设置为索引

  • 但滚动计算是从 当前行,即Pandas查找前1s之间的行 当前索引和现在(当前索引)并执行 定义了此窗口中行的计算,而我们需要 向前查看窗口。 因此,这里需要的技巧是:

    • 将索引计算为df.t_msec.max()-df.t_msec[ms]
    • 按相反的顺序处理
    • 再次颠倒结果的顺序
  • 最后一个技巧的原因是:

    • 我们想看看ID列(一个字符串
    • 但滚动计算只能在数值列上执行
  • 幸运的是,ID列只包含hex字符串,可以 转换为int。因此我们将其转换并保存在新的(临时)列下

  • 第一步是执行“设置”计算:

    lbl = int('0200', 16)  # Label to look for (hex -> dec)
    # ID converted to dec
    df['ID_dec'] = df.ID.apply(lambda x: int(x, 16))
    # Set index
    df = df.set_index(pd.to_datetime(df.t_msec.max() - df.t_msec, unit='ms'))
    
    因此,df现在包含:

                             t_msec    ID  ID_dec
    t_msec                                       
    1970-01-01 00:00:02.200      60  0200     512
    1970-01-01 00:00:02.190      70  020a     522
    1970-01-01 00:00:01.815     445  01f4     500
    1970-01-01 00:00:01.705     555  0200     512
    1970-01-01 00:00:01.600     660  02e2     738
    1970-01-01 00:00:01.255    1005  0200     512
    1970-01-01 00:00:00.750    1510  02e2     738
    1970-01-01 00:00:00.155    2105  0200     512
    1970-01-01 00:00:00.000    2260  02e2     738
    
    第二个(主要)步骤是计算Nr列:

    注意[:-1]反转源列和结果本身

    现在df包含:

                             t_msec    ID  ID_dec  Nr
    t_msec                                           
    1970-01-01 00:00:02.200      60  0200     512   3
    1970-01-01 00:00:02.190      70  020a     522   2
    1970-01-01 00:00:01.815     445  01f4     500   2
    1970-01-01 00:00:01.705     555  0200     512   2
    1970-01-01 00:00:01.600     660  02e2     738   1
    1970-01-01 00:00:01.255    1005  0200     512   1
    1970-01-01 00:00:00.750    1510  02e2     738   1
    1970-01-01 00:00:00.155    2105  0200     512   1
    1970-01-01 00:00:00.000    2260  02e2     738   0
    
    最后一步是删除临时列并恢复 原始索引:

    df = df.drop(columns='ID_dec').reset_index(drop=True)
    
    最终结果是:

       t_msec    ID  Nr
    0      60  0200   3
    1      70  020a   2
    2     445  01f4   2
    3     555  0200   2
    4     660  02e2   1
    5    1005  0200   1
    6    1510  02e2   1
    7    2105  0200   1
    8    2260  02e2   0
    

    执行时间应该大大缩短。写一条关于您和我的代码的执行时间(+行号)的注释。

    对于我的测试,我使用了以下数据帧:

       t_msec    ID
    0      60  0200
    1      70  020a
    2     445  01f4
    3     555  0200
    4     660  02e2
    5    1005  0200
    6    1510  02e2
    7    2105  0200
    8    2260  02e2
    
    因此,如果我们在距初始行1s内查找例如ID='0200' (t_msec==60)向前,则在 t_msec==[605551005]

    要计算整个结果,我们必须执行一些技巧:

  • 为了执行基于时间序列的滚动计算, 我们必须计算一个临时列,包括pd.to_datetime和 将其设置为索引

  • 但滚动计算是从 当前行,即Pandas查找前1s之间的行 当前索引和现在(当前索引)并执行 定义了此窗口中行的计算,而我们需要 向前查看窗口。 因此,这里需要的技巧是:

    • 将索引计算为df.t_msec.max()-df.t_msec[ms]
    • 按相反的顺序处理
    • 再次颠倒结果的顺序
  • 最后一个技巧的原因是:

    • 我们想看看ID列(一个字符串
    • 但滚动计算只能在数值列上执行
  • 幸运的是,ID列只包含hex字符串,可以 转换为int。因此我们将其转换并保存在新的(临时)列下

  • 第一步是执行“设置”计算:

    lbl = int('0200', 16)  # Label to look for (hex -> dec)
    # ID converted to dec
    df['ID_dec'] = df.ID.apply(lambda x: int(x, 16))
    # Set index
    df = df.set_index(pd.to_datetime(df.t_msec.max() - df.t_msec, unit='ms'))
    
    因此,df现在包含:

                             t_msec    ID  ID_dec
    t_msec                                       
    1970-01-01 00:00:02.200      60  0200     512
    1970-01-01 00:00:02.190      70  020a     522
    1970-01-01 00:00:01.815     445  01f4     500
    1970-01-01 00:00:01.705     555  0200     512
    1970-01-01 00:00:01.600     660  02e2     738
    1970-01-01 00:00:01.255    1005  0200     512
    1970-01-01 00:00:00.750    1510  02e2     738
    1970-01-01 00:00:00.155    2105  0200     512
    1970-01-01 00:00:00.000    2260  02e2     738
    
    第二个(主要)步骤是计算Nr列:

    注意[:-1]反转源列和结果本身

    现在df包含:

                             t_msec    ID  ID_dec  Nr
    t_msec                                           
    1970-01-01 00:00:02.200      60  0200     512   3
    1970-01-01 00:00:02.190      70  020a     522   2
    1970-01-01 00:00:01.815     445  01f4     500   2
    1970-01-01 00:00:01.705     555  0200     512   2
    1970-01-01 00:00:01.600     660  02e2     738   1
    1970-01-01 00:00:01.255    1005  0200     512   1
    1970-01-01 00:00:00.750    1510  02e2     738   1
    1970-01-01 00:00:00.155    2105  0200     512   1
    1970-01-01 00:00:00.000    2260  02e2     738   0
    
    最后一步是删除临时列并恢复 原始索引:

    df = df.drop(columns='ID_dec').reset_index(drop=True)
    
    最终结果是:

       t_msec    ID  Nr
    0      60  0200   3
    1      70  020a   2
    2     445  01f4   2
    3     555  0200   2
    4     660  02e2   1
    5    1005  0200   1
    6    1510  02e2   1
    7    2105  0200   1
    8    2260  02e2   0
    
    执行时间应该大大缩短。写一条关于你和我的代码执行时间的注释(+行号)