公共数据库 / 流行病学分析

NHANES 数据库怎么用:从数据下载到加权 Cox 回归与 RCS 曲线

常见的 NHANES 教程讲到下载和合并数据就结束了。本页用 1999–2018 年十个周期的官方原始数据,完整做一遍 TyG 指数与死亡风险的分析:下载、链接死亡数据、合并权重、加权 Cox 回归、RCS 曲线、亚组和敏感性分析。所有数字来自同一次真实运行。

本页数据来自 Scientify 的一次完整运行:下载 100 个官方文件并完成全部分析,约 1.5 小时,经独立审阅通过。 查看运行记录

直接答案

NHANES 是美国 CDC 下属 NCHS 每两年发布一次的全国健康与营养调查,数据免费公开,官网入口为 wwwn.cdc.gov/nchs/nhanes。用它做死亡结局研究分五步:下载各周期 XPT 文件并按 SEQN 合并;链接 NCHS 公共死亡文件;按变量所属子样本选权重并做多周期合并;用 survey 包拟合加权 Cox 回归和 RCS;最后做亚组与敏感性分析。本例纳入 22,894 人,全因死亡 3,686 例。

本页说明

教程
这页解决什么
你想用 NHANES 写一篇关联研究,但不清楚文件在哪里下载、权重怎么选、死亡数据怎么链接、Cox 和 RCS 怎么做才算正确。
适合谁
做公共数据库挖掘的医学研究生和临床医生。需要会用 R,了解 Cox 回归的基本概念。
读完你会得到
读完会得到一套完整的 NHANES 死亡结局分析流程、每一步应该得到的结果,以及一份可对照的真实结果。
覆盖
  • NHANES 官方文件的下载路径与变量查找
  • NCHS 公共死亡链接文件的定宽格式解析与心血管死亡定义
  • 空腹子样本权重的选择与多周期合并系数
  • TyG 指数公式与单位换算
  • survey 包加权 Cox 回归、RCS 曲线、加权 KM 曲线
  • 亚组交互作用、比例风险检验和敏感性分析的做法与真实结果
不覆盖
  • 饮食数据(24 小时膳食回顾)的两日权重
  • 孟德尔随机化等因果推断方法
  • 论文引言和讨论的写法

主线:一步步做完

第 1 步

为什么做这一步NHANES 每个周期的每个模块是一个单独的 XPT 文件,要先确定需要哪些文件。

NHANES 官网入口是 wwwn.cdc.gov/nchs/nhanes。数据按周期发布,1999 年起每两年一个周期,每个周期分人口学、膳食、体格检查、实验室和问卷五类模块,每个模块下是若干个 XPT 文件。在官网选周期、再选模块,就能看到文件列表和变量说明(Doc File)。

NHANES 由美国 CDC 下属的 NCHS 组织,1999 年起每两年一个周期,数据免费公开。每个周期的文件名用字母后缀区分:1999–2000 无后缀,2001–2002 为 _B,依次到 2017–2018 为 _J。所有文件通过受试者编号 SEQN 合并。

本例从十个周期共下载 100 个官方文件。CDC 已调整下载地址,旧路径 /Nchs/Nhanes/2017-2018/DEMO_J.XPT 会返回 404 网页,需要使用新路径。下载后检查文件开头,确认拿到的是 XPT 数据,不是 HTML 错误页。

当前有效的下载地址格式text
https://wwwn.cdc.gov/Nchs/Data/Nhanes/Public/2017/DataFiles/DEMO_J.xpt
# 年份写周期的第一年,文件名带周期后缀
R 读取 XPTr
library(haven)
demo <- read_xpt("DEMO_J.xpt")
glu  <- read_xpt("GLU_J.xpt")
trig <- read_xpt("TRIGLY_J.xpt")
d <- Reduce(function(x, y) merge(x, y, by = "SEQN", all.x = TRUE), list(demo, glu, trig))
周期人口学空腹血糖甘油三酯
1999–2000DEMOLAB10AMLAB13AM
2001–2002DEMO_BL10AM_BL13AM_B
2003–2004DEMO_CL10AM_CL13AM_C
2005–2006DEMO_DGLU_DTRIGLY_D
2007–2018DEMO_E … DEMO_JGLU_E … GLU_JTRIGLY_E … TRIGLY_J
前三个周期的实验室文件名与后面不同,变量名统一为 LBXGLU(血糖,mg/dL)和 LBXTR(甘油三酯,mg/dL)。逐周期核对变量名,不要凭文件名猜。

第 2 步

为什么做这一步死亡结局来自 NCHS 把 NHANES 与国家死亡索引(NDI)链接后发布的公共文件。

本例使用 2019 年公共版链接死亡文件,每个周期一个 .dat 文件。文件是定宽格式,需要按 NCHS 官方提供的读取程序指定列位置,不能当作 CSV 读取。

心血管死亡定义为 UCOD_LEADING 等于 001(心脏病)或 005(脑血管病)。随访时间用 PERMTH_EXM(从体检到死亡或随访截止的月数)。读完后检查死因代码频数和随访时间范围。

下载地址text
https://ftp.cdc.gov/pub/Health_Statistics/NCHS/datalinkage/linked_mortality/NHANES_2017_2018_MORT_2019_PUBLIC.dat
变量列位置含义
SEQN1–6受试者编号
ELIGSTAT15是否符合链接资格,1 为符合
MORTSTAT16死亡状态,1 为死亡
UCOD_LEADING17–19主要死因分类
PERMTH_INT43–45从访谈起的随访月数
PERMTH_EXM46–48从体检起的随访月数
Python 切片为左闭右开,SEQN 对应 line[0:6]。

第 3 步

为什么做这一步NHANES 是复杂抽样调查,不加权得到的是样本结果,不能代表美国人群。

选权重的规则是:分析用到的变量中,来自最小子样本的那个决定权重。空腹血糖和甘油三酯只在上午空腹子样本中测量,因此 TyG 研究要用空腹子样本权重(WTSAF2YR,1999–2002 为 WTSAF4YR),不能用体检权重 WTMEC2YR。

多周期合并时,每个周期的权重乘以“该周期年数 / 总年数”。本例合并 20 年:1999–2002 的四年权重乘以 4/20,2003 年起每个两年权重乘以 2/20。设计变量为 SDMVPSU(PSU)和 SDMVSTRA(层),二者在 DEMO 文件中。

建立复杂抽样设计(示例代码)r
library(survey)
d$wt20 <- ifelse(d$cycle %in% c("1999-2000", "2001-2002"),
                 d$WTSAF4YR * 4 / 20,
                 d$WTSAF2YR * 2 / 20)
options(survey.lonely.psu = "adjust")
des <- svydesign(ids = ~SDMVPSU, strata = ~SDMVSTRA,
                 weights = ~wt20, nest = TRUE, data = d)
# 先建全样本设计,再用 subset() 取分析人群,不要先删行再建设计
des_a <- subset(des, analysis_flag == 1)

第 4 步

为什么做这一步确定暴露变量的计算方法和最终分析人群。

NHANES 的 LBXTR 和 LBXGLU 已经是 mg/dL,直接代入,不要再换算一次。纳入标准为年龄 ≥20 岁、未妊娠、空腹血糖和甘油三酯均为正值、空腹权重大于 0、符合死亡链接资格且体检后随访时间大于 0。

TyG 指数text
TyG = ln[ TG (mg/dL) × FPG (mg/dL) / 2 ]

# 单位为 mmol/L 时先换算:TG × 88.57,葡萄糖 × 18.018
NHANES 1999–2018 纳入排除流程图,从 101,316 人到 22,894 人
纳入排除流程图。缺少空腹实验室值是最大的排除原因(30,601 人),最终纳入 22,894 人。

第 5 步

为什么做这一步估计 TyG 每升高 1 个单位,死亡风险变化多少。

完全调整后,TyG 的线性 HR 置信区间跨过 1。线性项不显著不等于没有关联,下一步用 RCS 检查是否存在非线性关系。95% 置信区间跨过 1 时,不应宣称存在统计学关联。

加权 Cox 回归(模型 3,示例代码)r
fit <- svycoxph(Surv(PERMTH_EXM, MORTSTAT) ~ tyg + age + sex + race +
                  edu + pir + smoke + bmi + diabetes + hypertension +
                  cvd + cancer, design = des_a)
summary(fit)
结局模型 3:每 1 单位 TyG 的 HR (95% CI)
全因死亡1.03 (0.95–1.12)
心血管死亡1.10 (0.93–1.29)
模型 1 未调整;模型 2 调整年龄、性别、种族;模型 3 再调整教育、PIR、吸烟、BMI、糖尿病、高血压、心血管病史和癌症。TyG 同时按四分位数分析,以 Q1 为参照。

第 6 步

为什么做这一步RCS 不预先假设线性关系,用来检验暴露与结局之间是否有曲线关系。

本例在加权 Cox 模型中使用 4 个结点,取加权 TyG 分布的第 5、35、65、95 百分位(7.63、8.33、8.82、9.76),参考值为加权中位数 8.57。RCS 输出两个 P 值:总体 P 检验 TyG 与死亡是否有关联,非线性 P 检验曲线是否偏离直线。

全因死亡的总体 P = 0.0096,非线性 P = 0.0090,曲线呈 U 形,最低点约在 TyG 9.0。心血管死亡的非线性 P = 0.025。

TyG 指数与全因死亡的加权 RCS 曲线,呈 U 形,最低点约 9.0
全因死亡 RCS 曲线(完全调整)。实线为 HR,灰色为 95% CI,虚线为 HR = 1。
TyG 指数与心血管死亡的加权 RCS 曲线
心血管死亡 RCS 曲线,非线性 P = 0.025。

第 7 步

为什么做这一步Cox 模型假设 HR 不随时间变化,需要检验。KM 曲线展示各组生存情况。

直接对 svycoxph 的结果调用 cox.zph 会得到接近 1 的 P 值,这是权重尺度造成的假象,不能用。本例把随访时间切成 0–60、60–120、>120 个月三段,在加权模型中加入 TyG × 时段交互项,用设计校正的 Wald 检验:全因死亡 P = 0.034,提示违反比例风险假设,因此同时报告分时段 HR;心血管死亡 P = 0.49。

加权 KM 曲线用 survey::svykm 按 TyG 四分位数绘制,组间比较用 survey::svylogrank。图中曲线必须是加权结果,未加权曲线不能标成加权。

按 TyG 四分位数分组的全因死亡加权 Kaplan-Meier 生存曲线
按 TyG 四分位数分组的加权 KM 曲线(全因死亡)。

第 8 步

为什么做这一步检验 TyG 与死亡的关联在不同人群中是否不同。

本例预设 7 类亚组:年龄(<60 / ≥60)、性别、种族、BMI、糖尿病、高血压、心血管病史。每层报告 HR、95% CI、人数和事件数,并给出交互作用 P 值。只有年龄的交互作用显著(P < 0.001):<60 岁 HR 1.14(0.95–1.37),≥60 岁 HR 0.95(0.87–1.05)。

判断亚组差异要看交互作用 P 值,不能用“一个亚组显著、另一个不显著”代替。本例非西班牙裔黑人亚组 HR 1.24(1.04–1.48)单独显著,但种族交互作用 P = 0.378,不能说 TyG 只在该人群中有关联。亚组检验未做多重比较校正,按探索性结果解释。

TyG 与全因死亡的亚组森林图,列出 7 类亚组的 HR、人数、事件数和交互作用 P 值
全因死亡亚组森林图,每 1 单位 TyG 的调整 HR。

第 9 步

为什么做这一步换一种合理的做法后,主要结论是否仍然成立。

分析目的
排除随访前 2 年内死亡减少基线疾病导致的反向因果
排除基线心血管病和癌症减少已有疾病的影响
多重插补(m = 5,10 轮)处理协变量缺失;结局、随访时间、暴露、权重和分层变量进入插补模型,用 Rubin 规则合并
不加权 Cox对照权重对结果的影响
每项敏感性分析列出纳入人数、事件数、模型设定和 HR。

原理与判断

对照

为什么做这一步同一数据库、同一指标,不同研究的结果为什么不同。

几项研究的共同结论是:四分位数趋势检验不显著,但 RCS 显示非线性。两者不矛盾:趋势检验只检验单调变化,RCS 允许曲线弯曲。拐点位置受年龄构成和协变量影响,8.88、9.18、9.364 都不能直接当作临床切点。

研究样本主要结果
Chen 等,20241999–2018,n = 17,118全因 Q4 对 Q1 HR 0.93(0.76–1.14);RCS 图示阈值 8.88,非线性 P = 0.0071
Wang 等,20242001–2018,n = 15,388全因 Q4 HR 1.02(0.62–1.48);曲线先降后升
Sun 等,20221999–2014,≥45 岁,n = 9,254全因连续 HR 1.01(0.93–1.10);拐点 9.18
本页1999–2018,≥20 岁,n = 22,894全因连续 HR 1.03(0.95–1.12);U 形,最低点约 9.0,探索性分段点 9.364
年龄范围、周期、随访截止、协变量和样本筛选不同,阈值不能互相移植。

参考与附录

运行记录

为什么做这一步说明数据来源与运行条件。

本页数字来自 2026 年 10 月 27 日在 Scientify 上的一次长周期研究任务。用户上传任务书后确认 6 条研究要求,Scientify 自行下载 100 个官方文件、解析死亡文件、合并权重、完成全部统计分析,并发现 cox.zph 用于加权模型时的尺度假象,改用时间交互检验。

最终交付 16 页中文报告、22 张图、表格、一键复现脚本和带 SHA256 的数据清单,独立审阅通过。从开始到审阅通过约 1.5 小时,全程使用云电脑 CPU,没有租用 GPU。

Scientify 工作区中确认 NHANES 研究要求 R1 到 R6 的界面
开始前确认的 6 条研究要求。
Scientify 研究简报中列出的发现与可信度
研究简报:每条发现标注可信度和证据。

常见错误与处理

按出现频率排序。

用了 WTMEC2YR 做空腹指标的分析

原因:空腹血糖和甘油三酯只在空腹子样本中测量。

怎么解决:改用 WTSAF2YR(1999–2002 为 WTSAF4YR),多周期按年数比例合并。

下载的 XPT 文件读不出来,或文件只有几 KB

原因:CDC 调整了下载路径,旧地址返回 HTML 404 页面。

怎么解决:使用 /Nchs/Data/Nhanes/Public/<年份>/DataFiles/ 路径,下载后检查文件头。

加权结果的标准误异常小

原因:先删行再建 svydesign,破坏了抽样结构。

怎么解决:先用全样本建设计,再用 subset() 取分析人群。

死亡文件读出来列错位

原因:把定宽 .dat 文件当作分隔符文件读取。

怎么解决:按 NCHS 官方读取程序的列位置读取,SEQN 为第 1–6 列。

TyG 数值明显偏大

原因:NHANES 的 mg/dL 值又乘了一次换算系数。

怎么解决:LBXTR、LBXGLU 已是 mg/dL,直接代入公式。

cox.zph 对 svycoxph 的 P 值接近 1

原因:权重尺度导致的假象,检验无效。

怎么解决:用时间分段交互项做设计校正的 Wald 检验。

survey 报 lonely PSU 错误

原因:子集中某个层只剩一个 PSU。

怎么解决:设置 options(survey.lonely.psu = "adjust"),并在方法中写明。

参考资料

常见问题

NHANES 数据库官网是哪个?

官网入口是 wwwn.cdc.gov/nchs/nhanes,由美国 CDC 下属的 NCHS 维护。数据免费下载,不需要注册。死亡链接数据在 ftp.cdc.gov 的 NCHS linked_mortality 目录。

NHANES 数据库怎么下载?

在 CDC 的 NHANES 数据门户按周期和模块下载 XPT 文件,当前地址格式为 wwwn.cdc.gov/Nchs/Data/Nhanes/Public/<年份>/DataFiles/<文件名>.xpt。死亡数据在 NCHS 的 linked_mortality 目录单独下载。

NHANES 权重怎么选?

由分析中来自最小子样本的变量决定。只用访谈变量选 WTINT2YR,用到体检变量选 WTMEC2YR,用到空腹实验室变量选 WTSAF2YR。多周期合并时按周期年数占总年数的比例调整。

TyG 指数计算公式是什么?

TyG = ln[甘油三酯(mg/dL) × 空腹血糖(mg/dL) / 2]。单位为 mmol/L 时先把甘油三酯乘以 88.57、血糖乘以 18.018。

RCS 曲线的总体 P 和非线性 P 有什么区别?

总体 P 检验暴露与结局是否有关联,非线性 P 检验关系是否偏离直线。本例全因死亡总体 P = 0.0096,非线性 P = 0.0090,说明存在非线性关联。

Cox 回归 HR 不显著,RCS 却显著,矛盾吗?

不矛盾。线性 HR 假设风险随暴露单调变化,U 形关系中两端风险都升高,线性项可能接近 1。本例 TyG 线性 HR 为 1.03(0.95–1.12),RCS 非线性 P = 0.009。

NHANES 发文章还能用 TyG 做吗?

TyG 与死亡的 NHANES 研究已有多篇发表,结论接近。新研究需要在人群、结局、暴露组合或方法上有明确差异,并在文中与已有研究对照。

把 NHANES 分析交给 Scientify

上传研究设想,Scientify 会下载官方数据、合并权重、完成加权回归和图表,并交付可复现的代码与报告。