Introduction: le jeu de Den Boer 2009

Comme cas d’étude, nous analyserons un jeu de données de Den Boer et collègues [@DenBoer:2009ik].

Les auteurs ont caractérisé le transcriptome de 190 patients souffrand de leucémie lymphoblastique aigue (Acute Lymphoblastic Leukaemia, ALL).

Cette leucémie est caractérisée par une prolifération clonale anormale, dans la moëlle osseuse, de progéniteurs de lymphocytes qui restent bloqués dans une phase précise de leur différenciation. La prolifération peut résulter de différentes mutations, dont certaines sont récurrentes chez différents patients. Le jeu de données de Den Boer inclut l’information concernant les problèmes génétiques particuliers associés à chaque échantillon d’un patient atteint de leucémie.

Dans leur article original, Den Boer et collègues ont défini une signature transcriptomique, c’est-à-dire une sélection de gènes dont les profils de transcription sont spécifiquement affectés dans une ou plusieurs sous-classes des leucémies. Les profils d’expression de ces gènes-signature peuvent ensuite être utilisés pour classer de nouveaux échantillons de patients atteints de leucémie, et prédire le type de perturbation génétique associée à leur cas.

Un avantage de ce jeu de données est qu’il inclut des groupes d’effectifs relativement élevés (4 groupes avec >30 patients), par rapport à d’autres publications dans le domaine de l’analyse transcriptomique.

Le tableau de donnée sur lequel nous travaillerons comporte 190 colonnes (une par patient) et ~22.000 lignes (une par gène) et les valeurs indiquent le niveau d’expression du gène chez le patient considéré.

On dispose également d’une table “pheno” qui fournit des informations sur chaque échantillon, et en particulier la classe de leucémie dont souffre ce patien (en fait cette classe est déterminée par son génotype plutôt que son phénotype, mais pour des raisons historiques les tableaux annotations des échantillons sont communément dénommés “pheno” dans le domaine des biopuces).

But du TP

Le but de ce TP sera de mettre en place une procédure qui combinera les tâches suivants:

  1. Télécharger les fichiers de données à partir d’un site Web.
  2. Mesurer une série de paramètres statistiques sur les gènes (lignes) et échantillons (colonnes).
  3. Détecter les gènes différentiellement exprimés entre deux groupes d’échantillons (correspondant à deux classes de leucémie).

Nous essaierons pour chaque étape - de modulariser le code en écrivant des fonctions ré-utilisables - d’utiliser des techniques efficaces en évitant les boucles, et en utilisant plutôt la fonction apply()

Exercices

Créaction d’un dossier local pour les données et résultats

  1. Ecrivez un bloc de code R qui définit (dans une variable dénommé dir.output) le chemin d’un dossier où vous sauvegarderez les données et les résultats de ce TP. Ce dossier sera défini comme un sous-dossier STAT/TP/DenBoer2009 à partir de la racine de votre compte. Créez ce dossier (sauf s’il existe déjà) et vérifiez son contenu en fichiers.

    Fonctions utiles:

    • Sys.getenv("HOME") indiquera la racine de votre compte (Unix et Mac OS X)
    • file.path() permet de construire un chemin en concaténant des chaînes de caractères
    • dir.create() pour créer un dossier. Lisez l’aide pour choisir les options appropriées.
    • list.files() pour obtenir la liste des fichiers dans un dossier donné
## Define the directory for the practical
dir.home <- Sys.getenv("HOME")
dir.output <- file.path(dir.home, "STAT", "TP", "DenBOer2009")
message(dir.output)
## Create the directory
dir.create(dir.output, recursive = TRUE, showWarnings = FALSE)
## Change directory to dir.output
setwd(dir.output)
## Print a message with output directory
message("Output directory for this practical: ", dir.output)
## Check it this directory already contains some files.
list.files(dir.output)

Si c’est la première fois que vous réalisez ce TP, la réponse devrait être

character(0)

Ceci indique que le dossier que vous venez de créer ne contient aucun fichier. Le résultat de list.files() est un vecteur contenant 0 chaînes de caractères.

Téléchargement des données

Créez un sous-dossier data dans votre dossier TP, et téléchargez-y les deux fichiers de données ci-dessous, sauf si ces fichiers existent déjà à cet endroit.

URL du dossier des données de Den Boer:

Dans ce dossier nous utiliserons les deux tables suivantes.

Vous pouvez éventuellement utiliser le fichier de Description des sous-types de cancers (abréviation, couleurs d’affichage):

Le dossier contient également un fichier de qualité des mesures (absent / marginal / présent), que nous ignorerons pour ce TP-ci:

Vous trouverez ci-dessous le code pour télécharger une copie des fichiers utiles dans votre dossier personnel.

Le bloc de code ci-dessous définit l’URL du dossier de données, à partir duquel nous allons télécharger la table de transcriptome + la description des échantillons (pheno).

## Define the URL of the example data sets
url.course <- "http://pedagogix-tagc.univ-mrs.fr/courses/ASG1"
microarray.data.url <- file.path(url.course, "data", "marrays")
## Check the results
print(paste("Course URL: ", url.course))
[1] "Course URL:  http://pedagogix-tagc.univ-mrs.fr/courses/ASG1"
print(paste("URL for the microarray data folder: ", microarray.data.url))
[1] "URL for the microarray data folder:  http://pedagogix-tagc.univ-mrs.fr/courses/ASG1/data/marrays"

Nous allons maintenant charger la matrice d’expression, fournie dans le fichier GSE13425_Norm_Whole.txt dans le dossier Den Boer du serveu. Ce fichier contient un tableau avec 1 ligne par gène1 et 1 colonne par échantillon. Chaque échantillon provient d’un patient souffrant de leucémie lymphoblatique aiguë (ALL).

We will once use the following functions:

  • file.path() to build the full URL to the expression table
  • download.file() to download the file from the URL and obtain a local copy. This will avoid us to download the whole file each time we restart the analysis.
  • read.table() to read the table from this URL. Note that this functions allows you to load a table either from a local folder (on your computer), or from any Web site.
## Get some help about the read.table fonction
# help(read.table)
## URL of the expression table on the course server
expr.url <- file.path(microarray.data.url, "GSE13425_Norm_Whole.txt") ## Build the full URL of the matrix
## Load expression values
dir.data <- file.path(dir.output, "data")
dir.create(dir.data, recursive = TRUE, showWarnings = FALSE)
expr.file <- file.path(dir.data, "DenBoer_2009_GSE13425_Norm_Whole.txt")
if (file.exists(expr.file)) {
message("Expression file already downloaded: ", expr.file)
} else {
message("Downloading matrix table from ", expr.url)
download.file(url = expr.url, destfile = expr.file)
message("Local expression file: ", expr.file)
}
## Load the expression table in memory
message("Loading expression table from ", expr.file)
expr.matrix <- read.table(expr.file,sep="\t", header = T, row.names = 1)

Exercices

  1. Adaptez le code ci-dessus pour télécharger une copie locale du fichier pheno.
## Get some help about the read.table fonction
# help(read.table)
## URL of the pheno table on the course server
pheno.url <- file.path(microarray.data.url, "phenoData_GSE13425.tab") ## Build the full URL of the matrix
## Load pheno values
pheno.file <- file.path(dir.data, "phenoData_GSE13425.tab")
if (file.exists(pheno.file)) {
message("pheno file already downloaded: ", pheno.file)
} else {
message("Downloading matrix table from ", pheno.url)
download.file(url = pheno.url, destfile = pheno.file)
message("Local pheno file: ", pheno.file)
}
## Load the pheno table in memory
message("Loading pheno table from ", pheno.file)
pheno.matrix <- read.table(pheno.file,sep="\t", header = T, row.names = 1)
# View(pheno.matrix)
## Check that the order ofthe pheno table rows is identifcal to the order of the columns in the expression table. For this, we count the number of differences
sum(colnames(expr.matrix) != rownames(pheno.matrix))
[1] 0
  1. Chargez les fichiers d’expression et de description des échantillons dans des objets de type data.frame(), et récupérez dans un vecteur les sous-types de cancer associés à chaque échantillon.

  2. Comptez le nombre d’échantillons par sous-classe de cancer.

# View(pheno.matrix)
sample.labels <- as.vector(pheno.matrix$sample.labels)
class.sizes <- sort(table(sample.labels), decreasing = TRUE)
  1. Sélectionnez deux groupes comportant au moins 30 échantillons chacun, et créez une table d’expression et une table pheno limitées à ces deux groupes. A partir de ce moment vous travaillerez systématiquement avec ces deux tables.
## Select the labels of the two most populated classes
group1 <- names(class.sizes[1])
group2 <- names(class.sizes[2])
## Select the columns of the expression matrix for each group
group1.expr <- expr.matrix[, sample.labels == group1]
dim(group1.expr)
[1] 22283    44
group2.expr <- expr.matrix[, sample.labels == group2]
dim(group2.expr)
[1] 22283    44
selected.samples <- (sample.labels == group1) | (sample.labels == group2)
group.labels <- sample.labels[selected.samples]
  1. En utilisant la fonction apply(), calculez pour chaque gène les paramètres suivants, et stockez-les dans une data.frame().

    • \(m_1, m_2\) moyennes d’échantillons des deux groupes;
    • \(s_2.est, s_2.est\) estimations des écarts-types des populations dont sont extraits les échantillons du 1er et 2d groupe, respectivement;
    • \(d\) différence entre les moyennes des deux groupes.
gene.stats <- data.frame(
m1 = apply(group1.expr, 1, mean),
m2 = apply(group2.expr, 1, mean),
s1.pop = apply(group1.expr, 1, sd),
s2.pop = apply(group2.expr, 1, sd)
)
gene.stats$d <- gene.stats$m2 - gene.stats$m1
# View(gene.stats)
hist(gene.stats$d, breaks=100)

  1. Sélectionnez un gène au hasard, récupérez dans un vecteur la ligne correspondante dans la table d’expression, et effectuez un test de comparaison de moyennes entre les deux groupes.
## Number of genes
my.gene <- sample(x = row.names(expr.matrix), size = 1)
welch.result <- t.test(x = group1.expr[my.gene, ], y = group2.expr[my.gene,], alternative = "two.sided", var.equal = FALSE)
## Get all the attributes of the t.test() result
attributes(welch.result)
$names
[1] "statistic"   "parameter"   "p.value"     "conf.int"    "estimate"    "null.value"  "alternative" "method"      "data.name"  

$class
[1] "htest"
result <- c(welch.result$statistic,
p = welch.result$p.value,
welch.result$parameter,
welch.result$estimate)
names(result) <- c("t", "p", "df", "m1", "m2")
result["d"] <- result["m2"] - result["m1"]
  1. Ecrivez une fonction R dénommée t.test.wrapper qui prend en entrée 2 vecteurs (expression et classes de cancer, respectivement), effectue un test de Student, et retourene un vecteur avec les statistiques pertinentes.
TTestVector <- function(values, group.labels, group1 = group.labels[1], ...) {
## Select samples of the first and second group, respectively
group1.values <- values[group.labels == group1]
group2.values <- values[group.labels != group1]
t.result <- t.test(x = group1.values, y = group2.values, ...)
## Collect the relevant statistics in the t.test result
result <- c(t.result$statistic,
p = t.result$p.value,
t.result$parameter,
t.result$estimate)
names(result) <- c("t", "p", "df", "m1", "m2")
result["d"] <- result["m2"] - result["m1"]
result["s1.est"] <- sd(group1.values)
result["s2.est"] <- sd(group2.values)
result["s.diff"] <- result["s2.est"] - result["s1.est"]
result["s.diff.percent"] <- 100*result["s.diff"] /max(result["s2.est"], result["s1.est"])
return(result)
}
## Run Welch test with my nice function
my.gene <- sample(x = row.names(expr.matrix), size = 1)
welch.result <- TTestVector(values = expr.matrix[my.gene,selected.samples],
group.labels = sample.labels[selected.samples],
alternative = "two.sided", var.equal = FALSE)
## Just for fun, run a Student test with the same gene
student.result <- TTestVector(values = expr.matrix[my.gene,selected.samples],
group.labels = sample.labels[selected.samples],
alternative = "two.sided", var.equal = TRUE)
## Compare the results obtained with Student and Welch t.test()
kable(data.frame(
Welch= welch.result,
Student = student.result), caption="Comparison between the results of a Welch and Student test on a randomly picked up gene. ")
Comparison between the results of a Welch and Student test on a randomly picked up gene.
Welch Student
t -1.1466819 -1.1466819
p 0.2547756 0.2546935
df 83.8280890 86.0000000
m1 3.5309091 3.5309091
m2 3.5784091 3.5784091
d 0.0475000 0.0475000
s1.est 0.2093491 0.2093491
s2.est 0.1779723 0.1779723
s.diff -0.0313768 -0.0313768
s.diff.percent -14.9877837 -14.9877837
  1. Ecrivez une boucle forqui applique ce même test à chaque ligne de la table d’expression, et récupère dans un tableau les résultats du test, avec une ligne par gène, une colonne par statistique pertinente produite par t.test(). Mesurez le temps d’exécution des 22.000 tests de Student avec cette boucle.
## Prepare a data frame to host all the results, with one row per gene
## and one column per field in the result of TTestVector
## (we use the previous result to adapt the number of columns.
welch.loop <- data.frame(matrix(nrow = nrow(expr.matrix), ncol=length(welch.result)))
names(welch.loop) <- names(welch.result) ## Set column names from previous result
row.names(welch.loop) <- row.names(expr.matrix) ## Set row names as gene names
head(welch.loop) ## Check that the data frame has the right shape and contains NA values
                  t  p df m1 m2  d s1.est s2.est s.diff s.diff.percent
DDR1|1007_s_at   NA NA NA NA NA NA     NA     NA     NA             NA
RFC2|1053_at     NA NA NA NA NA NA     NA     NA     NA             NA
HSPA6|117_at     NA NA NA NA NA NA     NA     NA     NA             NA
PAX8|121_at      NA NA NA NA NA NA     NA     NA     NA             NA
GUCA1A|1255_g_at NA NA NA NA NA NA     NA     NA     NA             NA
UBA7|1294_at     NA NA NA NA NA NA     NA     NA     NA             NA
## Run a
loop.time <- system.time(
for (my.gene in rownames(group1.expr)) {
welch.loop[my.gene,] <- TTestVector(
values=expr.matrix[my.gene, selected.samples],
group.labels = sample.labels[selected.samples],
alternative = "two.sided", var.equal = FALSE)
}
)
print(loop.time)
   user  system elapsed 
102.012  22.517 125.399 
  1. Utilisez cette fonction et la fonction apply pour appliquer le test de Student à chaque gène, et mesurz le temps d’exécution.
## Run all the t tests with the apply function
apply.time <- system.time(
welch.apply <- as.data.frame(t(apply(X = expr.matrix[, selected.samples], 1, TTestVector, group.labels = sample.labels[selected.samples], group1 = group1, alternative = "two.sided", var.equal = FALSE)))
)
print(apply.time)
   user  system elapsed 
  8.258   0.058   8.462 
kable(head(welch.apply), caption = "First rows of the table resulting from the application of Welch test to each gene. ")
First rows of the table resulting from the application of Welch test to each gene.
t p df m1 m2 d s1.est s2.est s.diff s.diff.percent
DDR1|1007_s_at -0.2044225 0.8386294 68.50664 4.679091 4.697045 0.0179545 0.2897458 0.5054428 0.2156970 42.674858
RFC2|1053_at -0.2171182 0.8286358 85.12354 3.132954 3.142727 0.0097727 0.2001230 0.2215733 0.0214503 9.680902
HSPA6|117_at -1.8028725 0.0758283 68.16601 2.563864 2.662955 0.0990909 0.1801836 0.3169446 0.1367610 43.149814
PAX8|121_at -0.5359874 0.5933759 84.46846 6.160682 6.179318 0.0186364 0.1517096 0.1737199 0.0220103 12.669978
GUCA1A|1255_g_at -1.2019848 0.2327599 83.68006 2.165000 2.188636 0.0236364 0.0842063 0.0996177 0.0154114 15.470531
UBA7|1294_at -6.0525510 0.0000000 77.01918 5.365682 5.854546 0.4888636 0.3074304 0.4387851 0.1313546 29.935985
## Nice formatting for the knit report (a bit tricky, because proc_time)
time.frame <- data.frame(
loop = as.factor(loop.time),
apply = as.factor(apply.time)
)
time.frame$loop <- as.numeric(as.vector(as.factor(loop.time)))
time.frame$apply <- as.numeric(as.vector(as.factor(apply.time)))
kable(time.frame, caption = paste("Time spent for", nrow(group1.expr), "Welch tests with apply:", apply.time), digits=3)
Time spent for 22283 Welch tests with apply: 8.25800000000001 Table: Time spent for 22283 Welch tests with apply: 0.0579999999999998 Table: Time spent for 22283 Welch tests with apply: 8.46199999999999 Table: Time spent for 22283 Welch tests with apply: 0 Table: Time spent for 22283 Welch tests with apply: 0
loop apply
user.self 102.012 8.258
sys.self 22.517 0.058
elapsed 125.399 8.462
user.child 0.000 0.000
sys.child 0.000 0.000

Exercice supplémentaire optionnel: à titre de curiosité, nous pouvons également appliquer le test de Student au même jeu de données (en combinant apply() et TTestVector()) et comparer (sur un graphe aux axes logarithmiques) les p-valeurs obtenues par Welch et Student, respectivement.

## Run all the t tests with the apply function
student.apply.time <- system.time(
student.apply <- as.data.frame(t(apply(X = expr.matrix[, selected.samples], 1, TTestVector, group.labels = sample.labels[selected.samples], group1 = group1, alternative = "two.sided", var.equal = TRUE)))
)
kable(head(student.apply), caption = "First rows of the table resulting from the application of Student test to each gene. ")
First rows of the table resulting from the application of Student test to each gene.
t p df m1 m2 d s1.est s2.est s.diff s.diff.percent
DDR1|1007_s_at -0.2044225 0.8385063 86 4.679091 4.697045 0.0179545 0.2897458 0.5054428 0.2156970 42.674858
RFC2|1053_at -0.2171182 0.8286305 86 3.132954 3.142727 0.0097727 0.2001230 0.2215733 0.0214503 9.680902
HSPA6|117_at -1.8028725 0.0749109 86 2.563864 2.662955 0.0990909 0.1801836 0.3169446 0.1367610 43.149814
PAX8|121_at -0.5359874 0.5933509 86 6.160682 6.179318 0.0186364 0.1517096 0.1737199 0.0220103 12.669978
GUCA1A|1255_g_at -1.2019848 0.2326688 86 2.165000 2.188636 0.0236364 0.0842063 0.0996177 0.0154114 15.470531
UBA7|1294_at -6.0525510 0.0000000 86 5.365682 5.854546 0.4888636 0.3074304 0.4387851 0.1313546 29.935985
print(apply.time)
   user  system elapsed 
  8.258   0.058   8.462 
plot(welch.apply[, "p"], student.apply[, "p"], log="xy")

10. Dessinez un volcano plot avec les résultats.

Le volcano plot indique en abscisse la "taille d'effet" (dans notre cas, la différence de moyennes), et l'ordonnée  $-log_{10}(p)$, où $p$ est la p-valeur.
## Define the threshold on p-value
alpha <- 0.05 ## Adopté à l'unanimité par les étudiants
## Draw a XY plot with the difference between means (X) versus the p-value
plot(welch.apply$d, welch.apply$p, xlab="m2 - m1", ylab="p", col="grey")
abline(v=0)
abline(h=alpha, col="red")

## Draw a volcano plot with Welch results
plot(welch.apply$d, -log10(welch.apply$p), xlab="m2 - m1", ylab="-log10(p)", col="grey", main="Volcano plot of the nominal p-values")
abline(v=0)
abline(h=-log10(alpha), col="red")

  1. Dessinez un histogramme des p-valeurs.
## Histogram of p-values for Den Boer 2009 expression matrix
hist(welch.apply$p, breaks=seq(from=0, to=1, by=0.05), main="P-value histogram", xlab="P-value", ylab="Nb genes", las=1, col="#BBDDFF")

Exercices supplémentaires:

a. Générez une matrice de données aléatoires de la même taille que la matrice d'expression, où chaque ligne comporte des données normales sous hypothèse nulle ($H_0: \mu_1 = \mu_2$). Effectuez le test de Student et dessinez le volcano plot et l'histogramme des p-valeurs. A titre d'exemple, choisissons $\mu_1 = \mu_2 = 0$, $\sigma_1 = \sigma_2 = 1$. 
b. Générez de la même façon une autre matrice de données sous hypothèse alternative, avec $\mu_1 = 0$, $\mu_2 = 2$, $\sigma_1 = \sigma_2 = 1$, effectuez un test de Student et dessinez le volcano plot et l'histogramme des p-valeurs. 
c. Sélectionnez 15000 lignes de la première matrice (sous $H_0$), 5000 lignes de la seconde (sous $H_A$), effectuez les tests de Student et dessinez le volcano plot et l'histogramme des p-valeurs.
## Get the dimensions of the expresion matrix
g <- nrow(expr.matrix) ## number of genes
s <- ncol(expr.matrix) ## Number of samples
## Generate a matrix with random data under H0
rand.h0 <- matrix(nrow=g, ncol=s, data = rnorm(n = g * s))
student.under.h0 <- as.data.frame(t(apply(X = rand.h0[, selected.samples], 1, TTestVector, group.labels = sample.labels[selected.samples], group1 = group1, alternative = "two.sided", var.equal = TRUE)))
## Plot the histogram of p-values for random normal data under H0
hist(student.under.h0$p, breaks=seq(from=0, to=1, by=0.05), main="Random numbers under H0", xlab="P-value", ylab="Nb genes", las=1, col="#BBDDFF")

## Draw a volcano plot with random normal data under H0
plot(student.under.h0$d, -log10(student.under.h0$p), xlab="m2 - m1", ylab="-log10(p)", col="grey", main="Random normal under H0")
abline(v=0)
abline(h=-log10(alpha), col="red")

  1. Dessinez un histogramme (en densités) avec les valeurs de la statistique du test (\(t\)).
hist(welch.apply$t, breaks=100)

  1. Corrections de tests multiples. Ajoutez au tableau de résultats les colonnes suivantes.

    • e-valeur (\(E = p \cdot N\), où \(N\) est le nombre de test)
    • p-valeur corrigée par la méthode de Bonferonni, calculé avec la fonction p.adjust() (tond vous lirez préalablement l’aide).
    • taux de de fausse découverte (False Discovery Rate, FDR), calculé avec la fonction p.adjust().
## E-value
g <- nrow(expr.matrix)
welch.apply$E <- welch.apply$p * g
welch.apply$Bonferroni <- p.adjust(welch.apply$p, method = "bonferroni")
welch.apply$BH <- p.adjust(welch.apply$p, method = "BH")
welch.apply$fdr <- p.adjust(welch.apply$p, method = "fdr")
plot(welch.apply$p, welch.apply$Bonferroni, log="xy", col="red")
points(welch.apply$p, welch.apply$BH, col="darkgreen")
points(welch.apply$p, welch.apply$fdr, col="blue", pch=20, cex=0.8)
grid()

## Negative control: all data under H0
student.under.h0$E <- student.under.h0$p * g
student.under.h0$Bonferroni <- p.adjust(student.under.h0$p, method = "bonferroni")
student.under.h0$BH <- p.adjust(student.under.h0$p, method = "BH")
student.under.h0$fdr <- p.adjust(student.under.h0$p, method = "fdr")
## Draw a volcano plot with random normal data under H0
plot(student.under.h0$d, -log10(student.under.h0$E), xlab="m2 - m1", ylab="-log10(E)", col="grey", main="Random normal under H0")
abline(v=0)
abline(h=-log10(alpha), col="red")

## Histogram of E-values for Den Boer
hist(welch.apply$E, breaks=g *seq(from=0, to=1, by=0.05), main="E-value histogram", xlab="E-value", ylab="Nb genes", las=1, col="#BBDDFF")

## Plot the histogram of E-values for random normal data under H0
hist(student.under.h0$E, breaks=g*seq(from=0, to=1, by=0.05), main="Random numbers under H0", xlab="E-value", ylab="Nb genes", las=1, col="#BBDDFF")

par(mfrow=c(1,1))
  1. Dessinez un graphe qui compare la p-valeur nominale (en abscisse) et les différentes corrections (en ordonnée). Utilisez les axes logarithmiques pour faire apparaître les valeurs pertinentes (très petites).
## Plot the volcano and p-value histograms of E-values
par(mfrow=c(2,2))
## Draw a volcano plot with Welch results
plot(welch.apply$d, -log10(welch.apply$E), xlab="m2 - m1", ylab="-log10(E)", col="grey", main="Den Boer, E-value volcano")
abline(v=0)
abline(h=-log10(alpha), col="red")## Histogram of p-values for Den Boer 2009 expression matrix

  1. Sélectionez les gènes significatifs avec un seuil \(\alpha=0.05\) sur le taux de fausse découverte.
selected.genes <- welch.apply$fdr < alpha
sum(selected.genes)
[1] 2762
  1. Sélectionnez une matrice restreinte aux profils d’expression des gènes différentiellement exprimés pour les deux groupes d’intérêt (les deux groupes dans la même matrice).
selected.expr.matrix <- expr.matrix[selected.genes, selected.samples]
dim(selected.expr.matrix)
[1] 2762   88

Ici s’arrête la matière à connaître pour l’examen: le reste du tuto est fourni pour le plaisir.

  1. Calculez – avec la fonction cor() – une matrice de corrélation entre échantillons de cette matrice de gènes différentiellement exprimés. Générez un diagramme de cette matrice avec heatmap().
## Compute Pearson correlation between samples
dim(selected.expr.matrix)
[1] 2762   88
## Compute inter-sample correlation
sample.cor <- cor(selected.expr.matrix)
dim(sample.cor)
[1] 88 88
heatmap(sample.cor, scale = "none", col=bluered(100), symm=TRUE)

  1. Utilisez la fonction hclust() pour effectuer un clustering des échantillons, sur base de cette matrice de corrélation.
## Compute inter-gene correlation
gene.cor <- 1 - cor(t(selected.expr.matrix))
dim(gene.cor)
[1] 2762 2762
## Build a gene tree by running hierarchical clustering between genes
gene.tree <- hclust(d = as.dist(gene.cor), method = "complete", members = NULL)
plot(gene.tree)

  1. Avec la fonction heatmap(), dessinez une carte thermique (heat map) des gènes différentiellement exprimés, en activant le clustering sur les colonnes (samples) et lignes (gènes). Raffinez ensuite le graphique avec la fonction heatmap2() de la librairie gplots (installez cette librairie si nécessaire).
## Gene-wise centering for the heatmap. The gene-wise (row-wise) mean is substracted fromeach expression value
selected.expr.matrix.gene.centered <- selected.expr.matrix - apply(selected.expr.matrix,1, mean)
# library(corrplot)
# corrplot(sample.cor[1:10, 1:10])
x <-
selected.expr.matrix.gene.centered
## Add class label to each gene name
colnames(x) <- paste(colnames(x), sample.labels[selected.samples])
## Compute maximal absolute value of x for the range of the heatmap
absmax <- ceiling(max(abs(range(x))))
## Use 99th percentile as limit for the color scale
zlim <- quantile(x = abs(unlist(x)), probs = 0.99)
## Draw a heatmap with one row per gene and one column per sample
heatmap(as.matrix(x), cexCol = 0.5, col=redgreen(100), scale="none", labRow = FALSE, symm=FALSE, margins=c(5,1), zlim=c(-zlim, zlim), Rowv = as.dendrogram(gene.tree))

  1. Au moyen de la fonction strsplit(), extrayez les noms des gènes significatifs à partir des étiquettes de lignes de la matrice d’expression. Ces étiquettes contiennent 2 identifiants séparés par un caractère \(|\) (tube): nom de gène et identifiant de la sonde sur la biopuce.
gene.rownames <- rownames(expr.matrix)
gene.desc <- t(data.frame(strsplit(x = gene.rownames, split = '|', fixed=TRUE)))
rownames(gene.desc) <- rownames(expr.matrix)
colnames(gene.desc) <- c("gene.name", "affy.ID")
# dim(gene.desc)
kable(head(gene.desc))
gene.name affy.ID
DDR1|1007_s_at DDR1 1007_s_at
RFC2|1053_at RFC2 1053_at
HSPA6|117_at HSPA6 117_at
PAX8|121_at PAX8 121_at
GUCA1A|1255_g_at GUCA1A 1255_g_at
UBA7|1294_at UBA7 1294_at
## Selected gene names
selected.gene.names <- as.vector(gene.desc[selected.genes, "gene.name"])
selected.affy.IDs <- as.vector(gene.desc[selected.genes, "affy.ID"])
  1. Analysez l’enrichissement fonctionnel de ces gènes avec les deux outils suivants:

  2. ACP (PCA), sparse PCA

References


  1. Plus précisément, chaque ligne correspond à un “probeset”, qui mesure la concentration d’une série d’oligonucléotides représentatifs d’un gène. Certains gènes sont représentés par plusieurs probesets, mais par souci de simplicité nous utiliserons le mot “gène” pour les mesures ci-dessous.