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

时间:2016-03-19 06:54:54

标签: python pandas

我有一组病人在几年内去看医生的数据。变量包括患者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,我会使用xtsettsfill,但我不知道大熊猫中的等价物。我将注意到,我的数据集在数千天内有超过300,000次观测,因此我们将非常感谢有效的解决方案。

我一直在撕扯我的头发,并试图找出解决问题的最佳方法,我会感激任何帮助!

已于2016年3月19日

我意识到我可能不太清楚我的最终输出。我试图计算在某一天接受治疗的患者数量,即使他们当天没有预约。

例如,(参见上面的输出表)我希望2014-08-13的患者数量为3,因为患者1,2和3仍在接受治疗。患者1和3当天有实际访问,但患者2没有。然而,患者2仍然很重要,因为她尚未进行最后一次就诊(2014-08-15),这表明她仍处于治疗中。

感谢所有的帮助和建议!

2 个答案:

答案 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

了解更多

答案 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