按小时分组,考虑夏令时的影响。

5

我正在查看一家全天候运作的工厂的班次数据。我希望将数据分组到每个班次更替,即6:00和18:00。到目前为止,我一直在尝试使用以下方法:

Data_Frame.groupby([pd.Grouper(freq='12H')]).count() 

但我发现由于频率设置为12小时,即使在夏令时期间,它也始终需要花费12个小时的时间。

不幸的是,即使时钟改变,它始终是在6:00和18:00。这意味着实际上有一个长11小时的班次和另一个长13小时的班次,因此在一年中间,组错了1个小时。

我认为这是一个如此基本的事情(夏令时),应该有某种方法告诉pandas它需要考虑夏令时。

我已经尝试将其从UTC更改为Europe/London,但它仍需要12小时的时间段。

非常感谢

编辑:

我找到的唯一方法是,在使用groupby之前将我的数据分成3个部分(第一个小时改变之前,在小时变化期间,在第二个小时改变之间),在每个部分上单独使用groupby,然后将它们组合起来,但这很烦人和乏味,所以任何比这更好的方法都会非常感激。


1
你尝试过使用时区感知的Series进行分组吗? - wwii
是的,我使用的数据都具有时区意识。 - Oliver Brace
你想在群组中看到什么?你想在那些变化的日子里看到十一小时和十三小时的群组,还是总是想看到十二小时的群组? - wwii
你能否提供一些时间序列的例子,比如秋季和春季变化前后六个小时的数据?在那段时间内,数据是否存在缺失或重复的小时?例如 00:00,01:00,03:00,...00:00,01:00,01:00,02:00,... - wwii
你看到这个 Stack Overflow 的问答了吗 - 如何在 Pandas 日期时间列中标记夏令时(DST)小时 - wwii
你是否从原始数据开始 - 你可能想要为同一时期发布日期/时间列。 - wwii
1个回答

0

涉及编程的内容,返回翻译文本:

跨度为1小时和10分钟的时区感知时间序列,覆盖了春季夏令时更改:

ts_hrly = pd.date_range('03-10-2018', '3-13-2018', freq='H', tz='US/Eastern')
ts_10m = pd.date_range('03-10-2018', '3-13-2018', freq='10T', tz='US/Eastern')

使用小时数据

ts = ts_hrly
df = pd.DataFrame({'tstamp':ts,'period':range(len(ts))})

dst转换看起来像这样:

>>> df[18:23]
    period                    tstamp
18      18 2018-03-11 00:00:00-05:00
19      19 2018-03-11 01:00:00-05:00
20      20 2018-03-11 03:00:00-04:00
21      21 2018-03-11 04:00:00-04:00
22      22 2018-03-11 05:00:00-04:00
>>>

为了将数据分组成每12小时一组,我将每个观测值分配到一个班次号码,然后按照班次号码进行分组。

我的数据恰好从一个班次变更开始,因此计算自那次班次变更以来的经过时间:

nanosec = df['tstamp'].values - df.iloc[0,1].value

寻找班次变更并使用 np.cumsum() 分配班次编号

shift_change = nanosec.astype(np.int64) % (3600 * 1e9 * 12)  == 0
df['shift_nbr'] = shift_change.cumsum()
gb = df.groupby(df['shift_nbr'])
for k,g in gb:
    print(f'{k} has {len(g)} items')

>>>
1 has 12 items
2 has 12 items
3 has 12 items
4 has 12 items
5 has 12 items
6 has 12 items

我还没有找到一种方法来补偿在班次中间开始的数据。

如果你想让受夏令时变化影响的班次组有11或13个项目,将时区感知系列更改为时区无关系列。

df2 = pd.DataFrame({'tstamp':pd.to_datetime(ts.strftime('%m-%d-%y %H:%M')),'period':range(len(ts))})

使用相同的过程来分配和按班次号分组。
nanosec = df2['tstamp'].values - df2.iloc[0,1].value
shift_change = nanosec.astype(np.int64) % (3600 * 1e9 * 12)  == 0
df2['shift_nbr'] = shift_change.cumsum()

for k,g in gb2:
    print(f'{k} has {len(g)} items')

>>>
1 has 12 items
2 has 11 items
3 has 12 items
4 has 12 items
5 has 12 items
6 has 12 items
7 has 1 items

不幸的是,pd.to_datetime(ts.strftime('%m-%d-%y %H:%M'))需要一些时间。这里有一种更快、更好的方法,使用时间戳的小时属性来计算经过的小时数——无需创建单独的时区无关系列,小时属性似乎是“未知”的。它也适用于从班次中间开始的数据。

ts = pd.date_range('01-01-2018 03:00', '01-01-2019 06:00', freq='H', tz='US/Eastern')
df3 = pd.DataFrame({'tstamp':ts,'period':range(len(ts))})

shift_change = ((df3['tstamp'].dt.hour - 6) % 12) == 0
shift_nbr = shift_change.cumsum()

gb3 = df3.groupby(shift_nbr)

print(sep,'gb3')
for k,g in gb3:
    if len(g) != 12:
        print(f'shift starting {g.iloc[0,1]} has {len(g)} items')

>>>
shift starting 2018-01-01 03:00:00-05:00 has 3 items
shift starting 2018-03-10 18:00:00-05:00 has 11 items
shift starting 2018-11-03 18:00:00-04:00 has 13 items
shift starting 2019-01-01 06:00:00-05:00 has 1 items

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接