Pandas DataFrame关联需求:按ID筛选过去一年范围内的book_date数据
解决Pandas DataFrame按ID关联并筛选日期区间的问题
嘿,我来帮你搞定这个需求!我们的目标是针对df1里的每个ID,找出df2中所有落在对应ID记录日期过去一年到该日期区间内的book_date。下面分步骤给你演示实现方法:
第一步:确保日期列是datetime类型
首先得把两个DataFrame里的日期列转换成Pandas的datetime格式,这样才能正确做时间运算:
import pandas as pd # 先模拟示例数据(你可以替换成自己的真实数据) df1 = pd.DataFrame({ 'ID': [1, 2], 'record_date': ['2015-02-01', '2016-05-15'] }) df2 = pd.DataFrame({ 'ID': [1, 1, 2, 2], 'book_date': ['2015-02-01', '2014-08-03', '2016-03-20', '2015-01-10'] }) # 转换日期列 df1['record_date'] = pd.to_datetime(df1['record_date']) df2['book_date'] = pd.to_datetime(df2['book_date'])
方法一:全量合并后过滤(适合小数据集)
这种方法逻辑直观,先按ID把两个DataFrame合并,再筛选符合日期条件的记录:
# 按ID合并两个DataFrame,保留df1的所有记录 merged_df = pd.merge(df1, df2, on='ID', how='left') # 计算每个record_date对应的"过去一年"日期 merged_df['one_year_ago'] = merged_df['record_date'] - pd.DateOffset(years=1) # 筛选book_date在[one_year_ago, record_date]区间内的记录 filtered_df = merged_df[ (merged_df['book_date'] >= merged_df['one_year_ago']) & (merged_df['book_date'] <= merged_df['record_date']) ] # 提取需要的列(按需调整) result = filtered_df[['ID', 'record_date', 'book_date']]
运行后,针对你举的ID=1的例子:record_date是2015-02-01,one_year_ago是2014-02-01,所以2015-02-01和2014-08-03都会被保留。如果你的需求是只保留等于record_date的book_date,可以把过滤条件改成merged_df['book_date'] == merged_df['record_date']。
方法二:分组处理(适合大数据集)
如果你的数据量很大,全量合并会占用过多内存,用groupby+apply的方式更高效:
def filter_book_dates(group): # 获取当前分组的record_date(每个ID在df1里应该只有一条记录吧?如果有多条需要调整) record_date = group['record_date'].iloc[0] one_year_ago = record_date - pd.DateOffset(years=1) # 从df2中筛选同ID且日期符合条件的记录 valid_books = df2[ (df2['ID'] == group.name) & (df2['book_date'] >= one_year_ago) & (df2['book_date'] <= record_date) ] # 把record_date补到结果里 valid_books['record_date'] = record_date return valid_books # 按ID分组处理df1 result = df1.groupby('ID').apply(filter_book_dates).reset_index(drop=True)
这种方法只会对每个ID的记录进行关联和筛选,避免了全量合并的内存开销。
验证结果
对于我们的示例数据,最终的result会是:
| ID | record_date | book_date |
|---|---|---|
| 1 | 2015-02-01 | 2015-02-01 |
| 1 | 2015-02-01 | 2014-08-03 |
| 2 | 2016-05-15 | 2016-03-20 |
如果你的实际需求是排除2014-08-03,那可能是对“过去一年”的定义有差异,比如你想筛选最近30天或者仅等于record_date的记录,只需要修改过滤条件里的时间差即可(比如把pd.DateOffset(years=1)改成pd.DateOffset(days=30))。
内容的提问来源于stack exchange,提问作者S_Ymln
相关产品推荐
相关产品推荐

