и его применение в биоинформатике
Лекция 12
Анна Валяева
24 ноября 2025
Пример задачи: как изучаемое вещество X влияет на профиль экспрессии генов в клеточной линии HeLa?
Для работы “с нуля” необходимы:
Задача: узнать, экспрессия каких генов изменилась в ответ на воздействие (treatment) по сравнению с контролем (control).
При этом в каждой группе как минимум 2 биологических повторности!
Сравнивать между образцами можно только нормированную экспрессию.
CPM (Counts Per Million)
\(CPM = \frac{Number \space of \space reads \space mapped \space to \space gene \space × \space 10^6}{Total \space number \space of \space mapped \space reads \space}\)
RPKM (Reads Per Kilobase Million), FPKM (Fragments Per Kilobase Million)
\(RPKM = \frac{Number \space of \space reads \space mapped \space to \space gene \space × 10^3 × \space 10^6}{Total \space number \space of \space mapped \space reads \space × Gene \space length \space in \space bp}\)
TPM (Transcripts Per Kilobase Million)
\(TPM = A \space × \space \frac{1}{\sum(A)} \space × \space 10^6\), где \(A = \frac{Total \space reads \space mapped \space to \space gene \space × \space 10^3}{Gene \space length \space in \space bp}\)
Средний уровень экспрессии в группе CTRL = 5
Средний уровень экспрессии в группе TRT = 10
\(Fold \space Change = \frac{mean \space expession_{treatment}} {mean \space expession_{control}} = \frac{10} {5} = 2\)
\(log_2FoldChange = log_2(\frac{mean \space expession_{treatment}} {mean \space expession_{control}}) = log_2(\frac{10} {5}) = 1\)
Экспрессия повышена в 2 раза: \(log_2FoldChange = 1\)
Экспрессия не изменилась: \(log_2FoldChange = 0\)
Экспрессия понижена в 2 раза: \(log_2FoldChange = -1\)
\(log_2FoldChange = 1\)
Но насколько статистически значим этот результат?
Не могли ли мы его наблюдать по случайным причинам, например, из-за технического или биологического шума?
Проведем статистический тест Манна-Уитни. В результате теста получили p-значение 0.056.
Что это значит?
P-значение - вероятность получить результат такой же, как видим сейчас, или еще экстремальней, при условии что нулевая гипотеза верна.
Нулевая гипотеза
\(H_0\) - принимаемое по умолчанию скептическое предположение о том, что эффекта нет.
В контексте анализа дифф экспрессии: \(H_0\) - настоящее значение \(log_2FoldChange\) равно 0.
Альтернативная гипотеза
\(H_1\), или \(H_A\) - альтернативное предположение о том, что эффект есть.
Более экстремальный результат - более маловероятный.
Если p-значение меньше заданного уровня значимости α (обычно 0.05), то нулевая гипотеза отвергается в пользу альтернативной - эффект есть.
Если p-значение больше α, то нет оснований отвергнуть нулевую гипотезу.
Уровень значимости выбирается заранее. Он контролирует вероятность ошибки I рода - вероятность ошибочно отвергнуть истинную нулевую гипотезу.
Наша задача - найти дифф экспрессируемые гены среди всех ненулевых генов.
Всего ненулевых генов ~10,000. К каждому гену мы применяем статистический тест. Даже если никаких настоящих изменений в экспрессии всех генов нет, просто из-за случайных причин примерно 5% тестов дадут p < 0.05.
Проблема множественного тестирования: чем больше тестов - тем больше шанс случайно найти “значимый” результат.
Нужно применять поправки на множественное тестирование!
Для анализа дифф экспрессии по данным РНК секвенирования разработаны специальные алгоритмы, учитывающие:
Если выборки большие, например, большие когорты больных и здоровых людей или десятки тысяч клеток в эксперименте по секвенированию единичных клеток, можно использовать универсальные тесты, например, критерий Манна-Уитни (Wilcoxon rank-sum test).
spc_tbl_ [43,346 × 10] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
$ GeneId : chr [1:43346] "ENSMUSG00000102693" "ENSMUSG00000064842" "ENSMUSG00000051951" "ENSMUSG00000102851" ...
$ GeneName: chr [1:43346] "RP23-271O17.1" "Gm26206" "Xkr4" "RP23-317L18.1" ...
$ Young_1 : num [1:43346] 0 0 2 0 0 0 0 4 0 0 ...
$ Young_2 : num [1:43346] 0 0 3 0 0 0 0 1 0 1 ...
$ Young_3 : num [1:43346] 0 0 1 0 0 0 0 3 0 0 ...
$ Young_4 : num [1:43346] 0 0 2 0 0 0 0 0 0 0 ...
$ Old_1 : num [1:43346] 0 0 2 0 0 0 0 1 0 1 ...
$ Old_2 : num [1:43346] 0 0 0 0 0 0 0 0 0 0 ...
$ Old_3 : num [1:43346] 0 0 2 0 0 0 0 0 0 0 ...
$ Old_4 : num [1:43346] 0 0 1 0 0 0 0 0 0 0 ...
Для ускорения работы DESeq2 можно заранее исключить гены с низкой и нулевой экспрессией. В некоторых случаях стоит исключить топ высоко-экспрессируемых генов.
Программы, использующие псевдовыравнивание на транскриптом, выдают значения экспрессии для транскриптов.
# Создаем таблицу соотвествия транскрипт-ген
library(TxDb.Mmusculus.UCSC.mm10.knownGene)
txdb <- TxDb.Mmusculus.UCSC.mm10.knownGene
k <- keys(txdb, keytype = "TXNAME")
tx2gene <- select(txdb, k, "GENEID", "TXNAME")
# Получаем список файлов kallisto
k_files <- list.files(
file.path(data_dir, "kallisto"),
pattern = "abundance.tsv",
recursive = TRUE, full.names = TRUE)
names(k_files) <- paste0("sample", 1:6)
# Агрегируем экспрессию транскриптов
BiocManager::install("tximport")
library(tximport)
txi <- tximport(k_files, type = "kallisto", tx2gene = tx2gene)
# Создаем DESeq-объект
dds <- DESeqDataSetFromTximport(
txi,
colData = coldata,
design = ~ Mouse)\[s_{j} = \underset{i}{median}{k_{ij} \over (\prod_{v=1}^m k_{iv})^{1/m}}\]
Основано на допущении: лишь относительно небольшое число генов действительно дифференциально экспрессируются.
\(Normalized\ counts_{j} = {Raw\ counts_{j} \over s_{j}}\)
[1] 1.0488580 1.1423301 0.6885799 0.8511961 1.3068077 1.1323248 0.9218329
[8] 1.0793817
Young_1 Young_2
RP23-271O17.1 0.000000 0.0000000
Gm26206 0.000000 0.0000000
Xkr4 1.906836 2.6262111
RP23-317L18.1 0.000000 0.0000000
RP23-317L18.4 0.000000 0.0000000
RP23-317L18.3 0.000000 0.0000000
RP23-115I1.6 0.000000 0.0000000
Gm1992 3.813671 0.8754037
RP23-115I1.5 0.000000 0.0000000
RP23-115I1.2 0.000000 0.8754037
Для визуализации каунты трансформируют, чтобы сделать дисперсию “примерно одинаковой” для всех генов, независимо от их уровня экспрессии:
rlog() - regularized log transformationvst() - variance stabilizing transformationПоэтому лучше секвенировать больше повторностей на всякий случай.
Переменную batch можно добавить в формулу для модели DESeq2.
Bulk RNA-seq эксперименты часто включают всего несколько биологических реплик образцов, поэтому по небольшой выборке точно оценить дисперсию экспрессии каждого гена проблематично. Дисперсия оценивается по множеству генов со схожим уровнем экспрессии.
Formal class 'DESeqResults' [package "DESeq2"] with 7 slots
..@ priorInfo : list()
..@ rownames : chr [1:43346] "RP23-271O17.1" "Gm26206" "Xkr4" "RP23-317L18.1" ...
..@ nrows : int 43346
..@ elementType : chr "ANY"
..@ elementMetadata:Formal class 'DFrame' [package "S4Vectors"] with 6 slots
.. .. ..@ rownames : NULL
.. .. ..@ nrows : int 6
.. .. ..@ elementType : chr "ANY"
.. .. ..@ elementMetadata: NULL
.. .. ..@ metadata : list()
.. .. ..@ listData :List of 2
.. .. .. ..$ type : chr [1:6] "intermediate" "results" "results" "results" ...
.. .. .. ..$ description: chr [1:6] "mean of normalized counts for all samples" "log2 fold change (MLE): Mouse Young vs Old" "standard error: Mouse Young vs Old" "Wald statistic: Mouse Young vs Old" ...
..@ metadata :List of 6
.. ..$ filterThreshold: Named num 4.45
.. .. ..- attr(*, "names")= chr "60.27064%"
.. ..$ filterTheta : num 0.603
.. ..$ filterNumRej :'data.frame': 50 obs. of 2 variables:
.. .. ..$ theta : num [1:50] 0.401 0.412 0.423 0.435 0.446 ...
.. .. ..$ numRej: num [1:50] 733 744 750 754 755 768 785 795 798 807 ...
.. ..$ lo.fit :List of 2
.. .. ..$ x: num [1:50] 0.401 0.412 0.423 0.435 0.446 ...
.. .. ..$ y: num [1:50] 734 741 748 756 764 ...
.. ..$ alpha : num 0.1
.. ..$ lfcThreshold : num 0
..@ listData :List of 6
.. ..$ baseMean : num [1:43346] 0 0 1.62 0 0 ...
.. ..$ log2FoldChange: num [1:43346] NA NA 0.895 NA NA ...
.. ..$ lfcSE : num [1:43346] NA NA 1.15 NA NA ...
.. ..$ stat : num [1:43346] NA NA 0.78 NA NA ...
.. ..$ pvalue : num [1:43346] NA NA 0.435 NA NA ...
.. ..$ padj : num [1:43346] NA NA NA NA NA NA NA NA NA NA ...
res %>% as.data.frame() %>%
mutate(gene = rownames(.)) %>%
select(gene, log2FoldChange, padj) %>%
drop_na(padj) %>%
filter(padj < 0.05) %>%
arrange(desc(abs(log2FoldChange))) %>% head() gene log2FoldChange padj
Krt8 Krt8 -7.854023 1.173674e-06
Krt18 Krt18 -7.791874 6.866451e-23
Astl Astl -5.908037 3.180374e-04
Fgf21 Fgf21 -5.892606 1.383096e-05
Prrt3 Prrt3 -5.576513 1.103255e-02
Gm15935 Gm15935 -5.530609 2.381310e-05
Данные: GSE184348 (Zhang et al., 2022)