対応あり二群間比較(DESeq)

DESeq を利用して対応ありの二群間比較データを解析する例を示す。検定方法としては Wald 検定と尤度比検定の 2 種類がある。

library(DESeq)
packageVersion("DESeq")
## [1] ‘1.20.0’

サンプルデータ

サンプルデータは、カウントデータが負の二項分布に従うように乱数を生成して作成した。例えるならば、4 人の患者A、B、C、D から正常細胞とがん細胞のサンプルを採取し、正常細胞とがん細胞の比較を行う。サンプルデータをこのような構成で生成した。全遺伝子数は 1,000 個であり、その発現パターンは以下のように設定した。

遺伝子 正常細胞 がん細胞
gene_1 ~ gene_50 がん細胞に比べて高発現
gene_51 ~ gene_100 正常細胞に比べて高発現
gene_101 ~ gene_1000 発現量に差がない

サンプルデータを読み込んでから行列型に変換し、count 変数に代入する。


count <- read.table("https://bi.biopapyrus.net/data/count2gp.txt", sep = "\t", header = T, row.names = 1)
count <- as.matrix(count)

dim(count)
## [1] 1000    8

head(count)
##        N_A N_B N_C N_D T_A T_B T_C T_D
## gene_1   1   1   0   2   4   1  54   0
## gene_2 170 212 187 195 745 630 828 807
## gene_3   8  10  11  10  39  41  45  37
## gene_4  44  29  40  49 196 208 129 158
## gene_5   0   2   0   0   0   0   1   0
## gene_6  88  95 141 123 555 270 340 561

実験群の識別ラベルを作成し cell 変数に代入する。また、処理の識別ラベルを作成し patient 変数に保存する。ただし、DESeq では、多因子比較の際にデータフレーム型を要求するため、これらをデータフレームにまとめる。

group <- data.frame(
  cell = factor(c("N", "N", "N", "N", "T", "T", "T", "T")),
  patient = factor(c("A", "B", "C", "D", "A", "B", "C", "D"))
)

尤度比検定

対応ありの二群間比較においては、患者間の比較に興味がなく、正常細胞とがん細胞のような比較が目的である。一般化線形モデルによりこれを解析を行う方法について説明する。

尤度比検定では 2 つのモデルから尤度を計算し比較することによって、2 つのモデルに差があるかどうかを検定する方法である。リードカウントデータをモデル化することによって、尤度比検定を発現変動遺伝子の検出に応用できる。尤度比検定で比較する 2 つのモデルはそれぞれ full model と reduced model と呼ばれる。full model には多くのパラメーターを含み、reduced model は full model より少ないパラメーターをしか含まない。そのため、両者を比べることで、reduced model に含まれていないパラメーターの効果を調べることができる。生物実験において、野生型と遺伝子 g のノックアウト型を比較して、遺伝子 g の機能を調べることに似ている。

一般化線形モデルを利用してモデル化を行うとき、確率変数を Y とし、確率変数が従う分布のパラメーターを β とすると、Y の期待値は g(E[Y]) = と表すことができる。ただし、g はリンク関数である。リンク関数は期待値 E[Y] と右辺が等しくなるように変換を行う単調な関数であり、しかも、その形は決まっている。例えば、データの分布は正規分布ならば g(x) = x、負の二項分布ならば g(x) = log(x) である。そこで、以下、説明を簡略するためにリンク関数を省略して書く。

まず、full model について考える。患者 A の正常細胞の発現量の期待値を β1 とする。患者 A と患者 B、C、D の発現量の期待値の差をそれぞれ β2、β3、β4 とおく。また、正常細胞とがん細胞の発現量の期待値の差を β5 とおく。これにより E[A-Normal] = β1、E[B-Normal] = β1 + β2、E[A-Tumor] = β1 + β5 などである。これらを行列の形で表すと以下のようになる。(N: Normal; T: Tumor)

\[ \begin{pmatrix} E[\mbox{NA}] \\ E[\mbox{NB}] \\ E[\mbox{NC}] \\ E[\mbox{ND}] \\ E[\mbox{TA}] \\ E[\mbox{TB}] \\ E[\mbox{TC}] \\ E[\mbox{TD}] \end{pmatrix} ^{T} = \begin{pmatrix}1 & 0 & 0 & 0 & 0\\ 1 & 1 & 0 & 0&0\\ 1 & 0 & 1 & 0 & 0 \\ 1 & 0 & 0 & 1 & 0 \\ 1 & 0 & 0 & 0 &1 \\ 1 & 1 & 0 & 0 & 1\\ 1 & 0 & 1 & 0 & 1\\ 1 & 0 &0 &1 & 1 \end{pmatrix}\begin{pmatrix}\beta_{1} \\ \beta_{2} \\ \beta_{3} \\ \beta_{4} \\ \beta_{5}\end{pmatrix} \]

この式が一般化線形モデルのモデルとされる。0 と 1 からなる行列はデザイン行列と呼び、観測値とパラメーターを関連させる重要な働きを持つ。遺伝子が n 個があればこのような式は n 個できる。遺伝子が n 個あるときプログラムが逐次的に処理を行ってくれるため、遺伝子が 1 個だけの時を考えればよい。

このモデルを full model と呼ぶことにする。full model のデザイン行列は model.matrix 関数を利用すれば簡単に作成できる。

model.matrix(~ group$patient + group$cell)
##   (Intercept) group$patientB group$patientC group$patientD group$cellT
## 1           1              0              0              0           0
## 2           1              1              0              0           0
## 3           1              0              1              0           0
## 4           1              0              0              1           0
## 5           1              0              0              0           1
## 6           1              1              0              0           1
## 7           1              0              1              0           1
## 8           1              0              0              1           1
## attr(,"assign")
## [1] 0 1 1 1 2
## attr(,"contrasts")
## attr(,"contrasts")$`group$patient`
## [1] "contr.treatment"
## 
## attr(,"contrasts")$`group$cell`
## [1] "contr.treatment"

次に尤度比検定を行い発現変動遺伝子を検出する。尤度比検定では 2 つのモデルの尤度を比較して検定を行うために、上で作成した full model の他にもう 1 つのモデル reduced model を必要とする。

まず、目的は正常細胞とがん細胞の比較で差異のある遺伝子を検出したい。そこで帰無仮説としては正常細胞とがん細胞の発現量は同じで E[N] = E[T]、すなわち β5 = 0 とすることができる。β5 = 0 となるモデルを reduced model として、full model と比較し尤度比検定を行う。そこで、もし、両者の尤度に差異が認められるならば、full model と reduced model は相違異なるモデルと考えられる。full model と reduced model の差は β5 によってもたらしているから、両者に差異があるということは β5 ≠ 0 を意味する。しかし、これは帰無仮説である β5 = 0 に矛盾する。よって、帰無仮説は間違いであり、棄却するべきである。逆に、両者の尤度に差異がなければ帰無仮説は保留される。これが尤度比検定である。

reduced model は以下のように作成できる。

\[ \begin{pmatrix} E[\mbox{NA}] \\ E[\mbox{NB}] \\ E[\mbox{NC}] \\ E[\mbox{ND}] \\ E[\mbox{TA}] \\ E[\mbox{TB}] \\ E[\mbox{TC}] \\ E[\mbox{TD}] \end{pmatrix} ^{T} = \begin{pmatrix}1 & 0 & 0 & 0 \\ 1 & 1 & 0 & 0\\ 1 & 0 & 1 & 0 \\ 1 & 0 & 0 & 1 \\ 1 & 0 & 0 & 0 \\ 1 & 1 & 0 & 0 \\ 1 & 0 & 1 & 0 \\ 1 & 0 &0 &1 \end{pmatrix}\begin{pmatrix}\beta_{1} \\ \beta_{2} \\ \beta_{3} \\ \beta_{4} \end{pmatrix} \]

R では以下のように作成できる。full model に比べ 1 列少なくなっている。DESeq を利用している時、デザイン行列の列名で判断しているため、以下のデザイン行列には group$cellT が含まれていないため、それに対応している β5 が自動的考慮されなくなる。パラメーターがずれることはない。

model.matrix(~ group$patient)
##   (Intercept) group$patientB group$patientC group$patientD
## 1           1              0              0              0
## 2           1              1              0              0
## 3           1              0              1              0
## 4           1              0              0              1
## 5           1              0              0              0
## 6           1              1              0              0
## 7           1              0              1              0
## 8           1              0              0              1
## attr(,"assign")
## [1] 0 1 1 1
## attr(,"contrasts")
## attr(,"contrasts")$`group$patient`
## [1] "contr.treatment"

ここで、full model は ~ group$patient + group$cell、reduced model は ~ group$patient で作成できることがわかった。そこで、DESeq を利用してこの 2 つのモデルを比較し、両モデルに差をもたらす遺伝子を検出する。コードは以下のように実行する。nbinomLRT 関数を実行するときに full model と reduced model の式を代入する。ただし、このとき、group 変数は一番最初に colData = group と代入してあるため、group$cellgroup$patient はそれぞれ略してそれぞれ cellpatient とだけにする。

cds <- newCountDataSet(countData = count, conditions = group)
cds <- estimateSizeFactors(cds)
cds <- estimateDispersions(cds)
## Error in fitNbinomGLMs(cds, count ~ patient) : 
##   Call 'estimateDispersions' with 'method="pooled"' (or 'blind') first.

biological replicate が存在しないために method = "blind" と指定して下さい、とエラーが起きる。パラメーターを調整して再実行する。

cds <- estimateDispersions(cds, method = "blind")
f.model <- fitNbinomGLMs(cds, count ~ patient + cell)
r.model <- fitNbinomGLMs(cds, count ~ patient)
## Warning message:
## In fitNbinomGLMs(cds, count ~ patient) :
##   You have used 'method="blind"' in estimateDispersion without also
##   setting 'sharingMode="fit-only"'. This will not yield useful results.

method = "blind"sharingMode = "fit-only" を同時に利用するとよいと警告される。そこで、スクリプぷとをすべて修正して、以下のように実行すれば良い。

cds <- newCountDataSet(countData = count, conditions = group)
cds <- estimateSizeFactors(cds)
cds <- estimateDispersions(cds, method = "blind", sharingMode = "fit-only")
f.model <- fitNbinomGLMs(cds, count ~ patient + cell)
r.model <- fitNbinomGLMs(cds, count ~ patient)
res <- nbinomGLMTest(f.model, r.model)
names(res) <- rownames(count)
head(res[order(res)], n = 20)
##      gene_95      gene_46      gene_32      gene_45      gene_14     gene_421 
## 6.071033e-12 3.588739e-09 1.330392e-07 2.766404e-07 1.848532e-06 4.551059e-06 
##      gene_16      gene_62      gene_52      gene_82      gene_36      gene_31 
## 5.185721e-06 5.350383e-06 7.492034e-06 8.301709e-06 9.062814e-06 9.822792e-06 
##      gene_48      gene_99      gene_61       gene_9     gene_833      gene_50 
## 1.374755e-05 2.201605e-05 3.041909e-05 3.908558e-05 4.388223e-05 7.450040e-05 
##      gene_83      gene_21 
## 7.862438e-05 9.803385e-05 

正常細胞とがん細胞の比較における発現変動遺伝子は gene_1 ~ gene_100 に設定してある。解析結果を見ると上位にランキングされている遺伝子はすべてこの範囲に入っている。

解析結果を整形して、result.txt ファイルに保存する。

table <- data.frame(
  gene.name = rownames(count),
  p.value = res,
  q.value = p.adjust(res, method = "BH")
)
write.table(table, file = "result.txt", col.names = T, row.names = F, sep = "\t")

References