## Location of the shared folder on the current install
data.folder <- "~/TCGA_import/data/BIC/" # Just for preparation
#data.folder <- "/shared/projects/du_bii_2019/data/module3/seance4/BIC/" # on the IFB-cluster-core
## Load libraries
message("Loading libraries")
library(knitr)
#library(kableExtra) ## Note: kableExtra has some side effect on kable: column padding is null, so all numbers seem to be mixed up
library(FactoMineR)
library(clues)
library(RColorBrewer)
library(ComplexHeatmap)
# library(corrplot)
library(FactoMineR)
library(ClassDiscovery)
# library(formattable)
Le tutoriel ci-dessous vous guidera pas-à-pas dans l’utilisation de fonctions R pour effectuer un clustering sur des profils transcriptomiques RNA-seq.
Les données sont issues de la base Recount2 (https://jhubiostatistics.shinyapps.io/recount/). Nous avons sélectionné l’étude TCGA (The Cancer Genome Atlas; https://cancergenome.nih.gov/), 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 ccontenant 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 nomiables pour tenir compte des tests multiples (nous avons testé ici ~20.000 gènes). Nous estimons le 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.
Vous pouvez choisir de travailler soir sur le cluster core de l’IFB soit sur les ordinateurs de Paris-Diderot.
Sur le cluster de l’IFB
Sur les machines de la salle d’ordinateurs de Paris-Diderot
.bashrc
:source /opt/sdv/anaconda/etc/profile.d/conda.sh`
conda activate
rstudio
Les données sont dans un répertoire partagé, dont le chemin dépend du serveur auquel vous êtes connectézs. Nous allons définir une variable data.folder
qui indiquera le chemin de ce dossier partagé, en fonction du serveur.
Sur le serveur Rstudio de l’IFB-core-cluster, les données sont dans le répertoire /shared/projects/du_bii_2019/data/module3/seance4/BIC/
.
## Liste des fichiers de données
data.folder <- "/shared/projects/du_bii_2019/data/module3/seance4/BIC/"
Utilisez les commandes R suivantes:
list.files()
pour vérifier le contenu du dosser data.folder
,file.size()
pour calculer la taille de ces fichiers.Astuces:
list.files()
retourne par défaut le nom de fichier, mais avec l’option full.names=TRUE
vous obtiendrez le chemin complet.# Return file sizes (in bytes)
message("Listing files in data folder: ", data.folder)
data.files <- list.files(path = data.folder) # List the data files
print(data.files)
[1] "BIC_counts_all-genes.tsv.gz" "BIC_counts_filtered-genes.tsv.gz" "BIC_edgeR_DEG_table.tsv" "BIC_edgeR_DEG_table.tsv.gz" "BIC_log2-norm-counts_all-genes.tsv.gz" "BIC_log2-norm-counts_edgeR_DEG_fdr_0.01.tsv"
[7] "BIC_log2-norm-counts_edgeR_DEG_fdr_0.01.tsv.gz" "BIC_log2-norm-counts_edgeR_DEG_top_1000.tsv.gz" "BIC_log2-norm-counts_filtered-genes.tsv" "BIC_log2-norm-counts_filtered-genes.tsv.gz" "BIC_pheno.tsv.gz" "BIC_sample-classes.tsv.gz"
## Full path
data.path <- list.files(path = data.folder, full.names = TRUE) # List the data files
print(data.files)
[1] "BIC_counts_all-genes.tsv.gz" "BIC_counts_filtered-genes.tsv.gz" "BIC_edgeR_DEG_table.tsv" "BIC_edgeR_DEG_table.tsv.gz" "BIC_log2-norm-counts_all-genes.tsv.gz" "BIC_log2-norm-counts_edgeR_DEG_fdr_0.01.tsv"
[7] "BIC_log2-norm-counts_edgeR_DEG_fdr_0.01.tsv.gz" "BIC_log2-norm-counts_edgeR_DEG_top_1000.tsv.gz" "BIC_log2-norm-counts_filtered-genes.tsv" "BIC_log2-norm-counts_filtered-genes.tsv.gz" "BIC_pheno.tsv.gz" "BIC_sample-classes.tsv.gz"
data.file.sizes <- file.size(data.path) # Get the size of the data files, in bytes
## Add file names
## (for some strange reason, file.size returns a vector
## with no names, which is not very convenient)
names(data.file.sizes) <- data.files
## Compute file sizes in megabytes
data.file.Mb <- signif(digits = 2, data.file.sizes / (1024^2))
kable(data.frame(data.file.Mb))
data.file.Mb | |
---|---|
BIC_counts_all-genes.tsv.gz | 79.000 |
BIC_counts_filtered-genes.tsv.gz | 47.000 |
BIC_edgeR_DEG_table.tsv | 1.600 |
BIC_edgeR_DEG_table.tsv.gz | 1.700 |
BIC_log2-norm-counts_all-genes.tsv.gz | 120.000 |
BIC_log2-norm-counts_edgeR_DEG_fdr_0.01.tsv | 85.000 |
BIC_log2-norm-counts_edgeR_DEG_fdr_0.01.tsv.gz | 85.000 |
BIC_log2-norm-counts_edgeR_DEG_top_1000.tsv.gz | 6.000 |
BIC_log2-norm-counts_filtered-genes.tsv | 120.000 |
BIC_log2-norm-counts_filtered-genes.tsv.gz | 120.000 |
BIC_pheno.tsv.gz | 0.950 |
BIC_sample-classes.tsv.gz | 0.019 |
Nous allons maintenant lire le fichier d’expression. Pour cela, nous concaténons le chemin du dossier de données et le nom du fichier d’expressiion (BIC_log2-norm-counts_edgeR_DEG_top_1000.tsv.gz
).
Ce fichier contient le comptages de lectures RNA-seq par gène, avec une sélection des gènes déclarés positifs pour letest de comparaison de moyennes multiples (voir-ci-dessus). Par ailleurs, nous avons arbitrairement appliqué un seuil supplémentaire en n’exportant que les 1000 gènes les plus significatifs, pour éviter de passer trop de temps sur le clustering hiérachique (complexité quadratique).
# Define the path of the expression file, by concatenating the data folder and the file name
# Note that file.path is convenient because it automatically used the appropriate parameter to separate the elements of a path (/ on Unix, \\ on Windows)
BIC.expr.file <- file.path(data.folder, "BIC_log2-norm-counts_edgeR_DEG_top_1000.tsv.gz")
# Load expression
message("Loading expression file\t", BIC.expr.file)
BIC.expr <- read.table(file = BIC.expr.file, header = TRUE)
Prenez le temps d’identifier
Remarque : Classiquement, en analyse de données, les individus sont les lignes du tableau de données, les colonnes sont les variables.
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 l’anlayse de tissus cancéreux, on considère 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.
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.
## Les données d'expression
dim(BIC.expr)
[1] 1000 819
## Les noms des lignes correspondent à des gènes
head(rownames(BIC.expr))
[1] "ENSG00000001617.11" "ENSG00000002834.17" "ENSG00000003989.16" "ENSG00000004838.13" "ENSG00000005302.17" "ENSG00000006016.10"
## Les noms des colonnes correspondent à des échantillons
head(colnames(BIC.expr))
[1] "X1AB92ADA.637E.4A42.A39A.70CEEEA41AE3" "DA98A67C.F11F.41D3.8223.1161EBFF8B58" "X06CCFD0F.7FB8.471E.B823.C7876582D6FC" "A33B2F42.6EC6.4FB2.8BE5.542407A0382E" "D021A258.8713.4383.9DCA.45E2F54A0411" "C705FA90.D9AA.4949.BACA.1C022A14CB03"
## transposons la table d'expression
message("Transcribing expression matrix")
BIC.expr.transposed <- t(BIC.expr)
Le fichier BIC_sample-classes.tsv.gz
contient les étiquettes de classes des échantillons.
BIC.sample.classes <- read.table(
file.path(data.folder, "BIC_sample-classes.tsv.gz"),
header = TRUE)
kable(BIC.sample.classes[1:10,])
cancer.type | ER1 | PR1 | Her2 | |
---|---|---|---|---|
1AB92ADA-637E-4A42-A39A-70CEEEA41AE3 | Luminal.A | Positive | Positive | Negative |
DA98A67C-F11F-41D3-8223-1161EBFF8B58 | Unclassified | Positive | Negative | Negative |
06CCFD0F-7FB8-471E-B823-C7876582D6FC | HER2pos | Negative | Negative | Positive |
A33B2F42-6EC6-4FB2-8BE5-542407A0382E | Unclassified | Positive | Negative | Negative |
D021A258-8713-4383-9DCA-45E2F54A0411 | Luminal.A | Positive | Positive | Negative |
C705FA90-D9AA-4949-BACA-1C022A14CB03 | Luminal.A | Positive | Positive | Negative |
85380A2D-9951-4D4B-A2A4-6F5F2AFC54E3 | Luminal.A | Positive | Positive | Negative |
F53A9C63-1AF7-4CBC-B8B7-4AA7AAED3364 | Luminal.A | Positive | Positive | Negative |
13EF5323-EAD9-4BC7-8AC4-33875BF12E17 | Luminal.B | Positive | Positive | Positive |
079EACA1-0319-4B54-B20B-673F4576C69D | Basal.like | Negative | Negative | Negative |
Chaque échantillon a été assigné à une classe selon la combinaison de 3 marqueurs immunologiques:
Utilisez
La fonction R summary()
pour compter le nombre de patientes positives / négatives pour chacun de ces trois marqueurs.
La fonction R table()
pour calculer le nombre d’échantillons de chaque type de cancer.
La fonction R table()
pour calculer une table de contiingence des marqueurs ER1 et PR1
summary(BIC.sample.classes)
cancer.type ER1 PR1 Her2
Basal.like :131 Negative:184 Negative:267 Negative:631
HER2pos : 41 Positive:635 Positive:552 Positive:188
Luminal.A :422
Luminal.B :118
Unclassified:107
table(BIC.sample.classes$cancer.type)
Basal.like HER2pos Luminal.A Luminal.B Unclassified
131 41 422 118 107
table(BIC.sample.classes$ER1, BIC.sample.classes$PR1)
Negative Positive
Negative 172 12
Positive 95 540
table(BIC.sample.classes$ER1,
BIC.sample.classes$PR1,
BIC.sample.classes$Her2)
, , = Negative
Negative Positive
Negative 131 8
Positive 70 422
, , = Positive
Negative Positive
Negative 41 4
Positive 25 118
Nous allons réaliser une ACP sans mise à l’échelle.
## Transformation ACP
BIC.prcomp <- prcomp(BIC.expr.transposed, center = FALSE, scale. = FALSE)
names(BIC.prcomp) # check the name of the fields of the PCA object
[1] "sdev" "rotation" "center" "scale" "x"
par(mfrow = c(1,2))
## Plot de l'écart-type sur les premières composantes
barplot(BIC.prcomp$sdev[1:10], col = "#FFEEDD",
main = "Standard deviation per PC")
## Visualisation des données
plot(BIC.prcomp, main = "Variance per PC", col="#BBDDFF")
par(mfrow=c(1,1))
Définissez une couleur pour chaque classe, et assignez à chaque échantillon la couleur correspondant à sa classe. Dessinez ensuite un nuage de points avec les coordonnées de chaque échantillon dans les 1ère et 2ème composantes (PC2 vs PC1)
# Assign a color to each cancer type
classes <- unique(BIC.sample.classes$cancer.type)
class.colors <- rainbow(n = length(classes))
names(class.colors) <- classes
data.frame(class.colors)
class.colors
Luminal.A #FF0000FF
Unclassified #CCFF00FF
HER2pos #00FF66FF
Luminal.B #0066FFFF
Basal.like #CC00FFFF
# Associate a color to each sample accordinig to its cancer type
sample.colors <- class.colors[BIC.sample.classes$cancer.type]
table(BIC.sample.classes$cancer.type, sample.colors)
sample.colors
#0066FFFF #00FF66FF #CC00FFFF #CCFF00FF #FF0000FF
Basal.like 0 0 0 0 131
HER2pos 0 0 0 41 0
Luminal.A 0 422 0 0 0
Luminal.B 118 0 0 0 0
Unclassified 0 0 107 0 0
Question: comment interprétez-vous les barplots des écarts-types et variances pour les premières comosantes ? A discuter pendant le cours.
Nous allons maintenant calculer la distance entre chaque paire d’échantillon, en utilsiant comme métrique le coefficient de corrélation de Spearman, plus adapté à ce type de données que la distance euclidienne utilisée sur les données iris durant le cours
Lisez l’aide de la fonction cor
, et utilisez cette fonction pour calculer la matrice de corrélation entre échantillons.
transformation du corrélation de Spearman en une distance à l’aide de la transformation : \(d = 1 - r\)
## Compute Spearman correlation coefficient
BIC.cor <- cor(BIC.expr, method = "spearman")
# Check the dimensions of the correlation matrix
# (should be N x N, where N is the number of samples)
dim(BIC.cor)
[1] 819 819
## Derive a dissimilarity value from the corrrelation
BIC.dist <- as.dist(1 - BIC.cor)
Faites un premier clustering hiérarchique, avec le critère d’aggrégation par défaut (lisez l’aide de la fonction hclust()
pour savoir quelle est ce critère par défaut).
## Run hierarchical clustering on the expression data
## (use default parameters)
BIC.hclust.complete <- hclust(BIC.dist)
## Plot the resulting tree
plot(BIC.hclust.complete, labels = F, hang = -1, las = 1, col = "grey",
main = "Spearman dissimilarity, complete linkage")
## Run hierarchical clustering with Ward agglomeration
BIC.hclust.ward <- hclust(BIC.dist, method = "ward.D2")
## Plot the resulting tree
plot(BIC.hclust.ward, labels = F, hang = -1, las = 1, col = "#88BB66",
main = "Spearman dissimilarity, Ward linkage")
ClassDiscovery::plotColoredClusters(
BIC.hclust.ward,
labs=BIC.sample.classes$cancer.type, col = "grey",
cols=sample.colors, cex=0.2)
legend("topright",
legend=sort(classes),
col = class.colors,
text.col = class.colors, cex=0.9)
Astuces:
rect.hclust
et cutree
pour visualiser les clusters sur le dendrogramme, puis récupérer les clusters.La fonction R heatmap()
permet de représenter à la fois les arbres produit par le clustering hiérarchique, et les profils d’expression.
Par défaut, elle effectue simultanément un clustering hiérarchique sur les lignes et sur les colonnes, ce qui permet de distinguer non seulement les groupes d’échantillons biologiques, mais également ceux de gènes.
Attention: la fonction heatmap()
effectue par défaut un clustering hiérarchique sur les lignes et colonnes de votre matrice d’expression.
heatmap(as.matrix(BIC.expr),
distfun = function(x) as.dist(1 - cor(t(x), method = "spearman")),
hclustfun = function(x) hclust(x, method = "ward.D2"),
labRow = NA, labCol = NA)
# Compute mean value per gene
gene.means <- apply(BIC.expr, 1, mean)
gene.sd <- apply(BIC.expr, 1, sd)
# Compute gene-wise centered expression values
BIC.expr.genes.centered <- BIC.expr - gene.means
# Compute gene-wise centred + scaled expression values
BIC.expr.genes.standardized <- BIC.expr.genes.centered / gene.sd
summary(unlist(BIC.expr.genes.standardized))
Min. 1st Qu. Median Mean 3rd Qu. Max.
-7.00569 -0.63658 -0.03651 0.00000 0.60201 12.86463
hist(unlist(BIC.expr.genes.standardized), breaks = 100,
main = "Gene-wise standardized expression values",
xlab = "z-score", ylab = "Number of measures",
col = "#DDEEFF", xlim = c(-7,7))
# Draw a vertical grid
abline(v = -7:7, col = "#BBBBBB", lty = "dotted")
#Mark center
abline(v = 0, col = "#008800", lwd = 2)
# Mark dispersion (mean +- 1 sdev)
arrows(x0 = -1, y0 = 50000, x1 = 1, y1 = 50000, length = 0.05, angle = 30, code = 3, lwd = 2, col = "#008800")
## define a Blue - White - Red palette
frenchflag.palette <- colorRampPalette(c('dark blue','white','dark red'))
## Define a green - black - red palette
GBR.palette <- colorRampPalette(c('green','black','red'))
heatmap(as.matrix(BIC.expr.genes.standardized),
zlim = c(-4,4),
distfun = function(x) as.dist(1 - cor(t(x), method = "spearman")),
hclustfun = function(x) hclust(x, method = "ward.D2"),
labRow = NA, labCol = NA, # DO not print the labels (unreadable anyway)
col = GBR.palette(100),
scale = "none")
The function heatmap.2()
is derived from heatmap()
but offers nice additional formatting options.
# Define a color for the heatmap
expr.colors <- heat.colors(n = 100)
# Compute dendrogram with the hclust() function
# Choose a custom dissimilirity measure
# and agglomeration rule
# compute dissimilarity between samples
sample.dist <- as.dist(1 - cor(BIC.expr, method = "spearman"))
# Run hierarchical clustering on samples
sample.clust = hclust(sample.dist, method = "complete")
# Convert the clustering result in a tree object that can be used with plot() and / or heatmap()
sample.tree <- as.dendrogram(sample.clust)
# Define colors for the cancer type
cancer.type <- unique(BIC.sample.classes$cancer.type)
type.cancer.colors <- rainbow(n = length(cancer.type))
names(type.cancer.colors) <- cancer.type
# Define colors for ER1 marker
ER1.classes <- unique(BIC.sample.classes$ER1)
ER1.colors <- rainbow(n = length(ER1.classes))
names(ER1.colors) <- ER1.classes
print(ER1.colors)
Positive Negative
"#FF0000FF" "#00FFFFFF"
# Define colors for PR1 marker
PR1.classes <- unique(BIC.sample.classes$PR1)
PR1.colors <- heat.colors(n = length(PR1.classes))
names(PR1.colors) <- PR1.classes
print(PR1.colors)
Positive Negative
"#FF0000FF" "#FFFF00FF"
# Define colors for Her2 marker
Her2.classes <- unique(BIC.sample.classes$Her2)
Her2.colors <- topo.colors(n = length(Her2.classes))
names(Her2.colors) <- Her2.classes
## Detiine annotations for the heatmap
## combining the 3 markers + cancer type
annot.tumeur.column = HeatmapAnnotation(
df = BIC.sample.classes,
col = list(cancer.type = type.cancer.colors,
ER1 = ER1.colors,
PR1 = PR1.colors,
Her2 = Her2.colors)
)
# A first heatmap
my.heatmap <- ComplexHeatmap::Heatmap(
as.matrix(BIC.expr.genes.standardized),
name = "TCGA Breast Invasive Cancer",
# col = frenchflag.palette(100),
col = brewer.pal(11,"RdBu"),
column_title = "Samples",
row_title = "Genes",
cluster_columns = sample.tree,
show_column_names = FALSE,
show_row_names = FALSE,
bottom_annotation = annot.tumeur.column
)
draw(my.heatmap)
faire un premier kmeans, par exemple, en prenant le nombre de groupe trouvé sur le hclust
faire une boucle pour trouver le nombre optimal de cluster, en calculant l’inertie intra totale en fonction du nombre de groupe kmeans()$totss
[faire une boucle pour i allant de 1 à 10 for (i in 1:10) {}
]
refaire le kmeans avec ce nombre optimal
visualiser ces groupes par exemple sur une projection des données dans le plan par PCA, à l’aide de la fonction prcomp()
.
Astuce: dans le résultat de prcomp()
, les coordonnées des points se trouvent dans le champs x
.
## Run k-means clustering with 20 centers
BIC.kmeans <- kmeans(BIC.expr.transposed, centers=20)
## Report the table of the clusters
table(BIC.kmeans$cluster)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
115 13 62 57 7 33 16 32 5 23 48 36 70 82 32 9 70 74 10 25
T1 = Sys.time() # take time at the beginning of the task
I.intra = numeric(length=20)
I.intra[1] = kmeans(BIC.expr.transposed, centers=2)$totss
for (i in 2:20) {
message("Running k-means with ", i, " centers")
kmi <- kmeans(BIC.expr.transposed, centers=i)
I.intra[i] <- kmi$tot.withinss
}
# Plot a curve showint the intra-cluster variance as a function of the number of clusters
plot((1:20)-0.5, I.intra, type="h", lwd=2, col = "blue",
xlab = "k", ylab = "Intra-cluster variance",
main = "k-mean: impact of k on the intra-cluster variance")
# Measure elapsed time
T2 = Sys.time()
Tdiff = difftime(T2,T1) ## Measure elapsed time
## Run k-means clustering with 2 clusters
BIC.kmeans2 <- kmeans(BIC.expr.transposed, centers = 2)
table(BIC.kmeans2$cluster) ## Cluster sizes
1 2
661 158
## Run k-means clustering with 3 clusters
BIC.kmeans3 <- kmeans(BIC.expr.transposed, centers = 3)
table(BIC.kmeans3$cluster) ## Cluster sizes
1 2 3
244 435 140
## Run k-means clustering with 10 clusters
BIC.kmeans10 <- kmeans(BIC.expr.transposed, centers = 10)
table(BIC.kmeans10$cluster) ## Cluster sizes
1 2 3 4 5 6 7 8 9 10
143 79 16 127 63 36 57 104 58 136
## Cut the tree at some arbitrary levels to get clusters
## 2 clusters to see if the first subdivision corresponds to one of the 3 markers (ER1, PR1, Her2)
BIC.cutree2 <- cutree(BIC.hclust.ward, k = 2)
## 5 clusters to see if the match the cancer types defined by biologists
BIC.cutree5 <- cutree(BIC.hclust.ward, k = 5)
## Define sample colors reflecting the cluster membership
hclust.k2.colors <- BIC.cutree2
kmeans.k2.colors <- BIC.kmeans2$cluster
kmeans.k10.colors <- BIC.kmeans10$cluster
## Define characters reflecting markers
pch.cancer.type <- as.numeric(BIC.sample.classes$cancer.type)
pch.er1 <- as.numeric(BIC.sample.classes$ER1)
pch.pr1 <- as.numeric(BIC.sample.classes$PR1)
pch.her2 <- as.numeric(BIC.sample.classes$Her2)
## Compare clusters and markers on the PC plot, to evaluate whether
## the components capture relevant information
par(mfrow=c(1,2))
plot(BIC.prcomp$x[,1:2],
col = hclust.k2.colors,
pch = pch.er1,
las = 1, cex = 0.7,
main = "Hclust 2 clusters versus markers")
legend("topright", cex = 0.8, legend = c("ER1+", "ER1-"), pch = )
plot(BIC.prcomp$x[,1:2],
col = kmeans.k10.colors,
pch = pch.er1,
las = 1, cex = 0.7,
main = "K-means 10 clusters versus markers")
Nous allons maintenant comparer les résultats de ces deux méthodes de clustering.
à l’aide de la fonction table
, calculez la matrice de confusion de vos deux clustering. Commentez.
à l’aide de la fonction adjustedRand(clues)
calculez le RI et le ARI de vos clustering. Commentez.
par(mfrow=c(1,2))
plot(BIC.hclust.ward, labels=FALSE, hang=-1, main = "Ward")
rect.hclust(BIC.hclust.ward, k=3)
BIC.cutree3 <- cutree(BIC.hclust.ward, k=3)
plot(BIC.hclust.ward, labels = F, hang = -1, main = "complete")
rect.hclust(BIC.hclust.ward, k = 10)
BIC.cutree10 <- cutree(BIC.hclust.ward, k = 10)
table(BIC.cutree3, BIC.kmeans$cluster)
BIC.cutree3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1 114 2 59 0 0 0 16 32 0 0 27 31 70 42 0 0 4 65 10 0
2 0 0 0 0 7 33 0 0 5 23 0 0 0 0 31 9 0 0 0 24
3 1 11 3 57 0 0 0 0 0 0 21 5 0 40 1 0 66 9 0 1
table(BIC.cutree10, BIC.kmeans$cluster)
BIC.cutree10 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1 107 0 55 0 0 0 2 5 0 0 21 1 3 40 0 0 4 23 0 0
2 0 0 0 0 7 33 0 0 0 13 0 0 0 0 3 9 0 0 0 1
3 0 0 0 51 0 0 0 0 0 0 0 0 0 0 1 0 3 0 0 1
4 1 11 3 6 0 0 0 0 0 0 21 5 0 40 0 0 63 9 0 0
5 0 0 0 0 0 0 14 1 0 0 0 0 0 0 0 0 0 1 0 0
6 0 0 0 0 0 0 0 0 0 10 0 0 0 0 28 0 0 0 0 23
7 7 0 2 0 0 0 0 26 0 0 6 30 0 2 0 0 0 41 0 0
8 0 2 2 0 0 0 0 0 0 0 0 0 66 0 0 0 0 0 0 0
9 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 10 0
10 0 0 0 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0
par(mfrow = c(1,1))
clues::adjustedRand(BIC.cutree3, BIC.kmeans3$cluster)
Rand HA MA FM Jaccard
0.6742643 0.3286149 0.3297773 0.6058162 0.4341984
clues::adjustedRand(BIC.cutree10, BIC.kmeans10$cluster)
Rand HA MA FM Jaccard
0.8481182 0.4189739 0.4228339 0.5141232 0.3377504
clues::adjustedRand(BIC.cutree3, BIC.kmeans10$cluster)
Rand HA MA FM Jaccard
0.6586272 0.2323173 0.2344287 0.4545910 0.2348100
clues::adjustedRand(BIC.cutree10, BIC.kmeans3$cluster)
Rand HA MA FM Jaccard
0.6745688 0.2536610 0.2557085 0.4747715 0.2824229
Nous connaissons les types de cancer des différentes tumeurs, définie en combinant trois marqueurs immunologiques :
et nous obtenons les classes suivantes :
qqs tumeurs sont non classées
Vous pouvez lire les données concernant le type de cancer grâce à la fonction read.table
, la ligne de commande est : mes.classes <- read.table("../../xxxx/BIC_sample-classes.tsv", h=T)
. A l’aide de la fonction summary
, déterminez le nombre de tumeurs pour chaque type de cancer
## Correspondence between markers
kable(table(BIC.sample.classes$ER1, BIC.sample.classes$PR1))
Negative | Positive | |
---|---|---|
Negative | 172 | 12 |
Positive | 95 | 540 |
fisher.test(table(BIC.sample.classes$ER1, BIC.sample.classes$PR1))
Fisher's Exact Test for Count Data
data: table(BIC.sample.classes$ER1, BIC.sample.classes$PR1)
p-value < 0.00000000000000022
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
42.94805 165.19652
sample estimates:
odds ratio
80.90786
# cut the tree at different levels (2, 5)
plot(BIC.hclust.ward, labels = FALSE, hang = -1)
rect.hclust(BIC.hclust.ward, k = 5, border = "blue")
rect.hclust(BIC.hclust.ward, k = 2, border = "red")
legend("topright",
legend = c("2 clusters", "5 clusters"),
col = c("red", "blue"), lwd = 2, cex = 0.7)
## hclust 2 clusters versus each marker
table(BIC.cutree2, BIC.sample.classes$Her2)
BIC.cutree2 Negative Positive
1 508 179
2 123 9
table(BIC.cutree2, BIC.sample.classes$ER1)
BIC.cutree2 Negative Positive
1 67 620
2 117 15
table(BIC.cutree2, BIC.sample.classes$PR1)
BIC.cutree2 Negative Positive
1 142 545
2 125 7
## K-means 2 clusters versus each marker
table(BIC.kmeans2$cluster, BIC.sample.classes$ER1)
Negative Positive
1 45 616
2 139 19
table(BIC.kmeans2$cluster, BIC.sample.classes$PR1)
Negative Positive
1 119 542
2 148 10
table(BIC.kmeans2$cluster, BIC.sample.classes$Her2)
Negative Positive
1 497 164
2 134 24
## 5 clusters
table(BIC.cutree5, BIC.sample.classes$Her2)
BIC.cutree5 Negative Positive
1 337 54
2 123 9
3 16 40
4 96 63
5 59 22
table(BIC.cutree5, BIC.sample.classes$ER1)
BIC.cutree5 Negative Positive
1 4 387
2 117 15
3 42 14
4 4 155
5 17 64
table(BIC.cutree5, BIC.sample.classes$cancer.type)
BIC.cutree5 Basal.like HER2pos Luminal.A Luminal.B Unclassified
1 3 0 298 51 39
2 104 7 1 0 20
3 11 28 2 5 10
4 1 2 80 47 29
5 12 4 41 15 9
cluster.vs.cancertype <- table(
BIC.cutree5,
BIC.sample.classes$cancer.type)
kable(cluster.vs.cancertype, caption = "Hierarchical clusters (c = 5) versus cancer type. ")
Basal.like | HER2pos | Luminal.A | Luminal.B | Unclassified |
---|---|---|---|---|
3 | 0 | 298 | 51 | 39 |
104 | 7 | 1 | 0 | 20 |
11 | 28 | 2 | 5 | 10 |
1 | 2 | 80 | 47 | 29 |
12 | 4 | 41 | 15 | 9 |
## clustering versus cancer.type
## Compute the confusion table and adjusted RAND index (ARI)
## 2 clusters versus each marker
table(BIC.cutree2, BIC.sample.classes$ER1)
BIC.cutree2 Negative Positive
1 67 620
2 117 15
clues::adjustedRand(
BIC.cutree2,
as.numeric(BIC.sample.classes$ER1))
Rand HA MA FM Jaccard
0.8195844 0.5810808 0.5813049 0.8707027 0.7688294
table(BIC.cutree2, BIC.sample.classes$PR1)
BIC.cutree2 Negative Positive
1 142 545
2 125 7
clues::adjustedRand(
BIC.cutree2,
as.numeric(BIC.sample.classes$PR1))
Rand HA MA FM Jaccard
0.7019742 0.3692338 0.3696219 0.7755577 0.6244903
table(BIC.cutree2, BIC.sample.classes$Her2)
BIC.cutree2 Negative Positive
1 508 179
2 123 9
clues::adjustedRand(
BIC.cutree2,
as.numeric(BIC.sample.classes$Her2))
Rand HA MA FM Jaccard
0.53388801 -0.07618062 -0.07559919 0.66226224 0.49369937
## 5 clusters versus cancer type
table(BIC.cutree5, BIC.sample.classes$cancer.type)
BIC.cutree5 Basal.like HER2pos Luminal.A Luminal.B Unclassified
1 3 0 298 51 39
2 104 7 1 0 20
3 11 28 2 5 10
4 1 2 80 47 29
5 12 4 41 15 9
clues::adjustedRand(
BIC.cutree5,
as.numeric(BIC.sample.classes$cancer.type))
Rand HA MA FM Jaccard
0.7105600 0.3330860 0.3348268 0.5451923 0.3743410
## Negative control: compute the same stat with randomly permuted values
table(BIC.cutree5, BIC.sample.classes$cancer.type)
BIC.cutree5 Basal.like HER2pos Luminal.A Luminal.B Unclassified
1 3 0 298 51 39
2 104 7 1 0 20
3 11 28 2 5 10
4 1 2 80 47 29
5 12 4 41 15 9
clues::adjustedRand(
sample(BIC.cutree5),
as.numeric(BIC.sample.classes$cancer.type))
Rand HA MA FM Jaccard
0.57235104 0.01463136 0.01720336 0.32763791 0.19572626
table(BIC.kmeans3$cluster, BIC.sample.classes$cancer.type)
Basal.like HER2pos Luminal.A Luminal.B Unclassified
1 22 31 111 41 39
2 1 0 310 77 47
3 108 10 1 0 21
clues::adjustedRand(
BIC.kmeans3$cluster,
as.numeric(BIC.sample.classes$cancer.type))
Rand HA MA FM Jaccard
0.6658905 0.2828718 0.2843799 0.5447041 0.3720078
table(BIC.kmeans10$cluster, BIC.sample.classes[,1])
Basal.like HER2pos Luminal.A Luminal.B Unclassified
1 2 0 112 17 12
2 12 4 39 15 9
3 0 0 13 3 0
4 0 0 99 21 7
5 0 0 45 8 10
6 23 1 1 2 9
7 0 0 36 12 9
8 85 6 0 0 13
9 7 30 2 8 11
10 2 0 75 32 27
clues::adjustedRand(BIC.kmeans10$cluster,
as.numeric(BIC.sample.classes[,1]))
Rand HA MA FM Jaccard
0.6788707 0.1385942 0.1418883 0.3302313 0.1726480
# Visualisation
## hclust (2 groupes) et HER2+/-
plot(BIC.prcomp$x[,1:2],
col = hclust.k2.colors,
pch = as.numeric(BIC.sample.classes$ER1), # character indicates ER1 status
las = 1, cex = 0.7,
main = "Clusters versus markers")
grid()
texte.legend <- c("ER1-", "ER1+", "gr1", "gr2")
legend("topright", texte.legend,
col = c(1, 1, 1, 2),
pch = c(1, 2, NA, NA),
text.col = c(1, 1, 1, 2))
## Draw a confusion table of cluster versus ER1
kable(table(BIC.cutree2, BIC.sample.classes$ER1), caption = "hclust clusters versus ER1 marker")
Negative | Positive |
---|---|
67 | 620 |
117 | 15 |
A la fin de tout travail d’analyse, il est important de conserver une trace précise et complète de l’environnement précis utilisé pour produire les résultats.
## Print the complete list of libraries + versions used in this session
sessionInfo()
R version 3.5.2 (2018-12-20)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Mojave 10.14.3
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/3.5/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.5/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] grid stats graphics grDevices utils datasets methods base
other attached packages:
[1] ClassDiscovery_3.3.9 oompaBase_3.2.6 cluster_2.0.7-1 ComplexHeatmap_1.20.0 RColorBrewer_1.1-2 clues_0.5.9 FactoMineR_1.41 knitr_1.21
loaded via a namespace (and not attached):
[1] Rcpp_1.0.0 magrittr_1.5 MASS_7.3-51.1 leaps_3.0 mclust_5.4.2 scatterplot3d_0.3-41 colorspace_1.4-0 lattice_0.20-38 rjson_0.2.20 highr_0.7 stringr_1.4.0 tools_3.5.2 circlize_0.4.5 xfun_0.5
[15] htmltools_0.3.6 yaml_2.2.0 digest_0.6.18 oompaData_3.1.1 GlobalOptions_0.1.0 shape_1.4.4 evaluate_0.13 rmarkdown_1.11 stringi_1.3.1 compiler_3.5.2 flashClust_1.01-2 GetoptLong_0.1.7