癌癥預(yù)后預(yù)測(cè)系統(tǒng):從數(shù)據(jù)預(yù)處理到模型融合的完整實(shí)踐)
多組學(xué)癌癥預(yù)后預(yù)測(cè)系統(tǒng)做了大半年從最初拍腦袋想“把幾個(gè)組學(xué)數(shù)據(jù)拼起來(lái)不就完了”到后面老老實(shí)實(shí)把數(shù)據(jù)清洗、特征篩選、融合模型、系統(tǒng)部署整個(gè)鏈路走通中間踩了不少坑。這套系統(tǒng)最后落地成一個(gè)小型Web服務(wù)輸入基因表達(dá)、甲基化、拷貝數(shù)變異這些公共數(shù)據(jù)幾秒鐘返回風(fēng)險(xiǎn)分?jǐn)?shù)、風(fēng)險(xiǎn)分層和1/3/5年生存概率。這篇文章就把整體設(shè)計(jì)、核心技術(shù)環(huán)節(jié)、實(shí)現(xiàn)細(xì)節(jié)、驗(yàn)證方法原原本本拆給大家適合正在做腫瘤生信分析、或者準(zhǔn)備把深度學(xué)習(xí)模型工程化交付的同學(xué)參考。1. 項(xiàng)目要解決什么問(wèn)題為什么單組學(xué)模型做到頭了先交代一下背景。我之前做過(guò)很多單組學(xué)預(yù)后模型基本都是“一個(gè)基因表達(dá)矩陣 一個(gè)Cox回歸調(diào)一調(diào)特征C-index到0.7左右就上不去了”。最初以為是樣本量不夠后來(lái)發(fā)現(xiàn)即使樣本加到六七百例性能還是在那個(gè)水平徘徊。這時(shí)候才意識(shí)到問(wèn)題出在數(shù)據(jù)維度上——單一組學(xué)只反映了腫瘤生物學(xué)的一個(gè)側(cè)面信息量存在天花板。1.1 單組學(xué)預(yù)測(cè)模型的上限在哪里以轉(zhuǎn)錄組為例基因表達(dá)數(shù)據(jù)本身噪音很大測(cè)序平臺(tái)不同、批次不同、樣本異質(zhì)性這些都會(huì)讓模型的泛化能力受損。單純依靠幾百個(gè)表達(dá)基因去預(yù)測(cè)患者兩年后是否復(fù)發(fā)生物學(xué)上也不合理。腫瘤的發(fā)生發(fā)展是一個(gè)從突變累積、表觀修飾改變、轉(zhuǎn)錄失調(diào)到蛋白功能異常的多層次過(guò)程你只截取其中一個(gè)層面當(dāng)然會(huì)有信息盲區(qū)。我做過(guò)一個(gè)對(duì)比實(shí)驗(yàn)同一批腫瘤樣本只用表達(dá)數(shù)據(jù)訓(xùn)練DeepSurvC-index穩(wěn)定在0.71加上甲基化特征后同一套訓(xùn)練流程提高到0.78再加拷貝數(shù)變異和miRNA數(shù)據(jù)后內(nèi)測(cè)能到0.82左右。這組數(shù)字說(shuō)明一個(gè)事實(shí)——組學(xué)之間的互補(bǔ)信息是真實(shí)存在的關(guān)鍵是你能不能把它們科學(xué)地整合起來(lái)。1.2 多組學(xué)不是簡(jiǎn)單堆數(shù)據(jù)信息互補(bǔ)與維度爆炸并存這里要給一個(gè)明確警告直接把幾個(gè)組學(xué)矩陣橫向拼接幾乎必翻車。原因有三個(gè)。第一維度爆炸。轉(zhuǎn)錄組兩萬(wàn)多個(gè)基因甲基化探針?biāo)氖迦f(wàn)個(gè)位點(diǎn)拷貝數(shù)變異也有數(shù)萬(wàn)個(gè)片段區(qū)域拼接完的特征向量幾十萬(wàn)維樣本量卻只有幾百這種“高維小樣本”問(wèn)題對(duì)神經(jīng)網(wǎng)絡(luò)模型來(lái)說(shuō)是災(zāi)難性的過(guò)擬合。第二數(shù)據(jù)缺失嚴(yán)重。公共數(shù)據(jù)庫(kù)里不是每個(gè)樣本都同時(shí)有表達(dá)、甲基化、拷貝數(shù)和miRNA數(shù)據(jù)樣本做交集之后總量從一千多例直接縮到四五百例是常態(tài)。你需要提前想清楚怎么處理缺失樣本人群。第三各組學(xué)數(shù)據(jù)的分布特征不同。表達(dá)數(shù)據(jù)經(jīng)過(guò)log值處理后近似正態(tài)甲基化Beta值在0到1之間有雙峰分布拷貝數(shù)變異有大量0值直接喂進(jìn)同一個(gè)歸一化流程非常不妥。所以多組學(xué)項(xiàng)目的第一課就是整合分析不等同于數(shù)組拼接前面有兩條很長(zhǎng)很長(zhǎng)的路要走——數(shù)據(jù)預(yù)處理和特征篩選。2. 數(shù)據(jù)準(zhǔn)備一臺(tái)機(jī)器90%的時(shí)間耗在預(yù)處理上這部分的經(jīng)驗(yàn)是我血淚換來(lái)的。系統(tǒng)設(shè)計(jì)時(shí)模型選型只花了一周但數(shù)據(jù)預(yù)處理斷斷續(xù)續(xù)搞了一個(gè)多月。公共數(shù)據(jù)倉(cāng)庫(kù)下載、樣本篩選、格式統(tǒng)一、歸一化、批次校正、求交集每一步都有坑。2.1 數(shù)據(jù)來(lái)源與樣本篩選邏輯多組學(xué)數(shù)據(jù)首選公共腫瘤數(shù)據(jù)庫(kù)通常會(huì)用TCGA和GEO這類公開(kāi)數(shù)據(jù)源。TCGA的特點(diǎn)是樣本量大、臨床隨訪信息相對(duì)完整而且同一批樣本通常有多個(gè)組學(xué)平臺(tái)的測(cè)序結(jié)果非常適合做多組學(xué)整合。GEO的好處是數(shù)據(jù)來(lái)源分散、可以拿到外部獨(dú)立驗(yàn)證集。樣本篩選這一步很多人忽略其實(shí)直接影響模型質(zhì)量。我用的篩選規(guī)則如下只保留原發(fā)腫瘤樣本剔除正常組織樣本和轉(zhuǎn)移灶樣本。正常組織在甲基化層面和腫瘤差異極大混在一起模型會(huì)學(xué)到“這是不是腫瘤”而不是“腫瘤預(yù)后如何”。刪除生存時(shí)間缺失、生存狀態(tài)缺失的樣本。刪除隨訪時(shí)間小于30天的樣本。隨訪太短的患者大概率還沒(méi)觀察到事件就被截尾留在數(shù)據(jù)集里會(huì)給模型帶來(lái)混亂信息。生存時(shí)間單位統(tǒng)一成“月”。我遇到過(guò)一版數(shù)據(jù)里天數(shù)、月數(shù)混用模型損失函數(shù)直接異常波動(dòng)。這些規(guī)則不復(fù)雜但每一條都是真實(shí)問(wèn)題。特別是隨訪時(shí)間篩除很多公開(kāi)數(shù)據(jù)集里確實(shí)有“診斷后兩周死亡”這種樣本它們對(duì)標(biāo)準(zhǔn)的生存分析損失函數(shù)影響極大。2.2 多維組學(xué)數(shù)據(jù)的規(guī)范化處理要點(diǎn)下表匯總了四類常見(jiàn)組學(xué)數(shù)據(jù)的處理要點(diǎn)數(shù)據(jù)類型原始數(shù)據(jù)形態(tài)常用歸一化方法關(guān)鍵預(yù)處理動(dòng)作轉(zhuǎn)錄組表達(dá)原始count矩陣或FPKMTMM歸一化后轉(zhuǎn)log2低表達(dá)基因過(guò)濾基因名去重miRNA表達(dá)count矩陣同轉(zhuǎn)錄組邏輯注意成熟體命名規(guī)范去批次DNA甲基化Beta值0到1之間轉(zhuǎn)M值后標(biāo)準(zhǔn)化去性染色體探針去SNP相關(guān)探針拷貝數(shù)變異GISTIC2.0分段值直接標(biāo)準(zhǔn)化或離散化大批量0值保留分段水平轉(zhuǎn)錄組表達(dá)我最常用的是edgeR包的TMMtrimmed mean of M-values歸一化然后做log2(x1)變換。注意RNA-seq的count矩陣和芯片的熒光信號(hào)強(qiáng)度矩陣統(tǒng)計(jì)特性完全不同如果在同一數(shù)據(jù)集中混用了兩種平臺(tái)后續(xù)批次校正會(huì)更難處理。甲基化數(shù)據(jù)是重災(zāi)區(qū)。450K或EPIC芯片有約四十五萬(wàn)個(gè)CpG位點(diǎn)但其中有很多探針是落在性染色體上的還有一些和已知SNP位點(diǎn)重疊、容易受基因型影響的探針這些都需要在預(yù)處理階段刪掉。另外Beta值分布偏斜通常轉(zhuǎn)成M值M log2(Beta / (1 - Beta))再做后續(xù)分析M值更接近正態(tài)分布比較適合做線性建模??截悢?shù)變異數(shù)據(jù)相對(duì)簡(jiǎn)單GISTIC2.0輸出的是每個(gè)樣本每個(gè)片段的拷貝數(shù)狀態(tài)大量位點(diǎn)是0值。直接數(shù)值化時(shí)我一般保留連續(xù)的GISTIC分值不做離散化讓模型自己去學(xué)0值背后的分布規(guī)律。2.3 批次效應(yīng)校正和樣本配對(duì)問(wèn)題這批樣本來(lái)自不同測(cè)序中心、不同時(shí)期、不同平臺(tái)批次效應(yīng)無(wú)可避免。我用的標(biāo)準(zhǔn)工具是sva包的ComBat函數(shù)核心思想是假設(shè)不同批次之間存在一個(gè)系統(tǒng)性偏移用經(jīng)驗(yàn)貝葉斯方法估計(jì)并去除這個(gè)偏移。這里必須強(qiáng)調(diào)所有批次校正都必須在訓(xùn)練集內(nèi)部完成并且要把校正參數(shù)保存下來(lái)后續(xù)外部驗(yàn)證數(shù)據(jù)應(yīng)用的是完全相同的參數(shù)不能重新擬合。這一點(diǎn)和標(biāo)準(zhǔn)化問(wèn)題很像做錯(cuò)了就是數(shù)據(jù)泄露。樣本配對(duì)是另一個(gè)大坑。不同組學(xué)數(shù)據(jù)的樣本ID寫法可能不同有的是TCGA-XX-XXXX有的是純數(shù)字序號(hào)還有的是GEO平臺(tái)的GSM編號(hào)。我寫了一個(gè)統(tǒng)一的清洗腳本先做ID格式規(guī)范化再做交集合并。同時(shí)強(qiáng)烈建議在合并前看一眼各平臺(tái)的樣本重疊情況。我遇到過(guò)某數(shù)據(jù)集表達(dá)平臺(tái)有1100個(gè)樣本甲基化只有650個(gè)最后配對(duì)完只剩520個(gè)。這種掉樣本現(xiàn)象是合理的但你要心里有數(shù)樣本量縮水的速度比你想象中快得多。3. 特征篩選決定模型上限的環(huán)節(jié)預(yù)處理做完之后各組學(xué)數(shù)據(jù)還是幾十萬(wàn)維。這個(gè)規(guī)模直接送進(jìn)神經(jīng)網(wǎng)絡(luò)大概率是災(zāi)難。我用到的策略是分層篩選每層用一個(gè)相對(duì)輕量的算法砍掉大量無(wú)關(guān)特征最后把特征數(shù)量控制在可管理范圍內(nèi)。3.1 第一層過(guò)濾差異分析 單因素Cox第一步是降維目標(biāo)很簡(jiǎn)單把明顯沒(méi)有區(qū)分能力的特征刪掉。對(duì)轉(zhuǎn)錄組數(shù)據(jù)先做低表達(dá)過(guò)濾保留在超過(guò)20%樣本中表達(dá)量大于某個(gè)閾值的基因。這一步就能砍掉不少背景噪音。然后做差異表達(dá)分析比較高風(fēng)險(xiǎn)組和低風(fēng)險(xiǎn)組的表達(dá)差異。但這里有個(gè)容易混淆的地方——預(yù)后模型更需要的是“與生存時(shí)間相關(guān)的基因”不只是“差異表達(dá)的基因”。所以更主流的做法是直接做單因素Cox回歸對(duì)每個(gè)基因單獨(dú)擬合一個(gè)比例風(fēng)險(xiǎn)模型看p值是否顯著。具體操作上可以用lifelines庫(kù)或者R里的survival包對(duì)標(biāo)準(zhǔn)化后的特征逐個(gè)建模保留p值小于0.05的特征。做這一步時(shí)要注意表達(dá)量接近零的基因它們的HR會(huì)出現(xiàn)極端的離群值比如幾百甚至上萬(wàn)因?yàn)閏ox模型的指數(shù)函數(shù)對(duì)數(shù)值太敏感。所以務(wù)必先過(guò)濾低表達(dá)/低變異特征再跑單因素Cox。3.2 第二層壓縮LASSO-Cox交叉驗(yàn)證單因素Cox篩完后特征數(shù)量通常還在幾千到一萬(wàn)之間。下一步我推薦LASSO-CoxL1正則化的Cox回歸它對(duì)高維特征有多重共線性下壓縮變量的能力通過(guò)懲罰項(xiàng)把無(wú)關(guān)特征的系數(shù)壓成零得到稀疏解。LASSO-Cox實(shí)現(xiàn)上我用的是R中g(shù)lmnet包的cv.glmnet函數(shù)選擇lambda時(shí)有兩個(gè)常見(jiàn)選擇——lambda.min和lambda.1se。lambda.min是交叉驗(yàn)證誤差最小的lambda值特征保留相對(duì)多擬合能力強(qiáng)但稍微復(fù)雜。lambda.1se是在最小誤差一個(gè)標(biāo)準(zhǔn)差范圍內(nèi)的最大lambda特征更稀疏模型更穩(wěn)定。建議默認(rèn)用lambda.1se尤其后面還要接神經(jīng)網(wǎng)絡(luò)融合模塊前面特征別再留太多冗余。做完LASSO之后我還會(huì)跑一遍隨機(jī)生存森林Random Survival Forest用它的特征重要性做交叉驗(yàn)證。兩套算法都保留下來(lái)的特征才是最終進(jìn)入融合模型的候選集。3.3 一個(gè)可以直接抄的篩選流水線整個(gè)特征篩選流水線可以總結(jié)成下面這幾個(gè)步驟每一步的輸入輸出都是前一步的下游方差過(guò)濾去掉近零方差特征。對(duì)甲基化數(shù)據(jù)尤其重要幾十萬(wàn)探針里很大一部分在所有樣本中都沒(méi)有變化。差異分析高風(fēng)險(xiǎn)組vs低風(fēng)險(xiǎn)組挑出組間差異明顯的特征。單因素Cox每個(gè)特征獨(dú)立做生存關(guān)聯(lián)分析保留p小于0.05的特征。LASSO-Cox交叉驗(yàn)證用lambda.1se選擇最終的稀疏特征集。RSF重要性核對(duì)確認(rèn)LASSO選出的特征與隨機(jī)生存森林的重要性排名方向一致。經(jīng)過(guò)這套流程轉(zhuǎn)錄組通常保留50到150個(gè)基因甲基化保留30到80個(gè)CpG位點(diǎn)拷貝數(shù)和miRNA各保留20到50個(gè)??傮w控制在150到300個(gè)特征之間這時(shí)候再做多組學(xué)融合維度才合理。注意特征篩選全過(guò)程只使用訓(xùn)練集。很多項(xiàng)目在外部隊(duì)列上性能崩盤就是因?yàn)楹Y選特征時(shí)用了全量數(shù)據(jù)相當(dāng)于讓驗(yàn)證集的信息提前進(jìn)入了模型。4. 多組學(xué)融合模型設(shè)計(jì)為什么不能簡(jiǎn)單拼接特征準(zhǔn)備好之后接下來(lái)的核心問(wèn)題就是怎么融合。這塊我認(rèn)真比較過(guò)三種方案早期拼接、中期融合、晚期集成。4.1 三種融合策略選型早期融合最簡(jiǎn)單把各組學(xué)特征拼成一個(gè)長(zhǎng)向量直接喂給模型。好處是容易實(shí)現(xiàn)壞處也很明顯一方面各組學(xué)內(nèi)部的結(jié)構(gòu)信息被淹沒(méi)在長(zhǎng)向量里另一方面不同組學(xué)特征數(shù)量差異巨大數(shù)量多的組學(xué)容易主導(dǎo)模型訓(xùn)練。中期融合是給每個(gè)組學(xué)單獨(dú)一個(gè)編碼器各自學(xué)出特征表示然后通過(guò)一個(gè)融合模塊組合各個(gè)表示向量。這種方案的優(yōu)點(diǎn)是各組學(xué)先做了一次信息壓縮融合模塊可以更公平地對(duì)待每個(gè)組學(xué)。晚期集成則是每組學(xué)單獨(dú)訓(xùn)練模型最后把預(yù)測(cè)打分平均或加權(quán)。這個(gè)方案實(shí)現(xiàn)獨(dú)立性最強(qiáng)但組學(xué)之間的交互信息完全丟失性能相對(duì)受限。融合策略實(shí)現(xiàn)難度組學(xué)交互可解釋性實(shí)測(cè)效果早期拼接低低差一般中期融合中高高較好最好晚期集成低無(wú)好中等我最后選了中期融合并在融合模塊上加了注意力機(jī)制讓模型自己學(xué)習(xí)不同組學(xué)在預(yù)測(cè)時(shí)的重要性權(quán)重。4.2 自適應(yīng)注意力融合模塊的實(shí)現(xiàn)細(xì)節(jié)融合模塊的設(shè)計(jì)思路比較簡(jiǎn)單每組學(xué)特征先進(jìn)過(guò)一個(gè)兩層的MLP編碼器把不同維度的特征壓縮到同一維度的表示向量然后計(jì)算每個(gè)組學(xué)表示向量的注意力權(quán)重加權(quán)求和。為了深度我再包了一層多頭注意力加殘差連接。這里給出核心部分的偽代碼import torch import torch.nn as nn class OmicsEncoder(nn.Module): def __init__(self, input_dim, hidden_dim128, output_dim128): super().__init__() self.net nn.Sequential( nn.Linear(input_dim, hidden_dim), nn.BatchNorm1d(hidden_dim), nn.ReLU(), nn.Dropout(0.3), nn.Linear(hidden_dim, output_dim) ) def forward(self, x): return self.net(x) class AttentionFusion(nn.Module): def __init__(self, omics_dims, hidden_dim128): super().__init__() # omics_dims 是每個(gè)組學(xué)篩選后的特征維度列表 self.encoders nn.ModuleList([ OmicsEncoder(dim, hidden_dim) for dim in omics_dims ]) # 注意力打分網(wǎng)絡(luò) self.attn nn.Linear(hidden_dim, 1) def forward(self, omics_list): representations [] for encoder, x in zip(self.encoders, omics_list): representations.append(encoder(x)) # representations: list of tensors, each (batch, hidden_dim) reps torch.stack(representations, dim1) # (batch, n_omics, hidden_dim) scores self.attn(reps).squeeze(-1) # (batch, n_omics) weights torch.softmax(scores, dim1) fused torch.sum(weights.unsqueeze(-1) * reps, dim1) return fused, weights這個(gè)模塊在實(shí)際運(yùn)行中非常穩(wěn)定而且訓(xùn)練完可以直接輸出每個(gè)樣本的組學(xué)注意力權(quán)重能用來(lái)分析“這個(gè)患者是哪類組學(xué)數(shù)據(jù)主導(dǎo)了風(fēng)險(xiǎn)預(yù)測(cè)”。我在系統(tǒng)里把這些權(quán)重一起展示出來(lái)臨床老師看了也覺(jué)得有價(jià)值。4.3 生存損失函數(shù)與訓(xùn)練策略融合表示向量后面接一個(gè)輸出層得到風(fēng)險(xiǎn)分?jǐn)?shù)h(x)訓(xùn)練目標(biāo)用Cox偏似然損失。公式是L -Σ_{i: event_i1} [ h(x_i) - log Σ_{j: t_j t_i} exp(h(x_j)) ]這里每個(gè)事件樣本的風(fēng)險(xiǎn)集是該時(shí)點(diǎn)仍存活的所有樣本分母對(duì)風(fēng)險(xiǎn)集中的樣本求和。這個(gè)損失直接優(yōu)化排序目標(biāo)比用分類模型預(yù)測(cè)“會(huì)不會(huì)復(fù)發(fā)”更合理。實(shí)現(xiàn)時(shí)要注意數(shù)值穩(wěn)定性常見(jiàn)的做法是先對(duì)h(x)做max減法再算logsumexp。PyTorch里頭直接用torch.logsumexp就行。訓(xùn)練配置我給了個(gè)常規(guī)方案AdamW優(yōu)化器學(xué)習(xí)率1e-3weight_decay 1e-4批大小64訓(xùn)練最多200個(gè)epoch早停patience設(shè)為15監(jiān)控驗(yàn)證集的C-index。所有編碼器的輸出維度統(tǒng)一設(shè)成128dropout設(shè)0.3防止多層結(jié)構(gòu)過(guò)擬合。有一點(diǎn)需要強(qiáng)調(diào)生存數(shù)據(jù)有大量右刪失樣本損失函數(shù)只對(duì)事件樣本的偏似然做求和但刪失樣本仍然參與風(fēng)險(xiǎn)集計(jì)算所以訓(xùn)練時(shí)不需要刻意做類別平衡。真正需要注意的反而是刪失比例過(guò)高比如超過(guò)80%時(shí)模型很難學(xué)到有效信號(hào)這時(shí)候更要依賴特征篩選階段保留那些與生存強(qiáng)相關(guān)的特征。5. 系統(tǒng)落地從Jupyter到可交付API模型在Jupyter里跑通只是一半工作后面要把它封裝成別人能用的系統(tǒng)。這個(gè)環(huán)節(jié)看上去瑣碎但直接決定了項(xiàng)目能不能真正交付。5.1 模型封裝與預(yù)處理參數(shù)固化最核心的思路是“把整個(gè)預(yù)處理流程固化成一次性的配置文件”。不能幻想部署時(shí)再跑一遍歸一化腳本必須把下面這些內(nèi)容全部序列化保存特征名單每個(gè)組學(xué)最終入選的特征名列表存成JSON。標(biāo)準(zhǔn)化參數(shù)每個(gè)特征的均值和標(biāo)準(zhǔn)差注意是訓(xùn)練集上的值。批次校正參數(shù)ComBat的估計(jì)參數(shù)。編碼器和融合模型的權(quán)重統(tǒng)一的torch checkpoint。推理版本信息記錄模型訓(xùn)練時(shí)的數(shù)據(jù)處理邏輯。推理函數(shù)接受原始數(shù)據(jù)作為輸入內(nèi)部按順序處理匹配特征名、缺失值用中位數(shù)填充、按保存的參數(shù)做標(biāo)準(zhǔn)化、調(diào)用模型得到風(fēng)險(xiǎn)分?jǐn)?shù)。缺失值處理這里也特別說(shuō)一下公共數(shù)據(jù)庫(kù)的輸入數(shù)據(jù)幾乎不可能特征全齊常見(jiàn)的單個(gè)樣本會(huì)有百分之幾的基因缺失。我實(shí)測(cè)下來(lái)用整個(gè)訓(xùn)練集中位數(shù)填充的效果比行刪除好很多模型穩(wěn)定性明顯提升。5.2 后端API實(shí)現(xiàn)我用FastAPI搭了一個(gè)輕量級(jí)后端提供一個(gè)POST接口接收樣本數(shù)據(jù)返回風(fēng)險(xiǎn)分?jǐn)?shù)、風(fēng)險(xiǎn)分層和生存概率。from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class SampleRequest(BaseModel): sample_id: str expression: dict # 基因名 - 表達(dá)值 methylation: dict # CpG位點(diǎn) - Beta值 cnv: dict # 片段名 - 拷貝數(shù)值 app.post(/predict) async def predict(req: SampleRequest): features preprocess(req) # 內(nèi)部含特征對(duì)齊、缺失填充、標(biāo)準(zhǔn)化 risk_score model.risk(features) prob_1y, prob_3y, prob_5y model.survival_probability(features) return { sample_id: req.sample_id, risk_score: risk_score, risk_level: high if risk_score cutoff else low, survival_prob: { 1y: prob_1y, 3y: prob_3y, 5y: prob_5y } }這里有一個(gè)必須提到的輸入校驗(yàn)如果提交數(shù)據(jù)的特征缺失率超過(guò)10%直接返回錯(cuò)誤提示而不是默默填一堆中位數(shù)進(jìn)去。缺失太多時(shí)填充分?jǐn)?shù)失真預(yù)測(cè)結(jié)果不可信。演示界面我用了Gradio三分鐘就能搭一個(gè)上傳CSV、返回可視化結(jié)果的交互頁(yè)面。它非常適合給非工程背景的課題組成員做演示比直接丟API方便得多。5.3 可解釋性輸出SHAP與KM曲線一個(gè)預(yù)測(cè)系統(tǒng)只輸出一個(gè)風(fēng)險(xiǎn)分?jǐn)?shù)對(duì)臨床合作方來(lái)說(shuō)遠(yuǎn)遠(yuǎn)不夠。他們一定會(huì)問(wèn)“為什么這個(gè)患者被判成高風(fēng)險(xiǎn)”。所以我額外加了一個(gè)可解釋性模塊。SHAP分析可以計(jì)算每個(gè)特征對(duì)風(fēng)險(xiǎn)分?jǐn)?shù)的貢獻(xiàn)而且能在樣本級(jí)別給出解釋。轉(zhuǎn)錄組特征、甲基化位點(diǎn)、拷貝數(shù)值各自的影響一目了然。同時(shí)按風(fēng)險(xiǎn)分?jǐn)?shù)中位數(shù)把患者分為高低風(fēng)險(xiǎn)兩組畫出Kaplan-Meier生存曲線并輸出log-rank檢驗(yàn)的p值。這條曲線在論文和匯報(bào)中都是最有說(shuō)服力的單圖。還有校準(zhǔn)曲線和決策曲線分析DCA。校準(zhǔn)曲線看的是模型預(yù)測(cè)的生存概率和實(shí)際觀察概率是否一致DCA則衡量模型在不同閾值下的臨床凈獲益。這兩個(gè)指標(biāo)是我交付時(shí)必出的圖也是很多審稿人關(guān)注的對(duì)象??山忉屝阅K看起來(lái)不算核心功能但在實(shí)際項(xiàng)目評(píng)審時(shí)的價(jià)值甚至超過(guò)了預(yù)測(cè)精度本身。這條經(jīng)驗(yàn)值得認(rèn)真體會(huì)。6. 效果驗(yàn)證與踩坑實(shí)錄模型好不好不能只看訓(xùn)練集指標(biāo)。驗(yàn)證環(huán)節(jié)如果做得不嚴(yán)謹(jǐn)整個(gè)系統(tǒng)就是空中樓閣。6.1 內(nèi)部驗(yàn)證和外部驗(yàn)證分別該看什么內(nèi)部驗(yàn)證方面我用分層劃分的方式按7比3拆分訓(xùn)練集和測(cè)試集保持刪失比例兩組近似然后做五折重復(fù)實(shí)驗(yàn)。報(bào)告指標(biāo)時(shí)C-index要給出均值和標(biāo)準(zhǔn)差最好也附95%置信區(qū)間。只看一個(gè)最好試次的數(shù)字那絕對(duì)是對(duì)自己耍流氓。時(shí)間依賴AUC也要報(bào)告1年、3年、5年的數(shù)值不能只報(bào)一個(gè)C-index。C-index是全局一致性指標(biāo)它無(wú)法告訴你模型在短期預(yù)后預(yù)測(cè)是否準(zhǔn)確。我系統(tǒng)里的最終內(nèi)部測(cè)試結(jié)果穩(wěn)定在C-index約0.821年AUC約0.803年AUC約0.835年AUC約0.78。外部驗(yàn)證是真正的試金石。公共數(shù)據(jù)庫(kù)里找一個(gè)獨(dú)立數(shù)據(jù)源應(yīng)用之前保存的完整預(yù)處理參數(shù)和模型權(quán)重只做特征映射和標(biāo)準(zhǔn)化不做任何重新擬合。外部數(shù)據(jù)集的C-index比內(nèi)部低0.05到0.1是非常正常的這反映了域偏移。如果外部驗(yàn)證下降幅度超過(guò)0.15就要懷疑特征篩選階段是否發(fā)生過(guò)數(shù)據(jù)泄露或者訓(xùn)練集過(guò)擬合太嚴(yán)重。6.2 實(shí)測(cè)中踩過(guò)的三個(gè)坑第一個(gè)坑標(biāo)準(zhǔn)化數(shù)據(jù)泄露。早期版本我在全數(shù)據(jù)集上計(jì)算了每個(gè)特征的均值標(biāo)準(zhǔn)差然后再拆分訓(xùn)練測(cè)試集。結(jié)果內(nèi)部C-index虛高了0.05。這個(gè)問(wèn)題非常隱蔽因?yàn)橹笜?biāo)看起來(lái)一切正常直到換新數(shù)據(jù)做外部驗(yàn)證才發(fā)現(xiàn)慘不忍睹。第二個(gè)坑甲基化特征沒(méi)做好預(yù)篩直接把數(shù)千個(gè)探針?biāo)瓦M(jìn)編碼器。模型訓(xùn)練C-index沖到0.95測(cè)試集只有0.65這是典型的過(guò)擬合。問(wèn)題出在甲基化特征經(jīng)過(guò)單因素Cox篩選后仍然保留了太多位點(diǎn)而樣本量只有四百多編碼器參數(shù)一多就立刻開(kāi)始背答案。第三個(gè)坑外部驗(yàn)證平臺(tái)的批次效應(yīng)。我用一個(gè)RNA-seq平臺(tái)訓(xùn)練的模型去驗(yàn)證另一個(gè)芯片平臺(tái)的數(shù)據(jù)ID對(duì)齊之后發(fā)現(xiàn)表達(dá)值分布差異巨大特征縮放到同一尺度后仍然有系統(tǒng)性偏差。后來(lái)我干脆在系統(tǒng)上明確區(qū)分了適用平臺(tái)類型并在輸入校驗(yàn)中加入了分布偏移預(yù)警。6.3 常見(jiàn)問(wèn)題速查表現(xiàn)象可能原因解決方法訓(xùn)練C-index極高測(cè)試集暴跌過(guò)擬合或數(shù)據(jù)泄露檢查是否在全數(shù)據(jù)上做過(guò)標(biāo)準(zhǔn)化加大dropout和正則化外部驗(yàn)證C-index遠(yuǎn)低于內(nèi)部批次效應(yīng)、平臺(tái)差異檢查預(yù)處理參數(shù)是否復(fù)用用ComBat校正后統(tǒng)一參數(shù)損失函數(shù)一開(kāi)始就是NaN生存時(shí)間單位混亂統(tǒng)一用月檢查有無(wú)0或負(fù)生存時(shí)間組學(xué)注意力權(quán)重嚴(yán)重偏向某一種特征數(shù)量不平衡調(diào)整編碼器輸出維度各組學(xué)特征數(shù)盡量均衡刪失樣本太多模型不收斂風(fēng)險(xiǎn)集信息不足加強(qiáng)特征篩選考慮換排序損失或DeepHit輸入樣本缺失率過(guò)高結(jié)果異常填充失真添加缺失率校驗(yàn)缺失超10%直接拒絕預(yù)測(cè)我在交付前還會(huì)加一道數(shù)據(jù)完整性測(cè)試用完全不相關(guān)的隨機(jī)輸入跑一遍推理確認(rèn)系統(tǒng)不會(huì)崩潰并對(duì)輸入數(shù)據(jù)的特征分布做分布偏移檢測(cè)。這些防御性邏輯是系統(tǒng)工程項(xiàng)目和實(shí)驗(yàn)代碼的區(qū)別也是花時(shí)間打磨的地方。最后再分享一點(diǎn)個(gè)人體會(huì)這套多組學(xué)系統(tǒng)從頭到尾走下來(lái)我最大的感受是在多組學(xué)項(xiàng)目里數(shù)據(jù)理解和特征工程的重要性遠(yuǎn)大于模型結(jié)構(gòu)本身。同一個(gè)融合模型前面數(shù)據(jù)處理差一步最終指標(biāo)能差出十個(gè)點(diǎn)。后來(lái)再接到新的癌種需求我基本都是老路徑先跑預(yù)處理流程照搬特征篩選快速重跑模型結(jié)構(gòu)幾乎不需要改動(dòng)。系統(tǒng)交付時(shí)最受歡迎的不是那個(gè)創(chuàng)新模型而是帶可視化解釋的Web界面和清晰的驗(yàn)證報(bào)告。做項(xiàng)目做系統(tǒng)最終評(píng)價(jià)標(biāo)準(zhǔn)永遠(yuǎn)是能不能讓使用者真正理解和信任這個(gè)模型。