<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>R-atique</title>
	<atom:link href="https://perso.ens-lyon.fr/lise.vaudor/feed/" rel="self" type="application/rss+xml" />
	<link>https://perso.ens-lyon.fr/lise.vaudor</link>
	<description>Analyse de données avec R</description>
	<lastBuildDate>Mon, 01 Dec 2025 14:31:01 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2020/06/img_LVaudor.jpg</url>
	<title>R-atique</title>
	<link>https://perso.ens-lyon.fr/lise.vaudor</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Les transformées d&#8217;ondelettes, ou comprendre les mystérieux signaux [félins] grâce aux maths</title>
		<link>https://perso.ens-lyon.fr/lise.vaudor/les-transformees-dondelettes-ou-comprendre-les-mysterieux-signaux-felins-grace-aux-maths/</link>
					<comments>https://perso.ens-lyon.fr/lise.vaudor/les-transformees-dondelettes-ou-comprendre-les-mysterieux-signaux-felins-grace-aux-maths/#comments</comments>
		
		<dc:creator><![CDATA[lvaudor]]></dc:creator>
		<pubDate>Mon, 01 Dec 2025 14:15:47 +0000</pubDate>
				<category><![CDATA[Tous les posts]]></category>
		<guid isPermaLink="false">https://perso.ens-lyon.fr/lise.vaudor/?p=1425</guid>

					<description><![CDATA[A quoi peuvent vous servir les transformées d&#8217;ondelettes? A part briller en société si vous avez la chance de comprendre de quoi il retourne, je veux dire? Eh bien, les transformées d&#8217;ondelettes peuvent servir à décrire et comprendre des signaux à des échelles variées: elles sont donc particulièrement utiles si l&#8217;on s&#8217;intéresse à un signal de type série temporelle pouvant être soumis à des variations périodiques. Cela peut être par.. <a href="https://perso.ens-lyon.fr/lise.vaudor/les-transformees-dondelettes-ou-comprendre-les-mysterieux-signaux-felins-grace-aux-maths/">Read More</a>]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">A quoi peuvent vous servir les transformées d&rsquo;ondelettes?</h2>



<p>A part briller en société si vous avez la chance de comprendre de quoi il retourne, je veux dire?</p>



<p>Eh bien, les transformées d&rsquo;ondelettes peuvent servir à <strong>décrire et comprendre</strong> des <strong>signaux</strong> à des <strong>échelles variées</strong>: elles sont donc particulièrement utiles si l&rsquo;on s&rsquo;intéresse à un signal de type série temporelle pouvant être soumis à des variations périodiques.</p>



<p>Cela peut être par exemple:</p>



<ul class="wp-block-list">
<li>des variations de température mesurées toutes les 3h sur une année</li>



<li>le niveau de la mer mesuré toutes les heures sur quelques mois,</li>



<li>le flux de trafic routier mesuré toutes les 10 minutes sur quelques jours</li>



<li>un niveau d&rsquo;hormones mesuré toutes les 10 minutes sur 48h.</li>
</ul>



<p>Ce genre de signaux résultant de processus qui s&rsquo;expriment à différentes échelles, il peut être pertinent de le décrire <strong>à travers le temps</strong> mais aussi <strong>à travers les échelles</strong> (ou périodes) pour mieux les comprendre.</p>



<p>Considérons par exemple la série temporelle suivante: j&rsquo;ai enregistré l&rsquo;<strong>humeur de mon chat</strong> toutes les 10 minutes pendant 10 jours grâce à une sonde ultra-perfectionnée (et ultra-imaginaire).</p>



<p><em>NB: Exceptionnellement, je montre ici des résultats de codes R sans montrer les codes eux-mêmes car les figures suivantes résultent d&rsquo;un gros travail de <strong>mise en application shiny</strong>-. Pour l&rsquo;instant, l&rsquo;appli <strong>waveleT</strong> est disponible dans sa version 2016 -!- ici: <a href="https://isig-apps.ens-lyon.fr/apps/lvaudor/waveleT/">https://isig-apps.ens-lyon.fr/apps/lvaudor/waveleT/</a>). Le repo github (avec le méga-commit correspondant à sa mise en package et son organisation en modules golem) est ici: </em><a href="https://github.com/lvaudor/waveleT"><em>https://github.com/lvaudor/waveleT</em></a>.<em> Je reviendrai ici faire sa promotion et déverser les états d&rsquo;âme qui m&rsquo;ont traversée au cours de sa réalisation <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f640.png" alt="🙀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> quand sa nouvelle version -golémisée et packagisée- sera déployée&#8230;</em></p>



<h1 class="wp-block-heading">Décrire par les ondelettes continues</h1>



<p>Voici donc une représentation des humeurs de mon chat au cours de quelques jours du mois de juin 2024:</p>



<figure class="wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><a href="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_Raw_y1.png"><img fetchpriority="high" decoding="async" width="700" height="400" data-id="1432" src="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_Raw_y1.png" alt="" class="wp-image-1432" srcset="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_Raw_y1.png 700w, https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_Raw_y1-300x171.png 300w" sizes="(max-width: 700px) 100vw, 700px" /></a></figure>
</figure>



<p>On y devine des <strong>variations journalières</strong>, atténuées certains jours, avec a priori des pics de bonne humeur entre 17h et 23h environ. (L&rsquo;appli peut s&rsquo;avérer utile pour bénéficier d&rsquo;un « hover » qui vous permet de situer les variations dans le temps en plaçant la souris dessus ;-)).</p>



<p>Si j&rsquo;applique une transformée d&rsquo;ondelettes continues sur ce signal j&rsquo;obtiens quelque chose comme ça:</p>



<figure class="wp-block-image size-full"><a href="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_CWT_y1_type1_power.png"><img decoding="async" width="700" height="400" src="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_CWT_y1_type1_power.png" alt="" class="wp-image-1433" srcset="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_CWT_y1_type1_power.png 700w, https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_CWT_y1_type1_power-300x171.png 300w" sizes="(max-width: 700px) 100vw, 700px" /></a></figure>



<p>C&rsquo;est flamboyant, c&rsquo;est fascinant, c&rsquo;est aussi légèrement effrayant peut-être (surtout si par le passé vous avez traîné dans des sessions poster de conférences où rôdent des physiciens pour qui ce genre de représentation est limpide: ça peut laisser un trauma).</p>



<p>En tout cas voilà comment on peut interpréter ce graphique:</p>



<ul class="wp-block-list">
<li>en x, on retrouve <strong>le temps</strong>: on couvre les quelques jours sur lesquels j&rsquo;ai effectué des mesures sur mon chat</li>



<li>en y, on trouve des<strong> périodes</strong> (ici exprimées en minutes). Donc un rythme journalier s&rsquo;exprimera aux alentours de 24*60=1440 minutes. Là encore, l&rsquo;échelle log2 sur l&rsquo;axe des y rend le « hover » fourni par l&rsquo;appli bien utile.</li>



<li>en échelle colorée, on trouve la « puissance » (power) des coefficients d&rsquo;ondelette. Elles correspondent  grosso modo à une mesure de la variance.</li>
</ul>



<p>Ici, on peut lire le graphique de cette manière: il y a des variations particulièrement importantes dans le signal à la période 1440 min = <strong>24h</strong> sur l&rsquo;ensemble de la période sauf les 8 et 9 juin (qui s&rsquo;avèrent être un samedi-dimanche): cela se voyait déjà sur le signal brut. Il y a aussi des variations à une échelle de 720 minutes (<strong>12h</strong>), et des variations (plus irrégulières peut-être à une échelle entre 240 et 480 minutes (<strong>entre 4 et 8h</strong>).</p>



<p>La puissance nous renseigne sur l&rsquo;<strong>ampleur des variations</strong> et non sur leur <strong>nature</strong>. Si l&rsquo;on représente directement les coefficients d&rsquo;ondelettes, on peut voir les variations positives et négatives:</p>



<figure class="wp-block-image size-full"><a href="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_CWT_y1_type1_wavelet.png"><img decoding="async" width="700" height="400" src="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_CWT_y1_type1_wavelet.png" alt="" class="wp-image-1434" srcset="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_CWT_y1_type1_wavelet.png 700w, https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_CWT_y1_type1_wavelet-300x171.png 300w" sizes="(max-width: 700px) 100vw, 700px" /></a></figure>



<p>Je peux ainsi constater que mon chat a un <strong>coup de mou</strong> <strong>quotidien </strong>(les jours de semaine) à peu près entre <strong>9h et 17h</strong>, et un coup de mieux entre 19h et 7h du matin. Le week-end, son humeur est globalement meilleure (pas de coup de mou en journée). Peut-être est-il heureux d&rsquo;avoir du monde à la maison?</p>



<p>Par ailleurs, pour l&rsquo;interprétation des <strong>périodes 12h et 4-8h</strong>, je peux vous fournir une information complémentaire: le <strong>distributeur automatique de mon chat lui a distribué une ration chaque jour à 6h, 10h, 18h, et 22h</strong>. Visiblement, mon chat est de meilleure humeur quand il a le ventre plein. Mais la fréquence à laquelle le distributeur améliore de façon apparente son humeur varie non seulement par son paramétrage -les croquettes tombent à 4h d&rsquo;intervalle à certains moments, à 8h d&rsquo;intervalle à d&rsquo;autres- et selon l&rsquo;événement que l&rsquo;on considère et sa durée -i.e., en quelque sorte, sa « forme »- : le fait d&rsquo;avoir les croquettes qui tombent -durée 30 secondes- et le fait d&rsquo;avoir le ventre plein -durée a priori plus importante-. Ainsi, même pour une une causalité claire (d&rsquo;autant plus claire à vrai dire que j&rsquo;ai simulé le jeu de données pour que l&rsquo;humeur de mon chat réponde aux horaires du distributeur de croquettes) il peut être <strong>délicat de décrire le signal en temps-fréquence</strong> (ou <strong>temps-période</strong>). Certaines périodicités sautent aux yeux, d&rsquo;autres moins.</p>



<h1 class="wp-block-heading">Décomposer par les ondelettes discrètes</h1>



<p>Voilà qui m&rsquo;amène à une <strong>autre manière d&rsquo;utiliser les ondelettes</strong> pour comprendre/décrire ce qui se passe dans un signal temporel.</p>



<p>La figure suivante montre le signal <strong>« débruité » pour tous les niveaux scalaires inférieures à une périodicité de 24h</strong>. On y voit parfaitement le rythme quotidien des humeurs de mon chat.</p>



<figure class="wp-block-image size-full"><a href="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_modwt_mra_y1_LS.png"><img loading="lazy" decoding="async" width="700" height="400" src="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_modwt_mra_y1_LS.png" alt="" class="wp-image-1435" srcset="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_modwt_mra_y1_LS.png 700w, https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_modwt_mra_y1_LS-300x171.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /></a></figure>



<p>Techniquement, ce signal débruité est reconstitué via une <strong>analyse multi-résolution par les ondelettes discrètes</strong> Là encore, je vous renvoie à mon appli <strong>waveleT</strong> qui permet de paramétrer l&rsquo;ondelette-mère et les niveaux scalaires de votre choix facilement.</p>



<p>Si je veux être capable d&rsquo;examiner les variations dans mon signal à une <strong>échelle intermédiaire</strong> (pour démêler, par exemple, ce qui se passe aux échelles temporelles entre 4 et 12h) je peux sélectionner des niveaux scalaires inférieurs:</p>



<figure class="wp-block-image size-full"><a href="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_modwt_mra_y1_MS.png"><img loading="lazy" decoding="async" width="700" height="400" src="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_modwt_mra_y1_MS.png" alt="" class="wp-image-1436" srcset="https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_modwt_mra_y1_MS.png 700w, https://perso.ens-lyon.fr/lise.vaudor/wp-content/uploads/2025/12/Fig_modwt_mra_y1_MS-300x171.png 300w" sizes="auto, (max-width: 700px) 100vw, 700px" /></a></figure>



<p>Il devient ainsi possible de considérer les variations du signal qui relèvent <strong>uniquement d&rsquo;une certaine période</strong>, en <strong>excluant ici le bruit</strong> (variations sur les périodes les plus courtes) et <strong>les variations sur la période de 24 heures et plus</strong>. Il s&rsquo;agit d&rsquo;un résultat qui reste descriptif, mais qui a le mérite de faciliter la description et l&rsquo;interprétation des variations d&rsquo;un signal complexe.</p>



<p><em>P.S.: le chat orange chez qui j&rsquo;ai vécu pendant 13 ans n&rsquo;est plus <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f494.png" alt="💔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> . Que ce post soit un hommage vibrant à ce qu&rsquo;il a accompli (quoique inconsciemment) pour la science et un témoignage ému de l&rsquo;importance qu&rsquo;il accordait à ce qui compte vraiment <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f63d.png" alt="😽" class="wp-smiley" style="height: 1em; max-height: 1em;" />.</em></p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://perso.ens-lyon.fr/lise.vaudor/les-transformees-dondelettes-ou-comprendre-les-mysterieux-signaux-felins-grace-aux-maths/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Le blog est mort. Vive le blog!</title>
		<link>https://perso.ens-lyon.fr/lise.vaudor/le-blog-est-mort-vive-le-blog/</link>
					<comments>https://perso.ens-lyon.fr/lise.vaudor/le-blog-est-mort-vive-le-blog/#comments</comments>
		
		<dc:creator><![CDATA[lvaudor]]></dc:creator>
		<pubDate>Thu, 06 Nov 2025 09:01:34 +0000</pubDate>
				<category><![CDATA[Tous les posts]]></category>
		<guid isPermaLink="false">https://perso.ens-lyon.fr/lise.vaudor/?p=1421</guid>

					<description><![CDATA[Quatre ans (!), quatre ans sans publier un seul billet sur ce blog. Quatre ans sans écrire, partager des réflexions, des découvertes, des bouts de code, des petites lubies du moment. Le blog a été laissé à l’abandon, un peu comme un vieux fichier .RData oublié dans un dossier poussiéreux. À vrai dire, il n’a jamais été complètement mort: j’ai continué à y déposer des supports de cours par exemple,.. <a href="https://perso.ens-lyon.fr/lise.vaudor/le-blog-est-mort-vive-le-blog/">Read More</a>]]></description>
										<content:encoded><![CDATA[
<p>Quatre ans (!), quatre ans sans publier un seul billet sur ce blog. Quatre ans sans écrire, partager des réflexions, des découvertes, des bouts de code, des petites lubies du moment. Le blog a été laissé à l’abandon, un peu comme un vieux fichier <code>.RData</code> oublié dans un dossier poussiéreux.</p>



<p>À vrai dire, il n’a jamais été complètement mort: j’ai continué à y déposer des supports de cours par exemple, mais sans m’y investir vraiment en mode « blog ». Pourquoi? D’abord pour des raisons personnelles (enfants, temps partiel, priorisation de projets « professionnellement urgents »), et plus récemment, parce que la révolution de l’IA générative m’a fait <strong>douter de l’intérêt</strong> de publier sur le blog.</p>



<p>Le doute était simple: <em>à quoi bon écrire du contenu quand il devient si facile de générer des supports pédagogiques parfaitement adaptés à chacun avec un simple prompt?</em> Mes statistiques de consultation ont confirmé mon intuition: divisées par trois en deux ans. Certes, c’est sans doute lié à mon manque d’activité (et à mon absence de tweets), mais il y a autre chose: <strong>les usages d’Internet changent</strong>. Les lecteurs ne lisent plus les blogs; ils lisent des contenus digérés par l’IA.</p>



<p>Pour autant, pas de rancune. J’<strong>utilise moi-même ces outils tous les jours</strong> pour analyser des données, debugger du code, améliorer ce que je rédige, et plus largement gagner du temps sur des tâches chronophages et/ou répétitives. Je ne vois pas au nom de quoi je m’offusquerais de leur usage par d’autres.</p>



<p>En revanche, dans le vaste schéma des choses, si l’IA devait se contenter de re-digérer des contenus générés par IA (on parle d&rsquo;auto-phagie), elle finirait par tourner en rond, à produire des <strong>contenus plats, stéréotypés, ou biaisés</strong>. Alors j’ai décidé: peu importe si les lecteurs me lisent moins directement, je projette de <strong>recommencer à écrire</strong> pour faire passer ma voix, pour que mon code et mes idées ne se dissolvent pas totalement dans les courants du web (oui, il y a sans doute un fond de mégalomanie dans cet air-là).</p>



<p>Cette envie me vient à l&rsquo;heure où j&rsquo;ai décidé de rédiger une HDR (et où, ce faisant, je redécouvre le plaisir d&rsquo;écrire sans -trop- de contraintes). En prévision de mon futur HDR-blues, il me faut trouver un futur exutoire à mes envies d&rsquo;expression personnelle. </p>



<p>Donc, le blog quasi-renaît de ses presque-cendres. Certaines choses changent: plus de promotion sur feu Twitter, mais sur LinkedIn (où je vois que « ça bouge »), et je continuerai à l’<strong>illustrer</strong> à la main (sans IA). Pourquoi? Parce que, certes, cela prend du temps, mais ça me fait plaisir… et parce que pour le moment aucune IA ne fait encore des illustrations qui me conviennent vraiment. Par contre, j&rsquo;<strong>utiliserai l&rsquo;IA pour améliorer le texte</strong> ou m&rsquo;aider à le structurer (c&rsquo;est un retour d&rsquo;ascenseur, en somme). On verra si cela se ressent dans mon style d&rsquo;écriture!… et si j&rsquo;arrive toujours, malgré cela, à y exprimer quelque chose de personnel. <em>Spoiler alert</em>: je crois que c&rsquo;est possible, et que les IA génératives comme ChatGPT peuvent même aider… même si les textes que je lui demande de réécrire « dans le style de Lise Vaudor » sont truffés de blagues vraiment nases -et vous m&rsquo;en voyez bien marrie!-.</p>



<p>Dans mes idées pour les  prochains billets, il y a justement cette question de l&rsquo;<strong>IA générative</strong> (oui pour le coup ce n&rsquo;est pas très original!), et notamment à la question de son <strong>coût environnemental</strong> qui m&rsquo;a toujours pas mal interrogée. Aussi, j&rsquo;aimerais faire renaître de ses cendres un autre de mes projets sur lequel j&rsquo;ai beaucoup travaillé, mais peu communiqué: celui de l&rsquo;<strong>analyse des signaux par les ondelettes</strong>. Espérons que toutes ces annonces en fanfare me poussent à effectivement trouver le temps d&rsquo;écrire tout cela <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f605.png" alt="😅" class="wp-smiley" style="height: 1em; max-height: 1em;" />.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://perso.ens-lyon.fr/lise.vaudor/le-blog-est-mort-vive-le-blog/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>Practice makes purrr-fect</title>
		<link>https://perso.ens-lyon.fr/lise.vaudor/practice-makes-purrr-fect/</link>
					<comments>https://perso.ens-lyon.fr/lise.vaudor/practice-makes-purrr-fect/#comments</comments>
		
		<dc:creator><![CDATA[lvaudor]]></dc:creator>
		<pubDate>Tue, 07 Sep 2021 12:47:52 +0000</pubDate>
				<category><![CDATA[Tous les posts]]></category>
		<guid isPermaLink="false">http://perso.ens-lyon.fr/lise.vaudor/?p=1324</guid>

					<description><![CDATA[purrr et dplyr sont dans un bateau: aucun ne tombe à l’eau Voilà déjà 3 ans, je publiais sur ce blog un billet sur le package purrr. Depuis, avec la pratique, j’ai pu identifier quelques points techniques qui me mettaient en difficulté assez fréquemment et pour lesquels j’aimerais vous présenter quelques explications. Ces difficultés sont en fait nées de l’utilisation simultanée de dplyr et de purrr, qui sont certes conçus.. <a href="https://perso.ens-lyon.fr/lise.vaudor/practice-makes-purrr-fect/">Read More</a>]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" src="../../lise.vaudor/Rfigures/Purrrfect/Lise_Vaudor_headband-1.png" alt="" /></p>
<h1>purrr et dplyr sont dans un bateau: aucun ne tombe à l’eau</h1>
<p>Voilà déjà 3 ans, je publiais sur ce blog un <a href="http://perso.ens-lyon.fr/lise.vaudor/iterer-des-fonctions-avec-purrr/">billet sur le package purrr</a>. Depuis, avec la pratique, j’ai pu identifier quelques points techniques qui me mettaient en difficulté assez fréquemment et pour lesquels j’aimerais vous présenter quelques explications.</p>
<p>Ces difficultés sont en fait nées de l’utilisation simultanée de <code>dplyr</code> et de <code>purrr</code>, qui sont certes conçus pour fonctionner ensemble, mais dont l’usage conjoint pouvait des fois causer quelques noeuds à mon cerveau lors de l’écriture de mes codes.</p>
<p>Un petit rappel rapide d’abord:</p>
<p>Le principe de base de purrr, c’est d’<strong>itérer n fois une fonction sur les n éléments d’un vecteur ou d’une liste</strong>.</p>
<p>Si la fonction <code>.f()</code> prend en entrée un argument <code>x</code> (et éventuellement des arguments supplémentaires figurés ici par <code>...</code>) et renvoie en sortie un résultat <code>y</code></p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Purrr/purrr1.png" style="width:30.0%" /></p>
<p>alors on peut grâce à <code>purrr::map()</code> appliquer la fonction <code>.f()</code> à tout un vecteur ou liste <code>.x=(x_1,x_2,x_3,...,x_n)</code> pour obtenir un vecteur ou liste <code>(y_1,y_2,y_3,...,y_n)</code>.|</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Purrr/purrr2.png" style="width:30.0%" /></p>
<p>Alors, partant de ce principe, comment les fonctions de purrr peuvent-elles s’articuler avec les idées “tidy” et notamment l’omniprésence de tableaux pour traiter les données?</p>
<h1>Fonctions, formules et pipéabilité</h1>
<p>Le premier petit souci que j’ai pu avoir dans l’usage conjoint de <code>dplyr</code> et <code>purrr</code> était lié au fait que (faute d’avoir compris toutes les possibilités syntaxiques des fonctions du package) je me retrouvais souvent obligée d’écrire des petites fonctions “rustines” destinées à ne servir qu’une seule fois, et qui faisaient tache dans la <em>beauté ondoyante et serpentine</em> de mon code :-p (beauté ondoyante et serpentine conférée par l’usage de dplyr et des pipes bien sûr).</p>
<p>C’est-à-dire que, au lieu de faire</p>
<pre><code>resultat &lt;- blabla %&gt;%
  dplyr::truc() %&gt;%
  dplyr::bidule() %&gt;%
  dplyr::machin() %&gt;%
  dplyr::mutate(chose=purrr::map(fonction_standard)) %&gt;% 
  dplyr::bidule() %&gt;%
  dplyr::machin()
</code></pre>
<p>j’étais régulièrement de faire un truc du genre</p>
<pre><code>resultat &lt;- blabla %&gt;%
  dplyr::truc() %&gt;%
  dplyr::bidule() %&gt;%
  dplyr::machin()

fonction_rustine=function(blabla){
  blabla
}

resultat= resultat %&gt;%
  dplyr::mutate(chose=purrr::map(fonction_rustine)) %&gt;% 
  dplyr::bidule() %&gt;%
  dplyr::machin()
</code></pre>
<p>car je ne trouvais pas la <strong>fonction standard adéquate</strong>.</p>
<p>Ainsi donc, ma <strong>méconnaissance de l’usage des formules</strong> dans les fonctions de <code>purrr</code> nuisaient à la “pipéabilité” de mon code. Cela vous semble peut-être un détail, mais ça m’ennuyait beaucoup (imaginez l’exemple ci-dessus avec davantage de lignes et plusieurs “petites fonctions rustines” par exemple: la relecture et compréhension de la chaîne de traitement s’en trouve vite complexifiée, même pour des opérations “toutes bêtes”).</p>
<p>Ainsi donc, première prise de conscience de ma part, on peut écrire, au lieu de :</p>
<pre><code>rustine=function(blabla){
  lignes_de_commande_impliquant_blabla
}

purrr::map(.x=truc, .f=rustine)
</code></pre>
<p>quelque chose comme:</p>
<pre><code>purrr::map(.x=truc,
           ~lignes_de_commande_impliquant_.x)
</code></pre>
<p>L’usage d’une formule peut aussi permettre d’<strong>utiliser une fonction standard qu’on souhaite itérer sur un autre argument que son premier argument</strong>. Par exemple:</p>
<pre><code>purrr::map(.x=truc,
           ~fonction_standard(a=33,b=.x))
</code></pre>
<p>Attention à la <strong>position des arguments supplémentaires</strong> pour la fonction .f() dans l’appel à map!</p>
<p>Dans le cas où on spécifie une <strong>fonction</strong>:</p>
<pre><code>purrr::map(.x=truc,
           .f=fonction_machin,
           argument_supplémentaire=33) 
#argument spécifié dans l'appel à map()
</code></pre>
<p>Dans le cas où on spécifie une <strong>formule</strong>:</p>
<pre><code>purrr::map(.x=truc,
           .f=~fonction_machin(blabla,
                               argument_supplémentaire=33)) 
# argument spécifié dans l'appel à fonction_machin()
</code></pre>
<p><small> Je n’ai pas réussi pour le moment à construire un “vrai” exemple permettant d’illustrer ces principes tout en restant simple… Je vais donc me contenter pour le moment de ces ‘fausses’ lignes de code…</small></p>
<h1>Petit à petit, les données font leur nid</h1>
<p>Passons maintenant à une autre fonction qui me permet régulièrement d’utiliser <code>purrr</code> pour mes jeux de données.</p>
<p>Il s’agit de la fonction tidyr::nest().</p>
<p>Chargeons le tidyverse:</p>
<pre><code>library(tidyverse)
</code></pre>
<p>et examinons la situation suivante:</p>
<pre><code>birds=tibble(id=paste0("ad_",1:6),
             species=c("orange","yellow","blue",
                       "blue","yellow","orange"),
             sex=rep(c("M","F"),3))
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Purrrfect/nest_im1.jpg" style="width:30.0%" /></p>
<p>La fonction tidyr::nest() permet de regrouper des lignes et colonnes en sous-jeux de données dans une colonne <code>data</code>. La colonne <code>data</code> correspond à une <strong>colonne-liste</strong> (ou <code>list-column en anglais</code>). Autrement dit, la commande ci-dessous regroupe les données (selon l’argument spécifié pour <code>group_by()</code>) en <strong>nids</strong>.</p>
<pre><code>nested_couples=birds %&gt;% 
  group_by(species) %&gt;% 
  nest()

nested_couples

## # A tibble: 3 × 2
## # Groups:   species [3]
##   species data            
##   &lt;chr&gt;   &lt;list&gt;          
## 1 orange  &lt;tibble [2 × 2]&gt;
## 2 yellow  &lt;tibble [2 × 2]&gt;
## 3 blue    &lt;tibble [2 × 2]&gt;
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Purrrfect/nest_im2.jpg" style="width:30.0%" /></p>
<p>Chaque couple-nid pond alors des oeufs selon des règles propres à leur espèce. Définissons la fonction <code>lay_eggs()</code> correspondant à ce processus.</p>
<pre><code>lay_eggs=function(species){
  n_egg=case_when(species=="orange"~2,
                  species=="blue"~1,
                  species=="yellow"~3)
  eggs=tibble(egg=paste0("egg_",1:n_egg))
  return(eggs)
}
lay_eggs("orange")

## # A tibble: 2 × 1
##   egg  
##   &lt;chr&gt;
## 1 egg_1
## 2 egg_2
</code></pre>
<p>Cette fonction prend en argument d’entrée l’espèce considérée, et renvoie en sortie une table comprenant autant de lignes que d’oeufs pondus.</p>
<p>On peut appliquer cette fonction à l’ensemble des couples-nids de la manière suivante:</p>
<pre><code>after_lay_eggs=nested_couples %&gt;% 
  mutate(eggs=purrr::map(species,lay_eggs))
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Purrrfect/nest_im3.jpg" style="width:30.0%" /></p>
<p>Examinons de plus près ce résultat, par exemple pour l’espèce “yellow”:</p>
<pre><code>after_lay_eggs %&gt;% filter(species=="yellow") %&gt;% pull(eggs)

## [[1]]
## # A tibble: 3 × 1
##   egg  
##   &lt;chr&gt;
## 1 egg_1
## 2 egg_2
## 3 egg_3
</code></pre>
<p>Il va s’agir maintenant de voir éclore les oeufs. Voici la fonction qui correspond à ce processus. Elle prend deux arguments: <code>eggs</code>, évidemment, mais aussi <code>species</code>, dont dépend le sex-ratio des juvéniles.</p>
<pre><code>hatch_eggs=function(eggs,species){
  sex_ratio=case_when(species=="blue"~0.54,
                      species=="yellow"~0.6,
                      species=="orange"~0.4)
  youngs=eggs %&gt;% 
    mutate(young=str_replace(egg,"egg","young")) %&gt;% 
    select(-egg) %&gt;% 
    mutate(sex=runif(nrow(eggs),0,1)) %&gt;% 
    mutate(sex=sex&lt;sex_ratio) %&gt;% 
    mutate(sex=case_when(sex==T~"M",
                         sex!=T~"F"))
}
</code></pre>
<p>On itère sur les deux arguments de la fonction donc on utilise <code>purrr::map2()</code> :</p>
<pre><code>set.seed(33)
after_hatch=after_lay_eggs %&gt;% 
  mutate(youngs=purrr::map2(eggs,species,hatch_eggs)) %&gt;% 
  select(-eggs)
</code></pre>
<p><small>Je retire la colonne <code>eggs</code> qui n’a plus lieu d’être après éclosion…</small></p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Purrrfect/nest_im4.jpg" style="width:30.0%" /></p>
<p>Examinons plus en détail par exemple ce qu’on obtient pour l’espèce “yellow”:</p>
<pre><code>after_hatch %&gt;% filter(species=="yellow") %&gt;% pull(youngs)

## [[1]]
## # A tibble: 3 × 2
##   young   sex  
##   &lt;chr&gt;   &lt;chr&gt;
## 1 young_1 F    
## 2 young_2 F    
## 3 young_3 M
</code></pre>
<p>Il est maintenant de laisser s’envoler nos petits oiseaux! Nous allons les faire sortir du nid…</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Purrrfect/nest_im5.jpg" style="width:30.0%" /></p>
<pre><code>birds_youngs=after_hatch %&gt;% 
  unnest(cols=c("youngs")) %&gt;% 
  ungroup()
birds_youngs

## # A tibble: 6 × 4
##   species data             young   sex  
##   &lt;chr&gt;   &lt;list&gt;           &lt;chr&gt;   &lt;chr&gt;
## 1 orange  &lt;tibble [2 × 2]&gt; young_1 M    
## 2 orange  &lt;tibble [2 × 2]&gt; young_2 F    
## 3 yellow  &lt;tibble [2 × 2]&gt; young_1 F    
## 4 yellow  &lt;tibble [2 × 2]&gt; young_2 F    
## 5 yellow  &lt;tibble [2 × 2]&gt; young_3 M    
## 6 blue    &lt;tibble [2 × 2]&gt; young_1 M
</code></pre>
<p>En faisant appel à <code>unnest()</code> sur la colonne <code>youngs</code>, on sort les juvéniles de leur nid et les attributs des “nids” (ici <code>species</code>) sont répétés autant de fois que nécessaire pour qualifier désormais les individus juvéniles.</p>
<p>Notez qu’on ne pourrait pas faire la même opération de manière concomittante sur <code>data</code> pour une question de dimensions (<code>data</code> comporte des éléments qui ont tous 2 lignes, <code>youngs</code> comporte des éléments dont le nombre de ligne varie entre 1 et 3).</p>
<p>Ce petit exemple très simple (et imagé) vous aidera j’espère à exploiter les possibilités offertes par le trio dplyr-tidyr::nest()-purrr!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://perso.ens-lyon.fr/lise.vaudor/practice-makes-purrr-fect/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>ACP</title>
		<link>https://perso.ens-lyon.fr/lise.vaudor/acp/</link>
					<comments>https://perso.ens-lyon.fr/lise.vaudor/acp/#comments</comments>
		
		<dc:creator><![CDATA[lvaudor]]></dc:creator>
		<pubDate>Tue, 11 May 2021 11:13:39 +0000</pubDate>
				<category><![CDATA[Tous les posts]]></category>
		<guid isPermaLink="false">http://perso.ens-lyon.fr/lise.vaudor/?p=1310</guid>

					<description><![CDATA[Très régulièrement, dans le cadre de ma mission de support à la recherche, on me demande de réaliser (ou d’aider à réaliser) des ACP (Analyses en Composantes Principales). En général cette demande ne s’ensuit pas d’un fol enthousiasme de ma part: je me sens un peu comme une cuisinière “bistronomique” à qui on demanderait tout le temps une entrecôte-frites. Je peux comprendre le côté “tradi mais appétent” mais pour moi.. <a href="https://perso.ens-lyon.fr/lise.vaudor/acp/">Read More</a>]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" src="../../lise.vaudor/Rfigures/ACP/Lise_Vaudor_headband-1.png" alt="" /></p>
<p>Très régulièrement, dans le cadre de ma mission de support à la recherche, on me demande de réaliser (ou d’aider à réaliser) des <strong>ACP (Analyses en Composantes Principales)</strong>. En général cette demande ne s’ensuit pas d’un fol enthousiasme de ma part: je me sens un peu comme une cuisinière “bistronomique” à qui on demanderait tout le temps une entrecôte-frites. Je peux comprendre le côté “tradi mais appétent” mais pour moi c’est pas l’éclate.</p>
<p>Quoi qu’il en soit, la demande étant somme toute légitime (et fréquente) voici un billet où je rassemble <strong>quelques éléments d’information et outils pour réaliser des ACP sans douleur</strong>.</p>
<h1>Une ACP, pour quoi faire</h1>
<p>Une ACP (ou “PCA” pour <strong>P</strong>rincipal <strong>C</strong>omponents <strong>A</strong>nalysis en anglais) c’est une analyse qui vise à <strong>décrire un jeu de données comprenant de multiples variables quantitatives</strong>.</p>
<p>Elle fait partie d’une même “famille” d’analyses, celle des <strong>analyses factorielles</strong> qui s’appliquent à de larges tableaux de données (pas forcément uniquement composés de variables quantitatives comme dans le cas de l’ACP).</p>
<p>Le principe d’une ACP est de <strong>réduire</strong> un jeu de données à <strong>N</strong>>2 variables (i.e. N dimensions) à quelques (généralement 2) variables nouvelles (ce qu’on appelle les <strong>composantes principales</strong>). Le but de la manoeuvre, c’est d’obtenir quelque chose qui est beaucoup plus <strong>facile à décrire et à représenter</strong> qu’un jeu de données avec beaucoup de variables (puisque 2 dimensions, c’est ce qu’il faut pour représenter le jeu de données “dans son entièreté” sur un graphique, que ce soit pour un article papier ou sur un écran d’ordinateur…).</p>
<p>Le coeur du “job” de l’ACP, c’est donc justement de <strong>calculer ces composantes principales à partir des variables de base</strong>.</p>
<p>Tentons une analogie.</p>
<p>Imaginez une banane par exemple. Il s’agit d’un objet 3D. Si je veux le représenter en 2D, selon l’angle que je choisirai pour la représenter, je vais obtenir quelque chose de plus ou moins “reconnaissable”.</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/ACP/ACP_banane.png" alt="" /></p>
<p>A gauche, l’angle choisi est tel qu’on ne reconnaît pas la forme de la banane. A droite, c’est bien mieux, car l’angle choisi permet de reconnaître le côté allongé et courbé caractéristique. <small>Notez que dans les deux cas, la couleur est une information supplémentaire bienvenue pour l’interprétation ;-).</small>.</p>
<p>Eh bien, pour réaliser l’image de droite, un dessinateur fait un peu l’équivalent d’une ACP en trouvant un “angle” (ou plus précisément un “plan” défini par deux axes) qui va apporter le plus d’information possible sur l’objet, de sorte que l’oeil humain puisse interpréter de quoi il s’agit.</p>
<p>Quand on travaille sur un jeu de données à N>>2 dimensions (et généralement N>>3) il est évidemment plus difficile d’avoir une image mentale de la structure/forme de l’objet d’origine que dans le cas d’une banane… La représentation “la plus juste possible” de cet objet en 1D, 2D ou 3D que propose l’ACP va permettre d’appréhender cette structure/forme.</p>
<h1>Calcul des composantes principales</h1>
<p>Je ne rentrerai pas ici dans le détail du calcul réalisé dans le cadre d’une ACP. Il y a derrière des notions de maths qui ne sont pas forcément très accessibles (c’est selon votre sensibilité, votre cursus, et la fraîcheur de vos études mais par exemple, j’ai pour ma part fait une prépa bio/véto il y a une quinzaine d’années -et donc pas mal de maths- mais le mécanisme exact du calcul me semble toujours un peu difficile à appréhender!).</p>
<p>Néanmoins, si vous êtes frustrés de ne pas comprendre “en profondeur” la méthode et que vous pensez que cela nuit à la qualité des interprétations que vous faites de vos analyses factorielles, je recommande les matériels pédagogiques relatifs au package <a href="http://factominer.free.fr/index_fr.html">FactoMineR</a>, et en particulier pour les ACP en particulier <a href="https://www.youtube.com/watch?v=1QPRsg3Bxok">cette vidéo</a> de François Husson, un des auteurs du package. C’est très bien amené et expliqué! Si vous tombez au bon moment, vous pouvez même suivre <a href="http://factominer.free.fr/course/MOOC_fr.html">le MOOC</a> (je l’ai suivi moi-même il y a quelques années et cela m’a bien aidé à mettre mes idées au clair).</p>
<h1>Réaliser l’ACP</h1>
<p>Il existe plusieurs packages pour réaliser les ACP. Les <strong>deux principaux</strong>, <code>FactoMineR</code> et <code>ade4</code> ont été développés par des équipes françaises (cocorico!?). Et ce n’est guère surprenant, les analyses factorielles elles-mêmes étant très françaises (comme l’entrecôte-frites?) puisqu’elles ont été mises au point dans les années 70 notamment par un certain Jean-Paul Benzécri et par son équipe.</p>
<p>Le package <code>ade4</code> a été développé (et est maintenu) par une équipe lyonnaise, qui travaille notamment avec des biologistes de l’évolution et des écologues (cela se ressent sur les exemples d’application d’ACP avec ce package que vous pourrez trouver!). Le package <code>FactoMineR</code> a quant à lui été développé (et est maintenu) par une équipe rennaise, qui travaille dans un univers un peu plus “agronomique”. Pour les méthodes les plus centrales (ACP, AFC), les différences entre ces packages sont à mon avis mineures et une fois que vous avez compris le principe d’une ACP <strong>vous pouvez sans inconvénient majeur opter pour l’un ou l’autre</strong>. Pour ma part, bien que Lyonnaise, j’ai une <strong>petite préférence pour FactoMineR</strong> car je trouve que c’est un peu plus facile de s’y retrouver (que ce soit pour les noms des fonctions ou des objets renvoyés, ou pour les supports pédagogiques).</p>
<p>Du coup, pour vous montrer un exemple d’ACP, je vais partir sur un exemple avec <code>FactoMineR</code>. D’ailleurs, je ne me casse vraiment pas la tête ici puisque je reprends le jeu de données et l’exemple proposé sur <a href="http://factominer.free.fr/factomethods/analyse-en-composantes-principales.html">le site de FactoMineR</a> lui-même</p>
<pre><code>library(FactoMineR)
data(decathlon)
head(decathlon)

##          100m Long.jump Shot.put High.jump  400m 110m.hurdle Discus Pole.vault Javeline 1500m Rank Points Competition
## SEBRLE  11.04      7.58    14.83      2.07 49.81       14.69  43.75       5.02    63.19 291.7    1   8217    Decastar
## CLAY    10.76      7.40    14.26      1.86 49.37       14.05  50.72       4.92    60.15 301.5    2   8122    Decastar
## KARPOV  11.02      7.30    14.77      2.04 48.37       14.09  48.95       4.92    50.31 300.2    3   8099    Decastar
## BERNARD 11.02      7.23    14.25      1.92 48.93       14.99  40.87       5.32    62.77 280.1    4   8067    Decastar
## YURKOV  11.34      7.09    15.19      2.10 50.42       15.31  46.26       4.72    63.44 276.4    5   8036    Decastar
## WARNERS 11.11      7.60    14.31      1.98 48.68       14.23  41.10       4.92    51.77 278.1    6   8030    Decastar
</code></pre>
<p>Il s’agit donc d’un jeu de données qui comprend les <strong>résultats pour différentes épreuves du Décathlon (en colonnes) de plusieurs athlètes (en lignes)</strong>.</p>
<p>Les 10 premières colonnes correspondent aux résultats (quantitatifs) aux 10 épreuves du Décathlon. Attention, pour les épreuves de vitesse (<code>100m</code>, <code>110m.hurdle</code>, <code>400m</code>, <code>1500m</code>), les valeurs élevées correspondent à de mauvaises performances!… Les variables supplémentaires “Rank”, et “Points” correspondent respectivement aux rang, et nombre de points total de chaque athlète, La variable supplémentaire “Competition” indique lors de quelle compétition ces résultats ont été obtenus.</p>
<p>Réalisons une ACP sur les 10 premières variables (les variables quantitatives) pour avoir un “aperçu” de la structure des résultats des athlètes aux différentes épreuves. J’utilise pour ce faire une fonction qui s’appelle <code>PCA()</code>:</p>
<pre><code>resultat=PCA(decathlon[,1:10], graph=FALSE)
</code></pre>
<p>Et voilà! ça tourne en une demi-seconde, et renvoie (en plus de graphiques si on ne précise pas graph=FALSE) le résultat suivant.</p>
<pre><code>resultat

## **Results for the Principal Component Analysis (PCA)**
## The analysis was performed on 41 individuals, described by 10 variables
## *The results are available in the following objects:
## 
##    name               description                          
## 1  "$eig"             "eigenvalues"                        
## 2  "$var"             "results for the variables"          
## 3  "$var$coord"       "coord. for the variables"           
## 4  "$var$cor"         "correlations variables - dimensions"
## 5  "$var$cos2"        "cos2 for the variables"             
## 6  "$var$contrib"     "contributions of the variables"     
## 7  "$ind"             "results for the individuals"        
## 8  "$ind$coord"       "coord. for the individuals"         
## 9  "$ind$cos2"        "cos2 for the individuals"           
## 10 "$ind$contrib"     "contributions of the individuals"   
## 11 "$call"            "summary statistics"                 
## 12 "$call$centre"     "mean of the variables"              
## 13 "$call$ecart.type" "standard error of the variables"    
## 14 "$call$row.w"      "weights for the individuals"        
## 15 "$call$col.w"      "weights for the variables"
</code></pre>
<p>Ce résultat comprend 3 éléments principaux:</p>
<ul>
<li>
<p><code>eig</code> des infos sur les <code>eigenvalues</code> (ou “valeurs propres”), qui vont nous permettre d’évaluer la <strong>qualité de l’ACP</strong>. J’y reviendrai dans la partie suivante.</p>
</li>
<li>
<p><code>ind</code>: des infos sur les <strong>individus</strong> (lignes du tableau initial)</p>
</li>
<li>
<p><code>var</code>: des infos sur les <strong>variables</strong> (colonnes du tableau initial)</p>
</li>
</ul>
<p><code>ind</code> et <code>var</code> contiennent tous deux des éléments d’information correspondant à</p>
<ul>
<li>
<p><code>coord</code> les <strong>coordonnées</strong> des individus ou variables sur les axes principaux</p>
</li>
<li>
<p><code>cos2</code> qui permet d’évaluer si un individu ou une variable en particulier est <strong>bien représenté</strong> sur les axes principaux</p>
</li>
<li>
<p><code>contrib</code> qui permet d’évaluer le <strong>“poids”</strong> d’un individu ou d’une variable particuliers dans le <strong>calcul des axes</strong>.</p>
</li>
</ul>
<p>Les résultats graphiques d’une ACP correspondent usuellement à la <strong>représentation des coordonnées des individus et des variables</strong> dans l’espace défini par les axes principaux (en pratique, on en retient souvent 2 par défaut). C’est le cas ici, si on laisse FactoMineR nous proposer une représentation graphique de l’ACP (en ne précisant pas <code>graph=FALSE</code>).</p>
<pre><code>resultat=PCA(decathlon[,1:10])
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/ACP/runPCA_and_graph-1.png" alt="" /><img decoding="async" src="../../lise.vaudor/Rfigures/ACP/runPCA_and_graph-2.png" alt="" /></p>
<p>Le premier graphique correspond aux individus, le deuxième aux variables.</p>
<p>Ces deux représentations sont (rappelons-le) <strong>imparfaites</strong> puisqu’en réduisant le nombre de dimensions du jeu de données de 10 à 2 on a <strong>perdu une partie de l’information contenue par le jeu de données</strong>.</p>
<h1>Qualité de l’ACP</h1>
<p>Les eigenvalues apportent une information quant à la qualité de l’ACP en permettant de calculer la <strong>proportion de variance</strong> (ou inertie) du jeu de donnée initial qui est <strong>portée par les composantes principales issues de l’analyse</strong>.</p>
<pre><code>resultat$eig

##         eigenvalue percentage of variance cumulative percentage of variance
## comp 1   3.2719055              32.719055                          32.71906
## comp 2   1.7371310              17.371310                          50.09037
## comp 3   1.4049167              14.049167                          64.13953
## comp 4   1.0568504              10.568504                          74.70804
## comp 5   0.6847735               6.847735                          81.55577
## comp 6   0.5992687               5.992687                          87.54846
## comp 7   0.4512353               4.512353                          92.06081
## comp 8   0.3968766               3.968766                          96.02958
## comp 9   0.2148149               2.148149                          98.17773
## comp 10  0.1822275               1.822275                         100.00000
</code></pre>
<p>Par construction, l’ACP calcule et ordonne les composantes pour que la première porte plus d’information que la deuxième, qui en porte plus que la troisième, etc.</p>
<p>Les valeurs dans la deuxième colonne (<code>percentage of variance</code>) correspondent en effet aux valeurs d’eigenvalues divisées par le nombre initial de variables (10).</p>
<p>On retrouve dans cette colonne <code>percentage of variance</code> les valeurs de 32.72% et 17.37% qui étaient indiquées dans les étiquettes d’axes des deux graphiques ci-dessus. Ainsi, avec une représentation 2D (correspondant aux deux premiers axes principaux) on arrive à représenter 32.7+17.3=50.0% de l’information contenue dans le jeu de données initial.</p>
<p>* »Et alors, __% d’inertie portée par mes deux premiers axes, c’est bien ou c’est pas bien? »* m’entends-je demander parfois.</p>
<p>Eh bien mon bon monsieur, ma bonne dame, ptêt ben qu’oui, ptêt ben qu’non. Il n’existe à ma connaissance pas de convention sur une valeur qui serait “suffisamment bonne”.</p>
<p>Ici, on a <strong>50% de l’info sur 2 axes</strong>, alors qu’on avait <strong>10 variables à la base</strong>. Avant de réaliser l’ACP, deux dimensions correspondaient donc à 2 fois un dixième de l’inertie du jeu de données, soit 20%. L’ACP a donc permis de passer de 20% à 50% de l’info représentable par un graphique 2D: ça semble honnête, tant qu’on garde à l’esprit dans les interprétations que la moitié de l’info est perdue dans notre tentative de simplification.</p>
<p>Si on avait eu à la base 4 variables dans le jeu de données, 50% de l’info représentée par les deux premiers axes de l’ACP, ç’aurait été clairement très mauvais, puisque 2 sur 4 des variables initiales auraient déjà pu apporter cette part d’info. Autrement dit, l’ACP n’aurait servi à strictement rien.</p>
<p><strong>La proportion d’info portée par les composantes principales dépend évidemment du nombre de variables en entrée.</strong></p>
<p>Mais pas que.</p>
<p>Ce qui permet à l’ACP de “réduire en dimensionnalité” un jeu de données, c’est l’<strong>existence de corrélations entre les variables d’origine</strong>.</p>
<p>Si dans un jeu de données on a deux groupes de variables extrêmement inter-corrélées, alors très bien: deux composantes principales seront à même de représenter relativement bien les deux types d’effets. Si en revanche les N>>2 variables sont très peu corrélées les unes aux autres, alors on n’a aucune chance de “résumer” fidèlement le jeu de données dans son ensemble à l’aide de quelques composantes principales…</p>
<h1>Interprétation</h1>
<p>On peut interpréter les sorties graphiques d’une ACP de trois manières:</p>
<ul>
<li>en examinant la <strong>position des variables dans le nouveau repère</strong> (et en comparant la position des variables les unes par rapport aux autres)</li>
<li>en examinant la <strong>position des individus dans le nouveau repère</strong> (et en comparant la position des individus les uns par rapport aux autres)</li>
<li>en examinant la <strong>position des individus par rapport à la position des variables</strong> dans le nouveau repère</li>
</ul>
<h2>Position des variables</h2>
<p>La représentation des variables dans le plan factoriel, aussi appelé <strong>cercle des corrélations</strong>, permet d’évaluer la liaison entre les variables.</p>
<p>Plus l’<strong>angle entre deux variables est petit, plus la corrélation est proche de 1</strong>. Si l’<strong>angle est droit</strong>, la corrélation est <strong>proche de 0</strong>. Si l’<strong>angle est de 180°</strong> (les flèches sont opposées) alors la corrélation est <strong>proche de -1</strong>. <small> tout ça est s’applique évidemment si les variables sont “bien représentées” par les deux premiers axes de l’ACP</small></p>
<pre><code>plot.PCA(resultat, choix="var")
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/ACP/pca_vars-1.png" alt="" /></p>
<p>Ici par exemple, les performances des sportifs semblent corrélées positivement pour les disciplines de “force” <code>Discus</code>,<code>Shot.put</code>,<code>High.jump</code>. Les disciplines de “vitesse” <code>400m</code>, <code>110m.hurdle</code> <code>100m</code> sont aussi positivement corrélées les unes aux autres. La performance en <code>Long.jump</code> est inversement corrélée aux résultats de vitesse (rappelons que les résultats de vitesse sont des temps, donc une bonne performance sur les épreuves de vitesse est corrélée à une bonne performance en saut en longueur).</p>
<p>La qualité de représentation d’une variable par un axe peut être évaluée à travers le <strong>cosinus carré</strong> de l’angle entre la variable et l’axe considéré. Le cosinus correspond à la projection orthogonale de la pointe de la flèche sur l’axe. Du coup, (petit rappel du théorème de Pythagore) la qualité de représentation sur les deux axes (i.e. la somme des cosinus carrés) correspond à la longueur de la flèche: <strong>plus la pointe de la flèche est proche du cercle, plus la représentation de la variable dans le plan factoriel est “de qualité”</strong>.</p>
<p>Rappelons que le premier axe correspond à la plus grande part d’inertie du jeu de données initial. Ici, on voit que le jeu de données est structuré principalement par (à droite) les bonnes performances (i.e. petites valeurs pour les épreuves de vitesse et grosses valeurs pour toutes les autres) vs (à gauche) les mauvaises performances.</p>
<h2>Position des individus</h2>
<pre><code>plot.PCA(resultat, choix="ind")
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/ACP/pca_inds-1.png" alt="" /></p>
<p>Ce graphique montre les <strong>“ressemblances” entre individus</strong>. Plus ils sont proches (comme par exemple Parkhomenko et Korkizoglou, en haut à gauche, ou Karpov, Sebrle et Clay à droite), et plus leurs “profils” de performance sont vraisemblablement similaires.</p>
<p>Les coordonnées des individus peuvent ainsi classiquement servir de base pour définir des classes d’individus à travers une classification hiérarchique ascendante (par exemple).</p>
<p>Comme dans le cas des variables, les individus <strong>les mieux représentés par le plan factoriel sont ceux les plus éloignés du centre</strong> (même si ici on ne peut pas lire directement les valeurs de cosinus sur le graphique &#8211; elles sont en revanche disponible dans l’objet <code>resultat</code> issu de l’ACP).</p>
<p>La <strong>position des individus</strong> peut en outre être interprétée <strong>en lien avec la position des variables</strong>. Par exemple Casarsa, tout en haut à gauche, a vraisemblablement eu des résultats assez mauvais dans toutes les épreuves, tandis que Sebrle (à droite, en haut) a plutôt eu de bons résultats, en particulier dans les épreuves “de force”.</p>
<h1>Représentations graphiques</h1>
<p>Pour l’instant je me suis contentée d’utiliser les représentations graphiques proposées par le package FactoMineR lui-même. Elles peuvent être suffisantes pour une première exploration des résultats d’ACP mais ne suffisent généralement pas à produire des graphiques suffisemment lisibles et jolis pour (par exemple) faire partie d’articles, rapports ou autres.</p>
<p>Il existe divers packages qui permettent d’améliorer et paramétrer finement les graphiques typiques d’une ACP. Si vous travaillez avec le package <code>FactoMineR</code>, le package <code>factoextra</code> est une possibilité intéressante. Voyez <a href="un%20billet">ici</a> très bien fait qui vous montrera quelques exemples d’utilisation de ce package (Vous ne serez de plus pas trop perdus car ce billet utilise aussi des données d’exemple liées au Décathlon -attention tout-de-même il s’agit d’un jeu de données <code>decathlon2</code> et non <code>decathlon</code> ce qui explique les quelques différences de résultats que vous pouvez remarquer).</p>
<p>Pour ma part je suis totalement conquise par le package <code>explor</code> de Julien Barnier pour explorer mes résultats d’ACP (plus d’infos <a href="https://juba.github.io/explor/articles/introduction_fr.html">ici</a>).</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/ACP/logo_explor.png" width="120" /></p>
<p>Ce package produit une <strong>interface Shiny</strong> qui vous permet de visualiser vos résultats et paramétrer finement vos sorties graphiques, décaler les étiquettes qui se chevaucheraient, etc. Et vous pouvez suite à ces manipulations soit exporter les figures (au format et dimensions de votre choix), soit copier le code R qui permet de produire les graphiques en question (dans un souci de reproductibilité de vos analyses…).</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/ACP/capture_explor.png" width="750" /></p>
<p>Pour lancer cette interface, c’est très simple. On réalise l’ACP avec le package de son choix (FactoMineR OU ade4!) et on lance la fonction <code>explor()</code> avec ce résultat d’ACP en objet:</p>
<pre><code>resultat=PCA(decathlon, quanti.sup=11:12,quali.sup=13, graph=FALSE)
explor::explor(resultat)
</code></pre>
<p>Ici j’ai précisé que mon jeu de données comprenait des <strong>variables supplémentaires</strong> (que je désigne par le numéro de colonne) de manière à pouvoir les utiliser dans les sorties graphiques.</p>
<p><small> Petit “tweak” d’utilisation de ce package: Il m’arrive également, quand je souhaite faire des graphiques qui sortent un peu des sentiers battus avec des résultats issus d’analyses factorielles, de récupérer les résultats mis en forme par la fonction <code>prepare_results()</code> de ce package. Ensuite j’utilise les tableaux en sortie avec le combo magique tidyr-dplyr-ggplot2 et hop, je suis à même d’obtenir exactement le graphique que j’ai en tête…</small></p>
]]></content:encoded>
					
					<wfw:commentRss>https://perso.ens-lyon.fr/lise.vaudor/acp/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Géocodage sous R via une API</title>
		<link>https://perso.ens-lyon.fr/lise.vaudor/geocodage-sous-r-via-une-api/</link>
					<comments>https://perso.ens-lyon.fr/lise.vaudor/geocodage-sous-r-via-une-api/#comments</comments>
		
		<dc:creator><![CDATA[lvaudor]]></dc:creator>
		<pubDate>Mon, 09 Nov 2020 13:06:04 +0000</pubDate>
				<category><![CDATA[Tous les posts]]></category>
		<guid isPermaLink="false">http://perso.ens-lyon.fr/lise.vaudor/?p=1267</guid>

					<description><![CDATA[Géocodage via une API: was ist das? Géocodage Le géocodage d’abord: Il s’agit d’une opération qui consiste à associer des coordonnées géographiques à un nom de lieu ou une adresse. C’est donc une opération incontournable si vous disposez par exemple d’un jeu de données comprenant des lieux sous forme de chaînes de caractère, et que vous voudriez l’utiliser pour produire une carte. API Qu’est-ce qu’une API, maintenant: API cela veut.. <a href="https://perso.ens-lyon.fr/lise.vaudor/geocodage-sous-r-via-une-api/">Read More</a>]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" src="../../lise.vaudor/Rfigures/geocodage/Lise_Vaudor_headband-1.png" alt="" /></p>
<h1>Géocodage via une API: was ist das?</h1>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/geocodage/API.png" alt="" /></p>
<h2>Géocodage</h2>
<p>Le <strong>géocodage d’abord</strong>: Il s’agit d’une opération qui consiste à associer des <strong>coordonnées géographiques</strong> à un <strong>nom de lieu</strong> ou <strong>une adresse</strong>. C’est donc une opération incontournable si vous disposez par exemple d’un jeu de données comprenant des lieux sous forme de chaînes de caractère, et que vous voudriez l’utiliser pour produire une <strong>carte</strong>.</p>
<h2>API</h2>
<p>Qu’est-ce qu’une <strong>API</strong>, maintenant:</p>
<p><strong>API</strong> cela veut dire <strong>Application Programming Interface</strong>. C’est un service qui permet aux développeurs de récupérer des données via internet pour les utiliser dans leurs applications. Imaginez par exemple que, aiguillonné par la faim, vous vous rendiez sur un site de commande de repas en ligne pour commander un burgher. Pour que seuls s’affichent les restaurants qui peuvent vous livrer et faire en sorte de vous fournir un temps d’attente probable, les développeurs de ce site ont fait en sorte de récupérer votre position à partir de l’adresse postale que vous leur avez fournie. Cette opération se fait automatiquement, à travers une API de géocodage (celle de Google par exemple). Dans ce cas, on comprend bien pourquoi cela s’appelle une API: l’<strong>interface</strong> du service vous permet de récupérer des données, qui seront utilisées dans une <strong>autre application</strong> (ici le site de vente de burghers en livraison).</p>
<h2>J’en ai vraiment besoin?</h2>
<p>“Mais moi je suis pas développeur” me direz-vous peut-être. Effectivement, vous n’avez peut-être pas l’intention de construire un site web ou une application qui sollicitera régulièrement telle ou telle API. Mais sans développer une application à proprement parler vous pouvez tout-de-même avoir besoin de géocoder un certain nombre d’adresses de manière automatique… Dans ce cas vous aurez une utilisation d’API <strong>ponctuelle et limitée à un nombre fixe de requêtes</strong> (le nombre d’éléments que vous voulez géocoder pour compléter votre jeu de données)… ça tombe bien, souvent l’utilisation gratuite des API est limitée à un certain nombre de requêtes par jour ou seconde (ben oui parce que c’est un service, et un service c’est rarement gratuit, sauf peut-être si c’est un petit service).</p>
<p>Personnellement, les quelques fois où j’ai souhaité faire du géocodage, c’était dans le but d’exploiter les renseignements de <strong>localisation d’utilisateurs Twitter</strong>: ça signifiait géocoder des noms de lieux renseignés à des niveaux de précision et d’exactitude divers (par exemple “Quartier Beauregard, Trifouillis-les-Oies”, ou juste “France”, ou “Allemagne et USA”, ou encore “Je suis partout où le vent me porte”… cette rubrique des profils Twitter pouvant être renseignée -ou au contraire laissée vide- totalement librement). Je souhaitais récupérer non seulement la <strong>localisation (latitude-longitude)</strong> mais aussi des <strong>informations d’appartenance</strong> (à une ville, ou un pays) à l’échelle la plus fine possible selon le degré de précision avec lequel l’utilisateur avait spécifié sa localisation.</p>
<p>Il existe diverses <strong>API</strong> qui permettent de réaliser le géocodage de noms de lieux et de récupérer non seulement la localisation mais également divers renseignements. Dans ce billet, je parlerai de l’API de géocodage de <strong>Google</strong>, de l’API <strong>Opencage</strong>, et de l’API <strong>Nominatim</strong> d’OSM.</p>
<h2>Exemple</h2>
<p>Dans la suite de ce billet je testerai ces trois API pour collecter des informations sur les lieux suivants:</p>
<pre><code>mydf &lt;-tibble::tibble(loc=c("Lyon, France",
                            "22 place du Général de Gaulle, Paris",
                            "la Guillotière, Lyon",
                            "Europe",
                            NA,
                            "Tucson, AZ",
                            "Rio Grande do Sul"))
</code></pre>
<p>Pour l’exemple j’ai choisi des lieux désignés de façon plus ou moins vague, à des échelles variées et un peu partout dans le monde.</p>
<h1>Pour utiliser une API: montrez patte blanche!</h1>
<p>Pour accéder à une API, il est la plupart du temps de s’<strong>enregistrer</strong> auprès de son fournisseur afin de disposer d’une <strong>clé d’accès (API key)</strong>: une espèce de long mot de passe qui permet à l’API de vous identifier vous et d’identifier l’application pour laquelle la requête est passée.</p>
<h2>Nominatim (OSM)</h2>
<p>Pour accéder à cette API: bonne nouvelle! Nul besoin d’une clé :-). L’utilisation est en principe accordée pour un usage “créatif et inattendu”… Attention néanmoins à utiliser le service de manière “respectueuse” (ie ne pas envoyer 2000 requêtes en 5 minutes par exemple, pour ne pas surcharger les serveurs par des demandes inconsidérées). Plus de détails &#91;ici&#93; (<a href="https://operations.osmfoundation.org/policies/nominatim/" class="uri">https://operations.osmfoundation.org/policies/nominatim/</a>)</p>
<h2>Google</h2>
<p>Pour accéder à l’API de géocodage de google, il faut disposer d’un <strong>compte Google</strong> et aller récupérer une clé pour les “maps-APIs” Google <a href="https://console.cloud.google.com/google/maps-apis/">ici</a>. Il va falloir aussi renseigner une <strong>carte de crédit</strong>, même si vous ne pensez pas dépasser les quotas d’accès gratuit (ça ne fait pas trop plaisir mais sans ces “billing informations” la clé ne fonctionnera pas…).</p>
<p>La clé devrait ressembler à un truc sympa du genre: “BEiz89gzKNzlcpaK90ver80A_230Lli0N173kinvB” (c’est évidemment une fausse clé que j’indique ici <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> ).</p>
<p>Notez que si vous disposer d’une clé pour l’API Google, cela vous permettra aussi de disposer des fonds de carte lorsque vous utilisez ggmap pour faire vos cartes (voir billet de blog <a href="http://perso.ens-lyon.fr/lise.vaudor/par-ici-les-jolies-cartes-avec-ggmap/">ici</a> -billet que j’avais rédigé à une époque où une clé n’était pas encore nécessaire pour cela-)</p>
<h2>Opencage</h2>
<p>Pour accéder à l’API Opencage, vous pouvez vous enregistrer <a href="https://opencagedata.com/pricing">ici</a>. Pour une utilisation ponctuelle et limitée (2500 requêtes par jour max) vous n’aurez pas besoin de renseigner votre carte de crédit (ouf!).</p>
<p>Votre clé sera un truc du genre “6fjzlc8z2s6f113qx215zlk22ig1vq” (encore une fois, c’est une clé que j’ai inventée pour vous montrer l’allure de la chose <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> ).</p>
<h2>Où enregistrer vos clés d’accès aux API?</h2>
<p>Si vous travaillez avec R, il y a de fortes chances que vous soyez amené à <strong>partager vos scripts</strong> avec des collaborateurs ou même avec le monde (via github par exemple). C’est donc une <strong>mauvaise idée d’enregistrer vos clés dans vos scripts</strong> ou dans tout autre document que vous pourriez partager par inadvertance. Il vaut mieux aller les cacher dans un document aux tréfonds de votre machine, qui vous permette d’accéder à leurs valeurs sans risquer de les partager.</p>
<p>Une solution pour cela consiste à les enregistrer comme variable d’environnement dans R. Pour faire cela vous pouvez faire</p>
<pre><code>usethis::edit_r_environ()
</code></pre>
<p>ce qui va vous ouvrir le fichier .Renviron, où qu’il se trouve sur votre machine.</p>
<p>Ensuite, vous taperez les lignes suivantes (avec les bonnes clés bien sûr) dans ce fichier:</p>
<pre><code>GOOGLE_KEY="BEiz89gzKNzlcpaK90ver80A_230Lli0N173kinvB"
OPENCAGE_KEY="6fjzlc8z2s6f113qx215zlk22ig1vq"
</code></pre>
<p>Après <strong>enregistrement de .Renviron</strong> et <strong>réouverture de R</strong>, vous pourrez accéder aux valeurs de ces variables à l’aide des commandes <code>Sys.getenv("GOOGLE_KEY")</code> et <code>Sys.getenv("OPENCAGE_KEY")</code>.</p>
<h1>Comment ça fonctionne?</h1>
<p>Les requêtes envoyées aux API ressemblent à des URL un peu complexes de ce genre (ici pour rechercher “La Guillotière, Lyon” auprès de l’API de géocodage Google):</p>
<pre><code>"https://maps.googleapis.com/maps/api/geocode/json?address=Grande+Rue+de+la+Guilloti%C3%A8re,+Lyon&amp;key=BEiz89gzKNzlcpaK90ver80A_230Lli0N173kinvB"
</code></pre>
<p><small>{Au passage, notez que “URL” (pour “Uniform Resource Locator”) prend ici tout son sens…</small></p>
<p>On peut voir que cette URL correspond d’abord à l’“adresse” de l’API (<a href="https://maps.googleapis.com/maps/api/geocode/json" class="uri">https://maps.googleapis.com/maps/api/geocode/json</a>), ensuite à la requête elle-même suivie du paramètre “key” (address=Grande+Rue+de+la+Guilloti%C3%A8re,+Lyon&amp;key=BEiz89gzKNzlcpaK90ver80A_230Lli0N173kinvB ») dont la nature et les valeurs possibles sont documentées directement par le fournisseur des API :</p>
<ul>
<li>pour Nominatim (OSM), c’est <a href="https://nominatim.org/release-docs/develop/api/Search/">ici</a></li>
<li>pour Google, c’est <a href="https://developers.google.com/maps/documentation/geocoding/overview">ici</a></li>
<li>pour Opencage, c’est <a href="https://opencagedata.com/api">ici</a></li>
</ul>
<p>En principe, donc, on peut très bien construire cette URL nous-même, en étudiant bien la doc de chaque API, et obtenir la réponse à travers la commande <code>httr::GET()</code> qui permet de récupérer l’info correspondante par http.</p>
<p>La réponse obtenue (par exemple avec l’URL ci-dessus) ressemble généralement à quelque chose de ce genre:</p>
<pre><code>{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "Grande Rue de la Guillotière",
               "short_name" : "Grande Rue de la Guillotière",
               "types" : [ "route" ]
            },
            {
               "long_name" : "Lyon",
               "short_name" : "Lyon",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Rhône",
               "short_name" : "Rhône",
               "types" : [ "administrative_area_level_2", "political" ]
            },
            {
               "long_name" : "Auvergne-Rhône-Alpes",
               "short_name" : "Auvergne-Rhône-Alpes",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "France",
               "short_name" : "FR",
               "types" : [ "country", "political" ]
            }
         ],
         "formatted_address" : "Grande Rue de la Guillotière, Lyon, France",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 45.7553017,
                  "lng" : 4.8602422
               },
               "southwest" : {
                  "lat" : 45.7461895,
                  "lng" : 4.842601
               }
            },
            "location" : {
               "lat" : 45.7502745,
               "lng" : 4.8504236
            },
            "location_type" : "GEOMETRIC_CENTER",
            "viewport" : {
               "northeast" : {
                  "lat" : 45.7553017,
                  "lng" : 4.8602422
               },
               "southwest" : {
                  "lat" : 45.7461895,
                  "lng" : 4.842601
               }
            }
         },
         "place_id" : "ChIJefk7rWnq9EcRDacYDiq2NLA",
         "types" : [ "route" ]
      }
   ],
   "status" : "OK"
}
</code></pre>
<p>C’est un résultat qui correspond à un format <strong>json</strong> (on pourrait aussi l’avoir au format “list” R).</p>
<p>Il est ainsi possible de <strong>récupérer les éléments de réponse</strong> qui nous intéressent moyennant une petite “gymnastique” de manipulation de listes sous R.</p>
<p>Dans un cas (construction de l’URL) comme dans l’autre (récupération des données depuis la liste) néanmoins, cela exige un peu de travail.</p>
<p>C’est pour cela qu’il existe des <strong>API clients</strong> R, c’est-à-dire des packages qui visent à simplifier l’envoi de requêtes et la récupération de données pour les utilisateurs de R. La simplification intervient à deux niveaux:</p>
<ul>
<li>pour construire l’URL, les paramètres sont passés (de manière classique pour des habitués de R) comme <strong>valeurs d’arguments des fonctions</strong>. Par ailleurs, il y a souvent eu un “écrémage” des paramètres possibles pour ne garder que les plus importants aux yeux des développeurs de ces packages.</li>
<li>les résultats sont <strong>formattés</strong> d’une manière allégée et simplifiée pour des utilisateurs de R (par exemple sous forme de tableau plutôt que sous forme de liste).</li>
</ul>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/geocodage/API_2.png" alt="" /></p>
<h1>API clients opencage, mixr, tidygeocode</h1>
<p>Je vais ici vous montrer les API clients</p>
<ul>
<li><code>tidygeocoder</code> (qui interroge l’API <strong>Nominatim (OSM)</strong>)</li>
<li><code>opencage</code> (qui interroge l’API <strong>Opencage</strong>)</li>
<li><code>mixr</code> (qui interroge les API <strong>google</strong> et <strong>Opencage</strong>)</li>
</ul>
<h2>API OSM: package tidygeocoder</h2>
<p>Comme son nom l’indique le package <code>tidygeocoder</code> a en entrée et en sortie des données sous forme <strong>tidy</strong>, il est donc particulièrement agréable à utiliser pour tous les aficionados du tidyverse.</p>
<p>Il peut aussi récupérer les données depuis l’API UScensus (sa source par défaut) mais pour des noms de lieu hors USA ce n’est évidemment pas indiqué… Je précise donc <code>method="osm"</code> dans l’appel à la fonction <code>geocode()</code> de <code>tidygeocoder</code> ci-dessous:</p>
<pre><code>result_tidygeocoder=tidygeocoder::geocode(mydf,
                                          loc,
                                          method="osm")
result_tidygeocoder

## # A tibble: 7 x 3
##   loc                                    lat    long
##   &lt;chr&gt;                                &lt;dbl&gt;   &lt;dbl&gt;
## 1 Lyon, France                          45.8    4.83
## 2 22 place du Général de Gaulle, Paris  NA     NA   
## 3 la Guillotière, Lyon                  45.8    4.84
## 4 Europe                                51     10   
## 5 &lt;NA&gt;                                  NA     NA   
## 6 Tucson, AZ                            32.2 -111.  
## 7 Rio Grande do Sul                    -29.8  -53.8
</code></pre>
<p>On peut également récupérer plus d’infos que simplement celles de latitude-longitude. Pour cela, il faut préciser l’argument <code>full_results=TRUE</code></p>
<pre><code>result_tidygeocoder_full=tidygeocoder::geocode(mydf,
                                               loc,
                                               method="osm",
                                               full_results=TRUE)
colnames(result_tidygeocoder_full)

##  [1] "loc"          "lat"          "long"         "place_id"     "licence"      "osm_type"     "osm_id"       "boundingbox"  "display_name" "class"        "type"         "importance"   "icon"
</code></pre>
<p>Pour en savoir plus sur ce package vous pouvez consulter <a href="https://www.r-bloggers.com/2019/11/geocoding-with-tidygeocoder/">cette page</a></p>
<h2>API Google/Opencage: package mixr</h2>
<p><code>mixr</code>, c’est un petit package “maison” que je me suis fait pour pouvoir réexploiter plus facilement un certain nombre de fonctions que je m’étais créées pour travailler avec des données Twitter. Il est encore en développement mais il est d’ores et déjà possible de l’installer depuis github <a href="https://github.com/lvaudor/mixr">ici</a> si vous le souhaitez. En termes de géocodage, il permet de récupérer des données depuis l’API Google et depuis l’API Opencage.</p>
<p>Pour cette deuxième option (API Opencage) il s’appuie très largement sur un autre package R: <code>opencage</code> voir <a href="https://github.com/ropensci/opencage">ici</a>. Son avantage principal par rapport à la fonction <code>opencage::opencage_forward()</code> est qu’il permet de géocoder plusieurs noms de lieux à la fois. Il s’agit apparemment d’une chose que les développeurs d’<code>opencage</code> ont préféré ne pas implémenter directement pour diverses raisons, l’une d’entre elles étant que les utilisateurs risquaient d’utiliser le service de manière immodérée: j’ai donc fait en sorte que dans la fonction <code>mixr::tidy_geocode(method="opencage")</code> chaque envoi de requête prenne a minima 1 seconde…</p>
<h2>Appel de la fonction tidy_geocode() pour l’API Google:</h2>
<pre><code>result_mixr_google=mixr::tidy_geocode(mydf,
                                      location=loc,
                                      method="google",
                                      info=c("lat","lng","country"))
result_mixr_google

## # A tibble: 7 x 4
##   stringlocation                         lat     lng country      
##   &lt;chr&gt;                                &lt;dbl&gt;   &lt;dbl&gt; &lt;chr&gt;        
## 1 Lyon, France                          45.8    4.84 France       
## 2 22 place du Général de Gaulle, Paris  48.9    2.43 France       
## 3 la Guillotière, Lyon                  45.8    4.84 France       
## 4 Europe                                54.5   15.3  &lt;NA&gt;         
## 5 &lt;NA&gt;                                  NA     NA    &lt;NA&gt;         
## 6 Tucson, AZ                            32.2 -111.   United States
## 7 Rio Grande do Sul                    -30.0  -51.2  Brazil
</code></pre>
<h2>Appel de la fonction tidy_geocode() pour l’API Opencage:</h2>
<pre><code>result_mixr_opencage=mixr::tidy_geocode(mydf,
                                        location=loc,
                                        method="opencage",
                               info=c("lat","lng","components.country_code"))

## Warning: `tbl_df()` is deprecated as of dplyr 1.0.0.
## Please use `tibble::as_tibble()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_warnings()` to see where this warning was generated.

result_mixr_opencage

## # A tibble: 37 x 4
##    stringlocation   lat     lng components.country_code
##    &lt;chr&gt;          &lt;dbl&gt;   &lt;dbl&gt; &lt;fct&gt;                  
##  1 Lyon, France    45.8  4.83   fr                     
##  2 Lyon, France    45.7  4.74   fr                     
##  3 Lyon, France    44.1  0.0135 fr                     
##  4 Lyon, France    46.6 -1.38   fr                     
##  5 Lyon, France    46.5 -1.34   fr                     
##  6 Lyon, France    45.7  4.74   fr                     
##  7 Lyon, France    46.7 -1.25   fr                     
##  8 Lyon, France    48.9  2.32   fr                     
##  9 Lyon, France    45.7  4.83   fr                     
## 10 Lyon, France    50.5  2.50   fr                     
## # … with 27 more rows
</code></pre>
<p>Pour l’une comme pour l’autre, vous pouvez consulter l’<strong>aide des fonctions</strong> pour voir quelles sont les infos que vous pouvez espérer obtenir…</p>
<h2>Citation</h2>
<p>Merci de citer ce billet de la manière suivante:</p>
<p>Vaudor L (2020). “Géocodage sous R via une API.” <em>R-atique: Analyse de données avec R</em>. <url: <a href="http://perso.ens-lyon.fr/lise.vaudor/geocodage-sous-r-via-une-api/" class="uri">http://perso.ens-lyon.fr/lise.vaudor/geocodage-sous-r-via-une-api/>.</url:></p>
<p>(<span class="citeproc-not-found"
data-reference-id="Misc"><strong>???</strong></span>){vaudor_geocodage, author = {Lise Vaudor}, title = {Géocodage sous R via une API}, month = {nov}, year = {2020}, journal = {R-atique: Analyse de données avec R}, type = {blog}, url = {<a href="http://perso.ens-lyon.fr/lise.vaudor/geocodage-sous-r-via-une-api/" class="uri">http://perso.ens-lyon.fr/lise.vaudor/geocodage-sous-r-via-une-api/</a>}, }</p>
]]></content:encoded>
					
					<wfw:commentRss>https://perso.ens-lyon.fr/lise.vaudor/geocodage-sous-r-via-une-api/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Utiliser un package</title>
		<link>https://perso.ens-lyon.fr/lise.vaudor/utiliser-un-package/</link>
					<comments>https://perso.ens-lyon.fr/lise.vaudor/utiliser-un-package/#respond</comments>
		
		<dc:creator><![CDATA[lvaudor]]></dc:creator>
		<pubDate>Wed, 07 Oct 2020 09:13:19 +0000</pubDate>
				<category><![CDATA[Tous les posts]]></category>
		<guid isPermaLink="false">http://perso.ens-lyon.fr/lise.vaudor/?p=1252</guid>

					<description><![CDATA[Qu’est-ce qu’un package ? Un package est un ensemble de fonctions documentées visant à la réalisation d’une tâche particulière. En poursuivant cette série de tutoriels vous serez notamment amenés à travailler avec le package dplyr qui vise à réaliser un ensemble d’opérations et de manipulations de base sur les tableaux de données, et le package ggplot2 qui vise à produire des graphiques en s’appuyant sur les principes de la grammaire.. <a href="https://perso.ens-lyon.fr/lise.vaudor/utiliser-un-package/">Read More</a>]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/Lise_Vaudor_headband-1.png" alt="" /></p>
<h1>Qu’est-ce qu’un package ?</h1>
<p>Un package est un <strong>ensemble de fonctions</strong> documentées visant à la <strong>réalisation d’une tâche particulière</strong>.</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/package_opened.png" alt="" /></p>
<p>En poursuivant cette série de tutoriels vous serez notamment amenés à travailler avec le package <code>dplyr</code> qui vise à réaliser un ensemble d’opérations et de manipulations de base sur les tableaux de données, et le package <code>ggplot2</code> qui vise à produire des graphiques en s’appuyant sur les principes de la grammaire des graphiques.</p>
<h1>Installation vs chargement</h1>
<p><strong>INSTALLATION</strong></p>
<p>L’installation d’un package consiste à <strong>télécharger les codes du package sur l’ordi</strong>.</p>
<p>Cette étape nécessite que vous téléchargiez l’ensemble des fichiers contenant le code du package sur votre ordi. De ce fait, c’est une étape qui nécessite que vous ayiez <strong>accès à internet</strong>… Par contre, vous n’avez besoin de réaliser cette installation <strong>une seule fois</strong> (tant que vous ne changez pas d’ordi, ou que vous n’avez pas besoin de mettre à jour le package par exemple).</p>
<p>Installer un package, c’est un peu comme ramener le carton d’outils de cuisine chez soi et les ranger dans le placard, cf illustration ci-dessous…</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/package_cuisine_installe.png" width="300" /></p>
<p>L’installation d’un package se fait généralement à l’aide de la commande:</p>
<pre><code>install.packages("dplyr")
</code></pre>
<p>Vous pouvez également effectuer cette installation à partir de l’outil “Packages” dans RStudio.</p>
<p><strong>CHARGEMENT</strong></p>
<p>Le chargement consiste à <strong>préparer R à l’utilisation des fonctions du package</strong> (en les appelant par leur nom).</p>
<p><strong>A chaque fois (ou presque) que vous utiliserez un package</strong> (i.e. pour chacune de vos sessions de travail avec ce package), vous aurez besoin de le <strong>charger</strong>. Le chargement d’un package permet en effet à R d’ajouter les noms de ses fonctions à son “répertoire” et donc d’aller chercher le code correspondant où il se doit.</p>
<p>Charger un package, c’est un peu l’équivalent de sortir les outils du placard de sorte qu’ils soient prêts à servir… cf illustration ci-dessous.</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/package_cuisine_charge.png" width="300" /></p>
<p>Vous pouvez charger un package de la manière suivante:</p>
<pre><code>library(dplyr)
</code></pre>
<h1>Espace de nommage, désambiguation</h1>
<p>Chaque package est associé à un <strong>espace de noms</strong> (namespace) qui correspond à l’ensemble des noms de fonctions qui le composent.</p>
<p>Un <strong>même nom</strong> peut correspondre à <strong>plusieurs fonctions</strong>, issues de <strong>packages différents</strong>.</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/package_desambiguation.png" width="400" /></p>
<p>Si ces packages sont installés et chargés pour une même session de travail, il est recommandé (voire indispensable) d’<strong>écrire explicitement à quel espace de noms on fait référence</strong> à l’aide de la notation <em>nomdupackage::nomdelafonction</em>…</p>
<pre><code>library(stats)
library(dplyr)

## 
## Attaching package: 'dplyr'

## The following objects are masked from 'package:stats':
## 
##     filter, lag

## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union

starwars %&gt;% filter(starwars,species=="Human")

## Error: Problem with `filter()` input `..1`.
## x Input `..1$name` must be a logical vector, not a character.
## &#x2139; Input `..1` is `starwars`.
</code></pre>
<h1>Vie et maintien d’un package</h1>
<p>Un package n’est pas définitivement figé au moment de sa création (ou de son dépôt sur le CRAN par exemple).</p>
<p>Il est <strong>amené à évoluer</strong>, en lien avec, par exemple, les <strong>demandes des utilisateurs</strong>, les <strong>ajouts ou modifications des contributeurs</strong>, les modifications rendues nécessaires par les <strong>changements de version des autres packages</strong> (dont il dépend) ou de <strong>R lui-même</strong>.</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/life_of_a_package_with_legend.png" alt="" /></p>
<p>En effet, un package est construit sur la base de codes R préexistants, mais également en se basant sur des packages, basés sur des packages, basés sur des packages… Ces packages constituent ce qu’on appelle les <strong>dépendances</strong>.</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/package_dependances.png" width="300" /></p>
<h1>Qualité d’un package</h1>
<p>La <strong>“qualité” d’un package</strong> peut recouvrir de nombreuses notions, parmi lesquelles:</p>
<ul>
<li>le fait que le <strong>code fonctionne</strong>, et soit robuste (à de légers changements dans les types de données entrées par exemple).</li>
<li>le fait que le <strong>code soit bien documenté</strong>, de sorte que l’utilisateur comprenne comment utiliser une fonction et à quoi correspond le résultat en sortie.</li>
<li>le fait que les <strong>traitements réalisés soient corrects</strong> (par exemple qu’un algorithme soit juste, qu’un test soit correct d’un point de vue statistique etc.) et corresponde bien au résultat escompté par l’utilisateur. <!-- Pour un package en cours de développement (installable depuis un repo github par exemple) il n'y a **aucune assurance de qualité** (autre que la confiance éventuelle que vous pouvez accorder à son auteur!). --></li>
</ul>
<p><!-- Pour un package **déposé sur le CRAN** (Comprehensive R Archive Network), l'**existence d'une documentation** et le **bon fonctionnement du code** sont assurés. --></p>
<p><!-- Quant à la **qualité et l'exactitude scientifique des codes** d'un package, elles ne sont en général pas garanties à proprement parler, sauf si le package fait l'objet d'une évaluation (par exemple via la publication d'un article -par exemple dans le *Journal of Statistical Software* ou sa "labellisation" par des organismes comme ROpenSci par exemple).  --></p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/package_qualite.png" width="400" /></p>
<ul>
<li>Qualité du code => qualité du matériel, de l’instrumentation</li>
<li>Qualité de la méthode => on obtient bien le produit escompté</li>
<li>Qualité de la doc => les instructions sont claires!</li>
</ul>
<h1>Des fonctions, de la documentation</h1>
<p>Pour obtenir de l’aide sur une fonction (installée, peut-être non chargée):</p>
<pre><code>??nomfonction
</code></pre>
<p>Pour obtenir de l’aide sur une fonction (installée et chargée):</p>
<pre><code>?nomfonction
help(nomfonction)
</code></pre>
<p>Pour obtenir la liste de la doc relative à un package:</p>
<pre><code>help(package="dplyr")
</code></pre>
<p>=> liste des fonctions, des vignettes, etc.</p>
<h1>Documentation simplifiée: vignettes</h1>
<p>Les vignettes sont des documents qui aident à <strong>prendre en main un package</strong> en identifiant ses <strong>fonctions les plus importantes</strong>, et en montrant <strong>un ou plusieurs cas d’usage</strong>.</p>
<p>Tous les packages ne font pas (hélas!) l’objet de vignettes!…</p>
<p>Pour lister les vignettes relatives à un package (par ex. dplyr):</p>
<pre><code>vignette(package="dplyr")

Vignettes in package ‘dplyr’:

colwise                colwise (source, html)
compatibility          dplyr compatibility (source, html)
base                   From base R to dplyr (source, html)
grouping               Grouped data (source, html)
dplyr                  Introduction to dplyr (source, html)
programming            Programming with dplyr (source, html)
rowwise                rowwise (source, html)
two-table              Two-table verbs (source, html)
window-functions       Window functions (source, html)
</code></pre>
<p>Pour visualiser une vignette donnée:</p>
<pre><code>vignette("colwise", package="dplyr") # dans RStudio
RShowDoc("colwise", package="dplyr") # dans le navigateur web
</code></pre>
<p>Les <strong>cheatsheets</strong> (ou antisèches) sont des documents visant à <strong>résumer de manière graphique</strong> la fonction et l’usage d’un package.</p>
<p>Tous les packages ne font pas (hélas, encore!) l’objet d’une cheatsheet. Les plus utiles sont listées ici:</p>
<p>(<a href="https://rstudio.com/resources/cheatsheets/" class="uri">https://rstudio.com/resources/cheatsheets/</a>)</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/exemple_cheatsheet.png" alt="" /></p>
<h1>Des problèmes d’installation?</h1>
<p>Ce n’est pas parce que vous avez des <strong>messages/ des warnings/ du rouge</strong> dans votre console que vous avez eu un problème d’installation…</p>
<p>La preuve:</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/install_changepoint.png" alt="" /></p>
<p>Le package a bien été installé!</p>
<p>Par contre, là, oui, l’installation <strong>n’a pas pu aboutir</strong>:</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/install_magick.png" alt="" /></p>
<p>Ici en l’occurrence, j’ai besoin d’installer magick sur ma machine (en dehors de R) avant d’installer le package R magick…</p>
<p>Parmi les <strong>problèmes classiques</strong> (et faciles à résoudre) qu’on peut rencontrer lors de l’installation, on peut citer:</p>
<ul>
<li>l’<strong>absence de connection internet</strong></li>
<li>l’<strong>absence de guillemets</strong> autour du nom de package dans l’appel à la fonction install.packages() (eh oui des fois ça coince pour des bêtises…)</li>
<li>une <strong>mauvaise orthographe</strong> du nom de package</li>
</ul>
<p>Illustration:</p>
<pre><code>install.packages("dplyr") #j'ai coupé internet

## Installing package into '/home/lvaudor/R/x86_64-pc-linux-gnu-library/3.6'
## (as 'lib' is unspecified)

install.packages(dplyr)

## Error in install.packages(dplyr): objet 'dplyr' introuvable

install.packages("deplyr")

## Installing package into '/home/lvaudor/R/x86_64-pc-linux-gnu-library/3.6'
## (as 'lib' is unspecified)

## Warning: package 'deplyr' is not available (for R version 3.6.3)
</code></pre>
<p>Les problèmes d’installation sont relativement souvent liés à un problème dans l’installation des dépendances:</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/install_golem_pb.png" alt="" /></p>
<p>Dans ce cas cela peut être une bonne idée d’<strong>installer la dépendance “qui coince” en premier</strong> (dans l’exemple ci-dessus xml2), puis retenter l’installation du package…</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_pour_users/package_dependances_install_pb.png" width="300" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://perso.ens-lyon.fr/lise.vaudor/utiliser-un-package/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Janitor: nettoie-moi cette table (et qu&#8217;elle brille!)</title>
		<link>https://perso.ens-lyon.fr/lise.vaudor/janitor-nettoie-moi-cette-table-et-que-ca-brille/</link>
					<comments>https://perso.ens-lyon.fr/lise.vaudor/janitor-nettoie-moi-cette-table-et-que-ca-brille/#respond</comments>
		
		<dc:creator><![CDATA[lvaudor]]></dc:creator>
		<pubDate>Thu, 11 Jun 2020 16:33:21 +0000</pubDate>
				<category><![CDATA[Tous les posts]]></category>
		<guid isPermaLink="false">http://perso.ens-lyon.fr/lise.vaudor/?p=1234</guid>

					<description><![CDATA[Chers lecteurs, bonjour! Aujourd’hui, je vais vous parler du package janitor, un package qui comprend notamment (mais pas seulement) un certain nombre de fonctions pour améliorer vos tableaux de contingence. En Anglais, “janitor” veut dire (plus ou moins) “homme à tout faire”. Et en effet, outre les tâches liées à la mise en forme de ces tableaux, le package janitor vise à prendre en charge pour vous un certain nombre.. <a href="https://perso.ens-lyon.fr/lise.vaudor/janitor-nettoie-moi-cette-table-et-que-ca-brille/">Read More</a>]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" src="../../lise.vaudor/Rfigures/Janitor/Lise_Vaudor_headband-1.png" alt="" /></p>
<p>Chers lecteurs, bonjour!</p>
<p>Aujourd’hui, je vais vous parler du package <code>janitor</code>, un package qui comprend notamment (mais pas seulement) un certain nombre de fonctions pour <strong>améliorer vos tableaux de contingence</strong>. En Anglais, “janitor” veut dire (plus ou moins) “homme à tout faire”. Et en effet, outre les tâches liées à la mise en forme de ces tableaux, le package <code>janitor</code> vise à prendre en charge pour vous un <strong>certain nombre de tâches aussi variées que pénibles</strong>…</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Janitor/logo_small.png" alt="" /></p>
<p>Jetons un coup d’oeil à l’ensemble des fonctions comprises dans ce package (je fais ça à l’aide de mon package flowrpowr (<a href="http://perso.ens-lyon.fr/lise.vaudor/certains-packages-sont-comme-des-fleurs/" class="uri">http://perso.ens-lyon.fr/lise.vaudor/certains-packages-sont-comme-des-fleurs/</a>):</p>
<pre><code>library(janitor)
library(flowrpowr)
flowrpowr::flowr_package("janitor")
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Janitor/unnamed-chunk-2-1.png" alt="" /></p>
<h1>Opérations sur les tables de contingences</h1>
<p>Les éléments apparaissant ci-dessous sont ceux relatifs aux <strong>tables de contingence</strong> (fonctions <code>tabyl</code> et consorts, fonctions de type <code>adorn_xxx()</code> &#8211;<code>adorn_title()</code>,<code>adorn_ns()</code>,<code>adorn_rounding()</code>,etc.-). Les autres fonctions sont toutes celles qui réalisent des opérations sur les données (en général, mais pas seulement, en lien avec le nettoyage de tableaux).</p>
<pre><code>flowrpowr::flowr_package("janitor", element=c("adorn","tabyl"))
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Janitor/unnamed-chunk-3-1.png" alt="" /></p>
<p>La fonction <code>tabyl()</code> est, en quelque sorte, l’équivalent (amélioré) de la fonction <code>table()</code>, qui compte des <strong>effectifs par classe</strong>. Mais là où <code>table()</code> travaille sur des vecteurs (ou facteurs), <code>tabyl()</code> prend <strong>pour premier argument un tableau de données</strong>. C’est peut-être un détail pour vous, mais en fait ça veut dire beaucoup: c’est le signe que le package <code>janitor</code> est “pipe-compatible” (et donc “dplyr-compatible”) (puisque le premier argument des fonctions est un jeu de données, on peut enchaîner les opérations à l’aide des “pipes” <code>%&gt;%</code>).</p>
<p>Voyez plutôt:</p>
<pre><code>tabyl(mtcars,cyl)  # en appel "classique"

##  cyl  n percent
##    4 11 0.34375
##    6  7 0.21875
##    8 14 0.43750

mtcars %&gt;%
  tabyl(cyl) # en appel "pipé"

##  cyl  n percent
##    4 11 0.34375
##    6  7 0.21875
##    8 14 0.43750
</code></pre>
<p>Remarquez en outre que, pour une variable, <code>tabyl()</code> vous affiche diligemment les <strong>proportions</strong> (<code>percent</code>) en plus des effectifs (<code>n</code>).</p>
<p>Comme <code>table()</code>, <code>tabyl()</code> sait aussi compter des effectifs croisés:</p>
<pre><code>mtcars %&gt;% 
  tabyl(cyl,am)

##  cyl  0 1
##    4  3 8
##    6  4 3
##    8 12 2
</code></pre>
<p>L’ensemble des fonctions <code>adorn_xxx()</code> vise à <strong>mettre en forme les tableaux d’effectifs</strong> produits par <code>tabyl()</code>.</p>
<p>On peut par exemple rajouter une <strong>colonne correspondant aux effectifs totaux</strong>:</p>
<pre><code>tab=mtcars %&gt;%
  tabyl(gear, cyl) %&gt;%
  adorn_totals("col")
tab

##  gear 4 6  8 Total
##     3 1 2 12    15
##     4 8 4  0    12
##     5 2 1  2     5
</code></pre>
<p>On peut afficher les <strong>pourcentages</strong> plutôt que les effectifs (ici <strong>pourcentages par ligne</strong>)</p>
<pre><code>tab=tab %&gt;%
  adorn_percentages("row")
tab

##  gear          4         6   8 Total
##     3 0.06666667 0.1333333 0.8     1
##     4 0.66666667 0.3333333 0.0     1
##     5 0.40000000 0.2000000 0.4     1
</code></pre>
<p>On peut <strong>limiter le nombre de digits</strong> dans l’affichage:</p>
<pre><code>tab=tab %&gt;% 
  adorn_pct_formatting(digits=2)
tab

##  gear      4      6      8   Total
##     3  6.67% 13.33% 80.00% 100.00%
##     4 66.67% 33.33%  0.00% 100.00%
##     5 40.00% 20.00% 40.00% 100.00%
</code></pre>
<p>On peut afficher, en plus des pourcentages, les effectifs:</p>
<pre><code>tab=tab %&gt;% 
  adorn_ns()
tab

##  gear          4          6           8        Total
##     3  6.67% (1) 13.33% (2) 80.00% (12) 100.00% (15)
##     4 66.67% (8) 33.33% (4)  0.00%  (0) 100.00% (12)
##     5 40.00% (2) 20.00% (1) 40.00%  (2) 100.00%  (5)
</code></pre>
<p>On peut rajouter le nom de la deuxième variable:</p>
<pre><code>tab=tab %&gt;% 
  adorn_title()
tab

##              cyl                                    
##  gear          4          6           8        Total
##     3  6.67% (1) 13.33% (2) 80.00% (12) 100.00% (15)
##     4 66.67% (8) 33.33% (4)  0.00%  (0) 100.00% (12)
##     5 40.00% (2) 20.00% (1) 40.00%  (2) 100.00%  (5)
</code></pre>
<p>Pour en savoir plus sur les fonctionnalités des “tabyls”, vous pouvez aller voir la vignette fournie par les auteurs de <code>janitor</code> (vous pouvez l’ouvrir en faisant <code>vignette("tabyls")</code> dans votre console une fois que vous avez installé le package).</p>
<h1>Nettoyage de tableaux de données</h1>
<p>Je ne vais pas aborder l’ensemble des autres fonctions de <code>janitor</code>, mais, pour aller à l’essentiel, disons que ces fonctions réalisent quelques tâches “de routine” pour nettoyer les tableaux de données. Par exemple:</p>
<pre><code>flowrpowr::flowr_package("janitor",element=c("compare|remove|clean|^round"))
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Janitor/unnamed-chunk-11-1.png" alt="" /></p>
<ul>
<li>
<p>les fonctions <code>remove_xxx()</code> <strong>retirent</strong> les <strong>colonnes qui contiennent une valeur constante</strong> (<code>remove_constant()</code>), ou les <strong>colonnes ou lignes complètement vides</strong> (<code>remove_empty_cols()</code>,<code>remove_empty_rows()</code>)</p>
</li>
<li>
<p>les fonctions <code>compare_df_cols...()</code> <strong>comparent les colonnes de deux tableaux</strong> (<code>compare_df_cols()</code>) et déterminent si, en l’état ils peuvent être “recollés” en semble par une opération de type <code>bind_rows()</code> ou <code>rbind()</code> (<code>compare_df_cols_same()</code>)</p>
</li>
</ul>
<p>-les fonctions <code>round_xxx()</code> constituent des améliorations de la fonction <code>round()</code> consistant à <strong>arrondir de manière systématique</strong> vers le haut les valeurs (<code>round_half_up()</code>) ou à arrondir à une fraction près (<code>round_to_fraction()</code>)</p>
<ul>
<li>les fonctions <code>...clean_names()</code> permettent de <strong>nettoyer des noms</strong> (<code>make_clean_names()</code>) et notamment les <strong>noms de colonnes des tableaux</strong> (<code>clean_names()</code>). C’est, je pense, cette fonction <code>clean_names()</code> que j’utilise le plus fréquemment dans le package <code>janitor</code>. <small> Si vous aussi vous êtes amenés à travailler avec des tableaux dont les noms de colonnes sont à coucher dehors, vous comprendrez pourquoi…</small> Admirez plutôt:</li>
</ul>
<p><!-- --></p>
<pre><code>tib=tibble("TempérDegCelsius"=NA,
       "précipit (mm/24h)"=NA,
       "succès_prob(%)"=NA,
       "Fiabilité.Estim"=NA) 
tib

## # A tibble: 1 x 4
##   TempérDegCelsius `précipit (mm/24h)` `succès_prob(%)` Fiabilité.Estim
##   &lt;lgl&gt;            &lt;lgl&gt;               &lt;lgl&gt;            &lt;lgl&gt;          
## 1 NA               NA                  NA               NA

tib %&gt;% clean_names()

## # A tibble: 1 x 4
##   temper_deg_celsius precipit_mm_24h succes_prob_percent fiabilite_estim
##   &lt;lgl&gt;              &lt;lgl&gt;           &lt;lgl&gt;               &lt;lgl&gt;          
## 1 NA                 NA              NA                  NA
</code></pre>
<p>A partir de noms de colonnes très hétérogènes et comprenant un certain nombre de caractères spéciaux, la fonction <code>clean_names()</code> produit des noms homogènes et commodes à utiliser dans R. Par défaut, la casse est de type “serpent” (<code>case="snake"</code>): tous les mots sont écrits en minuscule, séparés par un underscore <code>_</code>. Alternativement, et si telle est votre habitude, vous pouvez demander à ce que vos noms de variables soient en casse “petit chameau”, “grand chameau” ou “serpent criard”, etc., etc. (j’adore ces dénominations :-)…).</p>
<pre><code>tib %&gt;% clean_names(case="small_camel")

## # A tibble: 1 x 4
##   temperDegCelsius precipitMm24H succesProbPercent fiabiliteEstim
##   &lt;lgl&gt;            &lt;lgl&gt;         &lt;lgl&gt;             &lt;lgl&gt;         
## 1 NA               NA            NA                NA

tib %&gt;% clean_names(case="big_camel")

## # A tibble: 1 x 4
##   TemperDegCelsius PrecipitMm24H SuccesProbPercent FiabiliteEstim
##   &lt;lgl&gt;            &lt;lgl&gt;         &lt;lgl&gt;             &lt;lgl&gt;         
## 1 NA               NA            NA                NA

tib %&gt;% clean_names(case="screaming_snake")

## # A tibble: 1 x 4
##   TEMPER_DEG_CELSIUS PRECIPIT_MM_24H SUCCES_PROB_PERCENT FIABILITE_ESTIM
##   &lt;lgl&gt;              &lt;lgl&gt;           &lt;lgl&gt;               &lt;lgl&gt;          
## 1 NA                 NA              NA                  NA
</code></pre>
<h2>Citation</h2>
<p>Merci de citer ce billet de la manière suivante:</p>
<pre><code>## Vaudor L (2020). "Janitor: nettoie-moi cette table (et qu'elle brille!)." _R-atique: Analyse de données avec R_. &lt;URL: http://perso.ens-lyon.fr/lise.vaudor/janitor-nettoie-moi-cette-table-et-que-ca-brille/&gt;.

## @Misc{vaudor_janitor,
##   author = {Lise Vaudor},
##   title = {Janitor: nettoie-moi cette table (et qu'elle brille!)},
##   month = {jun},
##   year = {2020},
##   journal = {R-atique: Analyse de donnÃ©es avec R},
##   type = {blog},
##   url = {http://perso.ens-lyon.fr/lise.vaudor/janitor-nettoie-moi-cette-table-et-que-ca-brille/},
## }
</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://perso.ens-lyon.fr/lise.vaudor/janitor-nettoie-moi-cette-table-et-que-ca-brille/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Jamais sans ces packages!</title>
		<link>https://perso.ens-lyon.fr/lise.vaudor/jamais-sans-ces-packages/</link>
					<comments>https://perso.ens-lyon.fr/lise.vaudor/jamais-sans-ces-packages/#comments</comments>
		
		<dc:creator><![CDATA[lvaudor]]></dc:creator>
		<pubDate>Wed, 11 Mar 2020 08:46:28 +0000</pubDate>
				<category><![CDATA[Tous les posts]]></category>
		<guid isPermaLink="false">http://perso.ens-lyon.fr/lise.vaudor/?p=1200</guid>

					<description><![CDATA[Quand quelqu’un vient me demander des conseils pour débuter, ou effectuer une tâche particulière sous R, une des premières choses que je fais (outre lui conseiller la lecture de mon blog, bien sûr -rire machiavélique-) est de l’aiguiller sur quelques packages que je juge incontournables. En effet, s’il existe des points d’entrée plus généraux dans l’usage de R, avoir quelques points de repère quant aux packages qui simplifient vraiment son.. <a href="https://perso.ens-lyon.fr/lise.vaudor/jamais-sans-ces-packages/">Read More</a>]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/Lise_Vaudor_headband-1.png" alt="" /></p>
<p>Quand quelqu’un vient me demander des <strong>conseils pour débuter</strong>, ou <strong>effectuer une tâche particulière</strong> sous R, une des premières choses que je fais (outre lui conseiller la lecture de mon blog, bien sûr -rire machiavélique-) est de l’aiguiller sur <strong>quelques packages que je juge incontournables</strong>. En effet, s’il existe des points d’entrée plus généraux dans l’usage de R, avoir quelques points de repère quant aux packages qui simplifient vraiment son usage permet de gagner du temps dans son apprentissage en limitant l’étendue des possibles (dans un premier temps tout du moins!).</p>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/packages_indispensables.png" /></h2>
<p>A toutes fins utiles, donc, voici la <strong>liste de mes incontournables</strong>. Il va sans dire que c’est une liste qui est susceptible d’évoluer, non seulement au gré de mes apprentissages, mais aussi au gré des développements de R! D’ailleurs, si vous avez vous-même des packages chouchous que vous n’y voyez pas, n’hésitez pas à me l’indiquer en commentaire!!</p>
<h2>Manipulation de données</h2>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_dplyr.png" width="100" /> <code>dplyr</code>: manipulation des tableaux de données</h2>
<p>Je l’utilise pour tout ce qui est <strong>opération sur les tableaux</strong> (c’est-à-dire, tout le temps: quel que soit la nature de mon projet, il implique, à un moment ou un autre, de manipuler un tableau). D’ailleurs, j’avais déjà écrit un billet sur ce package <a href="http://perso.ens-lyon.fr/lise.vaudor/dplyr/">ici</a> (sélectionner des colonnes, filtrer des lignes, faire des tris, faire des regroupements) et <a href="http://perso.ens-lyon.fr/lise.vaudor/combinaisons-et-jointures-de-tables-avec-dplyr/">là</a> (réaliser des jointures).</p>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_tidyr.png" width="100" /> <code>tidyr</code>: restructuration des tableaux de données</h2>
<p>J’utilise <code>tidyr</code> de manière moins systématique, mais il réapparaît tout de même assez régulièrement dans mes scripts pour deux raisons en particulier:</p>
<ul>
<li>les <strong>pivots</strong>, réalisés à l’aide des fonctions <code>gather()</code> et <code>spread()</code> (désormais remplacées par les plus explicites <code>pivot_longer()</code> et <code>pivot_wider()</code>, respectivement) pour modifier la structure des données. J’avais écrit un paragraphe sur ces fonctions à la fin de <a href="http://perso.ens-lyon.fr/lise.vaudor/nettoyer-et-structurer-ses-donnees/">ce billet</a>. Vous pouvez aller voir le très bon billet de ThinkR sur le sujet <a href="https://thinkr.fr/manipuler-ses-donnees-avec-tidyr-ou-tout-ce-que-vous-voulez-savoir-sur-le-pivot/">ici</a>.</li>
<li>les fonctions <code>nest()</code> et <code>unnest()</code> pour créer des listes-colonnes de jeux de données (une fonctionnalité que j’utilise souvent en conjonction avec le package <code>purrr</code> et la programmation fonctionnelle)</li>
</ul>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_readr.png" width="100" /> <code>readr</code>: lecture des tableaux de données</h2>
<p>Pour lire des tableaux de données depuis des fichiers .csv ou .txt, j’utilise le plus souvent le package <code>readr</code>. Pour vous dire toute la vérité, même: la plupart du temps, si je constate que le fichier que j’essaie d’importer est un peu “spécial”, j’utilise la fonctionnalité “Import Dataset” de RStudio pour explorer les options et me générer la ligne de commande ad hoc (“bouh! la tricheuse!” entends-je certains se récrier dans l’audience), et c’est cette fonctionnalité qui (le plus souvent) me suggère l’usage de <code>readr</code>…</p>
<h1>Manipulation de données particulières</h1>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_stringr.png" width="100" /> <code>stringr</code>: Manipulation de chaînes de caractères</h2>
<p>Pour tout ce qui est <strong>manipulation de chaînes de caractères</strong> (qui vont au-delà de <code>paste0()</code>), j’utilise le package <code>stringr</code>. J’avais déjà écrit un billet de blog sur ce package <a href="http://perso.ens-lyon.fr/lise.vaudor/manipuler-des-strings-avec-r/">ici</a> ainsi qu’un billet le complétant sur le sujet des expressions régulières <a href="http://perso.ens-lyon.fr/lise.vaudor/strings-et-expressions-regulieres/">ici</a>.</p>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_tidytext.png" width="100" /> <code>tidytext</code> pour le traitement du langage naturel</h2>
<p>Pour traiter du langage naturel (des phrases, des paragraphes, des tweets, etc.) dans des traitements de type lexicométrie, j’utilise le package <code>tidytext</code>. J’y ai consacré <a href="http://perso.ens-lyon.fr/lise.vaudor/Descriptoire/_book/langage-naturel.html">un petit paragraphe du “Descriptoire”</a> (un livre en ligne traitant de l’analyse de textes avec R) mais si vous n’avez rien contre une ressource anglophone, les vignettes associées au package (et notamment l’<a href="https://cran.r-project.org/web/packages/tidytext/vignettes/tidytext.html">introduction</a>) sont très très bien faites…</p>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_lubridate.png" width="100" /> <code>lubridate</code>: opérations sur des dates, temps, heures</h2>
<p>Ce package permet de gérer (sans trop transpirer) toutes les <strong>opérations sur les données de type date, heure, temps</strong>, etc. (Lecture, conversion, arrondis, séquences de dates, opérations de type addition-soustraction, etc.). J’ai écrit un billet sur ce sujet <a href="http://perso.ens-lyon.fr/lise.vaudor/gerer-des-dates-avec-lubridate-un-jeu-denfant/">ici</a>.</p>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_forcats.png" width="100" /> <code>forcats</code>: opérations sur les facteurs (variables catégorielles)</h2>
<p>Pour travailler avec les variables catégorielles et notamment pour modifier les noms des différents niveaux (c’est peut-être un détail pour vous, mais pour moi ça veut dire beaucoup), j’utilise <code>forcats</code>. Voici le <a href="http://perso.ens-lyon.fr/lise.vaudor/manipulation-de-facteurs-avec-forcats/">billet</a> que j’avais écrit à ce sujet.</p>
<h1>Graphiques</h1>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_ggplot2.png" width="100" /> <code>ggplot2</code> : réalisation des graphiques</h2>
<p>Pour la <strong>réalisation des graphiques</strong>, bien sûr, je ne jure plus que par <code>ggplot2</code>. J’avais écrit (cela commence à faire un moment) un <a href="http://perso.ens-lyon.fr/lise.vaudor/par-ici-les-beaux-graphiques-avec-ggplot2/">billet</a> sur le sujet. En plus récent et plus complet, il y a aussi un de mes supports de cours <a href="http://perso.ens-lyon.fr/lise.vaudor/Supports_formation/initR_4_graphiques_introduction.html#(1)">ici</a>, <a href="http://perso.ens-lyon.fr/lise.vaudor/Supports_formation/initR_5_mapping.html#(1)">ici</a>, et <a href="http://perso.ens-lyon.fr/lise.vaudor/Supports_formation/initR_6_graphiques_approfondissement.html#(1)">là</a>.</p>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_patchwork.jpg" width="100" /> <code>patchwork</code>: combinaison de graphiques</h2>
<p>Pour <strong>combiner plusieurs graphiques en… patchworks</strong>, plus ou moins complexes, selon une syntaxe très intuitive (voir la vignette <a href="https://cran.r-project.org/web/packages/patchwork/vignettes/patchwork.html">ici</a>).</p>
<h1>Données géographiques et cartographie</h1>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/sf_logo.gif" width="100" /> <code>sf</code> : données géographiques vectorielles</h2>
<p>Pour tout ce qui est <strong>manipulation de données géographiques</strong> de type données <strong>vectorielles</strong>, le package <code>sf</code> est non seulement une mine d’or mais il est en plus tidyverse-friendly, c’est-à-dire qu’il fonctionne bien, notamment, avec les packages dplyr et ggplot2… J’ai un (très succinct) support de cours à son sujet <a href="http://perso.ens-lyon.fr/lise.vaudor/Supports_formation/initR_10_objets_spatiaux.html#(1)">ici</a>. En plus détaillé, vous pouvez aller jeter un coup d’oeil à cet <a href="https://statnmap.com/fr/2018-07-14-initiation-a-la-cartographie-avec-sf-et-compagnie/">article de StatnMap</a> sur le sujet!</p>
<h2><code>raster</code> : données raster, grid</h2>
<p>C’est (comme son nom l’indique) le package incontournable pour travailler avec des données de type <strong>raster</strong> (ou grid). Il est un peu plus ancien que <strong>sf</strong> et de ce fait les opérations croisant données raster et vectorielles qu’il propose sont plutôt compatibles avec le package <code>sp</code> (le prédecesseur de <code>sf</code>).</p>
<h2><code>tmap</code>: réalisation de cartes</h2>
<p>C’est un package qui permet de réaliser des <strong>cartes</strong> qui sont, au choix, <strong>statiques</strong> ou <strong>interactives</strong>. C’est aussi un package qui s’inscrit dans la logique “tidyverse” (malgré quelques différences de syntaxe par rapport à ggplot2). C’est de ce fait le package de cartographie que j’en suis venue à privilégier (parmi de nombreux choix possibles). Cependant, il m’arrive encore de faire appel à d’autres packages (comme <strong>leaflet</strong> par exemple) quand tmap ne répond pas à un besoin particulier. Par exemple, l’intégration d’une carte produite par tmap dans une appli shiny requiert l’utilisation de commandes que je ne comprends pas trop (mais que je suis malgré tout en mesure d’utiliser, par la grâce de Stack Overflow et du copier-coller ;-)). Or utiliser des choses sans les comprendre, cela me gêne un peu dans certains contextes (par exemple, quand je donne cours!).</p>
<h1>Rapports et applications</h1>
<p>J’aime partager le fruit de mon dur labeur dans des documents et applications qui permettent à mes interlocuteurs d’explorer les données/rendus/résultats des modèles de manière documentée, explicitée, et parfois interactive… Voilà les outils que j’utilise:</p>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_rmarkdown.png" width="100" /> <img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_knitr.png" width="100" /> <code>rmarkdown</code> et <code>knitr</code>: rapports tricotés</h2>
<p>Pour produire des rapports (c’est-à-dire des documents mêlant un plan, du code R, du texte, des résultats issus de R, des graphiques, etc.), j’utilise les packages <code>rmarkdown</code> et <code>knitr</code>… Vous pouvez consulter <a href="https://statistique-et-logiciel-r.com/guide-de-demarrage-en-r-markdown/">ce tutoriel</a> de Claire Della Vedova pour vous aider à vous lancer…</p>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_shiny.png" width="100" /> <code>shiny</code>: applications interactives</h2>
<p>Pour <strong>construire des applications</strong>, bien sûr, <code>shiny</code> est le must… Il y a beaucoup de tutos en ligne (à vous de choisir, selon vos préférences, un tuto anglophone/francophone/autre, un support sous forme de video/document/exercices en ligne…), mais à toutes fins utiles, j’ai moi-même un petit support de cours disponible <a href="http://perso.ens-lyon.fr/lise.vaudor/tuto-shiny/">ici</a> -je m’en sers pour donner cours “en vrai” donc c’est plus un aide-mémoire qu’un guide de démarrage, réellement-…</p>
<p>Pour l’instant en tant que “développeuse shiny occasionnelle” je m’en tiens essentiellement à <code>shiny</code> (avec quelquefois quelques additions par exemple <code>colourpicker</code> qui propose un widget pour choisir une couleur) mais je suis très intéressée par le package <code>golem</code> de ThinkR qui permet de <strong>modulariser les applis</strong> (car, oui, une appli, ça peut vite devenir gros, compliqué et bordélique) et que j’aimerais bien incorporer à mon “workflow” la prochaine fois que j’aurai l’occasion de développer une appli shiny… En plus, chouette, ils ont <a href="https://thinkr-open.github.io/golem/index.html">plein de doc</a> pour s’y mettre…</p>
<h1>Itérations</h1>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_purrr.png" width="100" /></h2>
<p>Je ne sais pas trop dans quelle rubrique classer <code>purrr</code>, mais il figure parmi mes nouveaux incontournables depuis maintenant 2 ou 3 ans. J’avais écrit un billet à ce sujet <a href="http://perso.ens-lyon.fr/lise.vaudor/iterer-des-fonctions-avec-purrr/">ici</a> De fait, quand on travaille très régulièrement avec dplyr (et des “tibbles”), l’usage de purrr pour <strong>remplacer les traditionnelles boucles for</strong> est le bienvenu… L’usage de <code>purrr</code> s’accompagne aussi d’un changement de pratiques pour moi puisque j’en viens de plus en plus à écrire mon code “en fonctions”!…</p>
<h1>Graphes</h1>
<p>Pour analyser des réseaux et produire des graphes (attention, j’ai bien dit graphes, et non graphiques!) j’utilise deux packages de Thomas Lin Pederson:</p>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_tidygraph.png" width="100" /> <code>tidygraph</code> : description et analyse de réseaux</h2>
<p>J’en parle succinctement dans <a href="http://perso.ens-lyon.fr/lise.vaudor/des-graphes-bien-peignes/">ce billet</a>(en promettant un article très prochainement. C’était il y a six mois. Gloups.): <code>tidygraph</code> permet de <strong>traiter des données en réseau</strong> (qui sont par conséquent structurés d’une manière différente des données “tidy” telles qu’on les connaît, où une ligne=un individu et une colonne=une variable). Ce package s’inscrit très largement dans les principes et la syntaxe du tidyverse.</p>
<h2><img decoding="async" src="../../lise.vaudor/Rfigures/packages_indispensables/logo_ggraph.png" width="100" /> <code>ggraph</code> : représentation de réseaux en graphes</h2>
<p>J’en parle dans <a href="http://perso.ens-lyon.fr/lise.vaudor/des-graphes-bien-jolis/">ce billet</a>. Ce package permet de représenter des réseaux en graphe en reprenant les principes et les éléments de syntaxe de ggplot2.</p>
<h1>Analyses factorielles</h1>
<p>Entre <code>FactoMineR</code> et <code>ade4</code>, mon coeur balance… Pourtant, j’aimerais bien être en mesure de trancher une fois pour toute, car pour moi, utiliser deux packages qui font “un peu la même chose mais pas exactement”, ça veut dire que je n’arrive jamais à me rappeler les commandes ni de l’un ni de l’autre.</p>
<p>Cependant, je pense que je n’arriverai jamais à trancher, car si je trouve <code>FactoMineR</code> un peu plus clair, je trouve aussi <code>ade4</code> un peu plus complet. Quelque part, on retrouve la “patte” des disciplines qui les a vus émerger: plus agronomique (culture méthodique et maîtrisée) côté <code>FactoMineR</code>, plus écologique (écosystème foisonnant et en évolution) côté <code>ade4</code>… (Que les auteurs de ces packages me pardonnent ces clichés, c’est juste comme ça que je m’explique mon “feeling” vis-à-vis de l’un ou de l’autre <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> ). D’ailleurs, j’ai fait mes études dans une école d’ingénieur agronome, et mon doctorat dans un laboratoire d’écologie, et vous comprendrez donc pourquoi, même d’un point de vue disciplinaire, j’ai du mal à faire mon choix entre ces deux packages…</p>
]]></content:encoded>
					
					<wfw:commentRss>https://perso.ens-lyon.fr/lise.vaudor/jamais-sans-ces-packages/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>Analyse multi-résolution d&#8217;une série à travers les ondelettes discrètes</title>
		<link>https://perso.ens-lyon.fr/lise.vaudor/analyse-multi-resolution-dune-serie-a-travers-les-ondelettes-discretes/</link>
					<comments>https://perso.ens-lyon.fr/lise.vaudor/analyse-multi-resolution-dune-serie-a-travers-les-ondelettes-discretes/#comments</comments>
		
		<dc:creator><![CDATA[lvaudor]]></dc:creator>
		<pubDate>Wed, 27 Nov 2019 15:20:24 +0000</pubDate>
				<category><![CDATA[Tous les posts]]></category>
		<guid isPermaLink="false">http://perso.ens-lyon.fr/lise.vaudor/?p=1178</guid>

					<description><![CDATA[Aïe aïe aïe!! Quelle prise de tête que les transformées d’ondelettes quand on n’est pas très matheux… Comprendre de A à Z comment elles fonctionnent, en déroulant tout le raisonnement de la définition d’une ondelette à l’interprétation finale de la transformée, c’est long, c’est compliqué, c’est même parfois impossible si on ne peut pas se lancer à corps perdu dans le sujet… Ici, je pars du principe que vous non.. <a href="https://perso.ens-lyon.fr/lise.vaudor/analyse-multi-resolution-dune-serie-a-travers-les-ondelettes-discretes/">Read More</a>]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" src="../../lise.vaudor/Rfigures/Ondelettes_discretes/draw_headband-1.png" alt="" /></p>
<p>Aïe aïe aïe!! Quelle prise de tête que les transformées d’ondelettes quand on n’est pas très matheux… Comprendre de A à Z comment elles fonctionnent, en déroulant tout le raisonnement de la définition d’une ondelette à l’interprétation finale de la transformée, c’est long, c’est compliqué, c’est même parfois impossible si on ne peut pas se lancer à corps perdu dans le sujet…</p>
<p>Ici, je pars du principe que vous non plus, vous n’êtes pas forcément prêts à faire le grand saut… alors je vais vous présenter une méthode liée aux transformées d’ondelettes discrètes, dite <strong>Analyse Multi-Résolution</strong> (MRA en anglais) en me concentrant sur le <em>résultat</em> plutôt que sur la <em>méthode</em>. <small>J’ai tout un tas de supports éparpillés sur la <em>méthode</em> en question donc il n’est pas exclu que je me fende un jour d’un bon gros billet avec tout plein d’équations sur le sujet mais je ne voudrais pas vous faire peur d’emblée :-)…</small></p>
<p>Notez que dans cette même démarche (de démocratisation des ondelettes) j’ai également mis en ligne <a href="http://perso.ens-lyon.fr/lise.vaudor/the-wavelet-toolkat/">une appli</a> permettant de tester tout un tas de méthodes d’analyse du signal par les ondelettes (ondelettes discrètes ou continues).</p>
<h1>Les ondelettes discrètes, pour quoi faire?</h1>
<p>Les transformées d’ondelettes peuvent servir à <strong>débruiter</strong>, <strong>filtrer</strong>, <strong>compresser</strong>, <strong>décomposer</strong> le signal et/ou sa variance en <strong>dissociant ses composantes à diverses échelles</strong>.</p>
<p>Pour ma part, je ne m’intéresse pas ces transformées pour la compression du signal mais plutôt à leur usage pour l’<strong>analyse de séries</strong>. Par ailleurs, je vais ici me concentrer sur l’analyse de séries (temporelles ou spatiales) 1D, excluant de ce fait l’analyse d’images (2D) de mon propos.</p>
<p>J’aimerais commencer en montrant rapidement ce que l’on peut réaliser à travers les transformées d’ondelettes. Considérons le signal suivant, qui correspond à une série de températures relevées à la station météo de Lyon Saint-Exupéry (température moyenne journalière, données disponibles <a href="https://www.ecad.eu//dailydata/predefinedseries.php">sur ce site</a> et que je vous remets <a href="../../lise.vaudor/Rdata/Ondelettes_discretes/TG_STAID000037.txt">ici</a>. On devine dans ce signal une <strong>forte composante saisonnière</strong> (échelle temporelle “moyenne”), à laquelle se rajoute du “<strong>bruit</strong>” (échelle temporelle fine), et, peut-être, une <strong>tendance de fond</strong> (échelle temporelle longue) à l’augmentation de la température moyenne (on verra si nos analyses le confirment!). De fait, j’ai choisi ces données car elles se prêtent tout naturellement à une analyse multi-résolution!!</p>
<pre><code>library(tidyverse)
data_ex=read.delim(paste0(dat.path,"TG_STAID000037.txt"),
                   sep=",", skip=20, na=-9999)%&gt;% 
  mutate(x=lubridate::ymd(DATE),
         y=TG/10) %&gt;% 
  group_by(x) %&gt;% 
  summarise(y=mean(y)) %&gt;% 
  na.omit()
ggplot(data_ex,aes(x=x,y=y))+
  geom_line(col="dark grey")
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Ondelettes_discretes/signal_brut-1.png" alt="" /></p>
<p>La décomposition en ondelettes discrètes permet de réaliser une analyse multi-résolution (<strong>MRA</strong>) du signal. <small>Je passe pour l’instant sur le code qui permet de réaliser les graphiques suivants… mais j’y reviendrai!</small> C’est à dire que l’on va pouvoir <strong>décomposer</strong> le signal en différentes composantes, qui correspondent à des échelles plus ou moins fines, et que cette décomposition aura l’intérêt d’être <strong>additive</strong>.</p>
<p>Si l’on considère la façon dont le signal est décomposé, étape par étape, on peut écrire les équations suivantes:</p>
<p>$$ \begin{aligned} Y &amp;= &amp; &amp; &amp; &amp; &amp; &amp; &amp; &amp;S1 &amp;+ &amp;D1\ &amp;= &amp; &amp; &amp; &amp; &amp; &amp;S2 &amp;+ &amp;D2 &amp;+ &amp;D1\ &amp;= &amp; &amp; &amp; &amp;S3 &amp;+ &amp;D3 &amp;+ &amp;D2 &amp;+ &amp;D1\ &amp;= &amp; &amp; S4 &amp;+ &amp;D4 &amp;+ &amp;D3 &amp;+ &amp;D2 &amp;+ &amp;D1\ etc. \end{aligned} $$</p>
<ul>
<li>D’abord, Y est décomposé à <strong>très petite échelle</strong> en un signal de <strong>“détail”</strong> (D1) et un signal lissé &#8211;<strong>“smooth”</strong>&#8211; (S1).</li>
<li>Puis ce signal lissé à très petite échelle peut être lissé à une échelle un peu moins petite en un nouveau “smooth” (S2) et un nouveau “detail” (D2): <em>S</em>1 = <em>S</em>2 + <em>D</em>2&#46;</li>
<li>A nouveau, on peut lisser ce smooth une échelle un peu plus grande pour produire un nouveau smooth (S3) et un nouveau détail (D3): <em>S</em>2 = <em>D</em>3 + <em>S</em>3</li>
<li>etc.</li>
</ul>
<p>A la fin, on arrive toujours à une <strong>somme de sous-signaux égale au signal de départ</strong>, chaque sous-signal nous informant sur la variation à une échelle donnée, de manière <strong>non redondante</strong> par rapport aux autres sous-signaux.</p>
<p>Voyez à quoi la “pyramide” d’équations ci-dessus correspond en terme de <strong>représentation des variations du signal</strong> (j’ai représenté les séries verticalement pour une meilleure lisibilité):</p>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Ondelettes_discretes/signal_details_pyramid-1.png" alt="" /></p>
<p>Il est en fait possible de <strong>lisser encore et encore ce signal</strong>, jusqu’à arriver à un smooth qui nous montre la tendance de fond. Ci-dessus je me suis arrêtée au niveau 4 car d’un point de vue graphique 4 niveaux de décomposition étaient déjà assez lourds…</p>
<p>Cela étant, rien ne nous empêche de <strong>regrouper certains sous-signaux</strong>… Par exemple, on peut essayer de distinguer une composante plutôt saisonnière (S4) au sein des variations journalières:</p>
<p><em>Y</em> = <em>S</em>4 + (<em>D</em>4 + <em>D</em>3 + <em>D</em>2 + <em>D</em>1) <img decoding="async" src="../../lise.vaudor/Rfigures/Ondelettes_discretes/signal_to_S4-1.png" alt="" /></p>
<p>Ainsi, en poussant la décomposition plus loin, et en regroupant un certain nombre de niveaux, on peut essayer d’isoler une tendance de fond:</p>
<p><em>Y</em> = <em>S</em>10 + (<em>D</em>10 + &#8230; + <em>D</em>5) + (<em>D</em>4 + &#8230; + <em>D</em>1) <img decoding="async" src="../../lise.vaudor/Rfigures/Ondelettes_discretes/signal_to_S10-1.png" alt="" /></p>
<p>Bingo! L’examen des graphiques ci-dessus révèle par exemple:</p>
<ul>
<li>qu’il y a bien une tendance à l’augmentation de la température depuis 1975 (on ne nous aurait donc pas menti! :-p).</li>
<li>il y a eu quelques années particulièrement froides dans la deuxième moitié des années 80 (on le voit sur S10) et en particulier un hiver 85 particulièrement rigoureux (on le voit sur D10+….+D5)</li>
<li>on remarque les épisodes de canicule dans leur effet sur la composante saisonnière (D10+…+D4): voyez par exemple la canicule 2003 marquée par un pic plus marqué que les autres…</li>
</ul>
<h1>Comment faire, sous R?</h1>
<p>Pour réaliser les transformées d’ondelettes discrètes sous R j’utilise un package qui s’appelle <code>wavelets</code>. Comme à mon habitude, je vais aussi utiliser le <code>tidyverse</code> pour réaliser les quelques traitements supplémentaires dont j’aurai besoin (et patchwork pour organiser mes panneaux de graphiques!)</p>
<pre><code>library(wavelets)
library(tidyverse)
library(patchwork)
</code></pre>
<p>Voilà comment je réalise mon analyse multi-résolution, à l’aide de la fonction <code>mra()</code> du package <code>wavelets</code>:</p>
<pre><code>mymra=mra(X=data_ex$y, 
          n.levels=10,
          boundary="reflection")
</code></pre>
<ul>
<li>Le premier argument <code>X</code> correspond au <strong>signal</strong> lui-même. Pour que la transformée d’ondelettes ait un sens, il faut que la série de données corresponde à des <strong>valeurs <em>Y</em> régulièrement espacées</strong> (ici dans le temps).</li>
<li>Le deuxième argument <code>n.levels</code> correspond au niveau maximal de décomposition (ce niveau maximal dépendra de la nature de l’ondelette et de la longueur de la série).</li>
<li>Le dernier argument <code>boundary</code> correspond à la méthode utilisée “au bord du signal” pour calculer les transformées d’ondelettes. En effet, pour calculer les coefficients d’ondelettes sur les bords du signal, on est obligés d’allonger artificiellement le signal. Les deux choix possibles sont “periodic” (on recycle le signal, du début à la fin) ou “reflection” (on retourne le signal, en miroir). Dans notre cas de séries de températures, l’existence d’une évolution entre le début et la fin du signal (augmentation graduelle de la température moyenne) rend la transformation “reflection” plus pertinente…</li>
</ul>
<p>Examinons maintenant ce que nous retourne la fonction <code>mra()</code>:</p>
<pre><code>str(mymra)

## Formal class 'mra' [package "wavelets"] with 9 slots
##   ..@ D       :List of 10
##   .. ..$ D1 : num [1:32532, 1] 0.418 -1.058 0.292 0.332 -0.51 ...
##   .. ..$ D2 : num [1:32532, 1] -0.538 -0.396 -0.244 0.316 1.119 ...
##   .. ..$ D3 : num [1:32528, 1] 0.1031 -0.207 -0.5185 -0.3569 -0.0928 ...
##   .. ..$ D4 : num [1:32528, 1] 2.249 2 1.697 1.147 0.477 ...
##   .. ..$ D5 : num [1:32512, 1] 0.868 0.899 0.913 0.835 0.716 ...
##   .. ..$ D6 : num [1:32512, 1] 0.861 1.047 1.215 1.3 1.343 ...
##   .. ..$ D7 : num [1:32512, 1] -3.88 -3.89 -3.89 -3.84 -3.76 ...
##   .. ..$ D8 : num [1:32512, 1] -2.47 -2.6 -2.72 -2.8 -2.87 ...
##   .. ..$ D9 : num [1:32256, 1] -2.88 -2.94 -2.99 -3.02 -3.05 ...
##   .. ..$ D10: num [1:31744, 1] 0.62 0.622 0.624 0.625 0.626 ...
##   ..@ S       :List of 10
##   .. ..$ S1 : num [1:32532, 1] 13.8 14.3 14.7 15.2 15.7 ...
##   .. ..$ S2 : num [1:32532, 1] 14.3 14.7 15 14.9 14.6 ...
##   .. ..$ S3 : num [1:32528, 1] 14.5 14.4 14.2 13.8 13.2 ...
##   .. ..$ S4 : num [1:32528, 1] 12.2 12.4 12.5 12.6 12.7 ...
##   .. ..$ S5 : num [1:32512, 1] 12.9 13 13.1 13.2 13.3 ...
##   .. ..$ S6 : num [1:32512, 1] 12 12 11.9 11.9 11.9 ...
##   .. ..$ S7 : num [1:32512, 1] 15.9 15.8 15.8 15.7 15.7 ...
##   .. ..$ S8 : num [1:32512, 1] 18.4 18.4 18.5 18.5 18.6 ...
##   .. ..$ S9 : num [1:32256, 1] 11.5 11.5 11.5 11.5 11.5 ...
##   .. ..$ S10: num [1:31744, 1] 11.3 11.3 11.3 11.3 11.3 ...
##   ..@ filter  :Formal class 'wt.filter' [package "wavelets"] with 7 slots
##   .. .. ..@ L        : int 8
##   .. .. ..@ level    : int 1
##   .. .. ..@ h        : num [1:8] 0.0322 0.0126 -0.0992 -0.2979 0.8037 ...
##   .. .. ..@ g        : num [1:8] -0.0758 -0.0296 0.4976 0.8037 0.2979 ...
##   .. .. ..@ wt.class : chr "Least Asymmetric"
##   .. .. ..@ wt.name  : chr "la8"
##   .. .. ..@ transform: chr "dwt"
##   ..@ level   : int 10
##   ..@ boundary: chr "reflection"
##   ..@ series  : num [1:32532, 1] 14.2 13.2 15 15.5 15.2 14.4 12.3 11.7 15.2 16.4 ...
##   ..@ class.X : chr "numeric"
##   ..@ attr.X  : list()
##   ..@ method  : chr "dwt"
</code></pre>
<p>Cet objet comprend un slot “filter” qui nous renseigne sur la <strong>nature de l’ondelette utilisée</strong> (car il existe plusieurs ondelettes possibles)! Ici, comme nous n’avons rien précisé dans l’appel à la fonction <code>mra()</code>, c’est par défaut l’ondelette “Least Asymetric” de longueur 8 (“la8”) qui a été utilisée (mais bien sûr nous aurions pu explicitement demander qu’une autre ondelette soit utilisée en utilisant l’argument <code>filter</code>):</p>
<pre><code>mymra@filter

## An object of class "wt.filter"
## Slot "L":
## [1] 8
## 
## Slot "level":
## [1] 1
## 
## Slot "h":
## [1]  0.03222310  0.01260397 -0.09921954 -0.29785780  0.80373875 -0.49761867 -0.02963553  0.07576571
## 
## Slot "g":
## [1] -0.07576571 -0.02963553  0.49761867  0.80373875  0.29785780 -0.09921954 -0.01260397  0.03222310
## 
## Slot "wt.class":
## [1] "Least Asymmetric"
## 
## Slot "wt.name":
## [1] "la8"
## 
## Slot "transform":
## [1] "dwt"
</code></pre>
<p>Outre des informations sur la méthode de calcul et la nature de l’ondelette (slot “filter”), l’objet <code>mymra</code> comprend l’ensemble des smooths et des details pour les 10 niveaux de décomposition demandés ici. On peut accéder à chacun de ces sous-signaux de la manière suivante:</p>
<pre><code>mymra@D$D1[1:5]

## [1]  0.4177861 -1.0581337  0.2924646  0.3321684 -0.5095316
</code></pre>
<p>Cela étant, quand on travaille dans la logique “tidy”, on a très envie d’obtenir tous ces sous-signaux comme autant de colonnes d’une table. Pour faciliter cette transformation, j’ai écrit une petite fonction <code>add_wav_data()</code>:</p>
<pre><code>add_wav_data=function(mydata,mra_obj){
  n=nrow(mydata)
  cut_to_size=function(x,n){
    if(dim(x)[1]&gt;n){
      x=x[1:n]
    }else{
      x=c(x,rep(NA,n-dim(x)[1]))
    }
    return(x)
    }
  if(class(mra_obj)=="mra"){
    S=mra_obj@S %&gt;%
      purrr::map(cut_to_size,n) %&gt;% 
      bind_cols() %&gt;% 
      mutate_all(as.vector)
    D=mra_obj@D %&gt;%
      purrr::map(cut_to_size,n) %&gt;% 
      bind_cols() %&gt;%
      mutate_all(as.vector)
    wav_data=bind_cols(S,D)
  }
  mydata=bind_cols(mydata,
                   wav_data)
  return(mydata)
}

data_ex_wav=add_wav_data(data_ex,mymra) 
str(data_ex_wav)

## Classes 'tbl_df', 'tbl' and 'data.frame':    16266 obs. of  22 variables:
##  $ x  : Date, format: "1975-04-20" "1975-04-21" "1975-04-22" "1975-04-23" ...
##  $ y  : num  14.2 13.2 15 15.5 15.2 14.4 12.3 11.7 15.2 16.4 ...
##  $ S1 : num  13.8 14.3 14.7 15.2 15.7 ...
##  $ S2 : num  14.3 14.7 15 14.9 14.6 ...
##  $ S3 : num  14.5 14.4 14.2 13.8 13.2 ...
##  $ S4 : num  12.2 12.4 12.5 12.6 12.7 ...
##  $ S5 : num  12.9 13 13.1 13.2 13.3 ...
##  $ S6 : num  12 12 11.9 11.9 11.9 ...
##  $ S7 : num  15.9 15.8 15.8 15.7 15.7 ...
##  $ S8 : num  18.4 18.4 18.5 18.5 18.6 ...
##  $ S9 : num  11.5 11.5 11.5 11.5 11.5 ...
##  $ S10: num  11.3 11.3 11.3 11.3 11.3 ...
##  $ D1 : num  0.418 -1.058 0.292 0.332 -0.51 ...
##  $ D2 : num  -0.538 -0.396 -0.244 0.316 1.119 ...
##  $ D3 : num  0.1031 -0.207 -0.5185 -0.3569 -0.0928 ...
##  $ D4 : num  2.249 2 1.697 1.147 0.477 ...
##  $ D5 : num  0.868 0.899 0.913 0.835 0.716 ...
##  $ D6 : num  0.861 1.047 1.215 1.3 1.343 ...
##  $ D7 : num  -3.88 -3.89 -3.89 -3.84 -3.76 ...
##  $ D8 : num  -2.47 -2.6 -2.72 -2.8 -2.87 ...
##  $ D9 : num  -2.88 -2.94 -2.99 -3.02 -3.05 ...
##  $ D10: num  0.62 0.622 0.624 0.625 0.626 ...
##  - attr(*, "na.action")= 'omit' Named int  1 2 3 4 5 6 7 8 9 10 ...
##   ..- attr(*, "names")= chr  "1" "2" "3" "4" ...
</code></pre>
<p>On est dès lors en mesure de faire notre petite tambouille (avec ggplot2, avec dplyr, etc.). Tenez, vérifions en deux coups de cuillère à pot que la décomposition du signal est bien additive:</p>
<pre><code>data_ex_wav %&gt;%
  mutate(somme=S10+D10+D9+D8+D7+D6+D5+D4+D3+D2+D1) %&gt;% 
  select(y,somme) %&gt;% 
  head(n=10)

## # A tibble: 10 x 2
##        y somme
##    &lt;dbl&gt; &lt;dbl&gt;
##  1  14.2  6.66
##  2  13.2  4.79
##  3  15    5.69
##  4  15.5  5.84
##  5  15.2  5.30
##  6  14.4  4.72
##  7  12.3  2.84
##  8  11.7  1.28
##  9  15.2  3.70
## 10  16.4  2.96
</code></pre>
<p>En outre, je peux utiliser ce tableau à ma guise pour réaliser un graphique montrant les composantes de mon choix:</p>
<pre><code>pbase=ggplot(data_ex_wav,aes(x=x,y=y))
pY =pbase+
  geom_line(col="dark grey")+ggtitle("Y")
pDall=pbase +
  geom_line(aes(x=x,y=D4+D3+D2+D1),col="lightgreen")+
  ggtitle("D4+...+D1")
pDseason=pbase+
  geom_line(aes(x=x,y=D10+D9+D8+D7+D6+D5), col="slateblue")+
  ggtitle("D10+...+D5")
pTrend=pbase+
  geom_line(aes(x=x,y=S10),col="gold",size=2)+
  ggtitle("S10")
pY/pTrend/pDseason/pDall
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Ondelettes_discretes/show_graph-1.png" alt="" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://perso.ens-lyon.fr/lise.vaudor/analyse-multi-resolution-dune-serie-a-travers-les-ondelettes-discretes/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Des graphes bien jolis</title>
		<link>https://perso.ens-lyon.fr/lise.vaudor/des-graphes-bien-jolis/</link>
					<comments>https://perso.ens-lyon.fr/lise.vaudor/des-graphes-bien-jolis/#respond</comments>
		
		<dc:creator><![CDATA[lvaudor]]></dc:creator>
		<pubDate>Tue, 15 Oct 2019 15:15:24 +0000</pubDate>
				<category><![CDATA[Tous les posts]]></category>
		<guid isPermaLink="false">http://perso.ens-lyon.fr/lise.vaudor/?p=1141</guid>

					<description><![CDATA[Dans ce billet, je vais me focaliser principalement sur ggraph, et j’essaierai de trouver le temps pour parler un peu plus en profondeur de tidygraph un peu plus tard dans un autre billet. Données Nous allons travailler sur cette table qui renseigne les noeuds de notre réseau, et cette autre table qui renseigne les liens. nodes=read_csv("../../lise.vaudor/Rdata/Graphes_et_tidyverse_ggraph/vertices.csv") edges=read_csv("../../lise.vaudor/Rdata/Graphes_et_tidyverse_ggraph/edges.csv") Pour aujourd’hui, je vais utiliser une fonction de tidygraph (tbl_graph()) pour former à.. <a href="https://perso.ens-lyon.fr/lise.vaudor/des-graphes-bien-jolis/">Read More</a>]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" src="../../lise.vaudor/Rfigures/Graphes_et_tidyverse_ggraph/Lise_Vaudor_headband-1.png" alt="" /></p>
<p>Dans ce billet, je vais me focaliser principalement sur <code>ggraph</code>, et j’essaierai de trouver le temps pour parler un peu plus en profondeur de tidygraph un peu plus tard dans un autre billet.</p>
<h1>Données</h1>
<p>Nous allons travailler sur cette table qui renseigne les <a href="../../lise.vaudor/Rdata/Graphes_et_tidyverse_ggraph/vertices.csv">noeuds</a> de notre réseau, et cette autre table qui renseigne les <a href="../../lise.vaudor/Rdata/Graphes_et_tidyverse_ggraph/edges.csv">liens</a>.</p>
<pre><code>nodes=read_csv("../../lise.vaudor/Rdata/Graphes_et_tidyverse_ggraph/vertices.csv")
edges=read_csv("../../lise.vaudor/Rdata/Graphes_et_tidyverse_ggraph/edges.csv")
</code></pre>
<p>Pour aujourd’hui, je vais utiliser une fonction de tidygraph (<code>tbl_graph()</code>) pour former à partir de ces deux tables un objet de type graphe (et même, plus précisément, de classe “tbl_graph”). Je passe rapidement sur cette étape, car j’y reviendrai très bientôt dans un autre billet…</p>
<pre><code>tib_g=tidygraph::tbl_graph(nodes=nodes,edges=edges) 
</code></pre>
<p>De la même manière qu’avec la fonction <code>ggplot()</code> du package <code>ggplot2</code>, je crée ma première “couche” avec la fonction <code>ggraph()</code> du package <code>ggraph</code>:</p>
<pre><code>g=tib_g %&gt;% 
   ggraph(layout="auto")
</code></pre>
<p>Pour l’instant, il n’y a rien à voir… mais je vais ensuite pouvoir exploiter les possibilités de <code>ggraph</code> pour la représentation des noeuds et des liens.</p>
<h1>Représentation des noeuds</h1>
<p>D’abord, voici les possibilités pour les noeuds:</p>
<pre><code>flowrpowr::flowr_package("ggraph",element="geom_node", layout="sugiyama")
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Graphes_et_tidyverse_ggraph/unnamed-chunk-1-1.png" alt="" /></p>
<p>Toutes n’ont pas forcément un intérêt dans notre cas (c’est fonction de la structure de notre graphe) donc je ne les testerai pas toutes, mais en voici quelques-unes adaptées à notre cas:</p>
<pre><code>g1=g + geom_node_point(color="goldenrod",size=3)
g2=g + geom_node_label(aes(label=name),fill="steelblue",alpha=0.2)
g3=g + geom_node_text(aes(label=name), color="olivedrab")
g4=g + geom_node_circle(aes(fill=gender, r=0.3))
library(patchwork)
(g1+g2)/(g3+g4)
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Graphes_et_tidyverse_ggraph/unnamed-chunk-2-1.png" alt="" /></p>
<p>Notez que l’on retrouve les traits les plus commodes de ggplot2, comme l’<strong>argument “mapping”</strong> qui permet de <strong>relier certaines caractéristiques des geoms à certaines variables dans notre jeu de données</strong>…</p>
<h1>Représentation des liens</h1>
<p>Maintenant, voyons les possibilités pour la représentation des liens:</p>
<pre><code>flowrpowr::flowr_package("ggraph",element="geom_edge", layout="sugiyama")
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Graphes_et_tidyverse_ggraph/unnamed-chunk-3-1.png" alt="" /></p>
<p>Et à nouveau, testons quelques-unes des possibilités:</p>
<pre><code>g11=g1+geom_edge_link(color="steelblue")
g12=g1+geom_edge_arc(color="coral")
g13=g1+geom_edge_link(aes(edge_width=weight),color="olivedrab", alpha=0.2)
g14=g1+geom_edge_link(aes(edge_colour=relationship))
(g11+g13)/(g12+g14)
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Graphes_et_tidyverse_ggraph/unnamed-chunk-4-1.png" alt="" /></p>
<h1>Facettes, échelles, etc.</h1>
<p>Evidemment, pour un “vrai” graphe, on va jouer sur tout en même temps (les noeuds, les liens, la superposition des couches, les esthétiques, etc.). <code>ggraph</code> permet également de créer des facettes d’un même graphe soit en fonction des noeuds, soit en fonction des liens</p>
<pre><code>gf=g +
  geom_edge_link(aes(edge_colour=relationship),
                 alpha=0.3, edge_width=2)+
  geom_node_label(aes(label=name, fill=gender),
                  alpha=0.3, label.size=0)+
  scale_edge_color_manual(values=c("couple"="red",
                                   "friends"="blue",
                                   "colleagues"="dark grey"))+
  scale_fill_manual(values=c("man"="yellow","woman"="orange"))+
  ggplot2::scale_x_continuous(expand=ggplot2::expand_scale(mult=0.1))
gf
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Graphes_et_tidyverse_ggraph/graph_it_all-1.png" alt="" /></p>
<p>(la dernière ligne me permet simplement d’étendre légèrement l’échelle des abscisses afin que les noms ne soient pas coupés sur les bords…)</p>
<p>On peut enfin <strong>facetter</strong> notre figure pour distinguer différents sous-graphes, en lien soit avec une variable catégorielle décrivant les noeuds (<code>facet_nodes()</code>), soit avec une variable catégorielle décrivant les liens (<code>facet_edges()</code>).</p>
<pre><code>gf_e=gf + facet_edges(~relationship)
gf_n=gf + facet_nodes(~gender)
gf_e/gf_n
</code></pre>
<p><img decoding="async" src="../../lise.vaudor/Rfigures/Graphes_et_tidyverse_ggraph/facetted_graphs-1.png" alt="" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://perso.ens-lyon.fr/lise.vaudor/des-graphes-bien-jolis/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
