我正在研究处方习惯,并拥有大量已售产品的数据框。
我正在尝试通过计算产品将持续多长时间并添加5天的法规遵从性,开始延误等软性因素以计算购买的结束日期,从而将购买的药物转变成药物的疗程。
然后我想将处方与重叠的日期窗口结合起来,但是我正在努力寻找一种有效的方法来做到这一点。我希望有一个groupby,但我不知道该怎么做。
我知道如何遍历数据框以创建具有相关信息的新数据框,但这是一个缓慢的操作,我希望可以找到一个更优雅的解决方案。
ID start end ingredient days dose end
1000 2018-10-03 2018-10-18 Metron... 10.0 125.00
1000 2018-10-13 2018-10-25 Metron... 7.0 125.00
1001 2018-03-08 2018-03-20 Cefalexin 7.0 150.00
1001 2018-09-17 2018-10-05 Cefalexin 13.0 150.00
1002 2018-05-18 2018-05-30 Amoxiclav 7.0 75.00
1002 2018-05-25 2018-06-06 Amoxiclav 7.0 100.00
1003 2018-07-01 2018-07-16 Amoxiclav 10.0 50.00
1003 2018-07-15 2018-07-30 Amoxiclav 10.0 50.00
1003 2018-07-25 2018-08-09 Amoxiclav 10.0 50.00
我的预期结果如下:
ID start end ingredient days dose
1000 2018-10-03 2018-10-25 Metron... 17.0 125.00
1001 2018-03-08 2018-03-20 Cefalexin 7.0 150.00
1001 2018-09-17 2018-10-05 Cefalexin 13.0 150.00
1002 2018-05-18 2018-05-30 Amoxiclav 7.0 75.00
1002 2018-05-25 2018-06-06 Amoxiclav 7.0 100.00
1003 2018-07-01 2018-08-05 Amoxiclav 30.0 50.00
1000
的第二次购买正好是10天,因此结束日期与他们的第二次结束日期相同。
1001
没有重叠,因此保持原样。
1002
在开始日期和结束日期重叠,但是剂量有所变化,因此不应合并使用。
1003
总共有30天的价值。他们最后一次购买的开始日期晚于第一次购买的结束日期。终止日期应为首次购买后的35天。这是一个可以协商的标准,可以接受与最终购买的结束日期匹配的结束日期。
我在这里吠错树了吗?是否必须迭代完成?
答案 0 :(得分:0)
我认为这里最大的问题是确定时间间隔何时重叠,剩下的只是分组和加法。
首先,请确保(如果尚未完成)将日期转换为datetime
,并将日期转换为timedelta
。这将有助于比较日期和持续时间并对其进行一些数学运算。
df['start'] = pd.to_datetime(df['start'])
df['end'] = pd.to_datetime(df['end'])
df['days'] = pd.to_timedelta(df['days'], unit='D')
此代码可产生预期的结果:
def join_times(x):
startdf = pd.DataFrame({'time':x['start'], 'what':1})
enddf = pd.DataFrame({'time':x['end'], 'what':-1})
mergdf = pd.concat([startdf, enddf]).sort_values('time')
mergdf['running'] = mergdf['what'].cumsum()
mergdf['newwin'] = mergdf['running'].eq(1) & mergdf['what'].eq(1)
mergdf['group'] = mergdf['newwin'].cumsum()
x['group'] = mergdf['group'].loc[mergdf['what'].eq(1)]
res = x.groupby('group').agg({'days':'sum', 'start':'first'})
res['end'] = res.apply(lambda x : x['start'] + x['days'] + pd.to_timedelta(5, unit='D'), axis=1)
return res
ddf = df.groupby(['ID', 'ingredient', 'dose']).apply(join_times).reset_index().drop('group', axis=1)
这需要解释。如您所见,我使用groupby
来识别子样本。然后,通过自定义join_times
函数完成该工作。
join_times
函数在单个数据帧的同一列(列'time'
)的开始和结束时间中连接在一起,并按顺序排序。
第二列'what'
用+1开始时间和-1结束时间标记。这些用于跟踪有多少间隔重叠(在列'running'
中使用cumsum()
)。
然后,构建布尔列'newwin'
以标识新的非重叠时间间隔的开始,并构建列'group'
以用相同的整数标记属于相同重叠时间间隔的行。>
将'group'
列添加到原始子样本中,复制先前构建的'group'
列中的值。最后,我们可以为每个子样本识别哪些行重叠。
因此,我们可以再次使用groupby
并求和'days'
列,并保留'start'
列的第一个日期。
'end'
列的计算方法是将'start'
的持续时间加上'days'
加上5天。
上面的代码使用您的数据示例给出:
ID ingredient dose days start end
0 1000 Metron... 125.0 17 days 2018-10-03 2018-10-25
1 1001 Cefalexin 150.0 7 days 2018-03-08 2018-03-20
2 1001 Cefalexin 150.0 13 days 2018-09-17 2018-10-05
3 1002 Amoxiclav 75.0 7 days 2018-05-18 2018-05-30
4 1002 Amoxiclav 100.0 7 days 2018-05-25 2018-06-06
5 1003 Amoxiclav 50.0 30 days 2018-07-01 2018-08-05
这是您的预期结果。由于groupby
的索引操作导致列顺序不同。