在python中有没有办法将基于时间的事件划分为小时模板?
我有一个包含各种事件的数据帧,包括开始时间和结束时间。 例如 我想要一个输出数据框,它是一个小时模板,列中为小时,行中为日期,具有相同的事件。将相应的小时和日期的值填充为“1”在python中有没有办法将基于时间的事件划分为小时模板?,python,pandas,datetime,time,Python,Pandas,Datetime,Time,我有一个包含各种事件的数据帧,包括开始时间和结束时间。 例如 我想要一个输出数据框,它是一个小时模板,列中为小时,行中为日期,具有相同的事件。将相应的小时和日期的值填充为“1” 任何帮助都将不胜感激。这里有一种方法可以做到这一点: # sample data d = pd.DataFrame({'Event': ['Event1','Event2'], 'StartTime':['2019-01-01 00:10:00', '2019-01-01 13:10
任何帮助都将不胜感激。这里有一种方法可以做到这一点:
# sample data
d = pd.DataFrame({'Event': ['Event1','Event2'],
'StartTime':['2019-01-01 00:10:00', '2019-01-01 13:10:00'],
'EndTime':['2019-01-01 11:10:00', '2019-01-01 20:10:00']})
# convert cols to datetime
col = ['StartTime','EndTime']
for c in col:
d[c] = pd.to_datetime(d[c])
# add a new column containing list of hours
d['hours'] = [[x for x in range(24)] for _ in range(d.shape[0])]
# explode the list into new rows
d = d.explode('hours').reset_index(drop=True)
# calculate the values for each hour
def make_table(f):
start_hour = int(f['StartTime'].dt.hour.unique())
hour_diff = (f['EndTime'] - f['StartTime']).astype('timedelta64[h]').tolist()
max_hour = int(f['EndTime'].dt.hour.unique())
use_hours = [x for x in range(start_hour, max_hour+1)]
f['encode'] = f['hours'].apply(lambda x: 1 if x in use_hours else 0)
return f
# apply the function to each group
d2 = d.groupby(['Event','StartTime','EndTime']).apply(make_table)
# convert d2 into wide format using pivot
d2 = pd.pivot_table(d2, values='encode', index=['Event','StartTime','EndTime'], columns=['hours'])
下面是输出的样子,只显示了几列
hours 0 1 2 3 4 5 6 ...
Event StartTime EndTime
Event1 2019-01-01 00:10:00 2019-01-01 11:10:00 1 1 1 1 1 1 1 ...
Event2 2019-01-01 13:10:00 2019-01-01 20:10:00 0 0 0 0 0 0 0 ...
以下是一种方法:
# sample data
d = pd.DataFrame({'Event': ['Event1','Event2'],
'StartTime':['2019-01-01 00:10:00', '2019-01-01 13:10:00'],
'EndTime':['2019-01-01 11:10:00', '2019-01-01 20:10:00']})
# convert cols to datetime
col = ['StartTime','EndTime']
for c in col:
d[c] = pd.to_datetime(d[c])
# add a new column containing list of hours
d['hours'] = [[x for x in range(24)] for _ in range(d.shape[0])]
# explode the list into new rows
d = d.explode('hours').reset_index(drop=True)
# calculate the values for each hour
def make_table(f):
start_hour = int(f['StartTime'].dt.hour.unique())
hour_diff = (f['EndTime'] - f['StartTime']).astype('timedelta64[h]').tolist()
max_hour = int(f['EndTime'].dt.hour.unique())
use_hours = [x for x in range(start_hour, max_hour+1)]
f['encode'] = f['hours'].apply(lambda x: 1 if x in use_hours else 0)
return f
# apply the function to each group
d2 = d.groupby(['Event','StartTime','EndTime']).apply(make_table)
# convert d2 into wide format using pivot
d2 = pd.pivot_table(d2, values='encode', index=['Event','StartTime','EndTime'], columns=['hours'])
下面是输出的样子,只显示了几列
hours 0 1 2 3 4 5 6 ...
Event StartTime EndTime
Event1 2019-01-01 00:10:00 2019-01-01 11:10:00 1 1 1 1 1 1 1 ...
Event2 2019-01-01 13:10:00 2019-01-01 20:10:00 0 0 0 0 0 0 0 ...
您可以使用:
df = pd.DataFrame({
'Event':list('abc'),
'StartTime':['24-12-19 1:14','22-12-19 0:32','23-12-19 6:00'],
'EndTime':['24-12-19 6:00','24-12-19 4:32','24-12-19 16:00']
})
df[['StartTime','EndTime']] = df[['StartTime','EndTime']].apply(pd.to_datetime, dayfirst=True)
df1 = (df.melt('Event')
.set_index('value')
.groupby('Event')['Event']
.resample('H')
.count()
.reset_index(name='val')
.assign(val=1,
date=lambda x: x['value'].dt.date,
hour=lambda x: x['value'].dt.hour)
.set_index(['Event','date','hour'])['val']
.unstack(fill_value=0)
.reset_index()
.rename_axis(None, axis=1)
)
说明:
首先通过和将两列转换为datetimes
按组进行重塑-以便可能
创建新列,将val的所有值设置为1、日期和
最后通过和进行整形
最后通过和进行一些数据清理
编辑:
对于工作时间的开始和结束,使用类似的解决方案-对于工作时间,减去最低工作时间,如果开始日期也减去1,则首先使用重采样:
EDIT1:Idea是按分钟重新采样,然后再聚合小时数:
df = pd.DataFrame({
'Event':list('abc'),
'StartTime':['20-12-19 18:06','22-12-19 0:32','23-12-19 6:00'],
'EndTime':['20-12-19 18:07','24-12-19 4:32','24-12-19 16:00']
})
您可以使用:
df = pd.DataFrame({
'Event':list('abc'),
'StartTime':['24-12-19 1:14','22-12-19 0:32','23-12-19 6:00'],
'EndTime':['24-12-19 6:00','24-12-19 4:32','24-12-19 16:00']
})
df[['StartTime','EndTime']] = df[['StartTime','EndTime']].apply(pd.to_datetime, dayfirst=True)
df1 = (df.melt('Event')
.set_index('value')
.groupby('Event')['Event']
.resample('H')
.count()
.reset_index(name='val')
.assign(val=1,
date=lambda x: x['value'].dt.date,
hour=lambda x: x['value'].dt.hour)
.set_index(['Event','date','hour'])['val']
.unstack(fill_value=0)
.reset_index()
.rename_axis(None, axis=1)
)
说明:
首先通过和将两列转换为datetimes
按组进行重塑-以便可能
创建新列,将val的所有值设置为1、日期和
最后通过和进行整形
最后通过和进行一些数据清理
编辑:
对于工作时间的开始和结束,使用类似的解决方案-对于工作时间,减去最低工作时间,如果开始日期也减去1,则首先使用重采样:
EDIT1:Idea是按分钟重新采样,然后再聚合小时数:
df = pd.DataFrame({
'Event':list('abc'),
'StartTime':['20-12-19 18:06','22-12-19 0:32','23-12-19 6:00'],
'EndTime':['20-12-19 18:07','24-12-19 4:32','24-12-19 16:00']
})
有没有办法将值添加为“小时”而不是1?例如,如果开始时间是12:30,我想在13号得到0.5hour@SuhasMucherla-可能,但更复杂。每组的最后一个值应该是多少?e、 g.如果24-12-19 10:22?它应该是22/60?是的,基本上我想要的是活动在特定时间的活动时间,以小时为单位。因此,如果它是组中的最后一个值,则为22/60,如果它是组中的第一个值,则为38/60如果事件的开始时间和结束时间在同一小时内,则上述解决方案似乎不起作用,例如,如果开始时间为24-12-19 18:06,结束时间为24-12-19 18:07,则我希望18小时列具有1/60。但这似乎没有发生,有什么解决办法吗?有没有办法将值添加为“小时”而不是1?例如,如果开始时间是12:30,我想在13号得到0.5hour@SuhasMucherla-可能,但更复杂。每组的最后一个值应该是多少?e、 g.如果24-12-19 10:22?它应该是22/60?是的,基本上我想要的是活动在特定时间的活动时间,以小时为单位。因此,如果它是组中的最后一个值,则为22/60,如果它是组中的第一个值,则为38/60如果事件的开始时间和结束时间在同一小时内,则上述解决方案似乎不起作用,例如,如果开始时间为24-12-19 18:06,结束时间为24-12-19 18:07,则我希望18小时列具有1/60。但这似乎没有发生,有什么解决办法吗?
print (df1)
Event date 0 1 2 3 4 5 6 7 8 \
0 a 2019-12-20 0.000000 0.0 0.0 0.0 0.000000 0.0 0.0 0.0 0.0
1 b 2019-12-22 0.466667 1.0 1.0 1.0 1.000000 1.0 1.0 1.0 1.0
2 b 2019-12-23 1.000000 1.0 1.0 1.0 1.000000 1.0 1.0 1.0 1.0
3 b 2019-12-24 1.000000 1.0 1.0 1.0 0.533333 0.0 0.0 0.0 0.0
4 c 2019-12-23 0.000000 0.0 0.0 0.0 0.000000 0.0 1.0 1.0 1.0
5 c 2019-12-24 1.000000 1.0 1.0 1.0 1.000000 1.0 1.0 1.0 1.0
9 10 11 12 13 14 15 16 17 18 19 20 21 22 \
0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.016667 0.0 0.0 0.0 0.0
1 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.000000 1.0 1.0 1.0 1.0
2 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.000000 1.0 1.0 1.0 1.0
3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.000000 0.0 0.0 0.0 0.0
4 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.000000 1.0 1.0 1.0 1.0
5 1.0 1.0 1.0 1.0 1.0 1.0 1.0 0.0 0.0 0.000000 0.0 0.0 0.0 0.0
23
0 0.0
1 1.0
2 1.0
3 0.0
4 1.0
5 0.0