En tant que bio-informaticiens, nous avons souvent à manipuler des données qui ne sont pas organisées comme nous le voudrions. Un cas souvent rencontré est l’obtention de données qui se trouvent dans un format « long » au lieu de les avoir dans le format plus habituel, « large ». Pour ceux qui sont familiers avec la librairie ggplot du langage R, vous connaissez très bien le format « long ». C’est le format requis par ggplot pour lui permettre de produire ses élégants graphiques.
En partant du format long, comment passer à une martice large (avec les gènes en rangées et les échantillons en colonnes)? Il y a plusieurs moyens de faire cette conversion, mais commençons d’abord par générer des données pour que vous puissiez essayer de les pivoter par vous-mêmes.
genes samples expression 1 BAD S01 7.525395 2 BAD S02 9.020534 3 BAD S03 14.099557 4 TP53 S01 5.175252 5 TP53 S02 4.437941 6 TP53 S03 3.827847 7 A2M S01 1.055729 8 A2M S02 17.104853 9 A2M S03 14.456857
genes S01 S02 S03 1 A2M 1.055730 17.104854 14.456857 2 BAD 7.525395 9.020534 14.099557 3 TP53 5.175253 4.437941 3.827848
Table1. Petit ensemble de données présenté dans le format long (à gauche) et large (à droite).
Génération de données
Nous pouvons générer un petit ensemble de données contenant 3 gènes et 3 échantillons en R en utilisant les fonctions rep
et rnorm
.
# répèter chaque item du vecteur n fois
genes = rep(c('BAD', 'TP53', 'A2M'),each=3)
#[1] "BAD" "BAD" "BAD" "TP53" "TP53" "TP53" "A2M" "A2M" "A2M"
# répèter chaque vecteur n fois
samples = rep(c('S01', 'S02', 'S03'),times=3)
#[1] "S01" "S02" "S03" "S01" "S02" "S03" "S01" "S02" "S03"
# choisir des nombres provenant d'une distribution normale
expression = abs(rnorm(9, 1, 10))
#[1] 17.623573 13.709192 4.529254 3.056479 2.407857 15.619984 2.309779
#[8] 8.497227 14.941006
df = as.data.frame(cbind(genes, samples, expression))
df$expression = as.numeric(as.character(df$expression))
Le code ci-dessus génère la matrice longue présentée dans la Table1. Nous pouvons utiliser la même idée pour construire un ensemble de données de 10 000 gènes par 1 000 échantillons*.
ngenes = 10000
nsamples = 1000
genes = rep(paste('G',seq(ngenes), sep=''),each=nsamples)
samples = rep(paste('S',seq(nsamples), sep=''),times=ngenes)
expression = abs(rnorm(ngenes*nsamples, 1, 10))
df = as.data.frame(cbind(genes, samples, expression))
df$expression = as.numeric(as.character(df$expression))
write.table(df, file='longbig.txt', sep='\t', quote=F)
Pivotement en R
En R, les librairies les plus utilisées pour pivoter des données sont : tidyr et reshape2. Les fonctions dcast
de reshape2 et spread
de tidyr sont faciles à utiliser. Nous n’avons qu’à spécifier les données à pivoter, quelle variable devrait être utilisée pour remplir la matrice et comment seront organisées les colonnes et les rangées.
La fonction dcast
s’attend à recevoir une formule spécifiant quelles variables serviront à identifier les rangées et quelle variable mettre en colonnes. Le paramètre value.var
spécifie la variable à utiliser pour remplir la matrice. Si les identificateurs de rangées sont composés de plusieurs variables, la formule ressemblera à : varRow1 + varRow2 ~ varCol
. Par exemple, genes + organism ~ samples
présentera les échantillons en colonnes et le gène et l’organisme comme identificateur de rangées.
Avec spread
, seules les variables à distribuer en colonnes et celle à utiliser pour remplir la matrice sont spécifiées.
library(reshape2)
tb = dcast(df, genes ~ samples, value.var="expression")
library(tidyr)
tb = spread(df, samples, expression)
Pour le plus gros dataset de 10 000 gènes et 1 000 échantillons, la matrice longue contient 10 000 000 rangées et 3 colonnes. Cela prend environ de 60-90 secondes pour lire le fichier de 331 MB en R et environ 10 secondes pour pivoter la table.
Pivotement en python
C’est aussi facile de passer du format long à large en python que ce l’est en R grâce au package pandas. Cette librairie offre beaucoup de fonctions intéressantes pour l’analyse de données. En fait, depuis l’ajout de fonctions de visualisation faciles à utiliser, je dois avouer que je me retrouve souvent à faire en python/pandas ce que j’avais l’habitude de faire en R.
Voici comment pivoter en python avec pandas:
import pandas
df = pandas.read_csv('longbig.txt', sep='\t')
tb = pandas.pivot_table(df, values="expression", index=["genes"], columns="samples")
Lire le fichier prend beaucoup moins de temps, mais l’étape de pivotement est plus longue. Au final, pivoter le gros jeu de données en python prend un temps équivalent à celui observé en R.
Agrégation
Les fonctions pivot_table
en python et dcast
en R permettent également de faire de l’agrégation de données, c’est-à-dire de réduire la dimensionnalité des données grâce à des fonctions comme la somme ou la moyenne. Par défaut, dcast
utilise une fonction de décompte (length
) comme fonction d’agrégation et pivot_table
utilise la moyenne, mais vous pouvez utiliser la fonction de votre choix. Ainsi, si plus d’une rangée ont le même identifiant, la fonction d’agrégation sera appliquée automatiquement. Par exemple, dans le code suivant, si nous ignorons les échantillons dans l’étape de pivotement (on demande seulement une colonne présentant l’expression en fonction des gènes), nous aurons plus d’une valeur d’expression par gène. Une moyenne sera donc calculée pour chaque gène.
tab = pandas.pivot_table(df, values="expression", index=["genes"])
## Moyenne de l'expression des échantillons par gène
#genes
#G1 7.959172
#G10 8.017683
#G100 8.199654
#G1000 8.059022
#...
df.ix[df.genes=='G1',:].mean() # Vérifie que c'est bien la moyenne qui est obtenue en sortie
#expression 7.959172
#dtype: float64
Pour utiliser une fonction d’agrégation sur des valeurs non-numériques, n’oubliez pas de définir votre propre fonction retournant la valeur non-numérique qui vous intéresse!
* Si cette étape est trop longue en R, passez à python (vous aurez besoin de la librairie pandas) :
import random
import pandas
ngenes = 10000
nsamples = 1000
genes = ['G%i' %i for i in range(ngenes)]*nsamples
samples = ['S%i' %i for i in range(nsamples)]*ngenes
samples.sort()
expression = [abs(random.gauss(1,10)) for i in range(nsamples*ngenes)]
df = pandas.DataFrame(zip(genes, samples), columns=['genes', 'samples'])
df['expression'] = expression
df.to_csv('longbig.txt', sep='\t')
Laisser un commentaire