在科學研究中處理高維數據的童鞋們,常常會遇到這種問題:我們明明知道自己的數據具有很好的內部特徵,卻無法找到合適的降維演算法展示出來。由於每一個樣品特徵內都可能會存在一些離散點,線性降維例如PCA、PCoA常常難以有效的區分不同的樣品特徵,而且忠實於相互距離的線性演算法往往難以獲得滿意的排序結果。這時候,你就需要更新自己的演算法庫啦!

這裡我們介紹一種非線性演算法,t分佈隨機鄰域嵌入(t-distributed stochastic neighbor embedding,t-SNE),是一種用於探索高維數據的非線性降維機器學習演算法。它將多維數據映射到適合於人類觀察的兩個或多個維度。PCA是一種線性演算法,它不能解釋特徵之間的複雜多項式關係。而t-SNE是基於在鄰域圖上隨機遊走的概率分佈來找到數據內的結構。線性降維演算法的一個主要問題是不相似的數據點放置在較低維度表示為相距甚遠,但為了在低維度用非線性流形表示高維數據,相似數據點必須表示為非常靠近,這不是線性降維演算法所能做的。

具體原理步驟如下所示:

隨機鄰接嵌入(SNE)從通過將數據點之間的高維歐幾裏得距離轉換為表示相似性的條件概率而開始,數據點xixj之間的條件概率pj|i由下式給出:

其中σi是以數據點xi為中心的高斯方差。對於高維數據點xixj的低維對應點yiyj而言,可以計算類似的條件概率qj|i

可以看出,SNE通過仿射(affinitie)變換將數據點映射到概率分佈上,將兩個數據點之間的歐式距離轉換為以一個點為中心一定範圍(也即高斯方差)內另一個點出現的條件概率。與線性演算法最小化低維與高維下距離差不同,SNE試圖最小化低維與高維下兩個分佈條件概率的差異,我們稱之為KL散度,目標函數也即兩個分佈的cost如下所示:

由cost函數可以看出,KL散度具有不對稱性,這主要通過最後對數相體現出來,高維下條件概率p與低維下條件概率q對調cost值就會不同,具體表現為該cost函數傾向於使用較大的q建模較小的p,也即會使原始數據中不同的特徵之間區分更加明顯,從而有效保留數據的局部特徵,因此,SNE演算法可以看成一種聚類簇識別演算法

SNE的代價函數關注於映射中數據的局部結構,優化該函數是非常困難的,因此在SNE的基礎上提出t-SNE,其在高維空間下使用高斯分佈將距離轉換為概率分佈,在低維空間下使用更加偏重長尾分佈的方式來將距離轉換為概率分佈,使得高維度下中低等的距離在映射後能夠有一個較大的距離,以減輕擁擠問題。

在最小化這個這兩個分佈的差異之後,我們最關心的是條件概率中涉及到的範圍也即高斯方差σ。有些特徵點周圍數據點是稀疏的,有些是緊密的(聚類簇的特徵不同),因此高斯方差大小也不同,因此定義困惑度:

其中H(Pi)是香農熵:

高斯方差σ越大,也即中心點周圍劃定的範圍越大,那麼其他點出現的條件概率的熵越大,那麼困惑度也越大。困惑度可以被解釋為一個點周圍有效近鄰點的數目。困惑度由用戶指定,典型值在5和50之間。

t-SNE非線性降維演算法通過基於具有多個特徵的數據點的相似性識別觀察到的簇來在數據中找到模式。本質上是一種降維和可視化技術。另外t-SNE的輸出可以作為其他分類演算法的輸入特徵。t-SNE幾乎可用於所有高維數據集,廣泛應用於圖像處理,自然語言處理,基因組數據和語音處理。在R中具有Rtsne包可以實現t-SNE分析,所使用的函數為Rtsne(X, ...),其中X為數據矩陣,每一行為一個記錄,Rtsne對行進行降維排序。

在生物學中,擴增子、宏基因組羣落組成數據以及宏基因組、基因組的功能注釋數據也可以使用t-SNE演算法進行分析,下面進行實例分析:

#讀取KEGG注釋數據
kegg=read.table("06_genome_module_complete_v4.txt", header=TRUE)
rownames(kegg)=kegg[,1]
kegg=kegg[,-1]
kegg=as.matrix(kegg)
#讀取分組與顏色配置文件
group=read.table("12_genome_group_col.txt", header=FALSE)
rownames(group)=group[,1]
col=read.table("12_genome_tax_col.txt", header=FALSE)
rownames(col)=col[,1]
#進行t-SNE分析
library(Rtsne)
kegg_tsne=Rtsne(kegg, dims=2, perplexity=40, check_duplicates=FALSE)
#繪製做圖結果
ggdata=data.frame(Dim1=kegg_tsne$Y[,1], Dim2=kegg_tsne$Y[,2],
Group=group[,3])
ggplot(ggdata) +
geom_point(aes(x=Dim1, y=Dim2, col=Group), size=3) +
scale_colour_manual(values=as.character(col[,2])) +
theme_classic() #使用經典坐標軸樣式

其中dims為降維後的維數,由用戶指定,一般為二維;perplexity為困惑度,由用戶指定,應該小於(nrow(X) - 1)/3。困惑度越小,得到的聚類簇越多、越分散;困惑度越大,得到的聚類簇越少、越集中。最終繪圖結果如下所示:

下面使用相同的數據進行PCA分析,可以對比兩者的差別:

kegg_pca=prcomp(kegg, scal=FALSE)
pc12=kegg_pca$x[, 1:2]/10
pca_sum=summary(kegg_pca)
pcap=as.vector(round(pca_sum$importance[2, 1:2], 3), mode="any")
pcapp=paste(pcap*100, "%",sep="")
pcap1=paste("PC1(", pcapp[1], ")", sep="")
pcap2=paste("PC2(", pcapp[2], ")", sep="")
ggdata=data.frame(pc12, Group=group[,3])
ggplot(ggdata) +
geom_point(aes(x=PC1, y=PC2, col=Group), size=3) +
scale_colour_manual(values=as.character(col[,2])) +
labs(x=pcap1,y=pcap2) + theme_classic() #使用經典坐標軸樣式

可以看到,相同數據集經過PCA分析不同聚類簇之間難以區分,而t-SNE則獲得了區分明顯的聚類簇,將數據集內部的結構特徵充分挖掘出來。那麼問題來了,既然困惑度由用戶指定,t-SNE根據用戶指定的困惑度探索最佳的降維方法,那麼用戶如何確定適合自己數據集的困惑度呢?在後續的文章中將會給出解答。

原文地址:什麼?你竟然還不知道t-SNE降維演算法!

歡迎關注公眾號「微生態與微進化」瞭解更多微生物生信分析技能!!


推薦閱讀:
相關文章