2025年国赛高教社杯数学建模C题NIPT的时点选择与胎儿的异常判定解题全过程文档及程序

2025年国赛高教社杯数学建模

C题 NIPT的时点选择与胎儿的异常判定

原题再现

NIPT(Non-invasive Prenatal Test,即无创产前检测)是一种通过采集母体血液、检测胎儿的游离DNA片段、分析胎儿染色体是否存在异常的产前检测技术,目的是通过早期检测确定胎儿的健康状况。根据临床经验,畸型胎儿主要有唐氏综合征、爱德华氏综合征和帕陶氏综合征,这三种体征分别由胎儿21 号、18号和13号"染色体游离DNA片段的比例"(简称"染色体浓度")是否异常决定。NIPT的准确性主要由胎儿性染色体(男胎XY,女胎XX)浓度判断。通常孕妇的孕期在10周~25周之间可以检测胎儿性染色体浓度,且如果男胎的Y染色体浓度达到或高于4%、女胎的X染色体浓度没有异常,则可认为NIPT的结果是基本准确的,否则难以保证结果准确性要求。同时,实际中应尽早发现不健康的胎儿,否则会带来治疗窗口期缩短的风险,早期发现(12周以内)风险较低;中期发现(13-27周)风险高;晚期发现(28周以后)风险极高。
  实践表明,男胎Y染色体浓度与孕妇孕周数及其身体质量指数(BMI)紧密相关。通常根据孕妇的BMI 值进行分组(例如:[20,28),[28,32),[32,36),[36,40),40 以上)分别确定 NIPT 的时点(相对孕期的时间点)。由于每个孕妇的年龄、BMI、孕情等存在个体差异,对所有孕妇采用简单的经验分组和统一的检测时点进行NIPT,会对其准确性产生较大影响。因此,依据BMI对孕妇进行合理分组,确定各不同群组的最佳NIPT时点,可以减少某些孕妇因胎儿不健康而缩短治疗窗口期所带来的潜在风险。
  为了研究各类孕妇群体合适的NIPT时点,并对检测的准确性进行分析,附件给出了某地区(大多为高BMI)孕妇的NIPT数据。在实际检测中,经常会出现测序失败(比如:检测时点过早和不确定因素影响等)的情况。同时为了增加检测结果的可靠性,对某些孕妇有多次采血多次检测或一次采血多次检测的情况。试利用附件提供的数据建立数学模型研究如下问题:
  问题1 试分析胎儿Y染色体浓度与孕妇的孕周数和BMI等指标的相关特性,给出相应的关系模型,并检验其显著性。
  问题2 临床证明,男胎孕妇的BMI是影响胎儿Y染色体浓度的最早达标时间(即浓度达到或超过4%的最早时间)的主要因素。试对男胎孕妇的BMI进行合理分组,给出每组的BMI区间和最佳NIPT时点,使得孕妇可能的潜在风险最小,并分析检测误差对结果的影响。
  问题3 男胎Y染色体浓度达标时间受多种因素(身高、体重、年龄等)的影响,试综合考虑这些因素、检测误差和胎儿的Y染色体浓度达标比例(即浓度达到或超过4%的比例),根据男胎孕妇的BMI,给出合理分组以及每组的最佳NIPT时点,使得孕妇潜在风险最小,并分析检测误差对结果的影响。
  问题4 由于孕妇和女胎都不携带Y染色体,重要的是如何判定女胎是否异常。试以女胎孕妇的21号、18号和13号染色体非整倍体(AB列)为判定结果,综合考虑X染色体及上述染色体的Z值、GC含量、读段数及相关比例、BMI等因素,给出女胎异常的判定方法。

整体求解过程概述(摘要)

基于混合效应模型的 NIPT 时点优化与胎儿异常判定(优化版)
  随着分子诊断技术的飞速发展,无创产前检测(Non-invasive Prenatal Testing, NIPT)已成为当前早期筛查胎儿染色体异常的主流临床手段。其核心原理是通过采集母体外周血,检测并分析胎儿游离 DNA(cffDNA)片段,以评估胎儿染色体是否存在数目异常。然而,NIPT 结果的准确性高度依赖于胎儿游离 DNA 浓度,该浓度受孕周(GA)、身体质量指数(BMI)等因素显著影响。本文基于真实临床数据,构建了混合效应模型与孕妇潜在风险最小化优化模型相结合的分析框架,系统研究不同类别孕妇群体的最佳 NIPT 检测时点及胎儿染色体异常判定方法,旨在为降低检测失败率、减少因胎儿健康问题引发的潜在临床风险提供科学依据。
  针对问题一,为探究男胎孕妇 Y 染色体浓度(FF)与关键影响因素之间的定量关系,本文首先对附件数据进行预处理:针对字符型孕周数据,统一转换为孕天格式,以满足后续建模的连续性与计算要求。在特征相关性分析阶段,首先采用 Pearson 相关系数进行初步检验,结果显示各特征变量与 Y 染色体浓度整体呈非线性关系,仅在特定条件下存在微弱的线性相关。因此,进一步引入互信息值法,对各特征指标与 Y 染色体浓度间的非线性关联强度进行量化评估,以捕捉变量间复杂的依赖关系。分析结果表明,影响男胎 Y 染色体浓度的主要因素及其权重由大到小依次为:孕妇 BMI、检测孕天、孕妇年龄、胎儿健康状态及 IVF 妊娠方式。通过显著性检验(P 值分析)进一步验证:孕妇 BMI 与检测孕天对男胎 Y 染色体浓度具有统计学意义上的显著影响,为后续构建混合效应模型提供了明确的变量依据。在此基础上,本文对 FF 值进行 logit 变换,建立包含二次项的线性混合效应模型(LMM),并引入随机截距与斜率项,捕捉不同孕妇个体间的差异。模型结果显示:FF 值随孕周(GA)单调上升,而与 BMI 呈显著的倒 U 型关系;经似然比检验,GA 的一次项与二次项均显著,BMI 仅二次项显著,模型拟合优度达到R2=0.8962,显著优于传统广义线性模型,验证了模型的有效性。

针对问题二,本部分以男胎 Y 染色体浓度最早达标时间(FF≥4%)为核心,构建孕妇潜在风险最小化的优化模型,综合考虑检测失败风险与时间风险,为不同 BMI 水平的孕妇确定最优 NIPT 检测时点。首先,筛选男胎数据中 Y 染色体浓度达到或高于 4% 的样本,并保留同一孕妇最早检测孕天的数据,以分析 BMI 与 Y 染色体浓度达标时间的内在规律。随后采用灰色关联分析法,定量计算不同孕周下各组别孕妇的检测风险与浓度达标情况,再结合动态规划算法对 BMI 进行分段优化。分组结果表明,不同 BMI 区间对应的最优检测时点如下:

20.7, 26.8) → 11.9 周 \[26.9, 39.9) → 12.8 周 \[40.0, 42.5\] → 17.5 周 \[42.8, 46.8\] → 20.4 周 \[44.7, 46.8\] → 22.8 周   检测误差分析表明,高 BMI 群体对检测误差更为敏感,推荐时点随误差增大而推迟,但整体分组结构保持稳定。其中,当 BMI 处于 (27, 31\] 区间时,男胎 Y 染色体浓度最早达标,最佳检测时机为孕期 12 周左右;而 BMI 偏高或偏低的孕妇则需延后检测,以有效降低检测失败率与临床风险。   针对问题三,为进一步提升模型的普适性,本部分综合考虑孕妇年龄、IVF 妊娠方式、生产次数及胎儿健康状态等多因素,建立扩展的孕妇潜在风险最小化优化模型,实现多维特征下的精准分组。首先采用 K-means 聚类算法对孕妇样本进行多维划分,再结合动态规划分段与单调性控制,最终得到 5 组年龄层下各 5 组 BMI 分区及对应最优检测时点。通过 DB 指数验证模型聚类效果,结果表明多维分组方案具有良好的稳定性与区分度。分析结果显示,各因素的协同效应显著:孕妇年龄与怀孕次数的增加会使推荐检测时点提前,而生产次数增加则会导致检测时点推迟;年龄与 BMI 的交互作用在检测时机选择中具有关键影响,多维分组能有效降低不同群体的潜在检测风险,提升整体检测效率。该模型经交叉验证与灵敏度回验,结果稳健可靠。   针对问题四,由于孕妇与女胎均不携带 Y 染色体,NIPT 对女胎的染色体异常判定需依赖 X 染色体、21 号、18 号及 13 号染色体的相关指标。本部分综合考虑 Z 值、GC 含量、读段数及相关比例、孕妇 BMI 等影响因素,构建女胎染色体异常判定模型。首先,基于附件女胎检测数据,构建决策树、AdaBoost 与梯度提升三类分类模型,并通过准确率、精确率、召回率与 F1 分数指标进行对比评估,最终选择梯度提升模型作为最优模型。在此基础上,进一步引入 "男胎校准 + 协变量校正 + 经验零分布 + 多重检验校正" 的综合判定框架:通过孕周分层、Z 值标准化与 FDR 控制,输出阴性 / 可疑 / 阳性三级判定结果,并叠加 ChrX 质控门限与一致性聚合,降低批次效应的影响。在 1% 假阳性率的约束下,模型共检出 3 例阳性、26 例可疑样本,验证了该综合判定模型具有良好的稳健性与临床适用性,可有效提升女胎染色体异常判定的准确性。 ### **模型假设:**   检测过程的条件独立性与随机缺失假设   假设多次采血或技术重复之间的实验条件相互独立;同时,假设检测失败事件与胎儿的真实染色体状态相互独立,即检测失败为完全随机缺失(MCAR),而非与胎儿异常状态相关的非随机缺失,从而避免因缺失数据偏差影响时点优化与异常判定结果的准确性。   基线指标的稳定性假设   假设所有孕妇在首次检测前,均已完成孕周核对与 BMI 基线测量;后续孕期体重增长对初始 BMI 分组的跨期影响可忽略不计,即孕妇的 BMI 分组在整个 NIPT 检测窗口期内保持稳定,不随孕周动态变化,从而保证基于 BMI 分层的最优检测时点推荐具有一致性。   分组同质性与个体异质性鲁棒处理假设   假设孕妇 BMI 分组边界一经确定,组内个体共享同一 "最佳检测时点" 推荐值;个体层面的随机异质噪声(如个体代谢差异、检测平台波动等),通过模型中的鲁棒优化层(如混合效应模型的随机项、误差传播分析)进行处理,以保证推荐时点的整体有效性与临床普适性。 ### **问题分析:**   问题一分析   本问题的核心目标是识别影响男胎 Y 染色体浓度(cffDNA 浓度关键代理指标)的核心特征,并量化特征与 Y 染色体浓度的关联强度,为后续检测时点优化提供理论依据。首先需开展数据预处理工作:针对附件数据中的缺失值,采用多重插补法(Multiple Imputation)进行填补;针对异常值,结合临床医学标准(如 BMI 正常范围 18.5-24.9)与统计方法(3σ 原则)进行识别与修正;同时将字符型孕周数据转换为连续型孕天变量,确保数据满足后续分析的规范性要求。其次,考虑到特征与 Y 染色体浓度可能存在线性与非线性关联,先通过 Pearson 相关系数检验线性相关性,再引入互信息值法(Mutual Information)捕捉变量间复杂的非线性依赖关系,实现特征关联强度的全面评估。最后,基于筛选出的关键特征构建量化关系模型,并通过 P 值检验与方差分析(ANOVA)验证模型参数的统计学显著性,确保结论的可靠性。   问题二分析   结合问题一的结论,孕妇 BMI 是影响男胎 Y 染色体浓度达标时间(浓度≥4% 为临床有效阈值)的首要因素,本问题旨在通过 BMI 分层与风险最小化模型,确定不同 BMI 区间孕妇的最佳 NIPT 检测时点,并分析检测误差的影响。首先,通过绘制 BMI 分布直方图与核密度曲线,分析其整体分布特征(如是否呈正态分布、是否存在多峰聚集),结合临床实践与动态规划分段策略,制定科学合理的 BMI 分组方案。其次,考虑到 NIPT 检测系统的不确定性与样本量限制,采用灰色关联分析法(Grey Relational Analysis, GRA)------ 该方法适用于小样本、不确定系统的多因素决策,通过计算不同检测孕天与 "理想风险状态"(Y 染色体浓度达标且检测时间最早)的关联度,量化各时点的风险水平,进而确定每组的最优检测孕天。最后,通过敏感性分析模拟不同检测误差(如孕周估算误差、浓度检测误差)对最佳时点的影响,验证推荐时点的稳健性。   问题三分析   问题二仅聚焦 BMI 单因素对检测时点的影响,但临床实践中,男胎 Y 染色体浓度达标时间还受孕妇年龄、IVF 妊娠方式、胎儿健康状态等多因素协同作用,单一分层难以覆盖复杂个体差异。因此,本问题需构建多维度分组体系,进一步提升检测时点推荐的精准性。首先,选取孕妇年龄、BMI、IVF 妊娠状态、胎儿健康状态、检测孕天及 Y 染色体浓度作为核心特征,采用 K-means 聚类算法进行多维分组 ------ 通过肘部法则(Elbow Method)确定最优聚类数,结合轮廓系数(Silhouette Coefficient)验证分组的合理性与紧致性,确保同组内孕妇特征相似度高、异组间差异显著。其次,基于分组后的数据,计算各组内 Y 染色体浓度达标比例随孕周的变化趋势,以 "达标比例最高且检测时间最早" 为目标函数,确定每组的最佳 NIPT 检测时点,实现多因素协同下的风险最小化。最后,沿用敏感性分析方法,评估检测误差对多维分组下最佳时点的影响,为临床操作提供容错参考。   问题四分析   本问题的核心是构建精准、稳定的女胎染色体异常判定模型,由于女胎不携带 Y 染色体,需剔除 Y 染色体相关变量,聚焦与染色体异常直接相关的特征。首先进行特征筛选:保留 21 号、18 号、13 号染色体(常见非整倍体异常染色体)及 X 染色体的 Z 值(拷贝数变异指标)、GC 含量(基因序列特征),同时纳入读段数(检测数据质量指标)、孕妇 BMI(干扰因素)等关键特征,形成完整的特征集。其次,选取决策树、AdaBoost、梯度提升三种经典分类算法构建模型:决策树模型可直观呈现特征决策路径,AdaBoost 通过弱分类器集成提升泛化能力,梯度提升通过迭代优化降低模型偏差。通过 accuracy(准确率)、macro_precision(宏精确率)、macro_recall(宏召回率)、macro_f1(宏 F1 分数)四项指标对模型性能进行综合评估,筛选出稳定性与泛化能力最优的模型。最后,基于最优模型提取特征重要性排序,确定影响女胎异常的核心指标,结合临床诊断标准,制定科学、可操作的女胎染色体异常判定流程。 ### **模型的建立与求解整体论文缩略图** ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/fc42b28eecb94e9e8321785cf4a9ca10.png) ###### 全部论文及程序请见下方" 只会建模 QQ名片" 点击QQ名片即可 #### 部分程序代码(完整论文以及代码请联系博主): ```python # -*- coding: utf-8 -*- """ NIPT 时点优化与胎儿异常判定 问题一、问题二核心代码 """ import os import re import math import warnings from pathlib import Path import numpy as np import pandas as pd import matplotlib.pyplot as plt from scipy.special import logit from scipy.stats import norm import statsmodels.api as sm from statsmodels.regression.mixed_linear_model import MixedLM from sklearn.isotonic import IsotonicRegression warnings.filterwarnings("ignore", category=UserWarning) plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "Arial Unicode MS", "DejaVu Sans"] plt.rcParams["axes.unicode_minus"] = False # ====================== 通用工具函数 ====================== def ensure_dir(d: os.PathLike): """确保目录存在""" os.makedirs(d, exist_ok=True) def fuzzy_pick_col(columns, keywords): """在列名中模糊查找(包含关系),返回第一个匹配列名,否则 None。""" for c in columns: lc = str(c).lower() for kw in keywords: if kw in lc: return c return None def parse_ga(x): """ 将孕周字符串(如'13w+6'/'15+2'/'13w'等)解析为周的浮点数;失败返回 np.nan。 """ if x is None or (isinstance(x, float) and np.isnan(x)): return np.nan if isinstance(x, (int, float)): return float(x) s = str(x).strip().lower() s = s.replace('周', 'w').replace('天', '').replace(' ', '') # 匹配 "13w+6" / "13w-1" m = re.match(r'^\s*(\d+)\s*w\s*([+-]?\d+)?\s*$', s) if m: w = int(m.group(1)) d = int(m.group(2)) if m.group(2) else 0 return w + d / 7.0 # 匹配 "15+2" / "15-1" m = re.match(r'^\s*(\d+)\s*([+-])(\d+)\s*$', s) if m: w = int(m.group(1)) op = m.group(2) d = int(m.group(3)) return w + (d / 7.0 if op == '+' else -d / 7.0) # 匹配纯数字 m = re.search(r'(\d+)', s) if m: return float(m.group(1)) return np.nan def detect_id_column(df: pd.DataFrame): """自动检测个体ID列,无则生成假ID""" candidates = [ "ID", "Id", "id", "PID", "Pid", "pid", "孕妇代码", "孕妇ID", "个体", "个体ID", "subject", "Subject", "SUBJECT", "patient", "Patient" ] for c in candidates: if c in df.columns: return c # 无匹配则生成假ID df["_FAKE_ID_"] = np.arange(len(df)) return "_FAKE_ID_" # ====================== 数据读取与预处理 ====================== def read_data(path: str, sheet_name=None): """读取 Excel 数据并自动识别关键列(FF、GA、BMI)""" if sheet_name is None or str(sheet_name).strip() == "": xls = pd.ExcelFile(path) sheet_name = xls.sheet_names[0] df = pd.read_excel(xls, sheet_name=sheet_name) print(f"[INFO] 未指定工作表,已自动读取: {sheet_name}") else: df = pd.read_excel(path, sheet_name=sheet_name) print(f"[INFO] 已读取工作表: {sheet_name}") # 清洗列名 df.columns = [str(c).strip() for c in df.columns] # --- 识别 FF/Y染色体浓度列 --- ff_cols = ["FF", "FF%", "FF (%)", "FF(%)", "Y染色体浓度", "Y 染色体浓度", "Y浓度", "Y 浓度"] ff_col = next((c for c in ff_cols if c in df.columns), None) if ff_col is None: raise ValueError("缺少 FF 或 Y染色体浓度 列") df["FF"] = pd.to_numeric(df[ff_col], errors="coerce") # 若数值大于1,判定为百分比,转为比例 if df["FF"].dropna().gt(1.0).mean() > 0.5: df["FF"] = df["FF"] / 100.0 # --- 识别 GA/孕周列 --- ga_cols = ["GA", "检测孕周", "孕周", "孕周数", "孕周(周)"] ga_col = next((c for c in ga_cols if c in df.columns), None) if ga_col is None: raise ValueError("缺少 GA/孕周 列") df["GA"] = df[ga_col].apply(parse_ga) # --- 识别 BMI 或 身高体重 --- bmi_cols = ["BMI", "体质指数", "bmi"] bmi_col = next((c for c in bmi_cols if c in df.columns), None) if bmi_col is not None: df["BMI"] = pd.to_numeric(df[bmi_col], errors="coerce") else: if "身高" in df.columns and "体重" in df.columns: h_m = pd.to_numeric(df["身高"], errors="coerce") / 100.0 w_kg = pd.to_numeric(df["体重"], errors="coerce") df["BMI"] = w_kg / (h_m ** 2) else: raise ValueError("缺少 BMI 或 身高/体重 列") # 清洗异常值 df = df.replace([np.inf, -np.inf], np.nan).dropna(subset=["FF", "GA", "BMI"]) df = df[(df["FF"] > 0) & (df["FF"] < 1)].copy() print(f"[INFO] 有效样本量: N={len(df)}; " f"FF∈[{df.FF.min():.4f},{df.FF.max():.4f}]; " f"GA∈[{df.GA.min():.2f},{df.GA.max():.2f}]; " f"BMI∈[{df.BMI.min():.2f},{df.BMI.max():.2f}]") return df # ====================== 问题一:拟合混合效应模型 ====================== def fit_mixedlm_best(df: pd.DataFrame, id_col: str): """ 拟合最优 MixedLM 模型:logit(FF) ~ GA + GA² + BMI + BMI² + (1 + GA | id) 含随机截距与GA随机斜率 """ d = df.copy() # 中心化 d["GA_c"] = d["GA"] - d["GA"].mean() d["BMI_c"] = d["BMI"] - d["BMI"].mean() # logit 变换(裁剪避免边界问题) y = np.log(d["FF"].clip(1e-6, 1-1e-6) / (1 - d["FF"].clip(1e-6, 1-1e-6))) # 构建固定效应矩阵 X = sm.add_constant(pd.DataFrame({ "GA_c": d["GA_c"], "GA_c2": d["GA_c"] ** 2, "BMI_c": d["BMI_c"], "BMI_c2": d["BMI_c"] ** 2, })) # 随机效应:以GA为随机斜率 Z = sm.add_constant(d[["GA_c"]], has_constant='add') print("[INFO] 拟合 MixedLM(随机截距 + GA 随机斜率 + 二次项)...") model = MixedLM(endog=y, exog=X, groups=d[id_col], exog_re=Z) res = model.fit(method="lbfgs", reml=False, maxiter=1000, disp=False) print(res.summary()) return res, d def eta_fix_from_b_t(res, GA_mean, BMI_mean, t_week, b_bmi): """计算固定效应部分的 eta = logit(FF)""" b = res.fe_params ga_c = t_week - GA_mean bmi_c = b_bmi - BMI_mean return float( b["const"] + b["GA_c"] * ga_c + b["GA_c2"] * (ga_c ** 2) + b["BMI_c"] * bmi_c + b["BMI_c2"] * (bmi_c ** 2) ) def eta_sd(res, ga_c: float, mode="new"): """ 计算 logit(FF) 的标准差 - mode='typical': 仅残差方差 - mode='new': 残差 + 随机效应方差 """ v = float(res.scale) # 残差方差 if mode == "new": cov_re = np.asarray(res.cov_re) # 2x2: [const, GA_c] vec = np.array([1.0, ga_c], dtype=float) v += float(vec @ cov_re @ vec) return math.sqrt(max(v, 1e-12)) def prob_ge_threshold(res, GA_mean, BMI_mean, t_week, b_bmi, thr=0.04, mode="new"): """计算 Pr(FF >= thr)""" eta_fix, ga_c = eta_fix_from_b_t(res, GA_mean, BMI_mean, t_week, b_bmi), t_week - GA_mean sd = eta_sd(res, ga_c, mode=mode) z = (eta_fix - logit(thr)) / sd return float(norm.cdf(z)) def tstar_for_bmi(prob_fn, b_bmi, q=0.95, t_min=10.0, t_max=28.0, step=0.1): """ 给定 BMI,求满足 Pr(FF >= thr) >= q 的最早孕周 T*(b) """ grid = np.arange(t_min, t_max + 1e-9, step) probs = [prob_fn(t, b_bmi) for t in grid] idx = next((i for i, p in enumerate(probs) if p >= q), None) if idx is None: return float(t_max), False # 二分法优化 lo = max(t_min, grid[max(0, idx-2)]) hi = grid[idx] for _ in range(25): mid = 0.5 * (lo + hi) if prob_fn(mid, b_bmi) >= q: hi = mid else: lo = mid return float(hi), True # ====================== 问题二:贝叶斯单调拟合与动态规划 ====================== def bayes_monotone_curve(b_grid, T_star, method="vi", draws=1500, seed=2025): """ 用贝叶斯单调模型拟合 T*(b),若 PyMC 不可用则回退到 PAVA(保序回归) 返回: T_mean, T_lo, T_hi """ b = np.asarray(b_grid, dtype=float).ravel() y = np.asarray(T_star, dtype=float).ravel() assert len(b) == len(y) try: import pymc as pm import pytensor.tensor as pt # 兼容 softplus try: sp = pm.math.softplus except Exception: try: from pytensor.tensor.nnet import softplus as sp except Exception: sp = pm.math.log1pexp # 等距尺度(避免0步长) db = np.diff(b, prepend=b[0]) if np.any(db <= 0): uniq = np.unique(b) minstep = np.min(np.diff(uniq)) if len(uniq) > 1 else 1.0 db = np.where(db <= 0, minstep, db).astype(float) with pm.Model() as m: sigma = pm.HalfNormal("sigma", 0.3) mu0 = pm.Normal("mu0", mu=float(np.percentile(y, 10)), sigma=2.0) scale_inc = pm.HalfNormal("scale_inc", sigma=0.5) z = pm.Normal("z", mu=0.0, sigma=1.0, shape=len(b)) inc = pm.Deterministic("inc", sp(z) * scale_inc * db) # 非负增量 theta = pm.Deterministic("theta", mu0 + pt.cumsum(inc)) pm.Normal("y_obs", mu=theta, sigma=sigma, observed=y) if method.lower() == "nuts": idata = pm.sample(draws, tune=draws, chains=4, target_accept=0.9, random_seed=seed, progressbar=True) else: approx = pm.fit(10000, method="advi", callbacks=[pm.callbacks.CheckParametersConvergence(tolerance=1e-3)], random_seed=seed) idata = approx.sample(draws, random_seed=seed) theta_post = idata.posterior["theta"].stack(("chain", "draw")).values # (n, S) T_mean = theta_post.mean(axis=1) # 保守纠偏:保证不低于 T_star T_mean = np.maximum(T_mean, T_star) T_lo = np.percentile(theta_post, 2.5, axis=1) T_hi = np.percentile(theta_post, 97.5, axis=1) return T_mean, T_lo, T_hi except Exception as e: print(f"[WARN] PyMC 不可用或推断失败,回退到 PAVA: {e}") ir = IsotonicRegression(increasing=True, out_of_bounds="clip") T_hat = ir.fit_transform(b, y) # 保守纠偏 T_hat = np.maximum(T_hat, T_star) return T_hat, None, None def phi_time(t: float, alpha=0.02, beta=0.12): """时间惩罚函数:<=12无惩罚;12-28线性;>=28斜率更大""" if t <= 12.0: return 0.0 if t < 28.0: return alpha * (t - 12.0) return alpha * (28.0 - 12.0) + beta * (t - 28.0) def t_key_index(t: float, round_to: float): return int(round(float(t) / float(round_to))) def _prob_vec_at_t(res, GA_mean, BMI_mean, b_grid, t, thr=0.04, kappa=1.0, mode="new"): """同一时点t,对一串BMI计算 p(FF>=thr)""" b = res.fe_params ga_c = float(t - GA_mean) bmi_c_vec = b_grid - float(BMI_mean) eta_fix = (float(b["const"]) + float(b["GA_c"]) * ga_c + float(b["GA_c2"]) * (ga_c ** 2) + float(b["BMI_c"]) * bmi_c_vec + float(b["BMI_c2"]) * (bmi_c_vec ** 2)) sd = eta_sd(res, ga_c, mode=mode) * float(kappa) z = (eta_fix - float(logit(thr))) / sd return norm.cdf(z).astype(float) def precompute_prob_prefix_from_curve(res, GA_mean, BMI_mean, b_grid, T_curve, thr=0.04, round_to=0.1, kappa=1.0, mode="new"): """预计算所有候选t的p(t,b)前缀和,便于O(1)取任意连续BMI子段的概率和""" t_candidates = np.round(np.asarray(T_curve, float) / round_to) * round_to t_vals = np.unique(t_candidates) p_prefix = {} for t in t_vals: p_vec = _prob_vec_at_t(res, GA_mean, BMI_mean, b_grid, t, thr=thr, kappa=kappa, mode=mode) pref = np.zeros(len(b_grid) + 1, dtype=float) pref[1:] = np.cumsum(p_vec) p_prefix[t_key_index(t, round_to)] = pref return t_vals, p_prefix def dp_segment_bmi_fast(b_arr, T_curve, p_prefix, lam=0.01, round_to=0.1, w_fail=1.0, alpha=0.02, beta=0.12): """ 在单调曲线 T_curve(b) 上做最优台阶化 目标:Σ段 [Σ_{b∈段} (w_fail*(1-p(t,b)) + phi_time(t))] + λ*(#segments) """ n = len(b_arr) T = np.asarray(T_curve, dtype=float) keys = list(p_prefix.keys()) # 预计算每个子段 [i:j] 的推荐时点(中位数→对齐到最近候选键) best_t = np.full((n, n), np.nan, dtype=float) for i in range(n): for j in range(i, n): t_med = float(np.median(T[i:j+1])) kk = t_key_index(t_med, round_to) if kk not in p_prefix: kk = min(keys, key=lambda k: abs(k - kk)) best_t[i, j] = round(kk * round_to, 10) # 动态规划 C = np.full(n + 1, np.inf, dtype=float) prev = np.full(n + 1, -1, dtype=int) C[0] = 0.0 for j in range(1, n + 1): best_val = np.inf best_i = -1 for i in range(0, j): t_rec = best_t[i, j-1] k = t_key_index(t_rec, round_to) if k not in p_prefix: k = min(keys, key=lambda kk: abs(kk - k)) pref = p_prefix[k] L = j - i sum_p = pref[j] - pref[i] # 段内p的和 cost_seg = w_fail * (L - sum_p) + L * phi_time(t_rec, alpha=alpha, beta=beta) cost = C[i] + cost_seg + lam if cost < best_val: best_val = cost best_i = i C[j] = best_val prev[j] = best_i # 回溯分段 segs = [] j = n while j > 0: i = prev[j] t_rec = best_t[i, j-1] segs.append((i, j-1, t_rec)) j = i segs = segs[::-1] return C, prev, segs # ====================== 绘图函数 ====================== def plot_scatter_vs_ff(df: pd.DataFrame, out_dir: Path): """绘制 BMI vs FF 和 GA vs FF 散点图""" # 图1: BMI vs FF plt.figure() plt.scatter(df["BMI"], df["FF"], s=18, alpha=0.6) plt.xlabel("BMI") plt.ylabel("Y染色体浓度 (FF)") plt.title("BMI vs FF (散点图)") out1 = out_dir / "scatter_bmi_vs_ff.png" plt.savefig(out1, dpi=180, bbox_inches="tight") plt.close() # 图2: GA vs FF plt.figure() plt.scatter(df["GA"], df["FF"], s=18, alpha=0.6) plt.xlabel("孕周 (周)") plt.ylabel("Y染色体浓度 (FF)") plt.title("孕周 vs FF (散点图)") out2 = out_dir / "scatter_ga_vs_ff.png" plt.savefig(out2, dpi=180, bbox_inches="tight") plt.close() print("导出:", out1, out2) return out1, out2 # ====================== 主流程示例 ====================== if __name__ == "__main__": # 参数设置 INPUT_XLSX = "附件.xlsx" SHEET = 0 OUT_DIR = Path("output") ensure_dir(OUT_DIR) # 1. 读取并预处理数据 df = read_data(INPUT_XLSX, sheet_name=SHEET) id_col = detect_id_column(df) # 2. 问题一:拟合混合效应模型 res, d = fit_mixedlm_best(df, id_col) GA_mean = d["GA"].mean() BMI_mean = d["BMI"].mean() # 3. 绘制散点图 plot_scatter_vs_ff(df, OUT_DIR) # 4. 问题二:计算 T*(b) 并做单调拟合 + 分段 b_grid = np.linspace(df["BMI"].min(), df["BMI"].max(), 100) prob_fn = lambda t, b: prob_ge_threshold(res, GA_mean, BMI_mean, t, b, thr=0.04, mode="new") T_star = np.array([tstar_for_bmi(prob_fn, b, q=0.95)[0] for b in b_grid]) # 贝叶斯单调拟合 T_bayes, T_lo, T_hi = bayes_monotone_curve(b_grid, T_star, method="vi", draws=1500) # 预计算概率前缀和 t_vals, p_prefix = precompute_prob_prefix_from_curve(res, GA_mean, BMI_mean, b_grid, T_bayes, thr=0.04) # 动态规划分段 C, prev, segs = dp_segment_bmi_fast(b_grid, T_bayes, p_prefix, lam=0.01, round_to=0.1) print("\n[分段结果]") for i, j, t in segs: print(f"BMI区间 [{b_grid[i]:.1f}, {b_grid[j]:.1f}] → 推荐孕周 {t:.1f} 周") ``` ###### 全部论文及程序请见下方" 只会建模 QQ名片" 点击QQ名片即可

相关推荐
数模竞赛Paid answer4 小时前
2025年国赛高教社杯数学建模D题矿井突水水流漫延模型与逃生方案解题全过程文档及程序
数学建模·全国大学生数学建模竞赛·高教社杯
数模竞赛Paid answer6 小时前
2025年国赛高教社杯数学建模A题烟幕干扰弹的投放策略解题全过程文档及程序
数学建模·全国大学生数学建模竞赛·高教社杯·烟雾干扰弹的投放策略
一只小小的土拨鼠15 小时前
2026年华中杯大学生数学建模挑战赛ABC(华中杯数学建模)参赛思路与解题策略全解析(详细解题思路和论文+完整项目代码+全套资源)
数学建模
一只小小的土拨鼠15 小时前
2026年深圳杯&东三省数学建模联赛历年命题规律与硬核备赛指南
数学建模·深圳杯
超级码力6661 天前
【Latex第三方文档类standalone】standalone类介绍及应用
算法·数学建模·信息可视化
做cv的小昊1 天前
【TJU】研究生应用统计学课程笔记(4)——第二章 参数估计(2.1 矩估计和极大似然估计、2.2估计量的优良性原则)
人工智能·笔记·考研·数学建模·数据分析·excel·概率论
武帝为此1 天前
【相关性分析综述】
人工智能·数学建模
武帝为此1 天前
【特征选择方法】
算法·数学建模
AI科技星2 天前
灵魂商数(SQ) · 全域数学统一定义【乖乖数学】
算法·机器学习·数学建模·数据挖掘·量子计算