All in One View

Content from Organisation des données avec des feuilles de calcul


Last updated on 2026-11-07 | Edit this page

Overview

Questions

  • Comment organiser des données tabulaires ?

Objectives

  • Découvrez les feuilles de calcul, leurs points forts et leurs points faibles.
  • Comment mettre en forme les données dans des feuilles de calcul pour une utilisation efficace des données ?
  • Apprenez à reconnaître les erreurs courantes dans les feuilles de calcul et comment les corriger.
  • Organisez vos données selon les principes des données ordonnées.
  • Apprenez à utiliser des formats de feuilles de calcul textuelles tels que les formats séparés par des virgules (CSV) ou par des tabulations (TSV).

Cet épisode est basé sur la leçon Data Analysis and Visualisation in R for Ecologists de Data Carpentries.

Logiciels de feuilles de calcul


Question

  • Quels sont les principes de base pour utiliser des feuilles de calcul afin d’organiser efficacement les données ?

Objectif

  • Décrivez les bonnes pratiques pour organiser les données afin que les ordinateurs puissent tirer le meilleur parti des jeux de données.

Point clé

  • Une bonne organisation des données est le fondement de tout projet de recherche.

Une bonne organisation des données est le fondement de votre projet de recherche. La plupart des chercheurs disposent de données ou effectuent leur saisie dans des feuilles de calcul. Les logiciels de feuilles de calcul sont des interfaces graphiques très utiles pour concevoir des tableaux de données et gérer des fonctions de contrôle de la qualité des données très basiques. Voir également Broman and Woo (2018).

Plan de la feuille de calcul

Les feuilles de calcul sont adaptées à l’entrée de données. C’est pourquoi nous avons beaucoup de données dans des feuilles de calcul. Une grande partie de votre temps en tant que chercheur sera consacrée à cette étape de « manipulation des données ». Ce n’est pas le plus plaisant, mais c’est nécessaire. Nous vous apprendrons comment concevoir l’organisation des données ainsi que quelques pratiques pour une manipulation des données plus efficace.

Ce que cette leçon ne vous enseignera pas

  • Comment effectuer des statistiques dans une feuille de calcul
  • Comment réaliser des graphiques dans une feuille de calcul
  • Comment écrire du code dans des logiciels de feuilles de calcul

Si vous souhaitez faire cela, une bonne référence est Head First Excel, publié par O’Reilly.

Pourquoi n’enseignons-nous pas l’analyse de données dans des feuilles de calcul ?

  • L’analyse de données dans des feuilles de calcul nécessite généralement beaucoup de travail manuel. Si vous souhaitez modifier un paramètre ou effectuer une analyse avec un nouveau jeu de données, vous devez généralement tout refaire manuellement. (Il est bien sûr possible de créer des macros, mais voir le point suivant.)

  • Il est également difficile de retracer ou de reproduire des analyses statistiques ou de graphiques réalisées dans des logiciels de feuilles de calcul lorsque l’on souhaite revenir sur son travail ou que quelqu’un demande des détails sur son analyse.

De nombreux logiciels de feuilles de calcul sont disponibles. Comme la plupart des participants utilisent Excel comme logiciel de feuille de calcul principal, cette leçon s’appuiera sur des exemples Excel. Un autre logiciel de feuille de calcul gratuit utilisable est LibreOffice. Les commandes peuvent légèrement différer d’un programme à l’autre, mais le principe général reste le même.

Les logiciels de feuilles de calcul couvrent bon nombre des tâches que nous devons être capables d’accomplir en tant que chercheurs. Nous pouvons les utiliser pour :

  • Saisie de données
  • Organisation des données
  • Sélection et tri de données
  • Statistiques
  • Graphiques

Les logiciels de feuilles de calcul utilisent des tableaux pour représenter et afficher des données. Les données formatées sous forme de tableaux constituent également le thème principal de ce chapitre, et nous verrons comment organiser les données en tableaux de manière standardisée afin de garantir une analyse ultérieure efficace.

Discussion

Défi : Discutez des points suivants avec votre voisin

  • Avez-vous utilisé des feuilles de calcul, dans vos recherches, vos cours ou à la maison ?
  • Quel type d’opérations effectuez-vous dans des feuilles de calcul ?
  • Pour quelles tâches pensez-vous que les feuilles de calcul sont adaptées ?
  • Avez-vous déjà fait quelque chose par erreur dans un programme de feuille de calcul qui vous a frustré ou déprimé ?

Problèmes liés aux feuilles de calcul

Les feuilles de calcul sont adaptées à la saisie de données, mais en réalité, nous avons tendance à utiliser les logiciels de feuilles de calcul pour bien plus que cela. Nous les employons pour créer des tableaux de données destinés à des publications, pour générer des statistiques de synthèse et pour réaliser des figures.

Générer des tableaux pour des publications dans une feuille de calcul n’est pas optimal : souvent, lors de la mise en forme d’un tableau de données pour une publication, nous présentons des statistiques de synthèse clés d’une manière qui n’est pas vraiment destinée à être lue comme des données, et cela implique souvent un formatage spécial (fusion de cellules, création de bordures, embellissement). Nous vous conseillons d’effectuer ce type d’opération au sein de votre logiciel de traitement de texte.

Les deux dernières applications, la génération de statistiques et de figures, doivent être utilisées avec prudence : en raison de la nature graphique et par glisser-déposer des programmes de feuilles de calcul, il peut être très difficile, voire impossible, de reproduire vos étapes (et encore moins de suivre celles de quelqu’un d’autre), surtout si vos statistiques ou vos figures nécessitent des calculs plus complexes. De plus, lors de calculs dans une feuille de calcul, il est facile d’appliquer par erreur une formule légèrement différente à plusieurs cellules adjacentes. Lors de l’utilisation d’un programme statistique basé sur une ligne de commande comme R ou SAS, il est pratiquement impossible d’appliquer un calcul à une observation de votre jeu de données mais pas à une autre, à moins de le faire intentionnellement.

Utilisation des feuilles de calcul pour la saisie et le nettoyage des données

Dans cette leçon, nous supposerons que vous utilisez très probablement Excel comme programme de feuilles de calcul principal — il en existe d’autres (gnumeric, Calc d’OpenOffice), et leurs fonctionnalités sont similaires, mais Excel semble être le programme le plus utilisé par les biologistes et les chercheurs en biomédecine.

Dans cette leçon, nous allons aborder :

  1. Mise en forme des tableaux de données dans des feuilles de calcul
  2. Problèmes de mise en forme
  3. Exportation de données

Mise en forme des tableaux de données dans des feuilles de calcul


Questions

  • Comment mettre en forme les données dans des feuilles de calcul pour une utilisation efficace des données ?

Objectifs

  • Décrire les bonnes pratiques de saisie et de mise en forme des données dans des feuilles de calcul.

  • Appliquez les bonnes pratiques pour organiser les variables et les observations dans une feuille de calcul.

Points clés

  • Ne modifiez jamais vos données brutes. Effectuez toujours une copie avant d’apporter toute modification.

  • Consignez dans un fichier texte brut toutes les étapes que vous suivez pour nettoyer vos données.

  • Organisez vos données selon les principes des données ordonnées.

L’erreur la plus courante consiste à traiter les logiciels de feuilles de calcul comme des cahiers de laboratoire, c’est-à-dire à s’appuyer sur le contexte, des notes en marge, la disposition spatiale des données et des champs pour transmettre des informations. En tant qu’êtres humains, nous pouvons (généralement) interpréter ces éléments, mais les ordinateurs ne perçoivent pas l’information de la même manière et, à moins d’expliquer à l’ordinateur ce que chaque élément signifie (ce qui peut s’avérer difficile !), celui-ci ne pourra pas comprendre comment nos données s’articulent.

Grâce à la puissance des ordinateurs, nous pouvons gérer et analyser des données de manière bien plus efficace et rapide, mais pour exploiter cette puissance, nous devons préparer nos données afin que l’ordinateur puisse les comprendre (et les ordinateurs sont très littéraux).

C’est pourquoi il est extrêmement important de préparer des tableaux bien structurés dès le départ, avant même de commencer à saisir les données de votre toute première expérience préliminaire. L’organisation des données est le fondement de votre projet de recherche. Elle peut faciliter ou compliquer le travail avec vos données tout au long de l’analyse ; il vaut donc la peine d’y réfléchir lors de la saisie des données ou de la mise en place de l’expérience. Vous pouvez organiser vos données de différentes manières dans les feuilles de calcul, mais certains de ces choix peuvent limiter votre capacité à travailler avec les données dans d’autres programmes, ou compliquer leur utilisation par vous-même dans six mois ou par un collaborateur.

Note : les meilleures mises en page et les meilleurs formats (ainsi que les logiciels et les interfaces) pour la saisie et l’analyse des données peuvent différer. Il est important d’en tenir compte et, idéalement, d’automatiser la conversion de l’un à l’autre.

Suivi de vos analyses

Lorsque vous travaillez avec des feuilles de calcul, pendant le nettoyage ou l’analyse des données, il est très facile de vous retrouver avec une feuille de calcul très différente de celle avec laquelle vous avez commencé. Pour pouvoir reproduire vos analyses ou comprendre ce que vous avez fait lorsqu’un évaluateur ou un enseignant demande une analyse différente, vous devriez

  • créez un nouveau fichier contenant vos données nettoyées ou analysées. Ne modifiez pas le jeu de données d’origine, sinon vous ne saurez jamais par où vous avez commencé !

  • Gardez une trace des étapes que vous avez franchies lors du nettoyage ou de l’analyse. Vous devez suivre ces étapes comme vous le feriez pour toute étape d’une expérience. Nous vous recommandons de le faire dans un fichier texte brut stocké dans le même dossier que le fichier de données.

Voici un exemple de configuration de feuille de calcul :

SCreenshot of a spreadsheet and a README.txt file.
Spreadsheet example setip

Mettez ces principes en pratique dès aujourd’hui lors de vos exercices.

Bien que la gestion des versions ne fasse pas partie du programme de ce cours, vous pouvez consulter la leçon de Carpentries sur ‘Git’ pour apprendre à maintenir le contrôle de version de vos données. Consultez également cet article de blog pour un tutoriel rapide ou Perez-Riverol et al. (2016) pour un cas d’utilisation davantage axé sur la recherche.

Structurer les données dans des feuilles de calcul

Les règles fondamentales de l’utilisation des logiciels de feuilles de calcul pour les données :

  1. Placez toutes vos variables dans des colonnes — ce que vous mesurez, comme « poids » ou « température ».
  2. Placez chaque observation dans sa propre ligne.
  3. Ne combinez pas plusieurs informations dans une seule cellule. Parfois, cela semble n’être qu’une seule chose, mais demandez-vous si c’est la seule façon dont vous souhaiteriez pouvoir utiliser ou trier ces données.
  4. Laissez les données brutes brutes — ne les modifiez pas !
  5. Exportez les données nettoyées dans un format textuel tel que le format CSV (valeurs séparées par des virgules). Cela garantit que n’importe qui puisse utiliser les données, et est requis par la plupart des dépôts de données.

Par exemple, nous disposons de données concernant des patients ayant consulté plusieurs hôpitaux à Bruxelles, en Belgique. Ils ont noté la date de la visite, l’hôpital, le sexe des patients, leur poids et leur groupe sanguin.

Si nous devions suivre les données de la manière suivante :

A table showing the blood and rhesus types encoded together in one column.
Multiple variable in a single column.

le problème est que les groupes ABO et Rhésus se trouvent dans la même colonne de type Blood. Ainsi, s’ils voulaient examiner toutes les observations du groupe A ou analyser les distributions de poids par groupe ABO, cela serait délicat avec cette configuration de données. Si, au lieu de cela, nous plaçons les groupes ABO et Rhésus dans des colonnes différentes, vous voyez que ce serait bien plus simple.

A table showing the blood and rhesus types encoded together in different columns.
Variables encoded in a single column each.

Une règle importante lors de la création d’une feuille de données est que les colonnes sont utilisées pour les variables et les lignes sont utilisées pour les observations :

  • les colonnes sont des variables
  • les lignes sont des observations
  • les cellules sont des valeurs individuelles
Discussion

Défi : Nous allons prendre un jeu de données mal structuré et décrire comment nous le nettoierions.

  1. Téléchargez un jeu de données mal structuré en cliquant sur ce lien.

  2. Ouvrez les données dans un programme de feuilles de calcul.

  3. Vous pouvez voir qu’il y a deux onglets. Les données contiennent diverses variables cliniques enregistrées dans différents hôpitaux de Bruxelles lors de la première et de la deuxième vague de COVID-19 en 2020. Comme vous pouvez le voir, les données ont été enregistrées de manière différente lors des vagues de mars et de novembre. Vous êtes désormais la personne responsable de ce projet et vous souhaitez pouvoir commencer à analyser les données.

  4. Avec la personne à vos côtés, identifiez ce qui ne va pas dans cette feuille de calcul. Discutez également des étapes que vous devriez suivre pour nettoyer les onglets des première et deuxième vagues, et pour les réunir toutes dans une seule feuille de calcul.

Important : N’oubliez pas notre premier conseil : créez un nouveau fichier (ou un nouvel onglet) pour les données nettoyées et ne modifiez jamais vos données originales (brutes).

Une fois que vous aurez effectué cet exercice, nous discuterons en groupe de ce qui ne fonctionnait pas dans ces données et de la manière dont vous les corrigeriez.

Discussion

Défi : Une fois les données nettoyées, répondez aux questions suivantes :

  • Combien d’hommes et de femmes ont participé à l’étude ?
  • Combien d’échantillons de chacun des groupes sanguins A, AB et B ont été testés ?
  • Comme ci-dessus, mais en ignorant les échantillons contaminés ?
  • Combien de sujets Rhesus + et - ont été testés ?
  • Combien de donneurs universels (O-) ont été testés ?
  • Quel est le poids moyen des hommes AB ?
  • Combien d’échantillons ont été testés dans les différents hôpitaux ?

Une excellente référence, notamment en ce qui concerne la programmation R, est l’article Tidy Data Wickham (2014).

Erreurs courantes dans les feuilles de calcul


Questions

  • Quels sont les défis courants liés au formatage des données dans des feuilles de calcul et comment peut-on les éviter ?

Objectifs

  • Reconnaître et résoudre les problèmes courants de mise en forme des feuilles de calcul.

Points clés

  • Évitez d’utiliser plusieurs tableaux au sein d’une seule feuille de calcul.
  • Évitez de répartir les données sur plusieurs onglets.
  • Enregistrez les zéros comme des zéros.
  • Utilisez une valeur nulle appropriée pour enregistrer les données manquantes.
  • N’utilisez pas de mise en forme pour transmettre des informations ou pour embellir votre feuille de calcul.
  • Placez les commentaires dans une colonne distincte.
  • Notez les unités dans les en-têtes de colonnes.
  • N’incluez qu’une seule information par cellule.
  • Évitez les espaces, les chiffres et les caractères spéciaux dans les en-têtes de colonnes.
  • Évitez les caractères spéciaux dans vos données.
  • Enregistrez les métadonnées dans un fichier texte brut distinct.

Il existe quelques erreurs potentielles auxquelles il convient de prêter attention, tant dans vos propres données que dans celles de vos collaborateurs ou provenant d’Internet. Si vous êtes conscient de ces erreurs et de leur impact négatif possible sur l’analyse ultérieure des données et l’interprétation des résultats, cela pourrait vous motiver, vous et les membres de votre projet, à tenter de les éviter. Apporter de légers ajustements à la manière dont vous formatez vos données dans des feuilles de calcul peut avoir un impact considérable sur l’efficacité et la fiabilité lors du nettoyage et de l’analyse des données.

Utilisation de plusieurs tableaux

Une stratégie courante consiste à créer plusieurs tableaux de données au sein d’une seule feuille de calcul. Cela confonde l’ordinateur, alors ne faites pas cela ! Lorsque vous créez plusieurs tableaux dans une seule feuille de calcul, vous établissez des associations erronées entre les éléments pour l’ordinateur, lequel considère chaque ligne comme une observation. Vous risquez également d’utiliser le même nom de champ à plusieurs endroits, ce qui rendra plus difficile le nettoyage de vos données pour obtenir une forme utilisable. L’exemple ci-dessous illustre ce problème :

A sheet with many subtable.
A sheet with many subtable.

Dans l’exemple ci-dessus, l’ordinateur verra (par exemple) la ligne 4 et supposera que toutes les colonnes A-AF se réfèrent au même échantillon. Cette ligne représente en réalité quatre échantillons distincts (l’échantillon 1 pour chacune des quatre dates de prélèvement différentes — le 29 mai, le 12 juin, le 19 juin et le 26 juin), ainsi que certaines statistiques de synthèse calculées (une moyenne (avr) et l’erreur-type de mesure (SEM)) pour deux de ces échantillons. Les autres lignes sont tout aussi problématiques.

Utilisation de plusieurs onglets

Mais qu’en est-il des onglets du classeur ? Cela semble être un moyen simple d’organiser les données, n’est-ce pas ? Eh bien, oui et non. Lorsque vous créez des onglets supplémentaires, vous ne permettez pas à l’ordinateur de percevoir les liens qui existent dans les données (vous devez introduire des fonctions spécifiques à l’application de feuille de calcul ou du scriptage pour garantir ce lien). Disons, par exemple, que vous créez un onglet distinct pour chaque jour où vous effectuez une mesure.

Ce n’est pas une bonne pratique pour deux raisons :

  1. vous êtes plus susceptible d’introduire par inadvertance des incohérences dans vos données si, à chaque mesure, vous commencez à enregistrer les données dans une nouvelle onglet, et

  2. même si vous parvenez à éviter toute incohérence, vous ajouterez une étape supplémentaire avant d’analyser les données, car vous devrez les réunir dans un seul tableau. Vous devrez indiquer explicitement à l’ordinateur comment combiner les onglets et, si ceux-ci sont formatés de manière incohérente, vous pourriez même devoir le faire manuellement.

La prochaine fois que vous saisissez des données et que vous souhaitez créer un autre onglet ou un autre tableau, demandez-vous si vous pourriez éviter d’ajouter cet onglet en ajoutant une autre colonne à votre feuille de calcul d’origine. Nous avons utilisé plusieurs onglets dans notre exemple de fichier de données désordonné, mais vous avez maintenant vu comment vous pouvez réorganiser vos données pour les regrouper entre les onglets.

Votre feuille de données peut devenir très longue au fil de l’expérience. Cela rend la saisie des données plus difficile si vous ne voyez pas vos en-têtes en haut de la feuille de calcul. Mais ne répétez pas votre ligne d’en-tête. Celles-ci peuvent facilement se confondre avec les données, ce qui posera problème par la suite. Au lieu de cela, vous pouvez geler les en-têtes de colonne afin qu’elles restent visibles, même lorsque votre feuille de calcul comporte de nombreuses lignes.

Ne pas renseigner les zéros

Il se peut que, lorsque vous mesurez quelque chose, la valeur soit généralement zéro, par exemple le nombre de fois où un lapin est observé lors de l’enquête. Pourquoi s’embêter à saisir le chiffre zéro dans cette colonne, alors qu’il s’agit pour la plupart de zéros ?

Cependant, il existe une différence entre un zéro et une cellule vide dans une feuille de calcul. Pour l’ordinateur, un zéro est en réalité une donnée. Vous l’avez mesuré ou compté. Une cellule vide signifie qu’elle n’a pas été mesurée et que l’ordinateur l’interprétera comme une valeur inconnue (également appelée valeur nulle ou manquante).

Les feuilles de calcul ou les programmes statistiques interpréteront probablement à tort les cellules vides que vous souhaitez considérer comme des zéros. En ne saisissant pas la valeur de votre observation, vous demandez à votre ordinateur de représenter ces données comme inconnues ou manquantes (nulles). Cela peut poser problème pour les calculs ou les analyses ultérieurs. Par exemple, la moyenne d’un ensemble de nombres comprenant une seule valeur nulle est toujours nulle (car l’ordinateur ne peut pas deviner la valeur des observations manquantes). C’est pourquoi il est très important de consigner les zéros comme des zéros et les données réellement manquantes comme des valeurs nulles.

Utilisation de valeurs nulles problématiques

Exemple : utiliser -999 ou d’autres valeurs numériques (ou zéro) pour représenter des données manquantes.

Solutions :

Il existe plusieurs raisons pour lesquelles les valeurs nulles sont représentées différemment au sein d’un jeu de données. Parfois, des valeurs nulles confuses sont enregistrées automatiquement par le dispositif de mesure. Dans ce cas, il n’y a pas grand-chose que l’on puisse faire, mais cela peut être traité lors du nettoyage des données avec un outil comme OpenRefine avant l’analyse. D’autres fois, des valeurs nulles différentes sont utilisées pour indiquer différentes raisons pour lesquelles les données manquent. Il s’agit d’informations importantes à recueillir, mais cela revient en réalité à utiliser une seule colonne pour enregistrer deux informations. Comme pour l’utilisation du formatage pour transmettre des informations, il serait judicieux ici de créer une nouvelle colonne telle que ‘data_missing’ et d’utiliser cette colonne pour enregistrer les différentes raisons.

Quelle qu’en soit la raison, il est problématique que des données inconnues ou manquantes soient enregistrées sous la forme de -999, 999 ou 0.

De nombreux logiciels statistiques ne reconnaîtront pas que ces valeurs sont destinées à représenter des valeurs manquantes (nulles). La manière dont ces valeurs sont interprétées dépendra du logiciel que vous utilisez pour analyser vos données. Il est essentiel d’utiliser un indicateur de valeur nulle clairement défini et cohérent.

Les cellules vides (dans la plupart des applications) et NA (pour R) sont de bons choix. White et al. (2013) présente dans son article des choix appropriés pour indiquer les valeurs manquantes dans différentes applications logicielles :

A table extracted from a paper showing commonly used null values.
Commonly used null values.

Utilisation de la mise en forme pour transmettre des informations

Exemple : mise en évidence de cellules, de lignes ou de colonnes à exclure d’une analyse, laisser des lignes vides pour indiquer des séparations dans les données.

A table showing several cells highlighted in yellow used to encode sample contamination.
Colours used to ecode information.

Solution : créer un nouveau champ pour coder les données à exclure.

Same table as above with a new variable encoding contambination.
A new variable encoding sample contamination

Utiliser la mise en forme pour embellir la feuille de données

Exemple : fusion de cellules.

Solution : Si vous n’y prenez pas garde, le formatage d’une feuille de calcul pour en améliorer l’aspect esthétique peut compromettre la capacité de votre ordinateur à identifier des associations dans les données. Les cellules fusionnées rendront vos données illisibles pour les logiciels de statistiques. Envisagez de restructurer vos données de manière à ne plus avoir besoin de fusionner des cellules pour les organiser.

Placer des commentaires ou des unités dans des cellules

La plupart des logiciels d’analyse ne peuvent pas lire les commentaires d’Excel ou de LibreOffice, et seraient confus par des commentaires placés dans les cellules de vos données. Comme décrit précédemment pour la mise en forme, créez un autre champ si vous devez ajouter des notes dans les cellules. De même, n’incluez pas d’unités dans les cellules : idéalement, toutes les mesures que vous placez dans une seule colonne doivent être dans la même unité, mais si pour une raison quelconque ce n’est pas le cas, créez un autre champ et précisez l’unité à laquelle appartient la cellule.

Saisir plus d’une information dans une cellule

Exemple : Enregistrer les groupes ABO et Rhesus dans une seule cellule, par exemple A+, B+, A-, …

Solution : Ne regroupez pas plusieurs informations dans une même cellule, car cela limite les possibilités d’analyse de vos données. Si vous avez besoin de ces deux mesures, concevez votre feuille de données pour les enregistrer séparément. Par exemple, prévoyez une colonne pour le groupe ABO et une autre pour le groupe Rhésus.

Utilisation de noms de champs problématiques

Choisissez des noms de champs descriptifs, mais veillez à ne pas inclure d’espaces, de chiffres ou de caractères spéciaux de quelque nature que ce soit. Les espaces peuvent être interprétés à tort par des analyseurs qui utilisent l’espace blanc comme délimiteur, et certains programmes ne supportent pas les noms de champs qui sont des chaînes de texte commençant par des chiffres.

Les tirets bas (_) constituent une bonne alternative aux espaces. Envisagez d’écrire les noms en camel case (comme ceci : ExampleFileName) pour améliorer la lisibilité. Gardez à l’esprit que des abréviations qui ont du sens aujourd’hui ne seront peut-être plus aussi évidentes dans six mois, mais n’exagérez pas non plus avec des noms excessivement longs. Inclure les unités dans les noms de champs évite toute confusion et permet aux autres de les interpréter facilement.

Exemples

Bon nom Bonne alternative Éviter
Max_temp_C MaxTemp Maximum Temp (°C)
Precipitation_mm Precipitation precmm
Mean_year_growth MeanYearGrowth Mean growth/year
sex sex M/F
weight weight w.
cell_type CellType Cell Type
Observation_01 first_observation 1st Obs

Utilisation de caractères spéciaux dans les données

Exemple : Vous traitez votre logiciel de feuille de calcul comme un traitement de texte lorsque vous rédigez des notes, par exemple en copiant des données directement depuis Word ou d’autres applications.

Solution : Il s’agit d’une stratégie courante. Par exemple, lorsqu’on rédige un texte plus long dans une cellule, on inclut souvent des sauts de ligne, des tirets longs, etc., dans sa feuille de calcul. De même, lors de la copie de données depuis des applications telles que Word, le formatage et des caractères non standard complexes (tels que des guillemets alignés à gauche ou à droite) sont inclus. Lors de l’exportation de ces données vers un environnement de programmation/statistique ou vers une base de données relationnelle, des problèmes dangereux peuvent survenir, comme la coupure de lignes en deux ou l’apparition d’erreurs d’encodage.

La bonne pratique générale consiste à éviter d’ajouter des caractères tels que des sauts de ligne, des tabulations et des tabulations verticales. En d’autres termes, traitez une cellule de texte comme un simple formulaire web ne pouvant contenir que du texte et des espaces.

Inclusion de métadonnées dans la table de données

Exemple : Vous ajoutez une légende en haut ou en bas de votre tableau de données expliquant la signification des colonnes, les unités, les exceptions, etc.

Solution : L’enregistrement des informations relatives à vos données (« métadonnées ») est essentiel. Vous connaissez peut-être par cœur votre jeu de données pendant que vous les collectez et les analysez, mais il est peu probable que vous vous souveniez, après quelques mois, un an ou plus, que la variable « sglmemgp » signifie membre unique d’un groupe, par exemple, ou de l’algorithme exact que vous avez utilisé pour transformer une variable ou en créer une dérivée.

Par ailleurs, il existe de nombreuses raisons pour lesquelles d’autres personnes pourraient souhaiter examiner ou utiliser vos données : comprendre vos résultats, les vérifier, examiner votre publication soumise, reproduire vos résultats, concevoir une étude similaire, ou même archiver vos données pour permettre l’accès et la réutilisation par d’autres. Bien que les données numériques soient par définition lisibles par machine, comprendre leur signification est une tâche réservée aux êtres humains. L’importance de documenter vos données durant la phase de collecte et d’analyse de votre recherche ne peut être surestimée, surtout si votre recherche doit faire partie du registre scientifique.

Toutefois, les métadonnées ne doivent pas figurer dans le fichier de données lui-même. Contrairement à un tableau dans un article ou à un fichier supplémentaire, les métadonnées (sous la forme de légendes) ne doivent pas être incluses dans un fichier de données, car ces informations ne sont pas des données, et leur inclusion peut perturber la manière dont les programmes informatiques interprètent votre fichier de données. Au lieu de cela, les métadonnées doivent être stockées dans un fichier distinct dans le même répertoire que votre fichier de données, idéalement au format texte brut, avec un nom qui l’associe clairement à votre fichier de données. Comme les fichiers de métadonnées sont au format texte libre, ils vous permettent également de coder des commentaires, des unités, des informations sur la manière dont les valeurs nulles sont codées, etc., lesquelles sont importantes à documenter mais peuvent perturber le formatage de votre fichier de données.

De plus, les métadonnées au niveau des fichiers ou de la base de données décrivent les relations entre les fichiers qui composent le jeu de données, leur format et s’ils remplacent d’autres fichiers ou ont eux-mêmes été remplacés. Un fichier readme.txt placé dans le dossier est le moyen habituel de recenser tous les fichiers et dossiers d’un projet.

(Le texte sur les métadonnées est adapté du cours en ligne Research Data MANTRA d’EDINA et de la Data Library de l’Université d’Édimbourg. MANTRA est sous licence Creative Commons Attribution 4.0 International License.)

Exportation de données


Question

  • Comment exporter des données à partir de feuilles de calcul de manière à ce qu’elles soient utiles pour des applications ultérieures ?

Objectifs

  • Stocker les données de feuilles de calcul dans des formats de fichiers universels.
  • Exporter des données depuis une feuille de calcul vers un fichier CSV.

Points clés

  • Les données stockées dans des formats de feuilles de calcul courants ne seront souvent pas lues correctement par les logiciels d’analyse de données, ce qui introduit des erreurs dans vos données.

  • L’exportation de données depuis des feuilles de calcul vers des formats tels que le CSV ou le TSV les place dans un format utilisable de manière cohérente par la plupart des programmes.

Stocker les données que vous allez utiliser pour vos analyses dans le format de fichier par défaut d’Excel (*.xls ou *.xlsx - selon la version d’Excel) n’est pas une bonne idée. Pourquoi ?

  • Parce qu’il s’agit d’un format propriétaire et qu’à l’avenir, la technologie permettant d’ouvrir le fichier pourrait disparaître ou devenir très rare, ce qui rendrait l’ouverture du fichier difficile, voire impossible.

  • D’autres logiciels de feuilles de calcul pourraient ne pas être capables d’ouvrir des fichiers enregistrés au format propriétaire d’Excel.

  • Différentes versions d’Excel peuvent traiter les données différemment, ce qui peut entraîner des incohérences. Les dates constituent un exemple bien documenté d’incohérences dans la conservation des données.

  • Enfin, un nombre croissant de revues et d’organismes de financement exigent que vous déposiez vos données dans un dépôt de données, et la plupart d’entre eux n’acceptent pas le format Excel. Elle doit être dans l’un des formats abordés ci-dessous.

  • Les points mentionnés ci-dessus s’appliquent également à d’autres formats, tels que les formats de données ouvertes utilisés par LibreOffice / Open Office. Ces formats ne sont pas statiques et ne sont pas analysés de la même manière par différents logiciels.

Le stockage des données dans un format universel, ouvert et statique aidera à remédier à ce problème. Essayez le format tabulé (valeurs séparées par des tabulations ou TSV) ou le format séparé par des virgules (valeurs séparées par des virgules ou CSV). Les fichiers CSV sont des fichiers texte brut où les colonnes sont séparées par des virgules, d’où le nom « valeurs séparées par des virgules » ou CSV. L’avantage d’un fichier CSV par rapport à un fichier Excel/SPSS/etc. est que nous pouvons ouvrir et lire un fichier CSV avec pratiquement n’importe quel logiciel, y compris des éditeurs de texte brut comme TextEdit ou le Bloc-notes. Les données d’un fichier CSV peuvent également être facilement importées dans d’autres formats et environnements, tels que SQLite et R. Nous ne sommes pas liés à une version spécifique d’un programme coûteux lorsque nous travaillons avec des fichiers CSV ; c’est donc un bon format pour garantir une portabilité et une pérennité maximales. La plupart des logiciels de feuilles de calcul peuvent enregistrer facilement dans des formats texte délimités comme le CSV, bien qu’ils puissent vous afficher un avertissement lors de l’exportation du fichier.

Pour enregistrer un fichier ouvert dans Excel au format CSV :

  1. Dans le menu supérieur, sélectionnez « Fichier » et « Enregistrer sous ».
  2. Dans le champ « Format », sélectionnez « Valeurs séparées par des virgules » (*.csv) dans la liste.
  3. Vérifiez à nouveau le nom du fichier et l’emplacement où vous souhaitez le enregistrer, puis cliquez sur « Enregistrer ».

Une note importante pour la rétrocompatibilité : vous pouvez ouvrir des fichiers CSV dans Excel !

Excel menu to export data in a csv format on MacOS
Saving an Excel file to CSV.

Note sur R et xls : Il existe des packages R capables de lire les fichiers xls (ainsi que les feuilles de calcul Google). Il est même possible d’accéder à différentes feuilles de calcul dans les documents xls.

Mais

  • certains d’entre eux ne fonctionnent que sous Windows.
  • cela revient à remplacer un export (simple mais manuel) vers csv par une complexité/des dépendances supplémentaires dans le code R d’analyse de données.
  • Les bonnes pratiques de mise en forme des données s’appliquent toujours.
  • Y a-t-il vraiment une bonne raison pour laquelle csv (ou un élément similaire) ne convient pas ?

Précautions concernant les virgules

Dans certains jeux de données, les valeurs elles-mêmes peuvent contenir des virgules (,). Dans ce cas, le logiciel que vous utilisez (y compris Excel) affichera très probablement les données de manière incorrecte dans des colonnes. Cela est dû au fait que les virgules faisant partie des valeurs de données seront interprétées comme des délimiteurs.

Par exemple, nos données pourraient ressembler à ceci :

species_id,genus,species,taxa
AB,Amphispiza,bilineata,Bird
AH,Ammospermophilus,harrisi,Rodent, not censused
AS,Ammodramus,savannarum,Bird
BA,Baiomys,taylori,Rodent

Dans le enregistrement AH,Ammospermophilus,harrisi,Rodent, not censused, la valeur de taxa contient une virgule (Rodent, not censused). Si nous tentons de lire ce qui précède dans Excel (ou un autre programme de feuille de calcul), nous obtiendrons quelque chose comme ceci :

A table illustrating ill-imported data that contained a comma in a cell. That cell has been split in two cells.
The risks of having commas inside comma-separated data.

La valeur de taxa a été divisée en deux colonnes (au lieu d’être placée dans une seule colonne D). Cela peut entraîner un certain nombre d’erreurs supplémentaires. Par exemple, la colonne supplémentaire sera interprétée comme une colonne contenant de nombreuses valeurs manquantes (et sans en-tête approprié). De plus, la valeur de la colonne D pour l’enregistrement de la ligne 3 (c’est-à-dire celui où la valeur de « taxa » contenait la virgule) est désormais incorrecte.

Si vous souhaitez stocker vos données au format csv et que vous prévoyez que vos valeurs puissent contenir des virgules, vous pouvez éviter le problème décrit ci-dessus en entourant les valeurs de guillemets (““). En appliquant cette règle, nos données pourraient ressembler à ceci :

species_id,genus,species,taxa
"AB","Amphispiza","bilineata","Bird"
"AH","Ammospermophilus","harrisi","Rodent, not censused"
"AS","Ammodramus","savannarum","Bird"
"BA","Baiomys","taylori","Rodent"

Désormais, l’ouverture de ce fichier en tant que csv dans Excel ne provoquera pas d’ajout de colonne, car Excel n’utilisera que les virgules situées en dehors des guillemets comme caractères de délimitation.

Alternativement, si vous travaillez avec des données contenant des virgules, vous devrez probablement utiliser un autre délimiteur lorsque vous travaillez dans une feuille de calcul1. Dans ce cas, envisagez d’utiliser des tabulations comme délimiteur et de travailler avec des fichiers TSV. Les fichiers TSV peuvent être exportés depuis des logiciels de feuilles de calcul de la même manière que les fichiers CSV.

Si vous travaillez avec un jeu de données existant dans lequel les valeurs ne sont pas entourées de “” mais qui utilisent des virgules à la fois comme séparateurs et comme éléments des valeurs, vous êtes potentiellement confronté à un problème majeur de nettoyage des données. Si le jeu de données que vous manipulez contient des centaines ou des milliers de lignes, les nettoyer manuellement (en supprimant les virgules des valeurs ou en plaçant les valeurs entre guillemets - ““) ne nécessitera pas seulement des heures et des heures, mais pourrait également entraîner l’introduction accidentelle de nombreuses erreurs.

Le nettoyage des jeux de données est l’un des problèmes majeurs dans de nombreuses disciplines scientifiques. L’approche dépend presque toujours du contexte particulier. Toutefois, il est recommandé de nettoyer les données de manière automatisée, par exemple en écrivant et en exécutant un script. Les leçons sur Python et R vous fourniront les bases nécessaires pour développer des compétences en matière de création de scripts adaptés.

Résumé


The tidy data analysis circle, iterating over data transformation, visualisation and modelling.
A typical data analysis workflow.

Un flux de travail typique d’analyse de données est illustré sur la figure ci-dessus, où les données sont à plusieurs reprises transformées, visualisées et modélisées. Cette itération est répétée plusieurs fois jusqu’à ce que les données soient comprises. Dans de nombreux cas concrets, cependant, la majeure partie du temps est consacrée au nettoyage et à la préparation des données, plutôt qu’à leur analyse et à leur compréhension effectives.

Un flux de travail d’analyse de données agile, comprenant plusieurs itérations rapides du cycle transformation/visualisation/modélisation, n’est réalisable que si les données sont formatées de manière prévisible et qu’il est possible de raisonner à partir d’elles sans avoir à les consulter et/ou à les corriger.

Key Points
  • Une bonne organisation des données est le fondement de tout projet de recherche.
Broman, Karl W., and Kara H. Woo. 2018. “Data Organization in Spreadsheets.” The American Statistician 72 (1): 2–10. https://doi.org/10.1080/00031305.2017.1375989.
Perez-Riverol, Yasset, Laurent Gatto, Rui Wang, et al. 2016. “Ten Simple Rules for Taking Advantage of Git and GitHub.” PLOS Computational Biology 12 (7): 1–11. https://doi.org/10.1371/journal.pcbi.1004947.
White, Ethan P., Elita Baldridge, Zachary T. Brym, Kenneth J. Locey, Daniel J. McGlinn, and Sarah R. Supp. 2013. “Nine Simple Ways to Make It Easier to (Re)use Your Data.” PeerJ PrePrints 1 (July): e7v2. https://doi.org/10.7287/peerj.preprints.7v2.
Wickham, Hadley. 2014. “Tidy Data.” Journal of Statistical Software, Articles 59 (10): 1–23. https://doi.org/10.18637/jss.v059.i10.

  1. Cela est particulièrement pertinent dans les pays européens où la virgule est utilisée comme séparateur décimal. Dans ce cas, le séparateur de valeurs par défaut dans un fichier CSV sera le point-virgule (;), ou les valeurs seront systématiquement mises entre guillemets.↩︎

Content from R et RStudio


Last updated on 2026-11-07 | Edit this page

Overview

Questions

  • Qu’est-ce que R et RStudio ?

Objectives

  • Décrivez le rôle des panneaux Script, Console, Environment et Plots de RStudio.
  • Organiser les fichiers et les répertoires pour un ensemble d’analyses sous la forme d’un projet R, et comprendre l’utilité du répertoire de travail.
  • Utilisez l’interface d’aide intégrée à RStudio pour rechercher plus d’informations sur les fonctions R.
  • Démontrer comment fournir suffisamment d’informations pour dépanner auprès de la communauté d’utilisateurs de R.

Cet épisode est basé sur la leçon Data Analysis and Visualisation in R for Ecologists de Data Carpentries.

Qu’est-ce que R ? Qu’est-ce que RStudio ?


Le terme R est utilisé pour désigner le langage de programmation, l’environnement de calcul statistique et le logiciel qui interprète les scripts écrits avec celui-ci.

RStudio est actuellement un moyen très populaire non seulement d’écrire vos scripts R, mais aussi d’interagir avec le logiciel R1. Pour fonctionner correctement, RStudio nécessite R et, par conséquent, les deux doivent être installés sur votre ordinateur.

La fiche pratique de l’IDE RStudio fournit bien plus d’informations que celles qui seront abordées ici, mais peut s’avérer utile pour apprendre les raccourcis clavier et découvrir de nouvelles fonctionnalités.

Pourquoi apprendre R ?


R ne nécessite pas beaucoup de clics, et c’est une bonne chose.

La courbe d’apprentissage peut être plus abrupte qu’avec d’autres logiciels, mais avec R, les résultats de votre analyse ne dépendent pas du fait de mémoriser une succession de clics, mais plutôt d’une série de commandes écrites, et c’est une bonne chose ! Ainsi, si vous souhaitez refaire votre analyse parce que vous avez collecté davantage de données, vous n’avez pas à vous rappeler quel bouton vous avez cliqué et dans quel ordre pour obtenir vos résultats ; il vous suffit de relancer votre script.

Le travail avec des scripts rend les étapes utilisées dans votre analyse claires, et le code que vous écrivez peut être examiné par une autre personne capable de vous fournir des retours et de repérer des erreurs.

Le travail avec des scripts vous oblige à avoir une compréhension plus approfondie de ce que vous faites, et facilite votre apprentissage et votre compréhension des méthodes que vous utilisez.

Le code R est idéal pour la reproductibilité

La reproductibilité signifie qu’une autre personne (y compris votre futur soi) peut obtenir les mêmes résultats à partir du même jeu de données en utilisant le même code d’analyse.

R s’intègre à d’autres outils pour générer des manuscrits ou des rapports à partir de votre code. Si vous collectez davantage de données ou corrigez une erreur dans votre jeu de données, les figures et les tests statistiques de votre manuscrit ou de votre rapport sont mis à jour automatiquement.

Un nombre croissant de revues et d’organismes de financement exigent que les analyses soient reproductibles ; maîtriser R vous donnera donc un avantage face à ces exigences.

R est interdisciplinaire et extensible

Avec plus de 10 000 packages2 pouvant être installés pour en étendre les capacités, R offre un cadre qui vous permet de combiner des approches statistiques issues de nombreuses disciplines scientifiques afin d’adapter au mieux le cadre analytique nécessaire à l’analyse de vos données. Par exemple, R dispose de packages pour l’analyse d’images, la SIG, les séries temporelles, la génétique des populations, et bien plus encore.

Two graphs showing the exponential increase of the number of CRAN packages from 2000 to 2018. The figure on the right shows linear trend for the log of number of packages.
Exponential increase of the number of packages available on CRAN, the Comprehensive R Archive Network. From the R Journal, Volume 10/2, December 2018.

R fonctionne avec des données de toutes formes et de toutes tailles

Les compétences que vous acquérez avec R s’adaptent facilement à la taille de votre jeu de données. Que votre jeu de données compte des centaines ou des millions de lignes, cela ne fera pas grande différence pour vous.

R est conçu pour l’analyse de données. Il dispose de structures de données et de types de données spéciaux qui facilitent la manipulation des données manquantes et des facteurs statistiques.

R peut se connecter à des feuilles de calcul, à des bases de données et à de nombreux autres formats de données, sur votre ordinateur ou sur le Web.

R produit des graphiques de haute qualité

Les fonctionnalités de tracé de R sont vastes et vous permettent d’ajuster tout aspect de votre graphique afin de transmettre le message de vos données de la manière la plus efficace possible.

R dispose d’une communauté vaste et accueillante

Des milliers de personnes utilisent R quotidiennement. Beaucoup d’entre elles sont prêtes à vous aider via des listes de diffusion et des sites web tels que Stack Overflow, ou sur la communauté RStudio. Ces vastes communautés d’utilisateurs s’étendent à des domaines spécialisés tels que la bioinformatique. L’un de ces sous-ensembles de la communauté R est Bioconductor, un projet scientifique d’analyse et de compréhension « des données issues d’essais biologiques actuels et émergents ». Cet atelier a été développé par des membres de la communauté Bioconductor ; pour plus d’informations sur Bioconductor, veuillez consulter l’atelier complémentaire “The Bioconductor Project”.

R est non seulement gratuit, mais il est également open source et multiplateforme.

Tout le monde peut examiner le code source pour voir comment R fonctionne. Grâce à cette transparence, les risques d’erreurs sont réduits et, si vous (ou quelqu’un d’autre) en trouvez, il est possible de signaler et de corriger des bugs.

Se familiariser avec RStudio


Commençons par découvrir RStudio, un environnement de développement intégré (IDE) pour travailler avec R.

Le produit open source RStudio IDE est gratuit sous la Licence publique générale Affero (AGPL) v3. RStudio IDE est également disponible avec une licence commerciale et un support par e-mail prioritaire de la part de Posit, Inc.

Nous utiliserons l’IDE RStudio pour écrire du code, naviguer dans les fichiers de notre ordinateur, examiner les variables que nous allons créer et visualiser les graphiques que nous générerons. RStudio peut également être utilisé pour d’autres tâches (par exemple, la gestion des versions, le développement de packages, la création d’applications Shiny) que nous ne traiterons pas durant l’atelier.

Screenshot of the RStudio interface showing the typical four panel setup.
RStudio interface screenshot. Clockwise from top left: Source, Environment/History, Files/Plots/Packages/Help/Viewer, Console.

La fenêtre de RStudio est divisée en quatre « panneaux » :

  • la Source pour vos scripts et documents (en haut à gauche, dans la disposition par défaut)
  • votre panneau Environment/History (environnement/historique, en haut à droite),
  • votre panneau Files/Plots/Packages/Help/Viewer (fichiers/graphiques/paquets/aide/visualiseur, en bas à droite), et
  • la Console de R (en bas à gauche).

L’emplacement de ces panneaux et leur contenu peuvent être personnalisés (voir le menu Tools -> Global Options -> Pane Layout).

L’un des avantages de RStudio est que toutes les informations nécessaires pour écrire du code sont disponibles dans une seule fenêtre. De plus, grâce à de nombreux raccourcis, à l’autocomplétion et à la coloration syntaxique des principaux types de fichiers utilisés lors du développement en R, RStudio facilite la saisie et réduit les risques d’erreur.

Configuration


Il est recommandé de regrouper un ensemble de données, d’analyses et de textes connexes au sein d’un seul dossier, appelé répertoire de travail. Tous les scripts contenus dans ce dossier peuvent alors utiliser des chemins relatifs vers les fichiers, indiquant l’emplacement d’un fichier au sein du projet (contrairement aux chemins absolus, qui indiquent l’emplacement d’un fichier sur un ordinateur spécifique). Travailler ainsi permet de déplacer beaucoup plus facilement son projet sur son ordinateur et de le partager avec d’autres sans se soucier de savoir si les scripts sous-jacents fonctionneront toujours.

RStudio propose un ensemble d’outils utiles pour ce faire via son interface « Projets », qui non seulement crée un répertoire de travail pour vous, mais mémorise également son emplacement (vous permettant de vous y rendre rapidement) et, optionnellement, conserve les paramètres personnalisés et les fichiers ouverts pour faciliter la reprise du travail après une pause. Suivez ci-dessous les étapes pour créer un « Projet R » pour ce tutoriel.

  1. Lancez RStudio.
  2. Dans le menu File, cliquez sur New project. Choisissez New directory, puis New project.
  3. Saisissez un nom pour ce nouveau dossier (ou « répertoire ») et choisissez un emplacement pratique. Ce sera votre répertoire de travail pour cette session (ou pour l’ensemble du cours) (par ex., bioc-intro).
  4. Cliquez sur Create project.
  5. (Facultatif) Configurez RStudio pour ne jamais enregistrer l’espace de travail en choisissant l’option « Never » dans les préférences.

Les préférences par défaut de RStudio fonctionnent généralement bien, mais enregistrer l’espace de travail dans un fichier .RData peut s’avérer contraignant, surtout avec des jeux de données volumineux. Pour désactiver cette fonctionnalité, ouvrez Tools –> « Global Options », puis choisissez « Never » pour l’option « Save workspace to .RData on exit ».

Screenshot of the RStudio General Options panel.
Set ‘Save workspace to .RData on exit’ to ‘Never’

Afin d’éviter les problèmes de codage de caractères entre Windows et les autres systèmes d’exploitation, nous allons définir UTF-8 par défaut :

Screenshot of the RStudio Code Options panel.
Set the default text encoding to UTF-8 to save us headache in the coming future. (Figure from the link above).

Organisation de votre répertoire de travail

L’utilisation d’une structure de dossiers cohérente à travers vos projets vous aidera à rester organisé et vous permettra également de retrouver et de classer vos éléments plus facilement à l’avenir. Cela peut s’avérer particulièrement utile lorsque vous avez plusieurs projets. En général, vous pouvez créer des répertoires (dossiers) pour les scripts, les données et les documents.

  • data/ Utilisez ce dossier pour stocker vos données brutes et les jeux de données intermédiaires que vous pourriez créer pour un analyse particulière. Par souci de transparence et de provenance, vous devriez toujours garder une copie de vos données brutes accessible et effectuer autant que possible le nettoyage et le prétraitement de vos données de manière programmatique (c’est-à-dire via des scripts, plutôt que manuellement). Séparer les données brutes des données traitées est également une bonne idée. Par exemple, vous pourriez conserver les fichiers data/raw/tree_survey.plot1.txt et ...plot2.txt séparément d’un fichier data/processed/tree.survey.csv généré par le script scripts/01.preprocess.tree_survey.R.
  • documents/ Ce serait un endroit pour conserver des plans, des brouillons et d’autres textes.
  • scripts/ (ou src) Ce serait l’emplacement où vous conserveriez vos scripts R pour différentes analyses ou des tracés, et éventuellement un dossier distinct pour vos fonctions (on y reviendra plus tard).

Vous pourriez avoir besoin de répertoires ou de sous-répertoires supplémentaires selon les besoins de votre projet, mais ceux-ci doivent constituer l’ossature de votre répertoire de travail.

Flow diagram showing the structure of the working directory and various directory of a typical RStuio project.
Example of a working directory structure.

Pour ce cours, nous aurons besoin d’un dossier data/ pour stocker nos données brutes, et nous utiliserons data_output/ lorsque nous apprendrons à exporter des données sous forme de fichiers CSV, ainsi que le dossier fig_output/ pour les figures que nous enregistrerons.

Discussion

Défi : créez la structure de votre répertoire de projet

Sous l’onglet Files à droite de l’écran, cliquez sur New Folder et créez un dossier nommé data au sein de votre répertoire de travail nouvellement créé (par ex., ~/bioc-intro/data). (Alternativement, saisissez dir.create("data") dans votre console R.) Répétez ces opérations pour créer des dossiers data_output/ et fig_output.

Nous allons conserver le script à la racine de notre répertoire de travail car nous n’utiliserons qu’un seul fichier, ce qui facilitera les choses.

Votre répertoire de travail devrait désormais ressembler à ceci :

Screenshot of RStudio's Files panel.
How it should look like at the beginning of this lesson

La gestion de projet s’applique également aux projets de bioinformatique, bien entendu3. William Noble ( Noble (2009) ) propose la structure de répertoires suivante :

Les noms de répertoires sont dans une police de caractères grande, et les noms de fichiers dans une police plus petite. Seul un sous-ensemble des fichiers est présenté ici. Notez que les dates sont formatées <year>-<month>-<day> afin qu’elles puissent être triées par ordre chronologique. Le code source src/ms-analysis.c est compilé pour créer bin/ms-analysis et est documenté dans doc/ms-analysis.html. Les fichiers README dans les répertoires de données précisent qui a téléchargé les fichiers de données depuis quelle URL et à quelle date. Le script pilote results/2009-01-15/runall génère automatiquement les trois sous-répertoires split1, split2 et split3, correspondant à trois partitions de validation croisée. Le script bin/parse-sqt.py est appelé par les deux scripts pilotes runall.

Figure form Nobel et al. (2009) showing a complex bioinformatics project structure.
Directory structure for a sample bioinformatics project.

L’aspect le plus important d’un répertoire de projet bien défini et bien documenté est de permettre à quelqu’un qui ne connaît pas le projet4 de

  1. comprendre de quoi traite le projet, quelles données sont disponibles, quelles analyses ont été réalisées et quels résultats ont été produits et, surtout, de

  2. répéter l’analyse — avec de nouvelles données, ou en modifiant certains paramètres d’analyse.

Le répertoire de travail

Le répertoire de travail est un concept important à comprendre. C’est l’endroit d’où R recherchera et enregistrera les fichiers. Lorsque vous écrivez du code pour votre projet, celui-ci doit faire référence aux fichiers par rapport à la racine de votre répertoire de travail et ne doit référencer que des fichiers situés au sein de cette structure.

L’utilisation de projets RStudio facilite cette tâche et garantit que votre répertoire de travail est correctement configuré. Si vous devez le vérifier, vous pouvez utiliser getwd(). Si, pour une raison quelconque, votre répertoire de travail ne correspond pas à celui attendu, vous pouvez le modifier dans l’interface de RStudio en vous rendant dans le navigateur de fichiers où se trouve votre répertoire de travail, en cliquant sur l’icône d’engrenage bleue More, puis en sélectionnant Set As Working Directory. Alternativement, vous pouvez utiliser setwd("/path/to/working/directory") pour réinitialiser votre répertoire de travail. Toutefois, vos scripts ne doivent pas contenir cette ligne, car elle échouera sur l’ordinateur de quelqu’un d’autre.

Exemple

Le schéma ci-dessous représente le répertoire de travail bioc-intro avec les sous-répertoires data et fig_output, ainsi que 2 fichiers dans ce dernier :

bioc-intro/data/
          /fig_output/fig1.pdf
          /fig_output/fig2.png

Si nous étions dans le répertoire de travail, nous pourrions référencer le fichier fig1.pdf à l’aide du chemin relatif bioc-intro/fig_output/fig1.pdf ou du chemin absolu /home/user/bioc-intro/fig_output/fig1.pdf.

Si nous étions dans le répertoire data, nous utiliserions le chemin relatif ../fig_output/fig1.pdf ou le même chemin absolu /home/user/bioc-intro/fig_output/fig1.pdf.

Interagir avec R


Le principe de la programmation consiste à rédiger des instructions que l’ordinateur doit suivre, puis à lui demander de les exécuter. Nous rédigeons, ou codons, des instructions en R, car c’est un langage commun que l’ordinateur et nous pouvons comprendre. Nous appelons ces instructions des commandes et nous demandons à l’ordinateur de les suivre en les exécutant (ou en les lançant).

Il existe deux principales façons d’interagir avec R : en utilisant la console ou en utilisant des scripts (fichiers texte bruts contenant votre code). La fenêtre de la console (dans RStudio, le panneau inférieur à gauche) est l’endroit où l’on peut saisir des commandes écrites dans le langage R et où l’ordinateur les exécute immédiatement. C’est également là que les résultats des commandes exécutées s’affichent. Vous pouvez saisir des commandes directement dans la console et appuyer sur Enter pour les exécuter, mais elles seront effacées lorsque vous fermerez la session.

Comme nous voulons que notre code et notre flux de travail soient reproductibles, il est préférable de saisir les commandes souhaitées dans l’éditeur de scripts et de sauvegarder le script. De cette façon, un registre complet de nos actions subsiste, et n’importe qui (y compris nous-mêmes à l’avenir !) peut facilement reproduire les résultats sur son propre ordinateur. Notez toutefois que le simple fait de saisir les commandes dans le script ne les lance pas automatiquement : elles doivent tout de même être envoyées à la console pour être exécutées.

RStudio vous permet d’exécuter des commandes directement depuis l’éditeur de scripts en utilisant le raccourci Ctrl + Enter (sur Mac, Cmd + Return fonctionne également). La commande de la ligne actuelle du script (indiquée par le curseur) ou l’ensemble des commandes du texte actuellement sélectionné sera envoyé à la console et exécuté lorsque vous appuyerez sur Ctrl + Enter. Vous trouverez d’autres raccourcis clavier dans ce cheatsheet RStudio concernant l’IDE RStudio.

À un moment donné de votre analyse, vous souhaiterez peut-être vérifier le contenu d’une variable ou la structure d’un objet, sans nécessairement en garder trace dans votre script. Vous pouvez saisir ces commandes et les exécuter directement dans la console. RStudio propose les raccourcis Ctrl + 1 et Ctrl + 2 qui vous permettent de basculer entre les fenêtres du script et de la console.

Lorsque R est prêt à accepter des commandes, la console affiche une invite >. Lorsqu’il reçoit une commande, saisie directement, copiée-collée ou envoyée depuis l’éditeur de scripts avec Ctrl + Enter, R tente de l’exécuter. Une fois l’exécution terminée, il affiche les résultats, puis une nouvelle invite > pour attendre de nouvelles commandes.

Si R attend encore une saisie parce que la commande est incomplète, la console affiche une invite +. Cela signifie que vous n’avez pas fini de saisir une commande complète. Vous n’avez pas fermé une parenthèse ou des guillemets : le nombre de parenthèses ouvrantes et fermantes, ou de guillemets ouvrants et fermants, ne correspond pas. Si cela se produit alors que vous pensiez avoir terminé votre commande, cliquez dans la console et appuyez sur Esc ; cela annulera la commande incomplète et vous ramènera à l’invite >.

Comment en apprendre davantage pendant et après le cours ?


Le contenu abordé durant ce cours vous donnera un premier aperçu de la manière dont vous pouvez utiliser R pour analyser des données dans le cadre de vos propres recherches. Toutefois, vous devrez en apprendre davantage pour effectuer des opérations avancées, telles que le nettoyage de votre jeu de données, l’utilisation de méthodes statistiques ou la création de graphiques esthétiques5. Le meilleur moyen de devenir maître et efficace avec R, comme pour tout autre outil, est de l’utiliser pour répondre à vos questions de recherche réelles. En tant que débutant, l’idée de devoir écrire un script de zéro peut sembler intimidante et, étant donné que de nombreuses personnes mettent leur code à disposition en ligne, la modification de code existant pour l’adapter à vos besoins pourrait vous faciliter les débuts.

Fake book cover showing a kitten with title 'Changing Stuff and Seeing What Happens.'

Chercher de l’aide


Utilisez l’interface d’aide intégrée à RStudio pour rechercher plus d’informations sur les fonctions R

Screenshot of RStudio's Help panel.
RStudio help interface.

L’un des moyens les plus rapides d’obtenir de l’aide consiste à utiliser l’interface d’aide de RStudio. Ce panneau se trouve par défaut dans le panneau inférieur droit de RStudio. Comme on peut le voir sur la capture d’écran, en saisissant le mot « Mean », RStudio tente également de proposer un certain nombre de suggestions qui pourraient vous intéresser. La description s’affiche ensuite dans la fenêtre d’affichage.

Je connais le nom de la fonction que je souhaite utiliser, mais je ne sais pas comment l’utiliser

Si vous avez besoin d’aide pour une fonction spécifique, disons barplot(), vous pouvez saisir :

R

?barplot

Si vous avez simplement besoin de vous rappeler le nom des arguments, vous pouvez utiliser :

R

args(lm)

Je veux utiliser une fonction qui fait X, il doit y avoir une fonction pour ça, mais je ne sais pas laquelle…

Si vous recherchez une fonction pour effectuer une tâche particulière, vous pouvez utiliser la fonction help.search(), qui s’appelle via le double point d’interrogation ??. Toutefois, celle-ci ne recherche dans les packages installés que des pages d’aide correspondant à votre requête de recherche.

R

??kruskal

Si vous ne trouvez pas ce que vous cherchez, vous pouvez utiliser le site rdocumentation.org qui recherche dans les fichiers d’aide de tous les packages disponibles.

Enfin, une recherche Google ou sur Internet générique « R <task> » vous dirigera souvent soit vers la documentation du package approprié, soit vers un forum utile où quelqu’un d’autre a déjà posé votre question.

Je bloque… Je reçois un message d’erreur que je ne comprends pas

Commencez par rechercher le message d’erreur sur Google. Cependant, cela ne fonctionne pas toujours très bien car les développeurs de packages s’appuient souvent sur la gestion des erreurs fournie par R. Vous vous retrouvez avec des messages d’erreur génériques qui pourraient ne pas être très utiles pour diagnostiquer un problème (par exemple : « subscript out of bounds »). Si le message est très générique, vous pouvez également inclure le nom de la fonction ou du package que vous utilisez dans votre requête.

Toutefois, vous devriez consulter Stack Overflow. Effectuez une recherche en utilisant la balise [r]. La plupart des questions ont déjà reçu une réponse, mais le défi consiste à utiliser les bons mots dans votre recherche pour trouver les réponses :

https://stackoverflow.com/questions/tagged/r

L’Introduction à R peut également s’avérer dense pour les personnes ayant peu d’expérience en programmation, mais c’est un bon endroit pour comprendre les fondements du langage R.

La FAQ de R est dense et technique, mais elle regorge d’informations utiles.

Demander de l’aide

La clé pour obtenir de l’aide est que l’interlocuteur saisisse rapidement votre problème. Vous devez faciliter au maximum la localisation du défaut.

Essayez d’utiliser les mots appropriés pour décrire votre problème. Par exemple, un package n’est pas la même chose qu’une bibliothèque. La plupart des gens comprendront ce que vous vouliez dire, mais d’autres ont des opinions très tranchées sur la différence de sens. Le point essentiel est que cela peut prêter à confusion pour les personnes qui tentent de vous aider. Soyez aussi précis que possible lorsque vous décrivez votre problème.

Si possible, essayez de réduire ce qui ne fonctionne pas à un exemple reproductible simple. Si vous pouvez reproduire le problème à l’aide d’un tableau de données très petit au lieu de celui de 50 000 lignes et 10 000 colonnes, fournissez ce petit tableau accompagné de la description de votre problème. Lorsque cela est approprié, essayez de généraliser votre démarche afin que même des personnes n’appartenant pas à votre domaine puissent comprendre la question. Par exemple, au lieu d’utiliser un sous-ensemble de votre jeu de données réel, créez un exemple générique petit (3 colonnes, 5 lignes). Pour plus d’informations sur la manière d’écrire un exemple reproductible, consultez cet article de Hadley Wickham.

Pour partager un objet avec quelqu’un d’autre, s’il est relativement petit, vous pouvez utiliser la fonction dput(). Elle générera du code R permettant de recréer exactement le même objet que celui en mémoire :

R

## iris is an example data frame that comes with R and head() is a
## function that returns the first part of the data frame
dput(head(iris))

OUTPUT

structure(list(Sepal.Length = c(5.1, 4.9, 4.7, 4.6, 5, 5.4),
    Sepal.Width = c(3.5, 3, 3.2, 3.1, 3.6, 3.9), Petal.Length = c(1.4,
    1.4, 1.3, 1.5, 1.4, 1.7), Petal.Width = c(0.2, 0.2, 0.2,
    0.2, 0.2, 0.4), Species = structure(c(1L, 1L, 1L, 1L, 1L,
    1L), levels = c("setosa", "versicolor", "virginica"), class = "factor")), row.names = c(NA,
6L), class = "data.frame")

Si l’objet est plus volumineux, fournissez soit le fichier brut (c’est-à-dire votre fichier CSV) avec votre script jusqu’au point où survient l’erreur (et après avoir supprimé tout ce qui n’est pas pertinent pour votre problème). Alternativement, notamment si votre question n’est pas liée à un tableau de données, vous pouvez enregistrer n’importe quel objet R dans un fichier[^export] :

R

saveRDS(iris, file="/tmp/iris.rds")

Le contenu de ce fichier n’est toutefois pas lisible par l’humain et ne peut pas être publié directement sur Stack Overflow. On peut plutôt l’envoyer par e-mail à quelqu’un qui pourra le lire à l’aide de la commande readRDS() (on suppose ici que le fichier téléchargé se trouve dans un dossier Downloads dans le répertoire personnel de l’utilisateur) :

R

some_data <- readRDS(file="~/Downloads/iris.rds")

Enfin, mais certainement pas des moindres, incluez toujours la sortie de sessionInfo(), car elle fournit des informations cruciales sur votre plateforme, les versions de R et des packages que vous utilisez, ainsi que d’autres informations qui peuvent s’avérer très utiles pour comprendre votre problème.

R

sessionInfo()

OUTPUT

R version 4.6.1 (2026-06-24)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 24.04.5 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0

locale:
 [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8
 [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8
 [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C
[10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C

time zone: UTC
tzcode source: system (glibc)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base

loaded via a namespace (and not attached):
[1] compiler_4.6.1 cli_3.6.6      tools_4.6.1    otel_0.2.0     knitr_1.52
[6] xfun_0.62      rlang_1.3.0    evaluate_1.0.5

Où demander de l’aide ?

  • La personne assise à vos côtés pendant le cours. N’hésitez pas à discuter avec votre voisin pendant l’atelier, à comparer vos réponses et à demander de l’aide.
  • Vos collègues sympathiques : si vous connaissez quelqu’un ayant plus d’expérience que vous, il pourrait être en mesure et disposé à vous aider.
  • Stack Overflow : si votre question n’a jamais été traitée auparavant et qu’elle est bien formulée, vous avez de bonnes chances d’obtenir une réponse en moins de 5 min. N’oubliez pas de suivre leurs recommandations sur la manière de poser une bonne question.
  • La liste de diffusion R-help : elle est consultée par de nombreuses personnes (dont la plupart de l’équipe principale de R), et beaucoup y publient, mais le ton peut être assez sec et elle n’est pas toujours très accueillante pour les nouveaux utilisateurs. Si votre question est pertinente, vous obtiendrez probablement une réponse très rapidement, mais ne vous attendez pas à ce qu’elle soit accompagnée d’émoticônes. De plus, ici plus qu’ailleurs, veillez à utiliser un vocabulaire correct (sinon, vous pourriez recevoir une réponse soulignant l’usage incorrect de vos mots plutôt que de répondre à votre question). Vous aurez également plus de succès si votre question porte sur une fonction de base plutôt que sur un package spécifique.
  • Si votre question concerne un package spécifique, vérifiez s’il existe une liste de diffusion à son sujet. Généralement, elle figure dans le fichier DESCRIPTION du package, accessible via packageDescription("name-of-package"). Vous pouvez également essayer d’envoyer un e-mail directement à l’auteur du package ou d’ouvrir un ticket dans le dépôt de code (par exemple, sur GitHub).
  • Il existe également des listes de diffusion spécialisées par thème (SIG, phylogénétique, etc…), la liste complète est disponible sur la page des listes de diffusion de R-project.

Plus de ressources

Paquets R


Chargement de packages

Comme nous l’avons vu plus haut, les packages R jouent un rôle fondamental dans R. Pour utiliser les fonctionnalités d’un package, à condition qu’il soit installé, nous devons d’abord le charger afin de pouvoir l’utiliser. Cela se fait avec la fonction library(). Ci-dessous, nous chargeons ggplot2.

R

library("ggplot2")

Installation de packages

Le dépôt de packages par défaut est le Comprehensive R Archive Network (CRAN), et tout package disponible sur CRAN peut être installé avec la fonction install.packages(). Ci-dessous, par exemple, nous installons le package dplyr que nous découvrirons plus tard.

R

install.packages("dplyr")

Cette commande installera le package dplyr ainsi que toutes ses dépendances, c’est-à-dire tous les packages dont il a besoin pour fonctionner.

Un autre dépôt majeur de packages R est géré par Bioconductor. Les packages Bioconductor sont gérés et installés à l’aide d’un package dédié, à savoir BiocManager, qui peut être installé depuis CRAN avec

R

install.packages("BiocManager")

Des packages individuels tels que SummarizedExperiment (nous l’utiliserons plus tard), DESeq2 (pour l’analyse RNA-Seq) et tout autre provenant de Bioconductor ou de CRAN peuvent ensuite être installés avec BiocManager::install.

R

BiocManager::install("SummarizedExperiment")
BiocManager::install("DESeq2")

Par défaut, BiocManager::install() vérifiera également tous vos packages installés pour voir s’il existe des versions plus récentes. Si c’est le cas, il vous les présentera et vous demandera si vous souhaitez Update all/some/none? [a/s/n]:, puis attendra votre réponse. Bien que vous devriez vous efforcer d’avoir les versions de packages les plus récentes, nous recommandons en pratique de ne mettre à jour les packages que lors d’une session R neuve, avant qu’aucun package ne soit chargé.

Key Points
  • Commencer à utiliser R et RStudio
Noble, William Stafford. 2009. “A Quick Guide to Organizing Computational Biology Projects.” PLOS Computational Biology 5 (7): 1–5. https://doi.org/10.1371/journal.pcbi.1000424.

  1. Contrairement à l’utilisation de R directement depuis la console de ligne de commande. Il existe d’autres logiciels qui s’interfacent et s’intègrent à R, mais RStudio est particulièrement adapté aux débutants tout en offrant de nombreuses fonctionnalités très avancées.↩︎

  2. c’est-à-dire des extensions qui confèrent à R de nouvelles fonctionnalités, telles que l’analyse de données en bioinformatique.↩︎

  3. Dans ce cours, nous considérons la bioinformatique comme une science des données appliquée aux données biologiques ou biomédicales.↩︎

  4. Cette personne pourrait être, et sera très probablement, vous-même dans quelques mois ou quelques années après la réalisation des analyses.↩︎

  5. Nous présenterons la plupart d’entre eux ici (à l’exception des statistiques), mais nous ne parviendrons qu’à effleurer la surface de la richesse des possibilités offertes par R.↩︎

Content from Introduction à R


Last updated on 2026-11-07 | Edit this page

Overview

Questions

  • Premières commandes en R

Objectives

  • Définissez les termes suivants en lien avec R : objet, affecter, appeler, fonction, arguments, options.
  • Attribuer des valeurs à des objets dans R.
  • Apprendre à nommer des objets
  • Utiliser des commentaires pour éclairer le script.
  • Résoudre des opérations arithmétiques simples dans R.
  • Appeler des fonctions et utiliser des arguments pour modifier leurs options par défaut.
  • Examiner le contenu des vecteurs et en manipuler le contenu.
  • Sélectionner des sous-ensembles de vecteurs et en extraire des valeurs.
  • Analyser des vecteurs contenant des données manquantes.

Cet épisode est basé sur la leçon Data Analysis and Visualisation in R for Ecologists de Data Carpentries.

Création d’objets dans R


Vous pouvez obtenir des résultats depuis R en saisissant simplement des expressions mathématiques dans la console :

R

3 + 5

OUTPUT

[1] 8

R

12 / 7

OUTPUT

[1] 1.714286

Cependant, pour faire des choses utiles et intéressantes, nous devons affecter des valeurs à des objets. Pour créer un objet, nous devons lui donner un nom suivi de l’opérateur d’affectation <-, puis de la valeur que nous souhaitons lui affecter :

R

weight_kg <- 55

<- est l’opérateur d’affectation. Il attribue des valeurs à droite à des objets à gauche. Ainsi, après avoir exécuté x <- 3, la valeur de x est 3. La flèche peut être lue comme 3 va dans x. Pour des raisons historiques, vous pouvez également utiliser = pour les affectations, mais pas dans tous les contextes. En raison des légères différences de syntaxe, il est recommandé d’utiliser toujours <- pour les affectations.

Dans RStudio, saisir Alt + - (appuyer sur Alt en même temps que la touche -) permet d’écrire <- en un seul coup de touche sur un PC, tandis que saisir Option + - (appuyer sur Option en même temps que la touche -) fait de même sur un Mac.

Nommer les variables

Les objets peuvent porter n’importe quel nom, tel que x, current_temperature ou subject_id. Il convient que les noms de vos objets soient explicites et pas trop longs. Ils ne peuvent pas commencer par un chiffre (2x n’est pas valide, mais x2 l’est). R est sensible à la casse (par exemple, weight_kg est différent de Weight_kg). Certains noms ne peuvent pas être utilisés car ils correspondent aux noms de fonctions fondamentales de R (par exemple, if, else, for ; voir la page du manuel Reserved Words in R pour une liste complète). En général, même si c’est autorisé, il est préférable de ne pas utiliser les noms d’autres fonctions (par exemple, c, T, mean, data, df, weights). En cas de doute, consultez l’aide pour voir si le nom est déjà utilisé. Il est également préférable d’éviter les points (.) au sein du nom d’un objet, comme dans my.dataset. De nombreuses fonctions en R contiennent des points dans leur nom pour des raisons historiques, mais comme les points ont une signification spéciale en R (pour les méthodes) et dans d’autres langages de programmation, il est préférable de les éviter. Il est également recommandé d’utiliser des noms communs pour les objets et des verbes pour les fonctions. Il est important d’être cohérent dans la mise en forme de votre code (l’endroit où vous placez les espaces, la manière dont vous nommez les objets, etc.). L’utilisation d’un style de codage cohérent rend votre code plus lisible pour vous-même à l’avenir et pour vos collaborateurs. En R, certains guides de style populaires sont celui de Google, le style de tidyverse et le guide de style de Bioconductor. Celui de tidyverse est très complet et peut sembler accablant au début. Vous pouvez installer le package lintr pour vérifier automatiquement les problèmes de mise en forme de votre code.

Objets vs. variables : Ce que l’on appelle objects dans R est appelé variables dans de nombreux autres langages de programmation. Selon le contexte, object et variable peuvent avoir des significations radicalement différentes. Cependant, dans cette leçon, les deux termes sont utilisés comme des synonymes. Pour plus d’informations, voir ici.

Lorsqu’on attribue une valeur à un objet, R n’affiche rien. Vous pouvez forcer R à afficher la valeur en utilisant des parenthèses ou en saisissant le nom de l’objet :

R

weight_kg <- 55    # doesn't print anything
(weight_kg <- 55)  # but putting parenthesis around the call prints the value of `weight_kg`

OUTPUT

[1] 55

R

weight_kg          # and so does typing the name of the object

OUTPUT

[1] 55

Maintenant que R a weight_kg en mémoire, nous pouvons effectuer des opérations arithmétiques avec celui-ci. Par exemple, nous souhaiterions peut-être convertir ce poids en livres (le poids en livres est 2,2 fois le poids en kg) :

R

2.2 * weight_kg

OUTPUT

[1] 121

Nous pouvons également modifier la valeur d’un objet en lui attribuant une nouvelle valeur :

R

weight_kg <- 57.5
2.2 * weight_kg

OUTPUT

[1] 126.5

Cela signifie que l’attribution d’une valeur à un objet ne modifie pas les valeurs des autres objets. Par exemple, stockons le poids de l’animal en livres dans un nouvel objet, weight_lb :

R

weight_lb <- 2.2 * weight_kg

puis modifier weight_kg en 100.

R

weight_kg <- 100
Discussion

Défi :

Selon vous, quel est le contenu actuel de l’objet weight_lb ? 126.5 ou 220 ?

Commentaires


Le caractère de commentaire dans R est # ; tout ce qui se trouve à droite d’un # dans un script sera ignoré par R. Il est utile de laisser des notes et des explications dans vos scripts.

RStudio permet de commenter ou de décommenter facilement un paragraphe : après avoir sélectionné les lignes que vous souhaitez commenter, appuyez simultanément sur Ctrl + Shift + C sur votre clavier. Si vous ne souhaitez commenter qu’une seule ligne, vous pouvez placer le curseur n’importe où sur cette ligne (c’est-à-dire qu’il n’est pas nécessaire de sélectionner l’intégralité de la ligne), puis appuyer sur Ctrl + Shift + C.

Discussion

Défi

Quelles sont les valeurs après chaque instruction dans ce qui suit ?

R

mass <- 47.5            # mass?
age  <- 122             # age?
mass <- mass * 2.0      # mass?
age  <- age - 20        # age?
mass_index <- mass/age  # mass_index?

Fonctions et leurs arguments


Les fonctions sont des « scripts préparés » qui automatisent des ensembles de commandes plus complexes, notamment des opérations d’affectation, etc. De nombreuses fonctions sont prédéfinies, ou peuvent être rendues disponibles en important des packages R (on en reparlera plus tard). Une fonction reçoit généralement un ou plusieurs paramètres appelés arguments. Les fonctions renvoient souvent (mais pas toujours) une valeur. Un exemple type serait la fonction sqrt(). L’entrée (l’argument) doit être un nombre, et la valeur de retour (en fait, la sortie) est la racine carrée de ce nombre. L’exécution d’une fonction (« son lancement ») est appelée appel de la fonction. Un exemple d’appel de fonction est :

R

b <- sqrt(a)

Ici, la valeur de a est transmise à la fonction sqrt(), la fonction sqrt() calcule la racine carrée et renvoie la valeur qui est ensuite affectée à l’objet b. Cette fonction est très simple, car elle ne prend qu’un seul argument.

La « valeur » de retour d’une fonction n’a pas nécessairement besoin d’être numérique (comme celle de sqrt()), et elle n’a pas non plus besoin d’être un seul élément : elle peut être un ensemble d’éléments, voire un jeu de données. Nous verrons cela lorsque nous lirons des fichiers de données dans R.

Les arguments peuvent être n’importe quoi, et non seulement des nombres ou des noms de fichiers, mais aussi d’autres objets. La signification exacte de chaque argument varie selon la fonction et doit être consultée dans la documentation (voir ci-dessous). Certaines fonctions acceptent des arguments qui peuvent être spécifiés par l’utilisateur ou, s’ils sont omis, prendre une valeur par défaut : ceux-ci sont appelés options. Les options sont généralement utilisées pour modifier le mode de fonctionnement de la fonction, par exemple pour déterminer si elle ignore les « valeurs erronées » ou quel symbole utiliser dans un graphique. Cependant, si vous souhaitez quelque chose de spécifique, vous pouvez spécifier une valeur de votre choix qui sera utilisée à la place de la valeur par défaut.

Essayons une fonction capable de prendre plusieurs arguments : round().

R

round(3.14159)

OUTPUT

[1] 3

Ici, nous avons appelé round() avec un seul argument, 3.14159, et celui-ci a renvoyé la valeur 3. C’est parce que la valeur par défaut consiste à arrondir au nombre entier le plus proche. Si nous souhaitons obtenir plus de chiffres, nous pouvons voir comment faire en obtenant des informations sur la fonction round. Nous pouvons utiliser args(round) ou consulter l’aide de cette fonction via ?round.

R

args(round)

OUTPUT

function (x, digits = 0, ...)
NULL

R

?round

On voit que si l’on souhaite un nombre de chiffres différent, on peut saisir digits=2 ou le nombre souhaité.

R

round(3.14159, digits = 2)

OUTPUT

[1] 3.14

Si vous fournissez les arguments exactement dans le même ordre que celui utilisé pour leur définition, vous n’avez pas besoin de les nommer :

R

round(3.14159, 2)

OUTPUT

[1] 3.14

Et si vous nommez les arguments, vous pouvez en changer l’ordre :

R

round(digits = 2, x = 3.14159)

OUTPUT

[1] 3.14

Il est recommandé de placer les arguments obligatoires (comme le nombre que vous arrondissez) en premier dans votre appel de fonction, et de spécifier le nom de tous les arguments optionnels. Sinon, quelqu’un lisant votre code pourrait devoir consulter la définition d’une fonction présentant des arguments inconnus pour comprendre ce que vous faites. En spécifiant le nom des arguments, vous vous préservez également contre d’éventuels changements futurs de l’interface de la fonction, qui pourraient potentiellement ajouter de nouveaux arguments entre ceux existants.

Vecteurs et types de données


Un vecteur est le type de données le plus courant et le plus basique dans R, et constitue pratiquement l’outil de base de R. Un vecteur est composé d’une série de valeurs, telles que des nombres ou des caractères. Nous pouvons attribuer une série de valeurs à un vecteur à l’aide de la fonction c(). Par exemple, nous pouvons créer un vecteur de poids d’animaux et l’attribuer à un nouvel objet weight_g :

R

weight_g <- c(50, 60, 65, 82)
weight_g

OUTPUT

[1] 50 60 65 82

Un vecteur peut également contenir des caractères :

R

molecules <- c("dna", "rna", "protein")
molecules

OUTPUT

[1] "dna"     "rna"     "protein"

Les guillemets autour de « dna », « rna », etc., sont indispensables ici. Sans les guillemets, R supposera qu’il existe des objets nommés dna, rna et protein. Comme ces objets n’existent pas dans la mémoire de R, un message d’erreur s’affichera.

Il existe de nombreuses fonctions qui vous permettent d’examiner le contenu d’un vecteur. length() vous indique combien d’éléments se trouvent dans un vecteur particulier :

R

length(weight_g)

OUTPUT

[1] 4

R

length(molecules)

OUTPUT

[1] 3

Une caractéristique importante d’un vecteur est que tous ses éléments sont du même type de données. La fonction class() indique la classe (le type d’élément) d’un objet :

R

class(weight_g)

OUTPUT

[1] "numeric"

R

class(molecules)

OUTPUT

[1] "character"

La fonction str() fournit un aperçu de la structure d’un objet et de ses éléments. C’est une fonction utile lorsque l’on travaille avec des objets volumineux et complexes :

R

str(weight_g)

OUTPUT

 num [1:4] 50 60 65 82

R

str(molecules)

OUTPUT

 chr [1:3] "dna" "rna" "protein"

Vous pouvez utiliser la fonction c() pour ajouter d’autres éléments à votre vecteur :

R

weight_g <- c(weight_g, 90) # add to the end of the vector
weight_g <- c(30, weight_g) # add to the beginning of the vector
weight_g

OUTPUT

[1] 30 50 60 65 82 90

Dans la première ligne, nous prenons le vecteur d’origine weight_g, ajoutons la valeur 90 à sa fin et enregistrons le résultat dans weight_g. Ensuite, nous ajoutons la valeur 30 au début, enregistrant à nouveau le résultat dans weight_g.

Nous pouvons répéter cette opération à plusieurs reprises pour agrandir un vecteur ou assembler un jeu de données. Lors de la programmation, cela peut s’avérer utile pour ajouter des résultats que nous recueillons ou calculons.

Un vecteur atomique est le type de données R le plus simple et constitue un vecteur linéaire d’un seul type. Plus haut, nous avons vu 2 des 6 principaux types de vecteurs atomiques utilisés par R : "character" et "numeric" (ou "double"). Ce sont les éléments de base à partir desquels sont construits tous les objets R. Les 4 autres types de vecteurs atomiques sont :

  • "logical" pour TRUE et FALSE (le type de données booléen)
  • "integer" pour les nombres entiers (par ex., 2L, le L indique à R qu’il s’agit d’un nombre entier)
  • "complex" pour représenter des nombres complexes avec partie réelle et partie imaginaire (par ex., 1 + 4i) et c’est tout ce que nous allons dire à leur sujet
  • "raw" pour les flux binaires dont nous ne parlerons pas davantage

Vous pouvez vérifier le type de votre vecteur en utilisant la fonction typeof() et en saisissant votre vecteur comme argument.

Les vecteurs sont l’une des nombreuses structures de données utilisées par R. Parmi les autres structures importantes figurent les listes (list), les matrices (matrix), les tableaux de données (data.frame), les facteurs (factor) et les tableaux (array).

Challenge

Défi :

Nous avons vu que les vecteurs atomiques peuvent être de type caractère, numérique (ou double), entier et logique. Mais qu’arrive-t-il si nous essayons de mélanger ces types dans un seul vecteur ?

R les convertit implicitement tous au même type

Challenge

Défi :

Qu’arrivera-t-il dans chacun de ces exemples ? (indice : utilisez class() pour vérifier le type de données de vos objets et saisissez leurs noms pour voir ce qui se passe) :

R

num_char <- c(1, 2, 3, "a")
num_logical <- c(1, 2, 3, TRUE, FALSE)
char_logical <- c("a", "b", "c", TRUE)
tricky <- c(1, 2, 3, "4")

R

class(num_char)

OUTPUT

[1] "character"

R

num_char

OUTPUT

[1] "1" "2" "3" "a"

R

class(num_logical)

OUTPUT

[1] "numeric"

R

num_logical

OUTPUT

[1] 1 2 3 1 0

R

class(char_logical)

OUTPUT

[1] "character"

R

char_logical

OUTPUT

[1] "a"    "b"    "c"    "TRUE"

R

class(tricky)

OUTPUT

[1] "character"

R

tricky

OUTPUT

[1] "1" "2" "3" "4"
Challenge

Défi :

Pourquoi pensez-vous que cela se produit ?

Les vecteurs ne peuvent contenir qu’un seul type de données. R tente de convertir le contenu de ce vecteur afin de trouver un dénominateur commun qui ne perde aucune information.

Challenge

Défi :

Combien de valeurs dans combined_logical sont "TRUE" (en tant que caractère) dans l’exemple suivant :

R

num_logical <- c(1, 2, 3, TRUE)
char_logical <- c("a", "b", "c", TRUE)
combined_logical <- c(num_logical, char_logical)

Un seul. Il n’y a aucune mémoire des types de données antérieurs, et la coercition s’effectue la première fois que le vecteur est évalué. Par conséquent, le TRUE dans num_logical est converti en 1 avant d’être converti en "1" dans combined_logical.

R

combined_logical

OUTPUT

[1] "1"    "2"    "3"    "1"    "a"    "b"    "c"    "TRUE"
Challenge

Défi :

En R, nous appelons coercion la conversion d’objets d’une classe à une autre. Ces conversions s’effectuent selon une hiérarchie, selon laquelle certains types sont prioritairement convertis en d’autres. Pouvez-vous tracer un schéma représentant la hiérarchie de la manière dont ces types de données sont convertis ?

logique → numérique → caractère ← logique

Extraction de sous-ensembles de vecteurs


Si nous souhaitons extraire une ou plusieurs valeurs d’un vecteur, nous devons fournir un ou plusieurs indices entre crochets. Par exemple :

R

molecules <- c("dna", "rna", "peptide", "protein")
molecules[2]

OUTPUT

[1] "rna"

R

molecules[c(3, 2)]

OUTPUT

[1] "peptide" "rna"    

Nous pouvons également répéter les indices pour créer un objet comportant plus d’éléments que l’original :

R

more_molecules <- molecules[c(1, 2, 3, 2, 1, 4)]
more_molecules

OUTPUT

[1] "dna"     "rna"     "peptide" "rna"     "dna"     "protein"

Les indices en R commencent à 1. Les langages de programmation tels que Fortran, MATLAB, Julia et R commencent à compter à partir de 1, car c’est ainsi que les êtres humains le font habituellement. Les langages de la famille C (y compris C++, Java, Perl et Python) comptent à partir de 0, car c’est plus simple pour les ordinateurs.

Enfin, il est également possible d’obtenir tous les éléments d’un vecteur, à l’exception de certains éléments spécifiés, en utilisant des indices négatifs :

R

molecules ## all molecules

OUTPUT

[1] "dna"     "rna"     "peptide" "protein"

R

molecules[-1] ## all but the first one

OUTPUT

[1] "rna"     "peptide" "protein"

R

molecules[-c(1, 3)] ## all but 1st/3rd ones

OUTPUT

[1] "rna"     "protein"

R

molecules[c(-1, -3)] ## all but 1st/3rd ones

OUTPUT

[1] "rna"     "protein"

Sélection conditionnelle d’éléments


Une autre façon courante de sélectionner un sous-ensemble consiste à utiliser un vecteur logique. TRUE sélectionnera l’élément ayant le même indice, tandis que FALSE ne le sélectionnera pas :

R

weight_g <- c(21, 34, 39, 54, 55)
weight_g[c(TRUE, FALSE, TRUE, TRUE, FALSE)]

OUTPUT

[1] 21 39 54

En général, ces vecteurs logiques ne sont pas saisis manuellement, mais sont le résultat d’autres fonctions ou de tests logiques. Par exemple, si vous souhaitiez sélectionner uniquement les valeurs supérieures à 50 :

R

## will return logicals with TRUE for the indices that meet
## the condition
weight_g > 50

OUTPUT

[1] FALSE FALSE FALSE  TRUE  TRUE

R

## so we can use this to select only the values above 50
weight_g[weight_g > 50]

OUTPUT

[1] 54 55

Vous pouvez combiner plusieurs tests à l’aide de & (les deux conditions sont vraies, ET) ou de | (au moins l’une des conditions est vraie, OU) :

R

weight_g[weight_g < 30 | weight_g > 50]

OUTPUT

[1] 21 54 55

R

weight_g[weight_g >= 30 & weight_g == 21]

OUTPUT

numeric(0)

Ici, < désigne « inférieur à », > « supérieur à », >= « supérieur ou égal à » et == « égal à ». Le double signe égal == est une opération de vérification de l’égalité numérique entre le membre de gauche et celui de droite, et ne doit pas être confondu avec le signe unique =, qui effectue l’affectation d’une variable (à l’instar de <-).

Une tâche courante consiste à rechercher certaines chaînes de caractères dans un vecteur. On pourrait utiliser l’opérateur « ou » | pour vérifier l’égalité avec plusieurs valeurs, mais cela peut rapidement devenir fastidieux. La fonction %in% permet de vérifier si l’un des éléments d’un vecteur de recherche est trouvé :

R

molecules <- c("dna", "rna", "protein", "peptide")
molecules[molecules == "rna" | molecules == "dna"] # returns both rna and dna

OUTPUT

[1] "dna" "rna"

R

molecules %in% c("rna", "dna", "metabolite", "peptide", "glycerol")

OUTPUT

[1]  TRUE  TRUE FALSE  TRUE

R

molecules[molecules %in% c("rna", "dna", "metabolite", "peptide", "glycerol")]

OUTPUT

[1] "dna"     "rna"     "peptide"
Challenge

Défi :

Parvenez-vous à comprendre pourquoi "four" > "five" renvoie TRUE ?

R

"four" > "five"

OUTPUT

[1] TRUE

Lorsqu’on utilise > ou < sur des chaînes de caractères, R compare leur ordre alphabétique. Ici, "four" vient après "five" et lui est donc supérieur.

Noms


Il est possible de nommer chaque élément d’un vecteur. Le bloc de code ci-dessous montre un vecteur initial sans aucun nom, ainsi que la manière dont les noms sont définis et récupérés.

R

x <- c(1, 5, 3, 5, 10)
names(x) ## no names

OUTPUT

NULL

R

names(x) <- c("A", "B", "C", "D", "E")
names(x) ## now we have names

OUTPUT

[1] "A" "B" "C" "D" "E"

Lorsqu’un vecteur possède des noms, il est possible d’accéder aux éléments par leur nom, en plus de leur index.

R

x[c(1, 3)]

OUTPUT

A C
1 3 

R

x[c("A", "C")]

OUTPUT

A C
1 3 

Données manquantes


Comme R a été conçu pour analyser des jeux de données, il inclut le concept de données manquantes (ce qui est rare dans d’autres langages de programmation). Les données manquantes sont représentées dans les vecteurs par NA.

Lorsque vous effectuez des opérations sur des nombres, la plupart des fonctions renvoient NA si les données avec lesquelles vous travaillez contiennent des valeurs manquantes. Cette fonctionnalité rend plus difficile le fait de négliger les cas où vous manipulez des données manquantes. Vous pouvez ajouter l’argument na.rm = TRUE pour calculer le résultat tout en ignorant les valeurs manquantes.

R

heights <- c(2, 4, 4, NA, 6)
mean(heights)

OUTPUT

[1] NA

R

max(heights)

OUTPUT

[1] NA

R

mean(heights, na.rm = TRUE)

OUTPUT

[1] 4

R

max(heights, na.rm = TRUE)

OUTPUT

[1] 6

Si vos données contiennent des valeurs manquantes, vous souhaiterez peut-être vous familiariser avec les fonctions is.na(), na.omit() et complete.cases(). Consultez les exemples ci-dessous.

R

## Extract those elements which are not missing values.
heights[!is.na(heights)]

OUTPUT

[1] 2 4 4 6

R

## Returns the object with incomplete cases removed.
## The returned object is an atomic vector of type `"numeric"`
## (or `"double"`).
na.omit(heights)

OUTPUT

[1] 2 4 4 6
attr(,"na.action")
[1] 4
attr(,"class")
[1] "omit"

R

## Extract those elements which are complete cases.
## The returned object is an atomic vector of type `"numeric"`
## (or `"double"`).
heights[complete.cases(heights)]

OUTPUT

[1] 2 4 4 6
Challenge

Défi :

  1. À l’aide de ce vecteur de tailles en pouces, créez un nouveau vecteur dont les valeurs NA ont été supprimées.

R

heights <- c(63, 69, 60, 65, NA, 68, 61, 70, 61, 59, 64, 69, 63, 63, NA, 72, 65, 64, 70, 63, 65)
  1. Utilisez la fonction median() pour calculer la médiane du vecteur heights.
  2. Utilisez R pour déterminer combien de personnes dans l’ensemble mesurent plus de 67 pouces.

R

heights_no_na <- heights[!is.na(heights)]
## or
heights_no_na <- na.omit(heights)

R

median(heights, na.rm = TRUE)

OUTPUT

[1] 64

R

heights_above_67 <- heights_no_na[heights_no_na > 67]
length(heights_above_67)

OUTPUT

[1] 6

Génération de vecteurs


Constructeurs

Il existe plusieurs fonctions permettant de générer des vecteurs de différents types. Pour générer un vecteur de nombres, on peut utiliser le constructeur numeric(), en fournissant la longueur du vecteur de sortie comme paramètre. Les valeurs seront initialisées à 0.

R

numeric(3)

OUTPUT

[1] 0 0 0

R

numeric(10)

OUTPUT

 [1] 0 0 0 0 0 0 0 0 0 0

Notons que si nous demandons un vecteur numérique de longueur 0, nous obtenons exactement cela :

R

numeric(0)

OUTPUT

numeric(0)

Il existe des constructeurs similaires pour les caractères et les valeurs logiques, nommés respectivement character() et logical().

Challenge

Défi :

Quelles sont les valeurs par défaut pour les vecteurs de caractères et logiques ?

R

character(2) ## the empty character

OUTPUT

[1] "" ""

R

logical(2)   ## FALSE

OUTPUT

[1] FALSE FALSE

Répliquer des éléments

La fonction rep permet de répéter une valeur un certain nombre de fois. Si nous souhaitons initialiser un vecteur numérique de longueur 5 avec la valeur -1, par exemple, nous pourrions procéder comme suit :

R

rep(-1, 5)

OUTPUT

[1] -1 -1 -1 -1 -1

De même, pour générer un vecteur rempli de valeurs manquantes, ce qui constitue souvent un bon point de départ, sans formuler d’hypothèses sur les données à collecter :

R

rep(NA, 5)

OUTPUT

[1] NA NA NA NA NA

rep peut accepter en entrée des vecteurs de longueur quelconque (ci-dessus, nous avons utilisé des vecteurs de longueur 1) et de tout type. Par exemple, si nous voulons répéter les valeurs 1, 2 et 3 cinq fois, nous procéderions comme suit :

R

rep(c(1, 2, 3), 5)

OUTPUT

 [1] 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
Challenge

Défi :

Et si nous voulions répéter les valeurs 1, 2 et 3 cinq fois, mais obtenir cinq 1, cinq 2 et cinq 3 dans cet ordre ? Il existe deux possibilités — consultez ?rep ou ?sort pour obtenir de l’aide.

R

rep(c(1, 2, 3), each = 5)

OUTPUT

 [1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3

R

sort(rep(c(1, 2, 3), 5))

OUTPUT

 [1] 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3

Génération de séquences

Une autre fonction très utile est seq, pour générer une suite de nombres. Par exemple, pour générer une suite d’entiers de 1 à 20 par paliers de 2, on utiliserait :

R

seq(from = 1, to = 20, by = 2)

OUTPUT

 [1]  1  3  5  7  9 11 13 15 17 19

La valeur par défaut de by est 1 et, étant donné que la génération d’une suite allant d’une valeur à une autre par paliers de 1 est fréquemment utilisée, il existe un raccourci :

R

seq(1, 5, 1)

OUTPUT

[1] 1 2 3 4 5

R

seq(1, 5) ## default by

OUTPUT

[1] 1 2 3 4 5

R

1:5

OUTPUT

[1] 1 2 3 4 5

Pour générer une suite de nombres de 1 à 20 d’une longueur finale de 3, on utiliserait :

R

seq(from = 1, to = 20, length.out = 3)

OUTPUT

[1]  1.0 10.5 20.0

Échantillons aléatoires et permutations

Un dernier groupe de fonctions utiles consiste à génèrer des données aléatoires. La première, sample, génère une permutation aléatoire d’un autre vecteur. Par exemple, pour établir un ordre aléatoire pour l’examen oral de 10 étudiants, j’attribue d’abord à chaque étudiant un numéro de 1 à 10 (par exemple, selon l’ordre alphabétique de son nom) puis :

R

sample(1:10)

OUTPUT

 [1]  9  4  7  1  2  5  3 10  6  8

Sans arguments supplémentaires, sample renvoie une permutation de tous les éléments du vecteur. Si je souhaite un échantillon aléatoire d’une certaine taille, je définirais cette valeur comme second argument. Ci-dessous, je tire 5 lettres aléatoires de l’alphabet contenu dans le vecteur letters prédéfini :

R

sample(letters, 5)

OUTPUT

[1] "s" "a" "u" "x" "j"

Si je souhaitais obtenir un échantillon plus long que le vecteur d’entrée, ou pouvoir tirer certains éléments plusieurs fois, je devrais fixer l’argument replace à TRUE :

R

sample(1:5, 10, replace = TRUE)

OUTPUT

 [1] 2 1 5 5 1 1 5 5 2 2
Challenge

Défi :

En essayant les fonctions ci-dessus, vous aurez constaté que les échantillons sont effectivement aléatoires et qu’on n’obtient pas la même permutation deux fois. Pour pouvoir reproduire ces tirages aléatoires, on peut définir manuellement la graine de génération de nombres aléatoires avec set.seed() avant de tirer l’échantillon aléatoire.

Testez cette fonctionnalité avec votre voisin. Tirez d’abord deux permutations aléatoires de 1:10 indépendamment et observez que vous obtenez des résultats différents.

Définissez maintenant la graine avec, par exemple, set.seed(123) et répétez l’échantillonnage aléatoire. Observez que vous obtenez désormais les mêmes échantillonnages aléatoires.

Répétez l’opération en définissant une graine différente.

Différentes permutations

R

sample(1:10)

OUTPUT

 [1]  9  1  4  3  6  2  5  8 10  7

R

sample(1:10)

OUTPUT

 [1]  4  9  7  6  1 10  8  3  2  5

Mêmes permutations avec la graine 123

R

set.seed(123)
sample(1:10)

OUTPUT

 [1]  3 10  2  8  6  9  1  7  5  4

R

set.seed(123)
sample(1:10)

OUTPUT

 [1]  3 10  2  8  6  9  1  7  5  4

Une graine différente

R

set.seed(1)
sample(1:10)

OUTPUT

 [1]  9  4  7  1  2  5  3 10  6  8

R

set.seed(1)
sample(1:10)

OUTPUT

 [1]  9  4  7  1  2  5  3 10  6  8

Tirage d’échantillons à partir d’une distribution normale

La dernière fonction que nous allons voir est rnorm, qui tire un échantillon aléatoire d’une distribution normale. Deux distributions normales dont les moyennes sont 0 et 100 et les écarts-types 1 et 5, notées N(0, 1) et N(100, 5), sont illustrées ci-dessous.

Two figures illustraing normal distributonis N(0,1) and N(100,5).
Two normal distributions: N(0, 1) on the left and N(100, 5) on the right.

Les trois arguments, n, mean et sd, définissent la taille de l’échantillon ainsi que les paramètres de la distribution normale, à savoir sa moyenne et son écart-type. Les valeurs par défaut de la moyenne et de l’écart-type sont respectivement 0 et 1.

R

rnorm(5)

OUTPUT

[1]  0.69641761  0.05351568 -1.31028350 -2.12306606 -0.20807859

R

rnorm(5, 2, 2)

OUTPUT

[1]  1.3744268 -0.1164714  2.8344472  1.3690969  3.6510983

R

rnorm(5, 100, 5)

OUTPUT

[1] 106.45636  96.87448  95.62427 100.71678 107.12595

Maintenant que nous avons appris à écrire des scripts et les bases des structures de données de R, nous sommes prêts à commencer à travailler avec des données plus volumineuses et à découvrir les tableaux de données.

Key Points
  • Comment interagir avec R

Content from Débuts avec les données


Last updated on 2026-11-07 | Edit this page

Overview

Questions

  • Première analyse de données dans R

Objectives

  • Décrivez ce qu’est un data.frame.
  • Charger des données externes depuis un fichier .csv dans un tableau de données.
  • Résumer le contenu d’un tableau de données.
  • Décrivez ce qu’est un facteur.
  • Convertir entre chaînes de caractères et facteurs.
  • Réordonner et renommer les facteurs.
  • Formater les dates.
  • Exporter et enregistrer les données.

Cet épisode est basé sur la leçon Data Analysis and Visualisation in R for Ecologists de Data Carpentries.

Présentation des données d’expression génique


Nous allons utiliser une partie des données publiées par Blackmore et al. (2017), The effect of upper-respiratory infection on transcriptomic changes in the CNS. L’objectif de l’étude était de déterminer l’effet d’une infection des voies respiratoires supérieures sur les modifications de la transcription de l’ARN dans le cervelet et la moelle épinière après l’infection. Des souris C57BL/6 âgées de huit semaines et appariées selon le sexe ont reçu, par voie intranasale, du sérum physiologique ou le virus de la grippe A. Les modifications transcriptomiques dans les tissus du cervelet et de la moelle épinière ont été évaluées par RNA-seq aux jours 0 (souris non infectées), 4 et 8.

L’ensemble de données est stocké sous la forme d’un fichier de valeurs séparées par des virgules (CSV). Chaque ligne contient des informations concernant une seule mesure d’expression ARN, et les onze premières colonnes représentent :

Colonne Description
gene Le nom du gène mesuré
sample Le nom de l’échantillon dans lequel l’expression génique a été mesurée
expression La valeur de l’expression génique
organism L’organisme/l’espèce - ici, toutes les données proviennent de souris
age L’âge de la souris (ici, toutes les souris avaient 8 semaines)
sex Le sexe de la souris
infection L’état infectieux de la souris, c’est-à-dire infectée par le virus de la grippe A ou non infectée.
strain La souche du virus de la grippe A.
time La durée de l’infection (en jours).
tissue Le tissu utilisé pour l’expérience d’expression génique, c’est-à-dire le cervelet ou la moelle épinière.
mouse L’identifiant unique de la souris.

Nous allons utiliser la fonction R download.file() pour télécharger le fichier CSV contenant les données d’expression génique, et nous utiliserons read.csv() pour charger dans la mémoire le contenu du fichier CSV sous la forme d’un objet de classe data.frame. Dans la commande download.file, la première entrée est une chaîne de caractères contenant l’URL de la source. Cette URL de source télécharge un fichier CSV depuis un dépôt GitHub. Le texte après la virgule ("data/rnaseq.csv") correspond à la destination du fichier sur votre machine locale. Vous devrez disposer d’un dossier sur votre machine nommé "data" où vous téléchargerez le fichier. Ainsi, cette commande télécharge le fichier distant, le nomme "rnaseq.csv" et l’ajoute à un dossier déjà existant nommé "data".

R

download.file(url = "https://github.com/carpentries-incubator/bioc-intro/raw/main/episodes/data/rnaseq.csv",
              destfile = "data/rnaseq.csv")

Vous êtes désormais prêt à charger les données :

R

rna <- read.csv("data/rnaseq.csv")

Cette instruction ne produit aucun résultat car, comme vous vous en souvenez peut-être, les affectations n’affichent rien. Si nous voulons vérifier que nos données ont été chargées, nous pouvons consulter le contenu du tableau de données en saisissant son nom :

R

rna

Waouh… c’était beaucoup de résultats. Au moins, cela signifie que les données ont été chargées correctement. Vérifions le début (les 6 premières lignes) de ce tableau de données à l’aide de la fonction head() :

R

head(rna)

OUTPUT

     gene     sample expression     organism age    sex  infection  strain time
1     Asl GSM2545336       1170 Mus musculus   8 Female InfluenzaA C57BL/6    8
2    Apod GSM2545336      36194 Mus musculus   8 Female InfluenzaA C57BL/6    8
3 Cyp2d22 GSM2545336       4060 Mus musculus   8 Female InfluenzaA C57BL/6    8
4    Klk6 GSM2545336        287 Mus musculus   8 Female InfluenzaA C57BL/6    8
5   Fcrls GSM2545336         85 Mus musculus   8 Female InfluenzaA C57BL/6    8
6  Slc2a4 GSM2545336        782 Mus musculus   8 Female InfluenzaA C57BL/6    8
      tissue mouse ENTREZID
1 Cerebellum    14   109900
2 Cerebellum    14    11815
3 Cerebellum    14    56448
4 Cerebellum    14    19144
5 Cerebellum    14    80891
6 Cerebellum    14    20528
                                                                       product
1                               argininosuccinate lyase, transcript variant X1
2                                       apolipoprotein D, transcript variant 3
3 cytochrome P450, family 2, subfamily d, polypeptide 22, transcript variant 2
4                         kallikrein related-peptidase 6, transcript variant 2
5                Fc receptor-like S, scavenger receptor, transcript variant X1
6          solute carrier family 2 (facilitated glucose transporter), member 4
     ensembl_gene_id external_synonym chromosome_name   gene_biotype
1 ENSMUSG00000025533    2510006M18Rik               5 protein_coding
2 ENSMUSG00000022548             <NA>              16 protein_coding
3 ENSMUSG00000061740             2D22              15 protein_coding
4 ENSMUSG00000050063             Bssp               7 protein_coding
5 ENSMUSG00000015852    2810439C17Rik               3 protein_coding
6 ENSMUSG00000018566           Glut-4              11 protein_coding
                            phenotype_description
1           abnormal circulating amino acid level
2                      abnormal lipid homeostasis
3                        abnormal skin morphology
4                         abnormal cytokine level
5 decreased CD8-positive alpha-beta T cell number
6              abnormal circulating glucose level
  hsapiens_homolog_associated_gene_name
1                                   ASL
2                                  APOD
3                                CYP2D6
4                                  KLK6
5                                 FCRL2
6                                SLC2A4

R

## Try also
## View(rna)

Note

read.csv() suppose que les champs sont séparés par des virgules ; cependant, dans plusieurs pays, la virgule est utilisée comme séparateur décimal et le point-virgule (;) comme séparateur de champs. Si vous souhaitez lire ce type de fichiers dans R, vous pouvez utiliser la fonction read.csv2(). Elle se comporte exactement comme read.csv(), mais utilise des paramètres différents pour les séparateurs décimaux et de champs. Si vous travaillez avec un autre format, ces deux paramètres peuvent être spécifiés par l’utilisateur. Consultez l’aide de read.csv() en saisissant ?read.csv pour en savoir plus. Il existe également la fonction read.delim() pour lire des fichiers de données séparés par des tabulations. Il est important de noter que toutes ces fonctions sont en réalité des fonctions wrapper pour la fonction principale read.table() avec des arguments différents. Ainsi, les données ci-dessus auraient également pu être chargées en utilisant read.table() avec le paramètre de séparation ,. Le code est le suivant :

R

rna <- read.table(file = "data/rnaseq.csv",
                  sep = ",",
                  header = TRUE)

L’argument header doit être défini à TRUE pour pouvoir lire les en-têtes, car par défaut, read.table() a l’argument header défini à FALSE.

Qu’est-ce que des tableaux de données ?


Les tableaux de données sont la structure de données de facto pour la plupart des données tabulaires, et ce que nous utilisons pour la statistique et la représentation graphique.

Un tableau de données peut être créé manuellement, mais il est le plus souvent généré par les fonctions read.csv() ou read.table() ; en d’autres termes, lors de l’importation de feuilles de calcul depuis votre disque dur (ou le Web).

Un tableau de données est la représentation de données sous la forme d’un tableau où les colonnes sont des vecteurs de longueur identique. Comme les colonnes sont des vecteurs, chacune d’elles doit contenir un seul type de données (par exemple, des caractères, des entiers, des facteurs). Voici, par exemple, une figure illustrant un tableau de données comprenant un vecteur numérique, un vecteur de caractères et un vecteur logique.

Schematic representation of a tablular structure with different colours representing different columns and variables types.
Conceptual representation of a data.frame

Nous pouvons le constater en examinant la structure d’un tableau de données avec la fonction str() :

R

str(rna)

OUTPUT

'data.frame':	32428 obs. of  19 variables:
 $ gene                                 : chr  "Asl" "Apod" "Cyp2d22" "Klk6" ...
 $ sample                               : chr  "GSM2545336" "GSM2545336" "GSM2545336" "GSM2545336" ...
 $ expression                           : int  1170 36194 4060 287 85 782 1619 288 43217 1071 ...
 $ organism                             : chr  "Mus musculus" "Mus musculus" "Mus musculus" "Mus musculus" ...
 $ age                                  : int  8 8 8 8 8 8 8 8 8 8 ...
 $ sex                                  : chr  "Female" "Female" "Female" "Female" ...
 $ infection                            : chr  "InfluenzaA" "InfluenzaA" "InfluenzaA" "InfluenzaA" ...
 $ strain                               : chr  "C57BL/6" "C57BL/6" "C57BL/6" "C57BL/6" ...
 $ time                                 : int  8 8 8 8 8 8 8 8 8 8 ...
 $ tissue                               : chr  "Cerebellum" "Cerebellum" "Cerebellum" "Cerebellum" ...
 $ mouse                                : int  14 14 14 14 14 14 14 14 14 14 ...
 $ ENTREZID                             : int  109900 11815 56448 19144 80891 20528 97827 118454 18823 14696 ...
 $ product                              : chr  "argininosuccinate lyase, transcript variant X1" "apolipoprotein D, transcript variant 3" "cytochrome P450, family 2, subfamily d, polypeptide 22, transcript variant 2" "kallikrein related-peptidase 6, transcript variant 2" ...
 $ ensembl_gene_id                      : chr  "ENSMUSG00000025533" "ENSMUSG00000022548" "ENSMUSG00000061740" "ENSMUSG00000050063" ...
 $ external_synonym                     : chr  "2510006M18Rik" NA "2D22" "Bssp" ...
 $ chromosome_name                      : chr  "5" "16" "15" "7" ...
 $ gene_biotype                         : chr  "protein_coding" "protein_coding" "protein_coding" "protein_coding" ...
 $ phenotype_description                : chr  "abnormal circulating amino acid level" "abnormal lipid homeostasis" "abnormal skin morphology" "abnormal cytokine level" ...
 $ hsapiens_homolog_associated_gene_name: chr  "ASL" "APOD" "CYP2D6" "KLK6" ...

Inspection des objets data.frame


Nous avons déjà vu comment les fonctions head() et str() peuvent être utiles pour vérifier le contenu et la structure d’un tableau de données. Voici une liste non exhaustive de fonctions permettant de se faire une idée du contenu et de la structure des données. Essayons-les !

Taille :

  • dim(rna) - retourne un vecteur dont le premier élément est le nombre de lignes et le second le nombre de colonnes (les dimensions de l’objet).
  • nrow(rna) - renvoie le nombre de lignes.
  • ncol(rna) - renvoie le nombre de colonnes.

Contenu :

  • head(rna) - affiche les 6 premières lignes.
  • tail(rna) - affiche les 6 dernières lignes.

Noms :

  • names(rna) - renvoie les noms des colonnes (synonyme de colnames() pour les objets data.frame).
  • rownames(rna) - renvoie les noms de lignes.

Résumé :

  • str(rna) - structure de l’objet et informations sur la classe, la longueur et le contenu de chaque colonne.
  • summary(rna) - statistiques de synthèse pour chaque colonne.

Note : la plupart de ces fonctions sont « génériques » ; elles peuvent être utilisées sur d’autres types d’objets en plus de data.frame.

Challenge

Défi :

Sur la base de la sortie de str(rna), pouvez-vous répondre aux questions suivantes ?

  • Quelle est la classe de l’objet rna ?
  • Combien y a-t-il de lignes et de colonnes dans cet objet ?
  • classe : tableau de données
  • nombre de lignes : 32428, nombre de colonnes : 19

Indexation et extraction de sous-ensembles de tableaux de données


Notre tableau de données rna possède des lignes et des colonnes (il a 2 dimensions) ; si nous souhaitons en extraire certaines données spécifiques, nous devons spécifier les « coordonnées » souhaitées. Les numéros de ligne viennent en premier, suivis des numéros de colonne. Notez toutefois que différentes manières de spécifier ces coordonnées donnent des résultats de classes différentes.

R

# first element in the first column of the data frame (as a vector)
rna[1, 1]
# first element in the 6th column (as a vector)
rna[1, 6]
# first column of the data frame (as a vector)
rna[, 1]
# first column of the data frame (as a data.frame)
rna[1]
# first three elements in the 7th column (as a vector)
rna[1:3, 7]
# the 3rd row of the data frame (as a data.frame)
rna[3, ]
# equivalent to head_rna <- head(rna)
head_rna <- rna[1:6, ]
head_rna

: est une fonction spéciale qui crée des vecteurs numériques d’entiers en ordre croissant ou décroissant ; voyez par exemple 1:10 et 10:1. Consultez la section Génération de vecteurs pour plus de détails.

Vous pouvez également exclure certains indices d’un tableau de données en utilisant le signe « - » :

R

rna[, -1]          ## The whole data frame, except the first column
rna[-c(7:66465), ] ## Equivalent to head(rna)

On peut extraire des sous-ensembles de tableaux de données en utilisant des indices (comme illustré précédemment), mais aussi directement les noms des colonnes :

R

rna["gene"]       # Result is a data.frame
rna[, "gene"]     # Result is a vector
rna[["gene"]]     # Result is a vector
rna$gene          # Result is a vector

Dans RStudio, vous pouvez utiliser la fonctionnalité d’autocomplétion pour obtenir les noms complets et corrects des colonnes.

Challenge

Défi

  1. Créez un data.frame (rna_200) contenant uniquement les données de la ligne 200 du jeu de données rna.

  2. Remarquez comment nrow() vous a donné le nombre de lignes dans un data.frame ?

  • Utilisez ce nombre pour extraire uniquement cette dernière ligne du tableau de données initial rna.

  • Comparez cela avec ce que vous voyez comme la dernière ligne à l’aide de tail() pour vous assurer que cela correspond aux attentes.

  • Extrayez cette dernière ligne en utilisant nrow() au lieu du numéro de ligne.

  • Créez un nouveau tableau de données (rna_last) à partir de cette dernière ligne.

  1. Utilisez nrow() pour extraire la ligne située au milieu du tableau de données rna. Stockez le contenu de cette ligne dans un objet nommé rna_middle.

  2. Combinez nrow() avec la notation - ci-dessus pour reproduire le comportement de head(rna), en ne gardant que les premières 6 lignes du jeu de données rna.

R

## 1.
rna_200 <- rna[200, ]
## 2.
## Saving `n_rows` to improve readability and reduce duplication
n_rows <- nrow(rna)
rna_last <- rna[n_rows, ]
## 3.
rna_middle <- rna[n_rows / 2, ]
## 4.
rna_head <- rna[-(7:n_rows), ]

Facteurs


Les facteurs représentent des données catégorielles. Ils sont stockés sous forme d’entiers associés à des étiquettes et peuvent être ordonnés ou non. Bien que les facteurs ressemblent (et se comportent souvent) à des vecteurs de caractères, ils sont en réalité traités comme des vecteurs entiers par R. Il faut donc être très prudent lorsque l’on les traite comme des chaînes de caractères.

Une fois créés, les facteurs ne peuvent contenir qu’un ensemble prédéfini de valeurs, appelées niveaux. Par défaut, R trie toujours les niveaux par ordre alphabétique. Par exemple, si vous avez un facteur avec 2 niveaux :

R

sex <- factor(c("male", "female", "female", "male", "female"))

R attribuera 1 au niveau "female" et 2 au niveau "male" (car f précède m, même si le premier élément de ce vecteur est "male"). Vous pouvez vérifier cela en utilisant la fonction levels() et vous pouvez trouver le nombre de niveaux à l’aide de nlevels() :

R

levels(sex)

OUTPUT

[1] "female" "male"  

R

nlevels(sex)

OUTPUT

[1] 2

Parfois, l’ordre des facteurs n’a aucune importance ; d’autres fois, vous souhaiterez peut-être en spécifier l’ordre car celui-ci a un sens (par ex. « low », « medium », « high »), car il améliore votre visualisation ou parce qu’il est requis par un type d’analyse particulier. Ici, l’un des moyens de réordonner nos niveaux dans le vecteur sex serait :

R

sex ## current order

OUTPUT

[1] male   female female male   female
Levels: female male

R

sex <- factor(sex, levels = c("male", "female"))
sex ## after re-ordering

OUTPUT

[1] male   female female male   female
Levels: male female

Dans la mémoire de R, ces facteurs sont représentés par des entiers (1, 2, 3), mais ils sont plus informatifs que les entiers car les facteurs sont auto-descriptifs : "female", "male" est plus descriptif que 1, 2. Lequel est « mâle » ? Vous ne pourriez pas le déterminer uniquement à partir des données entières. Les facteurs, en revanche, intègrent cette information. Cela est particulièrement utile lorsqu’il y a de nombreux niveaux (comme le biotype génique dans notre jeu de données d’exemple).

Lorsque vos données sont stockées sous forme de facteur, vous pouvez utiliser la fonction plot() pour obtenir un aperçu rapide du nombre d’observations représentées par chaque niveau de facteur. Examinons le nombre de mâles et de femelles dans nos données.

R

plot(sex)
Barplot showing the number of 'male' and 'female' occurrences.
Bar plot of the number of females and males.

Conversion en chaîne de caractères

Si vous devez convertir un facteur en vecteur de caractères, vous utilisez as.character(x).

R

as.character(sex)

OUTPUT

[1] "male"   "female" "female" "male"   "female"

Renommage des facteurs

Si nous souhaitons renommer ce facteur, il suffit de modifier ses niveaux :

R

levels(sex)

OUTPUT

[1] "male"   "female"

R

levels(sex) <- c("M", "F")
sex

OUTPUT

[1] M F F M F
Levels: M F

R

plot(sex)
Barplot showing the number of 'M' and 'F' occurrences.
Challenge

Défi :

  • Remplacez « F » et « M » par « Female » et « Male » respectivement.

R

levels(sex)

OUTPUT

[1] "M" "F"

R

levels(sex) <- c("Male", "Female")
Challenge

Défi :

Nous avons vu comment créer des tableaux de données en utilisant read.csv(), mais ils peuvent également être créés manuellement avec la fonction data.frame(). Il y a quelques erreurs dans ce data.frame conçu à la main. Pouvez-vous les repérer et les corriger ? N’hésitez pas à expérimenter !

R

animal_data <- data.frame(
       animal = c(dog, cat, sea cucumber, sea urchin),
       feel = c("furry", "squishy", "spiny"),
       weight = c(45, 8 1.1, 0.8))
  • absence de guillemets autour des noms des animaux
  • une entrée manquante dans la colonne « feel » (probablement pour l’un des animaux à poils)
  • une virgule manquante dans la colonne du poids
Challenge

Défi :

Pouvez-vous prédire la classe de chacune des colonnes dans l’exemple suivant ?

Vérifiez vos conjectures à l’aide de str(country_climate) :

  • Sont-elles ce que vous attendiez ? Pourquoi ? Pourquoi pas ?

  • Réessayez en ajoutant stringsAsFactors = TRUE après la dernière variable lors de la création du tableau de données. Que se passe-t-il maintenant ? stringsAsFactors peut également être défini lors de la lecture de feuilles de calcul textuelles dans R à l’aide de read.csv().

R

country_climate <- data.frame(
       country = c("Canada", "Panama", "South Africa", "Australia"),
       climate = c("cold", "hot", "temperate", "hot/temperate"),
       temperature = c(10, 30, 18, "15"),
       northern_hemisphere = c(TRUE, TRUE, FALSE, "FALSE"),
       has_kangaroo = c(FALSE, FALSE, FALSE, 1)
       )

R

country_climate <- data.frame(
       country = c("Canada", "Panama", "South Africa", "Australia"),
       climate = c("cold", "hot", "temperate", "hot/temperate"),
       temperature = c(10, 30, 18, "15"),
       northern_hemisphere = c(TRUE, TRUE, FALSE, "FALSE"),
       has_kangaroo = c(FALSE, FALSE, FALSE, 1)
       )
str(country_climate)

OUTPUT

'data.frame':	4 obs. of  5 variables:
 $ country            : chr  "Canada" "Panama" "South Africa" "Australia"
 $ climate            : chr  "cold" "hot" "temperate" "hot/temperate"
 $ temperature        : chr  "10" "30" "18" "15"
 $ northern_hemisphere: chr  "TRUE" "TRUE" "FALSE" "FALSE"
 $ has_kangaroo       : num  0 0 0 1

La conversion automatique du type de données est parfois une chance, parfois une source de frustration. Sachez qu’elle existe, apprenez les règles et vérifiez à nouveau que les données que vous importez dans R sont du type correct au sein de votre tableau de données. Si ce n’est pas le cas, utilisez-la à votre avantage pour détecter des erreurs qui auraient pu être introduites lors de la saisie des données (par exemple, une lettre dans une colonne qui ne devrait contenir que des nombres).

En savoir plus dans ce tutoriel RStudio

Matrices


Avant de poursuivre, maintenant que nous avons découvert les tableaux de données, rappelons l’installation des packages et apprenons un nouveau type de données, à savoir le matrix. Comme le data.frame, une matrice possède deux dimensions : des lignes et des colonnes. Mais la différence majeure est que toutes les cellules d’une matrix doivent être du même type : numeric, character, logical, … À cet égard, les matrices sont plus proches d’un vector que d’un data.frame.

Le constructeur par défaut pour une matrice est matrix. Il prend un vecteur de valeurs pour remplir la matrice ainsi que le nombre de lignes et/ou de colonnes1. Les valeurs sont disposées colonne par colonne, comme illustré ci-dessous.

R

m <- matrix(1:9, ncol = 3, nrow = 3)
m

OUTPUT

     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
Challenge

Défi :

À l’aide de la fonction installed.packages(), créez une matrice character contenant les informations sur tous les packages actuellement installés sur votre ordinateur. Analysez-la.

R

## create the matrix
ip <- installed.packages()
head(ip)
## try also View(ip)
## number of package
nrow(ip)
## names of all installed packages
rownames(ip)
## type of information we have about each package
colnames(ip)

Il est souvent utile de créer de grandes matrices de données aléatoires pour servir de données de test. L’exercice ci-dessous vous demande de créer une telle matrice avec des données aléatoires tirées d’une distribution normale de moyenne 0 et d’écart-type 1, ce qui peut être réalisé avec la fonction rnorm().

Challenge

Défi :

Construisez une matrice de 1000 lignes et 3 colonnes contenant des données suivant une loi normale de moyenne 0 et d’écart-type 1.

R

set.seed(123)
m <- matrix(rnorm(3000), ncol = 3)
dim(m)

OUTPUT

[1] 1000    3

R

head(m)

OUTPUT

            [,1]        [,2]       [,3]
[1,] -0.56047565 -0.99579872 -0.5116037
[2,] -0.23017749 -1.03995504  0.2369379
[3,]  1.55870831 -0.01798024 -0.5415892
[4,]  0.07050839 -0.13217513  1.2192276
[5,]  0.12928774 -2.54934277  0.1741359
[6,]  1.71506499  1.04057346 -0.6152683

Mise en forme des dates


L’un des problèmes les plus fréquents rencontrés par les nouveaux utilisateurs de R (ainsi que par les utilisateurs expérimentés !) est la conversion des informations de date et d’heure en une variable appropriée et utilisable lors des analyses.

Note sur les dates dans les logiciels de feuilles de calcul

Les dates dans les feuilles de calcul sont généralement stockées dans une seule colonne. Bien que cela semble être la manière la plus naturelle de consigner les dates, il ne s’agit en réalité pas d’une bonne pratique. Une application de feuille de calcul affichera les dates d’une manière apparemment correcte (pour un observateur humain), mais la façon dont elle gère et stocke réellement les dates peut s’avérer problématique. Il est souvent bien plus sûr de stocker les dates avec l’ANNÉE, le MOIS et le JOUR dans des colonnes distinctes, ou sous la forme d’ANNÉE et de JOUR DE L’ANNÉE dans des colonnes distinctes.

Les logiciels de feuilles de calcul tels que LibreOffice, Microsoft Excel, OpenOffice, Gnumeric, … utilisent des méthodes d’encodage des dates différentes (et souvent incompatibles) (même au sein d’un même logiciel entre les versions et les systèmes d’exploitation). De plus, Excel peut convertir des éléments qui ne sont pas des dates en dates ( Zeeberg et al. (2004) ), par exemple des noms ou des identifiants tels que MAR1, DEC1, OCT4. Ainsi, si vous évitez globalement le format de date, il est plus facile d’identifier ces problèmes.

La section Dates as data de la leçon Data Carpentry apporte des informations complémentaires sur les pièges liés aux dates dans les feuilles de calcul.

Nous allons utiliser la fonction ymd() du package lubridate (qui appartient au tidyverse ; en savoir plus sur le site web de tidyverse). lubridate est installé dans le cadre de l’installation de tidyverse. Lorsque vous chargez tidyverse (library(tidyverse)), les packages principaux (les packages utilisés dans la plupart des analyses de données) sont chargés. lubridate ne fait cependant pas partie du tidyverse principal, vous devez donc le charger explicitement avec library(lubridate).

Commencez par charger le package requis :

R

library("lubridate")

ymd() prend en entrée un vecteur représentant l’année, le mois et le jour, et le convertit en vecteur Date. Date est une classe de données reconnue par R comme étant une date et peut être manipulée en tant que telle. L’argument requis par la fonction est flexible, mais, selon les bonnes pratiques, il s’agit d’un vecteur de caractères formaté sous la forme « YYYY-MM-DD ».

Créons un objet date et examinons sa structure :

R

my_date <- ymd("2015-01-01")
str(my_date)

OUTPUT

 Date[1:1], format: "2015-01-01"

Concaténons maintenant l’année, le mois et le jour fournis séparément : nous obtenons le même résultat.

R

# sep indicates the character to use to separate each component
my_date <- ymd(paste("2015", "1", "1", sep = "-"))
str(my_date)

OUTPUT

 Date[1:1], format: "2015-01-01"

Familiarisons-nous maintenant avec un pipeline typique de manipulation de dates. Le petit jeu de données ci-dessous contient des dates stockées dans des colonnes distinctes year, month et day.

R

x <- data.frame(year = c(1996, 1992, 1987, 1986, 2000, 1990, 2002, 1994, 1997, 1985),
                month = c(2,  3,  3, 10,  1,  8,  3,  4,  5,  5),
                day = c(24,  8,  1,  5,  8, 17, 13, 10, 11, 24),
                value = c(4,  5,  1,  9,  3,  8, 10,  2,  6,  7))
x

OUTPUT

   year month day value
1  1996     2  24     4
2  1992     3   8     5
3  1987     3   1     1
4  1986    10   5     9
5  2000     1   8     3
6  1990     8  17     8
7  2002     3  13    10
8  1994     4  10     2
9  1997     5  11     6
10 1985     5  24     7

Nous appliquons maintenant cette fonction au jeu de données x. Nous créons d’abord un vecteur de caractères à partir des colonnes year, month et day de x en utilisant paste() :

R

paste(x$year, x$month, x$day, sep = "-")

OUTPUT

 [1] "1996-2-24" "1992-3-8"  "1987-3-1"  "1986-10-5" "2000-1-8"  "1990-8-17"
 [7] "2002-3-13" "1994-4-10" "1997-5-11" "1985-5-24"

Ce vecteur de caractères peut être utilisé comme argument pour ymd() :

R

ymd(paste(x$year, x$month, x$day, sep = "-"))

OUTPUT

 [1] "1996-02-24" "1992-03-08" "1987-03-01" "1986-10-05" "2000-01-08"
 [6] "1990-08-17" "2002-03-13" "1994-04-10" "1997-05-11" "1985-05-24"

Le vecteur Date obtenu peut être ajouté à x sous la forme d’une nouvelle colonne appelée date :

R

x$date <- ymd(paste(x$year, x$month, x$day, sep = "-"))
str(x) # notice the new column, with 'date' as the class

OUTPUT

'data.frame':	10 obs. of  5 variables:
 $ year : num  1996 1992 1987 1986 2000 ...
 $ month: num  2 3 3 10 1 8 3 4 5 5
 $ day  : num  24 8 1 5 8 17 13 10 11 24
 $ value: num  4 5 1 9 3 8 10 2 6 7
 $ date : Date, format: "1996-02-24" "1992-03-08" ...

Vérifions que tout a bien fonctionné. L’un des moyens d’examiner la nouvelle colonne est d’utiliser summary() :

R

summary(x$date)

OUTPUT

        Min.      1st Qu.       Median         Mean      3rd Qu.         Max.
"1985-05-24" "1988-01-11" "1993-03-24" "1993-03-18" "1997-01-20" "2002-03-13" 

Notez que ymd() attend l’année, le mois et le jour, dans cet ordre. Si vous avez, par exemple, le jour, le mois et l’année, vous aurez besoin de dmy().

R

dmy(paste(x$day, x$month, x$year, sep = "-"))

OUTPUT

 [1] "1996-02-24" "1992-03-08" "1987-03-01" "1986-10-05" "2000-01-08"
 [6] "1990-08-17" "2002-03-13" "1994-04-10" "1997-05-11" "1985-05-24"

lubdridate dispose de nombreuses fonctions pour gérer toutes les variations de dates.

Résumé des objets R


Jusqu’à présent, nous avons vu plusieurs types d’objets R, différant par le nombre de dimensions et par le fait qu’ils pouvaient stocker un seul ou plusieurs types de données :

  • vector : une dimension (une longueur), un seul type de données.
  • matrix : deux dimensions, un seul type de données.
  • data.frame : deux dimensions, un type par colonne.

Listes


Les listes sont un type de données que nous n’avons pas encore vu, mais qu’il est utile de connaître et qui complète le résumé que nous venons de voir :

  • list : une dimension, chaque élément peut être d’un type de données différent.

Ci-dessous, créons une liste contenant un vecteur de nombres, des caractères, une matrice, un tableau de données et une autre liste :

R

l <- list(1:10, ## numeric
          letters, ## character
          installed.packages(), ## a matrix
          cars, ## a data.frame
          list(1, 2, 3)) ## a list
length(l)

OUTPUT

[1] 5

R

str(l)

OUTPUT

List of 5
 $ : int [1:10] 1 2 3 4 5 6 7 8 9 10
 $ : chr [1:26] "a" "b" "c" "d" ...
 $ : chr [1:190, 1:17] "abind" "askpass" "assertthat" "backports" ...
  ..- attr(*, "dimnames")=List of 2
  .. ..$ : chr [1:190] "abind" "askpass" "assertthat" "backports" ...
  .. ..$ : chr [1:17] "Package" "LibPath" "Version" "Priority" ...
 $ :'data.frame':	50 obs. of  2 variables:
  ..$ speed: num [1:50] 4 4 7 7 8 9 10 10 10 11 ...
  ..$ dist : num [1:50] 2 10 4 22 16 10 18 26 34 17 ...
 $ :List of 3
  ..$ : num 1
  ..$ : num 2
  ..$ : num 3

La sous-sélection de listes s’effectue à l’aide de [] pour créer une nouvelle sous-liste ou de [[]] pour extraire un seul élément de cette liste (en utilisant des indices ou des noms, si la liste est nommée).

R

l[[1]] ## first element

OUTPUT

 [1]  1  2  3  4  5  6  7  8  9 10

R

l[1:2] ## a list of length 2

OUTPUT

[[1]]
 [1]  1  2  3  4  5  6  7  8  9 10

[[2]]
 [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
[20] "t" "u" "v" "w" "x" "y" "z"

R

l[1]   ## a list of length 1

OUTPUT

[[1]]
 [1]  1  2  3  4  5  6  7  8  9 10

Exportation et sauvegarde de données tabulaires


Nous avons vu comment importer une feuille de calcul textuelle dans R à l’aide de la famille de fonctions read.table. Pour exporter un data.frame vers une feuille de calcul textuelle, nous pouvons utiliser l’ensemble de fonctions write.table (write.csv, write.delim, …). Elles prennent toutes en argument la variable à exporter et le fichier de destination. Par exemple, pour exporter les données rna vers le fichier my_rna.csv dans le répertoire data_output, nous exécuterions :

R

write.csv(rna, file = "data_output/my_rna.csv")

Ce nouveau fichier CSV peut désormais être partagé avec d’autres collaborateurs qui ne maîtrisent pas R. Notez que, bien qu’il y ait des virgules dans certains champs du data.frame (voir par exemple la colonne « product »), R entourera par défaut chaque champ de guillemets, et nous pourrons donc le lire correctement dans R, malgré l’utilisation également de virgules comme séparateurs de colonnes.

Key Points
  • Données tabulaires dans R
Zeeberg, Barry R., Joseph Riss, David W. Kane, et al. 2004. “Mistaken Identifiers: Gene Name Errors Can Be Introduced Inadvertently When Using Excel in Bioinformatics.” BMC Bioinformatics 5 (1): 80. https://doi.org/10.1186/1471-2105-5-80.

  1. Le nombre de lignes ou de colonnes suffit, car l’autre peut être déduit de la longueur des valeurs. Essayez de voir ce qui se passe si les valeurs et le nombre de lignes/colonnes ne correspondent pas.↩︎

Content from Manipulation et analyse de données avec dplyr


Last updated on 2026-11-07 | Edit this page

Overview

Questions

  • Analyse de données en R à l’aide du méta-package tidyverse

Objectives

  • Décrivez l’objectif des packages dplyr et tidyr.
  • Décrivez plusieurs de leurs fonctions extrêmement utiles pour manipuler les données.
  • Décrivez les concepts de format large et de format long, et voyez comment restructurer un tableau de données d’un format à l’autre.
  • Démontrer comment joindre des tables.

Cet épisode est basé sur la leçon Data Analysis and Visualisation in R for Ecologists de Data Carpentries.

Manipulation des données à l’aide de dplyr et tidyr


L’extraction de sous-ensembles à l’aide de crochets est pratique, mais elle peut s’avérer fastidieuse et difficile à lire, surtout pour des opérations complexes.

Certains packages peuvent grandement faciliter notre tâche lors de la manipulation de données. Les packages dans R sont essentiellement des ensembles de fonctions supplémentaires qui vous permettent d’en faire davantage. Les fonctions que nous avons utilisées jusqu’à présent, comme str() ou data.frame(), sont intégrées à R ; le chargement de packages peut vous donner accès à d’autres fonctions spécifiques. Avant d’utiliser un package pour la première fois, vous devez l’installer sur votre machine, puis vous devez l’importer à chaque session R ultérieure lorsque vous en avez besoin.

  • Le package dplyr propose des outils puissants pour les tâches de manipulation de données. Il est conçu pour fonctionner directement avec des tableaux de données, avec de nombreuses opérations de manipulation optimisées.

  • Comme nous le verrons plus loin, il arrive que nous souhaitions restructurer un tableau de données afin de pouvoir effectuer certaines analyses spécifiques ou pour la visualisation. Le package tidyr répond à ce problème courant de restructuration des données et propose des outils pour manipuler les données de manière ordonnée.

Pour en savoir plus sur dplyr et tidyr après l’atelier, vous souhaiterez peut-être consulter cette fiche pratique sur la transformation de données avec dplyr et celle-ci sur tidyr.

  • Le package tidyverse est un « package parapluie » qui installe plusieurs packages utiles pour l’analyse de données qui fonctionnent bien ensemble, tels que tidyr, dplyr, ggplot2, tibble, etc. Ces packages nous aident à travailler avec les données et à interagir avec elles. Ils nous permettent d’effectuer de nombreuses opérations sur vos données, telles que la sous-sélection, la transformation, la visualisation, etc.

Si vous avez effectué la configuration, vous devriez déjà avoir installé le package tidyverse. Vérifiez si vous l’avez en essayant de le charger depuis la bibliothèque :

R

## load the tidyverse packages, incl. dplyr
library("tidyverse")

Si vous avez reçu un message d’erreur there is no package called ‘tidyverse’, c’est que vous n’avez pas encore installé le package pour cette version de R. Pour installer le package tidyverse, saisissez :

R

BiocManager::install("tidyverse")

Si vous avez dû installer le package tidyverse, n’oubliez pas de le charger dans cette session R en utilisant la commande library() ci-dessus !

Chargement de données avec tidyverse


Au lieu de read.csv(), nous lirons nos données à l’aide de la fonction read_csv() (notez le _ au lieu du .), issue du package tidyverse readr.

R

rna <- read_csv("data/rnaseq.csv")

## view the data
rna

OUTPUT

# A tibble: 32,428 × 19
   gene    sample  expression organism   age sex   infection strain  time tissue
   <chr>   <chr>        <dbl> <chr>    <dbl> <chr> <chr>     <chr>  <dbl> <chr>
 1 Asl     GSM254…       1170 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 2 Apod    GSM254…      36194 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 3 Cyp2d22 GSM254…       4060 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 4 Klk6    GSM254…        287 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 5 Fcrls   GSM254…         85 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 6 Slc2a4  GSM254…        782 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 7 Exd2    GSM254…       1619 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 8 Gjc2    GSM254…        288 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 9 Plp1    GSM254…      43217 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
10 Gnb4    GSM254…       1071 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
# ℹ 32,418 more rows
# ℹ 9 more variables: mouse <dbl>, ENTREZID <dbl>, product <chr>,
#   ensembl_gene_id <chr>, external_synonym <chr>, chromosome_name <chr>,
#   gene_biotype <chr>, phenotype_description <chr>,
#   hsapiens_homolog_associated_gene_name <chr>

Notez que la classe des données est désormais appelée « tibble ».

Les tibbles modifient certains comportements des objets tableau de données que nous avons présentés précédemment. La structure de données est très similaire à celle d’un tableau de données. Pour nos besoins, les seules différences sont les suivantes :

  1. Il affiche le type de données de chaque colonne sous son nom. Notez que <dbl> est un type de données défini pour contenir des valeurs numériques avec des décimales.

  2. Il n’affiche que les premières lignes de données et seulement autant de colonnes que celles qui tiennent sur un écran.

Nous allons maintenant découvrir certaines des fonctions dplyr les plus courantes :

  • select() : sélectionner des colonnes
  • filter(): sélectionner des lignes selon des conditions
  • mutate(): créer de nouvelles colonnes en utilisant des informations provenant d’autres colonnes
  • group_by() et summarise() : créer des statistiques de synthèse sur des données regroupées
  • arrange() : trier les résultats
  • count() : compter les valeurs discrètes

Sélection de colonnes et filtrage de lignes


Pour sélectionner des colonnes d’un tableau de données, utilisez select(). Le premier argument de cette fonction est le tableau de données (rna), et les arguments suivants sont les colonnes à conserver.

R

select(rna, gene, sample, tissue, expression)

OUTPUT

# A tibble: 32,428 × 4
   gene    sample     tissue     expression
   <chr>   <chr>      <chr>           <dbl>
 1 Asl     GSM2545336 Cerebellum       1170
 2 Apod    GSM2545336 Cerebellum      36194
 3 Cyp2d22 GSM2545336 Cerebellum       4060
 4 Klk6    GSM2545336 Cerebellum        287
 5 Fcrls   GSM2545336 Cerebellum         85
 6 Slc2a4  GSM2545336 Cerebellum        782
 7 Exd2    GSM2545336 Cerebellum       1619
 8 Gjc2    GSM2545336 Cerebellum        288
 9 Plp1    GSM2545336 Cerebellum      43217
10 Gnb4    GSM2545336 Cerebellum       1071
# ℹ 32,418 more rows

Pour sélectionner toutes les colonnes sauf certaines, placez un « - » devant la variable pour l’exclure.

R

select(rna, -tissue, -organism)

OUTPUT

# A tibble: 32,428 × 17
   gene    sample   expression   age sex   infection strain  time mouse ENTREZID
   <chr>   <chr>         <dbl> <dbl> <chr> <chr>     <chr>  <dbl> <dbl>    <dbl>
 1 Asl     GSM2545…       1170     8 Fema… Influenz… C57BL…     8    14   109900
 2 Apod    GSM2545…      36194     8 Fema… Influenz… C57BL…     8    14    11815
 3 Cyp2d22 GSM2545…       4060     8 Fema… Influenz… C57BL…     8    14    56448
 4 Klk6    GSM2545…        287     8 Fema… Influenz… C57BL…     8    14    19144
 5 Fcrls   GSM2545…         85     8 Fema… Influenz… C57BL…     8    14    80891
 6 Slc2a4  GSM2545…        782     8 Fema… Influenz… C57BL…     8    14    20528
 7 Exd2    GSM2545…       1619     8 Fema… Influenz… C57BL…     8    14    97827
 8 Gjc2    GSM2545…        288     8 Fema… Influenz… C57BL…     8    14   118454
 9 Plp1    GSM2545…      43217     8 Fema… Influenz… C57BL…     8    14    18823
10 Gnb4    GSM2545…       1071     8 Fema… Influenz… C57BL…     8    14    14696
# ℹ 32,418 more rows
# ℹ 7 more variables: product <chr>, ensembl_gene_id <chr>,
#   external_synonym <chr>, chromosome_name <chr>, gene_biotype <chr>,
#   phenotype_description <chr>, hsapiens_homolog_associated_gene_name <chr>

Cela sélectionnera toutes les variables de rna, à l’exception de tissue et de organism.

Pour sélectionner des lignes en fonction d’un critère spécifique, utilisez filter() :

R

filter(rna, sex == "Male")

OUTPUT

# A tibble: 14,740 × 19
   gene    sample  expression organism   age sex   infection strain  time tissue
   <chr>   <chr>        <dbl> <chr>    <dbl> <chr> <chr>     <chr>  <dbl> <chr>
 1 Asl     GSM254…        626 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 2 Apod    GSM254…      13021 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 3 Cyp2d22 GSM254…       2171 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 4 Klk6    GSM254…        448 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 5 Fcrls   GSM254…        180 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 6 Slc2a4  GSM254…        313 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 7 Exd2    GSM254…       2366 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 8 Gjc2    GSM254…        310 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 9 Plp1    GSM254…      53126 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
10 Gnb4    GSM254…       1355 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
# ℹ 14,730 more rows
# ℹ 9 more variables: mouse <dbl>, ENTREZID <dbl>, product <chr>,
#   ensembl_gene_id <chr>, external_synonym <chr>, chromosome_name <chr>,
#   gene_biotype <chr>, phenotype_description <chr>,
#   hsapiens_homolog_associated_gene_name <chr>

R

filter(rna, sex == "Male" & infection == "NonInfected")

OUTPUT

# A tibble: 4,422 × 19
   gene    sample  expression organism   age sex   infection strain  time tissue
   <chr>   <chr>        <dbl> <chr>    <dbl> <chr> <chr>     <chr>  <dbl> <chr>
 1 Asl     GSM254…        535 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 2 Apod    GSM254…      13668 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 3 Cyp2d22 GSM254…       2008 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 4 Klk6    GSM254…       1101 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 5 Fcrls   GSM254…        375 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 6 Slc2a4  GSM254…        249 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 7 Exd2    GSM254…       3126 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 8 Gjc2    GSM254…        791 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 9 Plp1    GSM254…      98658 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
10 Gnb4    GSM254…       2437 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
# ℹ 4,412 more rows
# ℹ 9 more variables: mouse <dbl>, ENTREZID <dbl>, product <chr>,
#   ensembl_gene_id <chr>, external_synonym <chr>, chromosome_name <chr>,
#   gene_biotype <chr>, phenotype_description <chr>,
#   hsapiens_homolog_associated_gene_name <chr>

Imaginons maintenant que nous soyons intéressés par les homologues humains des gènes de souris analysés dans cet ensemble de données. Ces informations se trouvent dans la dernière colonne du tibble rna, nommée hsapiens_homolog_associated_gene_name. Pour les visualiser facilement, nous créerons un nouveau tableau contenant uniquement les 2 colonnes gene et hsapiens_homolog_associated_gene_name.

R

genes <- select(rna, gene, hsapiens_homolog_associated_gene_name)
genes

OUTPUT

# A tibble: 32,428 × 2
   gene    hsapiens_homolog_associated_gene_name
   <chr>   <chr>
 1 Asl     ASL
 2 Apod    APOD
 3 Cyp2d22 CYP2D6
 4 Klk6    KLK6
 5 Fcrls   FCRL2
 6 Slc2a4  SLC2A4
 7 Exd2    EXD2
 8 Gjc2    GJC2
 9 Plp1    PLP1
10 Gnb4    GNB4
# ℹ 32,418 more rows

Certains gènes de souris n’ont pas d’homologues humains. Ceux-ci peuvent être récupérés à l’aide de filter() et de la fonction is.na(), qui détermine si un élément est un NA.

R

filter(genes, is.na(hsapiens_homolog_associated_gene_name))

OUTPUT

# A tibble: 4,290 × 2
   gene     hsapiens_homolog_associated_gene_name
   <chr>    <chr>
 1 Prodh    <NA>
 2 Tssk5    <NA>
 3 Vmn2r1   <NA>
 4 Gm10654  <NA>
 5 Hexa     <NA>
 6 Sult1a1  <NA>
 7 Gm6277   <NA>
 8 Tmem198b <NA>
 9 Adam1a   <NA>
10 Ebp      <NA>
# ℹ 4,280 more rows

Si nous voulons ne conserver que les gènes de souris possédant un homologue humain, nous pouvons insérer un symbole « ! » qui nie le résultat ; nous demandons ainsi toutes les lignes pour lesquelles hsapiens_homolog_associated_gene_name n’est pas un NA.

R

filter(genes, !is.na(hsapiens_homolog_associated_gene_name))

OUTPUT

# A tibble: 28,138 × 2
   gene    hsapiens_homolog_associated_gene_name
   <chr>   <chr>
 1 Asl     ASL
 2 Apod    APOD
 3 Cyp2d22 CYP2D6
 4 Klk6    KLK6
 5 Fcrls   FCRL2
 6 Slc2a4  SLC2A4
 7 Exd2    EXD2
 8 Gjc2    GJC2
 9 Plp1    PLP1
10 Gnb4    GNB4
# ℹ 28,128 more rows

Pipes


Et si vous vouliez sélectionner et filtrer simultanément ? Il existe trois façons d’y parvenir : utiliser des étapes intermédiaires, des fonctions imbriquées ou des pipes.

Avec des étapes intermédiaires, vous créez un tableau de données temporaire et vous l’utilisez comme entrée pour la fonction suivante, comme ceci :

R

rna2 <- filter(rna, sex == "Male")
rna3 <- select(rna2, gene, sample, tissue, expression)
rna3

OUTPUT

# A tibble: 14,740 × 4
   gene    sample     tissue     expression
   <chr>   <chr>      <chr>           <dbl>
 1 Asl     GSM2545340 Cerebellum        626
 2 Apod    GSM2545340 Cerebellum      13021
 3 Cyp2d22 GSM2545340 Cerebellum       2171
 4 Klk6    GSM2545340 Cerebellum        448
 5 Fcrls   GSM2545340 Cerebellum        180
 6 Slc2a4  GSM2545340 Cerebellum        313
 7 Exd2    GSM2545340 Cerebellum       2366
 8 Gjc2    GSM2545340 Cerebellum        310
 9 Plp1    GSM2545340 Cerebellum      53126
10 Gnb4    GSM2545340 Cerebellum       1355
# ℹ 14,730 more rows

C’est lisible, mais cela peut encombrer votre espace de travail avec de nombreux objets intermédiaires que vous devez nommer individuellement. Avec plusieurs étapes, cela peut s’avérer difficile à suivre.

Vous pouvez également imbriquer des fonctions (c’est-à-dire une fonction à l’intérieur d’une autre), comme ceci :

R

rna3 <- select(filter(rna, sex == "Male"), gene, sample, tissue, expression)
rna3

OUTPUT

# A tibble: 14,740 × 4
   gene    sample     tissue     expression
   <chr>   <chr>      <chr>           <dbl>
 1 Asl     GSM2545340 Cerebellum        626
 2 Apod    GSM2545340 Cerebellum      13021
 3 Cyp2d22 GSM2545340 Cerebellum       2171
 4 Klk6    GSM2545340 Cerebellum        448
 5 Fcrls   GSM2545340 Cerebellum        180
 6 Slc2a4  GSM2545340 Cerebellum        313
 7 Exd2    GSM2545340 Cerebellum       2366
 8 Gjc2    GSM2545340 Cerebellum        310
 9 Plp1    GSM2545340 Cerebellum      53126
10 Gnb4    GSM2545340 Cerebellum       1355
# ℹ 14,730 more rows

C’est pratique, mais cela peut s’avérer difficile à lire si trop de fonctions sont imbriquées, car R évalue l’expression de l’intérieur vers l’extérieur (dans ce cas, le filtrage, puis la sélection).

La dernière option, les pipes, est un ajout récent à R. Les pipes permettent de prendre la sortie d’une fonction et de la transmettre directement à la suivante, ce qui est utile lorsque l’on doit effectuer plusieurs opérations sur le même jeu de données.

Les pipes dans R ressemblent à %>% (disponible via le package magrittr) ou à |> (via R de base). Si vous utilisez RStudio, vous pouvez saisir le pipe avec Ctrl + Shift + M si vous avez un PC, ou Cmd + Shift + M si vous avez un Mac.

Dans le code ci-dessus, nous utilisons le pipe pour envoyer d’abord le jeu de données rna via filter() afin de conserver les lignes où sex est Male, puis via select() pour ne conserver que les colonnes gene, sample, tissue et expression.

Le pipe |> prend l’objet à sa gauche et le transmet directement comme premier argument à la fonction à sa droite ; nous n’avons plus besoin d’inclure explicitement le tableau de données comme argument des fonctions filter() et select().

R

rna |>
  filter(sex == "Male") |>
  select(gene, sample, tissue, expression)

OUTPUT

# A tibble: 14,740 × 4
   gene    sample     tissue     expression
   <chr>   <chr>      <chr>           <dbl>
 1 Asl     GSM2545340 Cerebellum        626
 2 Apod    GSM2545340 Cerebellum      13021
 3 Cyp2d22 GSM2545340 Cerebellum       2171
 4 Klk6    GSM2545340 Cerebellum        448
 5 Fcrls   GSM2545340 Cerebellum        180
 6 Slc2a4  GSM2545340 Cerebellum        313
 7 Exd2    GSM2545340 Cerebellum       2366
 8 Gjc2    GSM2545340 Cerebellum        310
 9 Plp1    GSM2545340 Cerebellum      53126
10 Gnb4    GSM2545340 Cerebellum       1355
# ℹ 14,730 more rows

Certains trouvent utile de lire le pipe comme le mot « puis ». Par exemple, dans l’exemple ci-dessus, nous avons pris le tableau de données rna, puis filtré avec filter les lignes contenant sex == "Male", puis sélectionné avec select les colonnes gene, sample, tissue et expression.

Les fonctions dplyr sont en soi assez simples, mais en les combinant dans des flux de travail linéaires à l’aide du pipe, nous pouvons effectuer des manipulations plus complexes de tableaux de données.

Si nous souhaitons créer un nouvel objet avec cette version réduite des données, nous pouvons lui attribuer un nouveau nom :

R

rna3 <- rna |>
  filter(sex == "Male") |>
  select(gene, sample, tissue, expression)

rna3

OUTPUT

# A tibble: 14,740 × 4
   gene    sample     tissue     expression
   <chr>   <chr>      <chr>           <dbl>
 1 Asl     GSM2545340 Cerebellum        626
 2 Apod    GSM2545340 Cerebellum      13021
 3 Cyp2d22 GSM2545340 Cerebellum       2171
 4 Klk6    GSM2545340 Cerebellum        448
 5 Fcrls   GSM2545340 Cerebellum        180
 6 Slc2a4  GSM2545340 Cerebellum        313
 7 Exd2    GSM2545340 Cerebellum       2366
 8 Gjc2    GSM2545340 Cerebellum        310
 9 Plp1    GSM2545340 Cerebellum      53126
10 Gnb4    GSM2545340 Cerebellum       1355
# ℹ 14,730 more rows
Challenge

Défi :

À l’aide de pipes, sélectionnez les données rna pour conserver les observations de souris femelles au temps 0, pour lesquelles l’expression du gène est supérieure à 50000, et ne conservez que les colonnes gene, sample, time, expression et age.

R

rna |>
  filter(expression > 50000,
         sex == "Female",
         time == 0 ) |>
  select(gene, sample, time, expression, age)

OUTPUT

# A tibble: 9 × 5
  gene   sample      time expression   age
  <chr>  <chr>      <dbl>      <dbl> <dbl>
1 Plp1   GSM2545337     0     101241     8
2 Atp1b1 GSM2545337     0      53260     8
3 Plp1   GSM2545338     0      96534     8
4 Atp1b1 GSM2545338     0      50614     8
5 Plp1   GSM2545348     0     102790     8
6 Atp1b1 GSM2545348     0      59544     8
7 Plp1   GSM2545353     0      71237     8
8 Glul   GSM2545353     0      52451     8
9 Atp1b1 GSM2545353     0      61451     8

Créer ou modifier des colonnes (mutate)


Il vous arrivera souvent de vouloir créer de nouvelles colonnes à partir des valeurs de colonnes existantes, par exemple pour effectuer des conversions d’unités ou pour déterminer le rapport entre des valeurs dans deux colonnes. Pour ce faire, nous utiliserons mutate().

Pour créer une nouvelle colonne de temps en heures :

R

rna |>
  mutate(time_hours = time * 24) |>
  select(time, time_hours)

OUTPUT

# A tibble: 32,428 × 2
    time time_hours
   <dbl>      <dbl>
 1     8        192
 2     8        192
 3     8        192
 4     8        192
 5     8        192
 6     8        192
 7     8        192
 8     8        192
 9     8        192
10     8        192
# ℹ 32,418 more rows

Vous pouvez également créer une deuxième nouvelle colonne en fonction de la première nouvelle colonne au sein d’un même appel à mutate() :

R

rna |>
  mutate(time_hours = time * 24,
         time_mn = time_hours * 60) |>
  select(time, time_hours, time_mn)

OUTPUT

# A tibble: 32,428 × 3
    time time_hours time_mn
   <dbl>      <dbl>   <dbl>
 1     8        192   11520
 2     8        192   11520
 3     8        192   11520
 4     8        192   11520
 5     8        192   11520
 6     8        192   11520
 7     8        192   11520
 8     8        192   11520
 9     8        192   11520
10     8        192   11520
# ℹ 32,418 more rows
Challenge

Défi

Créez un nouveau tableau de données à partir des données rna qui répond aux critères suivants : il ne doit contenir que les colonnes gene, chromosome_name, phenotype_description, sample et expression. Les valeurs d’expression doivent être transformées par logarithme. Ce tableau de données ne doit contenir que des gènes situés sur les chromosomes sexuels, associés à un phenotype_description et présentant une expression logarithmique supérieure à 5.

Indice : réfléchissez à l’ordre des commandes pour générer ce tableau de données !

R

rna |>
  mutate(expression = log(expression)) |>
  select(gene, chromosome_name, phenotype_description, sample, expression) |>
  filter(chromosome_name == "X" | chromosome_name == "Y") |>
  filter(!is.na(phenotype_description)) |>
  filter(expression > 5)

OUTPUT

# A tibble: 649 × 5
   gene   chromosome_name phenotype_description                sample expression
   <chr>  <chr>           <chr>                                <chr>       <dbl>
 1 Plp1   X               abnormal CNS glial cell morphology   GSM25…      10.7
 2 Slc7a3 X               decreased body length                GSM25…       5.46
 3 Plxnb3 X               abnormal coat appearance             GSM25…       6.58
 4 Rbm3   X               abnormal liver morphology            GSM25…       9.32
 5 Cfp    X               abnormal cardiovascular system phys… GSM25…       6.18
 6 Ebp    X               abnormal embryonic erythrocyte morp… GSM25…       6.68
 7 Cd99l2 X               abnormal cellular extravasation      GSM25…       8.04
 8 Piga   X               abnormal brain development           GSM25…       6.06
 9 Pim2   X               decreased T cell proliferation       GSM25…       7.11
10 Itm2a  X               no abnormal phenotype detected       GSM25…       7.48
# ℹ 639 more rows

Analyse de données selon le principe « séparer, appliquer, combiner »


De nombreuses tâches d’analyse de données peuvent être abordées selon le paradigme split-apply-combine : diviser les données en groupes, appliquer une analyse à chaque groupe, puis combiner les résultats. dplyr rend cela très simple grâce à l’utilisation de la fonction group_by().

R

rna |>
  group_by(gene)

OUTPUT

# A tibble: 32,428 × 19
# Groups:   gene [1,474]
   gene    sample  expression organism   age sex   infection strain  time tissue
   <chr>   <chr>        <dbl> <chr>    <dbl> <chr> <chr>     <chr>  <dbl> <chr>
 1 Asl     GSM254…       1170 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 2 Apod    GSM254…      36194 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 3 Cyp2d22 GSM254…       4060 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 4 Klk6    GSM254…        287 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 5 Fcrls   GSM254…         85 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 6 Slc2a4  GSM254…        782 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 7 Exd2    GSM254…       1619 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 8 Gjc2    GSM254…        288 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 9 Plp1    GSM254…      43217 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
10 Gnb4    GSM254…       1071 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
# ℹ 32,418 more rows
# ℹ 9 more variables: mouse <dbl>, ENTREZID <dbl>, product <chr>,
#   ensembl_gene_id <chr>, external_synonym <chr>, chromosome_name <chr>,
#   gene_biotype <chr>, phenotype_description <chr>,
#   hsapiens_homolog_associated_gene_name <chr>

La fonction group_by() n’effectue aucun traitement des données ; elle les regroupe en sous-ensembles : dans l’exemple ci-dessus, notre tibble initial de 32428 observations est divisé en 1474 groupes en fonction de la variable gene.

Nous pourrions également décider de regrouper le tibble selon les échantillons :

R

rna |>
  group_by(sample)

OUTPUT

# A tibble: 32,428 × 19
# Groups:   sample [22]
   gene    sample  expression organism   age sex   infection strain  time tissue
   <chr>   <chr>        <dbl> <chr>    <dbl> <chr> <chr>     <chr>  <dbl> <chr>
 1 Asl     GSM254…       1170 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 2 Apod    GSM254…      36194 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 3 Cyp2d22 GSM254…       4060 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 4 Klk6    GSM254…        287 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 5 Fcrls   GSM254…         85 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 6 Slc2a4  GSM254…        782 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 7 Exd2    GSM254…       1619 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 8 Gjc2    GSM254…        288 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 9 Plp1    GSM254…      43217 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
10 Gnb4    GSM254…       1071 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
# ℹ 32,418 more rows
# ℹ 9 more variables: mouse <dbl>, ENTREZID <dbl>, product <chr>,
#   ensembl_gene_id <chr>, external_synonym <chr>, chromosome_name <chr>,
#   gene_biotype <chr>, phenotype_description <chr>,
#   hsapiens_homolog_associated_gene_name <chr>

Ici, notre ensemble initial tibble de 32428 observations est divisé en 22 groupes en fonction de la variable sample.

Une fois les données regroupées, les opérations suivantes s’appliqueront indépendamment à chaque groupe.

La fonction summarise()

group_by() est souvent utilisé avec summarise(), lequel condense chaque groupe en un résumé à une seule ligne pour ce groupe.

group_by() prend en arguments les noms de colonnes contenant les variables catégorielles pour lesquelles vous souhaitez calculer les statistiques de synthèse. Ainsi, pour calculer la moyenne expression par gène :

R

rna |>
  group_by(gene) |>
  summarise(mean_expression = mean(expression))

OUTPUT

# A tibble: 1,474 × 2
   gene     mean_expression
   <chr>              <dbl>
 1 AI504432         1053.
 2 AW046200          131.
 3 AW551984          295.
 4 Aamp             4751.
 5 Abca12              4.55
 6 Abcc8            2498.
 7 Abhd14a           525.
 8 Abi2             4909.
 9 Abi3bp           1002.
10 Abl2             2124.
# ℹ 1,464 more rows

Nous pourrions également vouloir calculer les niveaux d’expression moyens de tous les gènes dans chaque échantillon :

R

rna |>
  group_by(sample) |>
  summarise(mean_expression = mean(expression))

OUTPUT

# A tibble: 22 × 2
   sample     mean_expression
   <chr>                <dbl>
 1 GSM2545336           2062.
 2 GSM2545337           1766.
 3 GSM2545338           1668.
 4 GSM2545339           1696.
 5 GSM2545340           1682.
 6 GSM2545341           1638.
 7 GSM2545342           1594.
 8 GSM2545343           2107.
 9 GSM2545344           1712.
10 GSM2545345           1700.
# ℹ 12 more rows

Mais nous pouvons également regrouper par plusieurs colonnes :

R

rna |>
  group_by(gene, infection, time) |>
  summarise(mean_expression = mean(expression))

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene, infection, and time.
ℹ Output is grouped by gene and infection.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, infection, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

OUTPUT

# A tibble: 4,422 × 4
# Groups:   gene, infection [2,948]
   gene     infection    time mean_expression
   <chr>    <chr>       <dbl>           <dbl>
 1 AI504432 InfluenzaA      4           1104.
 2 AI504432 InfluenzaA      8           1014
 3 AI504432 NonInfected     0           1034.
 4 AW046200 InfluenzaA      4            152.
 5 AW046200 InfluenzaA      8             81
 6 AW046200 NonInfected     0            155.
 7 AW551984 InfluenzaA      4            302.
 8 AW551984 InfluenzaA      8            342.
 9 AW551984 NonInfected     0            238
10 Aamp     InfluenzaA      4           4870
# ℹ 4,412 more rows

Une fois les données regroupées, vous pouvez également résumer plusieurs variables simultanément (et pas nécessairement sur la même variable). Par exemple, nous pourrions ajouter une colonne indiquant la médiane de expression par gène et par condition :

R

rna |>
  group_by(gene, infection, time) |>
  summarise(mean_expression = mean(expression),
            median_expression = median(expression))

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene, infection, and time.
ℹ Output is grouped by gene and infection.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, infection, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

OUTPUT

# A tibble: 4,422 × 5
# Groups:   gene, infection [2,948]
   gene     infection    time mean_expression median_expression
   <chr>    <chr>       <dbl>           <dbl>             <dbl>
 1 AI504432 InfluenzaA      4           1104.             1094.
 2 AI504432 InfluenzaA      8           1014               985
 3 AI504432 NonInfected     0           1034.             1016
 4 AW046200 InfluenzaA      4            152.              144.
 5 AW046200 InfluenzaA      8             81                82
 6 AW046200 NonInfected     0            155.              163
 7 AW551984 InfluenzaA      4            302.              245
 8 AW551984 InfluenzaA      8            342.              287
 9 AW551984 NonInfected     0            238               265
10 Aamp     InfluenzaA      4           4870              4708
# ℹ 4,412 more rows
Challenge

Défi

Calculez le niveau d’expression moyen du gène « Dok3 » par points temporels.

R

rna |>
  filter(gene == "Dok3") |>
  group_by(time) |>
  summarise(mean = mean(expression))

OUTPUT

# A tibble: 3 × 2
   time  mean
  <dbl> <dbl>
1     0  169
2     4  156.
3     8   61 

Comptage

Lors du travail avec des données, nous souhaitons souvent connaître le nombre d’observations pour chaque facteur ou combinaison de facteurs. Pour cette tâche, dplyr propose count(). Par exemple, si nous voulions compter le nombre de lignes de données pour chaque échantillon infecté et non infecté, nous procéderions comme suit :

R

rna |>
    count(infection)

OUTPUT

# A tibble: 2 × 2
  infection       n
  <chr>       <int>
1 InfluenzaA  22110
2 NonInfected 10318

La fonction count() est une abréviation de ce que nous avons déjà vu : regrouper par variable, puis résumer en comptant le nombre d’observations dans ce groupe. En d’autres termes, rna |> count(infection) équivaut à :

R

rna |>
    group_by(infection) |>
    summarise(n = n())

OUTPUT

# A tibble: 2 × 2
  infection       n
  <chr>       <int>
1 InfluenzaA  22110
2 NonInfected 10318

L’exemple précédent montre l’utilisation de count() pour compter le nombre de lignes/observations pour un facteur (c’est-à-dire infection). Si nous voulions compter une combinaison de facteurs, telle que infection et time, nous spécifierions le premier et le second facteur comme arguments de count() :

R

rna |>
    count(infection, time)

OUTPUT

# A tibble: 3 × 3
  infection    time     n
  <chr>       <dbl> <int>
1 InfluenzaA      4 11792
2 InfluenzaA      8 10318
3 NonInfected     0 10318

ce qui équivaut à ceci :

R

rna |>
  group_by(infection, time) |>
  summarise(n = n())

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by infection and time.
ℹ Output is grouped by infection.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(infection, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

OUTPUT

# A tibble: 3 × 3
# Groups:   infection [2]
  infection    time     n
  <chr>       <dbl> <int>
1 InfluenzaA      4 11792
2 InfluenzaA      8 10318
3 NonInfected     0 10318

Il est parfois utile de trier le résultat pour faciliter les comparaisons. Nous pouvons utiliser arrange() pour trier le tableau. Par exemple, nous pourrions vouloir classer le tableau ci-dessus par temps :

R

rna |>
  count(infection, time) |>
  arrange(time)

OUTPUT

# A tibble: 3 × 3
  infection    time     n
  <chr>       <dbl> <int>
1 NonInfected     0 10318
2 InfluenzaA      4 11792
3 InfluenzaA      8 10318

ou par nombres :

R

rna |>
  count(infection, time) |>
  arrange(n)

OUTPUT

# A tibble: 3 × 3
  infection    time     n
  <chr>       <dbl> <int>
1 InfluenzaA      8 10318
2 NonInfected     0 10318
3 InfluenzaA      4 11792

Pour trier par ordre décroissant, nous devons ajouter la fonction desc() :

R

rna |>
  count(infection, time) |>
  arrange(desc(n))

OUTPUT

# A tibble: 3 × 3
  infection    time     n
  <chr>       <dbl> <int>
1 InfluenzaA      4 11792
2 InfluenzaA      8 10318
3 NonInfected     0 10318
Challenge

Défi

  1. Combien de gènes ont été analysés dans chaque échantillon ?
  2. Utilisez group_by() et summarise() pour évaluer la profondeur de séquençage (la somme de tous les comptages) dans chaque échantillon. Quel échantillon présente la profondeur de séquençage la plus élevée ?
  3. Choisissez un échantillon et évaluez le nombre de gènes par biotype.
  4. Identifiez les gènes associés à la description du phénotype « abnormal DNA methylation », et calculez leur expression moyenne (en log) aux moments 0, 4 et 8.

R

## 1.
rna |>
  count(sample)

OUTPUT

# A tibble: 22 × 2
   sample         n
   <chr>      <int>
 1 GSM2545336  1474
 2 GSM2545337  1474
 3 GSM2545338  1474
 4 GSM2545339  1474
 5 GSM2545340  1474
 6 GSM2545341  1474
 7 GSM2545342  1474
 8 GSM2545343  1474
 9 GSM2545344  1474
10 GSM2545345  1474
# ℹ 12 more rows

R

## 2.
rna |>
  group_by(sample) |>
  summarise(seq_depth = sum(expression)) |>
  arrange(desc(seq_depth))

OUTPUT

# A tibble: 22 × 2
   sample     seq_depth
   <chr>          <dbl>
 1 GSM2545350   3255566
 2 GSM2545352   3216163
 3 GSM2545343   3105652
 4 GSM2545336   3039671
 5 GSM2545380   3036098
 6 GSM2545353   2953249
 7 GSM2545348   2913678
 8 GSM2545362   2913517
 9 GSM2545351   2782464
10 GSM2545349   2758006
# ℹ 12 more rows

R

## 3.
rna |>
  filter(sample == "GSM2545336") |>
  count(gene_biotype) |>
  arrange(desc(n))

OUTPUT

# A tibble: 13 × 2
   gene_biotype                           n
   <chr>                              <int>
 1 protein_coding                      1321
 2 lncRNA                                69
 3 processed_pseudogene                  59
 4 miRNA                                  7
 5 snoRNA                                 5
 6 TEC                                    4
 7 polymorphic_pseudogene                 2
 8 unprocessed_pseudogene                 2
 9 IG_C_gene                              1
10 scaRNA                                 1
11 transcribed_processed_pseudogene       1
12 transcribed_unitary_pseudogene         1
13 transcribed_unprocessed_pseudogene     1

R

## 4.
rna |>
  filter(phenotype_description == "abnormal DNA methylation") |>
  group_by(gene, time) |>
  summarise(mean_expression = mean(log(expression))) |>
  arrange()

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene and time.
ℹ Output is grouped by gene.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

OUTPUT

# A tibble: 6 × 3
# Groups:   gene [2]
  gene   time mean_expression
  <chr> <dbl>           <dbl>
1 Xist      0            6.95
2 Xist      4            6.34
3 Xist      8            7.13
4 Zdbf2     0            6.27
5 Zdbf2     4            6.27
6 Zdbf2     8            6.19

Restructuration des données


Dans le tableau rna, les lignes contiennent des valeurs d’expression (l’unité) associées à une combinaison de 2 autres variables : gene et sample.

Toutes les autres colonnes correspondent à des variables décrivant soit l’échantillon (organisme, âge, sexe, …), soit le gène (gene_biotype, ENTREZ_ID, product, …). Les variables qui ne varient pas selon les gènes ou les échantillons auront la même valeur dans toutes les lignes.

R

rna |>
  arrange(gene)

OUTPUT

# A tibble: 32,428 × 19
   gene     sample expression organism   age sex   infection strain  time tissue
   <chr>    <chr>       <dbl> <chr>    <dbl> <chr> <chr>     <chr>  <dbl> <chr>
 1 AI504432 GSM25…       1230 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 2 AI504432 GSM25…       1085 Mus mus…     8 Fema… NonInfec… C57BL…     0 Cereb…
 3 AI504432 GSM25…        969 Mus mus…     8 Fema… NonInfec… C57BL…     0 Cereb…
 4 AI504432 GSM25…       1284 Mus mus…     8 Fema… Influenz… C57BL…     4 Cereb…
 5 AI504432 GSM25…        966 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
 6 AI504432 GSM25…        918 Mus mus…     8 Male  Influenz… C57BL…     8 Cereb…
 7 AI504432 GSM25…        985 Mus mus…     8 Fema… Influenz… C57BL…     8 Cereb…
 8 AI504432 GSM25…        972 Mus mus…     8 Male  NonInfec… C57BL…     0 Cereb…
 9 AI504432 GSM25…       1000 Mus mus…     8 Fema… Influenz… C57BL…     4 Cereb…
10 AI504432 GSM25…        816 Mus mus…     8 Male  Influenz… C57BL…     4 Cereb…
# ℹ 32,418 more rows
# ℹ 9 more variables: mouse <dbl>, ENTREZID <dbl>, product <chr>,
#   ensembl_gene_id <chr>, external_synonym <chr>, chromosome_name <chr>,
#   gene_biotype <chr>, phenotype_description <chr>,
#   hsapiens_homolog_associated_gene_name <chr>

Cette structure est appelée long-format, car une seule colonne contient toutes les valeurs, et une ou plusieurs autres colonnes décrivent le contexte de chaque valeur.

Dans certains cas, le long-format n’est pas vraiment « lisible par l’humain », et un autre format, le wide-format, est préféré, car il permet de représenter les données de manière plus compacte. C’est généralement le cas pour les valeurs d’expression génique, que les scientifiques ont l’habitude de consulter sous forme de matrices, où les lignes représentent les gènes et les colonnes les échantillons.

Dans ce format, il deviendrait donc simple d’explorer la relation entre les niveaux d’expression génique au sein des échantillons, ainsi qu’entre eux.

OUTPUT

# A tibble: 1,474 × 23
   gene    GSM2545336 GSM2545337 GSM2545338 GSM2545339 GSM2545340 GSM2545341
   <chr>        <dbl>      <dbl>      <dbl>      <dbl>      <dbl>      <dbl>
 1 Asl           1170        361        400        586        626        988
 2 Apod         36194      10347       9173      10620      13021      29594
 3 Cyp2d22       4060       1616       1603       1901       2171       3349
 4 Klk6           287        629        641        578        448        195
 5 Fcrls           85        233        244        237        180         38
 6 Slc2a4         782        231        248        265        313        786
 7 Exd2          1619       2288       2235       2513       2366       1359
 8 Gjc2           288        595        568        551        310        146
 9 Plp1         43217     101241      96534      58354      53126      27173
10 Gnb4          1071       1791       1867       1430       1355        798
# ℹ 1,464 more rows
# ℹ 16 more variables: GSM2545342 <dbl>, GSM2545343 <dbl>, GSM2545344 <dbl>,
#   GSM2545345 <dbl>, GSM2545346 <dbl>, GSM2545347 <dbl>, GSM2545348 <dbl>,
#   GSM2545349 <dbl>, GSM2545350 <dbl>, GSM2545351 <dbl>, GSM2545352 <dbl>,
#   GSM2545353 <dbl>, GSM2545354 <dbl>, GSM2545362 <dbl>, GSM2545363 <dbl>,
#   GSM2545380 <dbl>

Pour convertir les valeurs d’expression génique de rna en format large, nous devons créer un nouveau tableau où les valeurs de la colonne sample deviendraient les noms des variables de colonne.

Le point clé ici est que nous suivons toujours une structure de données ordonnée, mais que nous avons reformaté les données en fonction des observations d’intérêt : les niveaux d’expression par gène, au lieu de les enregistrer par gène et par échantillon.

La transformation inverse consisterait à transformer les noms de colonnes en valeurs d’une nouvelle variable.

Nous pouvons effectuer ces deux transformations à l’aide de deux fonctions tidyr, pivot_longer() et pivot_wider() (voir l’article sur les pivots sur le site web de tidyr pour plus de détails).

Conversion des données vers un format plus large

Sélectionnons les 3 premières colonnes de rna et utilisons pivot_wider() pour transformer les données en format large.

R

rna_exp <- rna |>
  select(gene, sample, expression)
rna_exp

OUTPUT

# A tibble: 32,428 × 3
   gene    sample     expression
   <chr>   <chr>           <dbl>
 1 Asl     GSM2545336       1170
 2 Apod    GSM2545336      36194
 3 Cyp2d22 GSM2545336       4060
 4 Klk6    GSM2545336        287
 5 Fcrls   GSM2545336         85
 6 Slc2a4  GSM2545336        782
 7 Exd2    GSM2545336       1619
 8 Gjc2    GSM2545336        288
 9 Plp1    GSM2545336      43217
10 Gnb4    GSM2545336       1071
# ℹ 32,418 more rows

pivot_wider prend trois arguments principaux :

  1. les données à transformer ;
  2. le names_from : la colonne dont les valeurs deviendront de nouveaux noms de colonnes ;
  3. le values_from : la colonne dont les valeurs rempliront les nouvelles colonnes.
Figure showing the long table format on the left and wide table format on the right and arrows illustrating how the values in the 'sample' column on the left have become column names on the right and how the values in the 'expression' column on the left have become values on the the right. Below is the call to 'pivot_wider()' with annotations pointing to the 'sample' and 'expression' function arguments.
Wide pivot of the rna data.

R

rna_wide <- rna_exp |>
  pivot_wider(names_from = sample,
              values_from = expression)
rna_wide

OUTPUT

# A tibble: 1,474 × 23
   gene    GSM2545336 GSM2545337 GSM2545338 GSM2545339 GSM2545340 GSM2545341
   <chr>        <dbl>      <dbl>      <dbl>      <dbl>      <dbl>      <dbl>
 1 Asl           1170        361        400        586        626        988
 2 Apod         36194      10347       9173      10620      13021      29594
 3 Cyp2d22       4060       1616       1603       1901       2171       3349
 4 Klk6           287        629        641        578        448        195
 5 Fcrls           85        233        244        237        180         38
 6 Slc2a4         782        231        248        265        313        786
 7 Exd2          1619       2288       2235       2513       2366       1359
 8 Gjc2           288        595        568        551        310        146
 9 Plp1         43217     101241      96534      58354      53126      27173
10 Gnb4          1071       1791       1867       1430       1355        798
# ℹ 1,464 more rows
# ℹ 16 more variables: GSM2545342 <dbl>, GSM2545343 <dbl>, GSM2545344 <dbl>,
#   GSM2545345 <dbl>, GSM2545346 <dbl>, GSM2545347 <dbl>, GSM2545348 <dbl>,
#   GSM2545349 <dbl>, GSM2545350 <dbl>, GSM2545351 <dbl>, GSM2545352 <dbl>,
#   GSM2545353 <dbl>, GSM2545354 <dbl>, GSM2545362 <dbl>, GSM2545363 <dbl>,
#   GSM2545380 <dbl>

Notez que, par défaut, la fonction pivot_wider() ajoutera NA pour les valeurs manquantes.

Imaginons que, pour une raison quelconque, nous ayons des valeurs d’expression manquantes pour certains gènes dans certains échantillons. Dans l’exemple fictif suivant, le gène Cyp2d22 ne possède qu’une seule valeur d’expression, dans l’échantillon GSM2545338.

R

rna_with_missing_values <- rna |>
  select(gene, sample, expression) |>
  filter(gene %in% c("Asl", "Apod", "Cyp2d22")) |>
  filter(sample %in% c("GSM2545336", "GSM2545337", "GSM2545338")) |>
  arrange(sample) |>
  filter(!(gene == "Cyp2d22" & sample != "GSM2545338"))
rna_with_missing_values

OUTPUT

# A tibble: 7 × 3
  gene    sample     expression
  <chr>   <chr>           <dbl>
1 Asl     GSM2545336       1170
2 Apod    GSM2545336      36194
3 Asl     GSM2545337        361
4 Apod    GSM2545337      10347
5 Asl     GSM2545338        400
6 Apod    GSM2545338       9173
7 Cyp2d22 GSM2545338       1603

Par défaut, la fonction pivot_wider() ajoute NA pour les valeurs manquantes. Cela peut être paramétré via l’argument values_fill de la fonction pivot_wider().

R

rna_with_missing_values |>
  pivot_wider(names_from = sample,
              values_from = expression)

OUTPUT

# A tibble: 3 × 4
  gene    GSM2545336 GSM2545337 GSM2545338
  <chr>        <dbl>      <dbl>      <dbl>
1 Asl           1170        361        400
2 Apod         36194      10347       9173
3 Cyp2d22         NA         NA       1603

R

rna_with_missing_values |>
  pivot_wider(names_from = sample,
              values_from = expression,
              values_fill = 0)

OUTPUT

# A tibble: 3 × 4
  gene    GSM2545336 GSM2545337 GSM2545338
  <chr>        <dbl>      <dbl>      <dbl>
1 Asl           1170        361        400
2 Apod         36194      10347       9173
3 Cyp2d22          0          0       1603

Conversion des données vers un format plus long

Dans le cas inverse, nous utilisons les noms de colonnes pour les transformer en une paire de nouvelles variables. L’une des variables représente les noms de colonnes sous forme de valeurs, et l’autre contient les valeurs précédemment associées aux noms de colonnes.

pivot_longer() prend quatre arguments principaux :

  1. les données à transformer ;
  2. le names_to : le nouveau nom de colonne que nous souhaitons créer et remplir avec les noms actuels des colonnes ;
  3. le values_to : le nouveau nom de colonne que nous souhaitons créer et remplir avec les valeurs actuelles ;
  4. les noms des colonnes à utiliser pour remplir les variables names_to et values_to (ou à supprimer).
Figure showing the long table format on the left and wide table format on the right and arrows illustrating how the column names on the left have become a new column 'sample' on the left and the values in the wide table on the right have become a new column 'expression' on the left.  Below is the call to 'pivot_wider()' with annotations pointing to the 'sample', 'expression' and the '-gene' arguments.
Long pivot of the rna data.

Pour recréer rna_long à partir de rna_wide, nous créerions une clé appelée sample et une valeur appelée expression, et utiliserions toutes les colonnes sauf gene pour la variable clé. Ici, nous supprimons la colonne gene avec un signe moins.

Notez comment les nouveaux noms de variables doivent être entourés de guillemets ici.

R

rna_long <- rna_wide |>
    pivot_longer(names_to = "sample",
                 values_to = "expression",
                 -gene)
rna_long

OUTPUT

# A tibble: 32,428 × 3
   gene  sample     expression
   <chr> <chr>           <dbl>
 1 Asl   GSM2545336       1170
 2 Asl   GSM2545337        361
 3 Asl   GSM2545338        400
 4 Asl   GSM2545339        586
 5 Asl   GSM2545340        626
 6 Asl   GSM2545341        988
 7 Asl   GSM2545342        836
 8 Asl   GSM2545343        535
 9 Asl   GSM2545344        586
10 Asl   GSM2545345        597
# ℹ 32,418 more rows

Nous aurions également pu utiliser une spécification pour déterminer les colonnes à inclure. Cela peut s’avérer utile si vous disposez d’un grand nombre de colonnes d’identification, et il est plus simple de spécifier ce qu’il faut récupérer que ce qu’il faut laisser de côté. Ici, la fonction starts_with() peut aider à récupérer les noms d’échantillons sans avoir à tous les énumérer ! Une autre possibilité serait d’utiliser l’opérateur : !

R

rna_wide |>
    pivot_longer(names_to = "sample",
                 values_to = "expression",
                 cols = starts_with("GSM"))

OUTPUT

# A tibble: 32,428 × 3
   gene  sample     expression
   <chr> <chr>           <dbl>
 1 Asl   GSM2545336       1170
 2 Asl   GSM2545337        361
 3 Asl   GSM2545338        400
 4 Asl   GSM2545339        586
 5 Asl   GSM2545340        626
 6 Asl   GSM2545341        988
 7 Asl   GSM2545342        836
 8 Asl   GSM2545343        535
 9 Asl   GSM2545344        586
10 Asl   GSM2545345        597
# ℹ 32,418 more rows

R

rna_wide |>
    pivot_longer(names_to = "sample",
                 values_to = "expression",
                 GSM2545336:GSM2545380)

OUTPUT

# A tibble: 32,428 × 3
   gene  sample     expression
   <chr> <chr>           <dbl>
 1 Asl   GSM2545336       1170
 2 Asl   GSM2545337        361
 3 Asl   GSM2545338        400
 4 Asl   GSM2545339        586
 5 Asl   GSM2545340        626
 6 Asl   GSM2545341        988
 7 Asl   GSM2545342        836
 8 Asl   GSM2545343        535
 9 Asl   GSM2545344        586
10 Asl   GSM2545345        597
# ℹ 32,418 more rows

Notez que si nous avions des valeurs manquantes dans le format large, le NA serait inclus dans le nouveau format long.

Rappelons notre tibble fictif précédent contenant des valeurs manquantes :

R

rna_with_missing_values

OUTPUT

# A tibble: 7 × 3
  gene    sample     expression
  <chr>   <chr>           <dbl>
1 Asl     GSM2545336       1170
2 Apod    GSM2545336      36194
3 Asl     GSM2545337        361
4 Apod    GSM2545337      10347
5 Asl     GSM2545338        400
6 Apod    GSM2545338       9173
7 Cyp2d22 GSM2545338       1603

R

wide_with_NA <- rna_with_missing_values |>
  pivot_wider(names_from = sample,
              values_from = expression)
wide_with_NA

OUTPUT

# A tibble: 3 × 4
  gene    GSM2545336 GSM2545337 GSM2545338
  <chr>        <dbl>      <dbl>      <dbl>
1 Asl           1170        361        400
2 Apod         36194      10347       9173
3 Cyp2d22         NA         NA       1603

R

wide_with_NA |>
    pivot_longer(names_to = "sample",
                 values_to = "expression",
                 -gene)

OUTPUT

# A tibble: 9 × 3
  gene    sample     expression
  <chr>   <chr>           <dbl>
1 Asl     GSM2545336       1170
2 Asl     GSM2545337        361
3 Asl     GSM2545338        400
4 Apod    GSM2545336      36194
5 Apod    GSM2545337      10347
6 Apod    GSM2545338       9173
7 Cyp2d22 GSM2545336         NA
8 Cyp2d22 GSM2545337         NA
9 Cyp2d22 GSM2545338       1603

Le passage aux formats large et long peut être un moyen utile d’équilibrer un jeu de données afin que chaque réplicat ait la même composition.

Challenge

Question

À partir du tableau rna, utilisez la fonction pivot_wider() pour créer un tableau au format large présentant les niveaux d’expression génique dans chaque souris. Ensuite, utilisez la fonction pivot_longer() pour restaurer un tableau au format long.

R

rna1 <- rna |>
select(gene, mouse, expression) |>
pivot_wider(names_from = mouse, values_from = expression)
rna1

OUTPUT

# A tibble: 1,474 × 23
   gene     `14`    `9`  `10`  `15`  `18`   `6`   `5`  `11`  `22`  `13`  `23`
   <chr>   <dbl>  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1 Asl      1170    361   400   586   626   988   836   535   586   597   938
 2 Apod    36194  10347  9173 10620 13021 29594 24959 13668 13230 15868 27769
 3 Cyp2d22  4060   1616  1603  1901  2171  3349  3122  2008  2254  2277  2985
 4 Klk6      287    629   641   578   448   195   186  1101   537   567   327
 5 Fcrls      85    233   244   237   180    38    68   375   199   177    89
 6 Slc2a4    782    231   248   265   313   786   528   249   266   357   654
 7 Exd2     1619   2288  2235  2513  2366  1359  1474  3126  2379  2173  1531
 8 Gjc2      288    595   568   551   310   146   186   791   454   370   240
 9 Plp1    43217 101241 96534 58354 53126 27173 28728 98658 61356 61647 38019
10 Gnb4     1071   1791  1867  1430  1355   798   806  2437  1394  1554   960
# ℹ 1,464 more rows
# ℹ 11 more variables: `24` <dbl>, `8` <dbl>, `7` <dbl>, `1` <dbl>, `16` <dbl>,
#   `21` <dbl>, `4` <dbl>, `2` <dbl>, `20` <dbl>, `12` <dbl>, `19` <dbl>

R

rna1 |>
pivot_longer(names_to = "mouse_id", values_to = "counts", -gene)

OUTPUT

# A tibble: 32,428 × 3
   gene  mouse_id counts
   <chr> <chr>     <dbl>
 1 Asl   14         1170
 2 Asl   9           361
 3 Asl   10          400
 4 Asl   15          586
 5 Asl   18          626
 6 Asl   6           988
 7 Asl   5           836
 8 Asl   11          535
 9 Asl   22          586
10 Asl   13          597
# ℹ 32,418 more rows
Challenge

Question

Extrayez les gènes situés sur les chromosomes X et Y du tableau de données rna et étalez le tableau de données avec sex comme colonnes, chromosome_name comme lignes, et la moyenne de l’expression des gènes situés sur chaque chromosome comme valeurs, comme dans le tibble suivant :

A two by two table with  X and Y row names and Female and Male column names showing the total counts for each X/Y and Female/Male combination. The Y/Female combinations shows 3 counts, while all other counts are above 2000 counts.

Vous devrez effectuer un résumé avant de restructurer !

Calculons d’abord le niveau d’expression moyen des gènes liés aux chromosomes X et Y dans les échantillons provenant de souris mâles et femelles…

R

 rna |>
  filter(chromosome_name == "Y" | chromosome_name == "X") |>
  group_by(sex, chromosome_name) |>
  summarise(mean = mean(expression))

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by sex and chromosome_name.
ℹ Output is grouped by sex.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(sex, chromosome_name))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

OUTPUT

# A tibble: 4 × 3
# Groups:   sex [2]
  sex    chromosome_name  mean
  <chr>  <chr>           <dbl>
1 Female X               3504.
2 Female Y                  3
3 Male   X               2497.
4 Male   Y               2117.

Et pivoter la table au format large

R

rna_1 <- rna |>
  filter(chromosome_name == "Y" | chromosome_name == "X") |>
  group_by(sex, chromosome_name) |>
  summarise(mean = mean(expression)) |>
  pivot_wider(names_from = sex,
              values_from = mean)

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by sex and chromosome_name.
ℹ Output is grouped by sex.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(sex, chromosome_name))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

R

rna_1

OUTPUT

# A tibble: 2 × 3
  chromosome_name Female  Male
  <chr>            <dbl> <dbl>
1 X                3504. 2497.
2 Y                   3  2117.

Prenez maintenant ce tableau de données et transformez-le avec pivot_longer() afin que chaque ligne représente une combinaison unique chromosome_name par gender.

R

rna_1 |>
  pivot_longer(names_to = "gender",
               values_to = "mean",
               -chromosome_name)

OUTPUT

# A tibble: 4 × 3
  chromosome_name gender  mean
  <chr>           <chr>  <dbl>
1 X               Female 3504.
2 X               Male   2497.
3 Y               Female    3
4 Y               Male   2117.
Challenge

Question

Utilisez le jeu de données rna pour créer une matrice d’expression où chaque ligne représente les niveaux d’expression moyens des gènes et chaque colonne représente les différents moments temporels.

Calculons d’abord l’expression moyenne par gène et par moment

R

rna |>
  group_by(gene, time) |>
  summarise(mean_exp = mean(expression))

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene and time.
ℹ Output is grouped by gene.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

OUTPUT

# A tibble: 4,422 × 3
# Groups:   gene [1,474]
   gene      time mean_exp
   <chr>    <dbl>    <dbl>
 1 AI504432     0    1034.
 2 AI504432     4    1104.
 3 AI504432     8    1014
 4 AW046200     0     155.
 5 AW046200     4     152.
 6 AW046200     8      81
 7 AW551984     0     238
 8 AW551984     4     302.
 9 AW551984     8     342.
10 Aamp         0    4603.
# ℹ 4,412 more rows

avant d’utiliser la fonction pivot_wider()

R

rna_time <- rna |>
  group_by(gene, time) |>
  summarise(mean_exp = mean(expression)) |>
  pivot_wider(names_from = time,
              values_from = mean_exp)

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene and time.
ℹ Output is grouped by gene.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

R

rna_time

OUTPUT

# A tibble: 1,474 × 4
# Groups:   gene [1,474]
   gene         `0`     `4`     `8`
   <chr>      <dbl>   <dbl>   <dbl>
 1 AI504432 1034.   1104.   1014
 2 AW046200  155.    152.     81
 3 AW551984  238     302.    342.
 4 Aamp     4603.   4870    4763.
 5 Abca12      5.29    4.25    4.14
 6 Abcc8    2576.   2609.   2292.
 7 Abhd14a   591.    547.    432.
 8 Abi2     4881.   4903.   4945.
 9 Abi3bp   1175.   1061.    762.
10 Abl2     2170.   2078.   2131.
# ℹ 1,464 more rows

Notez que cela génère un tibble dont certains noms de colonnes commencent par un chiffre. Si nous voulions sélectionner la colonne correspondant aux temps, nous ne pourrions pas utiliser les noms de colonnes directement… Que se passe-t-il lorsque nous sélectionnons la colonne 4 ?

R

rna |>
  group_by(gene, time) |>
  summarise(mean_exp = mean(expression)) |>
  pivot_wider(names_from = time,
              values_from = mean_exp) |>
  select(gene, 4)

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene and time.
ℹ Output is grouped by gene.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

OUTPUT

# A tibble: 1,474 × 2
# Groups:   gene [1,474]
   gene         `8`
   <chr>      <dbl>
 1 AI504432 1014
 2 AW046200   81
 3 AW551984  342.
 4 Aamp     4763.
 5 Abca12      4.14
 6 Abcc8    2292.
 7 Abhd14a   432.
 8 Abi2     4945.
 9 Abi3bp    762.
10 Abl2     2131.
# ℹ 1,464 more rows

Pour sélectionner le temps 4, nous devrions entourer le nom de la colonne d’accents graves « ` ».

R

rna |>
  group_by(gene, time) |>
  summarise(mean_exp = mean(expression)) |>
  pivot_wider(names_from = time,
              values_from = mean_exp) |>
  select(gene, `4`)

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene and time.
ℹ Output is grouped by gene.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

OUTPUT

# A tibble: 1,474 × 2
# Groups:   gene [1,474]
   gene         `4`
   <chr>      <dbl>
 1 AI504432 1104.
 2 AW046200  152.
 3 AW551984  302.
 4 Aamp     4870
 5 Abca12      4.25
 6 Abcc8    2609.
 7 Abhd14a   547.
 8 Abi2     4903.
 9 Abi3bp   1061.
10 Abl2     2078.
# ℹ 1,464 more rows

Une autre possibilité consisterait à renommer la colonne, en choisissant un nom qui ne commence pas par un chiffre :

R

rna |>
  group_by(gene, time) |>
  summarise(mean_exp = mean(expression)) |>
  pivot_wider(names_from = time,
              values_from = mean_exp) |>
  rename("time0" = `0`, "time4" = `4`, "time8" = `8`) |>
  select(gene, time4)

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene and time.
ℹ Output is grouped by gene.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

OUTPUT

# A tibble: 1,474 × 2
# Groups:   gene [1,474]
   gene       time4
   <chr>      <dbl>
 1 AI504432 1104.
 2 AW046200  152.
 3 AW551984  302.
 4 Aamp     4870
 5 Abca12      4.25
 6 Abcc8    2609.
 7 Abhd14a   547.
 8 Abi2     4903.
 9 Abi3bp   1061.
10 Abl2     2078.
# ℹ 1,464 more rows
Challenge

Question

Utilisez le tableau de données précédent contenant les niveaux d’expression moyens par temps et créez une nouvelle colonne contenant les rapports d’expression (fold changes) entre le temps 8 et le temps 0, ainsi qu’entre le temps 8 et le temps 4. Convertissez ce tableau au format long en rassemblant les rapports d’expression calculés.

À partir du tibble rna_time :

R

rna_time

OUTPUT

# A tibble: 1,474 × 4
# Groups:   gene [1,474]
   gene         `0`     `4`     `8`
   <chr>      <dbl>   <dbl>   <dbl>
 1 AI504432 1034.   1104.   1014
 2 AW046200  155.    152.     81
 3 AW551984  238     302.    342.
 4 Aamp     4603.   4870    4763.
 5 Abca12      5.29    4.25    4.14
 6 Abcc8    2576.   2609.   2292.
 7 Abhd14a   591.    547.    432.
 8 Abi2     4881.   4903.   4945.
 9 Abi3bp   1175.   1061.    762.
10 Abl2     2170.   2078.   2131.
# ℹ 1,464 more rows

Calculez les rapports d’expression (fold changes) :

R

rna_time |>
  mutate(time_8_vs_0 = `8` / `0`, time_8_vs_4 = `8` / `4`)

OUTPUT

# A tibble: 1,474 × 6
# Groups:   gene [1,474]
   gene         `0`     `4`     `8` time_8_vs_0 time_8_vs_4
   <chr>      <dbl>   <dbl>   <dbl>       <dbl>       <dbl>
 1 AI504432 1034.   1104.   1014          0.981       0.918
 2 AW046200  155.    152.     81          0.522       0.532
 3 AW551984  238     302.    342.         1.44        1.13
 4 Aamp     4603.   4870    4763.         1.03        0.978
 5 Abca12      5.29    4.25    4.14       0.784       0.975
 6 Abcc8    2576.   2609.   2292.         0.889       0.878
 7 Abhd14a   591.    547.    432.         0.731       0.791
 8 Abi2     4881.   4903.   4945.         1.01        1.01
 9 Abi3bp   1175.   1061.    762.         0.649       0.719
10 Abl2     2170.   2078.   2131.         0.982       1.03
# ℹ 1,464 more rows

Et utilisez la fonction pivot_longer() :

R

rna_time |>
  mutate(time_8_vs_0 = `8` / `0`, time_8_vs_4 = `8` / `4`) |>
  pivot_longer(names_to = "comparisons",
               values_to = "Fold_changes",
               time_8_vs_0:time_8_vs_4)

OUTPUT

# A tibble: 2,948 × 6
# Groups:   gene [1,474]
   gene         `0`     `4`     `8` comparisons Fold_changes
   <chr>      <dbl>   <dbl>   <dbl> <chr>              <dbl>
 1 AI504432 1034.   1104.   1014    time_8_vs_0        0.981
 2 AI504432 1034.   1104.   1014    time_8_vs_4        0.918
 3 AW046200  155.    152.     81    time_8_vs_0        0.522
 4 AW046200  155.    152.     81    time_8_vs_4        0.532
 5 AW551984  238     302.    342.   time_8_vs_0        1.44
 6 AW551984  238     302.    342.   time_8_vs_4        1.13
 7 Aamp     4603.   4870    4763.   time_8_vs_0        1.03
 8 Aamp     4603.   4870    4763.   time_8_vs_4        0.978
 9 Abca12      5.29    4.25    4.14 time_8_vs_0        0.784
10 Abca12      5.29    4.25    4.14 time_8_vs_4        0.975
# ℹ 2,938 more rows

Jointure de tableaux


Dans de nombreuses situations concrètes, les données sont réparties sur plusieurs tables. Cela se produit généralement parce que différents types d’informations sont recueillis à partir de sources distinctes.

Pour certaines analyses, il peut être souhaitable de combiner les données de deux tables ou plus dans un seul tableau de données, en s’appuyant sur une colonne commune à toutes les tables.

Le package dplyr propose un ensemble de fonctions de jointure permettant de combiner deux tableaux de données en fonction de correspondances dans des colonnes spécifiées. Nous présentons ici une brève introduction aux jointures. Pour en savoir plus, veuillez vous référer au chapitre sur les jointures de tableaux. La fiche pratique sur la transformation des données propose également un bref aperçu des jointures de tableaux.

Nous allons illustrer la jointure à l’aide d’un petit tableau, rna_mini, que nous créerons en extrayant un sous-ensemble du tableau d’origine rna, en ne gardant que 3 colonnes et 10 lignes.

R

rna_mini <- rna |>
   select(gene, sample, expression) |>
   head(10)
rna_mini

OUTPUT

# A tibble: 10 × 3
   gene    sample     expression
   <chr>   <chr>           <dbl>
 1 Asl     GSM2545336       1170
 2 Apod    GSM2545336      36194
 3 Cyp2d22 GSM2545336       4060
 4 Klk6    GSM2545336        287
 5 Fcrls   GSM2545336         85
 6 Slc2a4  GSM2545336        782
 7 Exd2    GSM2545336       1619
 8 Gjc2    GSM2545336        288
 9 Plp1    GSM2545336      43217
10 Gnb4    GSM2545336       1071

La deuxième table, annot1, contient 2 colonnes, gene et gene_description. Vous pouvez soit télécharger annot1.csv en cliquant sur le lien puis en le déplaçant dans le dossier data/, soit utiliser le code R ci-dessous pour le télécharger directement dans le dossier.

R

download.file(url = "https://carpentries-incubator.github.io/bioc-intro/data/annot1.csv",
              destfile = "data/annot1.csv")
annot1 <- read_csv(file = "data/annot1.csv")
annot1

OUTPUT

# A tibble: 10 × 2
   gene    gene_description
   <chr>   <chr>
 1 Cyp2d22 cytochrome P450, family 2, subfamily d, polypeptide 22 [Source:MGI S…
 2 Klk6    kallikrein related-peptidase 6 [Source:MGI Symbol;Acc:MGI:1343166]
 3 Fcrls   Fc receptor-like S, scavenger receptor [Source:MGI Symbol;Acc:MGI:19…
 4 Plp1    proteolipid protein (myelin) 1 [Source:MGI Symbol;Acc:MGI:97623]
 5 Exd2    exonuclease 3'-5' domain containing 2 [Source:MGI Symbol;Acc:MGI:192…
 6 Apod    apolipoprotein D [Source:MGI Symbol;Acc:MGI:88056]
 7 Gnb4    guanine nucleotide binding protein (G protein), beta 4 [Source:MGI S…
 8 Slc2a4  solute carrier family 2 (facilitated glucose transporter), member 4 …
 9 Asl     argininosuccinate lyase [Source:MGI Symbol;Acc:MGI:88084]
10 Gjc2    gap junction protein, gamma 2 [Source:MGI Symbol;Acc:MGI:2153060]    

Nous souhaitons maintenant joindre ces deux tables en une seule contenant toutes les variables à l’aide de la fonction full_join() du package dplyr. La fonction trouvera automatiquement la variable commune pour faire correspondre les colonnes de la première et de la seconde table. Dans ce cas, gene est la variable commune. De telles variables sont appelées clés. Les clés sont utilisées pour faire correspondre des observations à travers différentes tables.

R

full_join(rna_mini, annot1)

OUTPUT

Joining with `by = join_by(gene)`

OUTPUT

# A tibble: 10 × 4
   gene    sample     expression gene_description
   <chr>   <chr>           <dbl> <chr>
 1 Asl     GSM2545336       1170 argininosuccinate lyase [Source:MGI Symbol;Acc…
 2 Apod    GSM2545336      36194 apolipoprotein D [Source:MGI Symbol;Acc:MGI:88…
 3 Cyp2d22 GSM2545336       4060 cytochrome P450, family 2, subfamily d, polype…
 4 Klk6    GSM2545336        287 kallikrein related-peptidase 6 [Source:MGI Sym…
 5 Fcrls   GSM2545336         85 Fc receptor-like S, scavenger receptor [Source…
 6 Slc2a4  GSM2545336        782 solute carrier family 2 (facilitated glucose t…
 7 Exd2    GSM2545336       1619 exonuclease 3'-5' domain containing 2 [Source:…
 8 Gjc2    GSM2545336        288 gap junction protein, gamma 2 [Source:MGI Symb…
 9 Plp1    GSM2545336      43217 proteolipid protein (myelin) 1 [Source:MGI Sym…
10 Gnb4    GSM2545336       1071 guanine nucleotide binding protein (G protein)…

En pratique, les annotations géniques sont parfois étiquetées de manière différente.

Le tableau annot2 est exactement identique au tableau annot1, sauf que la variable contenant les noms de gènes est nommée différemment. Encore une fois, vous pouvez soit télécharger annot2.csv vous-même et le déplacer dans data/, soit utiliser le code R ci-dessous.

R

download.file(url = "https://carpentries-incubator.github.io/bioc-intro/data/annot2.csv",
              destfile = "data/annot2.csv")
annot2 <- read_csv(file = "data/annot2.csv")
annot2

OUTPUT

# A tibble: 10 × 2
   external_gene_name description
   <chr>              <chr>
 1 Cyp2d22            cytochrome P450, family 2, subfamily d, polypeptide 22 [S…
 2 Klk6               kallikrein related-peptidase 6 [Source:MGI Symbol;Acc:MGI…
 3 Fcrls              Fc receptor-like S, scavenger receptor [Source:MGI Symbol…
 4 Plp1               proteolipid protein (myelin) 1 [Source:MGI Symbol;Acc:MGI…
 5 Exd2               exonuclease 3'-5' domain containing 2 [Source:MGI Symbol;…
 6 Apod               apolipoprotein D [Source:MGI Symbol;Acc:MGI:88056]
 7 Gnb4               guanine nucleotide binding protein (G protein), beta 4 [S…
 8 Slc2a4             solute carrier family 2 (facilitated glucose transporter)…
 9 Asl                argininosuccinate lyase [Source:MGI Symbol;Acc:MGI:88084]
10 Gjc2               gap junction protein, gamma 2 [Source:MGI Symbol;Acc:MGI:…

Si aucun des noms de variables ne correspond, nous pouvons définir manuellement les variables à utiliser pour le rapprochement. Ces variables peuvent être définies à l’aide de l’argument by, comme illustré ci-dessous avec les tables rna_mini et annot2.

R

full_join(rna_mini, annot2, by = c("gene" = "external_gene_name"))

OUTPUT

# A tibble: 10 × 4
   gene    sample     expression description
   <chr>   <chr>           <dbl> <chr>
 1 Asl     GSM2545336       1170 argininosuccinate lyase [Source:MGI Symbol;Acc…
 2 Apod    GSM2545336      36194 apolipoprotein D [Source:MGI Symbol;Acc:MGI:88…
 3 Cyp2d22 GSM2545336       4060 cytochrome P450, family 2, subfamily d, polype…
 4 Klk6    GSM2545336        287 kallikrein related-peptidase 6 [Source:MGI Sym…
 5 Fcrls   GSM2545336         85 Fc receptor-like S, scavenger receptor [Source…
 6 Slc2a4  GSM2545336        782 solute carrier family 2 (facilitated glucose t…
 7 Exd2    GSM2545336       1619 exonuclease 3'-5' domain containing 2 [Source:…
 8 Gjc2    GSM2545336        288 gap junction protein, gamma 2 [Source:MGI Symb…
 9 Plp1    GSM2545336      43217 proteolipid protein (myelin) 1 [Source:MGI Sym…
10 Gnb4    GSM2545336       1071 guanine nucleotide binding protein (G protein)…

Comme on peut le voir ci-dessus, le nom de la variable de la première table est conservé dans celle qui a été jointe.

Challenge

Défi :

Téléchargez le tableau annot3 en cliquant sur ce lien et placez le tableau dans votre répertoire data/. À l’aide de la fonction full_join(), joignez les tableaux rna_mini et annot3. Qu’est-il arrivé aux gènes Klk6, mt-Tf, mt-Rnr1, mt-Tv, mt-Rnr2 et mt-Tl1 ?

R

annot3 <- read_csv("data/annot3.csv")
full_join(rna_mini, annot3)

OUTPUT

# A tibble: 15 × 4
   gene    sample     expression gene_description
   <chr>   <chr>           <dbl> <chr>
 1 Asl     GSM2545336       1170 argininosuccinate lyase [Source:MGI Symbol;Acc…
 2 Apod    GSM2545336      36194 apolipoprotein D [Source:MGI Symbol;Acc:MGI:88…
 3 Cyp2d22 GSM2545336       4060 cytochrome P450, family 2, subfamily d, polype…
 4 Klk6    GSM2545336        287 <NA>
 5 Fcrls   GSM2545336         85 Fc receptor-like S, scavenger receptor [Source…
 6 Slc2a4  GSM2545336        782 solute carrier family 2 (facilitated glucose t…
 7 Exd2    GSM2545336       1619 exonuclease 3'-5' domain containing 2 [Source:…
 8 Gjc2    GSM2545336        288 gap junction protein, gamma 2 [Source:MGI Symb…
 9 Plp1    GSM2545336      43217 proteolipid protein (myelin) 1 [Source:MGI Sym…
10 Gnb4    GSM2545336       1071 guanine nucleotide binding protein (G protein)…
11 mt-Tf   <NA>               NA mitochondrially encoded tRNA phenylalanine [So…
12 mt-Rnr1 <NA>               NA mitochondrially encoded 12S rRNA [Source:MGI S…
13 mt-Tv   <NA>               NA mitochondrially encoded tRNA valine [Source:MG…
14 mt-Rnr2 <NA>               NA mitochondrially encoded 16S rRNA [Source:MGI S…
15 mt-Tl1  <NA>               NA mitochondrially encoded tRNA leucine 1 [Source…

Le gène Klk6 n’est présent que dans rna_mini, tandis que les gènes mt-Tf, mt-Rnr1, mt-Tv, mt-Rnr2 et mt-Tl1 ne figurent que dans le tableau annot3. Leurs valeurs respectives pour les variables du tableau ont été codées comme manquantes.

Exportation de données


Maintenant que vous avez appris à utiliser dplyr pour extraire des informations de vos données brutes ou les résumer, vous souhaiterez peut-être exporter ces nouveaux jeux de données pour les partager avec vos collaborateurs ou pour les archiver.

À l’instar de la fonction read_csv() utilisée pour lire des fichiers CSV dans R, il existe une fonction write_csv() qui génère des fichiers CSV à partir de tableaux de données.

Avant d’utiliser write_csv(), nous allons créer un nouveau dossier, data_output, dans notre répertoire de travail pour y stocker cet ensemble de données généré. Nous ne voulons pas écrire les ensembles de données générés dans le même répertoire que nos données brutes. Il est bon de les garder séparés. Le dossier data ne doit contenir que les données brutes et non modifiées, et doit rester intouché pour s’assurer que nous ne le supprimons ni ne le modifions. En revanche, notre script générera le contenu du répertoire data_output, de sorte que même si les fichiers qu’il contient sont supprimés, nous pourrons toujours les régénérer.

Utilisons write_csv() pour enregistrer le tableau rna_wide que nous avons créé précédemment.

R

write_csv(rna_wide, file = "data_output/rna_wide.csv")
Key Points
  • Données tabulaires en R à l’aide du méta-package tidyverse

Content from Visualisation des données


Last updated on 2026-11-07 | Edit this page

Overview

Questions

  • Visualisation dans R

Objectives

  • Créer des nuages de points, des boîtes à moustaches, des graphiques en courbes, etc., à l’aide de ggplot.
  • Définir les paramètres globaux des graphiques.
  • Décrire le facettage et l’appliquer dans ggplot.
  • Modifier l’aspect visuel d’un graphique ggplot existant (y compris les libellés d’axes et la couleur).
  • Créer des graphiques complexes et personnalisés à partir de données contenues dans un tableau de données.

Cet épisode est basé sur la leçon Data Analysis and Visualisation in R for Ecologists de Data Carpentries.

Visualisation des données


Nous commençons par charger les packages nécessaires. ggplot2 est inclus dans le package tidyverse.

R

library("tidyverse")

Si les données enregistrées lors de la leçon précédente ne sont plus présentes dans l’espace de travail, chargez-les.

R

rna <- read.csv("data/rnaseq.csv")

La fiche pratique de visualisation de données couvrira les bases et les fonctionnalités plus avancées de ggplot2, et permettra, en plus de servir de rappel, d’obtenir un aperçu des nombreuses représentations de données disponibles dans le package. Les tutoriels vidéo suivants (partie 1 et partie 2) de Thomas Lin Pedersen sont également très instructifs.

Graphiques avec ggplot2


ggplot2 est une bibliothèque de graphisme qui permet de créer facilement des graphiques complexes à partir de données contenues dans un tableau de données. Elle offre une interface plus programmatique pour spécifier les variables à tracer, la manière dont elles sont affichées ainsi que les propriétés visuelles générales. Le fondement théorique qui sous-tend ggplot2 est la Grammar of Graphics ( Wilkinson (2005) ). En utilisant cette approche, nous n’avons besoin que de modifications minimales si les données sous-jacentes changent ou si nous décidons de passer d’un graphique en barres à un graphique à dispersion. Cela permet de créer des graphiques de qualité publication avec un minimum d’ajustements et de peaufinage.

Il existe un ouvrage sur ggplot2 ( Wickham (2016) ) qui offre un bon aperçu, mais il est obsolète. La 3e édition est en préparation et sera disponible gratuitement en ligne. La page web ggplot2 (https://ggplot2.tidyverse.org) propose une documentation complète.

ggplot2 fonctionne avec des données au format « long », c’est-à-dire une colonne pour chaque dimension et une ligne pour chaque observation. Des données bien structurées vous feront gagner beaucoup de temps lors de la création de figures avec ggplot2.

Les graphiques ggplot sont construits étape par étape en ajoutant de nouveaux éléments. L’ajout de couches de cette manière permet une grande flexibilité et une personnalisation approfondie des graphiques.

Le principe de la Grammaire des graphiques est que l’on peut construire tout graphique à partir des mêmes 3 composants : (1) un jeu de données, (2) un système de coordonnées et (3) des geoms — c’est-à-dire des marques visuelles qui représentent des points de données 1

Pour créer un ggplot, nous utiliserons le modèle de base suivant, applicable à différents types de graphiques :

ggplot(data = <DATA>, mapping = aes(<MAPPINGS>)) +  <GEOM_FUNCTION>()
  • utilisez la fonction ggplot() et liez le graphique à un tableau de données spécifique à l’aide de l’argument data

R

ggplot(data = rna)
  • définissez une correspondance (avec la fonction esthétique (aes)), en sélectionnant les variables à tracer et en précisant comment les représenter dans le graphique, par exemple par les positions x/y ou par des caractéristiques telles que la taille, la forme, la couleur, etc.

R

ggplot(data = rna, mapping = aes(x = expression))
  • ajoutez des « geoms » — géométries, ou représentations graphiques des données dans le graphique (points, lignes, barres). ggplot2 propose de nombreuses geoms différentes ; nous utiliserons aujourd’hui quelques-unes des plus courantes, notamment :

    * `geom_point()` for scatter plots, dot plots, etc.
    * `geom_histogram()` for histograms
    * `geom_boxplot()` for, well, boxplots!
    * `geom_line()` for trend lines, time series, etc.

Pour ajouter un geom(etry) au graphique, utilisez l’opérateur +. Utilisons d’abord geom_histogram() :

R

ggplot(data = rna, mapping = aes(x = expression)) +
  geom_histogram()

OUTPUT

`stat_bin()` using `bins = 30`. Pick better value `binwidth`.
Default histogram produced by ggplot() and geom_histogram() for the expression data.

Le + du package ggplot2 est particulièrement utile car il permet de modifier des objets ggplot existants. Cela signifie que vous pouvez facilement configurer des modèles de graphiques et explorer commodément différents types de graphiques ; ainsi, le graphique ci-dessus peut également être généré avec un code comme celui-ci :

R

# Assign plot to a variable
rna_plot <- ggplot(data = rna,
                   mapping = aes(x = expression))

# Draw the plot
rna_plot + geom_histogram()
Challenge

Défi

Vous avez probablement remarqué un message automatique qui s’affiche lors du tracé de l’histogramme :

OUTPUT

`stat_bin()` using `bins = 30`. Pick better value `binwidth`.

Modifiez les arguments bins ou binwidth de geom_histogram() pour modifier le nombre ou la largeur des intervalles.

R

# change bins
ggplot(rna, aes(x = expression)) +
    geom_histogram(bins = 15)
Histograms produced by ggplot() and geom_histogram() for the expression data with bin set of 15 (top) and binwith set to 2000 (bottom).

R

# change binwidth
ggplot(rna, aes(x = expression)) +
    geom_histogram(binwidth = 2000)
Histograms produced by ggplot() and geom_histogram() for the expression data with bin set of 15 (top) and binwith set to 2000 (bottom).

On constate ici que les données sont asymétriques vers la droite. Nous pouvons appliquer une transformation logarithmique en base 2 pour obtenir une distribution plus symétrique. Notons que nous ajoutons ici une petite valeur constante (+1) afin d’éviter que des valeurs -Inf ne soient renvoyées pour des valeurs d’expression égales à 0.

R

rna <- rna |>
  mutate(expression_log = log2(expression + 1))

Si nous traçons maintenant l’histogramme des expressions transformées en logarithme en base 2, la distribution est effectivement plus proche d’une distribution normale.

R

ggplot(rna, aes(x = expression_log)) + geom_histogram()

OUTPUT

`stat_bin()` using `bins = 30`. Pick better value `binwidth`.
Histogram produced by ggplot() and geom_histogram() for the pre-computed log of expression.

Désormais, nous travaillerons sur les valeurs d’expression transformées par logarithme.

Challenge

Défi

Une autre façon de visualiser cette transformation consiste à examiner l’échelle des observations. Par exemple, il peut être utile de modifier l’échelle de l’axe afin de mieux répartir les observations dans l’espace du graphique. La modification de l’échelle des axes s’effectue de la même manière que l’ajout ou la modification d’autres composants (c’est-à-dire en ajoutant des commandes progressivement). Essayez d’effectuer cette modification :

  • Représentez l’expression non transformée à l’échelle log10 ; voir scale_x_log10(). Comparez-la au graphique précédent. Pourquoi des messages d’avertissement s’affichent-ils désormais ?

R

ggplot(data = rna,mapping = aes(x = expression))+
  geom_histogram() +
  scale_x_log10()

WARNING

Warning in scale_x_log10(): log-10 transformation introduced infinite values.

OUTPUT

`stat_bin()` using `bins = 30`. Pick better value `binwidth`.

WARNING

Warning: Removed 507 rows containing non-finite outside the scale range
(`stat_bin()`).
Histogram produced by ggplot(), geom_histogram() and scale_x_log10() for the log of expression.

Notes

  • Tout ce que vous insérez dans la fonction ggplot() est visible par toutes les couches geom que vous ajoutez (c’est-à-dire qu’il s’agit de paramètres de tracé globaux). Cela inclut la correspondance des axes x et y que vous configurez dans aes().
  • Vous pouvez également spécifier des correspondances pour un geom donné, indépendamment des correspondances définies globalement dans la fonction ggplot().
  • Le signe + utilisé pour ajouter de nouvelles couches doit être placé à la fin de la ligne contenant la couche précédente. Si, en revanche, le signe + est ajouté au début de la ligne contenant la nouvelle couche, ggplot2 n’ajoutera pas la nouvelle couche et renvoiera un message d’erreur.

R

# This is the correct syntax for adding layers
rna_plot +
  geom_histogram()

# This will not add the new layer and will return an error message
rna_plot
  + geom_histogram()

Création itérative de vos graphiques


Nous allons maintenant tracer un nuage de points avec deux variables continues et la fonction geom_point(). Ce graphique représentera les log2 des rapports d’expression (log2 fold changes), en comparant le temps 8 au temps 0 et le temps 4 au temps 0. Pour cela, nous devons d’abord calculer les moyennes des valeurs d’expression transformées en log2, par gène et par temps. Nous calculons ensuite les log2 des rapports d’expression en soustrayant la moyenne au temps 0 de celle au temps 8, puis de celle au temps 4. Notez que nous incluons également le biotype des gènes, que nous utiliserons plus tard pour représenter les gènes. Nous enregistrerons ces log2 des rapports d’expression dans un nouveau tableau de données appelé rna_fc..

R

rna_fc <- rna |> select(gene, time,
                         gene_biotype, expression_log) |>
  group_by(gene, time, gene_biotype) |>
  summarize(mean_exp = mean(expression_log)) |>
  pivot_wider(names_from = time,
              values_from = mean_exp) |>
  mutate(time_8_vs_0 = `8` - `0`, time_4_vs_0 = `4` - `0`)

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene, time, and gene_biotype.
ℹ Output is grouped by gene and time.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time, gene_biotype))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

Nous pouvons ensuite créer un ggplot avec le jeu de données rna_fc nouvellement créé. La création de graphiques avec ggplot2 est généralement un processus itératif. Nous commençons par définir le jeu de données que nous utiliserons, disposer les axes et choisir un geom :

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_point()
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. All dots are black.

Ensuite, nous commençons à modifier ce graphique pour en extraire davantage d’informations. Par exemple, nous pouvons ajouter de la transparence (alpha) afin d’éviter la superposition des points :

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_point(alpha = 0.3)
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. All dots are semi-transparent black.

Nous pouvons également ajouter des couleurs pour tous les points :

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_point(alpha = 0.3, color = "blue")
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. All dots are semi-transparent blue.

Ou encore, pour colorer chaque gène du graphique différemment, vous pourriez utiliser un vecteur comme entrée pour l’argument color. ggplot2 fournira une couleur différente correspondant à différentes valeurs du vecteur. Voici un exemple où nous colorions avec gene_biotype :

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_point(alpha = 0.3, aes(color = gene_biotype))
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. Dots are colour-coded based on the gene's biotype.

Nous pouvons également spécifier les couleurs directement au sein de la correspondance fournie dans la fonction ggplot(). Celles-ci seront prises en compte par toutes les couches geom, et la correspondance sera déterminée par les axes x et y configurés dans aes().

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0,
                                color = gene_biotype)) +
  geom_point(alpha = 0.3)
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. Dots are colour-coded based on the gene's biotype.

Enfin, nous pourrions également ajouter une ligne diagonale avec la fonction geom_abline() :

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0,
                                color = gene_biotype)) +
  geom_point(alpha = 0.3) +
  geom_abline(intercept = 0)
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. Dots are colour-coded based on the gene's biotype. A black line of slope 1 crossing the origin was added by geom_abline().

Notons que nous pouvons modifier la couche geom de geom_point à geom_jitter et que les couleurs resteront déterminées par gene_biotype.

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0,
                                color = gene_biotype)) +
  geom_jitter(alpha = 0.3) +
  geom_abline(intercept = 0)
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. Dots are colour-coded based on the gene's biotype. A black line of slope 1 crossing the origin was added by geom_abline().
Challenge

Défi

Les nuages de points peuvent être des outils exploratoires utiles pour de petits jeux de données. Pour les jeux de données comportant un grand nombre d’observations, comme le jeu de données rna_fc, la superposition des points peut constituer une limite. Une stratégie pour gérer de tels cas consiste à regrouper les observations dans des cellules hexagonales. L’espace du graphique est pavé d’hexagones. Une couleur est attribuée à chaque hexagone en fonction du nombre d’observations qu’il contient.

  • Pour regrouper les observations dans des cellules hexagonales avec ggplot2, installez d’abord le package R hexbin depuis CRAN et chargez-le.

  • Utilisez ensuite la fonction geom_hex() pour générer la figure hexbin.

  • Quels sont les avantages et les inconvénients d’un graphique à cellules hexagonales par rapport à un nuage de points ? Examinez le nuage de points ci-dessus et comparez-le au graphique à cellules hexagonales que vous avez créé.

R

install.packages("hexbin")

R

library("hexbin")

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_hex() +
  geom_abline(intercept = 0)
Scatter plot produced by ggplot() and geom_hexbin() comparing the log-foldchanges computed above shows hexagons coloured based on the underlying dot density. A black line of slope 1 crossing the origin was added by geom_abline().
Challenge

Défi

Utilisez ce que vous venez d’apprendre pour créer un graphique de dispersion de expression_log en fonction de sample à partir du jeu de données rna, en affichant le temps dans différentes couleurs. Est-ce un bon moyen de présenter ce type de données ?

R

ggplot(data = rna, mapping = aes(y = expression_log, x = sample)) +
    geom_point(aes(color = time))
Figures showing a stretch of overlapping points indicating the log of expression + 1 for each sample. The points are coloured with different shades of blue for samples collected at different time points.

Diagramme en boîtes


Nous pouvons utiliser des boîtes à moustaches pour visualiser la distribution des expressions géniques au sein de chaque échantillon :

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_boxplot()
Boxplot showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). Each boxplot is filled with white colour.

En ajoutant des points au graphique en boîtes, nous pouvons mieux appréhender le nombre de mesures et leur répartition :

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_jitter(alpha = 0.2, color = "tomato") +
  geom_boxplot(alpha = 0)
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). Each boxplot is transparent and the jittered dots are semi-transparent tomato-coloured and behind the boxpots.
Challenge

Défi

Remarquez que la couche du boxplot se trouve devant la couche du jitter. Que faut-il modifier dans le code pour placer le boxplot sous les points ?

Nous devrions inverser l’ordre de ces deux geoms :

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_boxplot(alpha = 0) +
  geom_jitter(alpha = 0.2, color = "tomato")
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). Each boxplot is transparent and the jittered dots are semi-transparent tomato-coloured. This time, the boxplots are behind the dots.

Vous remarquerez peut-être que les valeurs sur l’axe des abscisses sont toujours mal lisibles. Modifions l’orientation des étiquettes et ajustons-les verticalement et horizontalement pour qu’elles ne se chevauchent pas. Vous pouvez utiliser un angle de 90 degrés, ou expérimenter pour trouver l’angle approprié pour des étiquettes orientées en diagonale :

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_jitter(alpha = 0.2, color = "tomato") +
  geom_boxplot(alpha = 0) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). Each boxplot is transparent and the jittered dots are semi-transparent tomato-coloured. The sample labels are displayed vertically and readable.
Challenge

Défi

Ajoutez de la couleur aux points de votre graphique en boîtes en fonction de la durée de l’infection (time).

Indice : Vérifiez la classe de time. Envisagez de modifier la classe de time, passant de nombre entier à facteur, directement dans la correspondance ggplot. Pourquoi ce changement modifie-t-il la façon dont R crée le graphique ?

R

# time as integer
ggplot(data = rna,
         mapping = aes(y = expression_log,
                       x = sample)) +
  geom_jitter(alpha = 0.2, aes(color = time)) +
  geom_boxplot(alpha = 0) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). On the first figure, each boxplot is transparent and the jittered dots are semi-transparent and coloured in different shares of blue. On the second figures, each boxplot is transparent and the jittered dots are semi-transparent and coloured red, green and blue.

R

# time as factor
ggplot(data = rna,
         mapping = aes(y = expression_log,
                       x = sample)) +
  geom_jitter(alpha = 0.2, aes(color = as.factor(time))) +
  geom_boxplot(alpha = 0) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). On the first figure, each boxplot is transparent and the jittered dots are semi-transparent and coloured in different shares of blue. On the second figures, each boxplot is transparent and the jittered dots are semi-transparent and coloured red, green and blue.
Challenge

Défi

Les boîtes à moustaches sont des résumés utiles, mais masquent la forme de la distribution. Par exemple, si la distribution est bimodale, nous ne la verrions pas dans une boîte à moustaches. Une alternative à la boîte à moustaches est le graphique en violon, où la forme (de la densité des points) est tracée.

  • Remplacez le graphique en boîtes par un graphique en violons ; voir geom_violin(). Remplissez les violons en fonction du temps à l’aide de l’argument fill.

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_violin(aes(fill = as.factor(time))) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Violin plot showing the distribution of log expression + 1 values for each sample, as produced by geom_violin(). Each boxplot is transparent and the jittered dots are semi-transparent and coloured red, green and blue.
Challenge

Défi

  • Modifiez le graphique en violons pour remplir les violons par sex.

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_violin(aes(fill = sex)) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Violin plot showing the distribution of log expression + 1 values for each sample, as produced by geom_violon(). Each violin plot is coloured in red or blue depending on the sex variable.

Graphiques en courbes


Calculons l’expression moyenne par durée d’infection pour les 10 gènes présentant les log2 des rapports d’expression les plus élevés entre le temps 8 et le temps 0. Tout d’abord, nous devons sélectionner les gènes et créer un sous-ensemble de rna appelé sub_rna contenant les 10 gènes sélectionnés, puis regrouper les données et calculer l’expression génique moyenne au sein de chaque groupe :

R

rna_fc <- rna_fc |> arrange(desc(time_8_vs_0))

genes_selected <- rna_fc$gene[1:10]

sub_rna <- rna |>
    filter(gene %in% genes_selected)

mean_exp_by_time <- sub_rna |>
  group_by(gene,time) |>
    summarize(mean_exp = mean(expression_log))

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene and time.
ℹ Output is grouped by gene.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

R

mean_exp_by_time

OUTPUT

# A tibble: 30 × 3
# Groups:   gene [10]
   gene   time mean_exp
   <chr> <int>    <dbl>
 1 Acr       0     5.07
 2 Acr       4     5.54
 3 Acr       8     7.31
 4 Aipl1     0     3.70
 5 Aipl1     4     3.89
 6 Aipl1     8     6.56
 7 Bst1      0     3.20
 8 Bst1      4     3.77
 9 Bst1      8     5.22
10 Chil3     0     4.00
# ℹ 20 more rows

Nous pouvons créer le graphique en courbes avec la durée de l’infection sur l’axe des abscisses et l’expression moyenne sur l’axe des ordonnées :

R

ggplot(data = mean_exp_by_time, mapping = aes(x = time, y = mean_exp)) +
  geom_line()
Line plot, as produced by geom_line(), but the lines are clearly not show what we expect.

Malheureusement, cela ne fonctionne pas car nous avons tracé les données de tous les gènes ensemble. Nous devons indiquer à ggplot de tracer une ligne pour chaque gène en modifiant la fonction esthétique pour y inclure group = gene :

R

ggplot(data = mean_exp_by_time,
       mapping = aes(x = time, y = mean_exp, group = gene)) +
  geom_line()
Line plot, as produced by geom_line(), with 10 lines showing increasing expression values over time.

Nous pourrons distinguer les gènes dans le graphique si nous ajoutons des couleurs (l’utilisation de color regroupe également automatiquement les données) :

R

ggplot(data = mean_exp_by_time,
       mapping = aes(x = time, y = mean_exp, color = gene)) +
  geom_line()
Line plot, as produced by geom_line(), with 10 colour-coded lines showing increasing expression values over time.

Facettage


ggplot2 dispose d’une technique appelée facettage qui permet de diviser un graphique en plusieurs sous-graphiques selon un facteur du jeu de données. Ces différents sous-graphiques héritent des mêmes propriétés (limites des axes, graduations, etc.) afin de faciliter leur comparaison directe. Nous l’utiliserons pour créer un graphique en courbes au fil du temps pour chaque gène :

R

ggplot(data = mean_exp_by_time,
       mapping = aes(x = time, y = mean_exp)) + geom_line() +
  facet_wrap(~ gene)
Line plot, as produced by geom_line(), with 10 sub-plots/facets, each showing one line with increasing expression values over time. All y-scales are identical.

Ici, les axes x et y ont tous deux la même échelle pour tous les sous-graphiques. Vous pouvez modifier ce comportement par défaut en modifiant scales afin de permettre une échelle libre pour l’axe y :

R

ggplot(data = mean_exp_by_time,
       mapping = aes(x = time, y = mean_exp)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y")
Line plot, as produced by geom_line(), with 10 sub-plots/facets, each showing one line with increasing expression values over time. y-scales are now adapted to the expression range for each facet/gene.

Nous souhaitons maintenant séparer la ligne dans chaque graphique selon le sexe des souris. Pour ce faire, nous devons calculer l’expression moyenne dans le tableau de données, regroupé par gene, time et sex :

R

mean_exp_by_time_sex <- sub_rna |>
  group_by(gene, time, sex) |>
    summarize(mean_exp = mean(expression_log))

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene, time, and sex.
ℹ Output is grouped by gene and time.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time, sex))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

R

mean_exp_by_time_sex

OUTPUT

# A tibble: 60 × 4
# Groups:   gene, time [30]
   gene   time sex    mean_exp
   <chr> <int> <chr>     <dbl>
 1 Acr       0 Female     5.13
 2 Acr       0 Male       5.00
 3 Acr       4 Female     5.93
 4 Acr       4 Male       5.15
 5 Acr       8 Female     7.27
 6 Acr       8 Male       7.36
 7 Aipl1     0 Female     3.67
 8 Aipl1     0 Male       3.73
 9 Aipl1     4 Female     4.07
10 Aipl1     4 Male       3.72
# ℹ 50 more rows

Nous pouvons désormais créer le graphique facetté en effectuant un nouveau découpage selon le sexe à l’aide de color (au sein d’un même graphique) :

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y")
Line plot, as produced by geom_line(), with 10 sub-plots/facets, each showing two coloured lines (red for Female and blue for Make) with increasing expression values over time.

En général, les graphiques à fond blanc sont plus lisibles une fois imprimés. Nous pouvons régler le fond sur blanc à l’aide de la fonction theme_bw(). De plus, nous pouvons supprimer la grille :

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank())
Line plot, as produced by geom_line(), with 10 sub-plots/facets, each showing two coloured lines (red for Female and blue for Make) with increasing expression values over time. The figure background is now white.
Challenge

Défi

Utilisez ce que vous venez d’apprendre pour créer un graphique illustrant l’évolution de l’expression moyenne de chaque chromosome au cours de l’infection.

R

mean_exp_by_chromosome <- rna |>
  group_by(chromosome_name, time) |>
  summarize(mean_exp = mean(expression_log))

OUTPUT

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by chromosome_name and time.
ℹ Output is grouped by chromosome_name.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(chromosome_name, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

R

ggplot(data = mean_exp_by_chromosome, mapping = aes(x = time,
                                y = mean_exp)) +
  geom_line() +
  facet_wrap(~ chromosome_name, scales = "free_y")
Line plot, as produced by geom_line(), with 21 sub-plots/facets, each showing one line with expression values over time for each chromosome.

La fonction facet_wrap répartit les facettes sur plusieurs lignes et colonnes afin qu’elles tiennent clairement sur une seule page. La fonction facet_grid permet, quant à elle, de spécifier explicitement la disposition des facettes à l’aide d’une formule (rows ~ columns ; un . peut servir de marqueur pour indiquer une seule ligne ou une seule colonne).

Modifions le graphique précédent pour comparer l’évolution de la moyenne de l’expression génique chez les mâles et les femelles au fil du temps :

R

# One column, facet by rows
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = gene)) +
  geom_line() +
  facet_grid(sex ~ .)
Two line plots above each other, each showing 10 lines coloured by gene. The top facet shows the expression values for Female sample, the bottom one for Male samples.

R

# One row, facet by column
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = gene)) +
  geom_line() +
  facet_grid(. ~ sex)
Two line plots next to each other, each showing 10 lines coloured by gene. The left facet shows the expression values for Female sample, the right one for Male samples.

Thèmes de ggplot2


En plus de theme_bw(), qui change l’arrière-plan du graphique en blanc, ggplot2 propose plusieurs autres thèmes qui peuvent s’avérer utiles pour modifier rapidement l’aspect de votre visualisation. La liste complète des thèmes est disponible à https://ggplot2.tidyverse.org/reference/ggtheme.html. theme_minimal() et theme_light() sont populaires, et theme_void() peut être utile comme point de départ pour créer un nouveau thème personnalisé.

Le package ggthemes propose une grande variété d’options (dont un thème Excel 2003). Le site web des extensions ggplot2 propose une liste de packages qui étendent les fonctionnalités de ggplot2, notamment des thèmes supplémentaires.

Personnalisation


Revenons au graphique facetté de l’expression moyenne selon le temps et le gène, coloré par sexe.

Jetez un coup d’œil à la fiche pratique ggplot2, et réfléchissez à des moyens d’améliorer le graphique.

Désormais, nous pouvons remplacer les noms des axes par des appellations plus informatives que « time » et « mean_exp », et ajouter un titre à la figure :

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  labs(title = "Mean gene expression by duration of the infection",
       x = "Duration of the infection (in days)",
       y = "Mean gene expression")
Line plot with white background and custom title and axis legends.

Les axes possèdent des noms plus explicites, mais leur lisibilité peut être améliorée en augmentant la taille de la police :

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  labs(title = "Mean gene expression by duration of the infection",
       x = "Duration of the infection (in days)",
       y = "Mean gene expression")  +
  theme(text = element_text(size = 16))
Line plot with white background and larger custom title and axis legends.

Notez qu’il est également possible de modifier les polices de vos graphiques. Si vous utilisez Windows, vous devrez peut-être installer le package extrafont.

Nous pouvons encore personnaliser la couleur du texte des axes X et Y, la couleur de la grille, etc. Nous pouvons également, par exemple, déplacer la légende en haut en définissant legend.position à "top".

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  labs(title = "Mean gene expression by duration of the infection",
       x = "Duration of the infection (in days)",
       y = "Mean gene expression")  +
  theme(text = element_text(size = 16),
        axis.text.x = element_text(colour = "royalblue4", size = 12),
        axis.text.y = element_text(colour = "royalblue4", size = 12),
        panel.grid = element_line(colour="lightsteelblue1"),
        legend.position = "top")
Line plot with white background and larger custom title and axis legends and blue grid.

Si vous préférez votre personnalisation au thème par défaut, vous pouvez l’enregistrer sous la forme d’un objet afin de l’appliquer facilement à d’autres graphiques. Voici un exemple avec l’histogramme que nous avons créé précédemment.

R

blue_theme <- theme(axis.text.x = element_text(colour = "royalblue4",
                                               size = 12),
                    axis.text.y = element_text(colour = "royalblue4",
                                               size = 12),
                    text = element_text(size = 16),
                    panel.grid = element_line(colour="lightsteelblue1"))

ggplot(rna, aes(x = expression_log)) +
  geom_histogram(bins = 20) +
    blue_theme
Custrom 'blue_theme() showing a blue grid and blue axis legends.
Challenge

Défi

Avec toutes ces informations en main, prenez encore cinq minutes pour soit améliorer l’un des graphiques générés dans cet exercice, soit créer votre propre graphique esthétique. Consultez la fiche de référence ggplot2 de RStudio pour vous inspirer. Voici quelques idées :

  • Voyez si vous pouvez modifier l’épaisseur des lignes.
  • Pouvez-vous trouver un moyen de modifier le nom de la légende ? Et pour ses étiquettes ? (indice : cherchez une fonction ggplot commençant par scale_)
  • Essayez d’utiliser une autre palette de couleurs ou de spécifier manuellement les couleurs des lignes (voir https://www.cookbook-r.com/Graphs/Colors_(ggplot2)/).

Par exemple, en se basant sur ce graphique :

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank())
Plain facetted line plot, as produced by theme_bw() and a blank grid above.

Nous pouvons le personnaliser de la manière suivante :

R

# change the thickness of the lines
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line(size=1.5) +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank())

WARNING

Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
This warning is displayed once per session.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
generated.
Plain facetted line plot, as produced by theme_bw() and a blank grid with wide lines.

R

# change the name of the legend and the labels
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  scale_color_discrete(name = "Gender", labels = c("F", "M"))
Plain facetted line plot, as produced by theme_bw() and a blank grid with renamed colour labels.

R

# using a different color palette
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  scale_color_brewer(name = "Gender", labels = c("F", "M"), palette = "Dark2")
Plain facetted line plot, as produced by theme_bw() and a blank grid with a different color palette and renamed colour labels.

R

# manually specifying the colors
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  scale_color_manual(name = "Gender",  labels = c("F", "M"),
                     values = c("royalblue", "deeppink"))
Plain facetted line plot, as produced by theme_bw() and a blank grid with a manually-set colors and renamed colour labels..

Composer des graphiques


Le facettage est un excellent outil pour diviser un graphique en plusieurs sous-graphiques, mais il arrive que vous souhaitiez créer une seule figure contenant plusieurs graphiques indépendants, c’est-à-dire fondés sur des variables différentes ou même sur des tableaux de données distincts.

Commençons par créer les deux graphiques que nous souhaitons disposer côte à côte :

Le premier graphique compte le nombre de gènes uniques par chromosome. Nous devons d’abord réordonner les niveaux de chromosome_name et filtrer les gènes uniques par chromosome. Nous modifions également l’échelle de l’axe des ordonnées pour passer à une échelle logarithmique en base 10, afin d’améliorer la lisibilité.

R

rna$chromosome_name <- factor(rna$chromosome_name,
                               levels = c(1:19,"X","Y"))

count_gene_chromosome <- rna |>
  select(chromosome_name, gene) |>
  distinct() |> ggplot() +
  geom_bar(aes(x = chromosome_name), fill = "seagreen",
           position = "dodge", stat = "count") +
  labs(y = "log10(n genes)", x = "chromosome") +
  scale_y_log10()

count_gene_chromosome
A simple histogram with greed bars showing the log10 number of genes per chromosome.

Ci-dessous, nous supprimons également entièrement la légende en définissant legend.position à "none".

R

exp_boxplot_sex <- ggplot(rna, aes(y=expression_log, x = as.factor(time),
                 color=sex)) +
   geom_boxplot(alpha = 0) +
  labs(y = "Mean gene exp",
       x = "time") + theme(legend.position = "none")

exp_boxplot_sex
Transparently-filled red and blue boxplots for Female and Male expression values for different time points.

Le package patchwork propose une approche élégante pour combiner des figures en utilisant + pour les disposer (généralement côte à côte). Plus précisément, | les dispose explicitement côte à côte et / les empile les uns sur les autres.

R

install.packages("patchwork")

R

library("patchwork")
count_gene_chromosome + exp_boxplot_sex
A composed figure show the histogram (left) and boxplots (right) next to each other.

R

## or count_gene_chromosome | exp_boxplot_sex

R

count_gene_chromosome / exp_boxplot_sex
A composed figure show the histogram (top) and boxplots (bottom) on top or each other.

Nous pouvons affiner davantage le contrôle de la mise en page de la composition finale à l’aide de plot_layout pour créer des mises en page plus complexes :

R

count_gene_chromosome + exp_boxplot_sex + plot_layout(ncol = 1)
A composed figure show the histogram (top) and boxplots (bottom) on top or each other.

R

count_gene_chromosome +
 (count_gene_chromosome + exp_boxplot_sex) +
 exp_boxplot_sex +
 plot_layout(ncol = 1)
A figure composed of 4 plots with on top the histogram, in the middle the histogram and the boxpot, side-by-side, and at the bottom, the boxplot.

Le dernier graphique peut également être créé à l’aide des composants | et / :

R

count_gene_chromosome /
 (count_gene_chromosome | exp_boxplot_sex) /
 exp_boxplot_sex
As above, a figure composed of 4 plots with on top the histogram, in the middle the histogram and the boxpot, side-by-side, and at the bottom, the boxplot.

Pour en savoir plus sur patchwork, consultez sa page web ou cette vidéo.

Une autre option est le package gridExtra, qui permet de combiner des ggplots distincts en une seule figure à l’aide de grid.arrange() :

R

install.packages("gridExtra")

R

library("gridExtra")
grid.arrange(count_gene_chromosome, exp_boxplot_sex, ncol = 2)
A composed figure with the histogram (left) and boxplot (right) side-by-side.

En plus des arguments ncol et nrow, utilisés pour réaliser des dispositions simples, il existe des outils permettant de construire des mises en page plus complexes.

Exportation de graphiques


Une fois votre graphique créé, vous pouvez l’enregistrer dans un fichier au format de votre choix. L’onglet Exportation du volet Plot dans RStudio enregistre vos graphiques à faible résolution, ce qui ne sera pas accepté par de nombreuses revues et ne sera pas adapté aux posters.

Utilisez plutôt la fonction ggsave(), qui vous permet de modifier facilement la dimension et la résolution de votre graphique en ajustant les arguments correspondants (width, height et dpi).

Assurez-vous d’avoir le dossier fig_output/ dans votre répertoire de travail.

R

my_plot <- ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  labs(title = "Mean gene expression by duration of the infection",
         x = "Duration of the infection (in days)",
         y = "Mean gene expression") +
  guides(color=guide_legend(title="Gender")) +
  theme_bw() +
  theme(axis.text.x = element_text(colour = "royalblue4", size = 12),
        axis.text.y = element_text(colour = "royalblue4", size = 12),
        text = element_text(size = 16),
        panel.grid = element_line(colour="lightsteelblue1"),
        legend.position = "top")
ggsave("fig_output/mean_exp_by_time_sex.png", my_plot, width = 15,
       height = 10)

# This also works for grid.arrange() plots
combo_plot <- grid.arrange(count_gene_chromosome, exp_boxplot_sex,
                           ncol = 2, widths = c(4, 6))
ggsave("fig_output/combo_plot_chromosome_sex.png", combo_plot,
       width = 10, dpi = 300)

Remarque : Les paramètres width et height déterminent également la taille de la police dans le graphique enregistré.

Autres packages de visualisation


ggplot2 est un package très puissant qui s’intègre parfaitement à notre pipeline de données ordonnées et d’outils ordonnés. Il existe d’autres packages de visualisation dans R qu’il ne faut pas négliger.

Graphismes de base

Le système graphique par défaut fourni avec R, souvent appelé graphismes R de base, est simple et rapide. Il repose sur le modèle du peintre ou de la toile, où différentes sorties sont superposées directement les unes aux autres (voir figure ci-dessous ). C’est une différence fondamentale avec ggplot2 (et avec lattice, décrit ci-dessous), qui renvoie des objets dédiés, rendus à l’écran ou dans un fichier, et qui peuvent même être mis à jour.

R

par(mfrow = c(1, 3))
plot(1:20, main = "First layer, produced with plot(1:20)")

plot(1:20, main = "A horizontal red line, added with abline(h = 10)")
abline(h = 10, col = "red")

plot(1:20, main = "A rectangle, added with rect(5, 5, 15, 15)")
abline(h = 10, col = "red")
rect(5, 5, 15, 15, lwd = 3)
The 'base' figures, side-by-side, showing (from left to right) 20 empty dots along the diagonal, same with a vertical red line, and same as the second one with a rectangle overlaid in the middle of the plot.
Successive layers added on top of each other.

Une autre différence majeure est que la fonction de tracé des graphiques de base tente de faire la bonne chose en fonction du type d’entrée, c’est-à-dire qu’elle adapte son comportement en fonction de la classe de son entrée. Cela diffère encore grandement de ce que l’on trouve dans ggplot2, qui n’accepte que les tableaux de données en entrée et nécessite que les graphiques soient construits petit à petit.

R

par(mfrow = c(2, 2))
boxplot(rnorm(100),
        main = "Boxplot of rnorm(100)")
boxplot(matrix(rnorm(100), ncol = 10),
        main = "Boxplot of matrix(rnorm(100), ncol = 10)")
hist(rnorm(100))
hist(matrix(rnorm(100), ncol = 10))
A two-by-two composition of 2 boxplots at the top, and 2 histograms at the bottom.
Plotting boxplots (top) and histograms (bottom) vectors (left) or a matrices (right).

L’approche par défaut des graphiques de base peut s’avérer très efficace pour des figures simples et standard, qui peuvent être produites très rapidement avec une seule ligne de code et une seule fonction telle que plot, ou hist, ou boxplot, … Les paramètres par défaut ne sont cependant pas toujours les plus attrayants, et le réglage des figures, surtout lorsqu’elles deviennent plus complexes (par exemple pour produire des facettes), peut s’avérer long et fastidieux.

Le package lattice

Le package lattice ressemble à ggplot2 en ce qu’il utilise des tableaux de données en entrée, restitue des objets graphiques et prend en charge le facettage. lattice, en revanche, ne repose pas sur la grammaire graphique et possède une interface plus complexe.

Une bonne référence pour le package lattice est Deepayan (2008).

Key Points
  • Visualisation dans R
Deepayan, Sarkar. 2008. Lattice: Multivariate Data Visualization with r. Springer. http://lmdvr.r-forge.r-project.org.
Wickham, Hadley. 2016. ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. http://ggplot2.org.
Wilkinson, Leland. 2005. The Grammar of Graphics (Statistics and Computing). Springer-Verlag.

Content from Prochaines étapes


Last updated on 2026-11-07 | Edit this page

Overview

Questions

  • Qu’est-ce qu’un SummarizedExperiment ?
  • Qu’est-ce que Bioconductor ?

Objectives

  • Présentez le projet Bioconductor.
  • Présenter la notion de conteneurs de données.
  • Présentez un aperçu du SummarizedExperiment, largement utilisé dans les analyses omiques.

Prochaines étapes


Les données en bioinformatique sont souvent complexes. Pour y remédier, les développeurs définissent des conteneurs de données spécialisés (appelés classes) qui correspondent aux propriétés des données qu’ils doivent traiter.

Cet aspect est central pour le projet Bioconductor1, qui utilise la même infrastructure de données de base à travers ses différents packages. Cela a certainement contribué au succès de Bioconductor. Les développeurs de packages Bioconductor sont invités à utiliser l’infrastructure existante afin d’assurer la cohérence, l’interopérabilité et la stabilité du projet dans son ensemble.

Pour illustrer un tel conteneur de données omiques, nous présenterons la classe SummarizedExperiment.

SummarizedExperiment


La figure ci-dessous représente l’architecture de la classe SummarizedExperiment.

Schematic representation of the SummarizedExperiment class illustrating the following slots: fowData and rowRanges, one assay or multiple assays, colData and metadata.

Les objets de la classe SummarizedExperiment contiennent :

  • Un ou plusieurs tableaux de mesures (assays) contenant les données omiques quantitatives (données d’expression), stockées sous la forme d’un objet de type matrice. Les caractéristiques mesurées (gènes, transcrits, protéines, etc.) correspondent aux lignes, et les échantillons aux colonnes.

  • Un emplacement (slot) de métadonnées des échantillons contenant leurs covariables, stockées sous la forme d’un tableau de données. Les lignes de ce tableau représentent les échantillons et correspondent exactement aux colonnes des données d’expression.

  • Un emplacement (slot) de métadonnées des caractéristiques mesurées contenant leurs covariables, stockées sous la forme d’un tableau de données. Les lignes de ce tableau correspondent exactement aux lignes des données d’expression.

La nature coordonnée de SummarizedExperiment garantit que les dimensions des différents emplacements (slots) restent cohérentes lors de la manipulation des données : les colonnes des données d’expression correspondent aux lignes des métadonnées des échantillons, tandis que les lignes des données d’expression correspondent aux lignes des métadonnées des caractéristiques mesurées. Par exemple, si nous excluons un échantillon du tableau de mesures, il est automatiquement supprimé des métadonnées des échantillons lors de la même opération.

Les slots de métadonnées peuvent accueillir des covariables (colonnes) supplémentaires sans affecter les autres structures.

Création d’un SummarizedExperiment

Afin de créer un SummarizedExperiment, nous créerons les composants individuels, à savoir la matrice de comptage, ainsi que les métadonnées des échantillons et des gènes à partir de fichiers CSV. C’est généralement ainsi que les données RNA-Seq sont fournies (après traitement des données brutes).

  • Une matrice d’expression : nous chargeons la matrice de comptage en précisant que la première colonne contient les noms des lignes (les gènes), puis convertissons le data.frame en matrix. Vous pouvez la télécharger en cliquant sur ce lien.

R

count_matrix <- read.csv("data/count_matrix.csv",
                         row.names = 1) |>
    as.matrix()

count_matrix[1:5, ]

OUTPUT

        GSM2545336 GSM2545337 GSM2545338 GSM2545339 GSM2545340 GSM2545341
Asl           1170        361        400        586        626        988
Apod         36194      10347       9173      10620      13021      29594
Cyp2d22       4060       1616       1603       1901       2171       3349
Klk6           287        629        641        578        448        195
Fcrls           85        233        244        237        180         38
        GSM2545342 GSM2545343 GSM2545344 GSM2545345 GSM2545346 GSM2545347
Asl            836        535        586        597        938       1035
Apod         24959      13668      13230      15868      27769      34301
Cyp2d22       3122       2008       2254       2277       2985       3452
Klk6           186       1101        537        567        327        233
Fcrls           68        375        199        177         89         67
        GSM2545348 GSM2545349 GSM2545350 GSM2545351 GSM2545352 GSM2545353
Asl            494        481        666        937        803        541
Apod         11258      11812      15816      29242      20415      13682
Cyp2d22       1883       2014       2417       3678       2920       2216
Klk6           742        881        828        250        798        710
Fcrls          300        233        231         81        303        285
        GSM2545354 GSM2545362 GSM2545363 GSM2545380
Asl            473        748        576       1192
Apod         11088      15916      11166      38148
Cyp2d22       1821       2842       2011       4019
Klk6           894        501        598        259
Fcrls          248        179        184         68

R

dim(count_matrix)

OUTPUT

[1] 1474   22
  • Une table décrivant les échantillons, disponible à ce lien.

R

sample_metadata <- read.csv("data/sample_metadata.csv")
sample_metadata

OUTPUT

       sample     organism age    sex   infection  strain time     tissue mouse
1  GSM2545336 Mus musculus   8 Female  InfluenzaA C57BL/6    8 Cerebellum    14
2  GSM2545337 Mus musculus   8 Female NonInfected C57BL/6    0 Cerebellum     9
3  GSM2545338 Mus musculus   8 Female NonInfected C57BL/6    0 Cerebellum    10
4  GSM2545339 Mus musculus   8 Female  InfluenzaA C57BL/6    4 Cerebellum    15
5  GSM2545340 Mus musculus   8   Male  InfluenzaA C57BL/6    4 Cerebellum    18
6  GSM2545341 Mus musculus   8   Male  InfluenzaA C57BL/6    8 Cerebellum     6
7  GSM2545342 Mus musculus   8 Female  InfluenzaA C57BL/6    8 Cerebellum     5
8  GSM2545343 Mus musculus   8   Male NonInfected C57BL/6    0 Cerebellum    11
9  GSM2545344 Mus musculus   8 Female  InfluenzaA C57BL/6    4 Cerebellum    22
10 GSM2545345 Mus musculus   8   Male  InfluenzaA C57BL/6    4 Cerebellum    13
11 GSM2545346 Mus musculus   8   Male  InfluenzaA C57BL/6    8 Cerebellum    23
12 GSM2545347 Mus musculus   8   Male  InfluenzaA C57BL/6    8 Cerebellum    24
13 GSM2545348 Mus musculus   8 Female NonInfected C57BL/6    0 Cerebellum     8
14 GSM2545349 Mus musculus   8   Male NonInfected C57BL/6    0 Cerebellum     7
15 GSM2545350 Mus musculus   8   Male  InfluenzaA C57BL/6    4 Cerebellum     1
16 GSM2545351 Mus musculus   8 Female  InfluenzaA C57BL/6    8 Cerebellum    16
17 GSM2545352 Mus musculus   8 Female  InfluenzaA C57BL/6    4 Cerebellum    21
18 GSM2545353 Mus musculus   8 Female NonInfected C57BL/6    0 Cerebellum     4
19 GSM2545354 Mus musculus   8   Male NonInfected C57BL/6    0 Cerebellum     2
20 GSM2545362 Mus musculus   8 Female  InfluenzaA C57BL/6    4 Cerebellum    20
21 GSM2545363 Mus musculus   8   Male  InfluenzaA C57BL/6    4 Cerebellum    12
22 GSM2545380 Mus musculus   8 Female  InfluenzaA C57BL/6    8 Cerebellum    19

R

dim(sample_metadata)

OUTPUT

[1] 22  9
  • Une table décrivant les gènes, disponible à ce lien.

R

gene_metadata <- read.csv("data/gene_metadata.csv")
gene_metadata[1:10, 1:4]

OUTPUT

      gene ENTREZID
1      Asl   109900
2     Apod    11815
3  Cyp2d22    56448
4     Klk6    19144
5    Fcrls    80891
6   Slc2a4    20528
7     Exd2    97827
8     Gjc2   118454
9     Plp1    18823
10    Gnb4    14696
                                                                         product
1                                 argininosuccinate lyase, transcript variant X1
2                                         apolipoprotein D, transcript variant 3
3   cytochrome P450, family 2, subfamily d, polypeptide 22, transcript variant 2
4                           kallikrein related-peptidase 6, transcript variant 2
5                  Fc receptor-like S, scavenger receptor, transcript variant X1
6            solute carrier family 2 (facilitated glucose transporter), member 4
7                                          exonuclease 3'-5' domain containing 2
8                            gap junction protein, gamma 2, transcript variant 1
9                           proteolipid protein (myelin) 1, transcript variant 1
10 guanine nucleotide binding protein (G protein), beta 4, transcript variant X2
      ensembl_gene_id
1  ENSMUSG00000025533
2  ENSMUSG00000022548
3  ENSMUSG00000061740
4  ENSMUSG00000050063
5  ENSMUSG00000015852
6  ENSMUSG00000018566
7  ENSMUSG00000032705
8  ENSMUSG00000043448
9  ENSMUSG00000031425
10 ENSMUSG00000027669

R

dim(gene_metadata)

OUTPUT

[1] 1474    9

Nous créerons un SummarizedExperiment à partir de ces tableaux :

  • La matrice de comptage qui sera utilisée comme assay

  • Le tableau décrivant les échantillons sera utilisé comme slot métadonnées des échantillons

  • Le tableau décrivant les gènes sera utilisé comme slot métadonnées des caractéristiques

Pour ce faire, nous pouvons assembler les différentes parties à l’aide du constructeur SummarizedExperiment :

R

## BiocManager::install("SummarizedExperiment")
library("SummarizedExperiment")

Tout d’abord, nous nous assurons que les échantillons sont dans le même ordre dans la matrice de comptage et l’annotation des échantillons, et de même pour les gènes dans la matrice de comptage et l’annotation des gènes.

R

stopifnot(rownames(count_matrix) == gene_metadata$gene)
stopifnot(colnames(count_matrix) == sample_metadata$sample)

R

se <- SummarizedExperiment(assays = list(counts = count_matrix),
                           colData = sample_metadata,
                           rowData = gene_metadata)
se

OUTPUT

class: SummarizedExperiment
dim: 1474 22
metadata(0):
assays(1): counts
rownames(1474): Asl Apod ... Lmx1a Pbx1
rowData names(9): gene ENTREZID ... phenotype_description
  hsapiens_homolog_associated_gene_name
colnames(22): GSM2545336 GSM2545337 ... GSM2545363 GSM2545380
colData names(9): sample organism ... tissue mouse

Sauvegarde des données

L’exportation de données vers une feuille de calcul, comme nous l’avons fait dans un épisode précédent, présente plusieurs limites, telles que celles décrites dans le premier chapitre : incohérences possibles entre , et . comme séparateurs décimaux, et absence de définition des types des variables. De plus, l’exportation vers une feuille de calcul n’est pertinente que pour des données rectangulaires, telles que les tableaux de données et les matrices.

Une méthode plus générale de sauvegarde des données, spécifique à R et garantie sur tout système d’exploitation, consiste à utiliser la fonction saveRDS. La sauvegarde d’objets de ce type génère une représentation binaire sur le disque (en utilisant ici l’extension de fichier rds), laquelle peut être chargée à nouveau dans R à l’aide de la fonction readRDS.

R

saveRDS(se, file = "data_output/se.rds")
rm(se)
se <- readRDS("data_output/se.rds")
head(se)

En conclusion, lorsqu’il s’agit de sauvegarder des données depuis R qui seront à nouveau chargées dans R, la méthode préférée consiste à utiliser saveRDS et readRDS. Si des données tabulaires doivent être partagées avec quelqu’un qui n’utilise pas R, l’exportation vers une feuille de calcul textuelle constitue une bonne alternative.

À l’aide de cette structure de données, nous pouvons accéder à la matrice d’expression avec la fonction assay :

R

head(assay(se))

OUTPUT

        GSM2545336 GSM2545337 GSM2545338 GSM2545339 GSM2545340 GSM2545341
Asl           1170        361        400        586        626        988
Apod         36194      10347       9173      10620      13021      29594
Cyp2d22       4060       1616       1603       1901       2171       3349
Klk6           287        629        641        578        448        195
Fcrls           85        233        244        237        180         38
Slc2a4         782        231        248        265        313        786
        GSM2545342 GSM2545343 GSM2545344 GSM2545345 GSM2545346 GSM2545347
Asl            836        535        586        597        938       1035
Apod         24959      13668      13230      15868      27769      34301
Cyp2d22       3122       2008       2254       2277       2985       3452
Klk6           186       1101        537        567        327        233
Fcrls           68        375        199        177         89         67
Slc2a4         528        249        266        357        654        693
        GSM2545348 GSM2545349 GSM2545350 GSM2545351 GSM2545352 GSM2545353
Asl            494        481        666        937        803        541
Apod         11258      11812      15816      29242      20415      13682
Cyp2d22       1883       2014       2417       3678       2920       2216
Klk6           742        881        828        250        798        710
Fcrls          300        233        231         81        303        285
Slc2a4         271        304        349        715        513        320
        GSM2545354 GSM2545362 GSM2545363 GSM2545380
Asl            473        748        576       1192
Apod         11088      15916      11166      38148
Cyp2d22       1821       2842       2011       4019
Klk6           894        501        598        259
Fcrls          248        179        184         68
Slc2a4         248        350        317        796

R

dim(assay(se))

OUTPUT

[1] 1474   22

Nous pouvons accéder aux métadonnées de l’échantillon à l’aide de la fonction colData :

R

colData(se)

OUTPUT

DataFrame with 22 rows and 9 columns
                sample     organism       age         sex   infection
           <character>  <character> <integer> <character> <character>
GSM2545336  GSM2545336 Mus musculus         8      Female  InfluenzaA
GSM2545337  GSM2545337 Mus musculus         8      Female NonInfected
GSM2545338  GSM2545338 Mus musculus         8      Female NonInfected
GSM2545339  GSM2545339 Mus musculus         8      Female  InfluenzaA
GSM2545340  GSM2545340 Mus musculus         8        Male  InfluenzaA
...                ...          ...       ...         ...         ...
GSM2545353  GSM2545353 Mus musculus         8      Female NonInfected
GSM2545354  GSM2545354 Mus musculus         8        Male NonInfected
GSM2545362  GSM2545362 Mus musculus         8      Female  InfluenzaA
GSM2545363  GSM2545363 Mus musculus         8        Male  InfluenzaA
GSM2545380  GSM2545380 Mus musculus         8      Female  InfluenzaA
                strain      time      tissue     mouse
           <character> <integer> <character> <integer>
GSM2545336     C57BL/6         8  Cerebellum        14
GSM2545337     C57BL/6         0  Cerebellum         9
GSM2545338     C57BL/6         0  Cerebellum        10
GSM2545339     C57BL/6         4  Cerebellum        15
GSM2545340     C57BL/6         4  Cerebellum        18
...                ...       ...         ...       ...
GSM2545353     C57BL/6         0  Cerebellum         4
GSM2545354     C57BL/6         0  Cerebellum         2
GSM2545362     C57BL/6         4  Cerebellum        20
GSM2545363     C57BL/6         4  Cerebellum        12
GSM2545380     C57BL/6         8  Cerebellum        19

R

dim(colData(se))

OUTPUT

[1] 22  9

Nous pouvons également accéder aux métadonnées des caractéristiques à l’aide de la fonction rowData :

R

head(rowData(se))

OUTPUT

DataFrame with 6 rows and 9 columns
               gene  ENTREZID                product    ensembl_gene_id
        <character> <integer>            <character>        <character>
Asl             Asl    109900 argininosuccinate ly.. ENSMUSG00000025533
Apod           Apod     11815 apolipoprotein D, tr.. ENSMUSG00000022548
Cyp2d22     Cyp2d22     56448 cytochrome P450, fam.. ENSMUSG00000061740
Klk6           Klk6     19144 kallikrein related-p.. ENSMUSG00000050063
Fcrls         Fcrls     80891 Fc receptor-like S, .. ENSMUSG00000015852
Slc2a4       Slc2a4     20528 solute carrier famil.. ENSMUSG00000018566
        external_synonym chromosome_name   gene_biotype  phenotype_description
             <character>     <character>    <character>            <character>
Asl        2510006M18Rik               5 protein_coding abnormal circulating..
Apod                  NA              16 protein_coding abnormal lipid homeo..
Cyp2d22             2D22              15 protein_coding abnormal skin morpho..
Klk6                Bssp               7 protein_coding abnormal cytokine le..
Fcrls      2810439C17Rik               3 protein_coding decreased CD8-positi..
Slc2a4            Glut-4              11 protein_coding abnormal circulating..
        hsapiens_homolog_associated_gene_name
                                  <character>
Asl                                       ASL
Apod                                     APOD
Cyp2d22                                CYP2D6
Klk6                                     KLK6
Fcrls                                   FCRL2
Slc2a4                                 SLC2A4

R

dim(rowData(se))

OUTPUT

[1] 1474    9

Sélection d’éléments dans un SummarizedExperiment

Comme pour les tableaux de données, on peut extraire un sous-ensemble d’un SummarizedExperiment à l’aide d’indices numériques, de chaînes de caractères ou de valeurs logiques.

Ci-dessous, nous créons une nouvelle instance de la classe SummarizedExperiment qui ne contient que les 5 premières caractéristiques pour les 3 premiers échantillons.

R

se1 <- se[1:5, 1:3]
se1

OUTPUT

class: SummarizedExperiment
dim: 5 3
metadata(0):
assays(1): counts
rownames(5): Asl Apod Cyp2d22 Klk6 Fcrls
rowData names(9): gene ENTREZID ... phenotype_description
  hsapiens_homolog_associated_gene_name
colnames(3): GSM2545336 GSM2545337 GSM2545338
colData names(9): sample organism ... tissue mouse

R

colData(se1)

OUTPUT

DataFrame with 3 rows and 9 columns
                sample     organism       age         sex   infection
           <character>  <character> <integer> <character> <character>
GSM2545336  GSM2545336 Mus musculus         8      Female  InfluenzaA
GSM2545337  GSM2545337 Mus musculus         8      Female NonInfected
GSM2545338  GSM2545338 Mus musculus         8      Female NonInfected
                strain      time      tissue     mouse
           <character> <integer> <character> <integer>
GSM2545336     C57BL/6         8  Cerebellum        14
GSM2545337     C57BL/6         0  Cerebellum         9
GSM2545338     C57BL/6         0  Cerebellum        10

R

rowData(se1)

OUTPUT

DataFrame with 5 rows and 9 columns
               gene  ENTREZID                product    ensembl_gene_id
        <character> <integer>            <character>        <character>
Asl             Asl    109900 argininosuccinate ly.. ENSMUSG00000025533
Apod           Apod     11815 apolipoprotein D, tr.. ENSMUSG00000022548
Cyp2d22     Cyp2d22     56448 cytochrome P450, fam.. ENSMUSG00000061740
Klk6           Klk6     19144 kallikrein related-p.. ENSMUSG00000050063
Fcrls         Fcrls     80891 Fc receptor-like S, .. ENSMUSG00000015852
        external_synonym chromosome_name   gene_biotype  phenotype_description
             <character>     <character>    <character>            <character>
Asl        2510006M18Rik               5 protein_coding abnormal circulating..
Apod                  NA              16 protein_coding abnormal lipid homeo..
Cyp2d22             2D22              15 protein_coding abnormal skin morpho..
Klk6                Bssp               7 protein_coding abnormal cytokine le..
Fcrls      2810439C17Rik               3 protein_coding decreased CD8-positi..
        hsapiens_homolog_associated_gene_name
                                  <character>
Asl                                       ASL
Apod                                     APOD
Cyp2d22                                CYP2D6
Klk6                                     KLK6
Fcrls                                   FCRL2

Nous pouvons également utiliser la fonction colData() pour effectuer un sous-ensemble sur des éléments des métadonnées des échantillons, ou la fonction rowData() pour effectuer un sous-ensemble sur des éléments des métadonnées des caractéristiques. Par exemple, ici, nous ne conservons que les miRNAs et les échantillons non infectés :

R

se1 <- se[rowData(se)$gene_biotype == "miRNA",
          colData(se)$infection == "NonInfected"]
se1

OUTPUT

class: SummarizedExperiment
dim: 7 7
metadata(0):
assays(1): counts
rownames(7): Mir1901 Mir378a ... Mir128-1 Mir7682
rowData names(9): gene ENTREZID ... phenotype_description
  hsapiens_homolog_associated_gene_name
colnames(7): GSM2545337 GSM2545338 ... GSM2545353 GSM2545354
colData names(9): sample organism ... tissue mouse

R

assay(se1)

OUTPUT

         GSM2545337 GSM2545338 GSM2545343 GSM2545348 GSM2545349 GSM2545353
Mir1901          45         44         74         55         68         33
Mir378a          11          7          9          4         12          4
Mir133b           4          6          5          4          6          7
Mir30c-2         10          6         16         12          8         17
Mir149            1          2          0          0          0          0
Mir128-1          4          1          2          2          1          2
Mir7682           2          0          4          1          3          5
         GSM2545354
Mir1901          60
Mir378a           8
Mir133b           3
Mir30c-2         15
Mir149            2
Mir128-1          1
Mir7682           5

R

colData(se1)

OUTPUT

DataFrame with 7 rows and 9 columns
                sample     organism       age         sex   infection
           <character>  <character> <integer> <character> <character>
GSM2545337  GSM2545337 Mus musculus         8      Female NonInfected
GSM2545338  GSM2545338 Mus musculus         8      Female NonInfected
GSM2545343  GSM2545343 Mus musculus         8        Male NonInfected
GSM2545348  GSM2545348 Mus musculus         8      Female NonInfected
GSM2545349  GSM2545349 Mus musculus         8        Male NonInfected
GSM2545353  GSM2545353 Mus musculus         8      Female NonInfected
GSM2545354  GSM2545354 Mus musculus         8        Male NonInfected
                strain      time      tissue     mouse
           <character> <integer> <character> <integer>
GSM2545337     C57BL/6         0  Cerebellum         9
GSM2545338     C57BL/6         0  Cerebellum        10
GSM2545343     C57BL/6         0  Cerebellum        11
GSM2545348     C57BL/6         0  Cerebellum         8
GSM2545349     C57BL/6         0  Cerebellum         7
GSM2545353     C57BL/6         0  Cerebellum         4
GSM2545354     C57BL/6         0  Cerebellum         2

R

rowData(se1)

OUTPUT

DataFrame with 7 rows and 9 columns
                gene  ENTREZID        product    ensembl_gene_id
         <character> <integer>    <character>        <character>
Mir1901      Mir1901 100316686  microRNA 1901 ENSMUSG00000084565
Mir378a      Mir378a    723889  microRNA 378a ENSMUSG00000105200
Mir133b      Mir133b    723817  microRNA 133b ENSMUSG00000065480
Mir30c-2    Mir30c-2    723964 microRNA 30c-2 ENSMUSG00000065567
Mir149        Mir149    387167   microRNA 149 ENSMUSG00000065470
Mir128-1    Mir128-1    387147 microRNA 128-1 ENSMUSG00000065520
Mir7682      Mir7682 102466847  microRNA 7682 ENSMUSG00000106406
         external_synonym chromosome_name gene_biotype  phenotype_description
              <character>     <character>  <character>            <character>
Mir1901          Mirn1901              18        miRNA                     NA
Mir378a           Mirn378              18        miRNA abnormal mitochondri..
Mir133b          mir 133b               1        miRNA no abnormal phenotyp..
Mir30c-2        mir 30c-2               1        miRNA                     NA
Mir149            Mirn149               1        miRNA increased circulatin..
Mir128-1          Mirn128               1        miRNA no abnormal phenotyp..
Mir7682      mmu-mir-7682               1        miRNA                     NA
         hsapiens_homolog_associated_gene_name
                                   <character>
Mir1901                                     NA
Mir378a                                MIR378A
Mir133b                                MIR133B
Mir30c-2                               MIR30C2
Mir149                                      NA
Mir128-1                              MIR128-1
Mir7682                                     NA
Challenge

Défi

Extrayez les niveaux d’expression génique des trois premiers gènes dans les échantillons au temps 0 et au temps 8.

R

assay(se)[1:3, colData(se)$time != 4]

OUTPUT

        GSM2545336 GSM2545337 GSM2545338 GSM2545341 GSM2545342 GSM2545343
Asl           1170        361        400        988        836        535
Apod         36194      10347       9173      29594      24959      13668
Cyp2d22       4060       1616       1603       3349       3122       2008
        GSM2545346 GSM2545347 GSM2545348 GSM2545349 GSM2545351 GSM2545353
Asl            938       1035        494        481        937        541
Apod         27769      34301      11258      11812      29242      13682
Cyp2d22       2985       3452       1883       2014       3678       2216
        GSM2545354 GSM2545380
Asl            473       1192
Apod         11088      38148
Cyp2d22       1821       4019

R

# Equivalent to
assay(se)[1:3, colData(se)$time == 0 | colData(se)$time == 8]

OUTPUT

        GSM2545336 GSM2545337 GSM2545338 GSM2545341 GSM2545342 GSM2545343
Asl           1170        361        400        988        836        535
Apod         36194      10347       9173      29594      24959      13668
Cyp2d22       4060       1616       1603       3349       3122       2008
        GSM2545346 GSM2545347 GSM2545348 GSM2545349 GSM2545351 GSM2545353
Asl            938       1035        494        481        937        541
Apod         27769      34301      11258      11812      29242      13682
Cyp2d22       2985       3452       1883       2014       3678       2216
        GSM2545354 GSM2545380
Asl            473       1192
Apod         11088      38148
Cyp2d22       1821       4019
Challenge

Défi

Vérifiez que vous obtenez les mêmes valeurs en utilisant le tableau rna au format long.

R

rna |>
    filter(gene %in% c("Asl", "Apod", "Cyd2d22")) |>
    filter(time != 4) |>
    select(expression)

OUTPUT

# A tibble: 28 × 1
   expression
        <dbl>
 1       1170
 2      36194
 3        361
 4      10347
 5        400
 6       9173
 7        988
 8      29594
 9        836
10      24959
# ℹ 18 more rows

Le tableau au format long et le SummarizedExperiment contiennent les mêmes informations, mais sont structurés différemment. Chaque approche présente ses propres avantages : le premier convient bien aux packages tidyverse, tandis que le second constitue la structure privilégiée pour de nombreuses étapes de traitement bioinformatique et statistique. C’est le cas, par exemple, d’une analyse RNA-Seq classique avec le package DESeq2.

Ajout de variables aux métadonnées

Nous pouvons également ajouter des informations aux métadonnées. Supposons que vous souhaitiez ajouter le centre où les échantillons ont été collectés…

R

colData(se)$center <- rep("University of Illinois", nrow(colData(se)))
colData(se)

OUTPUT

DataFrame with 22 rows and 10 columns
                sample     organism       age         sex   infection
           <character>  <character> <integer> <character> <character>
GSM2545336  GSM2545336 Mus musculus         8      Female  InfluenzaA
GSM2545337  GSM2545337 Mus musculus         8      Female NonInfected
GSM2545338  GSM2545338 Mus musculus         8      Female NonInfected
GSM2545339  GSM2545339 Mus musculus         8      Female  InfluenzaA
GSM2545340  GSM2545340 Mus musculus         8        Male  InfluenzaA
...                ...          ...       ...         ...         ...
GSM2545353  GSM2545353 Mus musculus         8      Female NonInfected
GSM2545354  GSM2545354 Mus musculus         8        Male NonInfected
GSM2545362  GSM2545362 Mus musculus         8      Female  InfluenzaA
GSM2545363  GSM2545363 Mus musculus         8        Male  InfluenzaA
GSM2545380  GSM2545380 Mus musculus         8      Female  InfluenzaA
                strain      time      tissue     mouse                 center
           <character> <integer> <character> <integer>            <character>
GSM2545336     C57BL/6         8  Cerebellum        14 University of Illinois
GSM2545337     C57BL/6         0  Cerebellum         9 University of Illinois
GSM2545338     C57BL/6         0  Cerebellum        10 University of Illinois
GSM2545339     C57BL/6         4  Cerebellum        15 University of Illinois
GSM2545340     C57BL/6         4  Cerebellum        18 University of Illinois
...                ...       ...         ...       ...                    ...
GSM2545353     C57BL/6         0  Cerebellum         4 University of Illinois
GSM2545354     C57BL/6         0  Cerebellum         2 University of Illinois
GSM2545362     C57BL/6         4  Cerebellum        20 University of Illinois
GSM2545363     C57BL/6         4  Cerebellum        12 University of Illinois
GSM2545380     C57BL/6         8  Cerebellum        19 University of Illinois

Cela illustre que les slots de métadonnées peuvent s’étendre indéfiniment sans affecter les autres structures !

tidySummarizedExperiment

Vous vous demandez peut-être si nous pouvons utiliser des commandes tidyverse pour interagir avec les objets SummarizedExperiment. La réponse est oui, c’est possible grâce au package tidySummarizedExperiment.

Rappelez-vous à quoi ressemble notre objet SummarizedExperiment :

R

se

OUTPUT

class: SummarizedExperiment
dim: 1474 22
metadata(0):
assays(1): counts
rownames(1474): Asl Apod ... Lmx1a Pbx1
rowData names(9): gene ENTREZID ... phenotype_description
  hsapiens_homolog_associated_gene_name
colnames(22): GSM2545336 GSM2545337 ... GSM2545363 GSM2545380
colData names(10): sample organism ... mouse center

Chargez tidySummarizedExperiment, puis examinez à nouveau l’objet se.

R

## BiocManager::install("tidySummarizedExperiment")
library("tidySummarizedExperiment")

se

OUTPUT

class: SummarizedExperiment
dim: 1474 22
metadata(0):
assays(1): counts
rownames(1474): Asl Apod ... Lmx1a Pbx1
rowData names(9): gene ENTREZID ... phenotype_description
  hsapiens_homolog_associated_gene_name
colnames(22): GSM2545336 GSM2545337 ... GSM2545363 GSM2545380
colData names(10): sample organism ... mouse center

Il s’agit toujours d’un objet SummarizedExperiment, qui conserve donc sa structure efficace, mais nous pouvons désormais le consulter comme un tibble. La première ligne de la sortie indique qu’il s’agit d’une abstraction SummarizedExperiment-tibble. La deuxième ligne indique également le nombre de transcrits et d’échantillons.

Nous pouvons désormais utiliser les commandes de tidyverse pour interagir avec l’objet SummarizedExperiment.

Nous pouvons utiliser filter pour filtrer des lignes selon une condition, par exemple pour afficher toutes les lignes d’un échantillon.

R

se |> filter(sample == "GSM2545336")

OUTPUT

class: SummarizedExperiment
dim: 1474 1
metadata(1): latest_filter_scope_report
assays(1): counts
rownames(1474): Asl Apod ... Lmx1a Pbx1
rowData names(9): gene ENTREZID ... phenotype_description
  hsapiens_homolog_associated_gene_name
colnames(1): GSM2545336
colData names(10): sample organism ... mouse center

R

se |> filter(sex == "Female")

OUTPUT

class: SummarizedExperiment
dim: 1474 12
metadata(1): latest_filter_scope_report
assays(1): counts
rownames(1474): Asl Apod ... Lmx1a Pbx1
rowData names(9): gene ENTREZID ... phenotype_description
  hsapiens_homolog_associated_gene_name
colnames(12): GSM2545336 GSM2545337 ... GSM2545362 GSM2545380
colData names(10): sample organism ... mouse center

Nous pouvons utiliser select pour spécifier les colonnes que nous souhaitons consulter.

R

se |> select(sample, sex)

WARNING

Warning: `when()` was deprecated in purrr 1.0.0.
ℹ Please use `if` instead.
ℹ The deprecated feature was likely used in the tidySummarizedExperiment
  package.
  Please report the issue at
  <https://github.com/stemangiola/tidySummarizedExperiment/issues>.
This warning is displayed once per session.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
generated.

OUTPUT

tidySummarizedExperiment says: Key columns are missing. A data frame is returned for independent data analysis.

OUTPUT

# A tibble: 32,428 × 2
   sample     sex
   <chr>      <chr>
 1 GSM2545336 Female
 2 GSM2545336 Female
 3 GSM2545336 Female
 4 GSM2545336 Female
 5 GSM2545336 Female
 6 GSM2545336 Female
 7 GSM2545336 Female
 8 GSM2545336 Female
 9 GSM2545336 Female
10 GSM2545336 Female
# ℹ 32,418 more rows

Nous pouvons utiliser mutate pour ajouter des informations métadonnées.

R

se |> mutate(center = "Heidelberg University")

OUTPUT

class: SummarizedExperiment
dim: 1474 22
metadata(1): latest_mutate_scope_report
assays(1): counts
rownames(1474): Asl Apod ... Lmx1a Pbx1
rowData names(9): gene ENTREZID ... phenotype_description
  hsapiens_homolog_associated_gene_name
colnames(22): GSM2545336 GSM2545337 ... GSM2545363 GSM2545380
colData names(10): sample organism ... mouse center

Nous pouvons également combiner des commandes à l’aide du pipe tidyverse |>. Par exemple, nous pourrions combiner group_by et summarise pour obtenir la somme des comptages pour chaque échantillon.

R

se |>
    group_by(.sample) |>
    summarise(total_counts=sum(counts))

OUTPUT

tidySummarizedExperiment says: A data frame is returned for independent data analysis.

OUTPUT

# A tibble: 22 × 2
   .sample    total_counts
   <chr>             <int>
 1 GSM2545336      3039671
 2 GSM2545337      2602360
 3 GSM2545338      2458618
 4 GSM2545339      2500082
 5 GSM2545340      2479024
 6 GSM2545341      2413723
 7 GSM2545342      2349728
 8 GSM2545343      3105652
 9 GSM2545344      2524137
10 GSM2545345      2506038
# ℹ 12 more rows

Nous pouvons traiter l’objet tidy SummarizedExperiment comme un tibble ordinaire pour créer des graphiques.

Ici, nous représentons la distribution des comptages par échantillon.

R

se |>
    ggplot(aes(counts + 1, group=.sample, color=infection)) +
    geom_density() +
    scale_x_log10() +
    theme_bw()
Density plot showing log of expression counts + 1 density lines, one per samples, coloured based on the infection status.

Pour plus d’informations sur tidySummarizedExperiment, consultez le site web du package.

Message clé

  • SummarizedExperiment représente un moyen efficace de stocker et de manipuler des données omiques.

  • Ils sont utilisés dans de nombreux packages Bioconductor.

Si vous suivez la formation suivante consacrée à l’analyse du séquençage de l’ARN, vous apprendrez à utiliser le package Bioconductor DESeq2 pour réaliser des analyses d’expression différentielle. L’intégralité de l’analyse du package DESeq2 est gérée dans un SummarizedExperiment.

Key Points
  • Bioconductor est un projet qui fournit un support et des packages pour la compréhension de données biologiques à haut débit.
  • Un SummarizedExperiment est un type d’objet utile pour stocker et gérer des données omiques à haut débit.

  1. Le projet Bioconductor a été lancé par Robert Gentleman, l’un des deux créateurs du langage R. Bioconductor propose des outils dédiés à l’analyse de données omiques. Il utilise le langage de programmation statistique R ; son code source est ouvert et son développement est ouvert à la communauté.↩︎