You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于患者唯一标识(Patient Key)及24小时时间条件合并DataFrame的高效实现方法咨询

基于患者唯一标识(Patient Key)及24小时时间条件合并DataFrame的高效实现方法咨询

Hey Hannah, 你的需求其实完全不用硬编码循环来实现,pandas里有专门的工具能高效搞定这种按唯一键+时间窗口匹配的场景,比手动写循环快太多,尤其是数据量上去的时候优势特别明显。

核心思路:用merge_asof实现精准时间匹配

merge_asof是pandas专门为这种"按键匹配,同时按时间范围关联"的场景设计的,它会为左表的每一行,在右表中找到符合时间条件的最近匹配项,完美契合你要的"出院时间24小时内的入院记录"需求。

具体实现步骤

1. 先把时间列转成datetime类型

这是所有时间运算的前提,确保pandas能正确识别时间:

import pandas as pd

# 处理你的示例DataFrame A
df_a = pd.DataFrame({
    'Row': [1,2,3,4,5],
    'Patient Key': ['A123','A123','A321','A213','A321'],
    'Source Hospital': ['A','A','A','A','A'],
    'Source Discharge Datetime': ['1-1-23 01:00:00','2-3-23 10:00:00','3-2-32 11:00:00','2-3-23 13:00:00','3-30-32 12:00:00']
})

# 处理示例DataFrame B
df_b = pd.DataFrame({
    'Patient Key': ['A123','A123','A321','A213','A321'],
    'Destination Hospital': ['C','C','B','C','B'],
    'Destination Admit Datetime': ['1-1-23 03:00:00','2-5-23 10:00:00','3-2-32 11:45:00','2-3-23 13:59:00','3-5-32 12:00:00']
})

# 转换时间列格式
df_a['Source Discharge Datetime'] = pd.to_datetime(df_a['Source Discharge Datetime'])
df_b['Destination Admit Datetime'] = pd.to_datetime(df_b['Destination Admit Datetime'])

2. 对右表按匹配键和时间排序

merge_asof要求右表必须按匹配键和时间列排序,这样才能高效找到匹配项:

df_b_sorted = df_b.sort_values(by=['Patient Key', 'Destination Admit Datetime'])

3. 执行带时间条件的合并

设置好匹配键、时间列、时间窗口(24小时),以及匹配方向(找出院时间之后的入院记录):

result = pd.merge_asof(
    # 左表也要按匹配键和时间排序,确保匹配逻辑正确
    df_a.sort_values(by=['Patient Key', 'Source Discharge Datetime']),
    df_b_sorted,
    left_on='Source Discharge Datetime',
    right_on='Destination Admit Datetime',
    by='Patient Key',  # 按Patient Key分组匹配
    direction='forward',  # 找左表时间之后的右表记录
    tolerance=pd.Timedelta(hours=24)  # 时间窗口限制为24小时
)

# 调整列顺序,和你想要的结果一致
result = result[['Row', 'Patient Key', 'Source Hospital', 'Source Discharge Datetime', 'Destination Hospital', 'Destination Admit Datetime']]
# 按Row排序恢复原始顺序
result = result.sort_values('Row').reset_index(drop=True)

运行这段代码后,得到的结果和你预期的完全一致:没有匹配的记录(比如Row2、Row5)对应的Destination字段会自动显示NaN(对应你说的NULL),完全符合你的需求。

为什么不用硬编码循环?

手动写循环遍历每一行的方式,在数据量小的时候可能没问题,但如果你的真实数据有几万甚至几十万条记录,速度会慢到难以接受。merge_asof是pandas底层优化的矢量操作,效率比循环高几个数量级,代码也更简洁易维护。

备选方案:常规merge+时间过滤(适合小数据)

如果你的数据量很小,也可以用常规merge先按Patient Key合并,再过滤时间条件,但这种方法会产生笛卡尔积,数据量大时不推荐:

# 先按Patient Key左连接
temp = pd.merge(df_a, df_b, on='Patient Key', how='left')
# 计算时间差并筛选符合条件的记录
temp['time_diff'] = temp['Destination Admit Datetime'] - temp['Source Discharge Datetime']
valid_matches = temp[(temp['time_diff'] >= pd.Timedelta(0)) & (temp['time_diff'] <= pd.Timedelta(hours=24))]
# 合并回原始df_a,保留所有行
result = df_a.merge(valid_matches.drop_duplicates(subset=['Row']), how='left', on=['Row', 'Patient Key', 'Source Hospital', 'Source Discharge Datetime'])
result = result[['Row', 'Patient Key', 'Source Hospital', 'Source Discharge Datetime', 'Destination Hospital', 'Destination Admit Datetime']]

最后统计"流失"患者比例

得到结果后,统计NULL(NaN)的比例非常简单:

leakage_rate = result['Destination Hospital'].isna().mean() * 100
print(f"患者流失比例:{leakage_rate:.2f}%")

这样就能轻松得到你想要的分析结果啦!

备注:内容来源于stack exchange,提问作者Hannah McHugh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 15:14:30