{"id":2795,"date":"2016-11-14T15:33:37","date_gmt":"2016-11-14T20:33:37","guid":{"rendered":"http:\/\/bioinfo.iric.ca\/fr\/?p=2795"},"modified":"2017-04-29T18:22:08","modified_gmt":"2017-04-29T22:22:08","slug":"pivoter-des-tables-du-format-long-a-large","status":"publish","type":"post","link":"https:\/\/bioinfo.iric.ca\/fr\/pivoter-des-tables-du-format-long-a-large\/","title":{"rendered":"Pivoter des tables: du format long \u00e0 large"},"content":{"rendered":"<p>En tant que bio-informaticiens, nous avons souvent \u00e0 manipuler des donn\u00e9es qui ne sont pas organis\u00e9es comme nous le voudrions. Un cas souvent rencontr\u00e9 est l&rsquo;obtention de donn\u00e9es qui se trouvent dans un format \u00ab\u00a0long\u00a0\u00bb au lieu de les avoir dans le format plus habituel, \u00ab\u00a0large\u00a0\u00bb. Pour ceux qui sont familiers avec la librairie ggplot du langage R, vous connaissez tr\u00e8s bien le format \u00ab\u00a0long\u00a0\u00bb. C&rsquo;est le format requis par ggplot pour lui permettre de produire ses \u00e9l\u00e9gants graphiques.<\/p>\n<p>En partant du format long, comment passer \u00e0 une martice large (avec les g\u00e8nes en rang\u00e9es et les \u00e9chantillons en colonnes)? Il y a plusieurs moyens de faire cette conversion, mais commen\u00e7ons d&rsquo;abord par g\u00e9n\u00e9rer des donn\u00e9es pour que vous puissiez essayer de les pivoter par vous-m\u00eames.<\/p>\n<p>&nbsp;<br \/>\n<center><\/p>\n<div style=\"display: table;\">\n<div style=\"display: table-cell; padding: 10px; border-right: 1px solid white;\"><center><strong> Long <\/strong><\/center><\/p>\n<hr \/>\n<pre>  genes   samples expression\r\n1   BAD     S01    7.525395\r\n2   BAD     S02    9.020534\r\n3   BAD     S03   14.099557\r\n4  TP53     S01    5.175252\r\n5  TP53     S02    4.437941\r\n6  TP53     S03    3.827847\r\n7   A2M     S01    1.055729\r\n8   A2M     S02   17.104853\r\n9   A2M     S03   14.456857\r\n<\/pre>\n<\/div>\n<div style=\"display: table-cell; padding: 10px;\"><center><strong> Large <\/strong><\/center><\/p>\n<hr \/>\n<pre>  genes      S01       S02       S03\r\n1   A2M 1.055730 17.104854 14.456857\r\n2   BAD 7.525395  9.020534 14.099557\r\n3  TP53 5.175253  4.437941  3.827848\r\n<\/pre>\n<\/div>\n<\/div>\n<p><strong>Table1.<\/strong> Petit ensemble de donn\u00e9es pr\u00e9sent\u00e9 dans le format long (\u00e0 gauche) et large (\u00e0 droite).<br \/>\n<\/center><\/p>\n<h2>G\u00e9n\u00e9ration de donn\u00e9es<\/h2>\n<p>Nous pouvons g\u00e9n\u00e9rer un petit ensemble de donn\u00e9es contenant 3 g\u00e8nes et 3 \u00e9chantillons en R en utilisant les fonctions <code>rep<\/code> et <code>rnorm<\/code>.<\/p>\n<pre ><code class=\"r\">\r\n# r\u00e9p\u00e8ter chaque item du vecteur n fois\r\ngenes = rep(c('BAD', 'TP53', 'A2M'),each=3)  \r\n#[1] \"BAD\"  \"BAD\"  \"BAD\"  \"TP53\" \"TP53\" \"TP53\" \"A2M\"  \"A2M\"  \"A2M\"\r\n\r\n# r\u00e9p\u00e8ter chaque vecteur n fois\r\nsamples = rep(c('S01', 'S02', 'S03'),times=3)  \r\n#[1] \"S01\" \"S02\" \"S03\" \"S01\" \"S02\" \"S03\" \"S01\" \"S02\" \"S03\"\r\n\r\n# choisir des nombres provenant d'une distribution normale \r\nexpression = abs(rnorm(9, 1, 10))\r\n#[1] 17.623573 13.709192  4.529254  3.056479  2.407857 15.619984  2.309779\r\n#[8]  8.497227 14.941006\r\n\r\ndf = as.data.frame(cbind(genes, samples, expression))\r\ndf$expression = as.numeric(as.character(df$expression)) \r\n<\/code><\/pre>\n<p>Le code ci-dessus g\u00e9n\u00e8re la matrice longue pr\u00e9sent\u00e9e dans la Table1. Nous pouvons utiliser la m\u00eame id\u00e9e pour construire un ensemble de donn\u00e9es de 10 000 g\u00e8nes par 1 000 \u00e9chantillons*.<\/p>\n<pre><code  class=\"r\">\r\nngenes = 10000\r\nnsamples = 1000\r\ngenes = rep(paste('G',seq(ngenes), sep=''),each=nsamples)\r\nsamples = rep(paste('S',seq(nsamples), sep=''),times=ngenes)\r\nexpression = abs(rnorm(ngenes*nsamples, 1, 10))\r\ndf = as.data.frame(cbind(genes, samples, expression))\r\ndf$expression = as.numeric(as.character(df$expression))\r\nwrite.table(df, file='longbig.txt', sep='\\t', quote=F)\r\n<\/code><\/pre>\n<h2>Pivotement en R<\/h2>\n<p>En R, les librairies les plus utilis\u00e9es pour pivoter des donn\u00e9es sont : tidyr et reshape2. Les fonctions <code>dcast<\/code> de reshape2 et <code>spread<\/code> de tidyr sont faciles \u00e0 utiliser. Nous n&rsquo;avons qu&rsquo;\u00e0 sp\u00e9cifier les donn\u00e9es \u00e0 pivoter, quelle variable devrait \u00eatre utilis\u00e9e pour remplir la matrice et comment seront organis\u00e9es les colonnes et les rang\u00e9es.<\/p>\n<p>La fonction <code>dcast<\/code> s&rsquo;attend \u00e0 recevoir une formule sp\u00e9cifiant quelles variables serviront \u00e0 identifier les rang\u00e9es et quelle variable mettre en colonnes. Le param\u00e8tre <code>value.var<\/code> sp\u00e9cifie la variable \u00e0 utiliser pour remplir la matrice. Si les identificateurs de rang\u00e9es sont compos\u00e9s de plusieurs variables, la formule ressemblera \u00e0 : <code>varRow1 + varRow2 ~ varCol <\/code>. Par exemple, <code>genes + organism ~ samples<\/code> pr\u00e9sentera les \u00e9chantillons en colonnes et le g\u00e8ne et l&rsquo;organisme comme identificateur de rang\u00e9es.<\/p>\n<p>Avec <code>spread<\/code>, seules les variables \u00e0 distribuer en colonnes et celle \u00e0 utiliser pour remplir la matrice sont sp\u00e9cifi\u00e9es.<\/p>\n<pre ><code class=\"r\">\r\nlibrary(reshape2)\r\ntb = dcast(df, genes ~ samples, value.var=\"expression\")\r\n\r\nlibrary(tidyr)\r\ntb = spread(df, samples, expression) <\/code><\/pre>\n<p>Pour le plus gros dataset de 10 000 g\u00e8nes et 1 000 \u00e9chantillons, la matrice longue contient 10 000 000 rang\u00e9es 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.<\/p>\n<h2>Pivotement en python<\/h2>\n<p>C&rsquo;est aussi facile de passer du format long \u00e0 large en python que ce l&rsquo;est en R gr\u00e2ce au <em>package<\/em> pandas. Cette librairie offre beaucoup de fonctions int\u00e9ressantes pour l&rsquo;analyse de donn\u00e9es. En fait, depuis l&rsquo;ajout de fonctions de visualisation faciles \u00e0 utiliser, je dois avouer que je me retrouve souvent \u00e0 faire en python\/pandas ce que j&rsquo;avais l&rsquo;habitude de faire en R.<\/p>\n<p>Voici comment pivoter en python avec pandas:<\/p>\n<pre class=\"python\"><code>import pandas\r\ndf = pandas.read_csv('longbig.txt', sep='\\t')\r\ntb = pandas.pivot_table(df, values=\"expression\", index=[\"genes\"], columns=\"samples\")\r\n<\/code><\/pre>\n<p>Lire le fichier prend beaucoup moins de temps, mais l&rsquo;\u00e9tape de pivotement est plus longue. Au final, pivoter le gros jeu de donn\u00e9es en python prend un temps \u00e9quivalent \u00e0 celui observ\u00e9 en R.<\/p>\n<h2>Agr\u00e9gation<\/h2>\n<p>Les fonctions <code>pivot_table<\/code> en python et <code>dcast<\/code> en R permettent \u00e9galement de faire de l&rsquo;agr\u00e9gation de donn\u00e9es, c&rsquo;est-\u00e0-dire de r\u00e9duire la dimensionnalit\u00e9 des donn\u00e9es gr\u00e2ce \u00e0 des fonctions comme la somme ou la moyenne. Par d\u00e9faut, <code>dcast<\/code> utilise une fonction de d\u00e9compte (<code>length<\/code>) comme fonction d&rsquo;agr\u00e9gation et <code>pivot_table<\/code> utilise la moyenne, mais vous pouvez utiliser la fonction de votre choix. Ainsi, si plus d&rsquo;une rang\u00e9e ont le m\u00eame identifiant, la fonction d&rsquo;agr\u00e9gation sera appliqu\u00e9e automatiquement. Par exemple, dans le code suivant, si nous ignorons les \u00e9chantillons dans l&rsquo;\u00e9tape de pivotement (on demande seulement une colonne pr\u00e9sentant l&rsquo;expression en fonction des g\u00e8nes), nous aurons plus d&rsquo;une valeur d&rsquo;expression par g\u00e8ne. Une moyenne sera donc calcul\u00e9e pour chaque g\u00e8ne.<\/p>\n<pre class=\"python\"><code>tab = pandas.pivot_table(df, values=\"expression\", index=[\"genes\"])\r\n\r\n## Moyenne de l'expression des \u00e9chantillons par g\u00e8ne\r\n#genes\r\n#G1        7.959172\r\n#G10       8.017683\r\n#G100      8.199654\r\n#G1000     8.059022\r\n#...\r\n\r\ndf.ix[df.genes=='G1',:].mean() # V\u00e9rifie que c'est bien la moyenne qui est obtenue en sortie\r\n#expression    7.959172\r\n#dtype: float64\r\n<\/code><\/pre>\n<p>Pour utiliser une fonction d&rsquo;agr\u00e9gation sur des valeurs non-num\u00e9riques, n&rsquo;oubliez pas de d\u00e9finir votre propre fonction retournant la valeur non-num\u00e9rique qui vous int\u00e9resse!<\/p>\n<p>* Si cette \u00e9tape est trop longue en R, passez \u00e0 python (vous aurez besoin de la librairie pandas) :<\/p>\n<pre class=\"python\"><code>import random \r\nimport pandas \r\nngenes = 10000\r\nnsamples =  1000\r\ngenes = ['G%i' %i for i in range(ngenes)]*nsamples\r\nsamples = ['S%i' %i for i in range(nsamples)]*ngenes\r\nsamples.sort()\r\nexpression =  [abs(random.gauss(1,10)) for i in range(nsamples*ngenes)]\r\ndf = pandas.DataFrame(zip(genes, samples), columns=['genes', 'samples'])\r\ndf['expression'] = expression\r\ndf.to_csv('longbig.txt', sep='\\t')\r\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>En tant que bio-informaticiens, nous avons souvent \u00e0 manipuler des donn\u00e9es qui ne sont pas organis\u00e9es comme nous le voudrions. Un cas souvent rencontr\u00e9 est l&rsquo;obtention de donn\u00e9es qui se trouvent dans un format \u00ab\u00a0long\u00a0\u00bb au lieu de les avoir dans le format plus habituel, \u00ab\u00a0large\u00a0\u00bb. Pour ceux qui sont familiers avec la librairie ggplot du langage R, vous connaissez tr\u00e8s bien le format \u00ab\u00a0long\u00a0\u00bb. C&rsquo;est le format requis par ggplot pour lui permettre de produire ses \u00e9l\u00e9gants graphiques. En <a href=\"https:\/\/bioinfo.iric.ca\/fr\/pivoter-des-tables-du-format-long-a-large\/\"> [&#8230;]<\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[69,26,24],"tags":[138],"class_list":["post-2795","post","type-post","status-publish","format-standard","hentry","category-analyse-de-donnees","category-langage-python","category-langage-r","tag-manipulation-de-donnees"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts\/2795","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/comments?post=2795"}],"version-history":[{"count":13,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts\/2795\/revisions"}],"predecessor-version":[{"id":3287,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/posts\/2795\/revisions\/3287"}],"wp:attachment":[{"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/media?parent=2795"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/categories?post=2795"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bioinfo.iric.ca\/fr\/wp-json\/wp\/v2\/tags?post=2795"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}