根据ID和日期范围过滤数据框

时间:2018-11-29 20:48:19

标签: python-3.x pandas

我有一个熊猫数据框df,其中包含IDdate列:

start = datetime.datetime.today()
dates = [start, start+relativedelta(days=20), start+relativedelta(days=40),
         start, start+relativedelta(days=35), start+relativedelta(days=36),
         start, start+relativedelta(days=10), start+relativedelta(days=15)]

df = pd.DataFrame({'ID':[1,1,1,2,2,2,3,3,3], 'date':dates})

   ID                       date
0   1 2018-11-29 15:35:56.876549
1   1 2018-12-19 15:35:56.876549
2   1 2019-01-08 15:35:56.876549
3   2 2018-11-29 15:35:56.876549
4   2 2019-01-03 15:35:56.876549
5   2 2019-01-04 15:35:56.876549
6   3 2018-11-29 15:35:56.876549
7   3 2018-12-09 15:35:56.876549
8   3 2018-12-14 15:35:56.876549

现在,我要过滤df,以便每个ID仅包括前30天。即日期<=(date.min()+ 30天)

例如,这意味着ID = 1(2019年1月1日)距离第一个日期(2018年11月29日)已超过30天,因此应将其删除。等等。产生的新数据框应为:

   ID                       date
0   1 2018-11-29 15:35:56.876549
1   1 2018-12-19 15:35:56.876549
3   2 2018-11-29 15:35:56.876549
6   3 2018-11-29 15:35:56.876549
7   3 2018-12-09 15:35:56.876549
8   3 2018-12-14 15:35:56.876549

这如何以编程方式完成?

1 个答案:

答案 0 :(得分:2)

考虑为开始结束日期添加帮助列,然后运行布尔索引进行过滤。具体来说,将groupby().tansform用于内联min聚合:

df['start_date'] = df.groupby(df['ID'])['date'].transform('min')
df['end_date'] = df['start_date'] + relativedelta(days=30)

# BOOLEAN MASK
sub_df = df[(df['date'] >= df['start_date']) & (df['date'] <= df['end_date'])]
print(sub_df)
#    ID                       date                 start_date                   end_date
# 0   1 2018-11-29 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 1   1 2018-12-19 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 3   2 2018-11-29 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 6   3 2018-11-29 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 7   3 2018-12-09 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 8   3 2018-12-14 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788

# WITH BETWEEN()
sub_df = df[df['date'].between(df['start_date'], df['end_date'])]
print(sub_df)
#    ID                       date                 start_date                   end_date
# 0   1 2018-11-29 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 1   1 2018-12-19 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 3   2 2018-11-29 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 6   3 2018-11-29 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 7   3 2018-12-09 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 8   3 2018-12-14 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788

# WITH QUERY()
sub_df = df.query('date >= start_date & date <= end_date')
print(sub_df)
#    ID                       date                 start_date                   end_date
# 0   1 2018-11-29 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 1   1 2018-12-19 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 3   2 2018-11-29 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 6   3 2018-11-29 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 7   3 2018-12-09 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788
# 8   3 2018-12-14 15:22:35.301788 2018-11-29 15:22:35.301788 2018-12-29 15:22:35.301788

用于清理助手列:

# DROP HELPER COLUMNS
sub_df = sub_df.drop(columns=['start_date', 'end_date'])
print(sub_df)
#    ID                       date
# 0   1 2018-11-29 15:22:35.301788
# 1   1 2018-12-19 15:22:35.301788
# 3   2 2018-11-29 15:22:35.301788
# 6   3 2018-11-29 15:22:35.301788
# 7   3 2018-12-09 15:22:35.301788
# 8   3 2018-12-14 15:22:35.301788