登录
首页精彩阅读时间序列,从开始到结束日期自增扩充数据
时间序列,从开始到结束日期自增扩充数据
2021-07-15
收藏

来源:数据STUDIO

作者:云朵君

糖尿病是全球最常见的慢性非传染性疾病之一。流行病学调查显示,我国约11%的成年人患有糖尿病,而在住院患者中这一比例更高。

住院期间将长期服用药物,医院系统在检测到医嘱优先级别为长期医嘱时,会根据医嘱单上医嘱开始日期及时间,每天按时自动创建当日医嘱单,在没有停止或更改的情况下,其医嘱内容与上一天医嘱内容一致。患者根据每天的医嘱单上的内容按时按量服用药物,直至医生停止患者用药。

由于是重复内容,系统为节约存储空间,并未记录每天自动创建的重复医嘱单。但在做数据分析时,需要进行临床场景重现。

一、需求描述

有如下数据,columns = ['医嘱日期', '医嘱时间', '医嘱开始日期', '医嘱开始时间','医嘱优先级', '停止日期', '停止时间', '项目名称']

时间序列,从开始到结束日期自增扩充数据

现要求从医嘱开始日期到停止日期,按照日期自增逻辑扩充数据,其中自增的日期的医嘱开始时间为当日的01:00:00。结果如下图:

时间序列,从开始到结束日期自增扩充数据

二、方法一,表格合并

先上代码

def long_advice(item):
    # 逐条处理,传入Series     # 构建医嘱单内容表     item_df1 = pd.DataFrame(data=np.reshape(item.values,(1,-1)),columns=item.index)
    item_df2 = item_df1.copy()
    item_df2['医嘱开始时间'] = parse('01:00:00').time()
    item_df = pd.concat([item_df1, item_df2]).drop(columns='医嘱开始日期').reset_index(drop=True)
    
    # 构建时间序列索引     # 扩展的医嘱日期的医嘱时间为01:00:00,医嘱开始日期的医嘱时间为原有的医嘱时间     date_range_left = pd.DataFrame(
        data=parse('01:00:00').time(),
        index=pd.date_range(start=item.医嘱开始日期, end=item.停止日期),
        columns= ['医嘱开始时间']
                                  ).reset_index().rename(columns={'index':'医嘱开始日期'})
    date_range_left.loc[0,'医嘱开始时间']= item.医嘱时间
    
    # 以时间序列索引表为左表,以时间序列内容表为右表     date_range_df = pd.merge(date_range_left
                         ,item_df
                         ,on = '医嘱开始时间'                          ,how='left')
    return  date_range_df

步骤详解

导入Python包

import pandas as pd import numpy as np from datetime import datetime from dateutil.parser import parse

查看原始数据

# 前面步骤略,直接从主题开始 >>> item 医嘱日期      2019-08-05 00:00:00 医嘱时间                 16:34:25 医嘱开始日期    2019-08-05 00:00:00 医嘱开始时间               16:34:42 医嘱优先级                    长期医嘱 停止日期      2019-08-27 00:00:00 停止时间                 10:49:26 项目名称           格华止(500mg×30片) Name: 0, dtype: object 

pd.Series转pd.DataFrame

# 纵向向array转横向array >>> np.reshape(item.values,(1,-1))
array([[Timestamp('2019-08-05 00:00:00'), datetime.time(163425),
        Timestamp('2019-08-05 00:00:00'), datetime.time(163442),
        '长期医嘱', Timestamp('2019-08-27 00:00:00'),
        datetime.time(104926)]], dtype=object) >>> item_df1 = pd.DataFrame(data=np.reshape(item.values,(1,-1)),columns=item.index) # 或者 >>> pd.DataFrame(item).T

输出

时间序列,从开始到结束日期自增扩充数据

构建医嘱单内容表

# 首先创建副本,避免更改原表 >>> item_df2 = item_df1.copy() # 创建datetime.time()格式的'01:00:00' >>> parse('01:00:00').time()
datetime.time(10) # 将原来的时间更换为新的时间 >>> item_df2['医嘱开始时间'] = parse('01:00:00').time() # 合并两表 >>> item_df = pd.concat([item_df1, item_df2]
                       ).drop(columns='医嘱开始日期').reset_index(drop=True)

输出

时间序列,从开始到结束日期自增扩充数据

至此医嘱单内容已创建完毕,接下来需要创建自增的时间序列,并以时间序列做主表,以医嘱单内容表做从表,进行表与表之间的连接。

构建时间序列索引

从医嘱开始日期到停止日期创建pd.date_range() 索引,以医嘱开始时间等于'01:00:00' 为内容创建DataFrame,并重置索引并重命名,还原医嘱开始当日的开始时间。因为只要自增的那部分日期的医嘱时间为'01:00:00' ,而开始的第一天还是按照原来的开始时间。

>>> date_range_left = pd.DataFrame(data=parse('01:00:00').time(),
                                   index=pd.date_range(start=item.医嘱开始日期, end=item.停止日期),
                                   columns= ['医嘱开始时间']
                                  ).reset_index().rename(columns={'index':'医嘱开始日期'}) >>> date_range_left.loc[0,'医嘱开始时间']= item.医嘱开始时间 >>> date_range_left

输出

时间序列,从开始到结束日期自增扩充数据

这里主要用到了pd.date_range() 方法,可参考《时间序列》

合并时间序列索引表与医嘱单内容表

>>> date_range_df = pd.merge(date_range_left
                             , item_df
                             , on='医嘱开始时间'                              , how='left')

至此方法一已完成。

三、方法二,时间戳重采样

既然方法一已经提到用时间序列内pd.date_range() 方法,何不直接用升采用及插值的方法完成。

需要了解pandas里使用时间序列处理数据问题,可移步至《时间序列》。

上代码

def long_advice_2(item):
    # 逐条处理,传入Series     # 构建医嘱单内容表     item_df1 = pd.DataFrame(data=np.reshape(item.values,(1,-1)),columns=item.index)
    item_df2 = item_df1.copy()
    item_df2['医嘱开始时间'] = parse('01:00:00').time()
    item_df2['医嘱开始日期'] = item_df2['停止日期']
    item_df = pd.concat([item_df1, item_df2]).reset_index(drop=True)
    # 构建时间序列,将起始时间转换为 DatetimeIndex(['2019-08-05', '2019-08-27'], dtype='datetime64[ns]', freq=None)     frame = pd.DataFrame(item_df.drop(columns=['医嘱开始日期']).values,
             index=pd.to_datetime(item_df.医嘱开始日期.values),
             columns=item_df.drop(columns=['医嘱开始日期']).columns)
    
    # 时间戳重采样,resampling的填充和插值方式跟fillna和reindex的一样     date_range_df = frame.resample('D').bfill().reset_index().rename(columns={'index':'医嘱开始日期'})
    return date_range_df

构建医嘱单内容表

其中构建医嘱单内容表与前面类似,其不同之处为保留医嘱开始日期,将第二个开始日期替换为停止日期,以便后面转换为pd.date_range()日期范围。

>>> item_df1 = pd.DataFrame(data=np.reshape(item.values,(1,-1)),columns=item.index) >>> item_df2 = item_df1.copy() >>> item_df2['医嘱开始时间'] = parse('01:00:00').time() >>> item_df2['医嘱开始日期'] = item_df2['停止日期'] >>> item_df = pd.concat([item_df1, item_df2]).reset_index(drop=True) >>> item_df

输出

时间序列,从开始到结束日期自增扩充数据

构建时间序列

>>DataFrame的轴索引或列的日期转换为DatetimeIndex() >>> pd.to_datetime(item_df.医嘱开始日期.values)
DatetimeIndex(['2019-08-05''2019-08-27'], dtype='datetime64[ns]', freq=None) >>> frame = pd.DataFrame(item_df.drop(columns=['医嘱开始日期']).values,
                 index=pd.to_datetime(item_df.医嘱开始日期.values),
                 columns=item_df.drop(columns=['医嘱开始日期']).columns) >>> frame 

输出

时间序列,从开始到结束日期自增扩充数据

升采样及插值

时间戳重采样,resampling的填充和插值方式跟fillnareindex的一样

>>> date_range_df = frame.resample('D').bfill() >>> date_range_df

输出

时间序列,从开始到结束日期自增扩充数据

最后在重置索引并重命名即可。

四、要点总结

  • 构建自增时间序列
  • 时间序列内容,即需要重复的医嘱单准备
  • 医嘱开始时间准备,第一天与其后几天的时间不同
  • 插值,根据实际情况使用前插值(.ffill())或后插值(.bfill()

当然,除了上述的两种方法,如果您有更好的方法,欢迎搭讪交流。


数据分析咨询请扫描二维码

客服在线
立即咨询