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

如何在Python/Pandas中按字符串范围筛选ICD10编码并聚合数据?

解决Pandas中ICD10编码范围筛选及聚合问题

核心问题

直接用>=/<=对ICD10字符串做范围筛选会因为字符排序逻辑(比如C97之后会匹配CA00)导致错误,这里提供几种无需复杂解析器的简便方案,同时结合性别、年龄段完成聚合。


方案1:拆分编码前缀与数字段(通用首选)

ICD10编码规则是「字母前缀+数字编码」,拆分这两部分分别筛选,完美模拟SQL的BETWEEN效果:

  1. 提取前缀和数字部分
import pandas as pd

# 假设你的数据表是df
df['icd_prefix'] = df['ICD10'].str[0]  # 提取第一个字符作为前缀
# 提取编码中的数字部分并转为整数(适配C00、E10这类编码格式)
df['icd_num'] = df['ICD10'].str[1:].str.extract('(\d+)').astype(int).squeeze()
  1. 组合筛选条件(以C00-C97、20-29岁为例)
# ICD10范围筛选:C开头,数字00-97
icd_mask = (df['icd_prefix'] == 'C') & (df['icd_num'].between(0, 97))
# 年龄段筛选:20-29岁
age_mask = df['Age'].between(20, 29)
# 性别筛选(假设POL字段值为'男'/'女')
pol_mask = df['POL'].isin(['男', '女'])

# 合并所有筛选条件
filtered_df = df[icd_mask & age_mask & pol_mask]
  1. 按要求聚合生成报告
# 按性别、年龄段分组,统计唯一患者数
report = filtered_df.groupby(
    ['POL', pd.cut(df['Age'], bins=[20, 30], labels=['20-29'])]
)['PATIENTS_ID'].nunique().reset_index()

# 重命名列名贴合报告需求
report.columns = ['性别', '年龄段', '患者人数']

方案2:正则表达式精准匹配

针对特定ICD10范围,直接写正则表达式匹配,无需拆分字段:

比如匹配C00-C97的正则:^C(0[0-9]|[1-8][0-9]|9[0-7])$,匹配E10-E14的正则:^E1[0-4]$

# 筛选C00-C97 + 20-29岁 + 所有性别
filtered_df = df[
    df['ICD10'].str.match(r'^C(0[0-9]|[1-8][0-9]|9[0-7])$') &
    df['Age'].between(20, 29) &
    df['POL'].isin(['男', '女'])
]

# 聚合逻辑同方案1
report = filtered_df.groupby(['POL', pd.cut(df['Age'], bins=[20,30], labels=['20-29'])])['PATIENTS_ID'].nunique().reset_index()

方案3:预定义分类变量(适合固定编码集合)

如果你的ICD10范围是固定的,可以把编码转为有序分类,直接用between:

# 预定义C00-C97的所有编码(示例,可根据实际生成完整列表)
c_codes = [f'C{i:02d}' for i in range(0, 98)]
# 将ICD10转为有序分类,仅包含目标编码
df['ICD10_cat'] = pd.Categorical(df['ICD10'], categories=c_codes, ordered=True)

# 筛选C00-C97的编码
icd_mask = df['ICD10_cat'].between('C00', 'C97')
# 后续筛选、聚合同方案1

多ICD10范围批量处理

如果需要同时处理多个ICD10范围生成报告,可以用字典批量循环:

# 定义需要处理的ICD10范围:键是报告中的范围名称,值是(前缀, 起始数字, 结束数字)
icd_ranges = {
    '恶性肿瘤(C00-C97)': ('C', 0, 97),
    '糖尿病(E10-E14)': ('E', 10, 14)
}

final_report = []
for range_name, (prefix, start_num, end_num) in icd_ranges.items():
    # 生成当前范围的筛选条件
    mask = (df['ICD10'].str[0] == prefix) & (df['ICD10'].str[1:].str.extract('(\d+)').astype(int).squeeze().between(start_num, end_num))
    filtered = df[mask & df['Age'].between(20,29) & df['POL'].isin(['男','女'])]
    # 聚合
    agg_result = filtered.groupby(['POL', pd.cut(filtered['Age'], bins=[20,30], labels=['20-29'])])['PATIENTS_ID'].nunique().reset_index()
    agg_result['ICD10范围'] = range_name
    final_report.append(agg_result)

# 合并所有结果
final_report = pd.concat(final_report, ignore_index=True)
final_report.columns = ['性别', '年龄段', '患者人数', 'ICD10范围']

内容的提问来源于stack exchange,提问作者Imdelok

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 19:00:07