Python:将数据分组为时隙(分钟)

时间:2013-07-25 07:17:01

标签: python grouping

我有一个以mS精确间隔发生的事件列表,这些事件跨越了几天。我想聚集在'每n分钟'时隙中发生的所有事件(可以是20个事件,可以是没有事件)。我为每个活动都有一个datetime.datetime项,因此我可以毫不费力地获得datetime.datetime.minute

我的活动列表按时间顺序排序,最早的第一个,最后的最后一个。该列表在我正在处理的时间段内完成。

我的想法是我可以更改列表: -

[[a],[b],[c],[d],[e],[f],[g],[h],[i]...]

其中a,b,c出现在分钟0和29之间,d,e,f,g出现在分钟30和59之间,0到29之间没有任何东西(下一个小时),h,i介于30到59之间。

进入新名单: -

[[[a],[b],[c]],[[d],[e],[f],[g]],[],[[h],[i]]...]

我不确定如何构建一个循环遍历两个时隙的迭代器,直到时间序列列表结束。任何我能想到的xrange一旦完成就会停止,所以我想知道是否有一种方法可以使用'while'来进行切片?

我也将使用更小的时间段,大约5分钟,我使用30分钟作为示范的较短示例。

(对于上下文,我正在制作一个地理标记时间基于新西兰最近地震的基于时间的观点。并希望在一小段时间内显示所有发生的地震,以加快重播速度)< / p>

6 个答案:

答案 0 :(得分:9)

# create sample data
from datetime import datetime, timedelta
d = datetime.now()
data = [d + timedelta(minutes=i) for i in xrange(100)]

# prepare and group the data
from itertools import groupby

def get_key(d):
    # group by 30 minutes
    k = d + timedelta(minutes=-(d.minute % 30)) 
    return datetime(k.year, k.month, k.day, k.hour, k.minute, 0)

g = groupby(sorted(data), key=get_key)

# print data
for key, items in g:
    print key
    for item in items:
        print '-', item

这是this回答的python翻译,它通过将日期时间四舍五入到下一个边界并将其用于分组来工作。


如果您确实需要可能的空组,可以使用此方法或类似方法添加它们:

def add_missing_empty_frames(g):
    last_key = None
    for key, items in g:
        if last_key:
            while (key-last_key).seconds > 30*60:
                empty_key = last_key + timedelta(minutes=30)
                yield (empty_key, [])
                last_key = empty_key
        yield (key, items)
        last_key = key

for key, items in add_missing_empty_frames(g):
    ...

答案 1 :(得分:1)

如果您拥有整个列表,您可以直接遍历它并直接在正确的时间段内粘贴每个事件:

grouped = [[] for _ in xrange(whatever)]
for event in events:
    grouped[timeslot_of(event)].append(event)

如果您需要将可迭代的事件转换为分组的可迭代事件,事情就会变得更加混乱。 itertools.groupby几乎可以正常工作,但它会跳过没有事件的时间间隔。

答案 2 :(得分:1)

假设事件在名为events的按时间顺序排列的列表中可用,并且具有名为datetime的{​​{1}}属性:

timestamp

这在时间轴上使用第一个事件为t = 0。如果这不是您想要的,只需将interval = 10 # min period = 2*24*60 # two days in minutes timeslots = [[] for slot in range(period/interval)] for e in events: index = int((e.timestamp-events[0].timestamp).total_seconds()/60) / interval timeslots[index].append(e) 替换为代表您的t = 0的events[0].timestamp实例的引用。

答案 3 :(得分:1)

考虑以下

def time_in_range(t,t_min,delta_t):
    if t<=t_min+delta_t and t>=t_min:
         return True
    else:
         return False
def group_list(input_list,ref_time,time_dx,result=[]):
    result.append([])
    for i,item in enumerate(input_list):
        if time_in_range(item,ref_time,time_dx):
            result[-1].append(item)
        else:
            return group_list(input_list[i:],ref_time+time_dx,time_dx,result=result)
def test():
    input_list = [1,2,3,4,5,8,10,20,30]
    print group_list(input_list,0,5)
test()
# Ouput:
# [[1, 2, 3, 4, 5], [8, 10], [], [20], [], [30]]

您需要编写自己的time_in_range函数。

答案 4 :(得分:0)

  

我想知道是否有办法使用`while&#39;做切片?

我有这个定义可能对你有帮助。它没有库依赖项,并根据请求使用while循环:

如果你有2个名单; unix时间戳和值,每个时间长度相同:

timestamps [0]分别是值[0]的时间戳。

timestamps = [unix, unix, unix, ....etc.]
values = [0.1, 0.2, 0.5, 1.1, ....etc.]

假设从2011年11月开始,您有30天的数据,并且您希望按小时分组:

BEGIN = 1320105600

hourly_values = []
z = 0
while z < 720:   # 24 hours * 30 days = 720
    hourly_values.append([])  # append an new empty list for each hour
    for i in range(len(timestamps)):
        if timestamps[i] >= (BEGIN + 3600*z):  # 3600 sec = 1 hour
            if timestamps[i] < (BEGIN + 3600*(z+1)):
                hourly_values[z].append(values[i])
    z+=1
return hourly_values

这将返回每小时的列表列表,其中包含没有数据的小时内的空列表。

答案 5 :(得分:0)

您可以使用开槽模块。我遇到了类似的问题,最后我写了一个通用的解决方案 - https://github.com/saurabh-hirani/slotter

asciinema演示 - https://asciinema.org/a/8mm8f0qqurk4rqt90drkpvp1b?autoplay=1