我有一组病人在几年内去看医生的数据。变量包括患者ID和访问日期。我有兴趣在任何一天确定有多少患者仍在接受治疗。我认为患者的最后一次就诊表明他们不再接受治疗。
患者有不同的就诊次数和不同的就诊日期。这也意味着患者有不同的治疗时间。以下是我的数据示例:
index patient_id visit_date
0 01 2014-08-10
1 01 2014-08-12
2 01 2014-08-13
3 02 2014-08-12
4 02 2014-08-15
5 03 2014-08-13
6 03 2014-08-15
7 03 2014-08-16
理想情况下,我希望最终数据集如下所示:
date num_patients
2014-08-10 1
2014-08-11 1
2014-08-12 2
2014-08-13 3
2014-08-14 2
2014-08-15 2
2014-08-16 1
我正在使用pandas并且尝试使用reindex
尝试解决此问题但未成功。如果我使用的是Stata
,我会使用xtset
和tsfill
,但我不知道大熊猫中的等价物。我将注意到,我的数据集在数千天内有超过300,000次观测,因此我们将非常感谢有效的解决方案。
我一直在撕扯我的头发,并试图找出解决问题的最佳方法,我会感激任何帮助!
已于2016年3月19日
我意识到我可能不太清楚我的最终输出。我试图计算在某一天接受治疗的患者数量,即使他们当天没有预约。
例如,(参见上面的输出表)我希望2014-08-13的患者数量为3,因为患者1,2和3仍在接受治疗。患者1和3当天有实际访问,但患者2没有。然而,患者2仍然很重要,因为她尚未进行最后一次就诊(2014-08-15),这表明她仍处于治疗中。
感谢所有的帮助和建议!
答案 0 :(得分:3)
设置数据框,使visit_date
格式化为pandas datetime
对象并用作索引。 index
列被删除,因为它是多余的。
import pandas as pd
from StringIO import StringIO
# Create DataFrame from the example data
data = '''index patient_id visit_date
0 01 2014-08-10
1 01 2014-08-12
2 01 2014-08-13
3 02 2014-08-12
4 02 2014-08-15
5 03 2014-08-13
6 03 2014-08-15
7 03 2014-08-16
'''
df = pd.read_csv(StringIO(data), delim_whitespace=True)
# Remove the 'index' column; this is redundant
df.drop('index', axis=1, inplace=True)
# Convert 'visit_date' to datetime and set it as the index
df.visit_date = pd.to_datetime(df.visit_date, format='%Y-%m-%d')
df.set_index('visit_date', inplace=True, drop=True)
# Peek at the first five rows
print(df.head())
浏览DataFrame:
patient_id
visit_date
2014-08-10 1
2014-08-12 1
2014-08-13 1
2014-08-12 2
2014-08-15 2
请注意,patient_id
已转换为整数。只要每个id都是唯一的,这与分析的其余部分无关。
resample
由于现在是time series,因此pandas提供了一种使用resample
计算访问次数的简单方法:
# set bin size to 1 (D)ay and count
visits_count = df.resample('D').count()
print(visits_count)
哪个输出:
patient_id
visit_date
2014-08-10 1
2014-08-11 0
2014-08-12 2
2014-08-13 2
2014-08-14 0
2014-08-15 2
2014-08-16 1
groupby
提取计数的有效方法是对数据进行分组并将汇总函数应用于每个组。
def count_visits(grp):
count = grp.patient_id.size
return count
visits_df = df.groupby(df.index).apply(count_visits)
print(visits_df)
输出一只熊猫系列:
visit_date
2014-08-10 1
2014-08-12 2
2014-08-13 2
2014-08-15 2
2014-08-16 1
或者,您可以使用agg
函数来获得类似的结果。
import numpy as np
visits_df = df.groupby(df.index).agg(np.size)
print(visits_df)
输出pandas DataFrame:
patient_id
visit_date
2014-08-10 1
2014-08-12 2
2014-08-13 2
2014-08-15 2
2014-08-16 1
resample
groupby
and agg
上的本教程将为您提供更多帮助。答案 1 :(得分:1)
这是获得所需输出的一种方法,但我不确定它在非常大/稀疏的数据集上的效率。
import pandas as pd
from StringIO import StringIO
from pandas.tseries.offsets import DateOffset
str = '''patient_id visit_date
01 2014-08-10
01 2014-08-12
01 2014-08-13
02 2014-08-12
02 2014-08-15
03 2014-08-13
03 2014-08-15
03 2014-08-16
'''
df = pd.read_csv(StringIO(str), delim_whitespace=True)
df['visit_date'] = pd.to_datetime(df['visit_date'], format='%Y-%m-%d')
df = df.set_index('visit_date', drop=True)
# function to fill in the gaps for each patient
def fill_gaps(group):
return group.asfreq(DateOffset(days=1))
filled_df = df.groupby('patient_id').apply(fill_gaps)
这就是fill_df在这一点上的样子:
patient_id
patient_id visit_date
1 2014-08-10 1
2014-08-11 NaN
2014-08-12 1
2014-08-13 1
2 2014-08-12 2
2014-08-13 NaN
2014-08-14 NaN
2014-08-15 2
3 2014-08-13 3
2014-08-14 NaN
2014-08-15 3
2014-08-16 3
索引包含我们需要的所有信息,因此我们删除了patient_id列并重置了索引。此时,您可以在他的答案中使用@gauden提及的任何解决方案,并查看数据集中哪一个最快。
filled_df = filled_df.drop('patient_id', axis=1)
filled_df = filled_df.reset_index()
filled_df = filled_df.set_index('visit_date')
final_df = filled_df.groupby(filled_df.index).size()
现在,final_df看起来像是原始问题的最终数据集:
visit_date
2014-08-10 1
2014-08-11 1
2014-08-12 2
2014-08-13 3
2014-08-14 2
2014-08-15 2
2014-08-16 1