按小时分组,同时考虑夏令时

Oli*_*ace 5 python datetime dst pandas-groupby

我正在查看每天24小时工作的工厂的班次数据.我想在每次班次变更时对数据进行分组,即6:00和18:00.到目前为止,我一直在尝试:

Data_Frame.groupby([pd.Grouper(freq='12H')]).count() 
Run Code Online (Sandbox Code Playgroud)

但是我已经意识到,由于频率设置为12H,它总是需要12个小时,包括夏令时.

不幸的是,即使时钟发生变化,它总是在6:00和18:00.这意味着实际上一年中有一个时间长度为11个小时,另一个时间长度为13个小时,因此在年中组中有1个小时.

我觉得这是一个基本的东西(夏令时),应该有一些方法告诉大熊猫它需要考虑夏令时.

我已经尝试将它从UTC改为欧洲/伦敦,但它仍需要12个小时的时间.

非常感谢

编辑:

我发现这样做的唯一方法就是,在使用groupby之前将数据拆分为3(在第一个小时更改之前,在小时更改之前,第二个小时更改之前),逐个使用groupby然后将它们重新组合在一起,但这很烦人且乏味所以比这更好的东西是非常感激的.

wwi*_*wii 0

每小时和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')
Run Code Online (Sandbox Code Playgroud)

使用每小时数据

ts = ts_hrly
df = pd.DataFrame({'tstamp':ts,'period':range(len(ts))})
Run Code Online (Sandbox Code Playgroud)

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
>>>
Run Code Online (Sandbox Code Playgroud)

为了在 06:00 和 18:00 边界上按十二个小时的增量分组,我将每个观察值分配给一个班次编号,然后按班次编号分组

我的数据方便地从换班开始,因此计算自第一次换班以来经过的时间:

nanosec = df['tstamp'].values - df.iloc[0,1].value
Run Code Online (Sandbox Code Playgroud)

查找班次变更并用于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
Run Code Online (Sandbox Code Playgroud)

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

如果您希望受夏令时更改影响的轮班组有 11 或 13 个项目,请将时区感知系列更改为时区朴素系列

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

使用相同的流程按班次编号进行分配和分组

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
Run Code Online (Sandbox Code Playgroud)

不幸的是,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
Run Code Online (Sandbox Code Playgroud)