我有一个设备列表及其活动时间(开始时间和结束时间)。设备可以包含一个或多个活动日志。我要做的是为设备处于活动状态时为每个设备创建一个分发。
我当前的数据框看起来像这样:
device_id start_time end_time
1 03:53 10:54
1 06:00 14:00
2 20:29 06:17
为每个设备创建一个活动时间分配,我想我会创建每小时桶(对应于00到23之间的小时数)并填写设备处于活动状态的桶。因此,对于设备1,例如,第一行将是
[0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0]
和第二行
[0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0]
将它们相加以创建设备1的活动分布将给出:
[0,0,0,1,1,1,2,2,2,2,2,1,1,1,1,0,0,0,0,0,0,0,0,0]
我有以下尝试创建所需的列表,但是,它仅在结束时间大于开始时间时才起作用(例如,上面数据样本中的前两行)并且不会更长时间地工作比结束时间(例如上面数据样本中的第3行)。
for start, end in zip(df[df['start_time'].notnull() & df['end_time'].notnull()]['start_time'],df[df['start_time'].notnull() & df['end_time'].notnull()]['end_time']) :
start_time = pd.to_datetime(start, format ='%H:%M')
end_time = pd.to_datetime(end, format ='%H:%M')
activity = [0]*24
i = (start_time + dt.timedelta(minutes=((start_time.minute // 60 + (1 if start_time.minute>30 else 0) ) * 60) - start_time.minute)).hour
rounded_end_time = (end_time + dt.timedelta(minutes=((end_time.minute // 60 + (1 if end_time.minute>30 else 0) ) * 60) - end_time.minute)).hour
while i < rounded_end_time:
activity[i] = 1
i = i + 1
print activity
有任何修复建议吗? (或者是一种更聪明的方式来完成任务?)
答案 0 :(得分:1)
你只能使用如下的pandas:
x=pd.DataFrame([[1, '03:53', '10:54'],[1, '06:00', '14:00'],[2, '20:29', '06:17']])
x.columns=['device_id', 'start_time', 'end_time']
x['start_time']=pd.to_datetime(x['start_time'],format ='%H:%M')
x['end_time']=pd.to_datetime(x['end_time'],format ='%H:%M')
x['type'] = x['end_time']-x['start_time']>0
x['type'] = x['type'].apply(lambda x: 0 if x else 1)
x['min'] = x[['start_time','end_time']].min(axis=1)
x['max'] = x[['start_time','end_time']].max(axis=1)
for i in range(24):
h = '0'+str(i)
h = h[-2:]
l = x['min']<=pd.to_datetime(h + ':59',format ='%H:%M')
e = x['max']>=pd.to_datetime(h+':00',format ='%H:%M')
l=l.apply(lambda x: 1 if x else -1)
e=e.apply(lambda x: 1 if x else -1)
x[i]=l+e+x['type']
x[i]=x[i].apply(lambda x: 1 if x > 0 and x < 3 else 0)
x = x.drop(['start_time','end_time'],axis=1).groupby('device_id').agg(np.max)
x.reset_index().drop('device_id',axis=1).sum()
答案 1 :(得分:0)
解决了!我发布了评论的答案,以防有人需要它:
# for each pair of start and end time that are not null
for start, end in zip(df[df['start_time'].notnull() & df['end_time'].notnull()]['start_time'],df[df['start_time'].notnull() & df['end_time'].notnull()]['end_time']) :
start_time = pd.to_datetime(start, format ='%H:%M')
end_time = pd.to_datetime(end, format ='%H:%M')
#create a list of 24 indexes and initialize them to 0
activity = [0]*24
#round start and end time to the nearest hour
i = (start_time + dt.timedelta(minutes=((start_time.minute // 60 + (1 if start_time.minute>30 else 0) ) * 60) - start_time.minute)).hour
rounded_end_time = (end_time + dt.timedelta(minutes=((end_time.minute // 60 + (1 if end_time.minute>30 else 0) ) * 60) - end_time.minute)).hour
#calculate the number of hours of activity (which is also the number of buckets to be filled)
duration = (pd.to_datetime(rounded_end_time , format ='%H') - pd.to_datetime(i, format ='%H')).seconds//3600
#initialize a count to count the number of buckets we fill
count = 0
while duration > count:
activity[i] = 1
count = count +1
#set the index of the bucket to be filled to the next indes, unless it goes beyond the last bucket, in which case continue from the first bucket
i = (i+1 if i+1 < 24 else 0)
print activity
答案 2 :(得分:0)
获取开始/结束时间的行并将它们分组到时间桶中(在这种情况下,总持续时间为分钟)
注意:并非所有边缘情况都已涵盖,但如果您认为有用
,则可以扩展代码#your imports
import numpy as np
import pandas as pd
from pandas.tseries.offsets import Hour, Minute
#optional
from IPython.core.debugger import set_trace
# construct a sample raw data dataframe
start_times = ['2000-01-01 09:00', '2000-01-01 10:00']
end_times = ['2000-01-01 17:00', '2000-01-01 18:00']
index = ['Timeframe ' + str(i) for i in range(len(start_times))]
df = pd.DataFrame({'Start Time': pd.to_datetime(start_times),
'End Time' : pd.to_datetime(end_times)}, index=index)
数据框 df 类似于下面的
End Time Start Time
时间范围0 2000-01-01 17:00:00 2000-01-01 09:00:00
时间范围1 2000-01-01 18:00:00 2000-01-01 10:00:00
#Construct your dataframe for time buckets
rng = pd.date_range('2000-01-01 09:00', periods=9, freq='H')
ts = pd.DataFrame(0, index=rng, columns=['minutes'], dtype='float')
数据框 ts 类似于下面的
minutes
2000-01-01 09:00:00 0.0
2000-01-01 10:00:00 0.0
2000-01-01 11:00:00 0.0
2000-01-01 12:00:00 0.0
2000-01-01 13:00:00 0.0
2000-01-01 14:00:00 0.0
2000-01-01 15:00:00 0.0
2000-01-01 16:00:00 0.0
2000-01-01 17:00:00 0.0
for index, row in ts.iterrows():
#set_trace()
start_boundary = index
end_boundary = index + Hour()
time_count = pd.Timedelta('0 m')
for _, raw_data in df.iterrows():
#set_trace()
start_time = raw_data['Start Time']
end_time = raw_data['End Time']
if end_time > start_boundary:
if start_time < end_boundary:
if start_time <= start_boundary:
if end_time >= end_boundary:
time_count = time_count + (end_boundary - start_boundary)
else:
time_count = time + (end_time - start_boundary)
else:
if end_time >= end_boundary:
time_count = time_count + (end_boundary - start_time)
else:
time_count = time_count + (end_time - start_time)
#set_trace()
ts.at[index, 'minutes'] = time_count.seconds / 60
运行上面的代码,您的 ts 数据框(见下文)应根据 df 数据框
中的原始数据,以分钟为单位计算总持续时间 minutes
2000-01-01 09:00:00 60.0
2000-01-01 10:00:00 120.0
2000-01-01 11:00:00 120.0
2000-01-01 12:00:00 120.0
2000-01-01 13:00:00 120.0
2000-01-01 14:00:00 120.0
2000-01-01 15:00:00 120.0
2000-01-01 16:00:00 120.0
2000-01-01 17:00:00 60.0