我有一个数据框:
import pandas as pd
df = pd.DataFrame({
'Customer' : ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B'],
'EventTime' : ['2019-06-03 09:51:05', '2019-06-03 09:55:07',
'2019-06-03 10:02:00', '2019-06-03 10:06:00',
'2019-06-03 10:07:00', '2019-06-03 10:20:00',
'2019-06-03 10:29:59', '2019-06-03 09:51:00',
'2019-06-03 09:52:00'],
'Status' : ['NotWorking', 'Working', 'NotWorking', 'Working', 'NotWorking',
'Working', 'Working', 'NotWorking', 'Working']
})
df
每条记录代表一个在EventTime发生的事件。 我必须找出每15分钟间隔内每个州的每个客户多少秒。 听起来很复杂,不是吗?
例如,对于客户A在2019-06-03 09:51:05,状态更改为不工作。 对于此记录,15分钟的时间是2019-06-03 09:45:00-2019-06-03 09:59:59。
对于没有先前记录的记录,先前的状态为工作。 因此,在从2019-06-03 09:45:00到2019-06-03 09:51:05的15分钟间隔内,我们的状态工作时间为365秒。
现在从2019-06-03 09:51:05到同一客户的下一条记录2019-06-03 09:55:07我们的状态为不工作有242秒。
从2019-06-03 09:55:07到15分钟结束(2019-06-03 09:59:59),我们的状态(仍为工作状态)为292 +1 = 293秒。
因此,客户A的第一记录以及从2019-06-03 09:45:00开始的15分钟期间的记录如下所示:
A 2019-06-03 09:45:00工作= 365 + 293 = 658,不工作= 242
现在我们还有15分钟的时间,开始于2019-06-03 10:00:00。 从2019-06-03 10:00:00到2019-06-03 10:02:00状态工作有120秒。 从2019-06-03 10:02:00到2019-06-03 10:06:00状态为不工作的时间为240秒 从2019-06-03 10:06:00到2019-06-03 10:07:00状态下的工作时间为60秒 从2019-06-03 10:07:00到15分钟结束(2019-06-03 10:14:59),状态为不工作有479 +1 = 480秒。
因此,客户A和15分钟(2019年6月3日10:00:00)的下一次记录是:
A 2019-06-03 10:00:00工作= 120 + 60 = 180,不工作= 240 + 480 = 720。
输出应为
用大熊猫做这样的计算可能吗?
致谢。
编辑:这应该是最终结果
我已经这样做了,但是我认为可以用更好的方法完成。
def start_of_15_min(event_datetime):
minute = event_datetime.minute
if minute >= 45:
new_minute=45
elif minute >= 30:
new_minute=30
elif minute >= 15:
new_minute=15
elif minute >= 0:
new_minute=0
new_event_datetime = datetime.datetime(event_datetime.year, event_datetime.month, event_datetime.day, event_datetime.hour, new_minute, 0)
return new_event_datetime
def end_of_15_min(event_datetime):
start_of_15_min_per = start_of_15_min(event_datetime)
return start_of_15_min_per + datetime.timedelta(seconds=899)
# In[308]:
df = pd.DataFrame({
'Customer' : ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B'],
'Status' : ['NotWorking', 'Working', 'NotWorking', 'Working', 'NotWorking',
'Working', 'Working', 'NotWorking', 'Working'],
'EventTime' : ['2019-06-03 09:51:05', '2019-06-03 09:55:07',
'2019-06-03 10:02:00', '2019-06-03 10:06:00',
'2019-06-03 10:07:00', '2019-06-03 10:20:00',
'2019-06-03 10:29:59', '2019-06-03 09:51:00',
'2019-06-03 09:52:00'],
})
df.EventTime = pd.to_datetime(df.EventTime)
df
# In[310]:
df.groupby('Customer').EventTime.agg(['min', 'max']).applymap(start_of_15_min)
# In[311]:
for idx, row in df.groupby('Customer').EventTime.agg(['min', 'max']).applymap(start_of_15_min).iterrows():
for event_time in pd.date_range(start=row['min'], end=row['max'], freq='15T'):
if len(df[(df.Customer == idx) & (df.EventTime == event_time)]) == 0:
new_row = pd.DataFrame({'Customer' : idx, 'Status': np.nan, 'EventTime' : event_time}, index=[0])
df = df.append(new_row)
df = df.sort_values(['Customer', 'EventTime']).reset_index(drop=True)
df
# In[313]:
df.Status = df.groupby('Customer').Status.fillna(df.groupby('Customer').Status.shift())
df
# In[314]:
df.Status = df.Status.fillna('Working')
df
# In[315]:
for idx, row in df.groupby('Customer').EventTime.agg(['min', 'max']).applymap(end_of_15_min).iterrows():
for event_time in pd.date_range(start=row['min'], end=row['max'], freq='15T'):
if len(df[(df.Customer == idx) & (df.EventTime == event_time)]) == 0:
new_row = pd.DataFrame({'Customer' : idx, 'Status': np.nan, 'EventTime' : event_time}, index=[0])
df = df.append(new_row)
df = df.sort_values(['Customer', 'EventTime']).reset_index(drop=True)
df
# In[316]:
df.Status = df.groupby('Customer').Status.fillna(df.groupby('Customer').Status.shift())
df
# In[317]:
df['Seconds'] = df.groupby('Customer').EventTime.apply(lambda x: (x.shift(-1) - x).dt.seconds)
df
# In[318]:
df['StartOf15Minutes'] = df.EventTime.apply(start_of_15_min)
df
# In[319]:
df.Seconds = df.Seconds.fillna(1)
df
# In[320]:
fin = df.groupby(['Customer', 'StartOf15Minutes', 'Status']).Seconds.sum().to_frame()
fin
# In[305]:
fin.Seconds.sum()
答案 0 :(得分:1)
为首个重复行和最后一个重复行创建IDEEA数据框,通过Series.dt.floor
更改日期时间,并通过concat
进行连接:
df['EventTime'] = pd.to_datetime(df['EventTime'])
df1 = df.drop_duplicates('Customer').copy()
#swap values
df1['Status'] = df1['Status'].map({'NotWorking':'Working','Working':'NotWorking'})
df1['EventTime'] = df1['EventTime'].dt.floor('15T')
df2 = df.drop_duplicates('Customer', keep='last').copy()
df2['EventTime'] = df2['EventTime'].dt.floor('15T') + pd.Timedelta(60 * 15, 's')
df = pd.concat([df, df1, df2], ignore_index=True)
然后通过每组ffill
重新采样,每组删除最后一个值并汇总size
来计算秒数,以秒为单位:
df1 = (df.set_index('EventTime')
.groupby('Customer')
.resample('s').ffill())
df1 = df1[df1.index.get_level_values(0).duplicated(keep='last')]
df1 = (df1.reset_index(level=0, drop=True)
.groupby(['Customer', 'Status', pd.Grouper(freq='15T')])
.size())
print (df1)
Customer Status EventTime
A NotWorking 2019-06-03 09:45:00 242
2019-06-03 10:00:00 720
2019-06-03 10:15:00 300
Working 2019-06-03 09:45:00 658
2019-06-03 10:00:00 180
2019-06-03 10:15:00 600
B NotWorking 2019-06-03 09:45:00 60
Working 2019-06-03 09:45:00 840
dtype: int64