首页 > 解决方案 > 如何创建按日期排序的groupby ID变量第一次出现的指标列?

问题描述

我在表单的数据框中有一些医院就诊医疗保健数据:

CLIENT_ID DATE_ENCOUNTER DATE_CONSELLING COUNSELLING_COUNT 个
54950 2017-11-24 0
54950 2018-01-19 0
54950 2018-03-13 0
54950 2018-05-11 2018-04-30 1
54950 2018-12-17 2018-06-25 3
67777 2015-09-01 0
67777 2015-12-01 0
67777 2016-02-28 2016-02-28 1
70000 2019-06-07 2019-06-07 1
70000 2019-08-09 2019-06-07 1

我想创建一个列COUNSELLING_STARTED来指示客户是否CLIENT_ID已经开始咨询,但只是第一次。即COUNSELLING_COUNT == 1对于每个CLIENT_ID应该导致以下数据帧的第一次出现:

CLIENT_ID DATE_ENCOUNTER DATE_CONSELLING COUNSELLING_COUNT 个 COUNSELLING_STARTED
54950 2017-11-24 0 0
54950 2018-01-19 0 0
54950 2018-03-13 0 0
54950 2018-05-11 2018-04-30 1 1
54950 2018-12-17 2018-06-25 3 0
67777 2015-09-01 0 0
67777 2015-12-01 0 0
67777 2016-02-28 2016-02-28 1 1
70000 2019-06-07 2019-06-07 1 1
70000 2019-08-09 2019-06-07 1 0

下面是生成数据框的代码:

data = {'CLIENT_ID':[54950,54950,54950,54950,54950,67777,67777,67777,70000,70000],
'DATE_ENCOUNTER':['2017-11-24','2018-01-19','2018-03-13','2018-05-11','2018-12-17','2015-09-01','2015-12-01','2016-02-28','2019-06-07','2019-08-09'],
'DATE_COUNSELLING':[np.nan,np.nan,np.nan,'2018-04-30','2018-06-25',np.nan,np.nan,'2016-02-28','2019-06-07','2019-06-07'],
'COUNSELLING_COUNT':[0,0,0,1,3,0,0,1,1,1]}

df = pd.DataFrame(data)

标签: pythonpandasdataframenumpypandas-groupby

解决方案


更新

在我最初的回答中,我错过了一个事实,即如果有人没有咨询日期,我的方法会1为他们的第一个条目分配一个。这是解决此问题的两种快速方法。

一种选择是在执行我描述的 groupby 之前使用 NA 显式删除这些行:

dropped = df[~df['DATE_COUNSELLING'].isna()]
df.loc[:, 'COUNSELLING_STARTED'] = 0
df.loc[dropped['DATE_COUNSELLING'].isna().groupby(dropped['CLIENT_ID']).idxmin(), 'COUNSELLING_STARTED'] = 1
# note that `dropped` is used inside the brackets in the last line

第二种选择是简单地做我以前做过的事情,然后覆盖错误的条目(即,咨询是 NA):

df.loc[:, 'COUNSELLING_STARTED'] = 0
df.loc[df['DATE_COUNSELLING'].isna().groupby(df['CLIENT_ID']).idxmin(), 'COUNSELLING_STARTED'] = 1
df.loc[df['DATE_COUNSELLING'].isna(), 'COUNSELLING_STARTED'] = 0
# last line catches people with no counseling

这是我原来的答案

df.loc[:, 'COUNSELLING_STARTED'] = 0
df.loc[df['DATE_COUNSELLING'].isna().groupby(df['CLIENT_ID']).idxmin(), 'COUNSELLING_STARTED'] = 1

解释(使用我的第一种方法):

查找咨询日期在哪里nan;然后按客户端 ID 分组并找到最小值的索引(这将是第一个条目):

>>> dropped['DATE_COUNSELLING'].isna().groupby(dropped['CLIENT_ID']).idxmin()
CLIENT_ID
54950    3
67777    7
70000    8
Name: DATE_COUNSELLING, dtype: int64

1您正在使用这些索引来选择在新列中写入的位置。即使dropped没有任何 NA 值,我们仍然.isna()在 groupby 中使用以获取我们可以接受的值min(而不是字符串)。你也可以做类似的事情.astype(bool)

那么决赛df是:

   CLIENT_ID DATE_ENCOUNTER  ... COUNSELLING_COUNT  COUNSELLING_STARTED
0      54950     2017-11-24  ...                 0                    0
1      54950     2018-01-19  ...                 0                    0
2      54950     2018-03-13  ...                 0                    0
3      54950     2018-05-11  ...                 1                    1
4      54950     2018-12-17  ...                 3                    0
5      67777     2015-09-01  ...                 0                    0
6      67777     2015-12-01  ...                 0                    0
7      67777     2016-02-28  ...                 1                    1
8      70000     2019-06-07  ...                 1                    1
9      70000     2019-08-09  ...                 1                    0

[10 rows x 5 columns]

如果您想明确选择最早的咨询日期(而不是第一个非 NA 值),则可以将其用作索引器:

>>> pd.to_datetime(dropped['DATE_COUNSELLING']).groupby(dropped['CLIENT_ID']).idxmin()
CLIENT_ID
54950    3
67777    7
70000    8
Name: DATE_COUNSELLING, dtype: int64

这给出了相同的结果,因为日期是为每个客户排序的(即最早观察到的日期是第一个非 NA 值)。


推荐阅读