這些概念確實很難記憶,長時間不用很容易忘記。此文可以幫你快速回憶起這些概念,同時不涉及任何繞口的專業術語。
1. 記住基本框架,金標准和預測結果,沒有這兩個概念就沒有敏感性和特異性了。以上指標都是用於衡量我們(預測)方法的效果的。考慮兩個極端的方面,一、我的診斷/預測方法里的陽性包含了所有的陽性(金標准)個體,想實現這個很簡單,就是任何一個人來看病我都說你得了艾滋病,這會帶來什么結果呢?正面的就是所有的艾滋病個體我都可以給你判斷出來,負面的呢?就是同時一大堆正常人給誤判為艾滋病了;二、我的診斷/預測方法的陰性包含了所有的陰性(金標准)個體,一個極端的診斷方法就是任何一個人來看病我都說你沒有艾滋病,這回漏掉了很多的陽性個體。當然大部分的診斷和預測方法都不會這么極端,核心意思就是我們必須同時考慮我們方法在陽性和陰性(犯第一類錯誤和第二類錯誤)兩方面的綜合表現。
2. 畫表是你看到這幾個指標的第一反應,橫軸是金標准的陽性和陰性,縱軸是方法的陽性和陰性,我們預測的任何一個個體都會落到以下四個象限中的一個:
看圖說話:
真陽性:左上格,金標准和預測都為真;
真陰性:右下格,金標准和預測都為假;
假陽性:右上格,就是我們的預測結果是假的陽性(預測出來的陽性其實是金標准的陰性);
假陰性:左下格,就是我們的預測結果是假的陰性(預測出來的陰性其實是金標准的陽性);
敏感性sensitivity:顧名思義,就是我們的方法對陽性的敏感度,換句話說就是我給你一堆金標准的陽性結果,你能判斷出多少來。就像緝毒犬一樣,給你一堆含毒品的行李箱,你能聞出多少出來。這個值命名為敏感性還是很形象的。
特異性specificity:顧名思義,就是你的方法能指定地判斷出陰性的能力,我給你一堆金標准的陰性結果,你會不會誤判出一些陽性的結果。這個命名還是欠缺形象性,叫准陰性更貼切。
FDR:常用於多重檢驗下的p-value矯正;偽發現率,其意義為是 錯誤拒絕(拒絕真的(原)假設)的個數占所有被拒絕的原假設個數的比例的期望值。就是我的所有預測陽性中有多少是誤判的假陽性。以緝毒犬為例,我的狗聞出了一堆箱子,里面有多少是不含毒品的。在差異基因檢測中,使用FDR就是用於控制假陽性的比率(通常為0.05),是不是又把所有知識串起來了。
第一類錯誤、第二類錯誤:顯然我們的方法里有且僅有兩類錯誤,通常我們先考慮我們預測的陽性結果,里面有多少錯誤(其實是金標准的陰性),這些錯誤就是第一類錯誤,也就是上面的假陽性。在考慮我們預測的陰性結果,里面有多少是假陰性,也就是有多少第二類錯誤。
False positive rate (FPR):假陽性率,給你一堆金標准的陰性,有多少是假的陰性,等於1-specificity,1-准陰性不就是假陰性嗎。
Confusion matrix混淆矩陣 / Contingency table列聯表 (這個表的兩種名稱)

基於sensitivity和specificity衍生出來的兩個概念:只能用於二分類模型的評價。
怎么全面地評價一個二分類模型的好壞,模型的其他指標都依賴一個threshold,單一的threshold是有偏的。
ROC:receiver operating characteristic,每個分類器作出的預測呢,都是基於一個probability score的。一般默認的threshold呢都是0.5,如果probability>0.5,那么這個sample被模型分成正例了哈,反之則是反例。ROC曲線是一系列threshold(比如邏輯斯蒂分類問題,取多少閾值來划分類別)下的(FPR,TPR)數值點的連線。不同閾值下模型的sensitivity和specificity不同。
AUC:areas-under-the-curve,曲線下的面積(AUC)越大,或者說曲線更接近左上角(true positive rate=1, false positive rate=0)。AUC的意義:分別隨機從正負樣本集中抽取一個正樣本,一個負樣本,正樣本的預測值大於負樣本的概率。Wilcoxon-Mann-Witney Test。
- (0,0):TP=0,FP=0,可以發現該分類器預測所有的樣本都為負樣本(Negative)
- (1,1):TN=0,FN=0,可以發現該分類器預測所有的樣本都為正樣本(Positive)
- (0,1):FP=0,FN=0,它將所有的樣本都正確分類
- (1,0):TP=0,TN=0,它將所有的樣本都錯誤分類

繼續深入:
精確度Precision:很容易與敏感性搞混,分子是一樣的,但分母不同,精確度的分母是我們方法預測出來的陽性,敏感性是金標准的陽性。精確度表示我們預測了一堆陽性結果,里面有多少是靠譜的。
准確度Accuracy:和Precision中文意思是一樣的,Precision指的是測量結果的一致性。Accuracy指的是測量結果和真實結果的接近程度。

Recall:TPR,真陽性率,和sensitivity一個東西。
F1 score:F1-score(均衡平均數)是綜合考慮了模型查准率和查全率的計算結果,取值更偏向於取值較小的那個指標。F1-score越大自然說明模型質量更高。但是還要考慮模型的泛化能力,F1-score過高但不能造成過擬合,影響模型的泛化能力。
以下是我曾經的一個項目,不感興趣的可以不看。
終於要用到這個玩意了,很激動,主要統計假陰假陽性率。
我的任務:
1. 評估Pacbio MHC variation calling 結果(CCS/non-CCS)與Hiseq數據結果的一致性。
2. 分別在不同深度梯度的區域完成以上評估,推斷PB MHC做variation calling的最低深度。
這里要將一個位點分為SNP、REF 和 LowQual,然后只去 SNP 和 REF 進行統計。
#!/usr/bin/env python
# Author: LI ZHIXIN
import sys
import pysam
from collections import OrderedDict
def classify_DP(depth):
if depth > 101:
return 21
return ((depth-1)//5+1)
def parse_rec(rec):
sample = list(rec.samples)[0]
# filter the Invalid line
if not ('GQ' or 'GT' or 'DP') in rec.samples[sample].keys() or len(rec.alleles) <= 1:
# continue
return 1, "LowQual", rec.pos
# filter the LowQual
if rec.samples[sample]['GQ'] < 30:
return rec.samples[sample]['DP'], "LowQual", rec.pos
# filter the indel
flag = 0
for one in rec.alleles:
if len(one) != len(rec.ref):
flag = 1
if flag == 1:
return rec.samples[sample]['DP'], "LowQual", rec.pos
if rec.samples[sample]['GT'] != (0, 0): # rec.qual > 30
# variation_dict[rec.pos] = ["snp", rec.alleles]
return rec.samples[sample]['DP'], "snp", rec.pos
elif rec.samples[sample]['GT'] == (0, 0):
# variation_dict[rec.pos] = ["ref", rec.alleles]
return rec.samples[sample]['DP'], "ref", rec.pos
def read_gvcf(gvcf_file_path):
variation_dict = OrderedDict()
for i in range(1,22):
variation_dict[i] = {}
for j in ('LowQual', 'snp', 'ref'):
variation_dict[i][j] = []
# pos_list = []
gvcf_file = pysam.VariantFile(gvcf_file_path)
for rec in gvcf_file.fetch('chr6',28477796,33448354):
DP, pos_type, pos = parse_rec(rec)
if DP < 1 or DP > 20:
continue
# DP = classify_DP(DP)
variation_dict[DP][pos_type].append(pos)
# print(pos, DP, pos_type)
gvcf_file.close()
# return variation_dict, pos_list
return variation_dict
def read_hiseq_gvcf(gvcf_file_path):
variation_dict = OrderedDict()
# for i in range(1,22):
# variation_dict[i] = {}
for j in ('LowQual', 'snp', 'ref'):
variation_dict[j] = []
# pos_list = []
gvcf_file = pysam.VariantFile(gvcf_file_path)
for rec in gvcf_file.fetch('chr6',28477796,33448354):
DP, pos_type, pos = parse_rec(rec)
DP = classify_DP(DP)
variation_dict[pos_type].append(pos)
# print(pos, DP, pos_type)
gvcf_file.close()
# return variation_dict, pos_list
return variation_dict
def show_dict_diff_DP(Hiseq_unified_variation_dict, PB_non_CCS_variation_dict, outf, outf2):
for DP in range(1,21):
Hiseq_snp = set(Hiseq_unified_variation_dict['snp'])
Hiseq_ref = set(Hiseq_unified_variation_dict['ref'])
Hiseq_lowqual = set(Hiseq_unified_variation_dict['LowQual'])
PB_snp = PB_non_CCS_variation_dict[DP]['snp']
PB_ref = PB_non_CCS_variation_dict[DP]['ref']
PB_lowqual = PB_non_CCS_variation_dict[DP]['LowQual']
total = set(PB_snp + PB_ref + PB_lowqual)
Hiseq_snp = total & Hiseq_snp
Hiseq_ref = total & Hiseq_ref
Hiseq_lowqual = total & Hiseq_lowqual
PB_snp = set(PB_snp)
PB_ref = set(PB_ref)
PB_lowqual = set(PB_lowqual)
a = len(Hiseq_snp & PB_snp)
b = len(Hiseq_ref & PB_snp)
c = len(Hiseq_lowqual & PB_snp)
d = len(Hiseq_snp & PB_ref)
e = len(Hiseq_ref & PB_ref)
f = len(Hiseq_lowqual & PB_ref)
g = len(Hiseq_snp & PB_lowqual)
h = len(Hiseq_ref & PB_lowqual)
i = len(Hiseq_lowqual & PB_lowqual)
Low_total = (g+h+i)/(a+b+c+d+e+f+g+h+i)
if (a+b) == 0:
PPV = "NA"
else:
PPV = a/(a+b)
PPV = "%.4f"%(PPV)
if (a+d) == 0:
TPR = "NA"
else:
TPR = a/(a+d)
TPR = "%.4f"%(TPR)
print(str(DP)+" :\n", a,b,c,"\n",d,e,f,"\n",g,h,i,"\n", file=outf2, sep='\t', end='\n')
print(DP, TPR, PPV, "%.4f"%Low_total, file=outf, sep='\t', end='\n')
with open("./depth_stat.txt", "w") as outf:
print("Depth", "TPR", "PPV", "Low_total", file=outf, sep='\t', end='\n')
outf2 = open("raw.txt", "w")
Hiseq_unified_variation_dict = read_hiseq_gvcf("./hiseq_call_gvcf/MHC_Hiseq.unified.gvcf.gz")
PB_non_CCS_variation_dict = read_gvcf("./non_CCS_PB_call_gvcf/MHC_non_CCS.unified.gvcf.gz")
show_dict_diff_DP(Hiseq_unified_variation_dict, PB_non_CCS_variation_dict, outf, outf2)
outf2
又碰到一個高級python語法:在雙層循環中如何退出外層循環? 我用了一個手動的flag,有其他好方法嗎?
如何統計下機數據的覆蓋度和深度?當然要比對之后才能統計,而且還要對比對做一些處理。
在計算一個位點是否是SNP、indel、Ref時,不僅要考慮ref、alts、qual、GQ,而且必須要把GT、DP考慮在內,所以說還是比較復雜的。
最后如何分析第二個問題,call variation的最低深度?
統計不同深度下的假陰假陽性率,看在什么深度下其達到飽和。
