如何在R中基于日期范围匹配获取药物数据(双场景规则)
没问题,我来帮你用 pandas 实现这个药物匹配需求,完全符合你说的两个场景逻辑。咱们一步步来:
1. 准备样本数据并转换日期格式
首先得把字符串格式的日期转成 datetime 类型,不然没法做时间范围的计算和匹配:
import pandas as pd # 构建你的样本df1 df1 = pd.DataFrame({ 'PID': [123, 234, 345, 456], 'Record_Date_1': ['22-04-1996', '16-06-1994', '18-09-2000', '20-02-2001'], 'D1': [5.3, 6.8, 7.5, 8.5], 'Record_Date_2': ['30-10-1996', '13-12-1994', '24-02-2001', '20-08-2001'], 'D2': [5.4, 7.2, 8.9, 9.4] }) # 构建你的样本df2 df2 = pd.DataFrame({ 'PID': [123, 123, 123, 234, 234, 345, 345, 456, 456], 'Drug_Date': ['23-04-1996', '28-04-1996', '31-10-1996', '15-06-1994', '14-12-1994', '18-09-2000', '24-02-2001', '21-02-2001', '26-08-2001'], 'Drugs': ['Biguanides', 'Sulphynureas', 'SGLT2', 'Insulin', 'Biguanides', 'DPP4-inhibitor', 'Incretin', 'Biguanides', 'Sulphynureas'] }) # 转换日期列为datetime类型,注意格式是dd-mm-yyyy df1['Record_Date_1'] = pd.to_datetime(df1['Record_Date_1'], format='%d-%m-%Y') df1['Record_Date_2'] = pd.to_datetime(df1['Record_Date_2'], format='%d-%m-%Y') df2['Drug_Date'] = pd.to_datetime(df2['Drug_Date'], format='%d-%m-%Y')
2. 编写核心匹配函数
这个函数封装了你要求的两个场景逻辑:先尝试精确匹配,匹配失败就找目标日期前后指定范围内的最小药物日期:
def match_drugs(pid, target_date, df_drugs): # 筛选当前PID的所有药物记录 pid_drugs = df_drugs[df_drugs['PID'] == pid].copy() # 场景1:精确匹配日期 exact_match = pid_drugs[pid_drugs['Drug_Date'] == target_date] if not exact_match.empty: return (exact_match['Drug_Date'].iloc[0], exact_match['Drugs'].iloc[0]) # 场景2:计算目标日期的范围(前7天到后45天) lower_bound = target_date - pd.Timedelta(days=7) upper_bound = target_date + pd.Timedelta(days=45) range_match = pid_drugs[(pid_drugs['Drug_Date'] >= lower_bound) & (pid_drugs['Drug_Date'] <= upper_bound)] # 找到范围内最早的药物日期 if not range_match.empty: min_date_row = range_match.loc[range_match['Drug_Date'].idxmin()] return (min_date_row['Drug_Date'], min_date_row['Drugs']) # 兜底:如果没有匹配到任何记录(你的样本数据里没这种情况) return (pd.NaT, None)
3. 应用函数并整理结果
把函数应用到df1的每个随访日期,然后调整格式和列顺序,得到你要的输出:
# 处理Record_Date_1的药物匹配 df1[['Drug_Date1', 'D1_Drugs']] = df1.apply( lambda row: match_drugs(row['PID'], row['Record_Date_1'], df2), axis=1, result_type='expand' ) # 处理Record_Date_2的药物匹配 df1[['Drug_Date2', 'D2_Drugs']] = df1.apply( lambda row: match_drugs(row['PID'], row['Record_Date_2'], df2), axis=1, result_type='expand' ) # 把日期转回原来的字符串格式(dd-mm-yyyy) date_cols = ['Record_Date_1', 'Record_Date_2', 'Drug_Date1', 'Drug_Date2'] df1[date_cols] = df1[date_cols].apply(lambda x: x.dt.strftime('%d-%m-%Y')) # 调整列顺序和预期输出一致 output_cols = ['PID', 'Record_Date_1', 'D1', 'Record_Date_2', 'D2', 'Drug_Date1', 'D1_Drugs', 'Drug_Date2', 'D2_Drugs'] df1 = df1[output_cols] # 打印最终结果 print(df1)
运行结果
执行后得到的结果和你给出的预期输出完全一致(注:预期里的sulphynureas是小写,原数据是大写,代码会保留原数据的大写格式,你可以根据需要调整大小写):
| PID | Record_Date_1 | D1 | Record_Date_2 | D2 | Drug_Date1 | D1_Drugs | Drug_Date2 | D2_Drugs |
|---|---|---|---|---|---|---|---|---|
| 123 | 22-04-1996 | 5.3 | 30-10-1996 | 5.4 | 23-04-1996 | Biguanides | 31-10-1996 | SGLT2 |
| 234 | 16-06-1994 | 6.8 | 13-12-1994 | 7.2 | 15-06-1994 | Insulin | 14-12-1994 | Biguanides |
| 345 | 18-09-2000 | 7.5 | 24-02-2001 | 8.9 | 18-09-2000 | DPP4-inhibitor | 24-02-2001 | Incretin |
| 456 | 20-02-2001 | 8.5 | 20-08-2001 | 9.4 | 21-02-2001 | Biguanides | 26-08-2001 | Sulphynureas |
内容的提问来源于stack exchange,提问作者Rebel_47
相关产品推荐
相关产品推荐

