Anne Badel & Jacques van Helden
29 mars 2021
## Install required packages
packages <- c("knitr",
"FactoMineR", # for PCA
"aricode", # for adjusted Rand Index,
"RColorBrewer",
"vegan",
"pheatmap",
"scales", ## to draw plot with semi-transparent points
"tinytex")
# library(formattable)
for (pkg in packages) {
if (!require(pkg, character.only = TRUE)) {
install.packages(pkg)
require(pkg, character.only = TRUE)
}
}
We reload here the memory image saved at the end of the tutorial Data loading and exploration.
#### Reload memory image from github repository ####
github_mem_img <- "https://github.com/DU-Bii/module-3-Stat-R/blob/master/stat-R_2021/data/TCGA_BIC_subset/bic_data.Rdata?raw=true"
## Define local destination folder
bic_folder <- "~/m3-stat-R/TCGA-BIC_analysis"
## Create it if required
dir.create(bic_folder, showWarnings = FALSE, recursive = TRUE)
## Define local destination for the memory image
mem_image <- file.path(bic_folder, "bic_data.Rdata")
if (file.exists(mem_image)) {
message("Memory image already there, skipping download")
} else {
message("Downloading memory image from\n", github_mem_img)
download.file(url = github_mem_img, destfile = mem_image)
message("Local memory image\t", mem_image)
}
## Load the memory image
message("Loading memory image", mem_image)
load(mem_image)
Les données, leurs représentations
Comment comparer deux individus
Comment découvrir des “clusters” dans les données ?
Comment déterminer le nombre de groupe optimal ?
Comment comparer deux classifications ?
Les données sont issues de la base Recount2. Nous avons sélectionné l’étude TCGA : The Cancer Genome Atlas, regroupant des données RNA-seq pour plus de 12.000 patients souffrant de différents types de cancer. Nous nous intéressons ici uniquement aux données Breast Invasive Cancer (BIC) concernant le cancer du sein.
Les données ont été préparées pour vous, selon la procédure détaillée au cours sur l’analyse différentielle de données RNA-seq.
Filtrage des gènes à variance nulle et de ceux contenant trop de zéros.
Normalisation (méthode robuste aux outliers)
Analyse différentielle multi-groupes (en utilisant le package Bioconductor edgeR
).
Correction des P-valeurs pour tenir compte des tests multiples (nous avons testé ici ~20.000 gènes). Nous estimons le False Discovery Rate (FDR) selon la méthode de Benjamini-Hochberg (fonction R p.adjust(all.pvalues, method="fdr")
).
Sélection de gènes différentiellement exprimés sur base d’un seuil \(\alpha = 0.05\) appliqué au FDR.
Luminal.A.83 | Luminal.B.99 | Luminal.A.417 | Luminal.A.318 | |
---|---|---|---|---|
TSPAN6 | 18.98338 | 18.51158 | 16.48997 | 18.47712 |
DPM1 | 17.94254 | 17.06309 | 17.85425 | 17.20569 |
SCYL3 | 18.95936 | 17.00965 | 17.47549 | 16.82820 |
C1orf112 | 18.31903 | 15.89376 | 17.18320 | 15.71367 |
FGR | 13.76168 | 17.43222 | 15.12968 | 16.33244 |
CFH | 16.60954 | 20.49160 | 18.63168 | 19.63751 |
Pour des raisons historiques, en analyse transcriptomique les données sont toujours fournies avec
Cette convention a été établie en 1997, lors des toutes premières publications sur le transcriptome de la levure. Dans ces études, l’objet d’intérêt (l’“individu”) était le gène, et les variables étaient ses mesures d’expression dans les différentes conditions testées.
Pour le prochain TP sur la classification supervisée de tissus cancéreux, on considèrera au contraire que l’“objet” d’intérêt est l’échantillon prélevé sur le patient, et les variables sont les mesures d’expression des différents gènes chez un patient.
Classiquement, en analyse de données, les individus sont les lignes du tableau de données, les colonnes sont les variables.
Ce qui implique de faire attention, et éventuellement de travailler sur la matrice transposée (fonction t()
en R) pour utiliser correctement les fonctions classiques.
TSPAN6 DPM1 SCYL3 C1orf112 FGR CFH
Basal.like 16.84036 17.64740 17.93260 17.63825 16.67788 18.04494
Basal.like.1 18.52655 18.14431 16.79884 17.34841 15.56100 17.03132
Basal.like.2 19.14367 17.32173 17.05726 16.02602 17.61965 18.19628
Basal.like.3 17.93844 17.83135 17.37199 16.86000 14.62704 18.53828
1 ligne = 1 gène = 1 individu = 1 vecteur
1 colonne = 1 feature = 1 vecteur
l’ensemble des données = 1 data.frame
[1] 819 1000
TSPAN6 DPM1 SCYL3 C1orf112 FGR
Basal.like 16.84036 17.64740 17.93260 17.63825 16.67788
Basal.like.1 18.52655 18.14431 16.79884 17.34841 15.56100
Basal.like.2 19.14367 17.32173 17.05726 16.02602 17.61965
Basal.like.3 17.93844 17.83135 17.37199 16.86000 14.62704
L’intensité des couleurs reflète la densité locale des points
en tenant compte de l’ensemble des individus/ lignes et variables / colonnes = un nuage de points dans un espace à 1000 dimensions
= PAS de représentation possible (pour l’instant)
Nous utiliserons les termes anglais
en français :
On n’a pas d’information supplémentaire sur nos données, juste le data.frame
contenant
Clustering : on cherche à mettre en évidence des groupes (/ des clusters) dans les données
On a une information supplémentaire : on connaît le partitionnement de notre jeu de données
Classification : on cherche un algorithme / un modèle permettant de prédire la classe, le groupe de tout individu dont on connait les caractéristiques
- y a t’il des groupes ? si oui, combien ?
Définition d’une distance : fonction positive de deux variables
Si 1,2,3 seulement: dissimilarité
Euclidian distance | Correlation coefficient | Correlation distance | |
---|---|---|---|
A - B | 4.85 | 0.93 | 0.07 |
A - C | 5.59 | -0.53 | 1.53 |
B - C | 1.03 | -0.67 | 1.67 |
dist()
avec l’option method = "euclidean", "manhattan", ...
t1 | t2 | t3 | t4 | t5 | |
---|---|---|---|---|---|
X | 2.32 | 4.20 | 3.43 | 4.09 | 4.50 |
Y | 3.43 | 2.49 | 2.56 | 2.04 | 2.26 |
distance euclidienne : dist(mat.xy) =
3.76
distance de manhattan = dist(mat.xy, method = "manhattan")
7.97
1 - cor()
avec l’option method = "pearson", "spearman", ...
distance de corrélation = 1-cor(t(mat.xy)
1.91
KLHL13 TFPI SEMA3F GGCT
TFPI 71
SEMA3F 132 81
GGCT 132 82 34
DHX33 87 44 58 57
KLHL13 TFPI SEMA3F GGCT
TFPI 0.57
SEMA3F 1.26 1.24
GGCT 1.25 1.22 0.87
DHX33 0.85 1.08 1.33 1.15
Basal.like Basal.like.1 Basal.like.2 Basal.like.3 Basal.like.4
Basal.like.1 0.300
Basal.like.2 0.290 0.828
Basal.like.3 0.042 0.277 0.461
Basal.like.4 0.645 0.140 1.330 0.547
Basal.like.5 0.049 0.341 0.218 0.082 0.767
Revenons à nos données
On peut ensuite essayer de visualiser les données
plot
(! ne pas faire si “grosses” données)boxplot
(! ne pas faire si “grosses” données)[1] 0
Afin de pouvoir considérer que toutes les variables sont à la même échelle, il est parfois nécessaire de standardiser les données.
soit
soit
classification hiérarchique : mettre en évidence des liens hiérachiques entre les individus
ressemblance entre individus = distance
ressemblance entre groupes d’invidus = critère d’aggrégation
départ : n individus = n clusters distincts
calcul des distances entre tous les individus
regroupement des 2 individus les plus proches => (n-1) clusters
calcul des dissemblances entre chaque groupe obtenu à l’étape \((j-1)\)
regroupement des deux groupes les plus proches => \((n-j)\) clusters
Faire attention au données
Choisir
adaptés à nos données
Les individus dans le plan
=> faire apparaitres des classes / des clusters
construction des centres de gravité des k clusters construits à l’étape \((j-1)\)
\(k\) nouveaux clusters créés à partir des nouveaux centres suivant la même règle qu’à l’étape \(0\)
obtention de la partition \(P_j\)
TSPAN6 DPM1 SCYL3 C1orf112 FGR CFH FUCA2 GCLC NFYA STPG1 NIPAL3 LAS1L ENPP4 SEMA3F ANKIB1 CYP51A1 KRIT1 RAD52 BAD LAP3
5 5 5 5 4 2 2 5 2 4 5 2 5 2 2 2 5 4 5 2
Ces méthodes non supervisées, sont sans a priori sur la structure, le nombre de groupe, des données.
rappel : un cluster est composé
si les individus d’un même cluster sont proches
si les individus de 2 clusters différents sont éloignés => variance inter forte
La coupure de l’arbre à un niveau donné construit une partition. la coupure doit se faire :
après les agrégations correspondant à des valeurs peu élevées de l’indice
avant les agrégations correspondant à des niveaux élevés de l’indice, qui dissocient les groupes bien distincts dans la population.
k1 | k2 | k3 | |
---|---|---|---|
c1 | 398 | 57 | 0 |
c2 | 98 | 0 | 61 |
c3 | 3 | 293 | 0 |
c4 | 0 | 0 | 90 |
Algorithme | Pros | Cons |
---|---|---|
Hiérarchique | L’arbre reflète la nature imbriquée de tous les sous-clusters | Complexité quadratique (mémoire et temps de calcul) \(\rightarrow\) quadruple chaque fois qu’on double le nombre d’individus |
Permet une visualisation couplée dendrogramme (groupes) + heatmap (profils individuels) | ||
Choix a posteriori du nombre de clusters | ||
K-means | Rapide (linéaire en temps), peut traiter des jeux de données énormes (centaines de milliers de pics ChIP-seq) | Positions initiales des centres est aléatoire \(\rightarrow\) résultats changent d’une exécution à l’autre |
Distance euclidienne (pas appropriée pour transcriptome par exemple) |
Mesure de similarité entre deux clustering
à partir du nombre de fois que les clustering sont d’accord
\[R=\frac{m+s}{t}\]
[1] 0.8153634
\[ \text{ARI} = \frac{\text{RI}-\text{E(RI)}}{\text{Max RI} - \text{E(RI)}}\]
[1] 0.601469
POUR ALLER PLUS LOIN
distance euclidienne ou distance \(L_2\): \(d(x,y)=\sqrt{\sum_i (x_i-y_i)^2}\)
distance de manahattan ou distance \(L_1\): \(d(x,y)=\sum_i |x_i-y_i|\)
distance du maximum ou L-infinis, \(L_\infty\): \(d(x,y)=\max_i |x_i-y_i|\)
distance de Minkowski \(l_p\): \[d(x,y)=\sqrt[p]{\sum_i (|x_i-y_i|^p}\]
distance de Canberra (x et y valeurs positives): \[d(x,y)=\sum_i \frac{x_i-y_i}{x_i+y_i}\]
distance binaire ou distance de Jaccard ou Tanimoto: proportion de propriétés communes
Note : lors du TP, sur les données d’expression RNA-seq, nous utiliserons le coefficient de corrélation de Spearman et la distance dérivée, \(d_c = 1-r\)
Utilisées en bio-informatique:
Distance de Hamming: nombre de remplacements de caractères (substitutions)
Distance de Levenshtein: nombre de substitutions, insertions, deletions entre deux chaînes de caractères
\[d("BONJOUR", "BONSOIR")=2\]
Distance d’alignements: distances de Levenshtein avec poids (par ex. matrices BLOSSUM)
Distances d’arbre (Neighbor Joining)
Distances ultra-métriques (phylogénie UPGMA)
Il existe d’autres mesures de distances, plus ou moins adaptées à chaque problématique :
Jaccard (comparaison d’ensembles): \(J_D = \frac{A \cap B}{A \cup B}\)
Distance du \(\chi^2\) (comparaison de tableau d’effectifs)
Ne sont pas des distances, mais indices de dissimilarité :
Bray-Curtis (en écologie, comparaison d’abondance d’espèces)
Jensen-Shannon (comparaison de distributions) # Distance avec R : indice de Jaccard
ou pour des distances particulières, par exemple l’indice de Jaccard :
v.a | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
v.b | 0 | 1 | 0 | 0 | 0 | 1 | 0 |
v.c | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
v.a v.b
v.b 0.3333333
v.c 0.0000000 0.3333333
On considère les données comme des points de \(\mathbb{R}^n\)
\(\mathbb{R}^n\) : espace Euclidien à \(n\) dimensions, où
On considère les données comme des points de \(R^n\) (*)
Sur la base d’une distance
## Plot distances between 3 points in a 2D Euclidian space
plot(x = 0, y = 0, type = "n", xlim = c(0, 5), ylim = c(0, 5),
xlab = "", ylab = "", las = 1,
main = "3 individuals in a 2-D space\nDot plot representation",
panel.first = grid())
points(x = 1, y = 1, col = "blue", pch = 19)
text(x = 1, y = 1, col = "blue", label = "A", pos = 2)
points(x = 2, y = 0, col = "green", pch = 19)
text(x = 2, y = 0, col = "green", label = "B", pos = 4)
points(x = 4, y = 4, col = "red", pch = 19)
text(x = 4, y = 4, col = "red", label = "C", pos = 4)
\[D(C_1,C_2) = \min_{i \in C_1, j \in C_2} D(x_i, x_j)\]
\[D(C_1,C_2) = \max_{i \in C_1, j \in C_2} D(x_i, x_j)\]
\[D(C_1,C_2) = \frac{1}{N_1 N_2} \sum_{i \in C_1, j \in C_2} D(x_i, x_j)\]
\(d^2(C_i,C_j) = I_{intra}(C_i \cup C_j)-I_{intra}(C_i)-I_{intra}(C_j)\)
\(D(C_1,C_2) = \sqrt{\frac{N_1N_2}{N_1 + N_2}} \| m_1 -m_2 \|\)
dist()
avec l’option method = "euclidean", "manhattan", ...
t1 | t2 | t3 | t4 | t5 | SUM | |
---|---|---|---|---|---|---|
X | 2.27 | 2.73 | 1.47 | 4.65 | 3.27 | 14.39 |
Y | 2.64 | 3.99 | 3.78 | 2.61 | 2.02 | 15.03 |
abs(Y - X) | 0.37 | 1.25 | 2.31 | 2.04 | 1.25 | 7.23 |
(Y - X)^2 | 0.14 | 1.57 | 5.34 | 4.18 | 1.57 | 12.80 |
Eucl | 0.37 | 1.25 | 2.31 | 2.04 | 1.25 | 3.58 |
distance euclidienne : 3.58
distance de manhattan = 7.23
1 - cor()
avec l’option method = "pearson", "spearman", ...
distance de corrélation = 1.52
… c’est à dire aux options des fonctions dist()
et hclust()
# R environment used for this analysis |
r ## Print the complete list of libraries + versions used in this session sessionInfo() |
``` R version 4.0.2 (2020-06-22) Platform: x86_64-apple-darwin17.0 (64-bit) Running under: macOS Mojave 10.14.6 |
Matrix products: default BLAS: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib |
locale: [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 |
attached base packages: [1] stats graphics grDevices utils datasets methods base |
other attached packages: [1] tinytex_0.30 scales_1.1.1 pheatmap_1.0.12 vegan_2.5-7 lattice_0.20-41 permute_0.9-5 RColorBrewer_1.1-2 aricode_1.0.0 FactoMineR_2.4 knitr_1.31 |
loaded via a namespace (and not attached): [1] tidyselect_1.1.0 xfun_0.22 bslib_0.2.4 purrr_0.3.4 splines_4.0.2 colorspace_2.0-0 vctrs_0.3.6 generics_0.1.0 htmltools_0.5.1.1 mgcv_1.8-34 yaml_2.2.1 utf8_1.2.1 rlang_0.4.10 jquerylib_0.1.3 [15] pillar_1.5.1 glue_1.4.2 DBI_1.1.1 lifecycle_1.0.0 stringr_1.4.0 munsell_0.5.0 gtable_0.3.0 htmlwidgets_1.5.3 leaps_3.1 evaluate_0.14 labeling_0.4.2 parallel_4.0.2 fansi_0.4.2 highr_0.8 [29] Rcpp_1.0.6 KernSmooth_2.23-18 flashClust_1.01-2 DT_0.17 scatterplot3d_0.3-41 jsonlite_1.7.2 farver_2.1.0 ggplot2_3.3.3 digest_0.6.27 stringi_1.5.3 dplyr_1.0.5 ggrepel_0.9.1 grid_4.0.2 tools_4.0.2 [43] magrittr_2.0.1 sass_0.3.1 tibble_3.1.0 cluster_2.1.1 crayon_1.4.1 pkgconfig_2.0.3 ellipsis_0.3.1 MASS_7.3-53.1 Matrix_1.3-2 assertthat_0.2.1 rmarkdown_2.7 R6_2.5.0 nlme_3.1-152 compiler_4.0.2 ``` |
Contact: anne.badel@univ-paris-diderot.fr
Comment comparer des vecteurs-individus ?