根据时间将值分割成区间

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

我正在用Python处理纽约市地铁的闸机数据,想把这些数据变成每个车站的进出情况的可视化图。

到目前为止,我有一个根据开始日期(03-24-15)和结束日期(03-27-15)统计的进出次数列表:

{
'endTime': '03-25-14T21:40:30',
'entriesDuringPeriod': 158,
'exitsDuringPeriod': 597,
'startTime': '03-25-14T17:03:23'
},
{
'endTime': '03-26-14T01:00:00',
'entriesDuringPeriod': 29,
'exitsDuringPeriod': 235,
'startTime': '03-25-14T21:00:00'
},

我遇到的问题是,不同的时间段没有统一标准,有时候还会重叠。我想创建一个新的列表,把这些数据标准化为每小时的统计。

我对Python处理时间的知识不太了解,所以想请教一下,如何把字符串转换成日期对象,并根据时间来划分这些值。

最终的可视化会用d3.js来展示,如果这有影响的话。

2 个回答

1

解析给定的时间戳的方法如下:

import datetime
datetime.datetime.strptime("03-25-14T21:08:12", "%m-%d-%yT%H:%M:%S")

这样你就能得到一个 datetime 对象,这个对象可以和其他 datetime 对象进行比较。datetime本身包含了创建任意 datetime 对象的所有函数,这些对象可以用来进行排序或分组。

由于数据中的时间段不均匀且有重叠,可能有几种处理方法。如果你愿意线性地计算进出次数的平均值,你可以取每个时间段,计算每小时平均有多少次进出。然后,给定一个小时,你可以遍历所有数据点,找出某个数据点与这个小时的重叠程度(比如重叠15分钟或整个小时),然后根据重叠的百分比调整这个数据点每小时的平均进出次数,累加到一个总数中。

从伪代码的角度来看:

assume we have an hour to data accumulation bag called htdab
for given hour in time series
    for data point in all data points
        if data point's start <= given hour <= data point's end
            calculate percentage of overlap on top of given hour
            add data point's entries per hour * percentage of overlap to our htdab's entry for given hour
            add data point's exits per hour * percentage of overlap to our htdab's entry for given hour
1

把字符串转换成日期时间对象其实并不难:

from datetime import datetime
from time import time, mktime, strptime

def get_datetime( instr ):
  return datetime.fromtimestamp(mktime(strptime(instr, '%m-%d-%yT%H:%M:%S')))

# eg: get_datetime( '03-25-14T21:20:30' ) => datetime.datetime(2014, 3, 25, 21, 20, 30)

对数据进行分组或标准化主要取决于你想怎么处理重叠的时间段……比如说,你想假设人们的到达和离开是线性的,也就是说如果时间戳是一个半小时的话,66%的人会算在整点的那一小时,33%的人会算在另一小时的部分时间里吗?

补充:根据提问者的评论,这里有完全可用的代码:

from datetime import timedelta
from collections import defaultdict

def add_datum( dd, v ):
    end_dt = get_datetime(v['endTime'])
    start_dt = get_datetime(v['startTime'])
    total_duration = end_dt - start_dt 

    hour_start = datetime( year = start_dt.year, 
                           month = start_dt.month, 
                           day = start_dt.day, 
                           hour = start_dt.hour )
    hour_end = hour_start + timedelta( hours = 1 )

    while hour_start < end_dt:
        dt = min([hour_end, end_dt]) - max([ hour_start, start_dt ])
        fraction = 1.0 * dt.total_seconds() / total_duration.total_seconds()
        dd[ hour_start ]['hour'] = hour_start
        dd[ hour_start ]['entries'] += v['entriesDuringPeriod'] * fraction
        dd[ hour_start ]['exits'] += v['exitsDuringPeriod'] * fraction # exits

        hour_start = hour_end
        hour_end = hour_end + timedelta( hours = 1 )
    return dd


dd = defaultdict(lambda: {'entries':0,'exits':0})
all_data = [{ 'endTime': '03-25-14T21:40:30',
              'entriesDuringPeriod': 158,
              'exitsDuringPeriod': 597,
              'startTime': '03-25-14T17:03:23' },
            { 'endTime': '03-26-14T01:00:00',
              'entriesDuringPeriod': 29,
              'exitsDuringPeriod': 235,
              'startTime': '03-25-14T21:00:00' }]

[ add_datum( dd, i ) for i in all_data ]
res = dd.values()
res.sort( key = lambda i: i['hour'] )

print res
# [{'entries': 32.28038732182594,
#   'exits': 121.97083057677271,
#   'hour': datetime.datetime(2014, 3, 25, 17, 0)},
#  {'entries': 34.209418415829674,
#   'exits': 129.25963793829314,
#   'hour': datetime.datetime(2014, 3, 25, 18, 0)},
#  {'entries': 34.209418415829674,
#   'exits': 129.25963793829314,
#   'hour': datetime.datetime(2014, 3, 25, 19, 0)},
#  {'entries': 34.209418415829674,
#   'exits': 129.25963793829314,
#   'hour': datetime.datetime(2014, 3, 25, 20, 0)},
#  {'entries': 30.34135743068503,
#   'exits': 146.00025560834786,
#   'hour': datetime.datetime(2014, 3, 25, 21, 0)},
#  {'entries': 7.25,
#   'exits': 58.75,
#   'hour': datetime.datetime(2014, 3, 25, 22, 0)},
#  {'entries': 7.25,
#   'exits': 58.75,
#   'hour': datetime.datetime(2014, 3, 25, 23, 0)},
#  {'entries': 7.25,
#   'exits': 58.75,
#   'hour': datetime.datetime(2014, 3, 26, 0, 0)}]

撰写回答