Python 在pandas中计算面板数据集中并发实体的数量

Python 在pandas中计算面板数据集中并发实体的数量,python,pandas,Python,Pandas,我有一组数年内患者就诊的数据。变量包括患者id和就诊日期。我感兴趣的是确定在任何一天有多少患者仍在接受治疗。我假设患者最后一次就诊表明他们不再接受治疗 患者有不同的就诊次数和就诊日期。这也意味着患者接受不同长度的治疗。以下是我的数据示例: index patient_id visit_date 0 01 2014-08-10 1 01 2014-08-12 2 01 2014-08-13 3

我有一组数年内患者就诊的数据。变量包括患者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
,但我不知道这些在熊猫中的等价物。我会注意到,我的数据集在数千天内有超过300000个观测值,因此我们希望能找到一个有效的解决方案

我一直在努力找出解决我问题的最佳方法,希望能得到任何帮助

2016年3月19日编辑

我意识到我可能不太清楚我的最终结果。我试图统计某一天有多少患者正在接受治疗,即使他们那天没有预约

例如,(见上面的输出表)我希望2014-08-13年的患者数量为3,因为患者1、2和3仍在接受治疗。患者1和3当天有实际就诊,但患者2没有。然而,患者2仍然是计数的,因为她还没有登录她的最后一次访问(2014-0815),这表明她仍然处于治疗的中间。p> 感谢所有的帮助和建议

设置 设置数据框,使
visit\u date
格式化为pandas
datetime
对象并用作索引。
索引
列被删除,因为它是冗余的

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())
数据帧概览:

            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
visit_date            
2014-08-10           1
2014-08-12           2
2014-08-13           2
2014-08-15           2
2014-08-16           1
请注意,
患者id
已转换为整数。只要每个id都是唯一的,这就与分析的其余部分无关

分析 使用
重新采样
由于这现在是一个简单的方法,pandas提供了一种使用
重采样来计算访问次数的简单方法:

# 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)
输出数据帧:

            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
visit_date            
2014-08-10           1
2014-08-12           2
2014-08-13           2
2014-08-15           2
2014-08-16           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)
这就是此时填充的_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

非常感谢你的帮助!我不知道重采样,我认为这将是非常有帮助的。代码的最终输出与我想要的略有不同(参见原始帖子)。例如,有没有办法让2014-08-13的计数为3而不是2?应该是3,因为从技术上讲,患者1、2和3正在接受治疗(即使患者2在2014-08-13没有就诊)。@Eric刚刚在您的扩展问题中添加了缺少的部分。你的解决方案结合了他的答案和我的答案。我可以建议你选择一个作为你的解决方案,然后再投票给另一个吗?:)