创建五分钟时间块(Pandas/Python)

2 投票
1 回答
2068 浏览
提问于 2025-04-18 01:16

我正在处理观察行为数据,每一行代表一种行为,并带有时间戳。这个数据集包含多个观察周期,行为是实时记录的,时间戳使用的是Epoch时间格式。我想在我的数据框中创建一个新列,用来标记每个观察周期内的时间块。具体来说,我想把每个观察周期的前5分钟分成不同的时间块进行标记。(我需要用这些来计算不同行为在固定时间段内的频率)。数据大致长这样(还有更多列,但为了简化展示,我省略了其他列):

 observation     epoch         behavior
 1               12973561838   vo
 1               12973561870   bc
 1               12973561944   xp
 1               12973562055   vo
 1               12973562106   vo
 2               12731709280   wc
 2               12731709322   we
 2               12731709361   vb
 2               12731709374   vw
 ...

我希望最终的结果看起来是这样的:

  observation     epoch         behavior    timeblock
  1               12973561838   vo          1
  1               12973561870   bc          1
  1               12973561944   xp          2
  1               12973562055   vo          3
  1               12973562106   vo          3
  2               12731709280   wc          4
  2               12731709322   we          5
  2               12731709361   vb          5
  2               12731709374   vw          5
  ...

其中“时间块”#1将包括观察周期#1的前4分59秒,#2将包括5:00到9:59分钟……一直到25:00及以上,适用于每个观察周期。在这个例子中,#4将包括观察周期#2的前4分59秒,依此类推。(我知道Epoch时间值和我的时间块不完全匹配,但这是因为我简化了数据,只随便抓了一些时间戳。我认为这不会影响理解)。

我目前尝试过的: 我尝试使用groupby,并计算每个观察周期的5分钟时间块的实际Epoch值的开始和结束时间,放在一个单独的数据框中。但我不知道如何将这些应用到上面原始数据框中的每个观察周期的函数中,因为每个观察周期都有多个值。我怀疑答案在于更好地理解groupby和apply方法,但我在这方面遇到了困难。(另外,也许我没有使用正确的搜索词,但在论坛上找不到太多相关的信息。我只能找到关于时间序列的资料)。我考虑过的两个选项,但不知道如何编程实现:

  1. 计算每个观察周期的实际Epoch时间点,以便我可以根据每个观察周期的最小Epoch值将周期分成5分钟的时间块(这部分已经完成),然后用这个生成一个时间块标签的列(这部分让我卡住了)。

  2. 计算每个观察周期内每行条目的“自开始以来的时间”,基于该观察周期的最小Epoch值(这里也卡住了)。然后,不是为每个观察周期使用不同的值列表(如概念解决方案#1),而是使用一个标准的值范围(0到4:59分钟,5到9:59分钟等)来创建时间块标签的列。我不知道该如何开始这个。

非常感谢你的帮助!

更新说明如下

我已经使用groupby创建了每个“观察”周期的初始时间戳表:

 g_follow = teach_freq['Epoch'].groupby(teach_freq['observation'])

 start_follow = g_follow.min()

我把这个放入一个数据框中,并加上最大值(标记每个“观察”周期的结束时间戳)。这产生了以下数据框,共有225个“观察”周期:

 observation     min          max
 1               12973561838  12973563058
 2               12973571418  12973572718
 3               12973825256  12973826474   
 ...

请注意,每个“观察”周期都有不同的“最小”值,或者说不同的开始时间。上面选项#1意味着我需要编写代码,从我更大数据库中的每个Epoch条目中减去每个观察的“最小”代码。

更新:根据Dmitry建议的代码,我正在尝试使用以下内容:

 #where the dataframe with timeblocks & start times is named blocks
 #each observation period is in column 'follow'
 #and each start time for the observation periods is in column 'first'

 min_time = lambda row: row['Epoch'] - blocks[blocks['follow'] == row['follow']]['first']

接下来是:

 #where the dataframe with observed & timestamped behaviors is named teach_freq

 teach_freq['std_epoch'] = teach_freq.apply(min_time, axis=1)

但当我运行这个时,我得到了以下错误:

 ValueError: Wrong number of items passed 1, indices imply 225

1 个回答

3

我之前遇到过这个问题,这是我的解决办法。

  1. 观察是从某个时间点开始的。我们可以把每一行的时间减去最初的时间,这样就能得到从0开始的所有时间点。

    timeseries['timeblock'] = timeseries['epoch'] - timeseries['epoch'][0]
    
  2. 这个“标准化”的时间字段可以映射到5分钟的时间间隔:

    timeseries['timeblock'] = timeseries['timeblock'].map(lambda x: int(x/300))
    

我开始使用pandas也没多久,所以可能还有更符合pandas风格的解决方案。

[编辑] 你开始的时间块是从1开始的,所以正确的代码应该是

timeseries['timeblock'] = timeseries['timeblock'].map(lambda x: int(x/300)+1)

[编辑] 更新 - 我觉得你可以使用apply函数来减去正确的最小时间。

# let's say that data frame with observations and their mins is called omf
min_time = lambda row: row['epoch'] - omf[omf['observation'] == row['observation']]['min']
timeseries['new_epoch'] = timeseries.apply(min_time,axis=1)

[编辑] 更新 完整代码 - 使用你的符号和序列:

# Notice epoch lowercase, panda column names are case sensitive 
g_follow = teach_freq['epoch'].groupby(teach_freq['observation'])
start_follow = g_follow.min()
# Important - start_follow is a Series where observation is an index
blocks = start_follow # to have the same notation
# main part - using Series instead of DataFrame makes the indexing simpler 
min_time = lambda row: row['epoch'] - blocks[row['observation']]
teach_freq['std_epoch'] = teach_freq.apply(min_time, axis=1)

撰写回答