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

时间:2014-04-03 23:11:22

标签: python pandas

我操纵观察行为数据,其中每个行条目都是带有时间戳的行为。数据集包括多个观察期,并且实时记录行为,时间戳使用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
  ...

" timeblock" #1将包括观察期#1的前4:59分钟,#2将包括5:00至9:59分钟......至25:00及以上,每个观察期。在这个例子中,#4将包括观察期#2的前4:59分钟,依此类推。 (我意识到大纪元的时间价值与我的时间块不匹配,但那是因为我已经缩减了数据,只是随意地抓住了一些时间戳。我不认为这会伤害理解力。)

到目前为止我尝试过的事情: 我已经弄乱了groupby,并在一个单独的数据帧中计算了每个观察期的5分钟时间块开始和结束时的实际纪元值。但我无法看到如何将这些应用于上述原始数据框中每个观察期应用的函数,其中每个观察期有多个值。我怀疑答案在于更好地理解groupby和apply方法,但是我在实现这个问题时遇到了麻烦。 (另外,也许我没有使用正确的搜索条件,但我已经在论坛上发现了很多内容。我只能找到有关使用时间序列的信息)。我已经考虑了两个选项,但无法弄清楚如何编程:

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

  2. 根据该观察期的最小Epoch值计算观察期内每个行条目的开始时间(此处也卡在此处)。然后,不是为每个观察期使用不同的值列表(如概念解决方案#1),而是使用标准值范围(分钟0到4:59,5到9:59等)来创建列。时间块标签。我一直坚持如何开始这个。

  3. 非常感谢您的帮助!

    更新说明,

    我已经使用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意味着我需要编写代码来减去' min'来自每个时代的每个观察的代码。在我的大型数据库中输入。

    更新:根据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 个答案:

答案 0 :(得分:3)

之前我遇到过这个问题 - 这是我的解决方案。

  1. 观察从一些时间戳开始。我们可以从每一行中减去初始时间戳,因此我们将从时间0开始所有时期。

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

    timeseries['timeblock'] = timeseries['timeblock'].map(lambda x: int(x/300))
    
  3. 我不久前开始使用熊猫,所以可能存在更多类似熊猫的解决方案

    [编辑]你用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)