• Aucun résultat trouvé

Etude des expressions des gènes uniques par régression linéaire mixte

Arthur Gomez, dernière version du fichier : 9 avril 2013

Préparation des données

En premier lieu, nous avons donc créé pour chaque gène unique, un vecteur, rassemblant les valeurs d'expression pour chaque expérience où l'on a des

observations pour ce gène. Les gènes avec plusieurs représentants ont eux un vecteur de taille plus élevée (avec toutes les valeurs d'expression pour chaque expérience, de chacun des réprensentants), de manière à utiliser toutes les données disponibles lors de la regression. Les temps de prélèvement sont eux sauvegardés dans le vecteur time.steps, et les numéros des cochons dans pigs.

# This file makes a list of vectors Each element of the list corresponds

# to one unique gene and is a vector having a number of elements equal to

# the number of clones multiplied by the number of experiments

# Two other lists are constructed: pigs gives the number of the pig and

# times the time step

load("../data/acth-data.rda")

duplicates <- read.table("../data/duplicates.csv", sep = ";", header = TRUE)

duplicates$N.gene <- as.factor(duplicates$N.gene) jdd <- list()

pigs <- list()

time.steps <- list()

for (i in seq_along(unique(duplicates$N.gene))) { the.clones <- which(duplicates$N.gene ==

Ensuite, nous avons exécuté une régression linéaire mixte, en fonction du temps de prélèvement et où le facteur aléatoire est composé du cochon et du numéro de doublon (pour les gènes ayant plusieurs représentants)

Il y a donc pour chaque gène unique 3 pentes absolues (entre 0 et 1h, entre 1h et 4h et enfin entre 4h et 24h) calculées à partir des valeurs des différentes expériences où l'on a les observations.

Finalement, en divisant le coefficient de la pente par l'ordonnée à l'origine au temps 0 , on pourra obtenir les pentes relatives dans une autre matrice.

expr = a × temps + b + v

cochon×doublon

+ ϵ.

a/b

library(nlme)

slope.calculation <- function(the.expr, sel.factor, sel.time) { obs <- !is.na(the.expr)

g <- the.expr[obs]

times <- sel.time[obs]

tfind <- factor(sel.factor)[obs]

tdata <- data.frame(g, times, tfind)

reslm <- lme(g ~ times, random = ~1 | tfind, data = tdata) reslm$coefficients$fixed[2]

}

slope.calculation2 <- function(the.expr, sel.factor, sel.time) { obs <- !is.na(the.expr)

g <- the.expr[obs]

times <- sel.time[obs]

tfind <- factor(sel.factor)[obs]

tdata <- data.frame(g, times, tfind)

reslm <- lme(g ~ times, random = ~1 | tfind, data = tdata)

the.factor <- factor(paste("pig", the.pigs, "_clone", rep(1:nb.clones, rep(30,

nb.clones)), sep = ""))

tnt <- rep(1, length(the.times)) tnt[the.times == 1] <- 2

tnt[the.times == 4] <- 3 tnt[the.times == 24] <- 4

all.slopes <- vector(length = 4) for (sel.t in 1:3) {

sel.factor,

sel.times) }

}

all.slopes }

all.slopes <- t(sapply(names(jdd), super.slopes))

all.slopes.re <- sweep(all.slopes[, 1:3], 1, all.slopes[, 4], "/") all.slopes <- all.slopes[, 1:3]

save(all.slopes, file = "../results/all_slopes.rda")

save(all.slopes.re, file = "../results/all_slopes_re.rda")

Brève analyse des pentes

Voici donc un premier aperçu des données pour les 2 types de pente :

summary(all.slopes)

## V1 V2 V3

## Min. :-0.450 Min. :-3.324 Min. :-0.785

## 1st Qu.: 0.101 1st Qu.:-1.233 1st Qu.:-0.194

## Median : 0.528 Median :-0.777 Median : 0.178

## Mean : 0.551 Mean :-0.843 Mean : 0.366

## 3rd Qu.: 0.853 3rd Qu.:-0.376 3rd Qu.: 0.684

## Max. : 1.969 Max. : 0.686 Max. : 3.798

boxplot(all.slopes, xlab = "Pas de temps", ylab = "Pente", main =

"Boxplot pentes absolues")

D'une manière générale, les pentes entre les temps 1 et 2 ( et ) et les pentes entre les temps 3 et 4 (( et ) sont plus fortes que les pentes entre les temps 2 et 3.

summary(all.slopes.re)

## V1 V2 V3

## Min. :-0.0555 Min. :-0.3801 Min. :-0.1765

## 1st Qu.: 0.0108 1st Qu.:-0.1705 1st Qu.:-0.0185

## Median : 0.0621 Median :-0.0931 Median : 0.0253

## Mean : 0.0814 Mean :-0.1107 Mean : 0.0388

## 3rd Qu.: 0.1024 3rd Qu.:-0.0401 3rd Qu.: 0.0828

## Max. : 0.4428 Max. : 0.0919 Max. : 0.4225

boxplot(all.slopes.re, xlab = "Pas de temps", main = "Boxplot pentes relatives",

ylab = "Pentes")

t = 0 t = 1

t = 4 t = 24

Nous allons ensuite utiliser les données de ces pentes pour essayer de classer les différents gènes significativement exprimés afin de définir des profils pour chaque gène, illustrant l'évolution de leur expression au cours du temps.

A.2. Tri empirique des profils d’expression

Tri des gènes selon des profils de pente

Arthur Gomez, dernière version du fichier : 23 avril 2013

Description du travail et de la méthodologie

Nous avons commencé donc à définir 3 types de pente :

les pentes nulles ou quasi nulles (dont la valeur absolue est inférieure au premier décile des pentes absolues) : “ = ”

les pentes positives (supérieures au premier décile): “ + ”

les pentes négatives (inférieures à 0, dont la valeur absolue est supérieure au premier décile) : “ - ”

Ainsi, pour chaque gène, nous définierons un profil qui prend en compte ses 3 pentes : par exemple “+-+” pour définir une première pente postive, une seconde négative et une dernière à nouveau positive.

Une première étude a montré qu'il y avait beaucoup de pentes peu élevées

considérées comme croissantes, ou décroissantes, ce qui entrainait des profils aux effectifs très hétérogènes. Afin de pallier ce problème, le seuil pour définir les pentes nulles a été relevé, à 15% des pentes les plus faibles (en valeur absolue), puis au second décile des valeurs absolues des pentes.

Cette étude a donc été effectuée en premier lieu pour les pentes absolues :

load("../data/acth-data.rda")

duplicates <- read.table("../data/duplicates.csv", sep = ";", header = TRUE)

duplicates$N.gene <- as.factor(duplicates$N.gene) jdd <- list()

pigs <- list()

time.steps <- list()

for (i in seq_along(unique(duplicates$N.gene))) { the.clones <- which(duplicates$N.gene ==

classif <- matrix(nrow = nrow(all.slopes), ncol = 4) for (i in 1:nrow(all.slopes)) {

for (j in 1:3) {

a <- quantile(abs(all.slopes[, j]), probs = 0.1) if (all.slopes[i, j] >= a) {

if ((all.slopes[i, j] > (-a)) && (all.slopes[i, j] < (a))) {

classif[i, j] <- "="

}

classif[i, 4] <- paste(classif[i, 1], classif[i, 2], classif[i, 3],

sep = "") }

}

table(classif[, 4])

##

## ==- =-+ =+- -=+ --+ -+- +=- +-= +-- +-+

## 1 3 3 2 4 3 4 7 9 26

La classification ainsi obtenue étant très déséquilibrée et ayant donné des classes dont les pentes notées “+” avaient une variabilité importante, nous avons reproduit l'étude en seuillant au deuxième décile.

Seuillage au deuxième décile

classif <- matrix(nrow = nrow(all.slopes), ncol = 4) for (i in 1:nrow(all.slopes)) {

for (j in 1:3) {

La classification est beaucoup plus équilibrée. Nous l'analysons en représentant sur un même graphique, tous les clônes de tous les animaux correspondant à un même gène.

Les graphiques sont triés par profil d'évolution.

jeplotencouleur <- function(nu) {

the.factor <- factor(paste("pig", the.pigs, "_clone", rep(1:nb.clones, rep(30,

nb.clones)), sep = ""))

tnt <- rep(1, length(the.times)) tnt[the.times == 1] <- 2

tnt[the.times == 4] <- 3 tnt[the.times == 24] <- 4

the.colors <- rainbow(nlevels(the.factor))

plot(NA, type = "n", xlim = c(1, 4), ylim = range(the.expr, na.rm = TRUE),

axes = FALSE, xlab = "Heure de prélèvement", ylab =

"Valeur d'expression",

main = paste("gène numéro", names(jdd)[nu], sep = " ")) axis(2)

axis(1, at = c(1, 2, 3, 4), labels = c("+0h", "+1h", "+4h",

"+24h"))

for (ind in seq_along(unique(the.factor))) { the.ind <- unique(the.factor)[ind]

pig.gene <- the.expr[the.factor == the.ind]

x.value <- tnt[the.factor == the.ind]

# order.time <- match(c(0, 1, 4, 24), tnt[the.factor ==

the.ind])

lines(x.value, pig.gene, col = the.colors[ind], type =

"b", pch = 19) }

plot.new()

legend("center", lty = 1, col = the.colors, legend = unique(the.factor))

}

Gènes composant chaque profil (pentes absolues) :

==-liste <- which(classif[, 4] == "==-") names(jdd[liste])

## [1] "33" "37"

for (ind in liste) jeplotencouleur(ind)

A.3. Classification automatique des profils d’expression

Classification des gènes selon leur profil pentes

Arthur Gomez, dernière version du fichier : 2 mai 2013

Nous allons donc utiliser les pentes sur les expressions des gènes aux différents temps, pour essayer de définir plusieurs profils, classes de gènes. Nous commencerons donc par les données brutes, puis par la suite avec les pentes centrées et réduites.

Phase exploratoire : classification ascendante hiérarchique

En premier lieu, nous auront une approche par classification ascendante hiérarchique, afin d'avoir une idée du nombre de classes à définir.

load("../results/all_slopes.rda")

x <- dist(all.slopes, method = "euclidean") cha <- hclust(x, method = "ward")

plot(cha, main = "Classification hiérarchique des gènes selon les valeurs de leurs pentes de régression absolues",

xlab = "gènes", ylab = "inertie intra")

Cette classification se fait à partir de la distance euclidienne et utilise la méthode de Ward. On peut donc penser à partir de ce dendrogramme que 5 classes peut être un choix pertinent pour une étude à partir des k-means sur les pentes absolues.

load("../results/all_slopes_re.rda")

y <- dist(all.slopes.re, method = "euclidean") chr <- hclust(y, method = "ward")

plot(chr, main = "Classification hiérarchique des gènes selon les valeurs de leurs pentes de régression relatives",

xlab = "gènes", ylab = "inertie intra")

Sur les pentes relatives, on peut penser que le nombre de 4 classes est pertinent pour une approche par k-means Ensuite, nous allons passer à une classification sur les pentes qui seront centrées, et réduites.

penta <- scale(all.slopes)

x2 <- dist(penta, method = "euclidean") cha2 <- hclust(x2, method = "ward")

plot(cha2, main = "Classification hiérarchique des gènes selon les valeurs de leurs pentes de régression absolues",

xlab = "gènes", ylab = "inertie intra")

Là encore, on choisira de retenir 4 classes.

pentr <- scale(all.slopes.re)

y2 <- dist(pentr, method = "euclidean") chr2 <- hclust(y2, method = "ward")

plot(chr2, main = "Classification hiérarchique des gènes selon les valeurs de leurs pentes de régression relatives",

xlab = "gènes", ylab = "inertie intra")

Enfin, sur cette dernière classfication hiérarchique sur les pentes relatives

(préalablement centrées et réduites), un découpage en 4 classes semble être adapté pour une étude selon les k-means.

Représentation des données

Les individus (gènes) ont 3 dimensions (trois pentes). Pour les représenter en deux dimensions, on utilise une méthode appelée MDS (Multi-Dimensional Scaling) : cette méthode projette les individus sur un plan de manière à miniser la distorsion des distances deux à deux entre individus (cf Cox & Cox, 2001). Nous nous servirons

ensuite de cette représentation pour comparer les classifications obtenues.

coord <- cmdscale(dist(all.slopes))

plot(coord, pch = 19, xlab = "Première dimension", ylab =

"Deuxième dimension",

main = "Représentation des données par projection MDS")

Classification basée sur la méthode des k-means

La méthode des k-means exécute une classification selon des centres moyens (dont le nombre est un paramètre à choisir). Le nombre d'exécutions est défini par le

paramètre itération, où l'on recherche à chaque fois d'autres classes/centre moyens.

Cette méthode de classification est aléatoire, ce qui peut expliquer des résultats différents lors de certaines exécutions. Comme pour la majorité des classifications hiérarchiques nous avons retenu 4 classes, nous utiliserons 4 comme paramètre de centre-moyens pour les classifications non hiérarchiques de manière à pouvoir comparer les différentes classifications.

k-means pour les pentes absolues

Nous allons donc effectuer une classification pour les pentes absolues, puis sur les données préalablement centrées et réduites, afin de comparer ces classifications.

faire_cl <- function(nb.classes, data) { cl <- kmeans(data, nb.classes, 200) var.tot <- as.numeric(cl[3])

var.intra <- as.numeric(cl[5])

best.score <- var.intra/var.tot * 100 for (i in 1:2000) {

compare.communities(cna$clust, cna2$clust, method = "nmi")

## [1] 0.6733

table(cna$clust, cna2$clust)

##

## 1 2 3 4

## 1 0 0 4 9

## 2 0 0 22 9

## 3 12 0 0 0

## 4 0 6 0 0

plot(coord, type = "n")

text(coord[, 1], coord[, 2], cna$clust, col = cna$clust)

plot(coord, type = "n")

text(coord[, 1], coord[, 2], cna2$clust, col = cna2$clust)

k-means pour les pentes relatives

De la même manière que pour les pentes absolues, nous allons comparer les classifications obtenues par la méthode des k-means selon que les données sont centrées-réduites ou non.

load("../results/all_slopes_re.rda") set.seed(11041222)

cnr <- faire_cl(4, all.slopes.re)

load("../results/all_slopes_re.rda") set.seed(11041222)

cnr2 <- faire_cl(4, scale(all.slopes.re))

table(cnr$clust, cnr2$clust)

##

## 1 2 3 4

## 1 13 0 0 0

## 2 0 30 0 0

## 3 0 0 12 0

## 4 0 0 0 7

library(igraph)

compare.communities(cnr$clust, cnr2$clust, method = "nmi")

## [1] 1

plot(coord, type = "n")

text(coord[, 1], coord[, 2], cnr$clust, col = cnr$clust)

plot(coord, type = "n")

text(coord[, 1], coord[, 2], cnr2$clust, col = cnr2$clust)

Essai de classifications avec un nombre de classes plus élevé

La fonction suivante permet de calculer, pour un nombre de classes donné, le pourcentage de variance expliquée obtenue par la meilleure classification sur 2000 classifications obtenues par la méthode des k-means :

faire_clv2 <- function(nb.classes, data) { cl <- kmeans(data, nb.classes, 200) var.tot <- as.numeric(cl[3])

var.intra <- as.numeric(cl[5])

best.score <- var.intra/var.tot * 100 for (i in 1:2000) {

classif <- kmeans(data, nb.classes, 200) var.tot <- as.numeric(classif[3])

var.intra <- as.numeric(classif[5]) score <- var.intra/var.tot * 100 if (best.score > score) {

cl <- classif

best.score <- score }

}

best.score }

On refait la classification en augmentant le nombre de classes : pour trouver un nombre de classes pertinent, on commence par calculer, pour un nombre de classes variant de 1 à 10, le pourcentage de variance on expliquée par le nombre de classes :

set.seed(29121032)

matrice.test <- matrix(nrow = 10, ncol = 4) for (j in 1:4) {

if (j == 1) {

data <- all.slopes for (i in 1:10) {

matrice.test[i, j] <- faire_clv2(i, data) }

}

if (j == 2) {

data <- scale(all.slopes) for (i in 1:10) {

matrice.test[i, j] <- faire_clv2(i, data) }

}

if (j == 3) {

data <- all.slopes.re for (i in 1:10) {

matrice.test[i, j] <- faire_clv2(i, data) }

}

if (j == 4) {

data <- scale(all.slopes.re) for (i in 1:10) {

matrice.test[i, j] <- faire_clv2(i, data) }

} }

colnames(matrice.test) <- c("absolues", "absolues+scale",

"relatives", "relatives+scale") matrice.test

## absolues absolues+scale relatives relatives+scale

## [1,] 100.000 100.000 100.000 100.000

Pour les 4 types de données, nous avons ensuite effectué une classification avec un nombre de classes plus élevé (que 4) et qui paraissait pertinent, du point de vue de la

variance expliquée.

set.seed(29041014)

cl1 <- faire_cl(5, all.slopes)

cl2 <- faire_cl(8, scale(all.slopes)) cl3 <- faire_cl(8, all.slopes.re)

cl4 <- faire_cl(6, scale(all.slopes.re))

plot(coord, type = "n", main = "Données : pentes absolues avec 5 classes")

text(coord[, 1], coord[, 2], cl1$clust, col = cl1$clust)

plot(coord, type = "n", main = "Données : pentes absolues et centrées/réduites avec 8 classes")

text(coord[, 1], coord[, 2], cl2$clust, col = cl2$clust)

plot(coord, type = "n", main = "Données : pentes relatives avec 8 classes")

text(coord[, 1], coord[, 2], cl3$clust, col = cl3$clust)

plot(coord, type = "n", main = "Données : pentes relatives et centrées/réduites avec 6 classes")

text(coord[, 1], coord[, 2], cl4$clust, col = cl4$clust)

On peut remarquer que travailler sur les données absolues donnent des résultats semblant plus homogènes (confirmé par le tableau de pourcentages des variances intra toujours plus faibles, à nombre de classes égales). De plus,sur les pentes absolues, parfois les données centrées et réduites donnent un peu moins d'inertie intra, et cette approche peut donc être intéressante selon le nombre de classes demandées.

Composition des classes pour les classifications des pentes absolues

Nous allons appliquer cette fonction graphique aux gènes classés selon les

classifications des pentes absolues ci-dessus (plus pertinentes que les pentes relatives au nievau de l'inertie intra). Ainsi, pour chaque classe, chaque gène unique aura une représentation graphique au cours du temps comme dans l'étude sur les catégories par tri.

jeplotencouleur <- function(nu) {

the.factor <- factor(paste("pig", the.pigs, "_clone", rep(1:nb.clones, rep(30,

nb.clones)), sep = ""))

tnt <- rep(1, length(the.times)) tnt[the.times == 1] <- 2

tnt[the.times == 4] <- 3 tnt[the.times == 24] <- 4

the.colors <- rainbow(nlevels(the.factor))

plot(NA, type = "n", xlim = c(1, 4), ylim = range(the.expr, na.rm = TRUE),

axes = FALSE, xlab = "Heure de prélèvement", ylab =

"Valeur d'expression",

main = paste("gène numéro", names(jdd)[nu], sep = " ")) axis(2)

axis(1, at = c(1, 2, 3, 4), labels = c("+0h", "+1h", "+4h",

"+24h"))

for (ind in seq_along(unique(the.factor))) { the.ind <- unique(the.factor)[ind]

pig.gene <- the.expr[the.factor == the.ind]

x.value <- tnt[the.factor == the.ind]

# order.time <- match(c(0, 1, 4, 24), tnt[the.factor ==

the.ind])

lines(x.value, pig.gene, col = the.colors[ind], type =

"b", pch = 19) }

plot.new()

legend("center", lty = 1, col = the.colors, legend = unique(the.factor))

}

# This file makes a list of vectors Each element of the list corresponds

# to one unique gene and is a vector having a number of elements equal to

# the number of clones multiplied by the number of experiments

# Two other lists are constructed: pigs gives the number of the pig and

# times the time step

load("../data/acth-data.rda")

duplicates <- read.table("../data/duplicates.csv", sep = ";", header = TRUE)

duplicates$N.gene <- as.factor(duplicates$N.gene) jdd <- list()

pigs <- list()

time.steps <- list()

for (i in seq_along(unique(duplicates$N.gene))) { the.clones <- which(duplicates$N.gene ==

Composition des classes (classification en 5 classes)

Classe 1 :

liste <- which(cl1$clust == "1") names(jdd[liste])

## [1] "2" "6" "10" "57" "18" "26" "35" "39" "46" "47" "62" "65"

for (ind in liste) jeplotencouleur(ind)

A.4. Etudes PLS

Analyse PLS entre les expressions des gènes et les phénotypes

mesurés

Arthur Gomez, dernière version du fichier : 23 mai 2013

Cette analyse a pour but de visualiser un lien entre phénotypes et expression de gènes. Ainsi, l'individu n'est plus le gène seul, mais un prélèvement sur un animal, à un temps après injection. De cette manière, on a normalement pour chaque

expérience, des données phénotypiques, mais aussi l'analyse du transcryptome.

Nous utiliserons dons la table phenotypes (13 phenotypes x 30 individus) et la table sign.genes (110 gènes x 30 individus) contenant les expressions des 110 gènes avec une cinétique significative au cours du temps sur les 30 expériences.

Analyse descriptive simple des phénotypes

Etant donné la nature des données, (taux, decomptes, proportions) il est interessant de centrer et réduire les données pour la représentation graphique. Sur cette distribution, on peut remarquer une certaine assymétrie pour les variables Cortisol, NEFA, et nrouge indiquant des valeurs atypiques fortes. On peut aussi remarquer une dispersion

relativement plus forte au niveau des variables glucose, uree, nlympho et nrouges.

Analyse exploratoire

load("../data/acth-data.rda") summary(phenotypes)

## cortisol glucose lactate NEFA

boxplot(scale(phenotypes), main = "Distribution des valeurs des phénotypes",

las = 3)

Analyse et correction des valeurs manquantes

Le nombre de valeurs manquantes par colonne et par ligne est donné par les lignes de commandes suivantes :

apply(phenotypes, 2, function(x) sum(is.na(x)))

## cortisol glucose lactate NEFA uree nleuco

## 8 8 8 8 8 3

## plympho pgranulo nlympho ngranulo nrouges hematocrite

## 3 3 3 3 3 3

## hemoglob

## 3

missing.in.rows <- apply(phenotypes, 1, function(x) sum(is.na(x)))

Puis les deux lignes pour lesquelles toutes les mesures phénotypiques sont

manquantes sont supprimées du fichier de données des phénotypes ainsi que du fichier des expressions de gènes :

all.missing <- which(missing.in.rows == ncol(phenotypes)) all.missing

## 7 15

## 3 7

no.allmissing.pheno <- phenotypes[-all.missing, ] kept.genes <- sign.genes[-all.missing, ]

Ensuite, le package imputation est utilisé pour imputer les valeurs manquantes par une méthode des plus proches voisins : les 3 plus proches voisins sont utilisés pour imputer les valeurs manquantes (les observations pour lesquelles la distances, calculées sur les valeurs des variables non manquantes, sont les plus proches).

imputed.pheno <- kNNImpute(no.allmissing.pheno, 3, verbose = TRUE)$x

## [1] "Computing distance matrix..."

## [1] "Distance matrix complete"

## [1] "Imputing row 9"

## [1] "Imputing row 12"

## [1] "Imputing row 16"

## [1] "Imputing row 18"

## [1] "Imputing row 20"

## [1] "Imputing row 24"

## [1] "Imputing row 28"

Enfin, la distribution des phénotypes, après correction des valeurs manquantes est donnée ci-dessous :

summary(imputed.pheno)

boxplot(scale(phenotypes), main = "Distribution des valeurs des phénotypes",

las = 3)

boxplot(scale(imputed.pheno), main = "Distribution des valeurs des phénotypes après imputation",

las = 3)

On peut voir certains changements dans la distribution, en particulier plus de valeurs atypiques. Certaines variables sont moins dispersées : Glucose ; Urée ; nleuco . On voit aussi apparaitre une certaine assymétrie due à des valeurs fortes sur l'urée, ce qui veut dire que la valeur imputée est peut être un peu trop forte comparée à la

distribution, ou que cela est lié à la valeur faible qui est considérée comme atypique après imputation.

Les autres variables gardent des distributions plutôt similaires.

L'imputation est exécutée aussi au niveau de la table sign.genes. Les individus sans mesure de phénotype qui ont été enlevés de la table phenotypes sont aussi enlevés de la table sign.genes. Enfin, les valeurs manquantes des expressions de gènes sont aussi imputées de la même manière que pour les phénotypes.

where.miss <- which(apply(kept.genes, 1, function(x) sum(is.na(x))) != 0)

nearest.nei <- names(sort(as.matrix(dist(kept.genes))[11, ])[2:4]) col.miss <- which(apply(kept.genes, 2, function(x) sum(is.na(x)))

!= 0)

imputed.genes <- kept.genes

imputed.genes[where.miss, col.miss] <-mean(kept.genes[nearest.nei, col.miss])

Partial Least Squares

Maintenant que les données sont prêtes, nous allons faire une PLS. Nous garderons pour cette première analyse 15 données d'expression sur deux dimensions (seulement 13 pour les phénotypes). Dans le nuage des individus, les individus sont identifiés par leur numéro d'expérience et par le pas de temps “t0”, “t1”, “t4”, “t24” après injection d'ACTH.

kept.indiv <- indiv[-all.missing, ]

names.indiv <- paste(kept.indiv[, 2], kept.indiv[, 3], sep = "_t") rownames(imputed.pheno) <- names.indiv

rownames(imputed.genes) <- names.indiv

pls1 <- spls(imputed.pheno, imputed.genes, ncomp = 2, mode =

"canonical", keepX = rep(13, 2), keepY = rep(15, 2))

var.coord <- plotVar(pls1, comp = 1:2, X.label = TRUE, Y.label = TRUE)

plotIndiv(pls1, comp = 1:2, ind.names = TRUE, rep.space =

"XY-variate")

seuil <- 0.6

axes.genes.pls1 <- data.frame(coord1 = factor(rep("peu représenté", nrow(var.coord$coord.Y)),

levels = c("peu représenté", "positif", "negatif")), coord2 = factor(rep("peu représenté",

nrow(var.coord$coord.Y)), levels = c("peu représenté",

"positif", "negatif")))

axes.genes.pls1[var.coord$coord.Y > seuil] <- "positif"

axes.genes.pls1[var.coord$coord.Y < -seuil] <- "negatif"

rownames(axes.genes.pls1) <- rownames(var.coord$coord.Y) axes.pheno.pls1 <- data.frame(coord1 = factor(rep("peu représenté", nrow(var.coord$coord.X)),

levels = c("peu représenté", "positif", "negatif")), coord2 = factor(rep("peu représenté",

nrow(var.coord$coord.X)), levels = c("peu représenté",

"positif", "negatif")))

axes.pheno.pls1[var.coord$coord.X > seuil] <- "positif"

axes.pheno.pls1[var.coord$coord.X < -seuil] <- "negatif"

rownames(axes.pheno.pls1) <- rownames(var.coord$coord.X)

## pgranulo peu représenté peu représenté

## nlympho positif peu représenté

## ngranulo peu représenté peu représenté

## nrouges positif peu représenté

## hematocrite positif peu représenté

## hemoglob positif peu représenté

axes.genes.pls1

## coord1 coord2

L'individu “47_t1” (cochon d'identifiant 47 au temps 1) est très éloigné des autres. De plus, il est composé de 8 valeurs liées à l'imputation sur 13 (8 valeurs manquantes dans les données d'origine).

rownames(no.allmissing.pheno) <- names.indiv

apply(no.allmissing.pheno, 1, function(x) sum(is.na(x)))

## 8_t1 8_t4 12_t0 12_t1 12_t4 26_t0 26_t1 26_t4 26_t24

Afin d'avoir une analyse plus fine, plus pertinente, nous n'allons pas le prendre en compte dans la suite de l'étude.

PLS sans l'individu “47_t1”

Nous allons donc refaire une imputation de manière à enlever l'individu “47_t1” (ici tous les individus avec plus de 7 phénotypes manquants sont exclus de l'analyse).

all.missing <- which(missing.in.rows > 7)

no.allmissing.pheno <- phenotypes[-all.missing, ] kept.genes <- sign.genes[-all.missing, ]

kept.indiv <- indiv[-all.missing, ]

names.indiv <- paste(kept.indiv[, 2], kept.indiv[, 3], sep = "_t") imputed.pheno <- kNNImpute(no.allmissing.pheno, 3, verbose =

TRUE)$x

## [1] "Computing distance matrix..."

## [1] "Distance matrix complete"

## [1] "Imputing row 9"

## [1] "Imputing row 12"

## [1] "Imputing row 16"

## [1] "Imputing row 19"

## [1] "Imputing row 23"

## [1] "Imputing row 27"

where.miss <- which(apply(kept.genes, 1, function(x) sum(is.na(x))) != 0)

nearest.nei <- names(sort(as.matrix(dist(kept.genes))[11, ])[2:4]) col.miss <- which(apply(kept.genes, 2, function(x) sum(is.na(x)))

!= 0)

imputed.genes <- kept.genes

imputed.genes[where.miss, col.miss] <-mean(kept.genes[nearest.nei, col.miss])

boxplot(scale(phenotypes), main = "Distribution des valeurs des phénotypes",

las = 3)

boxplot(scale(imputed.pheno), main = "Distribution des valeurs des phénotypes après imputation",

las = 3)

On s'apperçoit que sans l'individu 47_t1, les distributions avant et après imputation se

On s'apperçoit que sans l'individu 47_t1, les distributions avant et après imputation se

Documents relatifs