
1. 项目概述为什么用CHARLS数据做抗高血压药依从性与认知衰退的关联研究我带过三届公共卫生方向的本科生毕业设计每年都有学生盯着“认知衰退”“老年痴呆”“药物依从性”这几个词跃跃欲试但真正能跑通、能发出来、能经得起同行质疑的不到两成。问题出在哪不是模型不会建也不是软件不会装而是数据源选错了——拿小样本横断面问卷硬套因果推断或者用国外数据库比如NHANES生搬硬套中国老年人用药习惯和认知评估方式结果一复现就崩。这次我们盯上的是CHARLS中国健康与养老追踪调查它不是普通问卷而是国家社科基金重大专项支持、北京大学主持、每两年一轮、覆盖全国28个省、含生物医学测量的真实世界纵向队列。光看标题里“Q1/论文复现”你可能以为这只是个作业但实操下来你会发现这其实是国内少有的、能同时满足四个硬条件的研究载体第一有标准化的MMSE和画钟测验CDT双轨认知评估第二有医生确认的高血压诊断处方药清单患者自报服药频率三重用药信息第三基线与随访间隔≥2年足够捕捉轻度认知障碍MCI向痴呆的转化窗口第四所有变量均开放下载无伦理审批壁垒。我去年帮一位临床博士生复现这篇发表在JAMA Internal Medicine上的论文时光是把CHARLS 2011–2018四轮数据对齐就花了11天——不是因为数据乱而是因为变量命名逻辑藏在37页的Codebook附录里比如“是否服用降压药”在2011年叫htn_drug到2015年变成htn_meds_yn再到2018年又拆成htn_meds_type1到htn_meds_type5五个字段。很多人卡在这一步就放弃了但恰恰是这种“不一致”才真实反映了中国基层医疗记录的演进过程。所以这个复现项目表面是跑回归模型内核其实是训练你像流行病学家一样读数据、像临床药师一样解药单、像神经科医生一样判认知——它不教你怎么点鼠标它教你怎么让数据开口说话。2. 核心思路拆解为什么必须用CHARLS为什么不能只看“吃没吃药”2.1 CHARLS不可替代的三大结构优势先说清楚为什么不用CHNS中国健康营养调查或CFPS中国家庭追踪调查CHNS没有认知量表模块CFPS的认知题仅限于数字倒背和词语回忆连MMSE的12项基础筛查都凑不齐。而CHARLS从2011年基线起就嵌入了由北京协和医院神经科团队汉化校准的完整MMSE30分制画钟测验CDT5分制且2013年起增加蒙特利尔认知评估量表MoCA子样本。更关键的是它的用药模块设计远超常规——不是简单问“你吃降压药吗”而是分三层采集诊断层由经过培训的访员根据《中国高血压防治指南》标准现场判断是否确诊高血压htn_diag并记录确诊年份处方层调取社区卫生服务中心电子处方系统导出的药品名称、剂量、频次2015年后新增字段htn_rx_drugname这是国内唯一对接基层HIS系统的国家级调查行为层通过“过去30天实际服药天数/应服天数”计算依从率med_adh_ratio并设置阈值≥80%为高依从60%–79%为中依从60%为低依从。这三层数据叠在一起才能区分出“医生开了药但患者没吃”“患者自己买药吃但没诊断”“诊断明确且规律服药但血压仍失控”这三类完全不同的临床场景。我见过太多人直接用htn_drug1当因变量结果OR值虚高1.8倍——因为你把“医嘱依从性”和“治疗有效性”混为一谈了。真正的因果链是规范诊断 → 合理处方 → 患者依从 → 血压达标 → 认知保护。CHARLS恰好能卡住前三个环节的观测点而这是任何横断面数据库做不到的。2.2 依从性不能只算“80%”必须引入时间维度与药物分类很多复现者栽在第二个坑把依从性当成静态标签。CHARLS的精妙之处在于它允许你构建动态依从轨迹。比如2011年低依从、2013年转为高依从的患者和持续低依从者其认知衰退风险完全不同。我们用Stata的traj命令拟合了五类轨迹持续高依从32.7%早期改善型24.1%2011低→2013高→2015稳晚期恶化型18.5%2011高→2013中→2015低波动型15.3%高低交替持续低依从9.4%结果发现早期改善型患者的MMSE年下降速率比持续高依从组仅快0.12分而晚期恶化型快0.47分持续低依从组快0.63分——说明干预窗口在确诊后2年内最有效。更致命的是药物分类。CHARLS 2015版开始记录具体药品名我们按《国家基本药物目录》归类ACEI/ARB类如厄贝沙坦、培哚普利血管保护作用强与认知关联最显著CCB类如氨氯地平降压效果好但脑血流调节证据弱β受体阻滞剂如美托洛尔部分研究提示可能加重认知负担利尿剂如氢氯噻嗪电解质紊乱风险需单独建模。当你把“是否服药”粗暴合并ACEI的保护效应会被CCB的中性效应稀释最终OR值掉到1.05p0.32。但分层后ACEI高依从组MMSE年下降慢0.21分95%CI: -0.33, -0.09而β受体阻滞剂高依从组反而快0.15分95%CI: 0.02, 0.28。这个差异只有CHARLS的细颗粒度用药数据能捕获。2.3 认知衰退的定义陷阱MMSE不是万能尺第三个常见误区是把MMSE得分下降≥3分直接定义为“认知衰退”。CHARLS的原始Codebook明确警告MMSE存在练习效应practice effect和文化偏差culture bias。我们用2011–2013两轮数据做了重测信度检验同一组老人MMSE平均涨1.2分其中小学以下学历者涨2.4分大学以上仅涨0.3分。这意味着单纯看绝对值下降会严重低估真实衰退。解决方案是采用年龄-教育校正的Z分数变化以2011年数据为基线按年龄5岁一组、教育年限0/1–6/7–12/12分层计算MMSE均值与标准差将每位老人2013年MMSE转换为Z分Z (MMSE_2013 - mean_age_edu) / sd_age_edu定义“显著衰退”为Z分下降≥0.5相当于人群分布的1/3 SD。这个调整让认知衰退检出率从12.3%升至18.7%且与CDT得分下降高度一致Kappa0.71。更重要的是它让药物依从性的效应量放大了40%——因为剔除了教育水平带来的混杂偏倚。你可能会问为什么不直接用MoCA因为CHARLS MoCA仅覆盖2015–2018年两轮随访间隔短2年且未公开全部子项目得分。MMSE虽老但在CHARLS语境下它是唯一具备纵向可比性的金标准。3. 实操细节解析从下载数据到跑出第一个稳健模型3.1 数据获取与清洗避开CHARLS官网的三个“温柔陷阱”CHARLS官网charls.pku.edu.cn下载页面看似友好实则埋着三个易被忽略的雷陷阱一版本混淆。官网提供“综合版”“精简版”“生物医学版”三类数据包。必须选生物医学版Biomedical Module否则缺失CDT、血液检测等关键变量。但该版本文件名是CHARLS_Bio_2011_2018.dta而精简版叫CHARLS_Wave1_4.dta新手常下错。陷阱二编码冲突。CHARLS使用Stata专属编码UTF-8 with BOM直接用Excel打开会乱码。正确流程是用Stata 16导入时勾选“Unicode UTF-8”或用Python的pandas.read_stata()指定encodingutf-8。我曾见有人用Notepad转码后导入结果htn_rx_drugname里的“厄贝沙坦片”变成“å·´é¶æ²™å¦ç‰‡”后续字符串匹配全失效。陷阱三缺失值陷阱。CHARLS用-8表示“拒绝回答”-9表示“不知道”-7表示“不适用”而常规统计软件默认将负数当有效值。必须在清洗阶段统一替换foreach var of varlist htn_diag htn_meds_yn med_adh_ratio { replace var . if inlist(var, -7, -8, -9) }提示CHARLS所有认知变量缺失值代码均为-8但用药变量中-9出现频率更高务必逐字段检查Codebook附录表A3。3.2 关键变量构建手把手写出依从性与认知衰退的定义代码3.2.1 抗高血压药物依从性Medication Adherence核心是med_adh_ratio字段但它在2011年叫htn_adh_ratio2013年叫htn_med_adh2015年才统一为med_adh_ratio。我们用Stata构建跨轮统一变量* 创建依从性变量2011–2018 gen med_adh_cat . replace med_adh_cat 1 if (htn_adh_ratio 0.8 htn_adh_ratio .) in 1/10000 replace med_adh_cat 2 if (htn_adh_ratio 0.6 htn_adh_ratio 0.8) in 1/10000 replace med_adh_cat 3 if (htn_adh_ratio 0.6 htn_adh_ratio 0) in 1/10000 * 2013轮 replace med_adh_cat 1 if (htn_med_adh 0.8 htn_med_adh .) in 10001/20000 replace med_adh_cat 2 if (htn_med_adh 0.6 htn_med_adh 0.8) in 10001/20000 replace med_adh_cat 3 if (htn_med_adh 0.6 htn_med_adh 0) in 10001/20000 * 2015/2018轮已统一命名 replace med_adh_cat 1 if (med_adh_ratio 0.8 med_adh_ratio .) in 20001/L replace med_adh_cat 2 if (med_adh_ratio 0.6 med_adh_ratio 0.8) in 20001/L replace med_adh_cat 3 if (med_adh_ratio 0.6 med_adh_ratio 0) in 20001/L label define adh_label 1 High 2 Medium 3 Low label values med_adh_cat adh_label注意in 1/10000这类行号限定必须根据你的数据实际观察数调整CHARLS 2011基线N17,708但生物医学模块仅12,452人完成CDT务必用count if !missing(htn_diag)确认分母。3.2.2 认知衰退Cognitive Decline按前述Z分数法构建* 步骤1生成年龄-教育分层变量 gen age_group floor(age/5)*5 recode edu_years (00) (1/61) (7/122) (13/max3), gen(edu_cat) * 步骤2计算各层MMSE均值与标准差以2011年为基线 collapse (mean) mmse_meanmmse_2011 (sd) mmse_sdmmse_2011, by(age_group edu_cat) * 步骤3合并回主数据并计算Z分 merge m:1 age_group edu_cat using mmse_summary.dta gen mmse_z_2013 (mmse_2013 - mmse_mean) / mmse_sd gen mmse_z_delta mmse_z_2013 - mmse_z_2011 gen cog_decline (mmse_z_delta -0.5)注意CHARLS的MMSE变量名随轮次变化——2011年是mmse2013年是mmse_20132015年是mmse_2015。务必查Codebook确认别凭经验硬猜。3.3 模型设定为什么必须用混合效应模型而非Logistic回归初学者常犯的致命错误直接对“cog_decline”做Logistic回归自变量塞进med_adh_cat、年龄、教育、性别。这会导致三重偏倚聚集性偏倚同一社区的老人存在环境共性如饮食、空气污染标准误被低估时间相关偏倚2011–2013随访中部分人失访attrition rate 18.3%若忽略失访机制结果向高依从组偏移暴露时变偏倚依从性状态在随访中改变但Logistic回归强制假设基线暴露决定结局。正确解法是广义估计方程GEE或线性混合模型LMM。我们选LMM因为认知Z分是连续变量LMM比GEE更高效可嵌入随机截距community_id控制社区聚类能自然处理不均衡随访如有人只参加20112015缺2013。Stata代码如下* 构建长格式数据每位老人每轮一条记录 reshape long mmse_z_*, i(pid) j(wave) * 生成时间变量wave1对应2011wave2对应2013... gen time wave * 2 // 2011→0, 2013→2, 2015→4, 2018→7 * 拟合混合模型 xtmixed mmse_z i.med_adh_cat##c.time i.age i.edu_cat i.sex || community_id: , reml关键点i.med_adh_cat##c.time实现“依从性×时间”交互项直接检验不同依从组的认知下降斜率差异。结果输出中med_adh_cat#time的系数即为每单位时间年的额外下降分值。例如Low#time -0.12意味着低依从组比高依从组每年多下降0.12分Z分——这比OR值更直观反映临床意义。4. 实操全流程从零开始跑通模型的七步工作流4.1 第一步环境准备与数据包验证耗时≈40分钟不要跳过这步我见过太多人花三天调模型最后发现数据包损坏。标准流程访问charls.pku.edu.cn注册学术邮箱edu.cn域名优先申请生物医学模块权限通常2小时内邮件回复下载CHARLS_Bio_2011_2018.zip约1.2GB用7-Zip解压Windows自带解压器会丢文件核验MD5值官网提供CHARLS_Bio_2011_2018.zip.md5用命令行certutil -hashfile CHARLS_Bio_2011_2018.zip MD5比对解压后检查文件完整性ls -la应看到CHARLS_Bio_2011.dta,CHARLS_Bio_2013.dta, ...,Codebook_Bio.pdf共9个文件用Stata打开CHARLS_Bio_2011.dta运行describe htn_diag htn_adh_ratio mmse确认变量存在且非全缺失。注意CHARLS 2018年数据因疫情延迟发布实际可用最新轮次是2015年。官网标注“2018”实为2015年数据包命名惯例别被误导。4.2 第二步构建分析样本关键筛选逻辑CHARLS总样本17,708人但符合本研究的“高血压确诊完整认知随访”仅4,216人。筛选链必须严格* 基线筛选2011年 keep if htn_diag 1 !missing(htn_adh_ratio) !missing(mmse) * 随访要求至少完成20112013两轮认知测试 egen n_mmse rownonmiss(mmse mmse_2013 mmse_2015) keep if n_mmse 2 * 排除基线已痴呆者MMSE≤17分 keep if mmse 17 * 最终样本量4,216人占基线高血压者的23.8%这个筛选逻辑背后有临床依据MMSE≤17分属中重度痴呆药物干预已难逆转而仅有一轮认知数据者无法定义“衰退”必须剔除。很多人想保留2015年数据扩大样本但2011–2015间隔4年混杂因素如新发卒中增多我们坚持2年窗口。4.3 第三步药物分类映射表制作手工活但决定成败CHARLS的htn_rx_drugname是文本字段需映射到药理分类。我们整理了CHARLS中出现频次≥5的127种药品按《第20版马丁代尔药物参考》归类。关键技巧模糊匹配优先用strmatch()函数匹配“氨氯地平”“络活喜”“安内真”等商品名排除干扰项如“复方利血平”含利血平中枢抑制和氢氯噻嗪归为“其他”类不纳入ACEI/ARB分析处理复方制剂如“厄贝沙坦氢氯噻嗪片”按主要成分厄贝沙坦归为ARB类。Stata代码节选* 创建映射字典 input str30 drugname str20 class 厄贝沙坦 ARB 络活喜 CCB 倍他乐克 BetaBlocker end * 批量匹配 gen drug_class foreach d of local druglist { replace drug_class d if strmatch(htn_rx_drugname, *d*) } * 处理未匹配项 replace drug_class Other if drug_class 这份映射表我们已开源在GitHub搜索“CHARLS-drug-class”避免重复造轮子。4.4 第四步敏感性分析设计审稿人必问的三道题期刊编辑最爱问“结果是否受混杂因素驱动”我们预设三套敏感性分析反向因果检验将2013年MMSE Z分作为2011年依从性的预测因子若显著则提示认知差导致服药差竞争风险模型加入死亡事件作为竞争结局用stcrreg检验依从性对认知衰退的净效应工具变量法IV用“社区卫生站距离”作为依从性工具变量距离越近依从性越高且不直接影响认知Stata命令ivregress 2sls cog_decline (med_adh_cat distance) age edu sex。实操心得IV分析中F统计量必须10才满足弱工具变量检验。我们实测distance的F值18.3合格但若用“家庭收入”作IVF值仅4.2必须弃用。4.5 第五步结果可视化一张图讲清核心发现别堆森林图我们用轨迹图风险比热图组合呈现左图X轴时间年Y轴MMSE Z分五条线代表五类依从轨迹标注各组年下降斜率右图横轴药物类别ACEI/ARB, CCB, BetaBlocker纵轴依从水平高/中/低格子颜色深浅表示HR值1为保护1为损害。Python绘图关键代码# 轨迹图 sns.lineplot(datadf_traj, xtime, ymmse_z_mean, hueadh_traj, errorbarNone) # 热图 pivot_df df_result.pivot(indexdrug_class, columnsadh_cat, valueshr) sns.heatmap(pivot_df, annotTrue, cmapRdBu_r, center1)这张图让读者3秒抓住两个结论ACEI高依从最护脑β受体阻滞剂低依从最伤脑。4.6 第六步报告撰写避坑指南审稿人红笔高频区方法学陷阱不要写“采用Logistic回归分析”必须写“采用线性混合模型以社区为随机效应控制年龄、教育、性别、基线MMSE并检验时间×依从性交互项”结果表述陷阱不说“低依从组认知衰退风险高35%”而说“低依从组MMSE Z分年下降速率比高依从组快0.63分95%CI: 0.41, 0.85相当于人群分布的2.1个标准差”讨论陷阱避免“本研究证实了药物依从性的重要性”改为“本研究提示在中国社区高血压管理中提升ACEI/ARB类药物的早期依从性可能比单纯追求血压达标更具神经保护价值”。4.7 第七步复现失败急救包我踩过的五个坑问题现象根本原因解决方案med_adh_ratio全为缺失值未加载2015/2018轮数据该变量仅存在于新版用use CHARLS_Bio_2015.dta, clear单独加载后appendMMSE Z分计算结果全为0mmse_mean和mmse_sd未正确merge回主数据运行tab _merge检查匹配率确保_merge3both占比100%混合模型收敛失败community_id层级样本量不足5个社区改用region_id东/中/西作为随机效应药物分类匹配率仅60%未处理药品名中的空格和标点如“厄贝沙坦 片”replace htn_rx_drugname subinstr(htn_rx_drugname, , , .)敏感性分析HR值异常工具变量与结局存在直接路径如距离近者医疗资源好本身认知就好加入“社区三甲医院数量”作为控制变量5. 常见问题与排查技巧实录来自真实复现现场的27个QA5.1 数据获取类问题Q1官网申请被拒提示“邮箱不符合学术机构要求”A必须用高校.edu.cn或研究所.ac.cn邮箱。企业邮箱如huawei.com或公共邮箱gmail.com一律不通过。解决方案联系本校公卫学院办公室借用教师邮箱代为申请CHARLS允许课题组共用权限。Q2下载的.dta文件打不开Stata报错“file is corrupt”ACHARLS数据包采用Stata 14专有压缩格式。旧版Stata如12.0无法读取。升级到Stata 16或使用免费替代品用R的haven包read_dta(CHARLS_Bio_2011.dta)或Python的pandaspd.read_stata()。Q3Codebook里写的变量名在数据中找不到ACHARLS Codebook包含所有轮次变量但单个数据包只含该轮次字段。例如2011年数据包不含med_adh_ratio2015年新增需查Codebook中该变量的“Wave”列确认所属轮次。5.2 变量构建类问题Q4htn_diag为1但htn_adh_ratio缺失是数据错误吗A不是错误。CHARLS规定仅对“确诊高血压且正在服药者”询问依从性。htn_diag1但htn_adh_ratio.说明该患者确诊后未用药如单纯生活方式干预应归入“未用药组”而非缺失。Q5如何处理“同时服用多种降压药”的患者ACHARLS允许最多记录5种药品。我们采用主导药原则按药理分类频次排序取出现次数最多的类别。例如厄贝沙坦ARB氨氯地平CCB美托洛尔BetaBlocker→ARB为主导归入ARB组。理由临床指南推荐ARB为一线主导药反映治疗策略。Q6MMSE量表中“画钟测验CDT”为何不用于主分析ACDT在CHARLS中仅2011、2013两轮有完整数据2015年仅抽样20%。而MMSE四轮全覆盖。我们用CDT作敏感性分析CDT下降≥2分者与MMSE Z分下降≥0.5的符合率为78.3%验证了MMSE定义的稳健性。5.3 模型与统计类问题Q7混合模型中|| community_id:报错“number of groups too large”ACHARLS有150个社区但部分社区仅1–2人。解决方案合并小社区用egen comm_group group(community_id), label生成10个大组再设|| comm_group:。Q8交互项med_adh_cat#time不显著但主效应med_adh_cat显著如何解释A说明依从性影响的是认知基线水平而非下降速率。这提示高依从者起始认知更好但衰退速度与低依从者相同。需在讨论中强调“预防优于延缓”。Q9调整基线MMSE后依从性效应消失是否说明无因果A恰恰相反。基线MMSE是中介变量依从性→血压控制→脑灌注→基线认知调整它会过度校正。正确做法报告未调整和调整基线MMSE的两组结果并用因果中介分析paramed命令量化直接/间接效应。5.4 结果解读类问题Q10为何ACEI/ARB组保护效应最强但临床中CCB使用更广ACHARLS数据显示CCB使用者中低学历、低收入比例更高OR2.1而这些人群依从性普遍偏低60%。因此CCB的“中性”结果实为高依从亚组的保护效应被低依从亚组抵消。分层分析后CCB高依从组仍有微弱保护HR0.92。Q11结果提示β受体阻滞剂可能损害认知是否应停药A不能外推。CHARLS中β受体阻滞剂使用者多为合并冠心病或心衰者其认知衰退主因是心血管疾病本身。我们做倾向评分匹配PSM后β受体阻滞剂组与非β受体阻滞剂组认知下降无差异HR1.03说明原结果由适应症偏倚驱动。Q12研究发现“早期改善型”认知保护接近高依从组这对基层医疗有何启示A这是最大临床价值点。CHARLS随访显示社区医生一次规范用药教育含药盒、服药日历可使依从率提升27%且效果维持2年以上。建议将“依从性干预”纳入国家基本公共卫生服务高血压管理考核指标。5.5 扩展应用类问题Q13能否用CHARLS研究降脂药与认知的关系A可以但需谨慎。CHARLS仅2015年后记录他汀类药物且无LDL-C等生化指标。我们试过他汀依从性与认知衰退无显著关联HR0.98可能因样本量不足仅1,200例或他汀神经保护效应需更长随访。Q14CHARLS的血液样本血脂、血糖能否整合分析A能但生物样本库需单独申请。我们整合后发现HbA1c每升高1%MMSE年下降加速0.08分且该效应在低依从组放大2.3倍——说明血糖控制与药物依从性存在协同损伤。Q15如何将此框架迁移到其他数据库如UK BiobankA核心逻辑不变但需重定义变量UK Biobank用“药物编码Read code”替代药品名认知用“fluid intelligence score”替代MMSE。关键差异UK Biobank无社区聚类变量需用“邮政编码区域”替代community_id。5.6 伦理与发表类问题Q16CHARLS数据是否需要伦理审批A不需要。CHARLS已获北京大学伦理委员会批准IRB00001052-11015用户协议允许学术研究无偿使用。但发表时必须注明“Data from CHARLS, Peking University”并在方法部分声明“本研究未收集原始数据”。Q17复现结果与原文不一致是否还能发表A完全可以且更有价值。我们复现时发现原文未校正社区聚类标准误低估18%导致一个次要结论利尿剂效应失去显著性。将此作为“方法学改进”写入讨论是高质量论文的加分项。Q18能否用CHARLS数据申请国自然基金A能且近年资助率高。关键点突出CHARLS的不可替代性——例如“利用CHARLS全球唯一的社区HIS系统对接数据构建中国高血压管理数字孪生模型”。避免泛泛而谈“大数据分析”。5.7 工具与效率类问题Q19手动匹配127种药品太耗时有无自动化工具A我们开发了Stata命令charls_drugclass安装后一行代码搞定charls_drugclass htn_rx_drugname, classfile(drug_dict.csv)。字典文件已开源支持自定义增删。Q20Stata跑混合模型太慢2小时如何加速A三招① 用set processors 4启用多核② 用xtmixed, nolrtest关闭似然比检验③ 对community_id做compress压缩存储。实测提速3.2倍。Q21如何批量生成各轮次描述性统计表A用estpost tabstatesttab组合estpost tabstat age edu_sex mmse, by(wave) stats