Sacha Schutzhttps://dridk.me/2023-03-12T19:30:31+01:00Exploiter des fichiers parquets avec Pola.rs et DuckDB2023-03-12T19:30:31+01:002023-03-12T19:30:31+01:00Sacha schutztag:dridk.me,2023-03-12:/parquet-files.html<p>Cela fait un bon moment que j'entends parler des <a href="https://fr.wikipedia.org/wiki/Apache_Parquet">fichiers Parquet</a>. Un format binaire beaucoup plus léger
que <a href="https://fr.wikipedia.org/wiki/Comma-separated_values">les fichiers CSV</a> pour le stockage des tableaux de données. <br>
Lorsque j'ai vu pour la première fois un collègue faire une requête SQL quasi instantanée sur des millions des lignes répartis sur …</p><p>Cela fait un bon moment que j'entends parler des <a href="https://fr.wikipedia.org/wiki/Apache_Parquet">fichiers Parquet</a>. Un format binaire beaucoup plus léger
que <a href="https://fr.wikipedia.org/wiki/Comma-separated_values">les fichiers CSV</a> pour le stockage des tableaux de données. <br>
Lorsque j'ai vu pour la première fois un collègue faire une requête SQL quasi instantanée sur des millions des lignes répartis sur différents fichiers parquets, je me suis dit les yeux grands écarquillés, que c'était peut être un peu plus que ça.
En effet, aujourd'hui le format parquet est utilisé en <a href="https://www.cetic.be/Apache-Parquet-pour-le-stockage-de-donnees-volumineuses">big data</a> pour stocker et interroger de façon efficace des données
volumineuses grâce à <a href="https://fr.wikipedia.org/wiki/Base_de_donn%C3%A9es_orient%C3%A9e_colonnes">un modèle orienté colonne</a> basée sur <a href="https://en.wikipedia.org/wiki/Apache_Arrow">Apache Arrow</a> que je décrirai juste après.
À cela, s'ajoute de nouveaux outils en Python pour pouvoir manipuler et interroger ces fichiers. </p>
<p>Dans ce billet de blog, je vous propose d'utiliser <a href="https://www.pola.rs/">pola.rs</a> et <a href="https://duckdb.org/">duckDB</a>, pour explorer les données d'un <a href="https://fr.wikipedia.org/wiki/Variant_Call_Format">fichier VCF</a> volumineux provenant de <a href="https://www.internationalgenome.org/data-portal/sample">1000genomes</a>. </p>
<h2>Architecture d'un fichier parquet</h2>
<h3>Base de données orientée colonnes</h3>
<p>Les bases de données classiques ( <a href="https://fr.wikipedia.org/wiki/MySQL">MYSQL</a>, <a href="https://fr.wikipedia.org/wiki/SQLite">SQLite</a>, <a href="https://fr.wikipedia.org/wiki/Oracle_Database">Oracle</a>... ) sont des architectures <a href="https://en.wikipedia.org/wiki/Column-oriented_DBMS#Row-oriented_systems">orientées en ligne</a>. C'est-à-dire que les lignes d'une table sont sauvegardées de manière contiguë en mémoire. Cela permet d'insérer ou de supprimer facilement des enregistrements. Revers de la médaille, il est plus coûteux de faire du calcul sur une colonne entière, car cela nécessite de parcourir l'ensemble des lignes. Ces bases de données sont optimisées pour le transactionnel et sont utilisées pour des <a href="https://fr.wikipedia.org/wiki/Traitement_transactionnel_en_ligne">système OLTP </a>(OnLine Transactional Processing), par exemple une base de données de production gérant des utilisateurs. <br>
Dans un fichier parquet, ce sont les colonnes qui sont sauvegardées de manière contiguë en mémoire. Ceci permet de faire
des opérations de façon très efficace sur les colonnes au détriment des opérations transactionnelles. Cette architecture est très performante pour des <a href="https://fr.wikipedia.org/wiki/Traitement_analytique_en_ligne">systèmes OLAP </a>(OnLine Analytical Processing). Par exemple un entrepôt de données destinés à être lu uniquement. </p>
<div class="figure">
<img src="../images/parquet/row_vs_col.png" />
<div class="legend"> À gauche, un tableau de donnée. En haut à droite, la représentation en
mémoire du tableau orienté ligne. En bas à droite, la représentation orientée
colonne. <a href="https://datacadamia.com/data/type/relation/structure/column_store"> source </a>
</div> </div>
<h3>Apache Arrow</h3>
<p><a href="https://en.wikipedia.org/wiki/Apache_Arrow">Apache Arrow</a> est un format standard de donnée orienté colonne pour la <strong><a href="https://fr.wikipedia.org/wiki/M%C3%A9moire_vive">mémoire vive</a></strong>. C'est-à-dire qu'il décrit, indépendamment du langage de programmation,comment représenter un tableau dans votre RAM. Par exemple, si vous manipulez les mêmes données stockées dans un <a href="https://en.wikipedia.org/wiki/Pandas_(software)#DataFrames">DataFrame</a> Python ou un DataFrame R, la structure mémoire sous-jacent sera la même. Autrement dit, vous allez pouvoir transférer un DataFrame Python vers un DataFrame R, sans faire la moindre copie ou transformation. Et lorsque l'on travaille avec beaucoup de données, cela est loin d'être négligeable. <br>
Le format parquet, développé par Apache, est entièrement compatible avec Arrow. La <a href="https://fr.wikipedia.org/wiki/S%C3%A9rialisation">sérialisation</a> et la <a href="https://fr.wikipedia.org/wiki/S%C3%A9rialisation#D%C3%A9s%C3%A9rialisation">déserialisation</a> d'un DataFrame,
c'est à dire l'écriture et la lecture d'un fichier parquet sera très performante avec un minimum de transformation. </p>
<div class="figure">
<img src="../images/parquet/arrow.png" />
<div class="legend"> Sans Arrow, il est nécessaire de faire des conversions et des copies coûteuses entre les
différentes sources de données. Le format mémoire agnostique d'Apache Arrow permet
d'éviter toutes ces opérations coûteuses<a href="https://datacadamia.com/data/type/relation/structure/column_store"> sources. </a>
</div> </div>
<h2>Du VCF au parquet avec polars</h2>
<p>Pour lire et écrire des fichiers parquet avec Python, vous pouvez utiliser la libraire <a href="https://fr.wikipedia.org/wiki/Pandas">pandas</a>. Cependant, pandas n'est pas basée sur Arrow et reste très lente pour manipuler de gros volumes de données.
Nous utiliserons ici les performances quasi <em>magique</em> de la libraire <a href="https://www.pola.rs/">pola.rs</a> pour transformer un fichier VCF en fichier parquet. </p>
<p>Pola.rs est écrit en Rust, est compatible avec Arrow, support nativement le multithreading et propose une <em><a href="https://fr.wikipedia.org/wiki/%C3%89valuation_paresseuse">Lazy évaluation</a></em> des transformations.
Je vous invite à jeter un œil sur la <a href="https://pola-rs.github.io/polars/py-polars/html/reference/">documentation Python</a> pour vous familiariser avec l'API qui diffère de celle de pandas. </p>
<h3>Téléchargement du fichier VCF</h3>
<p>Téléchargeons un fichier VCF provenant du projet <a href="https://www.internationalgenome.org/">1000Genomes</a> et décompressez-le. Nous allons lire le
fichier VCF comme un fichier CSV en mode Lazy. Ce dernier mode ne fonctionne pas encore pour les
fichiers compressés.</p>
<div class="highlight"><pre><span></span><code><span class="c1"># Téléchargement</span>
wget ftp://ftp.1000genomes.ebi.ac.uk/vol1/ftp/data_collections/1000_genomes_project/release/20190312_biallelic_SNV_and_INDEL/ALL.wgs.shapeit2_integrated_snvindels_v2a.GRCh38.27022019.sites.vcf.gz
<span class="c1"># Decompression</span>
gzip -d ALL.wgs.shapeit2_integrated_snvindels_v2a.GRCh38.27022019.sites.vcf.gz
</code></pre></div>
<h3>Création du fichier parquet avec pola.rs</h3>
<p>Après avoir installé pola.rs via: </p>
<div class="highlight"><pre><span></span><code>pip install pola.rs
</code></pre></div>
<ul>
<li>Lisez le fichier VCF comme un CSV avec <em>pl.scan_csv</em> </li>
<li>Sélectionner les colonnes CHROM, POS, REF, ALT </li>
<li>Écrire le fichier <em>variants.parquet</em> avec <em>sink_parquet</em></li>
</ul>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">pola.rs</span>
<span class="n">pl</span><span class="o">.</span><span class="n">scan_csv</span><span class="p">(</span>
<span class="s2">"ALL.wgs.shapeit2_integrated_snvindels_v2a.GRCh38.27022019.sites.vcf"</span><span class="p">,</span>
<span class="n">skip_rows</span><span class="o">=</span><span class="mi">40</span><span class="p">,</span> <span class="c1"># Je saute les 40 premieres lignes de commentaires</span>
<span class="n">sep</span><span class="o">=</span><span class="s2">"</span><span class="se">\t</span><span class="s2">"</span><span class="p">,</span> <span class="c1"># separateur TSV</span>
<span class="n">dtypes</span><span class="o">=</span><span class="p">{</span><span class="s2">"#CHROM"</span><span class="p">:</span> <span class="n">pl</span><span class="o">.</span><span class="n">Utf8</span><span class="p">},</span> <span class="c1"># Je précise le type, sinon la colonne est considéré comme un int</span>
<span class="p">)</span><span class="o">.</span><span class="n">select</span><span class="p">([</span> <span class="c1"># Je Selection les colonnes souhaitées</span>
<span class="n">pl</span><span class="o">.</span><span class="n">col</span><span class="p">(</span><span class="s2">"#CHROM"</span><span class="p">)</span><span class="o">.</span><span class="n">alias</span><span class="p">(</span><span class="s2">"CHROM"</span><span class="p">),</span> <span class="c1"># Je renomme ici la colonne avec alias</span>
<span class="n">pl</span><span class="o">.</span><span class="n">col</span><span class="p">(</span><span class="s2">"POS"</span><span class="p">),</span>
<span class="n">pl</span><span class="o">.</span><span class="n">col</span><span class="p">(</span><span class="s2">"REF"</span><span class="p">),</span>
<span class="n">pl</span><span class="o">.</span><span class="n">col</span><span class="p">(</span><span class="s2">"ALT"</span><span class="p">)]</span>
<span class="p">)</span><span class="o">.</span><span class="n">sink_parquet</span><span class="p">(</span> <span class="c1"># Ecriture du fichier parquet </span>
<span class="s2">"variants.parquet"</span>
<span class="p">)</span>
</code></pre></div>
<p>Je vous conseille de regarder le temps d'exécution et faire un <a href="https://fr.wikipedia.org/wiki/Htop">htop</a> pour voir la parallélisation opérée
ainsi que la consommation mémoire. C'est assez bluffant. Je met <strong>moins de 5 secondes</strong> sur mon ordinateurs perso (<em>AMD Ryzen 9 5900X</em>) pour traiter <strong>78'229'218</strong> variants.
Et pour la consommation mémoire, Les fonctions <em>scan_csv</em> et <em>sink_csv</em> permettent de faire la transformation du VCF sans le charger en mémoire. Regardez aussi les tailles du fichier. <strong>225Mo</strong> pour le fichier parquet et <strong>1.3Go</strong> pour son équivalent en CSV. En effet, les fichiers parquets sont compressés naturellement du fait du modèle orienté colonne.</p>
<h3>Requête SQL avec DuckDB</h3>
<p>À présent essayer de requêtes sur ce fichier. Nous pourrions le faire avec pola.rs, mais nous allons
plutôt faire une requête SQL en utilisant <a href="https://duckdb.org/">duckDB</a> qui s'installe tout aussi facilement avec la
commande suivante: </p>
<div class="highlight"><pre><span></span><code>pip install duckdb
</code></pre></div>
<p>Pour exécuter une requête SQL sur un fichier parquet, il suffit de considérer le fichier comme le
nom d'une table SQL : </p>
<div class="highlight"><pre><span></span><code><span class="c1"># Simple requête pour visualiser le contenu du fichier parquet </span>
<span class="n">duckdb</span><span class="o">.</span><span class="n">sql</span><span class="p">(</span><span class="s2">"SELECT * FROM 'variants.parquet'"</span><span class="p">)</span>
<span class="c1"># ┌─────────┬─────────┬─────────┬─────────┬─────────┐</span>
<span class="c1"># │ #CHROM │ POS │ REF │ ALT │ ID │</span>
<span class="c1"># │ varchar │ int64 │ varchar │ varchar │ varchar │</span>
<span class="c1"># ├─────────┼─────────┼─────────┼─────────┼─────────┤</span>
<span class="c1"># │ 1 │ 10416 │ CCCTAA │ C │ . │</span>
<span class="c1"># │ 1 │ 16103 │ T │ G │ . │</span>
<span class="c1"># │ 1 │ 17496 │ AC │ A │ . │</span>
<span class="c1"># │ 1 │ 51479 │ T │ A │ . │</span>
<span class="c1"># │ 1 │ 51898 │ C │ A │ . │</span>
<span class="c1"># │ 1 │ 51928 │ G │ A │ . │</span>
</code></pre></div>
<p>À présent, essayons de faire plus compliquer en comptant le nombre de <a href="https://dridk.me/transition_transversion.html">transitions</a> et de <a href="https://dridk.me/transition_transversion.html">transversions</a>. C'est à dire, le nombre de combinaisons A>T, C>G etc ... </p>
<div class="highlight"><pre><span></span><code><span class="c1"># A partir des SNPS len(ref)=1 et len(alt)=1</span>
<span class="c1"># Je construit une liste [ref, alt] que je trie </span>
<span class="c1"># Je fait un groupby et un comptage</span>
<span class="n">q</span> <span class="o">=</span> <span class="s2">"""</span>
<span class="s2">"SELECT list_sort([ref,alt]) AS mut, COUNT(*) as count FROM 'variants.parquet' </span>
<span class="s2">WHERE len(ref) = 1 AND len(alt)=1 GROUP BY mut</span>
<span class="s2">"""</span>
<span class="n">duckdb</span><span class="o">.</span><span class="n">sql</span><span class="p">(</span><span class="n">q</span><span class="p">)</span>
<span class="c1"># ┌───────────┬──────────────┐</span>
<span class="c1"># │ mut │ count │</span>
<span class="c1"># │ varchar[] │ int64 │</span>
<span class="c1"># ├───────────┼──────────────┤</span>
<span class="c1"># │ [C, T] │ 24782079 │</span>
<span class="c1"># │ [A, G] │ 24828822 │</span>
<span class="c1"># │ [G, T] │ 6103978 │</span>
<span class="c1"># │ [A, T] │ 5140035 │</span>
<span class="c1"># │ [A, C] │ 6086989 │</span>
<span class="c1"># │ [C, G] │ 6315729 │</span>
<span class="c1"># └───────────┴──────────────┘</span>
</code></pre></div>
<p>Vous devriez retrouver après quelques secondes les mêmes proportions que j'ai déjà détaillées dans un <a href="transition_transversion.html">précédent billet</a>.</p>
<h2>Autres astuces</h2>
<h3>Le partitionnement</h3>
<p>Niveau performance, c'est déjà bluffant. Mais il existe différentes <a href="https://duckdb.org/docs/sql/indexes.html">méthodes d'optimisation</a> pour être plus performant suivant l'usage des données.
Le partitionnement consiste à découper votre fichier parquet en plusieurs fichiers parquets depuis une ou plusieurs colonnes. Par exemple, je peut partitionner le fichier parquet <em>variants.parquet</em> par chromosomes. Si je dois chercher un variant sur le chromosome 8, je peux regarder uniquement dans le fichier correspondant. Inutile de parcourir les variants du chromosomes 2. </p>
<p>Construisons une partition sur la colonne chromosome avec duckDB : </p>
<div class="highlight"><pre><span></span><code><span class="n">duckdb</span><span class="o">.</span><span class="n">sql</span><span class="p">(</span>
<span class="s2">"COPY (SELECT * FROM 'variants.parquet') TO 'chromosomes' (FORMAT PARQUET, PARTITION_BY (CHROM))"</span>
<span class="p">)</span>
</code></pre></div>
<p>Après avoir exécuté cette requête, vous devriez avoir un dossier <em>chromosomes</em> contenant de
nombreux fichiers triés par chromosomes. <br>
Pour sélectionner vos variants depuis ce dossier, il suffit d'utiliser le caractère étoile ou des expressions régulières pour sélectionner la source de données souhaitées. </p>
<p>Dans l'exemple suivant, je sélectionne tous les variants à partir de tous les fichiers :</p>
<div class="highlight"><pre><span></span><code><span class="n">duckdb</span><span class="o">.</span><span class="n">sql</span><span class="p">(</span><span class="s2">"SELECT * FROM 'chromosomes/*/*.parquet'"</span><span class="p">)</span>
</code></pre></div>
<h3>Combiner Pola.rs et duckdb</h3>
<p>Une dernière astuce pour la fin. Pola.rs et duckdb sont de très bon amies et sont interchangeable. Vous pouvez switcher de l'un à l'autre très facilement ( Merci Arrow ). </p>
<div class="highlight"><pre><span></span><code><span class="c1"># Passer de duckdb à pola.rs</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">duckdb</span><span class="o">.</span><span class="n">sql</span><span class="p">(</span><span class="s2">"SELECT * FROM 'variants.parquet' WHERE CHROM='22'"</span><span class="p">)</span><span class="o">.</span><span class="n">pl</span><span class="p">()</span>
<span class="c1"># Passer de pola.rs à Duckdb</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">pl</span><span class="o">.</span><span class="n">read_csv</span><span class="p">(</span><span class="o">....</span><span class="p">)</span>
<span class="n">duckdb</span><span class="o">.</span><span class="n">sql</span><span class="p">(</span><span class="s2">"SELECT * FROM df"</span><span class="p">)</span>
</code></pre></div>
<h2>Conclusion</h2>
<p>Pola.rs et Duckdb sont des technologies née du <strong>big data</strong> qui, je vous parie, vont devenir des références pour la manipulation des données volumineuses et remplacer leurs prédécesseurs comme Pandas. </p>
<h2>Références</h2>
<ul>
<li><a href="https://www.pola.rs/">Pola.rs</a></li>
<li><a href="https://duckdb.org/">Duckdb</a></li>
<li><a href="https://www.cetic.be/Apache-Parquet-pour-le-stockage-de-donnees-volumineuses">Apache Parquet pour le stockage de données volumineuse</a></li>
<li><a href="https://towardsdatascience.com/demystifying-the-parquet-file-format-13adb0206705">Demystifying the Parquet file Format</a></li>
<li><a href="https://clickhouse.com/">Clickhouse : une autre base OLAP</a></li>
</ul>Créer un module python en C++ avec SWIG2022-01-17T23:18:57+01:002022-01-17T23:18:57+01:00Sacha Schutztag:dridk.me,2022-01-17:/swig.html<p><a href="https://fr.wikipedia.org/wiki/Python_(langage)">Python</a> n'étant pas connu pour sa rapidité, il existe plusieurs solutions pour exécuter du code compilé. Je citerai par exemple <a href="https://numba.pydata.org/">numba</a> qui utilise des décorateurs dédiés ou encore <a href="https://cython.org/">cython</a> qui permet d'écrire un module avec un langage mélangeant du python et du <a href="https://fr.wikipedia.org/wiki/C_(langage)">C</a>. <br>
Mais mon regard s'est porté récemment vers …</p><p><a href="https://fr.wikipedia.org/wiki/Python_(langage)">Python</a> n'étant pas connu pour sa rapidité, il existe plusieurs solutions pour exécuter du code compilé. Je citerai par exemple <a href="https://numba.pydata.org/">numba</a> qui utilise des décorateurs dédiés ou encore <a href="https://cython.org/">cython</a> qui permet d'écrire un module avec un langage mélangeant du python et du <a href="https://fr.wikipedia.org/wiki/C_(langage)">C</a>. <br>
Mais mon regard s'est porté récemment vers la librairie <a href="http://www.swig.org/Doc1.3/Python.html">SWIG</a> qui permet facilement d'encapsuler du code <a href="https://fr.wikipedia.org/wiki/C%2B%2B">C++</a> dans un module Python. Je vous propose donc dans ce billet, d'écrire à l'aide de <em>SWIG</em>, un module en C++ permettant de compter le nombre de base A,C,G,T présent dans un fichier <a href="https://fr.wikipedia.org/wiki/FASTA_(format_de_fichier)">Fasta</a>. </p>
<h2>Objectif</h2>
<p>L'objectif est d'écrire un module python appelé <em>fastareader</em> qui s’exécute de la façon suivante : </p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">fastareader</span> <span class="kn">import</span> <span class="n">FastaReader</span>
<span class="c1"># Instanciation : Compte le nombre de base A,C,G,T dans le fichier chr22.fa</span>
<span class="n">reader</span> <span class="o">=</span> <span class="n">FastaReader</span><span class="p">(</span><span class="s2">"chr22.fa"</span><span class="p">)</span>
<span class="c1"># Affiche le nombre de chaque base</span>
<span class="nb">print</span><span class="p">(</span><span class="n">reader</span><span class="p">[</span><span class="s2">"A"</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="n">reader</span><span class="p">[</span><span class="s2">"C"</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="n">reader</span><span class="p">[</span><span class="s2">"G"</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="n">reader</span><span class="p">[</span><span class="s2">"T"</span><span class="p">])</span>
</code></pre></div>
<h2>Installation de SWIG</h2>
<p>Swig est un programme en ligne de commande qui permet de générer automatiquement le code d'un module python à partir de notre code C++. <br>
Pour installer Swig dans sa version (4.0):</p>
<ul>
<li>
<p><strong>ubuntu</strong><br>
<code>sudo apt-get install swig</code></p>
</li>
<li>
<p><strong>Windows</strong> <br>
Télécharger le binaire <a href="http://www.swig.org/Doc1.3/Windows.html">ici</a></p>
</li>
</ul>
<h2>Création du module en C++</h2>
<p>Je crée d'abord 2 fichiers (<em>fastareader.h</em> et <em>fastareader.cpp</em>) contenant la classe C++ qui nous calculera le nombre de base après avoir parcouru le fichier. <br>
Je lui ajoute la <a href="https://www.geeksforgeeks.org/dunder-magic-methods-python/">méthode magique</a> <strong><code>__getitem__</code></strong> qui sera interprétée par python comme surcharge d’opérateur pour accéder aux résultats via la syntaxe <strong><code>reader['A']</code></strong>.</p>
<h4>Fastareader.h</h4>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf"><iostream></span><span class="cp"></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><string></span><span class="cp"></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><map></span><span class="cp"></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><fstream></span><span class="cp"></span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf"><cctype></span><span class="cp"></span>
<span class="k">using</span><span class="w"> </span><span class="k">namespace</span><span class="w"> </span><span class="nn">std</span><span class="p">;</span><span class="w"></span>
<span class="k">using</span><span class="w"> </span><span class="n">CountMap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">map</span><span class="o"><</span><span class="kt">char</span><span class="p">,</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="p">;</span><span class="w"> </span>
<span class="k">class</span><span class="w"> </span><span class="nc">FastaReader</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="k">public</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="c1">// Constructeur </span>
<span class="w"> </span><span class="n">FastaReader</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="n">string</span><span class="o">&</span><span class="w"> </span><span class="n">filename</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="c1">// Fonction magique pour pouvoir faire reader['A']</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="nf">__getitem__</span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="n">base</span><span class="p">);</span><span class="w"></span>
<span class="k">protected</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="c1">// Lis le fichier lors de la construction</span>
<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="n">read_file</span><span class="p">();</span><span class="w"></span>
<span class="k">private</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="n">string</span><span class="w"> </span><span class="n">mFilename</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">CountMap</span><span class="w"> </span><span class="n">mCounter</span><span class="p">;</span><span class="w"></span>
<span class="p">};</span><span class="w"></span>
</code></pre></div>
<h4>Fastareader.cpp</h4>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span><span class="w"> </span><span class="cpf">"fastareader.h"</span><span class="cp"></span>
<span class="n">FastaReader</span><span class="o">::</span><span class="n">FastaReader</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="n">string</span><span class="o">&</span><span class="w"> </span><span class="n">filename</span><span class="p">)</span><span class="w"></span>
<span class="o">:</span><span class="n">mFilename</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">read_file</span><span class="p">();</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="kt">int</span><span class="w"> </span><span class="n">FastaReader</span><span class="o">::</span><span class="n">__getitem__</span><span class="p">(</span><span class="kt">char</span><span class="w"> </span><span class="n">base</span><span class="p">)</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">mCounter</span><span class="p">[</span><span class="n">base</span><span class="p">];</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="kt">void</span><span class="w"> </span><span class="n">FastaReader</span><span class="o">::</span><span class="n">read_file</span><span class="p">()</span><span class="w"></span>
<span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="c1">// Nous parcourons le fichier et nous comptons les bases A,C,G,T</span>
<span class="w"> </span><span class="n">ifstream</span><span class="w"> </span><span class="nf">infile</span><span class="p">(</span><span class="n">mFilename</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="n">string</span><span class="w"> </span><span class="n">line</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">mCounter</span><span class="p">[</span><span class="sc">'A'</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">mCounter</span><span class="p">[</span><span class="sc">'C'</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">mCounter</span><span class="p">[</span><span class="sc">'G'</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">mCounter</span><span class="p">[</span><span class="sc">'T'</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="n">infile</span><span class="p">.</span><span class="n">good</span><span class="p">())</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="kt">char</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">toupper</span><span class="p">(</span><span class="n">infile</span><span class="p">.</span><span class="n">get</span><span class="p">());</span><span class="w"></span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">((</span><span class="n">c</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="sc">'A'</span><span class="p">)</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">(</span><span class="n">c</span><span class="w"> </span><span class="o">==</span><span class="sc">'C'</span><span class="p">)</span><span class="w"> </span><span class="o">||</span><span class="p">(</span><span class="w"> </span><span class="n">c</span><span class="o">==</span><span class="sc">'G'</span><span class="p">)</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">(</span><span class="n">c</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="sc">'T'</span><span class="p">))</span><span class="w"></span>
<span class="w"> </span><span class="n">mCounter</span><span class="p">[</span><span class="n">c</span><span class="p">]</span><span class="o">++</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Vous pouvez vérifier rapidement que le code compile avec le commande suivante. Mais par la suite, nous utiliserons <a href="https://setuptools.pypa.io/en/latest/">setuptools</a> pour la compilation et l'installation du module.</p>
<div class="highlight"><pre><span></span><code>g++ -c fastareader.cpp
</code></pre></div>
<h2>Le fichier d'interface SWIG</h2>
<p>L'interfaçage entre python et le C++ est paramétrée depuis le fichier <em>fastareader.i</em>. C'est ce fichier qu'il faudra modifier si vous voulez détailler comment convertir des objets C++ en objets Python. Cette conversion existe déjà pour la plus part des types. Par exemple, ici j'importe <strong><code>std_string.i</code></strong> afin de mapper les strings C++ en string Python. Allez voir la documentation sur les <em><a href="http://www.swig.org/Doc1.3/Typemaps.html">typemaps</a></em> pour plus de détails.</p>
<h4>Fastareader.i</h4>
<div class="highlight"><pre><span></span><code><span class="o">%</span><span class="k">module</span><span class="w"> </span><span class="n">fastareader</span><span class="w"> </span><span class="c1">// Nom du module python généré</span>
<span class="o">%</span><span class="n">include</span><span class="w"> </span><span class="s">"std_string.i"</span><span class="w"> </span><span class="c1">// permet de convertir les std:::string en Python string</span>
<span class="o">%</span><span class="p">{</span><span class="w"></span>
<span class="c1">// Le code de cette section sera intégré au fichier produit</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">"fastareader.h"</span><span class="c1"> </span><span class="cp"></span>
<span class="w"> </span><span class="o">%</span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="c1">// Cette section contient la liste des interfaces C++ à encapsuler</span>
<span class="w"> </span><span class="o">%</span><span class="n">include</span><span class="w"> </span><span class="s">"fastareader.h"</span><span class="w"></span>
</code></pre></div>
<p>Vous pouvez à présent générer le code de l'extension python avec la commande suivante:</p>
<div class="highlight"><pre><span></span><code>swig -c++ -python fastareader.i
</code></pre></div>
<p>Si tout se passe bien, vous devez obtenir 2 fichiers:</p>
<ul>
<li>un fichier <strong>fastareader.py</strong> contenant le module python à importer.</li>
<li>un fichier <strong>fastareader_wrap.cxx</strong> contenant l'encapsulation de votre code C++.</li>
</ul>
<h2>Compilation avec setuptools</h2>
<p>Une fois le code de l'extension généré, il faut le compiler et l'installer.
Pour cela, vous pouvez utiliser <a href="https://setuptools.pypa.io/en/latest/">setuptools</a> disponible dans la librairie standard de python. <br>
Créer le fichier <em>setup.py</em> avec le code suivant:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">distutils.core</span> <span class="kn">import</span> <span class="n">setup</span><span class="p">,</span> <span class="n">Extension</span>
<span class="c1"># Description de l'extension et du code à compiler.</span>
<span class="c1"># Notez bien le nom de l'extension `_fastareader` préfixé par le caractère `_` </span>
<span class="n">fastareader_module</span> <span class="o">=</span> <span class="n">Extension</span><span class="p">(</span>
<span class="s2">"_fastareader"</span><span class="p">,</span> <span class="n">sources</span><span class="o">=</span><span class="p">[</span><span class="s2">"fastareader.cpp"</span><span class="p">,</span> <span class="s2">"fastareader_wrap.cxx"</span><span class="p">]</span>
<span class="p">)</span>
<span class="n">setup</span><span class="p">(</span>
<span class="n">name</span><span class="o">=</span><span class="s2">"fastareader"</span><span class="p">,</span>
<span class="n">version</span><span class="o">=</span><span class="s2">"0.1"</span><span class="p">,</span>
<span class="n">author</span><span class="o">=</span><span class="s2">"Sacha Schutz"</span><span class="p">,</span>
<span class="n">ext_modules</span><span class="o">=</span><span class="p">[</span><span class="n">fastareader_module</span><span class="p">],</span>
<span class="n">py_modules</span><span class="o">=</span><span class="p">[</span><span class="s2">"fastareader"</span><span class="p">],</span>
<span class="p">)</span>
</code></pre></div>
<p>Compiler et installer maintenant votre module avec les commandes suivantes: </p>
<div class="highlight"><pre><span></span><code>python -m virtualenv venv
<span class="nb">source</span> venv/bin/activate
python setup.py build <span class="c1"># Compilation </span>
python setup.py install <span class="c1"># Installation </span>
</code></pre></div>
<p>Si tout c'est bien passé, vous devriez pouvoir lancer le code python vu au début de ce billet.</p>
<blockquote>
<p><strong>Note</strong>: Sous windows, vous aurez besoin d'installer <a href="https://docs.microsoft.com/fr-fr/visualstudio/install/install-visual-studio?view=vs-2022">Visual studio</a> pour compiler une extension Python. Attention, à bien vérifier les architectures (x64, x86) et quel versions de python vous utilisez. </p>
</blockquote>
<h2>Le benchmark</h2>
<p>Sur mon PC portable, Je met <strong>0.63 secondes</strong> pour compter l'ensemble des bases du chromosome 22 avec la module C++. Et encore, le code n'est pas optimisé.</p>
<h4>bench_cpp.py</h4>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">fastareader</span> <span class="kn">import</span> <span class="n">FastaReader</span>
<span class="n">reader</span> <span class="o">=</span> <span class="n">FastaReader</span><span class="p">(</span><span class="s2">"chr22.fasta"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">reader</span><span class="p">[</span><span class="s2">"A"</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="n">reader</span><span class="p">[</span><span class="s2">"C"</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="n">reader</span><span class="p">[</span><span class="s2">"G"</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="n">reader</span><span class="p">[</span><span class="s2">"T"</span><span class="p">])</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> ➜ <span class="nb">time</span> python bench_cpp.py
<span class="m">9094775</span>
<span class="m">8375985</span>
<span class="m">8369235</span>
<span class="m">9054551</span>
python test.py <span class="m">0</span>,63s user <span class="m">0</span>,02s system <span class="m">99</span>% cpu <span class="m">0</span>,645 total
</code></pre></div>
<p>Le même code écrit uniquement avec python prend <strong>12 secondes</strong>. Soit 20 fois plus longtemps. </p>
<h4>bench_python.py</h4>
<div class="highlight"><pre><span></span><code><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">"chr22.fasta"</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
<span class="n">counter</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">counter</span><span class="p">[</span><span class="s2">"A"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">counter</span><span class="p">[</span><span class="s2">"C"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">counter</span><span class="p">[</span><span class="s2">"G"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">counter</span><span class="p">[</span><span class="s2">"T"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">byte</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">while</span> <span class="n">byte</span><span class="p">:</span>
<span class="n">byte</span> <span class="o">=</span> <span class="nb">str</span><span class="o">.</span><span class="n">upper</span><span class="p">(</span><span class="n">byte</span><span class="p">)</span>
<span class="k">if</span> <span class="n">byte</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">"A"</span><span class="p">,</span> <span class="s2">"C"</span><span class="p">,</span> <span class="s2">"G"</span><span class="p">,</span> <span class="s2">"T"</span><span class="p">):</span>
<span class="n">counter</span><span class="p">[</span><span class="n">byte</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">byte</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">counter</span><span class="p">[</span><span class="s2">"A"</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="n">counter</span><span class="p">[</span><span class="s2">"C"</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="n">counter</span><span class="p">[</span><span class="s2">"G"</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="n">counter</span><span class="p">[</span><span class="s2">"T"</span><span class="p">])</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="o">(</span>venv<span class="o">)</span> ➜ <span class="nb">time</span> python bench_python.py
<span class="m">9094775</span>
<span class="m">8375985</span>
<span class="m">8369235</span>
<span class="m">9054551</span>
python test_py.py <span class="m">12</span>,67s user <span class="m">0</span>,02s system <span class="m">99</span>% cpu <span class="m">12</span>,791 total
</code></pre></div>
<h2>Si vous voulez m'aider !</h2>
<p>J'ai commencé à écrire un simple parseur de fichier VCF, qui contrairement à <a href="https://github.com/brentp/cyvcf2">cyvcf2</a>, ne dépend pas de htslib et compile facilement sous windows.
<a href="https://github.com/dridk/vcfreader">https://github.com/dridk/vcfreader</a></p>
<h2>Référence</h2>
<ul>
<li><a href="http://www.swig.org/doc.html">Documentation de SWIG</a></li>
</ul>Du Rock, Wikidata et du SPARQL2022-01-10T00:25:17+01:002022-01-10T00:25:17+01:00Sacha Schutztag:dridk.me,2022-01-10:/wikidata.html<p>Pouvez vous me citer toutes les personnes ayant eu un Oscar et le prix Nobel ? Quelles sont les lieux de naissance de toutes les célébrités se prénommant Antoine ? Trouvez moi tous les médicaments qui cible des gènes liés à la prolifération cellulaire ? <br>
Ce genre de question peut être difficile à …</p><p>Pouvez vous me citer toutes les personnes ayant eu un Oscar et le prix Nobel ? Quelles sont les lieux de naissance de toutes les célébrités se prénommant Antoine ? Trouvez moi tous les médicaments qui cible des gènes liés à la prolifération cellulaire ? <br>
Ce genre de question peut être difficile à répondre si vous utiliser seulement un moteur de recherche comme <a href="https://www.google.com/">Google</a>. Mais en utilisant une <a href="https://fr.wikipedia.org/wiki/Ontologie_(informatique)">ontologie</a> et un langage dédié appelé <a href="https://fr.wikipedia.org/wiki/SPARQL">SPARQL
</a>, vous allez pouvoir répondre à toutes ces questions en un éclair.<br>
Dans ce billet, je vous propose d'explorer l'ontologie de <a href="https://fr.wikipedia.org/wiki/Wikip%C3%A9dia:Accueil_principal">Wikipedia</a> (<a href="https://www.wikidata.org/wiki/Wikidata:Main_Page">wikidata</a>) et utiliser SPARQL pour construire une carte du monde montrant le nombre de groupe de <a href="https://fr.wikipedia.org/wiki/Rock">rock</a> par habitant de chaque pays.</p>
<h2>Qu'est ce qu'une ontologie ?</h2>
<p>Une ontologie est une façon d'organiser le savoir en reliant de nombreux concepts entre eux. Plus exactement, c'est un <a href="https://fr.wikipedia.org/wiki/Graphe">graphe</a> construit à partir d'un ensemble de <a href="https://fr.wikipedia.org/wiki/Triplet_RDF">triplets</a> composé chacun d'un <em>sujet</em>, d'un <em>prédicat</em> et d'un <em>objet</em>. <br>
Par exemple, les 3 triplets suivant permettent de relier les <a href="https://www.wikidata.org/wiki/Q11036">Rolling Stones</a> au <a href="https://www.wikidata.org/wiki/Q203925">Fish and Chips</a>. </p>
<div class="highlight"><pre><span></span><code># SUJET PREDICAT OBJET
<The Rolling Stones> <est d'origine du> <Royaume uni>
<The Rolling Stones> <est un groupe de> <Rock>
<Le Fish and Chips> <est d'origine du> <Royaume uni>
</code></pre></div>
<div class="figure">
<img src="../images/wikidata/graphe.png" />
<div class="legend"> Exemple d'ontologie </div>
</div>
<p>Dans une ontologie, les concepts sont définis par un identifiant unique. <br>
Sur wikidata, Le concept "<em>Rolling Stones</em>" porte l'identifiant <a href="https://www.wikidata.org/wiki/Q11036">Q11036</a> et le concept "<em>Fish and Chips</em>" porte l'identifiant <a href="https://www.wikidata.org/wiki/Q203925">Q203925</a>. Il en est de même pour les prédicats et les objets. Ainsi, les triplets précédents peuvent s'écrire de la manière suivante:</p>
<div class="highlight"><pre><span></span><code> wd:Q11036 wdt:P17 wd:Q145
wd:Q11036 wdt:P31 wd:Q5741069
wd:Q203925 wdt:P17 wd:Q145
</code></pre></div>
<p>Tous les triplets d'une ontologie sont généralement stockés dans un fichier texte au <a href="https://fr.wikipedia.org/wiki/Resource_Description_Framework">format RDF</a> ou dans une base de donnée dédiée appelée <a href="https://fr.wikipedia.org/wiki/Base_de_donn%C3%A9es_orient%C3%A9e_graphe#Triple_store">triple store</a>.
Vous trouverez sur internet de nombreuses ontologies, notamment en biologie avec par exemple <a href="http://geneontology.org/">GO</a> ( Gene ontology ) décrivant les éléments cellulaires ou <a href="https://hpo.jax.org/">HPO</a> (Human Phenotype Ontology) décrivant les signes cliniques des maladies. L'ensemble des ontologies disponible sur le web vise à former ce qu'on appelle <a href="https://fr.wikipedia.org/wiki/Web_s%C3%A9mantique">le web sémantique</a>.</p>
<h2>Le langage SPARQL</h2>
<p><a href="https://www.wikidata.org/wiki/Wikidata:SPARQL_tutorial/fr">SPARQL</a> est un langage dédié à l'extraction d'information depuis une ontologie. Je vous invite à exécuter les requêtes suivantes avec <a href="https://query.wikidata.org/">l'outil en ligne</a> mis à disposition par wikidata. <br>
Le principe est assez simple. Il faut écrire des triplets en remplaçant les concepts inconnus qui nous intéressent par des variables. <br>
Par exemple pour trouver tous les groupes de rocks anglais, nous cherchons <strong>?x</strong> tel que:</p>
<ul>
<li>?x est d'origine anglaise</li>
<li>?x est un groupe de rock </li>
</ul>
<p>En SPARQL, cela donne : </p>
<div class="highlight"><pre><span></span><code><span class="k">SELECT</span><span class="w"> </span><span class="o">?</span><span class="n">x</span><span class="w"> </span>
<span class="k">WHERE</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="o">?</span><span class="n">x</span><span class="w"> </span><span class="n">wdt</span><span class="p">:</span><span class="n">P17</span><span class="w"> </span><span class="n">wd</span><span class="p">:</span><span class="n">Q145</span><span class="p">.</span><span class="w"></span>
<span class="o">?</span><span class="n">x</span><span class="w"> </span><span class="n">wdt</span><span class="p">:</span><span class="n">P31</span><span class="w"> </span><span class="n">wd</span><span class="p">:</span><span class="n">Q5741069</span><span class="p">.</span><span class="w"></span>
<span class="err">}</span><span class="w"></span>
</code></pre></div>
<p>Pour avoir le noms des concepts en français: </p>
<div class="highlight"><pre><span></span><code><span class="k">SELECT</span><span class="w"> </span><span class="o">?</span><span class="n">x</span><span class="w"> </span><span class="o">?</span><span class="n">xLabel</span><span class="w"> </span>
<span class="k">WHERE</span><span class="w"> </span>
<span class="err">{</span><span class="w"></span>
<span class="o">?</span><span class="n">x</span><span class="w"> </span><span class="n">wdt</span><span class="p">:</span><span class="n">P17</span><span class="w"> </span><span class="n">wd</span><span class="p">:</span><span class="n">Q145</span><span class="p">.</span><span class="w"></span>
<span class="o">?</span><span class="n">x</span><span class="w"> </span><span class="n">wdt</span><span class="p">:</span><span class="n">P31</span><span class="w"> </span><span class="n">wd</span><span class="p">:</span><span class="n">Q5741069</span><span class="p">.</span><span class="w"></span>
<span class="n">SERVICE</span><span class="w"> </span><span class="n">wikibase</span><span class="p">:</span><span class="n">label</span><span class="w"> </span><span class="err">{</span><span class="w"> </span><span class="n">bd</span><span class="p">:</span><span class="n">serviceParam</span><span class="w"> </span><span class="n">wikibase</span><span class="p">:</span><span class="k">language</span><span class="w"> </span><span class="ss">"[AUTO_LANGUAGE],en"</span><span class="p">.</span><span class="w"> </span><span class="err">}</span><span class="w"></span>
<span class="err">}</span><span class="w"></span>
</code></pre></div>
<p>Et pour récupérer tous les groupes de rocks, le pays d'origine et le nombre d'habitant, je fais : </p>
<div class="highlight"><pre><span></span><code><span class="k">SELECT</span><span class="w"> </span><span class="o">?</span><span class="n">groupeLabel</span><span class="w"> </span><span class="o">?</span><span class="n">paysLabel</span><span class="w"> </span><span class="o">?</span><span class="n">population</span><span class="w"></span>
<span class="k">WHERE</span><span class="w"> </span>
<span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="o">?</span><span class="n">groupe</span><span class="w"> </span><span class="n">wdt</span><span class="p">:</span><span class="n">P31</span><span class="w"> </span><span class="n">wd</span><span class="p">:</span><span class="n">Q5741069</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="n">wdt</span><span class="p">:</span><span class="n">P495</span><span class="w"> </span><span class="o">?</span><span class="n">pays</span><span class="p">.</span><span class="w"></span>
<span class="w"> </span><span class="o">?</span><span class="n">pays</span><span class="w"> </span><span class="n">wdt</span><span class="p">:</span><span class="n">P1082</span><span class="w"> </span><span class="o">?</span><span class="n">population</span><span class="p">.</span><span class="w"></span>
<span class="w"> </span><span class="n">SERVICE</span><span class="w"> </span><span class="n">wikibase</span><span class="p">:</span><span class="n">label</span><span class="w"> </span><span class="err">{</span><span class="w"> </span><span class="n">bd</span><span class="p">:</span><span class="n">serviceParam</span><span class="w"> </span><span class="n">wikibase</span><span class="p">:</span><span class="k">language</span><span class="w"> </span><span class="ss">"[AUTO_LANGUAGE],en"</span><span class="p">.</span><span class="w"> </span><span class="err">}</span><span class="w"> </span>
<span class="err">}</span><span class="ss">""</span><span class="err">"</span><span class="w"></span>
</code></pre></div>
<p>Je vous invite à lire <a href="https://www.wikidata.org/wiki/Wikidata:SPARQL_tutorial/fr">ce tutoriel</a> pour plus de précision et à bien utiliser l'autocompletion de l'éditeur (ctrl+espace) pour éviter à devoir chercher les concepts un par un.</p>
<h2>Exécution depuis Python</h2>
<p>L’éditeur SPARQL de wikidata propose un bouton magique pour générer du code dans différents langages.</p>
<div class="figure">
<img src="../images/wikidata/editor.png" />
<div class="legend"> Editeur SPARQL de wikidata </div>
</div>
<p>Ainsi vous pouvez exécuter en python une requête SPARQL, récupérer le résultat en <a href="https://fr.wikipedia.org/wiki/JavaScript_Object_Notation">JSON</a> et construire un <a href="https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.html">Dataframe</a> avec <a href="https://pandas.pydata.org/docs/index.html">pandas</a>. Vous aurez besoin du package <a href="https://pypi.org/project/SPARQLWrapper/">sparqlwrapper</a>. </p>
<div class="highlight"><pre><span></span><code><span class="c1"># Installer sparqlwrapper</span>
<span class="c1">#!pip install sparqlwrapper</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">from</span> <span class="nn">SPARQLWrapper</span> <span class="kn">import</span> <span class="n">SPARQLWrapper</span><span class="p">,</span> <span class="n">JSON</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
<span class="n">endpoint_url</span> <span class="o">=</span> <span class="s2">"https://query.wikidata.org/sparql"</span>
<span class="n">query</span> <span class="o">=</span> <span class="s2">"""</span>
<span class="s2">SELECT ?groupeLabel ?paysLabel ?population</span>
<span class="s2">WHERE </span>
<span class="s2">{</span>
<span class="s2"> ?groupe wdt:P31 wd:Q5741069;</span>
<span class="s2"> wdt:P495 ?pays.</span>
<span class="s2"> ?pays wdt:P1082 ?population.</span>
<span class="s2"> SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } # Helps get the label in your language, if not, then en language</span>
<span class="s2">}"""</span>
<span class="k">def</span> <span class="nf">get_results</span><span class="p">(</span><span class="n">endpoint_url</span><span class="p">,</span> <span class="n">query</span><span class="p">):</span>
<span class="n">user_agent</span> <span class="o">=</span> <span class="s2">"WDQS-example Python/</span><span class="si">%s</span><span class="s2">.</span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">version_info</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">sys</span><span class="o">.</span><span class="n">version_info</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="c1"># TODO adjust user agent; see https://w.wiki/CX6</span>
<span class="n">sparql</span> <span class="o">=</span> <span class="n">SPARQLWrapper</span><span class="p">(</span><span class="n">endpoint_url</span><span class="p">,</span> <span class="n">agent</span><span class="o">=</span><span class="n">user_agent</span><span class="p">)</span>
<span class="n">sparql</span><span class="o">.</span><span class="n">setQuery</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
<span class="n">sparql</span><span class="o">.</span><span class="n">setReturnFormat</span><span class="p">(</span><span class="n">JSON</span><span class="p">)</span>
<span class="k">return</span> <span class="n">sparql</span><span class="o">.</span><span class="n">query</span><span class="p">()</span><span class="o">.</span><span class="n">convert</span><span class="p">()</span>
<span class="n">results</span> <span class="o">=</span> <span class="n">get_results</span><span class="p">(</span><span class="n">endpoint_url</span><span class="p">,</span> <span class="n">query</span><span class="p">)</span>
<span class="c1"># construction d'un dataframe</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">io</span><span class="o">.</span><span class="n">json</span><span class="o">.</span><span class="n">json_normalize</span><span class="p">(</span><span class="n">results</span><span class="p">[</span><span class="s1">'results'</span><span class="p">][</span><span class="s1">'bindings'</span><span class="p">])</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">df</span><span class="p">[[</span><span class="s2">"groupeLabel.value"</span><span class="p">,</span><span class="s2">"paysLabel.value"</span><span class="p">,</span> <span class="s2">"population.value"</span><span class="p">]]</span>
<span class="n">df</span><span class="o">.</span><span class="n">columns</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"groupe"</span><span class="p">,</span><span class="s2">"pays"</span><span class="p">,</span><span class="s2">"population"</span><span class="p">]</span>
</code></pre></div>
<h2>La carte !</h2>
<p>J'ai juste mouliné le tout avec <a href="https://geopandas.org/en/stable/">geopandas</a> sur un notebook jupyter disponible <a href="https://colab.research.google.com/drive/1PzdvHAeCxed9FtrAzpCRF5lKSmKGnfnQ?usp=sharing">ici</a>, et le tour est joué.</p>
<div class="figure">
<img src="../images/wikidata/map.png" />
<div class="legend"> Nombre de groupes de rock par pays</div>
</div>
<p>Les pays ayant le plus de groupes de rocks par habitant, sont les pays nordiques ( Finlande, Norvège, Groenland, Islande, Suède). 1 groupe référencé en Iran, 86 groupes pour la France et 270 pour le Royaume-unis !</p>
<h4>Note</h4>
<p>Toutes les questions dans l'introduction sont disponible dans le menu exemple de <a href="https://query.wikidata.org/">l’éditeur SPARQL de wikidata.</a></p>
<h3>Référence</h3>
<ul>
<li><a href="https://query.wikidata.org/">Wikidata Query service</a></li>
<li><a href="https://www.wikidata.org/wiki/Wikidata:SPARQL_tutorial/fr">Un tutoriel sur SPARQL/WIKIDATA en Français</a></li>
</ul>Analyse de génomes de SARS-CoV-22021-01-25T23:51:29+01:002021-01-25T23:51:29+01:00Sacha SCHUTZtag:dridk.me,2021-01-25:/covid_ngs.html<p>La <a href="https://fr.wikipedia.org/wiki/Pand%C3%A9mie_de_Covid-19">pandémie mondiale de Covid-19</a> a créé un élan sans précédent dans la production scientifique de données. Notamment, les données sur les génomes du virus produites par <a href="https://fr.wikipedia.org/wiki/S%C3%A9quen%C3%A7age_de_l%27ADN#S%C3%A9quen%C3%A7age_haut_d%C3%A9bit_(HTS)">séquençage haut débit</a> qui permettent aujourd'hui d'identifier de nouvelles mutations comme la <a href="https://fr.wikipedia.org/wiki/Variant_501.V2#Mutations">N501Y</a> du variant anglais <a href="https://fr.wikipedia.org/wiki/VOC-202012/01">B.1.1.7</a> où une <a href="https://fr.wikipedia.org/wiki/Asparagine">Asparagine …</a></p><p>La <a href="https://fr.wikipedia.org/wiki/Pand%C3%A9mie_de_Covid-19">pandémie mondiale de Covid-19</a> a créé un élan sans précédent dans la production scientifique de données. Notamment, les données sur les génomes du virus produites par <a href="https://fr.wikipedia.org/wiki/S%C3%A9quen%C3%A7age_de_l%27ADN#S%C3%A9quen%C3%A7age_haut_d%C3%A9bit_(HTS)">séquençage haut débit</a> qui permettent aujourd'hui d'identifier de nouvelles mutations comme la <a href="https://fr.wikipedia.org/wiki/Variant_501.V2#Mutations">N501Y</a> du variant anglais <a href="https://fr.wikipedia.org/wiki/VOC-202012/01">B.1.1.7</a> où une <a href="https://fr.wikipedia.org/wiki/Asparagine">Asparagine</a> (N) est remplacée par une <a href="https://fr.wikipedia.org/wiki/Tyrosine">Tyrosine</a> (Y) à la position 501 de la <a href="https://fr.wikipedia.org/wiki/P%C3%A9plom%C3%A8re">protéine S</a>. <br>
Le génome du <a href="https://fr.wikipedia.org/wiki/SARS-CoV-2">SARS-CoV-2</a> étant tout petit (30 kbases) par rapport au génome humain (3 Gbases), l'analyse bioinformatique peut se faire avec un ordinateur personnel. Cette analyse est donc l'occasion d'un très bon exercice pour se familiariser avec les outils d'alignement et de détection de variants.<br>
Dans ce billet, je vous propose de suivre pas-à-pas l'analyse d'un génome de SARS-CoV-2 à partir des données brutes générées par un séquenceur <a href="https://fr.wikipedia.org/wiki/Illumina">Illumina</a>. Pour cela, j'ai récupéré les données de séquençage de 245 échantillons provenant d'un laboratoire de l'état du <a href="https://fr.wikipedia.org/wiki/Delaware">Delaware</a> aux États-Unis. Plus précisément une paire de fichiers <a href="https://fr.wikipedia.org/wiki/FASTQ">Fastq</a> par échantillon contenant les courtes séquences, appelées <em>reads</em>, lus par le séquenceur. Je les ai ensuite toutes alignées sur <a href="https://www.ncbi.nlm.nih.gov/nuccore/NC_045512">le génome de référence de Wuhan</a> pour en extraire les mutations que j'ai annotées. Enfin, j'ai reconstruit les génomes de chaque échantillon afin de pouvoir attribuer le nom de leurs lignées. <br>
Pour réaliser cette analyse, il vous faudra de préférence un terminal <a href="https://fr.wikipedia.org/wiki/Linux">Linux</a> avec différents outils que vous pouvez installer avec <a href="https://docs.conda.io/en/latest/miniconda.html">conda</a>. Sinon un <a href="https://colab.research.google.com/">notebook</a> est à votre disposition à <a href="https://colab.research.google.com/drive/1V8EsdFyCmr7fmVkVf09JQhraatTWcd3f?usp=sharing">cette adresse</a>.</p>
<h2>Analyse de l'échantillon SRR13182925</h2>
<h3>Source des données</h3>
<p>Je connais 2 sources principales pour récupérer des données de séquençage. <a href="https://www.ncbi.nlm.nih.gov/sra">SRA du NCBI</a> et la base européenne <a href="https://www.ebi.ac.uk/ena/browser/home">ENA</a>. J'ai choisi cette dernière par convenance.
En fouillant, j'ai d'abord découvert le projet <a href="https://www.cogconsortium.uk">ICOG UK</a> constamment mis à jour et disposant de pas moins de 206 000 génomes à l'heure où j'écris ce billet. <br>
Mais pour mon petit PC de bureau, c'est trop de données. Nous nous contenterons pour le moment des 245 génomes du projet <a href="https://www.ebi.ac.uk/ena/browser/view/PRJNA673096">PRJNA673096</a> produit par le <a href="https://www.dhss.delaware.gov/dhss/dph/lab/labs.html">Delaware Public Health Lab</a> aux États-Unis. Il s'agit de données produites sur un <a href="https://emea.illumina.com/systems/sequencing-platforms/miseq.html">Illumina MiSeq</a> en <a href="https://dridk.me/ngs.html">Amplicon</a>.</p>
<h3>Téléchargement des données avec EnaBrowserTools</h3>
<p>Nous pouvons télécharger les fichiers Fastq directement depuis le site de l'ENA. Mais il existe un outil <a href="https://fr.wikipedia.org/wiki/Python_(langage)">python</a> en ligne de commande, <a href="https://github.com/enasequence/enaBrowserTools">enaBrowserTools</a>, qui va nous faciliter la tâche. Pour l'installer, il suffit de suivre la <a href="https://github.com/enasequence/enaBrowserTools/blob/master/README.md">documentation</a>: </p>
<ul>
<li>
<p><strong>enaDataGet</strong> nous permet de télécharger les données associées à un échantillon. </p>
</li>
<li>
<p><strong>enaGroupGet</strong> nous permet de télécharger l'ensemble des données d'un projet. </p>
</li>
</ul>
<p>Pour la suite de ce billet, nous nous contenterons d'analyser uniquement l'échantillon <a href="https://www.ebi.ac.uk/ena/browser/view/SRR13182925">SRR13182925</a>. Pour télécharger ses fichiers Fastq associés, taper la commande suivante:</p>
<div class="highlight"><pre><span></span><code>enaDataGet -f fastq SRR13182925
</code></pre></div>
<p>Cette commande crée un dossier <strong>SRR13182925</strong> contenant 2 fichiers Fastq : </p>
<ul>
<li><em>SRR13182925_1.fastq.gz</em> </li>
<li><em>SRR13182925_2.fastq.gz</em></li>
</ul>
<p>Ces 2 fichiers contiennent les courtes séquences lues, appelées <strong>reads</strong>, d'environ 150 bases provenant du génome viral trouvé dans l'échantillon. Ces reads sont lus dans les deux sens par le séquenceur. Pour cette raison, il y a 2 fichiers, un par sens de lecture. <br>
Vous pourrez en avoir un aperçu à l'aide la commande suivante : </p>
<div class="highlight"><pre><span></span><code>zcat SRR13182925_1.fastq.gz<span class="p">|</span>awk <span class="s1">'NR % 4 == 2 {print $0}'</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code>AGATAATACAGTTGAATTGGCAGGCACTTCTGTTGCATTACCAGCTTGTAGACGTACTGTGGCAGCTAAACTACCAAGTAC
ATATTGGCTTCCGGTGTAACTGTTATTGCCTGACCAGTACCAGTGTGTGTAC
TCGTAACAATCAAAGTACTTATCAACAACTTCAACTACAAATAGTAGTTGTCTGATATCACACATTGTTGGTAGATTATAACGATAGTAGTCATAATCGCTGATAGCAGCATTACCATCCTGAGCAAAGAAGAAGTGTTTTAATTCAACAGAACTTCCTTCCTTAAAGAAACCCTTAGACACAGCAAAGTCATAGAAGTCTTTGTTAAAATTACCGGGTTTGACAGTTTGAAAAGCAACATTGTTAGTAAGTGCAGCTACTGAAAAGCACGTAGTGCGT
ACATTACACATAAACGAACTTATGGATTTGTTTATGAGAATCTTCACAATTGGAACTGTAACTTTGAAGCAAGGTGAAATCAAGGATGCTACTCCTTCAGATTTTGTTCGCGCTACTGCAACGATACCGATACAAGCC
GTTAGATAGCACTCTAGTGTCAAATCTACAAACAATGGAATTAGCAGGATATCTATCGACATTGCAATTCCAAAATAGGCATACACCATCTGTGAATTTGTCAGAATGTGTGGCATAAGAATAGAAT
GTTTATTACCCTGACAAAGTTTTCAGATCCTCAGTTTTACATTCAACTCAGGACTTGTTCTTACCTTTCTTTTCCAATGTTACTTGGTTCCATGCTATACATG
etc ...
</code></pre></div>
<p>Pour plus de précision sur le format Fastq, lisez <a href="https://fr.wikipedia.org/wiki/FASTQ">la spécification du format</a>.</p>
<h3>Alignement des reads sur le génome de Wuhan</h3>
<p>L'alignement consiste à aligner les reads présents dans les fichiers Fastq (150 bases) sur un génome de référence du Sars-CoV-2 qui fait lui environ 30 000 bases. <br>
Nous devons d'abord télécharger ce génome de référence au doux nom de <a href="https://www.ncbi.nlm.nih.gov/nuccore/NC_045512">NC_045512.2</a>. Il s'agit d'un fichier <a href="https://fr.wikipedia.org/wiki/FASTA_(format_de_fichier)">Fasta</a> que vous pouvez récupérer depuis <a href="https://www.ncbi.nlm.nih.gov/nuccore/NC_045512">le site</a> ou via la commande suivante :</p>
<div class="highlight"><pre><span></span><code><span class="n">wget</span><span class="w"> </span><span class="o">-</span><span class="n">O</span><span class="w"> </span><span class="n">wuhan</span><span class="o">.</span><span class="n">fasta</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">www</span><span class="o">.</span><span class="n">ncbi</span><span class="o">.</span><span class="n">nlm</span><span class="o">.</span><span class="n">nih</span><span class="o">.</span><span class="n">gov</span><span class="o">/</span><span class="n">sviewer</span><span class="o">/</span><span class="n">viewer</span><span class="o">.</span><span class="n">cgi</span><span class="err">?</span><span class="k">tool</span><span class="o">=</span><span class="n">portal</span><span class="o">&</span><span class="n">save</span><span class="o">=</span><span class="n">file</span><span class="o">&</span><span class="nb">log</span><span class="o">$=</span><span class="n">seqview</span><span class="o">&</span><span class="n">db</span><span class="o">=</span><span class="n">nuccore</span><span class="o">&</span><span class="n">report</span><span class="o">=</span><span class="n">fasta</span><span class="o">&</span><span class="n">id</span><span class="o">=</span><span class="mi">1798174254</span><span class="o">&</span><span class="n">extrafeat</span><span class="o">=</span><span class="nb nb-Type">null</span><span class="o">&</span><span class="n">conwithfeat</span><span class="o">=</span><span class="n">on</span><span class="o">&</span><span class="n">hide</span><span class="o">-</span><span class="n">cdd</span><span class="o">=</span><span class="n">on</span><span class="w"></span>
</code></pre></div>
<p>Avant de procéder à l'alignement avec l'outil <a href="http://bio-bwa.sourceforge.net/">bwa</a>, il est nécessaire d'indexer ce génome. On fera de même avec l'outil <a href="http://www.htslib.org/">samtools</a> qui nous servira par la suite :</p>
<div class="highlight"><pre><span></span><code><span class="n">bwa</span><span class="w"> </span><span class="n">index</span><span class="w"> </span><span class="n">wuhan</span><span class="o">.</span><span class="n">fasta</span><span class="w"></span>
<span class="n">samtools</span><span class="w"> </span><span class="n">faidx</span><span class="w"> </span><span class="n">wuhan</span><span class="o">.</span><span class="n">fasta</span><span class="w"></span>
</code></pre></div>
<p>L'alignement est réalisé à l'aide de la commande ci-dessous qui nous créera un nouveau fichier <em>SRR13182925.sam</em> contenant les reads associés à leur position d'alignement sur le génome:</p>
<div class="highlight"><pre><span></span><code>bwa mem wuhan.fasta SRR13182925_1.fastq.gz SRR13182925_2.fastq.gz > SRR13182925.sam
</code></pre></div>
<p>Ce fichier <a href="https://samtools.github.io/hts-specs/SAMv1.pdf">SAM</a> est un fichier texte. On lui préfère sa version binaire, le <a href="https://samtools.github.io/hts-specs/SAMv1.pdf">BAM</a> plus légère et indexable.
Faisant d'une pierre deux coups, je trie le fichier par position, le convertit au format BAM et l'indexe avec les commandes ci-dessous:</p>
<div class="highlight"><pre><span></span><code><span class="n">samtools</span><span class="w"> </span><span class="n">sort</span><span class="w"> </span><span class="o">-</span><span class="n">O</span><span class="w"> </span><span class="n">bam</span><span class="w"> </span><span class="n">SRR13182925</span><span class="o">.</span><span class="n">sam</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">SRR13182925</span><span class="o">.</span><span class="n">bam</span><span class="w"></span>
<span class="n">samtools</span><span class="w"> </span><span class="n">index</span><span class="w"> </span><span class="n">SRR13182925</span><span class="o">.</span><span class="n">bam</span><span class="w"></span>
</code></pre></div>
<h3>Visualisation de l'alignement</h3>
<p>Pour visualiser cet alignement, vous pouvez utiliser le logiciel <strong>IGV</strong> disponible à <a href="http://software.broadinstitute.org/software/igv/">cette adresse</a>. Une fois lancé, chargez d'abord le génome de Wuhan depuis le menu <em>Genomes > Load Genome From Server</em> en cherchant SARS-Cov-2. Puis chargez le fichier <em>SRR13182925.bam</em> précédemment créé via <em>File > Load From File</em>.
Vous obtiendrez ainsi la vue suivante où j'ai zoomé sur le gène S pour visualiser une mutation. </p>
<div class="figure"> <img src="../images/covid_ngs/IGV.png" /> <div class="legend"> Visualisation des reads alignés sur le génome de référence avec le logiciel IGV. La flèche montre une mutation située sur le gène S visible sur l'ensemble des reads </div> </div>
<h3>Appel des variants et annotation</h3>
<p>Vous pourriez parcourir l'alignement visuellement et chercher toutes les mutations. Mais il est préférable de procéder de façon automatique grâce à un <a href="https://www.researchgate.net/figure/Commonly-used-NGS-variant-calling-software-Download-information-for-these-software-is_tbl1_232077026">variant caller</a>. Pour cela j'utilise <a href="https://github.com/freebayes/freebayes">freebayes</a>, qui à partir du fichier BAM, crée un <a href="https://en.wikipedia.org/wiki/Variant_Call_Format">fichier VCF</a> contenant l'ensemble des variants détectés. Avec <a href="https://pcingola.github.io/SnpEff/">SnpSift</a>, on garde uniquement les variants de bonne qualité avec un score superieur à 30 et on compresse avec <a href="http://www.htslib.org/doc/bgzip.html">bgzip</a> le fichier pour pouvoir l'indexer avec <a href="http://www.htslib.org/doc/tabix.html">tabix</a>:</p>
<div class="highlight"><pre><span></span><code>freebayes -f wuhan.fasta -p1 -C10 SRR13182925.bam<span class="p">|</span>SnpSift filter <span class="s2">"QUAL > 30"</span> - > SRR13182925.vcf
bgzip SRR13182925.vcf
tabix -p vcf SRR13182925.vcf.gz
</code></pre></div>
<p>Le fichier VCF obtenu contient uniquement les positions et les bases mutées. Pour avoir plus d'information, j'annote ce fichier avec <a href="https://pcingola.github.io/SnpEff/">SnpEff</a> qui me donnera entre autres le nom de la mutation en <a href="https://varnomen.hgvs.org/">nomenclature HGVS</a> ainsi que le gène où il se situe:</p>
<div class="highlight"><pre><span></span><code>snpEff -Xmx10G -v NC_045512.2 SRR13182925.vcf.gz > SRR13182925.ann.vcf
</code></pre></div>
<p>Il me suffit maintenant d'extraire de ce fichier les informations pertinantes. Pour cela, j'utilise <a href="https://pcingola.github.io/SnpEff/ss_filter/">SnpSift filter</a> associé à <a href="https://pcingola.github.io/SnpEff/ss_extractfields/">SnpSift extracFields</a> pour afficher les mutations dans un tableau à deux colonnes avec le nom de la mutation et le nom du gène ou elle se situe:</p>
<div class="highlight"><pre><span></span><code>SnpSift filter "(exists ANN[0].HGVS_P)" > SRR13182925.ann.vcf
|SnpSift extractFields - "ANN[0].HGVS_P" "ANN[0].GENE"
ANN[0].HGVS_P ANN[0].GENE
p.Phe924Phe ORF1ab
p.Thr1665Thr ORF1ab
p.Pro4715Leu ORF1ab
p.Thr95Asn S
p.Asp614Gly S
p.Ser68Phe E
p.Asp72Asp E
</code></pre></div>
<p>Vous pouvez également ouvrir le fichier <em>SRR13182925.ann.vcf</em> via l'interface graphique de <a href="https://github.com/labsquare/cutevariant">Cutevariant</a>. C'est un logiciel de mon cru en version bêta! Donc, soyez indulgent. </p>
<h3>Création du génome consensus</h3>
<p>Pour reconstruire la séquence du génome de l'échantillon à partir du fichier VCF, nous pouvons utiliser <a href="http://samtools.github.io/bcftools/bcftools.html">bcftools</a> qui nous génère un fichier Fasta: </p>
<div class="highlight"><pre><span></span><code>bcftools consensus SRR13182910.vcf.gz -f genome/whuan.fasta --sample unknown > SRR13182910.fa
</code></pre></div>
<p>Nous pouvons alors utiliser l'outil <a href="https://github.com/cov-lineages/pangolin">pangolin</a> pour asigner le nom de la ligné à ce génome. La nomenclature est défini <a href="https://www.nature.com/articles/s41564-020-0770-5">dans ce papier</a>:</p>
<div class="highlight"><pre><span></span><code>pangolin SRR13182910.fa
</code></pre></div>
<p>Nous obtenons alors l'identifiant <a href="https://cov-lineages.org/lineages/lineage_B.1.1.119.html">B.1.1.119</a> dont vous pouvez trouver la déscription <a href="https://cov-lineages.org/lineages/lineage_B.1.1.119.html">sur cette page</a>. Et comme nous pouvions s'y attendre, elle est trouvé en grande partie chez des nord-américains.</p>
<h2>Analyse des 245 génomes</h2>
<h3>Distribution des variants</h3>
<p>J'ai d'abord téléchargés tous les fichiers Fastq du projet via la commande suivante :</p>
<div class="highlight"><pre><span></span><code>enaGroupGet -f fastq PRJNA673096
</code></pre></div>
<p>Puis j'ai réalisé un pipeline avec <a href="https://snakemake.readthedocs.io/en/stable/">Snakemake</a> <a href="https://gist.github.com/dridk/c2a7c9c8a6232407bf0c45f4442e6fb6">disponible ici</a>. Il reprend les mêmes étapes vues plus haut à la seule différence que l'ensemble des variants détectés est colligé dans un même fichier VCF. <br>
Après quelques heures de calcul, j'ai finalement obtenu ce fichier VCF qui m'a permis d'analyser la fréquence des variants le long du génome que j'ai reporté dans le graphique suivant. <br>
Au total, j'ai trouvé environ 630 variants répartis le long du génome dont 4 mutations particulièrement fréquentes.</p>
<div class="figure"> <img src="../images/covid_ngs/lollipop.png" /> <div class="legend"> Repartition des variants trouvés parmi les 245 génomes avec leurs fréquences </div> </div>
<p>Ces 4 mutations sont probablement la conséquence d'un processus de sélection.<br>
En googlant, je trouve <a href="https://www.biorxiv.org/content/10.1101/2020.05.12.092056v1">ce papier</a> présentant les mutations Thr265Ile and Gln57His comme exclusif à la population Nord-Américaines. Ce qui colle bien avec l'origine de nos données. <br>
Le variant Pro4715Leu est également dominant et affecte <a href="https://fr.wikipedia.org/wiki/ARN_polym%C3%A9rase_ARN-d%C3%A9pendante">la polymérase RNA-dependent (RdRp)</a> catalysant la réplication de l'ARN. Peut-être que cette mutation modifie la fidélité de la réplication impactant ainsi son taux de mutation et donc son <a href="https://fr.wikipedia.org/wiki/%C3%89volvabilit%C3%A9">evolvabilité</a>, c'est-à-dire sa capacité à évoluer. <br>
Plus intéressant, est le variant Asp614Gly situé sur le gène (S) de la <a href="https://fr.wikipedia.org/wiki/Glycoprot%C3%A9ine">protéine Spike</a>, là même ou se situe le variant anglais en permettant au virus de pénétrer plus facilement les cellules humaines. Cette mutation Asp614Gly serait apparue en Europe début 2020 et serait maintenant la forme majoritaire (<a href="https://www.news-medical.net/news/20200925/22705/French.aspx">source</a>). </p>
<h3>Distribution des lignées</h3>
<p>J'ai également reconstruit chaque génome que j'ai assigné à sa ligné avec l'outil <a href="https://github.com/cov-lineages/pangolin">pangolin</a>. J'obtient la distribution suivant: </p>
<div class="figure"> <img src="../images/covid_ngs/lineage.png" /> <div class="legend"> Distribution des lignées de virus </div> </div>
<p>Nous pouvons voir ici la présence de ligné <a href="https://cov-lineages.org/lineages/lineage_B.1.2.html">B.1.2</a> en grand nombre. D'après <a href="https://cov-lineages.org/">le site cov-lineages</a>, elle est exclusivement Nord-américaine est descend de la ligné <a href="https://cov-lineages.org/lineages/lineage_B.1.html">B.1</a> apparu précocement et que l'on trouve partout dans le monde.
Quand à la ligné <a href="https://cov-lineages.org/lineages/lineage_B.1.369.html">B.1.369</a>, elle a d'abord été vu en Océanie puis aux Etats-Unis à partir de Juin 2020. <br>
Bref, tout qui colle avec l'origine nord-américaine de mes données! </p>
<h2>Conclusion</h2>
<p>Un très bon exercice rapide qui en intéressera certainement plus d'un. En tout cas, je me suis bien amusé ce week-end à apprendre un tas de chose interessante sur ce maudit virus. <br>
N'hésitez donc pas à reprendre mon pipeline si vous en avez besoin.
J'aimerai maintenant apprendre à reconstruire un arbre <a href="https://fr.wikipedia.org/wiki/Phylog%C3%A9nie">phylogénétique</a> à la fois dans le temps et dans l'espace. Ce qu'ils ont fait sur le <a href="https://nextstrain.org/ncov/europe?f_region=Europe">site nextrain</a>, est vraiment trop stylé! Cela permet de tracer l'évolution de ce virus qui, on ne le rappellera jamais assez, est expliquée par la <a href="https://fr.wikipedia.org/wiki/Charles_Darwin">théorie de l'évolution de Darwin</a>.</p>Créer votre propre langage avec textX en Python2020-11-08T15:32:40+01:002020-11-08T15:32:40+01:00Sacha Schutztag:dridk.me,2020-11-08:/textx.html<p>Un <a href="https://fr.wikipedia.org/wiki/Langage_d%C3%A9di%C3%A9">DSL</a> ( Domain Specific Language ) est un langage de programmation créé pour une tâche spécifique à l'inverse des langages de programmation usuels comme <a href="https://www.python.org/">Python</a>. On peut s'en servir par exemple pour créer des petits langages maison utilisés au sein d'une application. <br>
Dans ce billet, je vais vous montrer en Python …</p><p>Un <a href="https://fr.wikipedia.org/wiki/Langage_d%C3%A9di%C3%A9">DSL</a> ( Domain Specific Language ) est un langage de programmation créé pour une tâche spécifique à l'inverse des langages de programmation usuels comme <a href="https://www.python.org/">Python</a>. On peut s'en servir par exemple pour créer des petits langages maison utilisés au sein d'une application. <br>
Dans ce billet, je vais vous montrer en Python, comment créer un langage pour contrôler le mouvement d'un robot fictif grâce à la librarie <a href="https://textx.github.io/textX/stable/">textX</a>. </p>
<h2>Définition de notre grammaire</h2>
<p>Notre langage doit pouvoir permettre de contrôler le déplacement d'un robot sur un échiquier dans les 4 directions ( up, down, left, right). <br>
Par exemple : </p>
<div class="highlight"><pre><span></span><code>move up # Bouge d'une case vers le haut
move up 3 # Bouge de 3 case vers le haut
move left 3 # Bouge de 3 cause vers la gauche
</code></pre></div>
<p>L'idée est de parser ces instructions afin de récupérer les variables pour les consommer dans notre application. <br>
Nous pourrions très bien résoudre ce problème en parsant les instructions à coup <a href="expression-reguliere.html">d'expression régulière</a>. Mais dès que le langage deviendra plus complexe, l'utilisation d'un outil comme textX vous facilitera grandement la tâche.</p>
<h2>TextX: Un métalangage pour définir notre langage</h2>
<p>La librairie textX en Python dispose d'un <a href="https://fr.wikipedia.org/wiki/M%C3%A9talangage">métalangage</a> permettant de décrire la grammaire du langage que nous voulons créer (d'ou le prefix méta). Ce métamodèle est alors utilisé par textX pour construire <a href="https://fr.wikipedia.org/wiki/Arbre_syntaxique">l'arbre syntaxique</a> nécessaire pour parser les instructions données à notre robot. Je vous conseille de lire le code et de tester pour comprendre. </p>
<h3>Installation</h3>
<p>J'utilise Python 3.7, et la version 2.3 de textX : </p>
<div class="highlight"><pre><span></span><code>pip install textX
</code></pre></div>
<h3>Le métamodèle décrivant la grammaire</h3>
<p>Commençons par créer un fichier <em>robo.tx</em> afin de décrire notre grammaire en utilisant différents symboles. <br>
- <strong>Direction</strong> est un symbole décrivant les 4 directions possibles. C'est un symbole terminal, car il ne peut pas être décomposé en sous-symbole contrairement à MoveCommand. <br>
- <strong>MoveCommand</strong> est un symbole non terminal décrit à l'aide du symbole <strong>Direction</strong> et du symbole <strong>NUMBER</strong>. Ce dernier est un symbole fourni par défaut par textX pour décrire un nombre. La liste des autres types est <a href="https://textx.github.io/textX/stable/grammar/#textx-base-types">disponible ici.</a>. </p>
<div class="highlight"><pre><span></span><code><span class="o">//</span><span class="w"> </span><span class="nt">robo</span><span class="p">.</span><span class="nc">tx</span><span class="w"></span>
<span class="nt">MoveCommand</span><span class="o">:</span><span class="w"> </span>
<span class="w"> </span><span class="s1">'move'</span><span class="w"> </span><span class="nt">Direction</span><span class="w"> </span><span class="nt">NUMBER</span><span class="w"></span>
<span class="o">;</span><span class="w"></span>
<span class="nt">Direction</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="s1">'up'</span><span class="o">|</span><span class="s1">'down'</span><span class="o">|</span><span class="s1">'left'</span><span class="o">|</span><span class="s1">'right'</span><span class="w"></span>
<span class="o">;</span><span class="w"></span>
</code></pre></div>
<p>Utiliser cette commande pour vérifier que le modèle est valide: </p>
<div class="highlight"><pre><span></span><code>textx check robot.tx
</code></pre></div>
<p>Nous pouvons maintenant affecter les différentes valeurs de l'instruction à des variables qui seront accessibles depuis Python. Par la même occasion, je rends l'option step optionnelle grâce à l'opérateur "?". Pour cela, je modifie le code de la façon suivante: </p>
<div class="highlight"><pre><span></span><code><span class="n">MoveCommand</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="n">action</span><span class="o">=</span><span class="s1">'move'</span><span class="w"> </span><span class="n">direction</span><span class="o">=</span><span class="n">Direction</span><span class="w"> </span><span class="o">(</span><span class="n">step</span><span class="o">=</span><span class="n">NUMBER</span><span class="o">)?</span><span class="w"></span>
<span class="o">;</span><span class="w"></span>
<span class="n">Direction</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="s1">'up'</span><span class="o">|</span><span class="s1">'down'</span><span class="o">|</span><span class="s1">'left'</span><span class="o">|</span><span class="s1">'right'</span><span class="w"> </span>
<span class="o">;</span><span class="w"></span>
</code></pre></div>
<p>Maintenant, pour utiliser cette grammaire en Python, et parser par exemple l'instruction "<em>move up 4</em>", il faut charger le métamodèle et parser l'instruction à l'aide de la méthode <em><a href="https://github.com/textX/textX/blob/master/textx/model.py#L317">model_from_str</a></em>. Nous obtenons alors l'instance d'une classe <strong>MoveCommand</strong> contenant les 3 variables: <strong>action</strong>, <strong>direction</strong> et <strong>step</strong>.</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">textx</span> <span class="kn">import</span> <span class="n">metamodel_from_file</span>
<span class="n">metamodel</span> <span class="o">=</span> <span class="n">metamodel_from_file</span><span class="p">(</span><span class="s2">"robot.tx"</span><span class="p">)</span>
<span class="n">cmd</span> <span class="o">=</span> <span class="n">metamodel</span><span class="o">.</span><span class="n">model_from_str</span><span class="p">(</span><span class="s2">"move up 4"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">cmd</span><span class="p">))</span> <span class="c1"># MoveCommand instance class</span>
<span class="nb">print</span><span class="p">(</span><span class="n">cmd</span><span class="o">.</span><span class="n">action</span><span class="p">)</span> <span class="c1"># "move"</span>
<span class="nb">print</span><span class="p">(</span><span class="n">cmd</span><span class="o">.</span><span class="n">direction</span><span class="p">)</span> <span class="c1"># "up" </span>
<span class="nb">print</span><span class="p">(</span><span class="n">cmd</span><span class="o">.</span><span class="n">step</span><span class="p">)</span> <span class="c1"># 4</span>
</code></pre></div>
<h3>Allez un peu plus loin</h3>
<p>La classe <strong>MoveCommand</strong> peut être personnalisée en amont, pour pouvoir jouer finement sur les variables du modèle. Nous allons modifier la classe afin que le paramètre <strong>step</strong> soit égal à 1 par défaut lorsque celui-ci n'est pas renseigné. </p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">textx</span> <span class="kn">import</span> <span class="n">metamodel_from_file</span>
<span class="k">class</span> <span class="nc">MoveCommand</span><span class="p">:</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">action</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"action"</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">direction</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"direction"</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">step</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"step"</span><span class="p">)</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">step</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">step</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">step</span> <span class="o">=</span> <span class="mf">1.0</span>
<span class="n">metamodel</span> <span class="o">=</span> <span class="n">metamodel_from_file</span><span class="p">(</span><span class="s2">"robot.tx"</span><span class="p">,</span> <span class="n">classes</span><span class="o">=</span><span class="p">[</span><span class="n">MoveCommand</span><span class="p">])</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">metamodel</span><span class="o">.</span><span class="n">model_from_str</span><span class="p">(</span><span class="s2">"move up"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">model</span><span class="o">.</span><span class="n">step</span><span class="p">)</span> <span class="c1"># step = 1 </span>
</code></pre></div>
<p>Nous pouvons ajouter également à notre grammaire la possibilité de donner une suite d'instruction séparée par un point virgule. C'est là toute la magie de textX. Car il suffit d'ajouter le nouveau symbole <strong>Command</strong> que textX interprétera comme une liste de <strong>MoveCommand</strong> séparés par des points-virgules.</p>
<div class="highlight"><pre><span></span><code><span class="n">Command</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="n">commands</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="n">MoveCommand</span><span class="o">[</span><span class="s2">";"</span><span class="o">]</span><span class="w"></span>
<span class="o">;</span><span class="w"></span>
<span class="n">MoveCommand</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="n">action</span><span class="o">=</span><span class="s1">'move'</span><span class="w"> </span><span class="n">direction</span><span class="o">=</span><span class="n">Direction</span><span class="w"> </span><span class="o">(</span><span class="n">step</span><span class="o">=</span><span class="n">NUMBER</span><span class="o">)?</span><span class="w"></span>
<span class="o">;</span><span class="w"></span>
<span class="n">Direction</span><span class="o">:</span><span class="w"></span>
<span class="w"> </span><span class="s1">'up'</span><span class="o">|</span><span class="s1">'down'</span><span class="o">|</span><span class="s1">'left'</span><span class="o">|</span><span class="s1">'right'</span><span class="w"></span>
<span class="o">;</span><span class="w"></span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="n">metamodel</span> <span class="o">=</span> <span class="n">metamodel_from_file</span><span class="p">(</span><span class="s2">"robot.tx"</span><span class="p">,</span> <span class="n">classes</span><span class="o">=</span><span class="p">[</span><span class="n">MoveCommand</span><span class="p">])</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">metamodel</span><span class="o">.</span><span class="n">model_from_str</span><span class="p">(</span><span class="s2">"move up; move left 3; move right"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">cmd</span> <span class="ow">in</span> <span class="n">model</span><span class="o">.</span><span class="n">commands</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">cmd</span><span class="o">.</span><span class="n">step</span><span class="p">)</span>
</code></pre></div>
<h3>Visualiser votre modèle</h3>
<p>Pour finir, vous pouvez visualiser votre modèle à l'aide de la commande suivante et du fichier robot.txt contenant la suite d'instruction à tester : </p>
<div class="highlight"><pre><span></span><code># Fichier robot.txt
move up; move left 3; move right
</code></pre></div>
<div class="highlight"><pre><span></span><code>textx visualize robot.tx robot.txt
dot -Tpng -O robot.txt.dot
display robot.txt.dot.png
</code></pre></div>
<div class="figure"> <img src="../images/textx/robot.txt.dot.png" /> <div class="legend"> Arbre syntaxique des 3 commandes du fichier robot.txt</div> </div>
<h2>Conclusion</h2>
<p>Dans ce billet, j'ai présenté un cas très simple à visée pédagogique. Mais vous pouvez aller plus loin en créant des parseurs aussi complexes que des parseurs SQL ou JSON. Après, attention, n'utilisez pas ce genre d'outil pour réinventer la roue. Il existe déjà des langages (comme Python) qui font très bien les choses. Personnellement, j'ai créée un DSL dans mon logiciel cutevariant pour pouvoir facilement créer des filtres en ligne de commande sans avoir à passer par les contrôleurs d'une interface graphique. Vous pouvez jeter un oeil sur ma grammaire <a href="https://github.com/labsquare/cutevariant/blob/master/cutevariant/core/vql.tx">ici</a>. <br>
Je vous invite à aussi regarder les exemples sur le <a href="https://textx.github.io/textX/stable/">site officiel</a> dont je me suis largement inspiré. </p>
<h2>Référence</h2>
<ul>
<li><a href="https://textx.github.io/textX/stable/">TextX </a> </li>
</ul>
<p>Merci à @Aluriak pour m'avoir présenté cette techno ! </p>Explorer des données cartographiques avec osmium2020-11-01T19:30:31+01:002020-11-01T19:30:31+01:00Sacha schutztag:dridk.me,2020-11-01:/osmium-tools.html<p>Récemment j'ai été amené à devoir extraire toutes les cités en France ( que ce soit des villes, des villages ou des hameaux). j'ai d'abord cherché sur internet un dataset prémâché, mais j'ai vite constaté que ces données étaient souvent incomplètes par rapport aux cartes d'<a href="https://www.openstreetmap.fr/">OpenStreetMap</a>.
J'ai donc voulu directement …</p><p>Récemment j'ai été amené à devoir extraire toutes les cités en France ( que ce soit des villes, des villages ou des hameaux). j'ai d'abord cherché sur internet un dataset prémâché, mais j'ai vite constaté que ces données étaient souvent incomplètes par rapport aux cartes d'<a href="https://www.openstreetmap.fr/">OpenStreetMap</a>.
J'ai donc voulu directement récupérer les données utilisées par ce site et c'est là que je découvert <a href="https://osmcode.org/osmium-tool/">osmium-tools</a>. Un outil en ligne de commande pour manipuler les fichiers <a href="https://wiki.openstreetmap.org/wiki/OSM_file_formats">OSM</a> d'Open Street Map.</p>
<h2>Les fichiers OSM et PBF</h2>
<p>Les fichiers OSM sont des fichiers au format <a href="https://fr.wikipedia.org/wiki/Extensible_Markup_Language">XML</a> contenant la description d'une carte avec <a href="https://wiki.openstreetmap.org/wiki/Elements">3 éléments</a> notables ( <strong>les noeuds</strong>, <strong>les chemins</strong> et <strong>les relations</strong>). <br>
Les noeuds décrivent une position fixe dans l'espace , comme une ville.
Les chemins décrivent un segment ou un polygone, comme le contour d'un pays. Tandis que les relations sont simplement des groupes d'éléments.
Chaque élément est décrit par <a href="https://wiki.openstreetmap.org/wiki/Elements#Common_attributes">différents attributs</a> XML et des <a href="https://wiki.openstreetmap.org/wiki/Tags">tags</a> permettant d'associer des informations à l'élément sous forme de clef-valeur.
L'exemple suivant décrit par exemple la ville de Caen sous forme d'un noeud avec sa latitude et sa longitude comme attributs ainsi qu'une liste de tags.</p>
<div class="highlight"><pre><span></span><code> <span class="nt"><node</span> <span class="na">id=</span><span class="s">"1831881213"</span> <span class="na">version=</span><span class="s">"1"</span> <span class="na">changeset=</span><span class="s">"12370172"</span> <span class="na">lat=</span><span class="s">"49.182863"</span> <span class="na">lon=</span><span class="s">"-0.370679"</span> <span class="na">user=</span><span class="s">"lafkor"</span> <span class="na">uid=</span><span class="s">"75625"</span> <span class="na">visible=</span><span class="s">"true"</span> <span class="na">timestamp=</span><span class="s">"2012-07-20T09:43:19Z"</span><span class="nt">></span>
<span class="nt"><tag</span> <span class="na">k=</span><span class="s">"name"</span> <span class="na">v=</span><span class="s">"Caen"</span><span class="nt">/></span>
<span class="nt"><tag</span> <span class="na">k=</span><span class="s">"place"</span> <span class="na">v=</span><span class="s">"city"</span><span class="nt">/></span>
<span class="nt"><tag</span> <span class="na">k=</span><span class="s">"addr:postcode"</span> <span class="na">v=</span><span class="s">"14000"</span><span class="nt">/></span>
<span class="nt"></node></span>
</code></pre></div>
<p>Le format OSM n'est pas utilisé directement. On lui préfère le format <a href="https://wiki.openstreetmap.org/wiki/PBF_Format">PBF</a>, un format indexé plus léger et plus rapide.
Tous les fichiers d'openstreetmap sont ainsi disponibles au format PBF sur le site <a href="https://www.geofabrik.de/">Geofabrik</a>. Par exemple, la France et ses régions sont disponibles à <a href="https://download.geofabrik.de/europe/france.html">cette adresse</a>. </p>
<h2>Osmium-Tool: la boite à outils des fichiers OSM/PBF</h2>
<p><a href="https://osmcode.org/osmium-tool/">Osmium-tool</a> est un outil en ligne de commande écrit en C++ permettant de manipuler les fichiers OSM/PBF. Vous allez pouvoir extraire des données incluses dans un polygone défini, faire des conversions de format, filtrer les données par tag et bien plus....
Je vous propose dans ce billet de juste extraire l'ensemble des commune d'Alsace. </p>
<h3>Installation</h3>
<p>osmium-tool est disponible dans les dépots d'ubuntu: </p>
<div class="highlight"><pre><span></span><code><span class="n">sudo</span><span class="w"> </span><span class="n">apt</span><span class="o">-</span><span class="n">get</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">osmium</span><span class="o">-</span><span class="n">tools</span><span class="w"></span>
</code></pre></div>
<h3>Télécharger la région Alsace</h3>
<div class="highlight"><pre><span></span><code><span class="n">wget</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">download</span><span class="o">.</span><span class="n">geofabrik</span><span class="o">.</span><span class="n">de</span><span class="o">/</span><span class="n">europe</span><span class="o">/</span><span class="n">france</span><span class="o">/</span><span class="n">alsace</span><span class="o">-</span><span class="n">latest</span><span class="o">.</span><span class="n">osm</span><span class="o">.</span><span class="n">pbf</span><span class="w"></span>
</code></pre></div>
<h3>Résumer un fichier pbf</h3>
<p>La commande <strong>osmium fileinfo</strong> vous donnera des informations générales sur le fichier avec notamment le nombre de noeuds et de chemins:</p>
<div class="highlight"><pre><span></span><code><span class="n">osmium</span><span class="w"> </span><span class="n">fileinfo</span><span class="w"> </span><span class="o">-</span><span class="n">e</span><span class="w"> </span><span class="n">alsace</span><span class="o">-</span><span class="n">latest</span><span class="o">.</span><span class="n">osm</span><span class="o">.</span><span class="n">pbf</span><span class="w"> </span>
<span class="n">File</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">Name</span><span class="p">:</span><span class="w"> </span><span class="n">alsace</span><span class="o">-</span><span class="n">latest</span><span class="o">.</span><span class="n">osm</span><span class="o">.</span><span class="n">pbf</span><span class="w"></span>
<span class="w"> </span><span class="n">Format</span><span class="p">:</span><span class="w"> </span><span class="n">PBF</span><span class="w"></span>
<span class="w"> </span><span class="n">Compression</span><span class="p">:</span><span class="w"> </span><span class="n">none</span><span class="w"></span>
<span class="w"> </span><span class="n">Size</span><span class="p">:</span><span class="w"> </span><span class="mi">106931186</span><span class="w"></span>
<span class="n">Header</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">Bounding</span><span class="w"> </span><span class="n">boxes</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="p">(</span><span class="mf">6.83892</span><span class="p">,</span><span class="mf">47.3845</span><span class="p">,</span><span class="mf">8.24393</span><span class="p">,</span><span class="mf">49.0802</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">With</span><span class="w"> </span><span class="n">history</span><span class="p">:</span><span class="w"> </span><span class="n">no</span><span class="w"></span>
<span class="w"> </span><span class="n">Options</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">generator</span><span class="o">=</span><span class="n">osmium</span><span class="o">/</span><span class="mf">1.8</span><span class="o">.</span><span class="mi">0</span><span class="w"></span>
<span class="w"> </span><span class="n">osmosis_replication_base_url</span><span class="o">=</span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">download</span><span class="o">.</span><span class="n">geofabrik</span><span class="o">.</span><span class="n">de</span><span class="o">/</span><span class="n">europe</span><span class="o">/</span><span class="n">france</span><span class="o">/</span><span class="n">alsace</span><span class="o">-</span><span class="n">updates</span><span class="w"></span>
<span class="w"> </span><span class="n">osmosis_replication_sequence_number</span><span class="o">=</span><span class="mi">2772</span><span class="w"></span>
<span class="w"> </span><span class="n">osmosis_replication_timestamp</span><span class="o">=</span><span class="mi">2020</span><span class="o">-</span><span class="mi">10</span><span class="o">-</span><span class="mi">27</span><span class="n">T21</span><span class="p">:</span><span class="mi">42</span><span class="p">:</span><span class="mi">03</span><span class="n">Z</span><span class="w"></span>
<span class="w"> </span><span class="n">pbf_dense_nodes</span><span class="o">=</span><span class="bp">true</span><span class="w"></span>
<span class="w"> </span><span class="n">timestamp</span><span class="o">=</span><span class="mi">2020</span><span class="o">-</span><span class="mi">10</span><span class="o">-</span><span class="mi">27</span><span class="n">T21</span><span class="p">:</span><span class="mi">42</span><span class="p">:</span><span class="mi">03</span><span class="n">Z</span><span class="w"></span>
<span class="p">[</span><span class="o">======================================================================</span><span class="p">]</span><span class="w"> </span><span class="mi">100</span><span class="o">%</span><span class="w"> </span>
<span class="n">Data</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">Bounding</span><span class="w"> </span><span class="n">box</span><span class="p">:</span><span class="w"> </span><span class="p">(</span><span class="mf">6.11539</span><span class="p">,</span><span class="mf">47.3342</span><span class="p">,</span><span class="mf">9.60379</span><span class="p">,</span><span class="mf">49.7883</span><span class="p">)</span><span class="w"></span>
<span class="w"> </span><span class="n">Timestamps</span><span class="p">:</span><span class="w"></span>
<span class="w"> </span><span class="n">First</span><span class="p">:</span><span class="w"> </span><span class="mi">2006</span><span class="o">-</span><span class="mi">01</span><span class="o">-</span><span class="mi">11</span><span class="n">T15</span><span class="p">:</span><span class="mi">31</span><span class="p">:</span><span class="mi">39</span><span class="n">Z</span><span class="w"></span>
<span class="w"> </span><span class="n">Last</span><span class="p">:</span><span class="w"> </span><span class="mi">2020</span><span class="o">-</span><span class="mi">10</span><span class="o">-</span><span class="mi">27</span><span class="n">T21</span><span class="p">:</span><span class="mi">29</span><span class="p">:</span><span class="mi">47</span><span class="n">Z</span><span class="w"></span>
<span class="w"> </span><span class="n">Objects</span><span class="w"> </span><span class="n">ordered</span><span class="w"> </span><span class="p">(</span><span class="n">by</span><span class="w"> </span><span class="n">type</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">id</span><span class="p">):</span><span class="w"> </span><span class="n">yes</span><span class="w"></span>
<span class="w"> </span><span class="n">Multiple</span><span class="w"> </span><span class="n">versions</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">same</span><span class="w"> </span><span class="n">object</span><span class="p">:</span><span class="w"> </span><span class="n">no</span><span class="w"></span>
<span class="w"> </span><span class="n">CRC32</span><span class="p">:</span><span class="w"> </span><span class="mi">6</span><span class="n">bc2d1a1</span><span class="w"></span>
<span class="w"> </span><span class="n">Number</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">changesets</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
<span class="w"> </span><span class="n">Number</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">nodes</span><span class="p">:</span><span class="w"> </span><span class="mi">10880224</span><span class="w"></span>
<span class="w"> </span><span class="n">Number</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">ways</span><span class="p">:</span><span class="w"> </span><span class="mi">1751889</span><span class="w"></span>
<span class="w"> </span><span class="n">Number</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">relations</span><span class="p">:</span><span class="w"> </span><span class="mi">36547</span><span class="w"></span>
<span class="w"> </span><span class="n">Largest</span><span class="w"> </span><span class="n">changeset</span><span class="w"> </span><span class="n">ID</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="w"></span>
<span class="w"> </span><span class="n">Largest</span><span class="w"> </span><span class="n">node</span><span class="w"> </span><span class="n">ID</span><span class="p">:</span><span class="w"> </span><span class="mi">8053541452</span><span class="w"></span>
<span class="w"> </span><span class="n">Largest</span><span class="w"> </span><span class="n">way</span><span class="w"> </span><span class="n">ID</span><span class="p">:</span><span class="w"> </span><span class="mi">864360376</span><span class="w"></span>
<span class="w"> </span><span class="n">Largest</span><span class="w"> </span><span class="n">relation</span><span class="w"> </span><span class="n">ID</span><span class="p">:</span><span class="w"> </span><span class="mi">11801460</span><span class="w"></span>
</code></pre></div>
<h3>Filtrer par tags</h3>
<p>La <a href="https://wiki.openstreetmap.org/wiki/Key:place">documentation officielle</a> nous indique que les cités sont définies par le tag <strong>place</strong> avec 4 valeurs possibles:</p>
<ul>
<li>place=city</li>
<li>place=town</li>
<li>place=village</li>
<li>place=hamlet</li>
</ul>
<p>Pour garder uniquement ces noeuds taggés dans un nouveau fichier <em>place.pbf</em>, nous pouvons utiliser la commande <strong>osmium tag-filter</strong> en prefixant par "n/":</p>
<div class="highlight"><pre><span></span><code>osmium tags-filter alsace-latest.osm.pbf n/place<span class="o">=</span>city,town,village,hamlet -o place.pbf
</code></pre></div>
<h3>Exporter vers un fichier geojson</h3>
<p>Nous pouvons ensuite convertir le fichier PBF en <a href="https://fr.wikipedia.org/wiki/GeoJSON">GEOJSON</a> (un format <a href="https://fr.wikipedia.org/wiki/JavaScript_Object_Notation">JSON</a> facile à lire) utilisez pour cela <strong>osmium export</strong> :</p>
<div class="highlight"><pre><span></span><code>osmium <span class="nb">export</span> place.pbf -f geojson > place.geojson
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="s2">"FeatureCollection"</span><span class="w"></span>
<span class="p">[</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Feature"</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">"geometry"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Point"</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">"coordinates"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"></span>
<span class="w"> </span><span class="mf">8.0056049</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="mf">48.7521656</span><span class="w"></span>
<span class="w"> </span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="nt">"properties"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Greffern"</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">"place"</span><span class="p">:</span><span class="w"> </span><span class="s2">"village"</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">"population"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1943"</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Feature"</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">"geometry"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Point"</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">"coordinates"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"></span>
<span class="w"> </span><span class="mf">7.9445109</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="mf">49.0365935</span><span class="w"></span>
<span class="w"> </span><span class="p">]</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="nt">"properties"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Wissembourg"</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">"place"</span><span class="p">:</span><span class="w"> </span><span class="s2">"town"</span><span class="p">,</span><span class="w"></span>
<span class="err">...</span><span class="w"></span>
</code></pre></div>
<p>Personnellement, j'utilise le formidable outil <a href="https://stedolan.github.io/jq/">jq</a> pour pouvoir parser du json en ligne de commande. En plus, nous pouvons directement convertir du JSON en <a href="https://fr.wikipedia.org/wiki/Comma-separated_values">CSV</a> pour avoir une liste propre que l'on pourra consommer avec des outils comme <a href="https://fr.wikipedia.org/wiki/Stream_Editor">sed</a> ou <a href="https://fr.wikipedia.org/wiki/Awk">awk</a>. </p>
<div class="highlight"><pre><span></span><code>cat place.geojson <span class="p">|</span>jq -r <span class="s1">'.features[]| [.properties.name, .properties.place,.geometry.coordinates[0],.geometry.coordinates[1]]|@csv'</span>
<span class="c1"># "Greffern","village",8.0056049,48.7521656</span>
<span class="c1"># "Wissembourg","town",7.9445109,49.0365935</span>
<span class="c1"># "Strasbourg","city",7.7507127,48.584614</span>
<span class="c1"># "Mulhouse","city",7.3389275,47.7467</span>
<span class="c1"># "Saverne","town",7.3625953,48.7419909</span>
<span class="c1"># "Wittelsheim","town",7.2402432,47.8091086</span>
<span class="c1"># "Kingersheim","town",7.3386856,47.7923002</span>
<span class="c1"># "Ostwald","town",7.7102193,48.5425109</span>
<span class="c1"># "Cernay","town",7.1787669,47.8086824</span>
<span class="c1"># "Wittenheim","town",7.3373681,47.8080799</span>
</code></pre></div>
<h2>Conclusion</h2>
<p>Je n'ai pas l'habitude de manipuler ce genre de données et je pense que l'on peut faire bien plus avec. J'ai vu aussi qu'il y a d'autre outil comme <a href="https://wiki.openstreetmap.org/wiki/Osmosis">Osmosis</a> en java.
Si cela vous intéresse, j'ai mis <a href="https://github.com/dridk/france_place_gps">ici</a> un fichier contenant l'ensemble des cités par départements français ainsi que la procédure pour le fabriquer.</p>L'analyse en composante principale2020-09-20T18:34:56+02:002020-09-20T18:34:56+02:00Sacha SCHUTZtag:dridk.me,2020-09-20:/analyse-en-composante-principale.html<p><a href="https://fr.wikipedia.org/wiki/Analyse_en_composantes_principales">L'analyse en composante principale</a> ou PCA (Principal component analysis) est une méthode de <a href="https://fr.wikipedia.org/wiki/R%C3%A9duction_dimensionnelle">réduction de dimension,</a> largement utilisée en <a href="https://fr.wikipedia.org/wiki/Statistique_descriptive">statistique descriptive</a>, pour visualiser sur un graphique à 2 ou 3 dimensions des données décrites sur plus de dimensions.
Dans ce billet, nous chercherons d'abord à comprendre le principe général avec …</p><p><a href="https://fr.wikipedia.org/wiki/Analyse_en_composantes_principales">L'analyse en composante principale</a> ou PCA (Principal component analysis) est une méthode de <a href="https://fr.wikipedia.org/wiki/R%C3%A9duction_dimensionnelle">réduction de dimension,</a> largement utilisée en <a href="https://fr.wikipedia.org/wiki/Statistique_descriptive">statistique descriptive</a>, pour visualiser sur un graphique à 2 ou 3 dimensions des données décrites sur plus de dimensions.
Dans ce billet, nous chercherons d'abord à comprendre le principe général avec l'exemple simple d'un passage de 2 dimensions à 1 dimension. Puis nous détaillerons les bases mathématiques sous-jacentes et comment réaliser cette transformation en Python.</p>
<h2>Tout commence avec un tableau</h2>
<p>Chaque fois que je suis amené à analyser des données, mon premier réflexe et d'identifier un tableau ou chaque ligne représente une observation et chaque colonne une variable décrivant l'observation.
Par exemple le tableau suivant, représente la taille et le poids chez 6 individus:</p>
<div class="figure"><img src="../images/pca/table.png" /><div class="legend">
Tableau de données avec 6 observations et deux variables.
</div>
</div>
<p>D'un point de vue géométrique, nous pouvons représenter chacune de ces 6 observations par un point (ou vecteur) dans un <a href="https://fr.wikipedia.org/wiki/Dimension_d%27un_espace_vectoriel">espace</a> à 2 dimensions correspondant aux deux variables. Ce graphique nous montre alors la proximité entre les observations. Par exemple sur le graphique ci-dessous, les individus 1,2,3 et les individus 4,5,6 forment respectivement deux groupes.</p>
<div class="figure"><img src="../images/pca/2dplot.png" /><div class="legend">
Représentation dans un espace à deux dimensions du tableau de données. Chaque observation est représentée par un point ou vecteur.
De façon générale, les M observations d'un tableau de données peuvent être vu comme les M vecteurs dans un espace à N dimensions. L'ensemble formant une matrice de dimension NxM.
</div>
</div>
<p>En ajoutant une nouvelle variable dans ce tableau, par exemple l'âge d'un individu, nous pouvons représenter les observations par un graphique à 3 dimensions. Mais avec plus de variables, et donc plus de dimensions cela devient problématique. <br>
La solution à ce problème est la réduction de dimension en transformant par exemple un tableau à 10 variables vers un tableau à 2 variables facilement représentable sur un graphique. <br>
Pour comprendre comment cette transformation fonctionne, partons d'un cas simple: La réduction d'un tableau à 2 dimensions vers un tableau à 1 dimension. Il suffira ensuite de généraliser cette méthode à N dimensions.</p>
<h2>Passage de 2 dimensions à 1 dimension</h2>
<p>Pour faire cette transformation, il faut s'imaginer un axe passant au mieux par tous les points. Puis faire la projection de chaque point sur cet axe.
Cet axe ou composante principale est une nouvelle dimension fictive qui nous permet de représenter les observations sur 1 dimension. Et comme vous pouvez le constater sur le graphique ci-dessous, les deux groupes identifiables dans l'espace bidimensionnel l'est toujours dans ce nouvelle espace unidimensionnel.</p>
<div class="figure"><img src="../images/pca/pca2D.png" /><div class="legend">
Réduction de dimensions d'un espace à 2 dimensions vers in espace à 1 dimension. Les deux groupes d'individus sont toujours identifiables.
</div>
</div>
<p>Il faut cependant garder en tête qu'il y a une perte d'information lorsque l'on réalise cette transformation. Des données différentes avant transformation peuvent aboutir aux mêmes résultats. Plus les points sont corrélés entre eux, et plus l'information récupérée après la réduction de dimension sera grande. Une réduction de dimension par PCA doit donc <strong>TOUJOURS</strong> s'accompagner de la quantité d'information récupérée pour être interprétable.</p>
<div class="figure"><img src="../images/pca/pca_information.png" /><div class="legend">
Réduction de dimensions d'un espace à 2 dimensions vers un espace à 1 dimensions.
Dans les 3 exemples, la réduction de dimensions amène aux mêmes résultats. La différence est liée à la quantité d'information récupérée par la composante principale. Le premier graphique récupère que 40% de l'information tandisque la dernière récupère 90% de l'information.
</div>
</div>
<h2>Comprendre le calcul</h2>
<p>Nous allons maintenant voir comment trouver ces axes par le calcul, pour ensuite généraliser la méthode à N dimensions. Pour cela, quelque prérequis d'<a href="https://fr.wikipedia.org/wiki/Alg%C3%A8bre_lin%C3%A9aire">algèbre linéaire</a> sont nécessaires. </p>
<h3>Transformation linéaire</h3>
<p>En multipliant un <a href="https://fr.wikipedia.org/wiki/Vecteur">vecteur</a> $\vec{v}$ (un point) par une <a href="https://fr.wikipedia.org/wiki/Matrice">matrice</a> $M$ on obtient un nouveau vecteur $\vec{v_t}$. Autrement dit, on déplace le point vers un autre endroit grâce à une <a href="https://en.wikipedia.org/wiki/Transformation_matrix">matrice de transformation</a>.</p>
<p>$$
\vec{v_t} = M \vec{v}
$$</p>
<p>Par exemple, en infographie, on utilise ces matrices pour réaliser différente transformation d'objet comme des rotations, des déformations, des agrandissements etc ...<br>
Dans l'exemple ci-dessous, les 3 vecteurs (bleu, vert, rouge) définissent un carré. En faisant le produit de chaque vecteur par une matrice de transformation, on obtient 3 nouveaux vecteurs représentant le carré transformé. Essayer <a href="https://web.ma.utexas.edu/users/ysulyma/matrix/">ce site </a>pour tester.</p>
<div class="figure"><img src="../images/pca/matrix_transformation.png" /><div class="legend"> Différente matrice de transformation sur un un objet à 3 vecteurs<a href="https://en.wikipedia.org/wiki/Transformation_matrix"> Source </a></div> </div>
<h3>Vecteur propre et valeur propre</h3>
<p>Les <a href="https://fr.wikipedia.org/wiki/Valeur_propre,_vecteur_propre_et_espace_propre">vecteurs propres </a>(eigen vector) d'une matrice de transformation sont les vecteurs qui ne changent pas de direction après transformation. Chacun de ces vecteurs est associé à une <a href="https://fr.wikipedia.org/wiki/Valeur_propre,_vecteur_propre_et_espace_propre">valeur propre</a> $\lambda$ (eigen value) indiquant le degré d'élongation. </p>
<div class="figure"><img src="../images/pca/eigen_transformation.png" /><div class="legend">
Transformation d'un vecteur propre v par une matrice de transformation. Le vecteur transformé vt conserve sa direction. La valeur propre est de 2.
</div>
</div>
<h3>Calcul du vecteur et de la valeur propre</h3>
<p>Pour trouver les vecteurs et valeurs propres d'une matrice A: </p>
<p>$$ A = \begin{bmatrix}
a & b \
c & d
\end{bmatrix}
$$</p>
<p><center>Il faut donc résoudre l'équation suivante.</center></p>
<p>$$A\vec{v} = \lambda \vec{v}$$</p>
<p><center>Ce qui revient à résoudre : </center></p>
<p>$$(A-\lambda I) \vec{v} = \vec{0}$$</p>
<p><center>Cette équation admet des solution(s) $\lambda$ si :</center> </p>
<p>$$det(A-\lambda I) = 0 $$</p>
<p><center>C'est à dire : </center>
$$ det (\begin{bmatrix}
a - \lambda & b \
c & d - \lambda
\end{bmatrix}) = 0
$$</p>
<p><center>Pour trouver $\lambda$ il suffit donc de résoudre : </center></p>
<p>$$
(a - \lambda)(c - \lambda) - bc = 0
$$</p>
<p>En remplaçant lambda dans l'équation d'origine, nous trouvons alors les vecteurs propres associés. <br>
Avant de comprendre en quoi les vecteurs propres sont utiles pour notre réduction de dimension, il nous faut encore définir une chose: <em>la matrice de covariance</em>.</p>
<h3>Matrice de covariance</h3>
<p><strong>La variance</strong> d'une variable x, informe de la dispersion des données autour de la moyenne. C'est la moyenne de tous les écarts à la moyenne au carré.
Elle s'écrit : </p>
<p>$$var(x) = \frac{1}{N} \sum_{i=0}^{n} (x-\bar{x})^{2}$$</p>
<p>Dans notre tableau, la variance de la taille et du poids sont respectivement de 328.5 et 238.</p>
<p><strong>La covariance</strong> entre deux variables indique la variance d'une variable x par rapport à une variable y. Elle indique le degré de corrélation entre deux variables. Elle s'écrit :</p>
<p>$$cov(x,y) = \frac{1}{N} \sum_{i=0}^{n} (x_i - \bar{x})(y_i - \bar{y})$$</p>
<p>Plus les variables x et y sont corrélé, plus la valeur absolue de la covariance est grande : </p>
<div class="figure"><img src="../images/pca/cov.png" /><div class="legend">
</div> </div>
<p><strong>La matrice de covariance</strong> est une matrice carrée contenant l'ensemble des covariances entre variables prises 2 à 2. </p>
<p>$$M = \begin{bmatrix}
cov(x,x) & cov(x,y) \
cov(y,x) & cov(y,y)
\end{bmatrix}$$</p>
<h3>Trouver les axes principaux</h3>
<p>Vous avez maintenant tous les ingrédients pour comprendre comment trouver les axes passant aux mieux par vos données. Car voilà... Les axes d'une analyse en composante principale correspondent aux <strong>vecteurs propres</strong> de la matrice de covariance de vos données. Et la quantité d'information récupérée par chaque axe correspond aux <strong>valeurs propres</strong> de leurs vecteurs associés. </p>
<div class="figure"><img src="../images/pca/eigen_2d.png" /><div class="legend">
Les vecteurs propres de la matrice de covariance correspondent aux deux axes passant aux mieux par les données. Ici l'axe 1 récupère davantage d'information que l'axe 2.
Les vecteurs propres sont toujours orthogonaux entre eux.
</div>
</div>
<p>En généralisant, pour réduire un espace à N dimensions vers un espace à K dimensions, il suffit de faire la projection des points de l'espace de départ sur les K premiers vecteurs propres qui récupère le maximum d'information. C'est à dire ceux qui ont les valeurs propres les plus grande.
Passons à la pratique pour voir, en réalisant toutes ces opérations en Python.</p>
<h2>Analyse en composante principale en Python</h2>
<p>Nous allons utiliser le <a href="https://fr.wikipedia.org/wiki/Iris_de_Fisher">jeux de données iris</a> contenant 50 observations de fleurs et 4 variables (ou 4 dimensions) et les réduire sur une espace à deux dimensions. </p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
<span class="kn">import</span> <span class="nn">altair</span> <span class="k">as</span> <span class="nn">alt</span>
<span class="kn">from</span> <span class="nn">numpy</span> <span class="kn">import</span> <span class="n">linalg</span> <span class="k">as</span> <span class="n">LA</span>
<span class="kn">from</span> <span class="nn">sklearn</span> <span class="kn">import</span> <span class="n">datasets</span>
<span class="kn">from</span> <span class="nn">sklearn.decomposition</span> <span class="kn">import</span> <span class="n">PCA</span>
<span class="c1"># Téléchargement du jeux de données iris </span>
<span class="n">data</span><span class="p">,</span> <span class="n">species</span> <span class="o">=</span> <span class="n">datasets</span><span class="o">.</span><span class="n">load_iris</span><span class="p">(</span><span class="n">return_X_y</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">species</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">species</span><span class="p">)</span>
<span class="c1"># Calcul de la matrice de covariance </span>
<span class="n">cov_matrix</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">cov</span><span class="p">()</span>
<span class="c1"># Calcul des vecteurs et valeurs propres de la matrice de covariance </span>
<span class="n">eigen_values</span><span class="p">,</span> <span class="n">eigen_vectors</span> <span class="o">=</span> <span class="n">LA</span><span class="o">.</span><span class="n">eig</span><span class="p">(</span><span class="n">cov_matrix</span><span class="p">)</span>
<span class="c1"># Calcul de l'information récupéré en pourcentage sur les 2 premiers axes</span>
<span class="n">info</span> <span class="o">=</span> <span class="p">(</span><span class="n">eigen_values</span> <span class="o">/</span> <span class="nb">sum</span><span class="p">(</span><span class="n">eigen_values</span><span class="p">)</span> <span class="o">*</span> <span class="mi">100</span><span class="p">)</span><span class="o">.</span><span class="n">round</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">axe1_info</span> <span class="o">=</span> <span class="n">info</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">axe2_info</span> <span class="o">=</span> <span class="n">info</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="c1"># Projection des points sur les deux premiers vecteurs </span>
<span class="n">projection_matrix</span> <span class="o">=</span> <span class="n">eigen_vectors</span><span class="o">.</span><span class="n">T</span><span class="p">[:][:</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">T</span>
<span class="n">data_t</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">dot</span><span class="p">(</span><span class="n">projection_matrix</span><span class="p">)</span>
<span class="c1"># Affichage des nouvelles données à 2 dimensions</span>
<span class="n">data_t</span><span class="o">.</span><span class="n">columns</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"axe1"</span><span class="p">,</span> <span class="s2">"axe2"</span><span class="p">]</span>
<span class="n">data_t</span><span class="p">[</span><span class="s2">"species"</span><span class="p">]</span> <span class="o">=</span> <span class="n">species</span>
<span class="n">alt</span><span class="o">.</span><span class="n">Chart</span><span class="p">(</span><span class="n">data_t</span><span class="p">)</span><span class="o">.</span><span class="n">mark_point</span><span class="p">()</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span>
<span class="n">x</span><span class="o">=</span><span class="n">alt</span><span class="o">.</span><span class="n">X</span><span class="p">(</span><span class="s2">"axe1"</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="sa">f</span><span class="s2">"axe 1 </span><span class="si">{</span><span class="n">axe1_info</span><span class="si">}</span><span class="s2">%"</span><span class="p">),</span>
<span class="n">y</span><span class="o">=</span><span class="n">alt</span><span class="o">.</span><span class="n">Y</span><span class="p">(</span><span class="s2">"axe2"</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="sa">f</span><span class="s2">"axe 2 </span><span class="si">{</span><span class="n">axe2_info</span><span class="si">}</span><span class="s2">%"</span><span class="p">),</span>
<span class="n">color</span><span class="o">=</span><span class="s2">"species:N"</span><span class="p">)</span>
</code></pre></div>
<div class="figure"><img src="../images/pca/iris.png" /><div class="legend">
Réduction d'un espace à 4 dimensions vers un espace à 2 dimensions.
</div> </div>
<p>Ce graphique représente donc la projection d'observation d'un espace à 4 dimensions vers un espace à deux dimensions. Ces 2 axes sont accompagnés du pourcentage d'information récupéré grâce aux valeurs propres. Le premier axe récupère 92,46% de l'information puis le second récupère 5.31%. Au total, les 2 premiers axes ont récupéré plus de 97% de l'information. Et comme les couleurs nous le montre, nous constatons que les fleurs de la même espèce sont à proximité dans cette espace bidimensionnel. </p>
<h2>Conclusion</h2>
<p>Nous avons vu dans ce billet, comment réaliser une analyse en composante principale pas à pas. Bien entendu, il existe des librairies permettant de réaliser cette transformation en une ligne, comme <a href="https://scikit-learn.org/stable/auto_examples/decomposition/plot_pca_iris.html">ici avec sklearn</a>. Mais, c'est toujours bien de comprendre comment ça marche !
Par ailleurs, l'analyse en composante principale est une méthode parmi d'autres, de réduction de dimension. Il en existe d'autres avec chacune leurs avantages. Notamment des méthodes non linéaires comme <a href="https://fr.wikipedia.org/wiki/Algorithme_t-SNE">t-SNE</a> ou <a href="https://en.wikipedia.org/wiki/Nonlinear_dimensionality_reduction">UMAP</a>.
Sachez aussi que la PCA a d'autres applications en informatique, notamment dans le traitement d'image, la compression et la réduction du bruit. En effet si vous faites une PCA sur une image, vous récupérer le maximum d'information utile sans le bruit. En faisant l'inverse d'une PCA, vous reconstituerez alors une image débruitée. </p>
<h2>Réferences</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=HMOI_lkzW08">Statquest (youtube) ACP en 5 minutes</a></li>
<li><a href="https://towardsdatascience.com/the-jewel-of-the-matrix-a-deep-dive-into-eigenvalues-eigenvectors-22f1c8da11fd">The Jewel of the Matrix: A Deep Dive Into Eigenvalues & Eigenvectors</a></li>
<li><a href="https://www.visiondummy.com/2014/04/geometric-interpretation-covariance-matrix/">A geometric interpretation of the covariance matrix</a></li>
<li><a href="https://medium.com/@kyasar.mail/pca-principal-component-analysis-729068e28ec8">PCA: Principal Component Analysis</a></li>
</ul>Programmation par contrainte2020-05-23T15:16:33+02:002020-05-23T15:17:34+02:00Sacha Schutztag:dridk.me,2020-05-23:/programmation-par-contrainte.html<p>On dit souvent qu'être fainéant est gage de qualité chez un programmeur. Dans le sens où il cherchera à résoudre un problème en tapant un minimum de ligne de code et en déléguant au maximum à sa machine. C'est encore plus vrai avec la <a href="https://fr.wikipedia.org/wiki/Programmation_par_contraintes">programmation par contrainte</a>. Contrairement à la …</p><p>On dit souvent qu'être fainéant est gage de qualité chez un programmeur. Dans le sens où il cherchera à résoudre un problème en tapant un minimum de ligne de code et en déléguant au maximum à sa machine. C'est encore plus vrai avec la <a href="https://fr.wikipedia.org/wiki/Programmation_par_contraintes">programmation par contrainte</a>. Contrairement à la programmation classique dite <a href="https://fr.wikipedia.org/wiki/Programmation_imp%C3%A9rative">impérative</a>, où vous devez décrire comment résoudre un problème, la programmation par contrainte est un autre <a href="https://fr.wikipedia.org/wiki/Paradigme_(programmation)">paradigme</a> qui vous demande de décrire le problème de façon formelle et c'est un solveur qui se débrouillera de le résoudre pour vous.
Dans ce billet nous allons aborder la programmation par contrainte en solvant un problème combinatoire en génétique: <a href="https://csiflabs.cs.ucdavis.edu/~gusfield/gusfieldorzack.pdf">l'inférence haplotyique</a>.
Pour cela, nous utiliserons la libraire <a href="https://developers.google.com/optimization">OR-tools</a> fournie par Google, simple d'utilisation et disposant d'une API en python. </p>
<blockquote>
<p><em>Constraint programming represents one of the closest approaches computer science has yet made to the Holy Grail of programming: theuser states the problem, the computer solves it.</em> <strong>Eugene C. Freude</strong></p>
</blockquote>
<h2>Un simple problème pour comprendre</h2>
<p>Les problèmes de satisfaction de contraintes ou <a href="https://fr.wikipedia.org/wiki/Probl%C3%A8me_SAT">problème SAT</a> sont des problèmes qui cherchent à trouver toutes les solutions satisfaisant un liste de contraintes booléennes. <br>
Prenons par exemple <strong>2 dés</strong> et lançons-les. Quelles sont les valeurs possibles des 2 dés tels que la somme soit égale à 7 ? <br>
De façon générale, pour modéliser ce problème, Il faut d'abord définir les variables et leurs domaines, c'est-à-dire les valeurs qu'elles sont autorisées à prendre. Dans notre cas, nous avons 2 dés dont les valeurs vont de 1 à 6. Ensuite, il faut définir leurs contraintes par des <a href="https://fr.wikipedia.org/wiki/Expression_bool%C3%A9enne_(programmation_informatique)">expressions booléennes</a>. Ici, la somme des 2 dés est égale à 7.
Et c'est tout.... Le solveur se chargera du reste. <br>
la librarie <a href="https://developers.google.com/optimization">OR-tools</a> va nous permettre de modéliser ce problème et le résoudre via son solveur SAT. <br>
Regardons le code: </p>
<p>Après avoir installer OR-tools:</p>
<div class="highlight"><pre><span></span><code><span class="n">python</span><span class="w"> </span><span class="o">-</span><span class="n">m</span><span class="w"> </span><span class="n">pip</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="o">--</span><span class="n">upgrade</span><span class="w"> </span><span class="o">--</span><span class="n">user</span><span class="w"> </span><span class="n">ortools</span><span class="w"></span>
</code></pre></div>
<p>Exécuter le code suivant: </p>
<div class="highlight"><pre><span></span><code><span class="c1"># Import de la libraire </span>
<span class="c1"># Ortools tools dispose de différents solveurs, notamment un solveur SAT. </span>
<span class="kn">from</span> <span class="nn">ortools.sat.python</span> <span class="kn">import</span> <span class="n">cp_model</span>
<span class="c1"># Création du modèle = Notre problème</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">cp_model</span><span class="o">.</span><span class="n">CpModel</span><span class="p">()</span>
<span class="c1"># Création de deux variables : Le dé x et le dé y avec un domaine de valeur entre 1 et 6 </span>
<span class="n">x</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">NewIntVar</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="s2">"Premier dé "</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">NewIntVar</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="s2">"Deuxième dé"</span><span class="p">)</span>
<span class="c1"># Création d'une contrainte </span>
<span class="n">model</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="n">x</span><span class="o">+</span><span class="n">y</span> <span class="o">==</span> <span class="mi">7</span><span class="p">)</span>
<span class="c1"># Création du solveur pour résoudre le problème</span>
<span class="n">solver</span> <span class="o">=</span> <span class="n">cp_model</span><span class="o">.</span><span class="n">CpSolver</span><span class="p">()</span>
<span class="n">status</span> <span class="o">=</span> <span class="n">solver</span><span class="o">.</span><span class="n">Solve</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
<span class="c1"># Le solveur peut nous dire si le modèle admet des solutions ou non </span>
<span class="k">if</span> <span class="n">status</span> <span class="o">==</span> <span class="n">cp_model</span><span class="o">.</span><span class="n">FEASIBLE</span><span class="p">:</span>
<span class="c1"># Afficher toutes les solutions </span>
<span class="n">solver</span><span class="o">.</span><span class="n">SearchForAllSolutions</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">cp_model</span><span class="o">.</span><span class="n">VarArraySolutionPrinter</span><span class="p">([</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">]))</span>
</code></pre></div>
<p>Vous devriez alors obtenir toutes les solutions possibles comme montré ci-dessous. </p>
<div class="highlight"><pre><span></span><code>Solution 0, time = 0.00 s
Premier dé = 1 Deuxième dé = 6
Solution 1, time = 0.00 s
Premier dé = 2 Deuxième dé = 5
Solution 2, time = 0.00 s
Premier dé = 3 Deuxième dé = 4
Solution 3, time = 0.00 s
Premier dé = 4 Deuxième dé = 3
Solution 4, time = 0.00 s
Premier dé = 5 Deuxième dé = 2
Solution 5, time = 0.00 s
Premier dé = 6 Deuxième dé = 1
</code></pre></div>
<p>Essayez de votre coté de retirer les contraintes. Vous devriez alors obtenir toutes les combinaisons de dé possible.
Et si vous voulez éviter d'avoir une symétrie des résultats, vous pouvez rajouter la contrainte suivante : <em>model.Add(x > y)</em> pour obtenir une liste réduite.</p>
<div class="highlight"><pre><span></span><code> Premier dé = 4 Deuxième dé = 3
Solution 1, time = 0.00 s
Premier dé = 6 Deuxième dé = 1
Solution 2, time = 0.00 s
Premier dé = 5 Deuxième dé = 2
</code></pre></div>
<p>C'était facile non ? Et vous pouvez résoudre ce problème avec autant de dé que vous voulez aussi facilement. En réalité ce problème est tellement simple qu'il peut se résoudre plus efficace en programmation impérative. <a href="https://twitter.com/Natir_chan">@Natir</a> m'a gentillement proposé le <em>one-liner</em> suivant : </p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">itertools</span>
<span class="p">[</span><span class="n">d</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">itertools</span><span class="o">.</span><span class="n">combinations_with_replacement</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">7</span><span class="p">)),</span> <span class="mi">2</span><span class="p">)</span> <span class="k">if</span> <span class="nb">sum</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="o">==</span> <span class="mi">7</span><span class="p">]</span>
</code></pre></div>
<p>Mais pour d'autres problèmes combinatoires plus complexes, cela sera beaucoup plus facile en le modélisant comme un problème de satisfaction de contrainte comme celui que nous allons voir. </p>
<h2>Inférence haplotypique</h2>
<h3>Qu'est-ce qu'un haplotype ?</h3>
<p>Nous sommes des organismes <a href="https://fr.wikipedia.org/wiki/Diplo%C3%AFde">diploïdes</a>. C'est-à-dire que nos chromosomes vont par paire. Nous avons par exemple deux chromosomes 3 <a href="https://fr.wikipedia.org/wiki/Chromosome_homologue">homologues</a>, l'un provenant du père et l'autre de la mère.
Si vous héritez d'une <a href="https://fr.wikipedia.org/wiki/Mutation_(g%C3%A9n%C3%A9tique)">mutation génétique</a> présente sur le chromosome 3 de votre père, alors vous héritez aussi des autres mutations sur ce même chromosome. On dit alors que ces mutations sont en <a href="https://fr.wikipedia.org/wiki/D%C3%A9s%C3%A9quilibre_de_liaison">déséquilibre de liaison</a> et forme un <a href="https://fr.wikipedia.org/wiki/Haplotype">haplotype</a>. En réalité, il y a des recombinaisons plus ou moins grandes au sein des chromosomes qui brisent cette liaison. Je préfère alors définir un haplotype comme un ensemble de variation génétique qui voyage ensemble à travers les générations.</p>
<h3>Qu'est-ce qu'un génotype ?</h3>
<p>Lorsque l'on séquence l'ADN d'un individu, nous lisons les mutations génétiques sans savoir si elles sont portées sur le chromosome paternel ou maternel. Pour une mutation donnée, nous pouvons juste dire si le patient est <a href="https://fr.wikipedia.org/wiki/Homozygote">homozygote</a> (même mutation sur les deux chromosomes homologues ) ou <a href="https://fr.wikipedia.org/wiki/H%C3%A9t%C3%A9rozygote">hétérozygote</a> (mutation différente). <br>
Tout le problème est de pouvoir inférer les haplotypes à partir du génotype. </p>
<div class="figure"><img src="../images/programmation_contrainte/inference_haplotypique.png" /><div class="legend"> A gauche: Génotype obtenu à partir des deux haplotypes parentaux.
A droite: Illustration d'un problème d'inférence haplotypique. </div>
</div>
<h3>Modélisation du problème</h3>
<p>Supposons que nous connaissons l'existence de <strong>m</strong> haplotypes pour <strong>n</strong> variations .
Posons <strong>H</strong>, une matrice binaire <strong>m</strong> x <strong>n</strong> définissant la présence ou non de chaque variation sur chaque haplotype.
Posons <strong>G</strong>, un vecteur de taille <strong>n</strong> définit sur {0,1,2} pour representer le génotype d'un individu avec 0 pour homozygote non muté, 1 pour hétérozygote et 2 pour homozygote muté . </p>
<div class="figure">
<img src="../images/programmation_contrainte/probleme_sat.png" />
<div class="legend">Modélisation du problème d'inférence haplotypique. A partir d'un Matrix de 4 haplotypes connus sur 3 variations. L'objectif est de trouver les deux haplotypes pouvant expliquer le génotype.</div></div>
<p>Le problème revient à trouver deux haplotypes (2 numéros de lignes de H) dont la somme de chaque colonne est égale à la valeur du génotype correspondant.
Pour ce faire nous définissons dans notre modèle chaque élément de H comme une constante. Puis deux variables correspondant aux numéros de ligne de H dont le domaine varie entre 0 et m-1. Enfin, nous posons nos contraintes pour que la somme des haplotypes choisis corresponde au génotype.</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">ortools.sat.python</span> <span class="kn">import</span> <span class="n">cp_model</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="c1"># Creation d'une modèle</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">cp_model</span><span class="o">.</span><span class="n">CpModel</span><span class="p">()</span>
<span class="c1"># Matrice H </span>
<span class="n">haplotype_input</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span>
<span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">],</span> <span class="c1"># haplotype 0</span>
<span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span> <span class="c1"># haplotype 1</span>
<span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span> <span class="c1"># haplotype 2</span>
<span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">],</span> <span class="c1"># haplotype 3</span>
<span class="p">])</span>
<span class="c1">#Vecteur G </span>
<span class="n">genotype_input</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span> <span class="c1"># genotype input to test </span>
<span class="c1"># Dimensions de la matrice H</span>
<span class="n">len_haplotype</span><span class="p">,</span> <span class="n">len_snp</span> <span class="o">=</span> <span class="n">haplotype_input</span><span class="o">.</span><span class="n">shape</span>
<span class="c1"># Création de d'une constante dans notre modèle pour chaque élement de H</span>
<span class="n">haplotypes</span> <span class="o">=</span> <span class="p">[[</span><span class="n">model</span><span class="o">.</span><span class="n">NewConstant</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">v</span><span class="p">))</span> <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">line</span><span class="p">]</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">haplotype_input</span><span class="p">]</span>
<span class="c1"># Création de deux variables correspondant au lignes des haplotypes choisis</span>
<span class="n">index_a</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">NewIntVar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">len_haplotype</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="s2">"haplotype index"</span><span class="p">)</span>
<span class="n">index_b</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">NewIntVar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">len_haplotype</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="s2">"haplotype index"</span><span class="p">)</span>
<span class="c1"># Valeurs de l'halpotype A choisi </span>
<span class="n">a_values</span> <span class="o">=</span> <span class="p">[</span><span class="n">model</span><span class="o">.</span><span class="n">NewIntVar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="sa">f</span><span class="s2">"value_a_</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">len_snp</span><span class="p">)]</span>
<span class="c1"># Valeurs de l'halpotype B choisi </span>
<span class="n">b_values</span> <span class="o">=</span> <span class="p">[</span><span class="n">model</span><span class="o">.</span><span class="n">NewIntVar</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="sa">f</span><span class="s2">"value_b_</span><span class="si">{</span><span class="n">i</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">len_snp</span><span class="p">)]</span>
<span class="c1"># On transpose la matrix pour utiliser la contrainte AddElement</span>
<span class="n">haplotype_transpose</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="nb">list</span><span class="p">,</span> <span class="nb">zip</span><span class="p">(</span><span class="o">*</span><span class="n">haplotypes</span><span class="p">)))</span>
<span class="c1"># La contrainte AddElement(index,variable,target) correspond à variable[index] == target</span>
<span class="c1"># Pour chaque variation, ajouter la contraintes d'addition </span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">len_snp</span><span class="p">):</span>
<span class="n">model</span><span class="o">.</span><span class="n">AddElement</span><span class="p">(</span><span class="n">index_a</span><span class="p">,</span> <span class="n">haplotype_transpose</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">a_values</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
<span class="n">model</span><span class="o">.</span><span class="n">AddElement</span><span class="p">(</span><span class="n">index_b</span><span class="p">,</span> <span class="n">haplotype_transpose</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="n">b_values</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
<span class="n">model</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="n">a_values</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">b_values</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="n">genotype_input</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
<span class="c1"># Suppression de la symétrie des résultats </span>
<span class="n">model</span><span class="o">.</span><span class="n">Add</span><span class="p">(</span><span class="n">index_a</span> <span class="o"><</span> <span class="n">index_b</span><span class="p">)</span>
<span class="n">solver</span> <span class="o">=</span> <span class="n">cp_model</span><span class="o">.</span><span class="n">CpSolver</span><span class="p">()</span>
<span class="n">status</span> <span class="o">=</span> <span class="n">solver</span><span class="o">.</span><span class="n">Solve</span><span class="p">(</span><span class="n">model</span><span class="p">)</span>
<span class="k">if</span> <span class="n">status</span> <span class="o">==</span> <span class="n">cp_model</span><span class="o">.</span><span class="n">FEASIBLE</span><span class="p">:</span>
<span class="n">solver</span><span class="o">.</span><span class="n">SearchForAllSolutions</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">cp_model</span><span class="o">.</span><span class="n">VarArraySolutionPrinter</span><span class="p">([</span><span class="n">index_a</span><span class="p">,</span><span class="n">index_b</span><span class="p">]))</span>
<span class="k">else</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"pas de solution "</span><span class="p">)</span>
</code></pre></div>
<p>Nous obtenons comme solution au génotype G=[0,1,2], l'haplotype 1 [0,0,1] et l'haplotype 2 [0,1,1].</p>
<div class="highlight"><pre><span></span><code>Solution 0, time = 0.00 s
haplotype index = 0 haplotype index = 3
</code></pre></div>
<h2>Conclusion</h2>
<p>La programmation par contrainte est particulièrement efficace lorsqu'il s'agit d'un problème combinatoire <a href="https://fr.wikipedia.org/wiki/NP-difficile">NP difficile</a> comme résoudre un sudoku ou colorier les régions d'une carte de France tel que deux régions voisines soient coloriées de différentes couleurs. Je vous invite à regarder <a href="https://github.com/google/or-tools/tree/stable/examples/python">leurs codes sources </a>.
Il existe bien sûr d'autres types de solveur et d'autre langage comme <a href="https://fr.wikipedia.org/wiki/Prolog">Prolog</a> ou <a href="https://fr.wikipedia.org/wiki/Answer_set_programming">ASP</a>. Je vous invite d'ailleur à consulter un rare <a href="https://lucas.bourneuf.net/blog/asp-tuto.html">tutorial en français</a> sur l'Answer Set Programming fait par @Aluriak.</p>Équation différentielle et python2020-04-12T14:45:57+02:002020-04-12T14:45:57+02:00Sacha Schutztag:dridk.me,2020-04-12:/equation-differentielle.html<p>Dans ce billet nous allons définir et apprendre à résoudre <a href="https://fr.wikipedia.org/wiki/%C3%89quation_diff%C3%A9rentielle_ordinaire">des équations différentielles ordinaires</a> à l'aide du langage Python.
Nous traiterons ensuite un cas pratique en modélisant une épidémie avec un <a href="https://interstices.info/modeliser-la-propagation-dune-epidemie/">modèle SIR</a> pour faire écho à la situation actuelle. <br>
PS: Je ne suis pas mathématicien, donc désolé pour mon …</p><p>Dans ce billet nous allons définir et apprendre à résoudre <a href="https://fr.wikipedia.org/wiki/%C3%89quation_diff%C3%A9rentielle_ordinaire">des équations différentielles ordinaires</a> à l'aide du langage Python.
Nous traiterons ensuite un cas pratique en modélisant une épidémie avec un <a href="https://interstices.info/modeliser-la-propagation-dune-epidemie/">modèle SIR</a> pour faire écho à la situation actuelle. <br>
PS: Je ne suis pas mathématicien, donc désolé pour mon vocabulaire et mon absence de rigueur.</p>
<h2>À quoi sert une équation différentielle ?</h2>
<p>À l'instar d'une équation usuelle, comme $x+2=3$, où il faut trouver la valeur de $x$, une équation différentielle a pour inconnue une fonction.
Plus exactement, il s'agit d'une équation mettant en relation la fonction inconnue et ses <a href="https://fr.wikipedia.org/wiki/D%C3%A9riv%C3%A9e">dérivées</a>. En effet, il est souvent plus simple de modéliser un problème en définissant les variations d'une fonction (sa dérivée) plutôt que la fonction elle-même. Par exemple, pour connaître la position d'une voiture en fonction du temps lors d'un trajet, vous pourriez par exemple, attacher un mètre ruban derrière la voiture et regarder au temps t, combien de mètres vous avez parcourus. Je ne pense pas devoir vous convaincre en disant que cette méthode est difficile à réaliser. Il est effectivement plus simple de lire la vitesse sur votre compteur à intervalle de temps régulier et de calculer à partir de celle-ci votre position. Car la vitesse n'est autre que la dérivé de la position par rapport au temps. Si par exemple, vous avez une vitesse constante de $f'(t) = 50 km/h$, alors vous pouvez déduire que l'équation donnant la position en fonction du temps est $f(t) = 50 \times t$. Au bout de 2h de route, vous avez parcouru 100 km. </p>
<h2>Calculer le nombre de bactéries en fonction du temps</h2>
<p>Essayons par exemple de trouver la fonction $N(t)$ décrivant l'évolution du nombre de bactéries en fonction du temps. Supposons pour l'exemple que nous avons au temps zéro $N_0=100$ bactéries et que le nombre de bactéries au temps $t+1$ augmente de façon proportionnelle à $N(t)$. C'est-à-dire qu'à $t+1$ nous avons: </p>
<p>$$
N(t+1) = N(t) + N(t) \times k \[5mm]
N(t+1) - N(t) = N(t) \times k \[5mm]
Soit \[5mm]
\Delta N = N(t) \times k
$$ </p>
<p>Cette équation exprime la quantité de nouvelles bactéries à rajouter à chaque génération. <br>
Essayons à présent en Python, avec 3 méthodes différentes, d'utiliser cette formule pour calculer le nombre de bactéries en fonction du temps.</p>
<h3>Méthode algorithmique naïve</h3>
<p>Une façon triviale de résoudre ce problème en Python est de calculer itérativement à partir de N(t), la prochaine valeur de N(t+1).
Nous obtenons alors une croissance exponentielle. </p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
<span class="n">N_0</span> <span class="o">=</span> <span class="mi">100</span> <span class="c1"># Population initial</span>
<span class="n">k</span> <span class="o">=</span> <span class="mf">0.2</span> <span class="c1"># coef</span>
<span class="n">times</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">100</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># Temps </span>
<span class="n">y</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">N</span> <span class="o">=</span> <span class="n">N_0</span>
<span class="c1"># iteration et calcul de N(t+1)</span>
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">times</span><span class="p">:</span>
<span class="n">y</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">N</span><span class="p">)</span>
<span class="n">N</span> <span class="o">=</span> <span class="n">N</span> <span class="o">+</span> <span class="n">N</span> <span class="o">*</span> <span class="n">k</span>
<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span> <span class="p">(</span><span class="mi">15</span><span class="p">,</span><span class="mi">5</span><span class="p">))</span>
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">times</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="s2">"bo"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"#01a698"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"temps"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"Nombre de bactérie"</span><span class="p">)</span>
</code></pre></div>
<div class="figure">
<img src="../images/equa_diff/bact_1.png" />
<div class="legend"> </div>
</div>
<h3>Méthode algorithmique avec scipy</h3>
<p>L'équation précédente définie sur des intervalles de temps discret peut être réinterprétée dans le domaine continu à l'aide de l'équation différentielle ci-dessous:</p>
<p>$$
\frac{dN}{\delta t} = N \times K \[5mm]
Soit \[5mm]
\frac{dN}{\delta t} = N \times ln(k + 1)<br>
$$</p>
<blockquote>
<p><strong>Attention</strong>: La valeur de grand <strong>K</strong> dans le domaine continu pour un $\delta t$ infinitésimal n'est pas le même que petit <strong>k</strong> dans le domaine discret pour un $\Delta t=1$. La relation entre K et k s'écrit $K = ln(k + 1)$. Merci à <a href="https://twitter.com/paljasn?lang=fr">@Paljasn </a> pour l'explication ! </p>
</blockquote>
<p>En python, la fonction <a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.ode.html">ode</a> du module <a href="https://docs.scipy.org/doc/scipy/reference/tutorial/integrate.html">integrate</a> de <a href="https://docs.scipy.org/doc/scipy/reference/index.html">scipy</a> permet de résoudre cette équation différentielle. Il faut d'abord définir la dérivée de l'équation différentielle avec comme premier argument la fonction inconnue (N) puis sa variable (t) et autant de paramètres que nécessaire (k):</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
<span class="kn">from</span> <span class="nn">scipy.integrate</span> <span class="kn">import</span> <span class="n">ode</span>
<span class="k">def</span> <span class="nf">deriv</span><span class="p">(</span><span class="n">N</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">K</span><span class="p">):</span>
<span class="sd">""" Dérivé de N par rapport au temps t et du coef K """</span>
<span class="n">dNdt</span> <span class="o">=</span> <span class="n">K</span> <span class="o">*</span> <span class="n">N</span>
<span class="k">return</span> <span class="n">dNdt</span>
<span class="n">N_0</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">k</span> <span class="o">=</span> <span class="mf">0.2</span>
<span class="n">K</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="c1"># Résolution de l'équation différentielle avec ode </span>
<span class="n">ret</span> <span class="o">=</span> <span class="n">odeint</span><span class="p">(</span><span class="n">deriv</span><span class="p">,</span> <span class="n">N</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">args</span> <span class="o">=</span> <span class="p">(</span><span class="n">K</span><span class="p">,)</span> <span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span> <span class="p">(</span><span class="mi">15</span><span class="p">,</span><span class="mi">5</span><span class="p">))</span>
<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"temps"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"Nombre de bactérie"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="s2">"bo"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"#a81b22"</span><span class="p">)</span>
</code></pre></div>
<div class="figure">
<img src="../images/equa_diff/bact_2.png" />
<div class="legend"> </div>
</div>
<h3>Méthode analytique</h3>
<p>La méthode précédente permet de tracer la fonction $N(t)$. En revanche, elle ne nous donne pas son équation. Dans la plupart des cas, on ne pourra pas faire autrement. Il faudra alors utiliser des méthodes similaires aux précédentes.
Cependant, dans notre exemple, il existe une solution analytique en isolant $dN$ et en calculant son intégrale. Le nombre de bactéries en fonction du temps s'écrit alors : </p>
<p>$$
\begin{array}{lc}
\frac{dN}{dt} = N \times k \[0.2cm]
\frac{dN}{dt} \times dt = N \times k \times dt \[0.2cm]
dN = N \times k \times dt \[0.2cm]
\frac{1}{N}dN= k \times dt \[0.2cm]
\int\frac{1}{N}dN= \int k \times dt \[0.2cm]
ln(N) + c_1 = kt + c_2 \[0.2cm]
ln(N) = kt + C \[0.2cm]
N = N_0 \times e^{kt}
\end{array}
$$</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
<span class="n">N_0</span> <span class="o">=</span> <span class="mi">100</span>
<span class="n">k</span> <span class="o">=</span> <span class="mf">0.2</span>
<span class="n">K</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">times</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span>
<span class="c1"># Calcul de N via la fonction analytique </span>
<span class="n">N</span> <span class="o">=</span> <span class="n">N_0</span> <span class="o">*</span> <span class="n">np</span><span class="o">.</span><span class="n">exp</span><span class="p">(</span><span class="n">K</span> <span class="o">*</span> <span class="n">times</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span> <span class="p">(</span><span class="mi">15</span><span class="p">,</span><span class="mi">5</span><span class="p">))</span>
<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"temps"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"Nombre de bactérie"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="s2">"bo"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"#a81b22"</span><span class="p">)</span>
</code></pre></div>
<div class="figure">
<img src="../images/equa_diff/bact_3.png" />
<div class="legend"> </div>
</div>
<h2>Modélisation d'une épidémie</h2>
<p>Le modèle SIR est une <a href="https://fr.wikipedia.org/wiki/Mod%C3%A8les_compartimentaux_en_%C3%A9pid%C3%A9miologie">modélisation compartimentale</a> décrivant l'évolution au cours du temps du nombre d'individus Sains (S), Infectés (I) et Rétablis (R).
Dans ce modèle à trois compartiments, la population est constante. Le nombre de nouveaux patients infectés dépend du nombre d'individus sains et du nombre d'individus infecté pondéré par un facteur β. C'est-à-dire qu'à chaque instant t, il faut retirer des sains et ajouter aux infectés le nombre $-\beta \times I(t) \times S(t)$.
De même, le nombre de patients rétabli dépend du nombre d'infecté et d'un paramètre γ. À chaque instant t, le nombre de patients rétablis augmente donc de $\gamma \times I(t)$. </p>
<div class="figure">
<img src="../images/equa_diff/schema_sir.png" />
<div class="legend"> Modèle à trois compartiments avec deux constantes de transfert décrivant l'évolution de la population durant une épidémie. </div>
</div>
<p>L'évolution du nombre d'individus dans ces 3 compartiments peut alors être décrite à l'aide de 3 équations différentielles et des deux constantes de transfert β et γ.</p>
<p>$$
\begin{array}{lc}
\frac{dS(t)}{dt} = -\beta \times I(t) \times S(t) \
\frac{dI(t)}{dt} = \beta \times I(t) \times S - \gamma \times I(t) \
\frac{dR(t)}{dt} = \gamma \times I(t)\
\end{array}
$$</p>
<p>Nous pouvons alors traduire ces 3 équations différentielles et les résoudre avec le module ode. </p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">deriv</span><span class="p">(</span><span class="n">y</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">beta</span><span class="p">,</span> <span class="n">gamma</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd"> y : liste contenant les 3 fonctions inconnus </span>
<span class="sd"> t : le temps </span>
<span class="sd"> beta, gamma : les deux facteurs du modèle</span>
<span class="sd"> """</span>
<span class="n">S</span><span class="p">,</span><span class="n">I</span><span class="p">,</span><span class="n">R</span> <span class="o">=</span> <span class="n">y</span>
<span class="c1"># Description des 3 equations differentielles </span>
<span class="n">dSdt</span> <span class="o">=</span> <span class="o">-</span><span class="n">S</span> <span class="o">*</span> <span class="n">I</span> <span class="o">*</span> <span class="n">beta</span>
<span class="n">dIdt</span> <span class="o">=</span> <span class="n">S</span> <span class="o">*</span> <span class="n">I</span> <span class="o">*</span> <span class="n">beta</span> <span class="o">-</span> <span class="n">gamma</span> <span class="o">*</span> <span class="n">I</span>
<span class="n">dRdt</span> <span class="o">=</span> <span class="n">gamma</span> <span class="o">*</span> <span class="n">I</span>
<span class="k">return</span> <span class="n">dSdt</span><span class="p">,</span> <span class="n">dIdt</span><span class="p">,</span> <span class="n">dRdt</span>
<span class="c1"># Au temps t0, 70% sains, 30% infécté, 0 guéri </span>
<span class="n">y0</span> <span class="o">=</span> <span class="mf">0.7</span><span class="p">,</span> <span class="mf">0.3</span><span class="p">,</span> <span class="mi">0</span>
<span class="c1"># Evolution sur 28 jours </span>
<span class="n">t</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">28</span><span class="p">)</span>
<span class="c1"># Paramètres du modèle </span>
<span class="n">beta</span> <span class="o">=</span> <span class="mf">0.5</span>
<span class="n">gamma</span> <span class="o">=</span> <span class="mf">0.1</span>
<span class="c1"># Resolution des équations differentielles </span>
<span class="n">ret</span> <span class="o">=</span> <span class="n">odeint</span><span class="p">(</span><span class="n">deriv</span><span class="p">,</span> <span class="n">y0</span><span class="p">,</span> <span class="n">t</span><span class="p">,</span> <span class="n">args</span> <span class="o">=</span> <span class="p">(</span> <span class="n">beta</span><span class="p">,</span> <span class="n">gamma</span><span class="p">))</span>
<span class="n">S</span><span class="p">,</span><span class="n">I</span><span class="p">,</span><span class="n">R</span> <span class="o">=</span> <span class="n">ret</span><span class="o">.</span><span class="n">T</span>
<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span><span class="mi">10</span><span class="p">))</span>
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">S</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Sains"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">I</span><span class="p">,</span><span class="n">label</span><span class="o">=</span><span class="s2">"Inféctés"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="n">R</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Rétablis"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s2">"temps"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s2">"nombre d'individu"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span>
<span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Proportion des individus durant une épidémie modélisé par MIR avec β = </span><span class="si">{</span><span class="n">beta</span><span class="si">}</span><span class="s2"> et γ = </span><span class="si">{</span><span class="n">gamma</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</code></pre></div>
<div class="figure">
<img src="../images/equa_diff/MIR.png" />
<div class="legend">Evolution en pourcentage des 3 populations (saines, infectées, guéries) au cours du temps à l'aide d'un modèle SIR paramétré par β=0.5 et γ=0.1 </div>
</div>
<p>Je vous invite à jouer avec les paramètres de ce modèle afin de voir l'impact qu'ils ont sur l'épidémie. Vous pouvez le faire directement en ligne sur <a href="https://interstices.info/modeliser-la-propagation-dune-epidemie/">la page suivante.</a>. Par ailleurs, le notebook de ce billet est <a href="https://colab.research.google.com/drive/1FySg6HwXhdXYDhD0c5z3orxjOve0pGi3">disponible ici</a> </p>
<h2>Référence</h2>
<ul>
<li><a href="https://interstices.info/modeliser-la-propagation-dune-epidemie/">modeliser-la-propagation-dune-epidemie/</a> </li>
<li><a href="https://apmonitor.com/pdc/index.php/Main/SolveDifferentialEquations">Solve Differential Equations with ODEINT</a></li>
<li><a href="https://scipython.com/book/chapter-8-scipy/additional-examples/the-sir-epidemic-model/">The SIR epidemic model</a></li>
<li><a href="https://web.stanford.edu/class/archive/math/math21/math21.1156/files/21/notes5.pdf">An example of a differential equation: Bacterial growth</a></li>
</ul>Inférence bayésienne et python2020-03-27T19:40:47+01:002020-03-27T19:40:47+01:00Sacha Schutztag:dridk.me,2020-03-27:/inference_bayesienne.html<p>Cela fait un moment que j'avais envie de publier sur l'<em>inférence bayésienne</em>. Mon intérêt pour ce sujet a été éveillé par la lecture du livre <a href="https://laboutique.edpsciences.fr/produit/1035/9782759822614/La%20formule%20du%20savoir">La formule du savoir</a> par <a href="https://fr.wikipedia.org/wiki/L%C3%AA_Nguy%C3%AAn_Hoang">Nguyên Hoang Lê</a>. En deux mots, l'inférence bayésienne est une méthode qui permet de donner une crédibilité à nos …</p><p>Cela fait un moment que j'avais envie de publier sur l'<em>inférence bayésienne</em>. Mon intérêt pour ce sujet a été éveillé par la lecture du livre <a href="https://laboutique.edpsciences.fr/produit/1035/9782759822614/La%20formule%20du%20savoir">La formule du savoir</a> par <a href="https://fr.wikipedia.org/wiki/L%C3%AA_Nguy%C3%AAn_Hoang">Nguyên Hoang Lê</a>. En deux mots, l'inférence bayésienne est une méthode qui permet de donner une crédibilité à nos croyances en s'appuyant sur nos observations et nos <em>a priori</em>.
Dans ce billet je définirai, à partir d'exemples intuitifs, l'inférence bayésienne et son vocabulaire. Puis, j'implémenterai la méthode avec un script rédigé en <em>python</em> seul et avec la librairie de programmation probabiliste <a href="https://docs.pymc.io/">PyMC3</a>. </p>
<h2>La probabilité des causes</h2>
<p>Selon le principe de causalité, la connaissance des <em>causes</em>, permet de <strong>prédire</strong>, ses <em>effets</em>. La mécanique newtonienne permet, par exemple, de prédire la trajectoire d'un javelot lancé par un athlète. <br>
On peut, cependant, être tenter de faire l'inverse. C'est à dire d'<strong>inférer</strong> les causes à partir des effets observés. En observant des traces de pas, nous pouvons par exemple supposer avec une probabilité plus ou moins forte que le tueur était sur la scène du crime. <br>
En général, les observations peuvent être suffisemment décrites et mesurées alors que la connaissance des causes ou des théories sous-jacentes est la plupart du temps hors de portée. Grâce à l'inférence bayésienne il devient possible de mesurer, à partir de l'observation et d'un <em>a priori</em>, la crédibilité d'une cause. <br>
Dans la suite de ce billet, j'utiliserai les mots <em>hypothèses</em> et <em>donnée</em> que vous pouvez à tout moment remplacer par <em>cause</em> est <em>effets</em>.
<center>
<img src="../images/inference_bayesienne/predire_inferer.png" /> <br>
</center></p>
<h2>Qui est dans la boite ?</h2>
<p>Imaginez une boite dans laquelle se cache une personne inconnue. Quelle probabilité peut-on accorder aux deux <strong>hypothèses</strong> suivantes :</p>
<ul>
<li><em>la personne est un homme</em></li>
<li><em>la personne est une femme</em></li>
</ul>
<p>A priori, sans autre information, la probabilité est 50-50, 'est-à-dire qu'il y a autant de chance que ce soit une femme qu'un homme. Appelons cette probabilité, probabilité <strong>a-priori</strong> notée <strong>p(hypothèse)</strong>, soit dans notre exemple <strong>p(homme) = p(femme) = 0.5</strong>. Notons que la somme des probabilités de l'ensemble des hypothèses doit être égale à 1 (la personne inconnue ne peut être autre chose qu'un homme ou une femme).
Si maintenant, nous disposons d'une <strong>donnée</strong> supplémentaire, à savoir que la personne inconnue a les cheveux longs, la probabilité que l'inconnu soit un homme ou une femme change en augmentant <strong>p(femme)</strong> et en diminuant d'autant <strong>p(homme)</strong>. En effet, intuitivement, nous savons qu'il y a plus de femmes aux cheveux longs que d'hommes aux cheveux longs.<br>
Cette nouvelle grandeur est appelée, en statistique, <strong>vraisemblance des données</strong> : c'est la probabilité d'observer des données en supposant une hypothèse vrai. Elle est notée <strong>p(donnée|hypothèse)</strong>. Admettons, par exemple, que parmi toutes les femmes, 70% ont les cheveux longs et parmi tous les hommes, 10% ont les cheveux longs. Dans ce cas <strong>p(cheveux_longs|femme) = 70%</strong> et <strong>p(cheveux_longs|Homme) = 10%</strong>. <br>
Mais ce que nous cherchons est différents. Nous voulons connaître la probabilité que la personne dans la boîte soit une femme, sachant qu'elle porte les cheveux long. Nous appelons cette probabilité, probabilité <strong>a-posteriori</strong> notée <strong>p(hypothèse|donnée)</strong>. (Attention de ne pas confondre cette dernière probabilité avec la vraisemblance des données: la probabilité d'être argentin sachant qu'on est le pape n'est pas la même chose que la probabilité d'être le pape sachant qu'on est argentin.) <br>
La probabilité a-posteriori est égale, selon la <a href="https://fr.wikipedia.org/wiki/Th%C3%A9or%C3%A8me_de_Bayes">formule de Bayes</a>, au produit de la probabilité a-priori et de la vraisemblance des données, le tout normalisé par la somme des probabilités <em>a-posteriori</em> de toutes les autres hypothèses : </p>
<p>$$
\begin{array}{lc}
p(H|D) &=& \frac{p(H) \times p(D|H)}{\sum_{i} p(H_i) \times p(D|H_i) }\[0.5cm]
\end{array}\[0.5cm]
\text{$H$ : hypothèse et $D$ : données}
$$
Calculons, dans notre exemple, la probabilité <em>a-posteriori</em> pour chaque hypothèse :</p>
<p>$$
\begin{array}{lcc}
p(\text{homme}) \times p(\text{cheveux_longs}|\text{homme}) = 0,5 \times 0,1 = 0,05 \[0.5cm]
p(\text{femme}) \times p(\text{cheveux_longs}|\text{femme}) =0,5 \times 0,7 = 0,35
\end{array}
$$
et donc :</p>
<p>$$
\begin{array}{ccl}
p(\text{homme}|\text{cheveux_longs}) = \frac{0.05} {(0.35 + 0.05)} = 12,5\% \[0.5cm]
p(\text{femme}|\text{cheveux_longs}) = \frac{0.35} {(0.35 + 0.05)} = 87,5\%
\end{array}
$$</p>
<p>La personne dans cette boite, a donc 87,5% de chance d'être une femme et 12.5% de chance d'être un homme. </p>
<p>Cependant, le bayésiens préfèrent raisonner en termes de paris plutôt qu'en termes de probabilités. En effet, le dénominateur de la formule de Bayes est une constante parfois très compliqué à calculer. Il s'annule lorsque l'on fait le rapport entre les deux hypothèses.
Dans notre cas :
$$ \frac{p(\text{femme}|\text{cheveux_longs})}{p(\text{homme}|\text{cheveux_longs})} = \frac{0.35}{0.05} = 7$$</p>
<p>Je peux ainsi parier à 7 contre 1 que la personne dans la boite est une femme. Remarquez que le bayésien évalue toujours une hypothèse par rapport à toutes les autres. Les probabilités perdent leurs caractères absolus pour devenir relatives. </p>
<p>Ainsi, si il y avait une seul formule à retenir, ce serait la relation de proportionnalité suivante:</p>
<p>$$ posteriori \sim priori \times vraisemblance $$</p>
<p>En résumé, l'inférence bayésienne consiste à évaluer une probabilité <em>a-postiori</em> à partir d'une probabilité <em>a-priori</em> corrigée par la vraisemblance des données observées. La probabilité ainsi obtenue peut à son tour servir d'un <em>a-priori</em> que l'on corrigera si de nouvelles données sont disponibles. En procédant ainsi de façon itérative, la probabilité des hypothèses convergera vers <em>«la vérité»</em> ... <br>
Je vous soumets à votre réflexion un exercice dans le contexte de la pandémie du <a href="https://fr.wikipedia.org/wiki/Maladie_%C3%A0_coronavirus_2019">Covid-19</a>, de quoi occuper votre temps de confinement. Si je me mets à tousser, quel pari faites-vous sur le fait que je sois contaminé ou non ? C'est marrant, mais vous auriez certainement pas dit la même chose quelque mois plutôt. Pourquoi à votre avis ? A cause de vos a-priori que vous ne devez jamais ignorer ! </p>
<h2>Bayes pour les distributions continues</h2>
<p>Dans l'exemple précédent de la personne câchée dans une boite, la distribution des probabilités des deux hypothèses, femme ou homme, peut être représentée par une <a href="https://fr.wikipedia.org/wiki/Liste_de_lois_de_probabilit%C3%A9#Distributions_discr%C3%A8tes">distribution</a> discrète à deux événements. Nous pouvons généraliser le problème en augmentant le nombre d'hypothèses. Par exemple, chercher la probabilité que la personne dans la boite soit blond(e), brun(e), roux, châtain ou , pour allez encore plus loin, des hypothèses sur la taille. Dans ce cas, il y a une infinité d'hypothèses et la distribution discrète tend vers une <a href="https://fr.wikipedia.org/wiki/Variable_al%C3%A9atoire_%C3%A0_densit%C3%A9">densité de probabilité </a> d'une variable aléatoire continue.</p>
<p><center>
<img src="../images/inference_bayesienne/distr_continue.png" /> <br>
</center></p>
<p>Pour calculer la probabilité d'une variable (ou hypothèse) $x$ connaissant les probabilités des données, la formule de Bayes s'applique de la même façon, sauf que la somme au dénominateur devient une intégrale :</p>
<p>$$p(x|\text{donnée}) = \frac{p(x) \times p(\text{donnée}|x) }{\int p(x)p(\text{donnée}|x) dx}$$ </p>
<h2>Parier sur les paramètres d'une loi de probabilité</h2>
<p>Une loi de probabilité est une fonction mathématique décrivant la distribution d'une variable aléatoire. Elle est définie, par exemple, par la moyenne (µ) et l'écart type (σ) pour une <a href="https://fr.wikipedia.org/wiki/Loi_normale">loi normale</a>, le paramètre lambda (λ) pour une <a href="https://fr.wikipedia.org/wiki/Loi_de_poisson">loi de poisson</a> ou encore les paramètres (n,p) pour une <a href="https://fr.wikipedia.org/wiki/Loi_binomiale">loi binomiale</a>.
En statistique bayésienne, on fera des paris sur ces paramètres après avoir observé des données. Supposons, par exemple, que la distribution des tailles de la population suit une loi normale de moyenne µ. En observant les tailles de plusieurs individus dans un échantillon, nous pouvons essayer de deviner la valeur de µ. Plus exactement, nous allons chercher la distribution de probabilités des valeurs possible de µ. <br>
Dit autrement, le paramètre θ d'une loi de probabilité A décrivant une variable aléatoire $x$ peut lui même être décrit comme une variable aléatoire suivant une autre loi de probabilité B. C'est compliqué, je sais.. Allez, un exemple concrêt pour mieux comprendre. </p>
<h2>Comment savoir si une pièce est truquée ?</h2>
<p>Considérons le jeu de pile-ou-face avec une pièce de monnaie et appelons thêta (θ) la probabilité que la pièce tombe sur face. Si la pièce n'est pas truquée alors la probabilité θ est 0,5. Dans le cas contraire, θ peut prendre n'importe quelle valeur comprise entre 0 et 1.
Statistiquement parlant nous dirons que la variable aléatoire $x$
(pile ou face) suit une <a href="https://fr.wikipedia.org/wiki/Loi_de_Bernoulli">loi discrète de Bernouilli</a> paramétrée par θ. </p>
<p>$$x \sim \text{Bern}(p=\theta)$$</p>
<p>Malheureusement je n'ai aucune idée de la valeur de θ. Pour l'estimer, il faut expérimenter en lançant plusieurs fois la pièce et comptabiliser les fois où elle tombe sur face (1) et les fois où elle tombe sur pile (0).
Voici par exemple ce que j'obtiens après 10 lancers : </p>
<div class="highlight"><pre><span></span><code>Observation = [1,0,0,1,1,0,1,1,0,1]
</code></pre></div>
<p>À partir de ces données, comment faites-vous pour estimer θ ? <br>
Et bien, grâce à l'inférence bayésienne, nous pouvons calculer la distribution des valeurs possible de θ au regard de notre observation: </p>
<p>$$p(\theta|\text{observation}) \sim p(\theta) \times p(\text{observation}|\theta)$$</p>
<p>Il nous faut donc un <strong>a-priori</strong> et une <strong>vraisemblance</strong>.</p>
<h3>Calcul de l'a-priori</h3>
<p>θ est une probabilité. Sa valeur est comprise entre 0 et 1. Ils nous faut donc une loi définie sur cet intervalle.
Nous pourrions, par exemple, choisir la <a href="https://fr.wikipedia.org/wiki/Loi_uniforme_continue">loi uniforme</a> sur [0-1], c'est-à-dire associer à chaque valeur possible de θ la même probabilité. Ça marcherait, mais dans ce cas, l'a-priori ne nous apporterait aucune information.
Personnellement, j'aurais tendance à dire qu'une pièce truquée est peu probable, car après tout.... je n’en ai jamais vu !<br>
Nous allons donc choisir une <a href="https://fr.wikipedia.org/wiki/Loi_b%C3%AAta">loi bêta</a>, très souvent utilisée en inférence bayésienne pour définir l'a-priori :</p>
<p>$$\theta \sim \text{Beta}(a, b)$$</p>
<p>La forme de cette loi bêta dépend de deux paramètres $a$ et $b$, comme cela est illustré dans la figure ci-dessous. </p>
<div class="figure">
<img src="../images/inference_bayesienne/beta.png" />
<div class="legend">différentes formes de la loi bêta selon les paramètres a et b
</div>
</div>
<p>Je vous propose d'utiliser la loi symétrique de paramètres $a = 5$, et $b = 5$, dont la probabilité est maximum pour $θ = 0.5$ et tend vers zéro lorsque $θ$ tend vers 0 ou 1. <br>
A l'aide du module <em>stats</em> de la librarie <a href="https://www.scipy.org/">scipy</a>, nous pouvons implémenter cette fonction en langage python : </p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">prior</span><span class="p">(</span><span class="n">theta</span><span class="p">):</span>
<span class="n">prior</span> <span class="o">=</span> <span class="n">stats</span><span class="o">.</span><span class="n">beta</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span><span class="mi">5</span><span class="p">)</span><span class="o">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span>
<span class="k">return</span> <span class="n">prior</span>
</code></pre></div>
<h3>Calcul de la vraisemblance</h3>
<p>La vraisemblance est la probabilité d'observer des données en supposant vrai la loi de Bernoulli sous une valeur spécifique de θ.
Etant donné qu'il y a plusieurs observations indépendantes ($x1, x2, x3, \cdots$) nous pouvons écrire : </p>
<p>$$p(x_1,x_2,\cdots, x_n | \theta ) = p(x_1|\theta) \times p(x_2|\theta) \times \cdots \times p(x_n|\theta) $$</p>
<p>Ce qui peut être implémenter en python comme suit : </p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">vraissemblance</span><span class="p">(</span><span class="n">observations</span><span class="p">,</span> <span class="n">theta</span><span class="p">):</span>
<span class="n">L</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">loi</span> <span class="o">=</span> <span class="n">stats</span><span class="o">.</span><span class="n">bernoulli</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span>
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">observations</span><span class="p">:</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">loi</span><span class="o">.</span><span class="n">pmf</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="n">L</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>
<span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">prod</span><span class="p">(</span><span class="n">L</span><span class="p">)</span>
</code></pre></div>
<blockquote>
<p><em>En réalité, nous aurions pu utiliser la loi binomiale... Mais nous n'allons pas nous encombrer d'une autre loi</em>.</p>
</blockquote>
<h3>Calcul de l' a-posteriori</h3>
<p>Il suffit maintenant d'appliquer la formule de Bayes pour avoir la forme de la distribution des probabilités a-posteriori de θ et l'afficher avec <a href="https://matplotlib.org/">matplotlib</a>:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">posteriori</span><span class="p">(</span><span class="n">theta</span><span class="p">,</span> <span class="n">observations</span><span class="p">):</span>
<span class="n">prior</span> <span class="o">=</span> <span class="n">prior</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span>
<span class="n">likelihood</span> <span class="o">=</span> <span class="n">vraissemblance</span><span class="p">(</span><span class="n">observations</span><span class="p">,</span> <span class="n">theta</span><span class="p">)</span>
<span class="k">return</span> <span class="n">likelihood</span> <span class="o">*</span> <span class="n">prior</span>
<span class="c1"># 100 observations </span>
<span class="c1">#observations = [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, .... ] </span>
<span class="c1"># Calculer les probabilités pour plusieurs valeurs de θ </span>
<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">linspace</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="p">[</span><span class="n">posteriori</span><span class="p">(</span><span class="n">theta</span><span class="p">,</span> <span class="n">data</span><span class="p">[:</span><span class="mi">100</span><span class="p">])</span> <span class="k">for</span> <span class="n">theta</span> <span class="ow">in</span> <span class="n">x</span><span class="p">]</span>
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span>
</code></pre></div>
<div class="figure">
<img src="../images/inference_bayesienne/posteriori.png" />
<div class="legend">Distribution a-posteriori de θ avec un maximum autour de θ = 0,8. L'axe des absisses correspond aux valeurs possible de θ, l'axe des ordonnées à leurs probabilités </div>
</div>
<p>Pour mieux comprendre ce graphique, j'ai calculé l' <em>a-posteriori</em> avec un nombre croissant d'observations : </p>
<div class="figure">
<img src="../images/inference_bayesienne/plot.svg" />
<div class="legend"> Distribution des probabilités θ en augmentantle nombre d'observations. Plus les données s'accumulent, plus le maximum de la distribution se stabilise autour de θ = 0,8. </div>
</div>
<p>Sans observation, le maximum de la distribution des probabilités est en θ = 0,5. Il s'agit là de notre a-priori. Ensuite, avec l'accumulation progressive des observations, le maximum de la distribution se rapproche de 0,8 et la variance de la distribution diminue. <br>
Ainsi nous pouvons conclure, grâce à l'inférence bayésienne, que les observations sont en faveur d'une pièce truquée avec un θ probablement de 0,76. Effectivement, j'ai généré automatiquement les observations avec une loi de Bernouilli paramétré par 0,8 et je vous ai caché volontairement le code pour éviter les confusions! Notons dans l'exemple, que l'<em>a-priori</em> très faible pour la valeur de 0,8 nous empèche d'être parfaitement centré sur 0,8. Il nous faudrait pour cela plus de donnée. L'adage suivant illustre bien cette situation: « Une affirmation extraordinaire nécessite une preuve plus qu’ordinaire ».</p>
<h2>Utilisation de PyMC3</h2>
<p>Pour finir, voici le même algorithme, mais implémenté cette fois en utilisant la librairie <a href="https://docs.pymc.io/">PyMC3</a>. Il s'agit d'une librairie puissante et très simple permettant de faire de la programmation probabiliste. La librarie fonctionne à l'aide d'<a href="https://fr.wikipedia.org/wiki/M%C3%A9thode_de_Monte-Carlo_par_cha%C3%AEnes_de_Markov">echantillonneur MCMC</a>. Pour faire simple, les échantillonneurs vont générer aléatoirement des valeurs de θ suivant la distribution a-posteriori recherchée.
Cela permet d'éviter le calcul fastidieux de l'intégrale vu plus haut, et construire des modèles bien plus complexes avec de nombreux paramètres. </p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">pymc3</span> <span class="k">as</span> <span class="nn">pm</span>
<span class="kn">import</span> <span class="nn">arviz</span> <span class="k">as</span> <span class="nn">az</span>
<span class="c1">#observations = [0, 0, 1, 1, 0, 1, 1, 0, 1, 1, .... ] </span>
<span class="k">with</span> <span class="n">pm</span><span class="o">.</span><span class="n">Model</span><span class="p">()</span> <span class="k">as</span> <span class="n">model</span><span class="p">:</span>
<span class="c1"># Definition d'un a priori suivant une loi bêta paramétrée par alpha et bêta </span>
<span class="n">theta</span> <span class="o">=</span> <span class="n">pm</span><span class="o">.</span><span class="n">Beta</span><span class="p">(</span><span class="s2">"theta"</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">beta</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="c1"># Définition de la vraisemblance des données sous l'hypothèse thêta </span>
<span class="n">y</span> <span class="o">=</span> <span class="n">pm</span><span class="o">.</span><span class="n">Bernoulli</span><span class="p">(</span><span class="s2">"y"</span><span class="p">,</span> <span class="n">p</span><span class="o">=</span><span class="n">theta</span><span class="p">,</span> <span class="n">observed</span> <span class="o">=</span> <span class="n">data</span><span class="p">)</span>
<span class="c1"># Échantillonnage de 1000 valeurs de thêta</span>
<span class="n">trace</span> <span class="o">=</span> <span class="n">pm</span><span class="o">.</span><span class="n">sample</span><span class="p">(</span><span class="mi">1000</span><span class="p">,</span> <span class="n">random_seed</span><span class="o">=</span><span class="mi">123</span><span class="p">)</span>
<span class="c1"># Visualisation des résultats avec la librarie arviz</span>
<span class="n">az</span><span class="o">.</span><span class="n">plot_trace</span><span class="p">(</span><span class="n">trace</span><span class="p">)</span>
</code></pre></div>
<div class="figure">
<img src="../images/inference_bayesienne/arviz.png" />
<div class="legend">Distribution des probabilités de θ avec <a href="https://en.wikipedia.org/wiki/Credible_interval)(Highest Posterior Density interval"> l'interval de crédibilité appelé HPD. </a> </div>
</div>
<p>Voilà pour ce billet qui est déjà assez long ! Je vous invite fortement à regarder les références ci-dessous. L'ensemble du code ayant servi à illustrer ce billet est disponible et éditable sur <a href="https://colab.research.google.com/drive/14RWMzPAfN6u-n0WrurPzjIbliv6ecHu9">google colab</a>. <br>
Il y a également <a href="https://covid19dashboards.com/growth-bayes/">ce billet</a> pour anglophone dans le contexte du Covid-19 qui fait des prédictions bayésienne sur la cinétique de l'épidémie.</p>
<h2>Référence</h2>
<ul>
<li><a href="https://www.youtube.com/channel/UC0NCbj8CxzeCGIF6sODJ-7A">chaine YouTube de Science4All</a> </li>
<li><a href="https://dun.unistra.fr/ipm/unit/bayesien/co/1a_1_1.html">Introduction aux statistiques bayésiennes</a></li>
<li><a href="https://www.fnac.com/livre-numerique/a12861451/Osvaldo-Martin-Bayesian-Analysis-with-Python?Origin=fnac_google#FORMAT=ePub">Livre: Bayesian Analysis with Python</a></li>
</ul>Les chaînes de Markov2019-12-24T12:44:30+01:002019-12-24T12:44:30+01:00Sacha Schutztag:dridk.me,2019-12-24:/chaine-de-markov.html<p>Les <a href="https://fr.wikipedia.org/wiki/Cha%C3%AEne_de_Markov">chaînes de Markov </a>sont très populaires en bioinformatique, en particulier lorsque l'on travaille avec des séquences biologiques.
J'aime bien me les représenter comme des machines générant des symboles aléatoires (ou <a href="https://fr.wikipedia.org/wiki/Processus_stochastique">processus stochastique</a>) dont la probabilité d'apparition de chacun dépend du précédent. <br>
Dans ce billet, nous allons les définir et …</p><p>Les <a href="https://fr.wikipedia.org/wiki/Cha%C3%AEne_de_Markov">chaînes de Markov </a>sont très populaires en bioinformatique, en particulier lorsque l'on travaille avec des séquences biologiques.
J'aime bien me les représenter comme des machines générant des symboles aléatoires (ou <a href="https://fr.wikipedia.org/wiki/Processus_stochastique">processus stochastique</a>) dont la probabilité d'apparition de chacun dépend du précédent. <br>
Dans ce billet, nous allons les définir et voir comment nous pouvons les utiliser en pratique.</p>
<h2>Un dé à 4 faces</h2>
<p>Imaginez un dé à 4 faces sur lequel sont représentées les quatre bases A,C,G,T de l'ADN. Lancez ce dé plusieurs fois en notant chaque résultat.
Par exemple, le premier lancé vous donne un A, le deuxième un T, le troisième un A et ainsi de suite jusqu'à générer une longue séquence.
Si le dé n'est pas truqué, à chaque lancée, vous avez exactement une chance sur 4 d'obtenir chacune des quatre bases. <br>
Une façon de représenter ce tirage aléatoire est d'utiliser un <a href="https://fr.wikipedia.org/wiki/Th%C3%A9orie_des_graphes">graphe</a>, appelé diagramme de transition, ou chaque nœud représente les bases ou <strong>états</strong> et les arrêtes les probabilités de <strong>transitions</strong>. Dans la figure ci-dessous, il y a 4 états (A,C,G,T) et 16 transitions avec leurs probabilités toutes égales à 1/4. Par exemple, la probabilité d'obtenir un C après en A est de 1/4 et de même pour les autres transitions.
Pour générer une séquence aléatoire, choisissiez un nœud au hasard, puis faite une marche dans ce graphe en suivant les probabilités de transition. Notez la valeur de chaque nœud traversé. Bravo, vous venez de générer une séquence à l'aide une chaîne de Markov. </p>
<div class="figure"> <img src="../images/markov/animation.gif" /> <div class="legend">Génération d'une séquence avec une chaîne de Markov. <br/>Il y a 4 états (A,C,G,T) et 4x4=16 transitions possibles toutes avec une probabilité de 1/4</div> </div>
<h2>Définition d'une chaîne de Markov</h2>
<p>Une chaîne de Markov se définit donc par un vecteur d'état <strong>E</strong> et une matrice de transition <strong>T</strong>. <br>
Dans notre cas, il y a 4 états possibles soit:</p>
<p>$$E = {A,C,G,T}$$ </p>
<p>Et 16 probabilités de transition, noté $p(N_{t+1}|N)$ , que l'on représente par une <a href="https://fr.wikipedia.org/wiki/Matrice_(math%C3%A9matiques)#Alg%C3%A8bre_des_matrices_carr%C3%A9es">matrice</a> carrée avec dans l'ordre A,C,G,T pour les lignes et les colonnes. Par exemple la transition <em>p(A|A)</em> (A précédé de A) se lis dans la matrice aux coordonnées (0,0). La transition p(A|C) ( A précédé de C), aux coordonnées (0,1) .</p>
<p>$$
T = \begin{bmatrix}
1/4 & 1/4 & 1/4 & 1/4 \
1/4 & 1/4 & 1/4 & 1/4\
1/4 & 1/4 & 1/4 & 1/4\
1/4 & 1/4 & 1/4 & 1/4 \
\end{bmatrix}
$$</p>
<p>En changeant les probabilités de transition, nous pouvons alors paramétrer notre générateur pour qu'il produise des séquences avec des profils particuliers. Dans la figure suivante, j'ai donné une probabilité de 0.7 aux transitions p(G|C) et p(C|G). Avec cette nouvelle table de transition, je peux alors générer des séquences riches en GC comme l'illustre l'animation suivante.</p>
<div class="figure"> <img src="../images/markov/animation2.gif" /> <div class="legend"> Les probabilités de transitons ont changé en faveur de G->C et C->G. <br/> La séquence générée est riche en GC </div> </div>
<h2>Distribution stationnaire</h2>
<p>En faisant tourner votre générateur assez longtemps et en comptant la fréquence d'apparition de chaque base, vous obtiendrez une <a href="https://fr.wikipedia.org/wiki/Distribution_statistique">distribution</a> <a href="https://fr.wikipedia.org/wiki/Probabilit%C3%A9_stationnaire_d%27une_cha%C3%AEne_de_Markov">stationnaire</a> au bout d'un certain temps. C'est-à-dire que peut importe la longueur de la séquence, la probabilité d'avoir une certaine base dans la séquence sera toujours la même.
Les histogrammes ci-dessous montrent la fréquence des bases obtenues parmi les N premiers nucléotides générées par une chaîne de Markov en utilisant la matrice de transition du dé à 4 faces équiprobables. Comme on peut s'y attendre, cette distribution converge pour devenir uniforme. </p>
<div class="figure"> <img src="../images/markov/distribution1.png" /> <div class="legend"> Distributions des bases sur un génération de N bases. <br/> La distribution converge pour devenir uniforme</div> </div>
<p>Ces distributions se calculent en faisant un peu d'algèbre linéaire.
On choisi de représenter la distribution des 4 bases par un vecteur $\pi_{t} = [pA, pC, pG, pT]$ à un temps donné t . Par exemple, si nous choisissons une séquence commençant par un A, alors la distribution au temps $t0$ est = [1,0,0,0].
On peut alors calculer la distribution au temps t+1 en faisant le <a href="https://fr.wikipedia.org/wiki/Produit_vectoriel">produit</a> du vecteur par la matrice de transition T: </p>
<p>$$
\pi_{t+1} = \pi_{t} T
$$</p>
<p>De façon générale, on peut calculer la distribution au temps n par :</p>
<p>$$
\pi_{n} = \pi_{0}T^n
$$</p>
<p>Trouver la distribution stationnaire, c'est chercher celle qui ne change pas entre deux temps. C'est-à-dire résoudre l'équation suivante :</p>
<p>$$
\pi = \pi T
$$</p>
<p>Sachant cela, vous allez pouvoir construire des chaînes de Markov avec la distribution stationnaire de votre choix. <br>
De façon beaucoup plus générale, utiliser les chaînes de Markov comme générateurs aléatoires d'une distribution particulière est à la base des <a href="https://fr.wikipedia.org/wiki/M%C3%A9thode_de_Monte-Carlo_par_cha%C3%AEnes_de_Markov">algorithmes MCMC</a>. Principalement en <a href="https://fr.wikipedia.org/wiki/Inf%C3%A9rence_bay%C3%A9sienne">inférence bayésienne</a> pour calculer une distribution a posteriori. Mais ça, c'est une autre histoire ! </p>
<h2>Un modèle d'apprentissage</h2>
<p>Si maintenant, au lieu de générer des séquences à partir d'une chaîne de Markov nous faisions l'inverse. C'est-à-dire construire une chaîne de Markov après avoir observé une famille de séquence. Par exemple, les séquences de différents <a href="https://fr.wikipedia.org/wiki/Promoteur_(biologie)">promoteurs</a>. Cette chaîne servirait alors de modèle pour représenter cette famille. Pour cela il suffit de comptabiliser toutes les transitions existantes dans un jeu de séquence pour déduire les probabilités de la matrice de transition. <br>
Parmi les séquences suivantes, il y a 5 transitions T->A sur 32 transitions possibles. On note alors dans la matrice de transition que la probabilité p(A|T) est de 5/32. On fait de même pour les autres transitions pour obtenir une matrice complète.</p>
<div class="figure"> <code> <b style="color:red">TA</b>CGC <br/>
CCT<b style="color:red">TA</b> <br/>
GCCGC <br/>
AG<b style="color:red">TA</b>G <br/>
AGCGC <br/>
C<b style="color:red">TA</b><b style="color:red">TA </b><br/>
GTGCA<br/>
CGCCA <br/> </code> <div class="legend">Dans cette série, il y a 32 transitions. Parmi elles, 5 sont des transitions T->A. La probabilité est donc de 5/32</div> </div>
<p>Une fois la chaîne de Markov définie, il est alors possible d'utiliser ses probabilités pour générer une nouvelle séquence semblable à celles utilisées dans la construction du modèle. C'est de cette façon que les générateurs de texte aléatoires fonctionnent. Par exemple, ce site qui génère des <a href="https://filiph.github.io/markov/">Tweets de Donald Trump</a>. <br>
En génétique, on va plutôt tester si une nouvelle séquence a le même profil que les séquences du modèle. Par exemple quelle est la probabilité que la séquence ATTCG soit une séquence du modèle $\theta$ ?
Étant donné que la probabilité d'apparition d'une base dépend uniquement de la précédemment, la probabilité de ATTCG peut s'écrire comme le produit de chaque transition: </p>
<p>$$
p(ATTCG|\theta) = p(A) * p(T|A) * p(T|T) * p(C|T) * p(G|C)
$$</p>
<p>Ou plus généralement : </p>
<p>$$
P(S|\theta) = \prod_{0}^{n} p(S_{n}|S_{n-1})
$$</p>
<p>Et comme les additions c'est mieux que les multiplications, on calcule la vraisemblance via le logarithme: </p>
<p>$$
L_{\theta}(S) = \sum_{0}^{n} log(p(S_{n}|S_{n-1}))
$$</p>
<p>En lisant les probabilités de la table de transition, on peut alors calculer cette vraisemblance pour évaluer le degré d'appartenance d'une séquence à sa famille. Ce genre d'algorithme s'utilise par exemple pour identifier des familles de protéines. L'algorithme <a href="https://en.wikipedia.org/wiki/HMMER">HMMER</a> fonctionne de la même façon, mais en utilisant des chaînes de Markov plus complexe, appelé chaîne de Markov caché que je vais décrire rapidement.</p>
<h2>Les chaînes de Markov cachées</h2>
<p>Une <a href="https://fr.wikipedia.org/wiki/Mod%C3%A8le_de_Markov_cach%C3%A9">chaîne de Markov cachée</a> ou HMM ( Hidden Markov Model) est simplement une chaîne de Markov dont certains des états sont cachés. Plus précisément ce sont des états qui ne font pas partie de la séquence générée. Reprenons notre dé et appelons le <strong>X</strong>. Ajoutons un deuxième dé truqué appelé <strong>Y</strong> contenant uniquement des G sur ces 4 faces. On lance toujours un seul dé pour générer une séquence. Sauf que cette fois, à chaque lancée, il y a une chance sur 2 que nous changions de dé en cachette. On dit que <strong>X</strong> et <strong>Y</strong> sont les états cachés avec 4 probabilités d’émissions chacun. Cette chaîne de Markov peut être représentée par le graphe suivant:</p>
<div class="figure"> <img src="../images/markov/hmm.png" /> <div class="legend">Chaîne de Markov caché avec 2 états cachés X et Y et 4 émissions</div> </div>
<p>Ces 2 états cachés peuvent représenter par exemple les introns et les exons. Les probabilités d’émissions seront différentes selon l'état caché en cours.
Il est peut être plus rare par exemple d'avoir du GC dans un exon que dans un intron.
On utilise également les chaînes de Markov caché pour modéliser les insertions et les délétions. Le graphe ci-dessous vous montre une chaîne de Markov particulière prenant en compte les positions comme états cachés avec leurs 4 émissions possibles A,C,G,T. En lisant de gauche à droite, ce générateur est capable de produire la séquence ACAATC ou ACACCCCCATC grâce à plusieurs insertions en position 3.</p>
<div class="figure"> <img src="../images/markov/hmm2.png" /> <div class="legend">Dans cette chaîne de Markov, les positions sont prises en compte. En position 3, il y a 60% de chance d'avoir une insertion</div> </div>
<p>Comme vu plus haut, il est possible de construire une chaîne de Markov caché en apprenant depuis un corpus de séquence. Mais cette fois, les probabilités de transitions cachées sont beaucoup plus difficiles à calculer, car on ne les observe pas.
On peut les estimer en cherchant les valeurs les plus vraisemblance avec par exemple l'<a href="https://fr.wikipedia.org/wiki/Algorithme_de_Baum-Welch">algorithme de Baum-Welch</a>. Il s'agit d'un algorithme d'espérance maximisation que nous avons déjà vue dans un <a href="expectation-maximisation.html">autre billet</a>. Notez aussi l'algorithme de <a href="https://fr.wikipedia.org/wiki/Algorithme_de_Viterbi">Viterbi</a> qui permet d'identifier le chemin le plus probable, lorsqu'on désire aligner une séquence sur un profil HMM. </p>
<h2>En bref</h2>
<p>Les chaînes de Markov sont des processus stochastiques dont l'état futur dépend uniquement du présent. Elles peuvent être utilisées en génétique pour générer des séquences, mais surtout comme modèle d'apprentissage comme les profils HMM.
Elles sont à la base des algorithmes MCMC faisant partie des plus beaux <a href="https://cs.gmu.edu/~henryh/483/top-10.html">algorithmes du XXe siècle</a>, rien que ça! </p>
<h3>Référence</h3>
<ul>
<li><a href="https://github.com/dridk/notebook/blob/master/markov/Markov.ipynb">Mon notebook pour ce billet</a></li>
<li><a href="http://nazejournal.free.fr/article.php?page=chaines-markov">http://nazejournal.free.fr</a></li>
<li><a href="https://mattiacinelli.com/
hidden-markov-model-applied-to-biological-sequence-part-2/">https://mattiacinelli.com</a></li>
<li><a href="https://bioinfo-fr.net/suivez-le-guide-en-quete-de-hmm">https://bioinfo-fr.net/</a></li>
</ul>Ce que peut révéler un test génétique sur Internet2019-04-08T20:07:20+02:002019-04-08T20:07:20+02:00Sacha Schutztag:dridk.me,2019-04-08:/tests-genetiques.html<p><a href="https://www.myheritage.fr/">MyHeritage</a>, <a href="https://www.23andme.com">23andMe</a>, <a href="https://www.ancestry.fr/">Ancestry</a>… Vous en avez sûrement entendu parler. Bien qu'interdits en France <a href="https://www.legifrance.gouv.fr/affichCodeArticle.do?cidTexte=LEGITEXT000006070721&idArticle=LEGIARTI000006419305&dateTexte=&categorieLien=cid">(article 16-10)</a>, ces tests génétiques en libre accès bénéficient pourtant d'une bonne publicité.
Depuis peu, elle se fait par l'intermédiaire de YouTube. <a href="https://www.youtube.com/watch?v=by168cgLmw0">Amixem</a>, <a href="https://www.youtube.com/watch?v=xrkmdXyOaHg">Squeezie</a> et plus récemment <a href="https://www.youtube.com/watch?v=rEY-smTTLto">Dr Nozman</a> ont fait ces tests, puis ont partagé leurs …</p><p><a href="https://www.myheritage.fr/">MyHeritage</a>, <a href="https://www.23andme.com">23andMe</a>, <a href="https://www.ancestry.fr/">Ancestry</a>… Vous en avez sûrement entendu parler. Bien qu'interdits en France <a href="https://www.legifrance.gouv.fr/affichCodeArticle.do?cidTexte=LEGITEXT000006070721&idArticle=LEGIARTI000006419305&dateTexte=&categorieLien=cid">(article 16-10)</a>, ces tests génétiques en libre accès bénéficient pourtant d'une bonne publicité.
Depuis peu, elle se fait par l'intermédiaire de YouTube. <a href="https://www.youtube.com/watch?v=by168cgLmw0">Amixem</a>, <a href="https://www.youtube.com/watch?v=xrkmdXyOaHg">Squeezie</a> et plus récemment <a href="https://www.youtube.com/watch?v=rEY-smTTLto">Dr Nozman</a> ont fait ces tests, puis ont partagé leurs résultats en vidéo. Devant cet engouement, j'ai voulu savoir quelles informations étaient rendues à l'utilisateur et si des diagnostics médicaux pouvait être établis d'après les résultats. </p>
<div class="figure"> <img src="../images/test_genetique/23andme.png" /> <div class="legend">Promotion 23andMe pour la fête des pères. « Des liens qui unissent vraiment. »</div> </div>
<h2>La génétique à deux vitesses</h2>
<p>Avant tout, j'aimerais vous montrer le paradoxe de ces tests génétiques, qu'ils soient réalisés dans un cadre médical ou directement sur Internet.
En médecine, ces tests sont très probablement les analyses les plus contrôlées de toutes les analyses de <a href="https://fr.wikipedia.org/wiki/Biologie_m%C3%A9dicale">biologie médicale</a>. Ils sont sous l'égide de l'<a href="https://fr.wikipedia.org/wiki/Agence_de_la_biom%C3%A9decine">Agence de la biomédecine</a> et sont prescrits uniquement par des <a href="https://fr.wikipedia.org/wiki/G%C3%A9n%C3%A9tique_m%C3%A9dicale">médecins généticiens</a> ou par des médecins non généticiens, mais travaillant en relation avec une équipe de génétique clinique. Un consentement (<a href="http://robertdebre.aphp.fr/wp-content/blogs.dir/137/files/2013/08/Consentement_genetique-2.pdf">exemple</a>) est obligatoirement demandé aux patients. En oncogénétique, les analyses sont souvent réalisées deux fois pour éviter une erreur sur l'identité. Pour signer des résultats, même après mon doctorat de médecine, j'ai dû attendre d'avoir <a href="https://www.agence-biomedecine.fr/agrement-praticiens-genetique?lang=fr">les agréments</a> de l'Agence de la biomédecine…
Et en même temps, il n'a jamais été aussi facile de faire un test génétique sur Internet. Le fait de ne pas avoir besoin de faire une prise de sang les rend même plus faciles et plus accessibles qu'un examen classique de <a href="https://fr.wikipedia.org/wiki/Biochimie_clinique">biochimie</a> ou d'<a href="https://fr.wikipedia.org/wiki/H%C3%A9matologie">hématologie</a>. On clique sur un bouton, on reçoit un kit salivaire par la poste et le tour est joué. <br>
Mais alors, pourquoi un tel contrôle en médecine ?
D'abord, à cause du caractère de la génétique à pouvoir prédire des maladies chez des personnes en bonne santé. Contrairement à un examen classique qui teste des patients malades, les examens de génétique concernent souvent des individus sains. C'est une médecine aussi bien de diagnostic (identifier une maladie chez un patient) que de prédiction (identifier une maladie susceptible de se déclarer). Par exemple, retirer les seins d'une femme en bonne santé parce qu'elle est porteuse d'une mutation prédisposant au cancer reste une décision délicate à prendre. <br>
Ensuite, il y a l'hérédité. Vos gènes ne vous appartiennent pas, vous les partagez avec votre famille. Faire votre propre diagnostic implique aussi de le faire chez les membres de votre famille. Et donc si vous réalisez ce type de test génétique, les résultats peuvent vous déclarer porteur d'une mutation, et indirectement suggérer que vos parents, vos frères, vos sœurs, vos enfants partagent également cette mutation. Cela n'impliquera donc pas que vous.</p>
<h2>Un test de généalogie qui en dit plus ?</h2>
<p>La plupart de ces tests sont vendus comme une analyse sur vos origines ethniques. La société MyHeritage utilise pour cela une <a href="https://fr.wikipedia.org/wiki/Puce_%C3%A0_ADN">puce à ADN</a> permettant d'identifier environ <a href="https://www.illumina.com/products/by-type/microarray-kits/infinium-omni-express.html">700 000</a> variations génétiques appelées SNV (Single Nucleotide Variant) absentes ou présentes de votre génome, qu'elle compare à des populations de référence. Une des méthodes est d'identifier des groupes de SNV (<a href="https://fr.wikipedia.org/wiki/Haplogroupe">haplogroupes</a>) permettant d'associer un individu à sa population d'origine.
Mais alors, qu'est-ce que ces SNV et que peuvent-ils dire de plus ? </p>
<h3>Single Nucleotide Variant (SNV)</h3>
<p>Un génome humain est constitué de 3 milliards de bases, représentées par les lettres A, C, G et T. Elles sont réparties sur 46 chromosomes différents (22 paires de chromosomes de 1 à 21 + 1 paire XX ou XY selon que vous êtes une femme ou un homme, respectivement). Chacune de vos cellules est constituée de 2 versions de ce génome, héritées de votre mère et de votre père.
Un SNV est une modification d'une lettre d'un génome (le vôtre par exemple) par rapport à un génome de référence (séquence d'ADN assemblée par les scientifiques, représentative d'une espèce — ici l'humain – réalisée à partir de plusieurs personnes). Si par exemple, à la position 101594229 du chromosome 9 on vous identifie un A, mais sur le génome de référence il y a un G, alors vous avez un SNV qui peut s'écrire : <a href="http://genome.ucsc.edu/cgi-bin/hgTracks?db=hg19&lastVirtModeType=default&lastVirtModeExtraState=&virtModeType=default&virtMode=0&nonVirtPosition=&position=chr9%3A101594229%2D101594229&hgsid=718306327_QCaQikXTcs5svbD4i9HYmPnkk40x">chr9:101594229G>A</a>. Une partie de ces variations observées sont référencées dans des bases de données de variations génétiques, comme la base de données <a href="https://en.wikipedia.org/wiki/DbSNP">dbSNP</a> qui attribue à des SNV fréquents un identifiant unique (<a href="https://www.ncbi.nlm.nih.gov/snp/rs145236923">rs145236923</a>). <br>
Quant au <a href="https://fr.wikipedia.org/wiki/G%C3%A9notype">génotype</a> d'un SNV, il indique si vous portez la variation sur un seul ou sur les deux chromosomes hérités de vos parents. Pour une variation donnée, il y a trois génotypes possibles : <a href="https://fr.wikipedia.org/wiki/Homozygote">homozygote</a> sauvage, <a href="https://fr.wikipedia.org/wiki/H%C3%A9t%C3%A9rozygote">hétérozygote</a> (sauvage et muté) et homozygote muté.</p>
<ul>
<li>GG : vous n'êtes pas porteur du SNV (sur aucun chromosome), vous êtes homozygote sauvage ;</li>
<li>AG : vous portez le SNV à l'état hétérozygote (sur un seul chromosome) ;</li>
<li>AA : vous portez le SNV à l'état homozygote (sur deux chromosomes), vous êtes homozygote muté.</li>
</ul>
<div class="figure"> <img src="../images/test_genetique/genotype.png" /> <div class="legend">Source : <a href="https://en.wikipedia.org/wiki/Zygosity">Wikipedia, Zygosity</a></div> </div>
<p><a href="https://fr.wikipedia.org/wiki/Puce_%C3%A0_ADN">Les puces à ADN</a> permettent d'identifier les génotypes de milliers de SNV préalablement choisis. Le fichier de résultat brut fourni par MyHeritage donne l'identifiant du SNV, sa localisation (chromosome, position) et le génotype pour le p̶a̶t̶i̶e̶n̶t̶ client :</p>
<div class="highlight"><pre><span></span><code># Exemple de fichier brut
rs28678693 1 838665 CC
rs4475691 1 846808 CT
rs72631889 1 851390 TT
</code></pre></div>
<h3>Comment interpréter ces SNV ?</h3>
<p>Sur les 3 milliards de bases du génome, il y a chez un individu environs 1 SNV toutes les 1000 bases qui le distingue d'un autre individu. La majorité d'entre elles sont bénignes, mais certains peuvent être pathogènes.
En génétique médicale, on classe ces variations en 5 classes différentes :</p>
<ul>
<li>Classe 1 : variation bénigne (<em>benign</em>)</li>
<li>Classe 2 : variation probablement bénigne (<em>likely benign</em>)</li>
<li>Classe 3 : variation de signification indéterminée (<em>unknown significance</em>)</li>
<li>Classe 4 : variation probablement pathogène (<em>likely pathogenic</em>)</li>
<li>Classe 5 : variation pathogène (<em>pathogenic</em>)</li>
</ul>
<p>Cette classification se fait à l'aide d'arguments scientifiques plus ou moins forts, résumés dans ce qu'on appelle les recommandations de l'<a href="https://www.acmg.net/docs/standards_guidelines_for_the_interpretation_of_sequence_variants.pdf">ACMG</a>. Par exemple, on peut se poser certaines questions.</p>
<ul>
<li>La variation est-elle déjà décrite dans la littérature (déjà connue) ?</li>
<li>La variation est-elle rare ou fréquente dans la population (beaucoup d'autres personnes l'ont aussi) ?</li>
<li>Est-elle située dans un gène ou non (située dans les régions codantes du génome) ?</li>
<li>Si oui, impacte-t'elle la protéine codée par ce gène ? </li>
<li>Entraîne-t-elle l'apparition d'un codon stop dans la séquence protéique (protéine tronquée par exemple) ?</li>
<li>…</li>
</ul>
<p>Être porteur d'une variation classée pathogène ne suffit pas pour prédire ou diagnostiquer une maladie. Par exemple, dans le cas des <a href="https://fr.wikipedia.org/wiki/Transmission_autosomique_r%C3%A9cessive">maladies récessives</a> (<a href="https://fr.wikipedia.org/wiki/Mucoviscidose">mucoviscidose</a>, <a href="https://fr.wikipedia.org/wiki/Dr%C3%A9panocytose">drépnaocytose</a>…), il faut que les deux copies du gène soient touchées pour être malade. Dans le cas des maladies à <a href="https://fr.wikipedia.org/wiki/P%C3%A9n%C3%A9trance">pénétrance</a> incomplète (<a href="https://fr.wikipedia.org/wiki/H%C3%A9mochromatose">hémochromatose</a>), vous pouvez être porteur de la mutation sans présenter un seul signe de la maladie.</p>
<h2>Y a-t-il des variations pathogènes dans ces tests ?</h2>
<p>Pour répondre à cette question, j'ai récupéré depuis la base de données <a href="https://www.ncbi.nlm.nih.gov/clinvar/">ClinVar</a> les variations pathogènes connues de classe 5 et j'ai fait l'intersection avec les 700 000 SNV de la puce <a href="https://www.illumina.com/products/by-type/microarray-kits/infinium-omni-express.html">illumina OmniExpress 24</a> utilisée par MyHeritage. Un notebook Python est <a href="https://github.com/dridk/notebook/blob/master/myheritage/myheritage.ipynb">disponible ici</a>.
Il en ressort une centaine de SNV classés pathogènes :</p>
<script type="text/javascript" language="javascript" src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script type="text/javascript" language="javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<p><link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css"></p>
<table id="example" class="display" style="width:100%">
<thead>
<tr>
<th>Pathologie</th>
<th>rsid</th>
</tr>
</thead>
</table>
<script>
$(document).ready(function() {
$('#example').DataTable( {
"ajax": "https://raw.githubusercontent.com/dridk/notebook/master/myheritage/clinvar_omniexpress24.json"
} );
} );
</script>
<p>Parmi ces maladies génétiques, je me contenterai de commenter deux d'entre elles.</p>
<h3>La mucoviscidose</h3>
<p>22 SNV présents sont identifiés sur cette puce comme pathogènes pour la mucoviscidose. Il s'agit d'une <a href="https://fr.wikipedia.org/wiki/Transmission_autosomique_r%C3%A9cessive">maladie récessive</a> très fréquente impliquant le gène <a href="https://fr.wikipedia.org/wiki/G%C3%A8ne_et_prot%C3%A9ine_CFTR"><em>CFTR</em></a> situé sur le chromosome 7. Cela signifie que les deux copies du gène doivent êtres touchées pour entraîner la maladie. Une personne hétérozygote est porteuse saine et a un risque d'1 sur 2 de transmettre la variation à son enfant.
On trouve dans la liste la variation <a href="https://www.snpedia.com/index.php/Rs75961395">rs75961395 ou VG07S29458</a>, correspondant à la mutation <a href="https://cftr.iurc.montp.inserm.fr/cgi-bin/affiche.cgi?variant=c.254G%3EA&provenance=0">c.254G>A Gly85Glu</a> décrite dans la base de donnée <a href="https://cftr.iurc.montp.inserm.fr/cgi-bin/home.cgi?">CFTR-France</a>.
Elle fait partie des 30 mutations les plus fréquentes que l'on recherche systématiquement en routine (lors du diagnostic). Mais elle représente moins de 1 % des mutations chez les patients, loin derrière la mutation <a href="https://fr.wikipedia.org/wiki/%CE%94F508">DF508</a>, la plus connue et la plus fréquente.</p>
<div class="figure"> <img src="../images/test_genetique/cftr_pie.png" /> <div class="legend">La G85E represence 0,6 % des causes de mucoviscidoses. <br/>Source: Cystic Fibrosis Foundation Patient Registry 2014.</div> </div>
<h3>Prédisposition au cancer</h3>
<p>S’il y a bien des tests génétiques extrêmement contrôlés, ce sont les tests d'oncogénétique indiquant la prédisposition au cancer avec une forte pénétrance. En étant porteur de ce type de variation pathogène, il y a une forte probabilité de développer un cancer. La liste de ces gènes est détaillée sur la <a href="https://www.e-cancer.fr/Professionnels-de-sante/L-organisation-de-l-offre-de-soins/Oncogenetique-et-plateformes-de-genetique-moleculaire/Les-predispositions-genetiques">page de l'INCa</a> que je vous conseille de lire. <br>
On y trouve le <a href="https://www.orpha.net/consor/cgi-bin/OC_Exp.php?Lng=FR&Expert=145">syndrome héréditaire de prédisposition au cancer du sein et de l'ovaire</a>, <a href="https://fr.wikipedia.org/wiki/Angelina_Jolie#Cancer">médiatisé par l'actrice Angelina Jolie</a>, probablement porteuse d'une mutation dans le gène <em>BRCA1</em> et qui a eu recours à la chirurgie prophylactique.
Sur la puce, j'ai trouvé la variation <a href="https://www.ncbi.nlm.nih.gov/projects/SNP/snp_ref.cgi?rs=rs28897743">rs28897743 ou i5009343</a> située sur le gène <em>BRCA2</em>. Cette variation est identifiée comme probablement pathogène. Je n'ai pas trouvé de papier sur cette mutation. Il y a également d'autres variations dans les exons mais non classées. <br>
Pour les hommes, il y a aussi la variation <a href="https://www.snpedia.com/index.php/Rs721048">rs721048</a>, associée au cancer de la prostate qui, d'après <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4500625/">ce papier</a>, est fortement impliquée.</p>
<h2>En conclusion</h2>
<p>Parmi ces 700 000 SNV testés, très peu sont répertoriés dans ClinVar comme étant pathogènes. Pour certains syndromes à transmission dominante, vous seriez déjà au courrant si vous étiez atteint. Cependant, gardez en tête que les bases de données génétiques sont très loin d'être exhaustives. Chaque jour, de nouvelles variations sont découvertes comme pouvant être impliquées dans une maladie. C'est d'ailleurs pour cela que ces puces sont très utiles à la recherche. Vous n'êtes donc pas à l'abri que, dans 10 ans, ces données révèlent une information importante sur votre santé.
Je pense en particulier au <a href="https://en.wikipedia.org/wiki/Polygenic_score">score de risque polygénique</a> associant la présence de plusieurs SNV à une maladie. On trouve déjà sur Internet ce genre de test pour la maladie d'Alzheimer par exemple. Bref, tous ces tests sont, à mon sens, éthiquement borderline. Surtout quand de la publicité est faite sur YouTube sachant que sa dirigeante <a href="https://fr.wikipedia.org/wiki/Susan_Wojcicki">Susan Wojcicki</a> est la sœur de <a href="https://fr.wikipedia.org/wiki/Anne_Wojcicki">Anne Wojcicki</a>, elle-même dirigeante de… 23andMe. <br>
Je vous conseille donc de réfléchir à deux fois avant de faire ce genre de test, de bien lire le consentement et de le faire de façon anonyme. Il faut par ailleurs garder en tête qu'il n'y a pas plus identifiant que notre propre génome et que cet anonymat est relatif. Je n'en ai pas parlé, mais vous n'êtes pas l'abri que ces données arriveront un jour entre de mauvaises mains. L'argument <em>c'est ultra sécurisé</em> on l'a déjà entendu avec tous les services web qui se sont ensuite fait pirater. <br>
Je tiens enfin à recommander à toutes celles et ceux qui ont réalisé le test d'éviter de s'essayer à l'autodiagnostic. Si vous avez la moindre inquiétude quant à vos résultats, consultez un médecin généticien en demandant à votre médecin généraliste. </p>
<h2>Références</h2>
<ul>
<li><a href="https://www.has-sante.fr/portail/upload/docs/application/pdf/2013-02/regles_de_bonne_pratique_en_genetique_constitutionnelle_a_des_fins_medicales.pdf">Règles de bonne pratique génétique</a></li>
<li><a href="https://www.acmg.net/ACMG/Medical-Genetics-Practice-Resources/Practice-Guidelines.aspx">ACMG</a></li>
<li><a href="https://etatsgenerauxdelabioethique.fr/">États généraux de bioéthique</a></li>
<li><a href="https://www.e-cancer.fr/Professionnels-de-sante/L-organisation-de-l-offre-de-soins/Oncogenetique-et-plateformes-de-genetique-moleculaire/Les-predispositions-genetiques">Prédisposition oncogénétique - INCa</a></li>
</ul>
<h2>Merci pour la relecture</h2>
<ul>
<li>Charlotte Andrieu </li>
<li>@Oodnadatta</li>
</ul>L'entropie et la théorie de l'information2019-02-08T22:24:08+01:002019-02-09T11:56:40+01:00Sacha Schutztag:dridk.me,2019-02-08:/shannon-entropy.html<p>L'entropie, et plus généralement la théorie de l'information, est un concept essentiel en informatique. Publié par <a href="https://fr.wikipedia.org/wiki/Claude_Shannon">Claude Shannon</a> en 1948 dans "<a href="http://math.harvard.edu/~ctm/home/text/others/shannon/entropy/entropy.pdf">A mathematical theory of communication</a>", cette théorie a permis l'essor des communications modernes en passant par la téléphonie jusqu'aux transmissions des données massives par internet. On trouve également cette …</p><p>L'entropie, et plus généralement la théorie de l'information, est un concept essentiel en informatique. Publié par <a href="https://fr.wikipedia.org/wiki/Claude_Shannon">Claude Shannon</a> en 1948 dans "<a href="http://math.harvard.edu/~ctm/home/text/others/shannon/entropy/entropy.pdf">A mathematical theory of communication</a>", cette théorie a permis l'essor des communications modernes en passant par la téléphonie jusqu'aux transmissions des données massives par internet. On trouve également cette théorie dans <a href="https://fr.wikipedia.org/wiki/Compression_de_donn%C3%A9es">les algorithmes de compression</a>, les statistiques ou encore en <a href="https://fr.wikipedia.org/wiki/Intelligence_artificielle">intelligence artificielle</a>. Sans oublier bien-sûr la bio-informatique avec l'analyse de notre support d'information préféré : l'ADN.
Ce billet a pour objectif de vous faire comprendre ce qu'est l'entropie au sens de Shannon.</p>
<h2>Une mesure de l'incertitude</h2>
<p>L'entropie peut être vue comme une mesure de l'incertitude d'un événement en fonction de la connaissance que nous avons. Par exemple depuis que je suis petit, le soleil se lève tous les jours. Je suis donc certain qu'il se lèvera demain. En revanche, il est incertain que je croise aujourd'hui un chat noir dans la rue. Cela m'est déjà arrivé plusieurs fois, mais rien ne garantit que cela arrive aujourd'hui. Pour lever cette incertitude, je dois récupérer une certaine quantité d'<strong>information</strong>...</p>
<div class="figure"> <img src="../images/entropy/draw.png" /> <div class="legend"> Vous ne pouvez recevoir qu'une réponse par oui ou par non. Utiliser votre carnet pour poser le minimum de question </div> </div>
<p>L'entropie est une valeur qui quantifie cette incertitude.
Pour comprendre, faisons une expérience de pensée: <br>
Imaginez que vous êtes sur la plage d'une île déserte avec un téléphone qui vous permet de contacter le gardien d'un phare en face de vous. Tous les matins depuis un 1 mois, vous lui demandez la prévision météo du jour que vous notez précieusement dans un carnet.
Un jour, le micro du gardien casse et impossible pour lui de vous répondre vocalement. Cependant il peut toujours vous entendre. Il choisit alors de répondre à vos questions par oui ou par non en utilisant le signal lumineux de son phare. Lumière verte pour Oui, lumière rouge pour non.
Combien de questions au minimum allez-vous poser au gardien du phare pour lever l'incertitude sur la météo du jour ? </p>
<h3>Cas n°1</h3>
<p>En regardant votre carnet, vous constatez qu'il y a eu de la pluie 50% du temps et du soleil 50% du temps. </p>
<p><center>
<img src="../images/entropy/bar_plot_1.png" />
</center></p>
<p>Il y a donc 1 chance sur 2 pour qu'il pleuve aujourd'hui. Pour connaître la réponse, vous appelez le phare et lui posez une seule et unique question: </p>
<p><center>
<em>Est ce qu'il va pleuvoir aujourd'hui ?</em>
</center></p>
<p>Il vous répond <strong>oui</strong> ou <strong>non</strong> en utilisant <strong>1</strong> seul signal lumineux.
Plus précisément, le phare vous a envoyé <strong>1</strong> <a href="https://fr.wikipedia.org/wiki/Bit">bit</a> de donnée et cela a suffi à lever votre incertitude. Autrement dit, votre incertitude de 1 chance sur 2 a été divisée par 2. </p>
<h3>Cas n°2</h3>
<p>Imaginez cette fois avoir noté dans votre carnet : Pluie : 100% du temps , Soleil : 0%, Orage : 0% , Neige : 0%. </p>
<p><center>
<img src="../images/entropy/bar_plot_4.png" />
</center></p>
<p>Dans ce cas, vous ne poserez aucune question au phare. Vous êtes certain qu'il va pleuvoir. Le phare vous transmet donc 0 bit d'information. L'incertitude est nulle.</p>
<h3>Cas n°3</h3>
<p>Cette fois vous avez 4 prévisions différentes notées dans votre carnet. Pluie 25% du temps, Soleil 25% du temps, Neige 25% du temps, Orage 25% du temps. C'est-à-dire 1 chance sur 4 pour chaque prévision.</p>
<p><center>
<img src="../images/entropy/bar_plot_2.png" />
</center></p>
<p>En réflechissant, vous trouverez qu'il faut suivre un arbre décisionnel en posant 2 questions au minimum pour lever votre incertitude.</p>
<p><center>
<img src="../images/entropy/decision.png" />
</center></p>
<p>Le phare vous envoie par exemple 2 signaux rouges ( non et non ). Vous en concluez qu'il y aura un orage aujourd'hui.
Vous avez donc reçu 2 bits d'information ce qui divise votre incertitude par 4. <br>
Une autre façon de faire est de demander au gardien <em>quel temps fera-t-il aujourd'hui</em> et de lire sa réponse en fonction du code suivant:</p>
<div class="highlight"><pre><span></span><code>vert-vert (11) = pluie
vert-rouge (10) = neige
rouge-vert (01) = soleil
rouge-rouge (00) = orage
</code></pre></div>
<p>Ce code est défini sur 2 bits pour représenter uniquement les N=4 prévisions possibles.
De façon générale, le nombre de bits nécessaire pour représenter N prévisions se calcule comme suite. Gardez cette formule en tête pour la suite.</p>
<p><center>
$$2^{bits} = N$$
<em>Soit</em>
$$bits = log_2(N) $$
<em>Ou encore</em>
$$bits = -log_2(1/N) $$
<em>Dans notre cas</em>
$$bits = -log_2(1/4) = 2 $$</p>
<p></center></p>
<h3>Cas n°4</h3>
<p>Imaginez maintenant que les prévisions de votre carnet ne soient pas équiprobables. <br>
50% de pluie, 25% de soleil, 12.5% neige et 12.5% orage.</p>
<p><center>
<img src="../images/entropy/bar_plot_3.png" />
</center></p>
<p>Pour économiser l'énergie du phare à long terme, il vous faut poser vos questions de façon stratégique. En effet, si vous lui posez comme question "Va-t-il pleuvoir aujourd'hui?", il y a 1 chance sur 2 qu'il réponde par <strong>oui</strong>. Et vous n'aurez plus à lui poser d'autre question. Super économique. En revanche, si il répond <strong>non</strong>, il faudra peut-être poser 2 questions supplémentaires, soit 3 questions en tout pour lever l'incertitude. Ce qui est plus que nos 2 bits vu précédemment.
Mais en raisonnant sur plusieurs jours, l'économie est évidente. Dans 50% des cas il faudra poser 1 question, dans 25% des cas 2 questions et 3 questions dans le dernier quart.
Donc en moyenne, l'arbre décisionnel suivant est le plus économique sur le temps: </p>
<p><center>
<img src="../images/entropy/decision2.png" />
</center></p>
<p>Le code suivant peut être alors utilisé par le phare pour vous transmettre la météo de façon optimale:</p>
<div class="highlight"><pre><span></span><code>vert (1) = pluie
rouge-vert (10) = soleil
rouge-rouge-vert (001) = neige
rouge-rouge-rouge (000) = orange
</code></pre></div>
<p>Vous utiliserez 1 bits dans 50% des cas, 2 bits dans 25% des cas, 3 bits dans 25% (12.5% * 2) des cas. Ce qui donne en moyenne 1.75 bits (1x0.5 + 2x0.25 + 3x0.125 + 3x0.125) .
Cette valeur que nous venons de calculer, c'est <strong>l'entropie de Shannon</strong> notée <em>H</em>. <br>
Son équation s'écrit comme ceci avec $p_i$ la probabilité de l'événement i pour la distribution P.</p>
<p><center>
$$H(P) = -\sum_i p_i \log_2(p_i)$$
</center></p>
<p>Si vous appliquez cette formule sur les 4 distributions des cas vus précédements, vous devriez retrouver le nombre de question à poser (1 bits, 0 bits, 2 bits et 1.75 bits).
L'entropie est donc une mesure de l'incertitude calculée en bits. C'est la plus petite quantité d'information nécessaire pour lever votre incertitude. On ne pourra jamais faire moins, c'est la théorie qui le dit! Elle est d'autant plus grande que l'incertitude est grande. Plus exactement, l'entropie est maximale lorsque tous les événements possibles inscrits dans votre carnet ( pluie, neige ...) sont équiprobables. <br>
L'entropie est ainsi une mesure permettant de caractériser <a href="https://fr.wikipedia.org/wiki/Distribution_statistique">une distribution statistique</a>.</p>
<h2>Entropie croisée et divergence de Kullback-Leibler</h2>
<p>L'<a href="https://fr.wikipedia.org/wiki/Entropie_crois%C3%A9e">entropie croisée </a>(cross entropy) permet de quantifier la dissimilarité entre deux distributions en comparant leurs entropies. Par exemple pour comparer une distribution observée P à une distribution théorique Q.
En reprenant l'exemple précédant, imaginez que vous êtes sur une îles P avec un carnet P mais que vous posez vos questions au phare de l'îles Q qui avait donné d'autre prédictions inscrites sur le carnet Q. Combien de question supplémentaire allez vous poser au phare Q avec votre carnet P ? <br>
Ce nombre s'obtient en calculant la <a href="https://fr.wikipedia.org/wiki/Divergence_de_Kullback-Leibler">divergence de Kullback-Leibler</a> (ou divergence K-L ou entropie relative):</p>
<p><center>
$$D_{KL}(P||Q) = -\sum_i p_i \log_2(p_i / q_i)$$
</center></p>
<p>Lorsque les deux distributions sont identiques, alors la divergence est de 0. Vous pouvez aussi calculer ce qu'on appelle l'entropie croisé ( ou cross entropy) qui se calcule de cette façon:</p>
<p><center>
$$H(P,Q) = H(p) + D_{KL}(P||Q) $$
<em> ce qui revient à </em>
$$H(P,Q) = -\sum_i p_i \log_2(q_i)$$
</center></p>
<p>L'entropie croisée est très utilisée en intelligence artificielle, dans les méthodes de <a href="https://fr.wikipedia.org/wiki/Classement_automatique">classifications suppervisées</a>. En effet, elle sert de <a href="https://fr.wikipedia.org/wiki/Optimisation_lin%C3%A9aire">fonction objective</a> à minimiser. Par exemple, pendant la phase d'entrainement d'un <a href="https://fr.wikipedia.org/wiki/R%C3%A9seau_de_neurones_artificiels">réseau de neurones artificiels</a>, l'objectif est de minimiser l'entropie croisée afin que la distribution prédite soit le plus proche possible de la distribution réelle observée. </p>
<h2>Conclusion</h2>
<p>L'entropie mesure la quantité d'information minimum nécessaire pour vous transmettre un message. Ce n'est donc pas étonnant qu'on retrouve ce concept dans les algorithmes de compression comme le <a href="https://fr.wikipedia.org/wiki/Codage_de_Huffman">codage de Huffman</a> ou en <a href="https://fr.wikipedia.org/wiki/Cryptographie">cryptographie</a>. <br>
Il y a aussi <a href="https://fr.wikipedia.org/wiki/Principe_d%27entropie_maximale">le principe d'entropie maximale</a> qui consiste à choisir pour des données, le meilleur modèle qui maximise l'entropie. Ou encore la décomposition par minimisation de l'entropie, bien illustré sur <a href="https://media.nature.com/m685/nature-assets/ismej/journal/v9/n4/images/ismej2014195f1.jpg">cette image</a>. J'essaierai de discuter tous ces concepts dans des billets dédiés. <br>
Je n'oublie quand même pas de conclure avec l'ADN, dont la séquence peut être vue comme une suite de 4 événements aléatoires (A,C,G,T) à l'instar de nos prévisions météorologiques. Par exemple, nous pouvons aligner plusieurs séquences d'ADN et calculer la fréquence des 4 nucléotides puis l'entropie sur chaque position. Vous pouvez alors quantifier une certitude (2-entropie) sur la présence d'un nucléotide dans un motif particulier. C'est ce qui est illustré dans le <a href="https://en.wikipedia.org/wiki/Sequence_logo">logo-plot</a> ci-dessous. Regardez la légende sur l'axe des ordonnées qui vous donne une echelle en bits sur la certitude (2 - entropie ) quand à la présence d'un nucléotide dans le motif.</p>
<p><center>
<img src="../images/entropy/logo_plot.png" />
</center></p>
<h3>Référence</h3>
<ul>
<li><a href="https://www.youtube.com/watch?v=ErfnhcEV1O8">Super vidéo d'Aurélien Géron (en)</a></li>
<li><a href="https://www.youtube.com/watch?v=R4OlXb9aTvQ">Une autre super vidéo (en)</a></li>
<li><a href="http://www.yann-ollivier.org/entropie/entropie1">La théorie de l'information: L'origine de l'entropie</a></li>
</ul>
<h3>Merci</h3>
<p><a href="https://github.com/andhena">@andhena</a></p>L'algorithme de Newton-Raphson2018-10-28T12:00:35+01:002018-10-28T12:00:35+01:00Sacha Schutztag:dridk.me,2018-10-28:/newton-raphson.html<p>La méthode de <a href="https://fr.wikipedia.org/wiki/M%C3%A9thode_de_Newton">Newton-Raphson</a> est une méthode algorithmique pour trouver la racine d'une fonction. C'est-à-dire trouver x tel que f(x) = 0. Cette méthode est d'une simplicité déconcertante que je vais détailler dans ce billet de façon géométrique puis algorithmique.</p><p>La méthode de <a href="https://fr.wikipedia.org/wiki/M%C3%A9thode_de_Newton">Newton-Raphson</a> est une méthode algorithmique pour trouver la racine d'une fonction. C'est-à-dire trouver x tel que f(x) = 0. Cette méthode est d'une simplicité déconcertante que je vais détailler dans ce billet de façon géométrique puis algorithmique.</p>
<h2>Trouver la racine d'une fonction cubique</h2>
<p>Prenons une <a href="https://fr.wikipedia.org/wiki/Fonction_cubique">fonction cubique</a>, par exemple $f(x) = x^3 +3$ et traçons la courbe sur un <a href="https://fr.wikipedia.org/wiki/Rep%C3%A8re_affine">repère cartésien</a>.</p>
<div class="figure">
<img src="../images/newton_raphson/cubic.png" />
<div class="legend">La fonction cubique coupe l'axe des abscisses au point rouge. Nous voulons trouver les coordonnées de ce point par une méthode algorithmique</div> </div>
<p>La méthode de Newton-Raphson nous permet de trouver le point x de la courbe tel que f(x) = 0. C'est-à-dire le point de la courbe qui coupe l'axe des abscisses. Bien sûr, nous pourrions simplement résoudre l'équation et trouver x. Mais parfois, les fonctions sont plus complexes et il n'existe aucune solution analytique. La méthode de Newton-Raphson nous permet d'y remédier par un <a href="https://fr.wikipedia.org/wiki/M%C3%A9thode_it%C3%A9rative">algorithme itératif</a> décrit ci-dessous:</p>
<h3>Représentation géométrique</h3>
<p>Choisissons un point au hasard A sur l'axe des abscisses.
Par exemple A=(2.5, 0).</p>
<div class="figure">
<img src="../images/newton_raphson/test0-1.png" />
<div class="legend">Prenons un point au hasard A</div> </div>
<p>Puis trouvons le point A' l'image de A par la fonction cubique. C'est-à-dire le point A'=(2.5, f(2.5)).</p>
<div class="figure">
<img src="../images/newton_raphson/test0-2.png" />
<div class="legend">Le point A' est l'image de A par f</div> </div>
<p>Enfin, traçons la <a href="https://fr.wikipedia.org/wiki/Tangente_(g%C3%A9om%C3%A9trie)">tangente</a> de la courbe au point A'. Cette tangente est une droite qui couple l'axe des abscisses au point B.</p>
<div class="figure">
<img src="../images/newton_raphson/test0-3.png" />
<div class="legend">La tangente de la courbe au point A' coupe l'axe des abscisses au point B</div> </div>
<p>À partir du point B, il suffit de recommencer les mêmes étapes qu'avec le point A. Chercher B', tracer la tangente en B' puis trouver le point C et ainsi de suite... Vous verrez alors rapidement qu'en 7 itérations, les points convergent vers la racine (autour de -1.44) comme illustrée dans l'animation ci-dessous: </p>
<div class="figure">
<img src="../images/newton_raphson/anim.gif" />
<div class="legend">La fonction cubique coupe l'axe des abscisses en point que nous cherchons à trouver par une méthode algorithmique</div> </div>
<h3>Représentation algébrique</h3>
<p>Maintenant que vous visualisez comment trouver la racine d'une fonction en utilisant la méthode de Newton-Raphson, voyons comme la calculer. Quelques notions de math vues au lycée suffiront:</p>
<h4>Équation de la tangente au point A'</h4>
<p><a href="https://fr.wikipedia.org/wiki/Tangente_(g%C3%A9om%C3%A9trie)#Calculs_de_tangente">La tangente en un point</a> d'une fonction f(x) ayant pour dérivée f'(x) est une droite d'équation $y=f'(a)(x-a) + f(a)$ avec «a» les coordonnées de A sur l'axe des abscisses. Dans notre cas, l'équation de la tangente au point A' se calcule comme ceci:</p>
<p><center> <em> Notre fonction cubique a pour équation: </em> </center>
$$f(x) = x^3 + 3$$
<center> <em> Sa derivé est donc: </em> </center>
$$f'(x) = 3x^2$$
<center> <em> La tagente au point A' (a=2.5) a donc pour equation: </em> </center>
$$
y=f'(a)(x-a) + f(a)\
y=3a^2(x-a) + a^3 + 3\
$$
<center> <em> En remplaçant «a» par 2.5: </em> </center>
$$
y=18,75x - 28,25\
$$</p>
<h4>Coordonnée du point B en fonction du point A</h4>
<p>connaissant l'équation, les coordonnées du point B ou la tangente coupe l'axe des abscisses se calcul en résolvant l'équation linéaire $18,75x - 28,25=0$. Soit $x=28,25/18,75≈1,506$. Les coordonnées du point B sont donc (1.506,0). </p>
<p>D'une manière générale, nous pouvons calculer le point B(b,0) en fonction du point A(a,0). En effet, résoudre l'équation linéaire revient à faire:</p>
<p>$$f'(a)(b-a) + f(a) = 0\$$
$$f'(a)(b-a) = -f(a)\$$
$$(b-a) = \frac{-f(a)}{f'(a)}\$$
$$b=a - \frac{f(a)}{f'(a)}$$</p>
<p><center> <em> En résumé, le point $x_{k+1}$ en fonction du point $x_{k}$ s'exprime par la suite: </em> </center>
$$x_{k+1} = x - \frac{f(x)}{f'(x)}\$$</p>
<h3>Représentation algorithmique en python</h3>
<p>En implémentant la méthode de Newton-Raphson en python, cela donne :</p>
<div class="highlight"><pre><span></span><code><span class="c1"># Fonction cubique</span>
<span class="k">def</span> <span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="k">return</span> <span class="n">x</span><span class="o">**</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">3</span>
<span class="c1"># Dérivé de la fonction cubique</span>
<span class="k">def</span> <span class="nf">df</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
<span class="k">return</span> <span class="mi">3</span><span class="o">*</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span>
<span class="n">a</span> <span class="o">=</span> <span class="mf">2.5</span> <span class="c1"># On part d'un point aléatoire</span>
<span class="c1"># On applique la formule sur plusieurs itérations... Disons 10</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">a</span> <span class="o">-</span> <span class="n">f</span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="o">/</span><span class="n">df</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="c1"># 1.5066666666666668</span>
<span class="c1"># 0.5639244350466844</span>
<span class="c1"># -2.7685979807840897</span>
<span class="c1"># -1.9761928373643123</span>
<span class="c1"># -1.5735216658126505</span>
<span class="c1"># -1.4528964881677187</span>
<span class="c1"># -1.4423274010169043</span>
<span class="c1"># -1.4422495745072248</span>
<span class="c1"># -1.4422495703074085</span>
<span class="c1"># -1.4422495703074083</span>
</code></pre></div>
<h3>En résumé</h3>
<ul>
<li>
<p>La méthode de Newton-Raphson permet de trouver rapidement la racine d'une fonction et a beaucoup d'usage en informatique.</p>
</li>
<li>
<p>La méthode de Newton permet de trouver les extrêmes (minimum et maximum) d'une fonction. En effet, trouver le minimum ou le maximum d'une fonction c'est trouver où la dérivée s'annule. Par exemple dans <a href="https://dridk.me/gradient_descendant.html">le billet précédent sur la descente en gradient</a> vous pouvez calculer le minimum de la fonction objective en connaissant sa dérivée et sa dérivée seconde. Vous verrez que pour une régression linéaire il suffit d'une seule itération pour trouver le minimum.</p>
</li>
<li>
<p>La méthode de Newton permet de trouver la solution à f(x)=c où «c» est une constante. Il suffit de trouver une fonction g(x)=f(x)-c de telle sorte que la racine de g résout l'équation qui nous intéresse.</p>
</li>
<li>
<p>S’il y a plusieurs racines, on ne peut pas prédire vers quelle racine l'algorithme va converger.</p>
</li>
<li>
<p>La méthode de Newton marche assez bien sûr des <a href="https://fr.wikipedia.org/wiki/Fonction_monotone">fonctions monotones</a> mais
peut ne pas converger avec d'autre fonction.</p>
</li>
<li>
<p>On ne peut pas garantir la convergence si la fonction n'est pas deux
fois dérivable à dérivée seconde continue.</p>
</li>
<li>
<p>On doit bien partir d'un point. Même si, dans les bonnes conditions,
le choix de ce point n'a pas grande importance, il peut en avoir avec
les fonctions non monotones.</p>
</li>
<li>
<p>Si les conditions sont respectées, cet algorithme est beaucoup plus performant que la <a href="https://fr.wikipedia.org/wiki/M%C3%A9thode_de_dichotomie">dichotomie</a>.</p>
</li>
<li>
<p>La méthode de Newton est utilisée dans <a href="https://fr.wikipedia.org/wiki/Mod%C3%A8le_lin%C3%A9aire_g%C3%A9n%C3%A9ralis%C3%A9">les modèles linéaires généralisés (MLG)</a></p>
</li>
<li>
<p>La méthode de Newton a été utilisée pour calculer rapidement l'<a href="https://fr.wikipedia.org/wiki/Racine_carr%C3%A9e_inverse_rapide">inverse d'une racine carrée</a> dans Quake3. </p>
</li>
</ul>
<h1>Référence</h1>
<ul>
<li><a href="https://fr.wikipedia.org/wiki/M%C3%A9thode_de_Newton">Wikipedia</a> </li>
<li><a href="ttps://medium.com/@ruhayel/an-intuitive-and-physical-approach-to-newtons-method-86a0bd812ec3">An intuitive and physical approach to Newton’s method</a></li>
<li><a href="https://github.com/dridk/notebook/blob/master/newton-raphson/">Retrouver mon notebook sur github</a></li>
</ul>
<h1>Remerciements</h1>
<ul>
<li>Metaentropy</li>
<li>O.Dameron</li>
</ul>L'algorithme de descente en gradient2018-10-17T20:43:30+02:002018-10-17T20:43:30+02:00Sacha Schutztag:dridk.me,2018-10-17:/gradient_descendant.html<p>Si vous vous êtes déjà pencher sur l'<a href="https://fr.wikipedia.org/wiki/Intelligence_artificielle">intelligence artificielle</a>, vous avez certainement du entendre parler de la méthode de <a href="https://fr.wikipedia.org/wiki/Algorithme_du_gradient">descente en gradient</a>. Il s'agit d'un algorithme permettant de trouver rapidement le minimum d'une fonction mathématique. Pour faire simple, trouver <em>x</em> tel que <em>f(x)</em> soit le plus petit possible …</p><p>Si vous vous êtes déjà pencher sur l'<a href="https://fr.wikipedia.org/wiki/Intelligence_artificielle">intelligence artificielle</a>, vous avez certainement du entendre parler de la méthode de <a href="https://fr.wikipedia.org/wiki/Algorithme_du_gradient">descente en gradient</a>. Il s'agit d'un algorithme permettant de trouver rapidement le minimum d'une fonction mathématique. Pour faire simple, trouver <em>x</em> tel que <em>f(x)</em> soit le plus petit possible.
Cette méthode est très utilisée en <a href="https://fr.wikipedia.org/wiki/Intelligence_artificielle">IA</a> avec les <a href="https://fr.wikipedia.org/wiki/R%C3%A9seau_de_neurones_artificiels">réseaux de neurones artificiels</a>. Mais avant d'en arriver là, nous allons tenter de comprendre cet algorithme en estimant le paramètre «a» d'une simple régression linéaire d'équation y=ax.</p>
<h2>Une modèle linéaire</h2>
<p>J'ai généré pour ce billet 100 points aléatoires (figure ci-dessous). Disons que ces points représentent la taille en fonction du poids. Nous voulons trouver l'équation de la droite passant au mieux par tous les points. Simple vous me direz ? Effectivement il existe une méthode analytique, c'est-à-dire une formule magique, permettant de trouver directement le paramètre «a» de l'équation <em>y = ax</em>. Il s'agit de la méthode des moindres carrée détaillé <a href="https://fr.khanacademy.org/math/statistics-probability/describing-relationships-quantitative-data/more-on-regression/v/proof-part-1-minimizing-squared-error-to-regression-line">ici</a> pour les plus curieux.<br>
Sauf que pour l'exemple et parce que la majorité des modèles statistiques ne disposent pas de solution analytique, nous allons estimer ce paramètre par une méthode algorithmique: <a href="https://fr.wikipedia.org/wiki/Algorithme_du_gradient">La descente en gradient</a>. </p>
<div class="figure">
<img src="../images/gradient_descendant/observation.png" />
<div class="legend">Taille en fonction du poids pour 100 observations</div> </div>
<h2>Une erreur à minimiser</h2>
<p>La première étape consiste à définir une <a href="https://fr.wikipedia.org/wiki/Fonction_objectif">fonction objectif</a> que l'on cherchera à minimiser. C'est à dire une fonction qui prend en paramètre «a» et qui retourne une erreur. Dans notre cas, l'écart entre les points et la droite de regression sera notre fonction objective. <br>
Cette fonction objective se définit comme étant la moyenne de la somme des écarts au carré entre les valeurs observés (y<sub>i</sub>) et les valeurs calculées par la droite d'équation y=ax. Le tout
Cette fonction s'écrit de la façon suivante:</p>
<ul>
<li>«a», le paramètre à estimer de la droite de régression y=ax</li>
<li>y<sub>i</sub> , la valeur observée au point i </li>
<li>ax<sub>i</sub> la valeur prédite par la droite au point i</li>
<li>n le nombre de points</li>
</ul>
<p>$$
f(a) = \frac{1}{n}\sum_{i=0}^{n}(y_{i}-ax_{i})^{2} \
$$</p>
<p>Traduit en python, cela donne : </p>
<div class="highlight"><pre><span></span><code><span class="n">X</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="o">....</span><span class="p">])</span> <span class="o">//</span> <span class="n">poids</span>
<span class="n">Y</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="o">....</span><span class="p">])</span> <span class="o">//</span> <span class="n">taille</span>
<span class="k">def</span> <span class="nf">error</span><span class="p">(</span><span class="n">a</span><span class="p">):</span>
<span class="n">y_pred</span> <span class="o">=</span> <span class="n">X</span> <span class="o">*</span> <span class="n">a</span>
<span class="n">y_observed</span> <span class="o">=</span> <span class="n">Y</span>
<span class="n">size</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="n">diff</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">((</span><span class="n">y_pred</span> <span class="o">-</span> <span class="n">y_observed</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span><span class="o">/</span><span class="n">size</span>
<span class="k">return</span> <span class="n">diff</span>
</code></pre></div>
<p>De façon naïve, nous pouvons tester toutes les valeurs du paramètre «a» et tracer la fonction objective. Visuellement cela donne une parabole dont le minimum correspond à la meilleur valeur «a».</p>
<div class="figure">
<img src="../images/gradient_descendant/naif.png" />
<div class="legend">Fonction objective: L'erreur en fonction du paramètre «a». L'erreur minimum se situe aux alentours de 3</div> </div>
<p>Dans la vraie vie, on ne va pas pouvoir s'amuser à tester toutes les valeurs des paramètres possibles. Si vous êtes par exemple avec un modèle à 20 paramètres, il y aurait beaucoup, beaucoup trop de combinaison à tester. C'est là qu'intervient la méthode de descente de gradient en faisant varier les paramètres d'un modèle de façon graduelle.</p>
<h2>À petit pas jusqu'à l'arrivée</h2>
<p>La méthode de descente en gradient consiste à prendre une valeur de «a» au hasard et la faire varier plus ou moins fortement par rapport à la pente de la fonction objective. Au lieu de tester toutes les valeurs de «a», vous faites varier sa valeur avec des pas variables qui deviennent de plus en plus petits au fur et à mesure que l'on se rapproche du minimum. <br>
En cherchant dans vos souvenirs du lycée, cette pente c'est la dérivée encore appelé dérivée partielle si vous travaillez sur plusieurs paramètres. Elle se calcule comme suite: </p>
<p>$$f(a) = \frac{1}{n}\sum_{i=0}^{n}(y_{i}-ax_{i})^{2} $$ </p>
<p><center> <em> Se développe en : </em> </center></p>
<p>$$ f(a) = \frac{1}{n}\sum_{i=0}^{n}(y_{i}^{2}-2y_{i}ax_{i} + (ax_{i})^{2} ) $$ </p>
<p><center> <em> Soit </em> </center></p>
<p>$$ f(a) = \frac{1}{n}\sum_{i=0}^{n}(-2y_{i}ax_{i} + a^{2}x_{i}^{2} ) $$ </p>
<p><center> <em> En dérivant par rapport à «a» nous obtenons : </em> </center></p>
<p>$$ f'(a) = \frac{-2}{n}\sum_{i=0}^{n}(x_{i}(y_{i} - ax_{i}) $$ </p>
<p>En reprenant cette équation et en la traduisant en python, nous obtenons: </p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">derror</span><span class="p">(</span><span class="n">a</span><span class="p">):</span>
<span class="n">size</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="k">return</span> <span class="o">-</span><span class="mi">2</span><span class="o">/</span><span class="n">size</span> <span class="o">*</span> <span class="nb">sum</span><span class="p">(</span><span class="n">X</span> <span class="o">*</span> <span class="p">(</span><span class="n">Y</span> <span class="o">-</span> <span class="n">a</span> <span class="o">*</span> <span class="n">X</span><span class="p">))</span>
</code></pre></div>
<p>La figure ci-dessous montre les valeurs des pentes pour différentes valeurs de «a» allant de -10 à 10. Comme vous pouvez le constater, plus nous nous rapprochons du minimum et plus la pente diminue. Elle est négative à gauche et positive à droite. Pour trouver la bonne valeur de «a», il suffit de faire varier «a» proportionnellement à ce gradient. Si la pente diminue, on augmente «a», si elle augmente on diminue «a».</p>
<div class="figure">
<img src="../images/gradient_descendant/derivate.png" />
<div class="legend">différente pente pour différente valeur de a</div> </div>
<p>L'implémentation en python est alors triviale (ci-dessous). En partant de a=-20, je fais une boucle qui incrémente «a» d'une certaine valeur «g» égale au gradient divisé par la variable «taux». Cette variable, appelé taux d'apprentissage, permet d'ajuster la taille du pas. Si le taux d'apprentissage est grand, alors les pas seront plus petits, la précision du résultat sera bonne, mais mettra plus de temps à être atteint. À l'inverse, un taux d'apprentissage petit sera moins précis, mais plus rapide. <br>
Lorsque le minimum est atteint, c'est à dire lorsque le gradient est nul ( ici entre -0.5 et 0.5), je sort de la boucle et je récupère la valeur finale de «a».</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">descent_gradient</span><span class="p">(</span><span class="n">a</span><span class="o">=-</span><span class="mi">20</span><span class="p">,</span> <span class="n">taux</span> <span class="o">=</span> <span class="mi">400000</span><span class="p">):</span>
<span class="n">grad</span> <span class="o">=</span> <span class="mf">100.0</span>
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
<span class="n">grad</span> <span class="o">=</span> <span class="n">derror</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="n">g</span> <span class="o">=</span> <span class="n">grad</span><span class="o">/</span> <span class="n">taux</span>
<span class="k">if</span> <span class="o">-</span><span class="mf">0.5</span> <span class="o"><=</span> <span class="n">grad</span> <span class="o"><=</span> <span class="mf">0.5</span><span class="p">:</span>
<span class="k">return</span> <span class="n">a</span>
<span class="n">a</span> <span class="o">+=</span> <span class="o">-</span><span class="n">g</span>
</code></pre></div>
<p>L'animation ci-dessous illustre cette descente en gradient et montre qu'elle s'équilibre autour de a=3.8. <br>
Nous pouvons alors conclure, grâce à notre algorithme, qule notre modèle linéaire est défini par l'équation: <br>
Taille = Poid * 3.8.</p>
<p><center></p>
<video controls>
<source src="../images/gradient_descendant/gradient.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
<p></center></p>
<h2>Conclusion</h2>
<p>Nous avons vu un exemple de descente en gradient pour évaluer un seul paramètre dans un modèle de régression linéaire. Dans d'autre modèle à plusieurs paramètres comme «a» et «b» de l'équation y = ax + b, la fonction d'erreur est une <a href="https://www.khanacademy.org/math/multivariable-calculus">équation multiparamètrique</a> de la forme f(a,b). Visuellement, il s'agit d'un surface en 3D ou vous allez faire varier les paramètres à l'aide de leurs dérivées partielles pour trouver le minimum. Il s'agit souvent d'un minimum local et différentes solutions existent pour pallier à ce problème (<a href="https://fr.wikipedia.org/wiki/Algorithme_du_gradient_stochastique">Algorithme de gradient stochastique</a>). Un <a href="https://www.youtube.com/watch?v=Q9-vDFvDdfg&t=612s">bonne vidéo Youtube</a> par <a href="https://www.youtube.com/channel/UC0NCbj8CxzeCGIF6sODJ-7A">Science4All</a> explique cette méthode.</p>
<div class="figure">
<img src="../images/gradient_descendant/gradientDescent.jpg" />
<div class="legend">Descent en gradient pour 2 paramètres θ<sub>1</sub> et θ<sub>2</sub>. J(θ<sub>1</sub>,θ<sub>2</sub>) est la fonction objective </div> </div>
<p>Dans les réseaux neuronaux, les modèles sont constitués d'autant de paramètres qu'il y a de neurones. Et pour faire ces descentes de gradient, des libraries comment <a href="https://www.tensorflow.org/api_docs/python/tf/gradients">TensorFlow</a> ou <a href="https://pytorch.org/docs/stable/optim.html">Pytorch</a> ont vu le jour pour optimiser les calculs en les parallisants à l'aide de matrix appelées <a href="https://fr.wikipedia.org/wiki/Tenseur">Tenseur</a>. </p>
<p>En esperant vous avoir éclairé ... ++ </p>
<h2>Référence</h2>
<p>Le notebook contenant l'ensemble du code est disponible <a href="https://github.com/dridk/notebook/tree/master/gradient_descent">ici</a></p>
<ul>
<li><a href="https://www.khanacademy.org/math/multivariable-calculus">Multivariable calculus</a></li>
<li><a href="https://www.youtube.com/watch?v=TEB2z7ZlRAw">Khan Academy</a></li>
<li><a href="https://www.youtube.com/watch?v=nhqo0u1a6fw">Siraj Raval</a></li>
<li><a href="https://www.dunod.com/livres-aurelien-geron">Livre de Aurélien Géron</a></li>
</ul>
<h2>Remerciements</h2>
<p>@Max
@Natir</p>L'énigme du Rusty Lake Hostel2018-09-30T23:52:18+02:002018-09-30T23:52:18+02:00Sacha Schutztag:dridk.me,2018-09-30:/the-rusty-lake-hostel.html<p>Cela fait plusieurs jours que je m'éclate sur un jeu <a href="https://fr.wikipedia.org/wiki/Android">android</a> appelé « <a href="https://store.steampowered.com/app/435120/Rusty_Lake_Hotel/">The rusty lake hostel</a> ». Il s'agit d'une sorte d'escape game en <a href="https://fr.wikipedia.org/wiki/Pointer-et-cliquer">point & click </a> ou vous devez résoudre des énigmes. Parmi celles-ci, il y en a une qui m'a donné du fil à retordre et qui m'a contraint à …</p><p>Cela fait plusieurs jours que je m'éclate sur un jeu <a href="https://fr.wikipedia.org/wiki/Android">android</a> appelé « <a href="https://store.steampowered.com/app/435120/Rusty_Lake_Hotel/">The rusty lake hostel</a> ». Il s'agit d'une sorte d'escape game en <a href="https://fr.wikipedia.org/wiki/Pointer-et-cliquer">point & click </a> ou vous devez résoudre des énigmes. Parmi celles-ci, il y en a une qui m'a donné du fil à retordre et qui m'a contraint à écrire du code pour la résoudre.
Il s'agit d'une énigme composée de 3 bouteilles de volumes différents : la première de <strong>10</strong> litres , la deuxième de <strong>5</strong> litres et la troisième de <strong>6</strong> litres. En début de partie, la première bouteille contient 10 litres d'eau sur les 10, la deuxième 1 litre sur les 5 et la troisième est vide. <br>
Le but du jeu est de réussir à avoir 8 litres dans la première en vidant les bouteilles les unes dans les autres successivement. </p>
<div class="figure"> <img src="../images/rusty_lake/base.jpg" /> <div class="legend">Trois bouteilles.</div> </div>
<p>En essayant à tâtons et en réfléchissant, vous trouverez surement la réponse en un temps raisonnable. Mais j'ai préféré écrire du code qui réfléchisse pour moi afin d'être plus systématique et parce que c'est plus rigolo. J'ai d'abord pensé à de la programmation logique avec <a href="https://fr.wikipedia.org/wiki/Prolog">Prolog</a> ou <a href="https://fr.wikipedia.org/wiki/Answer_set_programming">Answer Set Programming</a>. Mais n'étant pas à l'aise dans ces langages, j'ai demandé à un copain, Aluriak, qui s'est fait une joie de résoudre ce problème en ASP et dont les résultats <a href="https://lucas.bourneuf.net/blog/asp-temporal.html">sont dispo sur son blog</a>. <br>
De mon côté, j'ai choisi une approche algorithmique en construisant un graphe résumant tous les états possibles associés à leurs transitions. Le notebook est disponible <a href="https://github.com/dridk/notebook/blob/master/rusty_lake/rusty_lake.ipynb">ici</a> .</p>
<h2>Un graphe d'état</h2>
<p>On peut résumer ce problème comme une succession d'états reliés par des transitions. Un état est défini par les 3 volumes dans chaque bouteille. Par exemple le premier état <strong>(10,1,0)</strong> correspond à la première bouteille remplie à 10 L, la deuxième à 1 L et la troisième à 0 L.
À partir de cet état, il existe 3 transitions possibles. <br>
Si vous videz la première bouteille dans la seconde vous obtenez l'état <strong>(6,5,1)</strong>. <br>
Si vous videz la deuxième bouteille dans la troisième, vous obtenez l'état <strong>(10,0,1)</strong>. <br>
Si vous videz la première bouteille dans la troisième vous obtenez l'état <strong>(4,1,6)</strong>. <br>
Il n'y a pas d'autre possibilité, comme illustré ci-dessous :</p>
<div class="figure"> <img src="../images/rusty_lake/graphe_base.png" /> <div class="legend">À partir de l'état (10,1,0) il y a trois façons différentes de transvaser l'eau.</div> </div>
<p>Nous pouvons alors recommencer ce processus à partir de chacun des nouveaux états et construire successivement les autres états dans un <a href="https://fr.wikipedia.org/wiki/Graphe_orient%C3%A9">graphe orienté</a>. <br>
Pour cela, j'ai utilisé <a href="https://www.python.org/download/releases/3.0/">Python</a> et la librairie <a href="https://networkx.github.io/">networkx</a> en représentant chaque état par un <a href="http://apprendre-python.com/page-apprendre-tuples-tuple-python">tuple</a> de dimension 3. <br>
la fonction suivante permet de passer d'un état à un autre : </p>
<div class="highlight"><pre><span></span><code><span class="c1"># Vider la bouteille x dans la bouteille y connaissant l'état (state) et</span>
<span class="c1"># le volume maximum pour chaque bouteille (vmax). Retourne None si impossible.</span>
<span class="k">def</span> <span class="nf">change_state</span><span class="p">(</span><span class="n">x</span><span class="p">:</span><span class="nb">int</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span><span class="nb">int</span><span class="p">,</span> <span class="n">state</span><span class="p">:</span><span class="nb">tuple</span><span class="p">,</span> <span class="n">vmax</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">)):</span>
<span class="n">new_state</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">state</span><span class="p">)</span>
<span class="c1"># Calcul de e : le volume de liquide à déplacer</span>
<span class="n">e_in</span> <span class="o">=</span> <span class="p">(</span><span class="n">vmax</span><span class="p">[</span><span class="n">y</span><span class="p">]</span> <span class="o">-</span> <span class="n">new_state</span><span class="p">[</span><span class="n">y</span><span class="p">])</span>
<span class="n">e_out</span> <span class="o">=</span> <span class="n">state</span><span class="p">[</span><span class="n">x</span><span class="p">]</span>
<span class="n">e</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">e_in</span><span class="p">,</span> <span class="n">e_out</span><span class="p">)</span>
<span class="k">if</span> <span class="n">e</span> <span class="o">==</span> <span class="mi">0</span> <span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">new_state</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">-</span> <span class="n">e</span> <span class="o"><</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">new_state</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">if</span> <span class="n">new_state</span><span class="p">[</span><span class="n">y</span><span class="p">]</span> <span class="o">+</span> <span class="n">e</span> <span class="o">></span> <span class="n">vmax</span><span class="p">[</span><span class="n">y</span><span class="p">]:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="n">new_state</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">-=</span> <span class="n">e</span>
<span class="n">new_state</span><span class="p">[</span><span class="n">y</span><span class="p">]</span> <span class="o">+=</span> <span class="n">e</span>
<span class="k">return</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">new_state</span><span class="p">)</span>
<span class="c1"># Exemple </span>
<span class="nb">print</span><span class="p">(</span><span class="n">change_state</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,(</span><span class="mi">10</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">)))</span>
</code></pre></div>
<p>En partant de l'état <strong>(10,1,0)</strong>, j'ai alors construit un graphe montrant tous les états successifs possibles en 7 mouvements. J'ai choisi 7 itérations, car empiriquement je savais que cela suffirait pour trouver la solution. Dans l'idéal, j'aurais fais une boucle infinie qui s'arrête des qu'elle trouve 8 litres dans la première bouteille. Mais là il est minuit et j'ai la flemme de changer le code...</p>
<div class="highlight"><pre><span></span><code><span class="c1"># Création d'un graphe dirigé # Creat </span>
<span class="n">graph</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">DiGraph</span><span class="p">()</span>
<span class="c1"># Liste de toutes les transitions possibles</span>
<span class="c1"># Bouteille 0 dans 1, bouteille 1 dans 2, etc.</span>
<span class="n">choices</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">permutations</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">],</span><span class="mi">2</span><span class="p">))</span>
<span class="c1"># Création du premier noeud avec l'état 10,1,0</span>
<span class="n">parent</span> <span class="o">=</span> <span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span>
<span class="n">graph</span><span class="o">.</span><span class="n">add_node</span><span class="p">(</span><span class="n">parent</span><span class="p">)</span>
<span class="c1"># Construction du graphe sur 7 itérations </span>
<span class="k">for</span> <span class="n">depth</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">7</span><span class="p">):</span>
<span class="n">parents</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">graph</span><span class="o">.</span><span class="n">nodes</span><span class="p">())</span>
<span class="k">for</span> <span class="n">parent</span> <span class="ow">in</span> <span class="n">parents</span><span class="p">:</span>
<span class="k">for</span> <span class="n">choice</span> <span class="ow">in</span> <span class="n">choices</span><span class="p">:</span>
<span class="n">child</span> <span class="o">=</span> <span class="n">change_state</span><span class="p">(</span><span class="o">*</span><span class="n">choice</span><span class="p">,</span> <span class="n">parent</span><span class="p">)</span>
<span class="k">if</span> <span class="n">child</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">graph</span><span class="o">.</span><span class="n">add_node</span><span class="p">(</span><span class="n">child</span><span class="p">)</span>
<span class="n">graph</span><span class="o">.</span><span class="n">add_edges_from</span><span class="p">([(</span><span class="n">parent</span><span class="p">,</span> <span class="n">child</span><span class="p">)],</span> <span class="n">label</span><span class="o">=</span><span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">))</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">with_labels</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</code></pre></div>
<p>Voilà ce qu'on obtient comme graphe. Et comme vous pouvez l'observer en jaune, il y a l'état <strong>(8,0,3)</strong> avec les 8 litres dans la première bouteille. C'est l'état que nous cherchons à atteindre.</p>
<div class="figure"> <img src="../images/rusty_lake/graphe.png" /> <div class="legend">Graphe de l'ensemble des états possibles avec 7 mouvements.</div> </div>
<h2>La solution</h2>
<p>Il suffit alors de trouver dans le graphe le chemin le plus court partant de l'état initial <strong>(10,0,1)</strong> vers l'état final <strong>(8,0,3)</strong> en utilisant <a href="https://fr.wikipedia.org/wiki/Algorithme_de_Dijkstra">l'algorithme de Dijkstra</a>. (Allez faire un tour sur la chaine YouTube « <a href="https://www.youtube.com/watch?v=JPeCmKFrKio">À la découverte des graphes</a> » pour comprendre cet algorithme). Networkx nous fournit directement l'implémentation via la fonction <a href="https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.shortest_paths.generic.shortest_path.html#networkx.algorithms.shortest_paths.generic.shortest_path">shortest_path</a> :</p>
<div class="highlight"><pre><span></span><code><span class="n">states</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">shortest_path</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span><span class="n">source</span><span class="o">=</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="n">target</span><span class="o">=</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span>
<span class="c1">#State 1 (10, 1, 0)</span>
<span class="c1">#State 2 (4, 1, 6)</span>
<span class="c1">#State 3 (4, 5, 2)</span>
<span class="c1">#State 4 (9, 0, 2)</span>
<span class="c1">#State 5 (9, 2, 0)</span>
<span class="c1">#State 6 (3, 2, 6)</span>
<span class="c1">#State 7 (3, 5, 3)</span>
<span class="c1">#State 8 (8, 0, 3)</span>
</code></pre></div>
<p>Sept transitions sont donc nécessaires pour passer de l'état <strong>(10,1,0)</strong> à l'état <strong>(8,0,1)</strong>. La solution de l'énigme est donc la suivante: </p>
<ul>
<li>State (10,1,0)<ul>
<li>Vider la première bouteille dans la troisième.</li>
</ul>
</li>
<li>State (4,1,6)<ul>
<li>Vider la troisième bouteille dans la deuxième.</li>
</ul>
</li>
<li>State (4,5,2)<ul>
<li>Vider la deuxième bouteille dans la première.</li>
</ul>
</li>
<li>State (9,0,2)<ul>
<li>Vider la troisième bouteille dans la deuxième.</li>
</ul>
</li>
<li>State (9,2,0)<ul>
<li>Vider la première bouteille dans la troisième.</li>
</ul>
</li>
<li>State (3,2,6)<ul>
<li>Vider la troisième bouteille dans la deuxième.</li>
</ul>
</li>
<li>State (3,5,3)<ul>
<li>Vider la deuxième bouteille dans la première.</li>
</ul>
</li>
<li>State (8,0,3) </li>
</ul>
<h2>Un mot pour la fin</h2>
<p>Un bon samedi matin gaché à coder mais des nuits d'insomnies évitées à me ruiner les méninges sur ce problème. Vous me direz qu'il suffisait d'aller voir la solution en vidéo ci-dessous...
Mais ça, c'est <em>tricher</em> avec beacoup, beaucoup moins de classe !</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/AqylpTp1sNs?start=423" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<h2>Remerciements</h2>
<ul>
<li><a href="https://github.com/Aluriak">@Aluriak</a> </li>
<li><a href="https://github.com/Oodnadatta">@Oodnadatta</a></li>
</ul>Algorithme d'Espérance-Maximisation2018-08-06T18:13:58+02:002018-08-06T18:41:28+02:00Sacha Schutztag:dridk.me,2018-08-06:/expectation-maximisation.html<p>Nous allons voir dans ce billet l'algorithme d'<a href="https://fr.wikipedia.org/wiki/Algorithme_esp%C3%A9rance-maximisation">espérance-maximisation</a> ou algorithme EM (Expectation-maximisation) qui va nous permettre d'identifier les paramètres de deux <a href="https://fr.wikipedia.org/wiki/Loi_normale">lois normales</a> depuis une seule distribution mixte ou <a href="https://fr.wikipedia.org/wiki/Mod%C3%A8le_de_m%C3%A9lange_gaussien">mélange gaussien</a> ou GMM (Gaussian Mixture model).
Comme d'habitude, je vais faire au plus simple. Ce billet fait directement suite …</p><p>Nous allons voir dans ce billet l'algorithme d'<a href="https://fr.wikipedia.org/wiki/Algorithme_esp%C3%A9rance-maximisation">espérance-maximisation</a> ou algorithme EM (Expectation-maximisation) qui va nous permettre d'identifier les paramètres de deux <a href="https://fr.wikipedia.org/wiki/Loi_normale">lois normales</a> depuis une seule distribution mixte ou <a href="https://fr.wikipedia.org/wiki/Mod%C3%A8le_de_m%C3%A9lange_gaussien">mélange gaussien</a> ou GMM (Gaussian Mixture model).
Comme d'habitude, je vais faire au plus simple. Ce billet fait directement suite à celui sur <a href="maximum-de-vraissemblance.html">le maximum de vraisemblance</a> mais vous n'êtes pas obligé de le lire.</p>
<h2>Mélange de Gaussienne</h2>
<p>Nous allons étudier la distribution des tailles chez 1000 hommes et 1000 femmes. La taille des hommes suit une loi normale de moyenne <strong>μ=190 cm</strong> et d'écart-type <strong>σ=10</strong>. Celle des femmes, une moyenne <strong>μ=160cm</strong> et d'écart type <strong>σ=5</strong>.
Nous pouvons générer et representer visuellement ces données en <a href="https://www.python.org/">python</a> avec <a href="http://www.numpy.org/">numpy</a> et <a href="https://seaborn.pydata.org/">seaborn</a>: </p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">import</span> <span class="nn">seaborn</span> <span class="k">as</span> <span class="nn">sns</span>
<span class="n">hommes</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="mi">190</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">1000</span><span class="p">)</span>
<span class="c1"># hommes = [171,171,173,180,190,159 ...]</span>
<span class="n">femmes</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="mi">160</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span> <span class="mi">1000</span><span class="p">)</span>
<span class="c1"># femmes = [145,170,145,161,139,150 ...]</span>
<span class="n">sns</span><span class="o">.</span><span class="n">distplot</span><span class="p">(</span><span class="n">femmes</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Femmes"</span><span class="p">)</span>
<span class="n">sns</span><span class="o">.</span><span class="n">distplot</span><span class="p">(</span><span class="n">hommes</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"Hommes"</span><span class="p">)</span>
</code></pre></div>
<div class="figure">
<img src="../images/mixture_model/hommes_femmes.png" />
<div class="legend"> Distribution des tailles chez les femmes (roses) et les hommes (bleus) </div>
</div>
<p>Imaginez maintenant que vous avez seulement une liste . Cette nouvelle distribution est la <a href="https://fr.wikipedia.org/wiki/Concat%C3%A9nation">concaténation</a> des deux distributions précédentes : </p>
<div class="highlight"><pre><span></span><code><span class="n">X</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">concatenate</span><span class="p">((</span><span class="n">femmes</span><span class="p">,</span><span class="n">hommes</span><span class="p">))</span>
<span class="n">sns</span><span class="o">.</span><span class="n">distplot</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s2">"mixture"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s2">"green"</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">legend</span><span class="p">()</span>
</code></pre></div>
<div class="figure">
<img src="../images/mixture_model/mixture.png" />
<div class="legend"> Distribution des Tailles sans connaissance du sexe. </div>
</div>
<p><strong>Le but du jeu à présent</strong>, est de retrouver les paramètres des deux gaussiennes paramétrées par <strong>(μA,σA) </strong> et <strong>(μB,σB)</strong> uniquement à partir de cette distribution que nous appellerons <strong>X</strong>.</p>
<h2>Algorithme EM</h2>
<p>L'<a href="https://fr.wikipedia.org/wiki/Algorithme_esp%C3%A9rance-maximisation">Algorithme EM</a> ( Expectation-Maximisation ) va nous permettre de trouver les paramètres de ces deux gaussiennes en partant de valeurs aléatoires et en les ajustant au fur et mesure jusqu'à ce que la vraisemblance de ces modèles soient maximales. Les étapes sont les suivantes : </p>
<ol>
<li>Initialiser deux lois normales A et B en choisissant des valeurs aléatoires pour (μA /σA et μB / σB) </li>
<li>Pour chaque valeur de <strong>X</strong>, calculer sa probabilité sous l'hypothèse A (pA) puis B (pB)</li>
<li>Pour chaque valeur de <strong>X</strong>, calculer le poids <strong>wA</strong> = pA/(pA+pB) et <strong>wB</strong>=pB/(pA+pB) </li>
<li>Calculer des nouveaux paramètres (μA,σA) et (μB,σB) en ajustant <strong>X</strong> à partir des poids <strong>wA</strong> et <strong>wB</strong>.</li>
<li>Recommencer ...</li>
</ol>
<p>En Python cela donne : </p>
<div class="highlight"><pre><span></span><code> <span class="c1"># Distribution des tailles X.. (voir plus haut )</span>
<span class="c1"># X = [159,158, 159, 179, 189 ....]</span>
<span class="c1"># Générer un modèle aléatoire A </span>
<span class="n">A_mean</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span><span class="mi">300</span><span class="p">)</span>
<span class="n">A_sd</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">30</span><span class="p">)</span>
<span class="c1"># Générer un modèle aléatoire B </span>
<span class="n">B_mean</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span><span class="mi">300</span><span class="p">)</span>
<span class="n">B_sd</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="mi">30</span><span class="p">)</span>
<span class="c1"># Faite 50 itérations... ( ca suffira)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">50</span><span class="p">):</span>
<span class="c1"># Pour chaque valeur de X, calculer la probabilité </span>
<span class="c1"># sous l'hypothèse A et B</span>
<span class="n">p_A</span> <span class="o">=</span> <span class="n">scipy</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">norm</span><span class="p">(</span><span class="n">loc</span><span class="o">=</span><span class="n">A_mean</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="n">A_sd</span><span class="p">)</span><span class="o">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="n">p_B</span> <span class="o">=</span> <span class="n">scipy</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">norm</span><span class="p">(</span><span class="n">loc</span><span class="o">=</span><span class="n">B_mean</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="n">B_sd</span><span class="p">)</span><span class="o">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="c1"># Calculer pour chaque valeur de X, un poids correspondant </span>
<span class="c1"># à son degrès d'appartenance à la loi A ou B.</span>
<span class="n">p_total</span> <span class="o">=</span> <span class="n">p_A</span> <span class="o">+</span> <span class="n">p_B</span>
<span class="n">weight_A</span> <span class="o">=</span> <span class="n">p_A</span> <span class="o">/</span> <span class="n">p_total</span>
<span class="n">weight_B</span> <span class="o">=</span> <span class="n">p_B</span> <span class="o">/</span> <span class="n">p_total</span>
<span class="c1"># Exemple : Si la taille de 189cm appartient à la lois B </span>
<span class="c1"># alors weight_B(189) sera grand et weight_A(189) sera petit.</span>
<span class="c1">#Ajustement des paramètres (μA,σA) et (μB,σB) en fonction du poids.</span>
<span class="n">A_mean</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">X</span> <span class="o">*</span> <span class="n">weight_A</span> <span class="p">)</span><span class="o">/</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">weight_A</span><span class="p">)</span>
<span class="n">B_mean</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">X</span> <span class="o">*</span> <span class="n">weight_B</span> <span class="p">)</span><span class="o">/</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">weight_B</span><span class="p">)</span>
<span class="n">A_sd</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">weight_A</span> <span class="o">*</span> <span class="p">(</span><span class="n">X</span> <span class="o">-</span> <span class="n">A_mean</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">weight_A</span><span class="p">))</span>
<span class="n">B_sd</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">weight_B</span> <span class="o">*</span> <span class="p">(</span><span class="n">X</span> <span class="o">-</span> <span class="n">B_mean</span><span class="p">)</span><span class="o">**</span><span class="mi">2</span><span class="p">)</span> <span class="o">/</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">weight_B</span><span class="p">))</span>
<span class="c1"># On recommence jusqu'à convergence. Non testé ici, je m'arrête à 50 iterations.</span>
</code></pre></div>
<p>Et voilà ce que l'on obtient en animant le tout à chaque itération: </p>
<div class="figure">
<img src="../images/mixture_model/em_algo.gif" />
<div class="legend"> Ajustement de deux lois normales (orange et bleu) à la distribution X (vert) selon l'algorithme EM </div>
</div>
<h1>Loi normale multivariée</h1>
<p>Dans cet exemple, nous avons étudié la distribution d'une seule variable (<em>la taille</em>) en utilisant une loi normale paramétrée par μ et σ.
Mais nous pouvons faire encore mieux en étudier la distribution de plusieurs variables simultanément (Par exemple la taille et le poids). On utilise pour cela une généralisation de la loi normale que l'on appelle <a href="https://fr.wikipedia.org/wiki/Loi_normale_multidimensionnelle">loi normale multidimensionnelle</a> paramètré par un vecteur μ et une matrice de covariance σ. <br>
En prenant 2 variables comme la Taille et le Poid, μ correspond à la liste des moyennes [μTaille, μPoid] et σ correspond à une matrice symétrique 2x2 contenant les <a href="https://fr.wikipedia.org/wiki/Covariance">covariances</a> et <a href="https://fr.wikipedia.org/wiki/Variance_(statistiques_et_probabilit%C3%A9s)">variances</a> de la taille et du poids. <br>
Vous pouvez vous représenter une loi normale à deux variables comme un <a href="https://fr.wikipedia.org/wiki/Sombrero">Sombrero</a> aplati et vu de haut ou chaque point est representé dans le plan par ses coordonnées (x=Taille et y=Poids).</p>
<div class="figure">
<img src="../images/mixture_model/bivariate.png" />
<div class="legend"> Exemple d'une distribution normale bivariée. Imaginez que la courbe rouge représente la taille et la bleu le poid </div>
</div>
<div class="figure">
<img src="../images/mixture_model/bivariate_gaussian.png" />
<div class="legend"> Representation en 3 dimensions d'une loi normale bivariée. La projection sur le plan des variables (Taille,Poids) permet d'identifier une région de densité de probabilité. </br><a href="https://scipython.com/blog/visualizing-the-bivariate-gaussian-distribution/"> Source </a> </div>
</div>
<p>Et comme nous l'avons fait précédement avec <strong>une variable</strong>, nous pouvons identifier plusieurs gaussiennes multivariées dans un espace à <strong>plusieurs variables</strong> (figure ci-dessous). <br>
En d'autres termes, identifier à quelle distribution appartient un point dans un espace à N dimension, c'est faire de la <a href="https://fr.wikipedia.org/wiki/Partitionnement_de_donn%C3%A9es">clusterisation</a>.</p>
<div class="figure">
<img src="../images/mixture_model/bivariate2.png" />
<div class="legend"> Exemple: Gauche: Distribution de deux variables et identification de 2 clusters. Droite: Modèle normal bivarié montrant la densité sur son 3ème axe. <br/><a href="https://www.sciencedirect.com/science/article/pii/S0167947315000171">Source</a> </div>
</div>
<h1>Hard et Soft clustering</h1>
<p>Il existe d'autres algorithmes pour détecter des clusters, notamment l'algorithme <a href="https://fr.wikipedia.org/wiki/K-moyennes">k-means</a> ou encore les <a href="https://fr.wikipedia.org/wiki/M%C3%A9thode_des_k_plus_proches_voisins">k-plus proches voisins</a>. Ces méthodes de clustering sont dites "<a href="https://www.youtube.com/watch?v=xtDMHPVDDKk">Hard clustering</a>" car ils atégorisent de façon précise un point (Soit c'est un homme, soit c'est une Femme). Au contraire, avec l'algorithme EM et les mixtures gaussiennes, nous pouvons faire du <a href="https://www.youtube.com/watch?v=xtDMHPVDDKk">soft clustering</a>. Au lieu de dire que tel point appartient soit au groupe A soit au groupe B, on lui donne une probabilité d'appartenance à chacun de ces groupes. (90% de chance que ce soit un homme, 1% que ce soit une femme). C'est ce qu'on appelle la <a href="https://fr.wikipedia.org/wiki/Logique_floue">logique floue</a>.</p>
<div class="figure">
<img src="../images/mixture_model/clustering.png" />
<div class="legend"> Différence entre le soft et du hard clustering en utilisant un gradient de couleur. En rouge les femmes, en bleu les hommes </div>
</div>
<h1>Conclusion</h1>
<p>L'algorithme EM fait partie de la grande famille du <a href="https://fr.wikipedia.org/wiki/Apprentissage_automatique">machine learning</a> et de <a href="https://fr.wikipedia.org/wiki/Apprentissage_non_supervis%C3%A9">l'apprentissage non supervisé</a>. C'est un avant goût des méthodes bayesiennes utilisées en intelligence artificielle. Si vous voulez approfondir le sujet, allez voir du côté de la libraire <a href="http://scikit-learn.org/stable/modules/mixture.html">scikit-learn</a>. </p>
<h2>Références</h2>
<ul>
<li><a href="https://stackoverflow.com/questions/11808074/what-is-an-intuitive-explanation-of-the-expectation-maximization-technique">StackOverflow</a></li>
<li><a href="https://www.coursera.org/learn/bayesian-methods-in-machine-learning">Coursera: Bayesian Methods for Machine Learning</a></li>
</ul>
<h3>Remerciements</h3>
<ul>
<li>Merci à André pour la relecture</li>
</ul>Euler et l'assemblage des génomes2018-07-18T18:45:20+02:002018-07-19T18:22:14+02:00Sacha Schutztag:dridk.me,2018-07-18:/assemblage.html<p>Imaginez une pile de journaux identiques que vous faites sauter avec des pétards pour en faire une pluie de fragments de texte aléatoire. Comment feriez-vous, à partir de ces milliers de morceaux de papier, pour reconstruire un exemplaire complet du journal ?
La même question se pose lorsque l'on désire reconstruire …</p><p>Imaginez une pile de journaux identiques que vous faites sauter avec des pétards pour en faire une pluie de fragments de texte aléatoire. Comment feriez-vous, à partir de ces milliers de morceaux de papier, pour reconstruire un exemplaire complet du journal ?
La même question se pose lorsque l'on désire reconstruire le génome d'un organisme à partir des milliards de courtes séquences générées par un <a href="https://dridk.me/ngs.html">séquenceur haut débit</a>. Si vous pensez qu'il suffit de tester toutes les combinaisons en comparant les fragments deux à deux, sachez que même avec un ordinateur très puissant, cela prendrait beaucoup de temps.
Nous allons donc voir dans ce billet, comment les programmes d'assemblages classiques fonctionnent et comment un gars du nom de Euler, en s'amusant à compter les ponts de la ville de Königsberg, nous permet aujourd'hui de faire de l'assemblage de génomes de façon efficace.</p>
<h1>Les <em>k</em>-mers</h1>
<p>Les <a href="https://en.wikipedia.org/wiki/K-mer"><em>k</em>-mers</a> sont l'ensemble des mots de k lettres que l'on peut lire dans une séquence. Par exemple, la séquence suivante <strong>TAATGCCATGGGATGT</strong> peut se décomposer (avec des pétards ou non) en 14 mots de 3 lettres appelés 3-mers :</p>
<div class="highlight"><pre><span></span><code>TAATGCCATGGGATGT
TAA
AAT
ATG
TGC
GCC
CCA
CAT
ATG
TGG
GGG
GGA
GAT
ATG
TGT
</code></pre></div>
<p>Ce que nous allons tenter dans la suite de ce billet, c'est de reconstruire la séquence d'origine à partir de ces 14 mots de 3 lettres rangés dans un ordre arbitraire :</p>
<div class="highlight"><pre><span></span><code>AAT,ATG,ATG,ATG,CAT,CCA,GAT,GCC,GGA,GGG,TAA,TGC,TGG,TGT
</code></pre></div>
<p>Attention, notez bien dans cette liste que le mot <strong>ATG</strong> est présent 3 fois. Il s'agit de l'abondance du k-mer qu'il faut prendre en compte en raisonnant bien avec 3 mots <strong>ATG</strong> et non un seul.</p>
<h1>Construction d'un graphe</h1>
<p>À partir de cette liste de 3-mers, nous allons construire un <a href="https://www.youtube.com/watch?v=YYv2R1cCTa0">graphe</a> orienté. C'est-à-dire un ensemble de nœuds reliés par des flèches. Pour cela, deux méthodes s'offrent à nous.</p>
<h2>Les k-mers sont des nœuds</h2>
<p>Si nous représentons chaque k-mer par un nœud, alors deux nœuds consécutifs dans la séquence partagent le même suffixe et préfixe.
Par exemple le k-mer T<strong>GC</strong> précède le k-mer <strong>GC</strong>C car le suffixe du premier (-GC) correspond au préfixe du second (GC-). Cette relation se représente avec deux nœuds et une flèche :</p>
<div class="figure">
<img src="../images/assemblage/hamilton_node.png" />
<div class="legend"> Relation entre deux k-mers dans un graphe. Le suffixe (k-1) du premier correspond au préfixe (k-1) du second</div>
</div>
<p>Nous pouvons alors construire un graphe en reliant tous nos k-mers via leurs suffixes/préfixes et obtenir la figure suivante :</p>
<div class="figure">
<img src="../images/assemblage/hamilton_graphe.png" />
<div class="legend"> Graphe représentant chaque k-mer par un nœud. Saurez-vous trouver le chemin passant par tous les nœuds une seule fois ?</div>
</div>
<p>Pour reconstruire la séquence d'origine, il suffit de trouver un chemin passant par tous les nœuds une fois et une seule. On appelle ce chemin <a href="https://fr.wikipedia.org/wiki/Graphe_hamiltonien">un parcours Hamiltonien</a>. Essayez de le trouver par vous même avant de regarder l'animation ci-dessous :</p>
<div class="figure">
<img src="../images/assemblage/hamilton_graphe_path.gif" />
<div class="legend"> Parcours Hamiltonien dans le graphe. Chaque nœud est traversé une fois et une seule</div>
</div>
<p>Cette méthode est simple, mais il y a un hic. La recherche du parcours Hamiltonien dans un graphe est un problème mathématique dit <a href="https://fr.wikipedia.org/wiki/Probl%C3%A8me_NP-complet">NP-complet</a>. Pour faire simple, il n'existe pas d'algorithme informatique rapide pour trouver ce chemin. Le temps de calcul augmente exponentiellement avec la taille du graphe. Par exemple, pour un graphe plus complexe, tel que celui utilisé pour reconstruire la séquence d'un génome, il vous faudra toujours énormément de temps de calcul, même avec les plus super des super calculateurs.
Il nous faut une meilleure méthode…</p>
<h2>Les k-mers sont des flèches</h2>
<p>Nous allons cette fois construire un graphe en représentant les k-mers par des flèches. Les nœuds contiendront le préfixe et le suffixe du k-mer. Par exemple si une flèches représente le k-mer <strong>TGC</strong> alors les deux nœuds autour de la flèche sont <strong>TG</strong> et <strong>GC</strong>.</p>
<div class="figure">
<img src="../images/assemblage/euler_node.png" />
<div class="legend"> Représentation d'un k-mer par une flèches. Les nœuds contiennent les suffixes et préfixes des k-mers</div>
</div>
<p>Nous pouvons alors construire le graphe suivant :</p>
<div class="figure">
<img src="../images/assemblage/not_fusion_graphe.png" />
<div class="legend"> Graphe représentant chaque k-mer par une flèches. Les nœuds sont les préfixes/suffixes. Certain nœuds en couleur sont présent plusieurs fois et peuvent être fusionnés</div>
</div>
<p>Cette fois, au lieu de chercher un chemin passant par <strong>tous les nœuds</strong> une seule fois, nous allons chercher un chemin passant par <strong>toutes les flèches</strong> une fois et une seule. En le recherchant, vous verrez tout de suite qu'un tel parcours n'existe pas dans ce dernier graphe. Par exemple, on ne peut pas traverser tous les chemins <strong>AT</strong>-><strong>TG</strong> sans être bloqué.
Pour remédier à ce problème, nous allons fusionner tous les nœuds identiques. Visualisez par exemple les 3 nœuds violets <b style="color:#5C3566;">AT</b> et imaginez-les se rapprocher pour former un seul nœud sans jamais toucher aux flèches. Vous obtenez alors un unique nœud <strong>AT</strong> relié par 3 flèches au nœud <strong>TG</strong>. Faites la même chose pour les autres nœuds identiques et vous obtiendrez le fameux <a href="https://fr.wikipedia.org/wiki/Graphe_de_de_Bruijn">graphe de de Bruijn</a>.</p>
<div class="figure">
<img src="../images/assemblage/debruijn_graphe.png" />
<div class="legend"> Graphe de de Bruijn </div>
</div>
<p>Vous pouvez maintenant chercher le chemin passant par toutes les flèches une fois et une seule. C'est ce qu'on appelle un parcours <a href="https://fr.wikipedia.org/wiki/Graphe_eul%C3%A9rien">Eulérien</a>. Essayer de le trouver par vous même, ce n'est pas très difficile.</p>
<div class="figure">
<img src="../images/assemblage/euler_path.gif" />
<div class="legend"> Parcours Eulérien dans un graphe de de Bruijn </div>
</div>
<p>Contrairement au parcours Hamiltonien, le parcours Eulérien, si il existe, peut être trouvé rapidement par un algorithme informatique. La <a href="https://fr.wikipedia.org/wiki/Analyse_de_la_complexit%C3%A9_des_algorithmes">complexité</a> de cet algorithme est dite « en O(n) ». C'est à dire que le temps de calcul est proportionnel à la taille du graphe.
Voyons maintenant la théorie mathématique derrière ce parcours que l'on doit à <a href="https://fr.wikipedia.org/wiki/Leonhard_Euler">Leonhard Euler</a> et à la ville de <a href="https://fr.wikipedia.org/wiki/K%C3%B6nigsberg">Königsberg</a> en Pologne.</p>
<h1>Les ponts de Königsberg</h1>
<h2>Le théorème de Euler</h2>
<p>En 1873, un mathématicien du nom de Leonhard Euler s'est posé la question de savoir si il existait une promenade dans la ville de Königsberg passant par tous les ponts une fois et une seule. C'est <a href="https://fr.wikipedia.org/wiki/Probl%C3%A8me_des_sept_ponts_de_K%C3%B6nigsberg">le problème des 7 ponts de Königsberg</a> qui peut être modélisé sous la forme d'un graphe :</p>
<div class="figure">
<img src="../images/assemblage/Konigsberg_bridges.png" />
<div class="legend"> Gauche : Pont de Königsberg Droite : représentation des ponts par un graphe. Les chiffres indiquent le nombres d'arêtes relié au nœud. Existe-t-il un chemin passant par tous les ponts ?</div>
</div>
<p>Euler démontre qu'un parcours Eulérien (passant par toutes les arêtes une fois et une seule) existe dans un graphe si et seulement chaque nœud est relié à un nombre pair d'arêtes. En effet, si l'on doit entrer dans un nœud par 1 arête, il faut forcément ressortir par 1 autre arête. Dans le cas des ponts de Königsberg, un tel chemin n'existe pas, car le nombre d'arêtes par nœud est respectivement de 5,3,3,3 (voir image ci-dessus).
Dans un graphe orienté comme le notre, c'est à dire lorsque les arrêtes sont des flèches, un chemin Eulérien existe si le nombre de flèches à l'entrée d'un nœud est le même qu'à la sortie.</p>
<h2>Avons-nous un chemin eulérien dans notre graphe de de Bruijn ?</h2>
<p>Pour que les conditions du théorème de Euler s'appliquent à notre graphe de de Bruijn, nous devons tricher en ajoutant une flèche entre le dernier nœud <strong>TA</strong> et le premier nœud <strong>GT</strong> et former ainsi un cycle. Vous constaterez alors, que pour chaque nœud, il y a autant de flèches d'entrée que de flèches de sortie. Nous pouvons alors conclure, sans même le connaître, qu'un chemin Eulérien existe.</p>
<div class="figure">
<img src="../images/assemblage/euler_cycle.png"/>
<div class="legend"> Graphe de de Bruijn modifié pour pouvoir avoir un cycle de Euler. En rouge le nombre de flèches à l'entré d'un nœud, en vert le nombre de flèches à la sortie d'un nœud. Le [degré](https://fr.wikipedia.org/wiki/Degr%C3%A9_(th%C3%A9orie_des_graphes)) d'entré et de sortie pour chaque nœud sont identique. D'après le théorème, il existe donc un chemin Eulérien passant par toutes les flèches une fois et une seule</div>
</div>
<h2>L'algorithme de Euler</h2>
<p>Il existe une algorithme rapide pour pouvoir trouver le chemin Eulérien. Pour le comprendre (c'est très simple, je vous rassure), regardez juste cette courte vidéo sur la chaîne YouTube « <a href="https://www.youtube.com/channel/UCHtJVeNLyR1yuJ1_xCK1WRg">à la découverte des graphes</a> ». Personnellement, je trouve que c'est la meilleure chaîne de vulgarisation sur la théorie des graphes. A garder en favoris.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/DH0Hxes2nOo" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<h1>Conclusion</h1>
<p>Nous avons vu deux méthodes pour reconstruire une séquence à partir de ses k-mers. Nous pouvons soit chercher un parcours Hamiltonien dans un graphe de k-mer ou alors chercher un parcours Eulérien dans un graphe de de Bruijn. Cette dernière méthode est préférée, car il existe un algorithme efficace.
Dans ce billet, je me suis grandement inspiré du livre <a href="https://www.amazon.fr/Bioinformatics-Algorithms-Active-Learning-Approach/dp/0990374602">Bioinformatics Algorithms</a> que je vous conseille fortement. C'est le même exemple détaillé sur plus de 20 pages.
Sinon, dans la réalité, la reconstruction d'un génome est plus complexe et fait intervenir d'autres notions comme les <a href="https://fr.wikipedia.org/wiki/Contig">contigs</a>, les <a href="https://en.wikipedia.org/wiki/Scaffolding_(bioinformatics)">scaffolds</a>, les bulles, la correction d'erreurs de séquençage ou encore le <a href="https://www.ncbi.nlm.nih.gov/pubmed/23095524">gap filling</a>.
Je ne suis absolument pas spécialiste de ce domaine, mais j'avais juste envie de vous partager ce que j'avais compris. Pour plus de précisions, voir avec <a href="https://twitter.com/natir_chan">@Natir</a>, c'est un expert de l'assemblage.
Enfin, tout les notions vues dans ce billet concernent l'assemblage d'un génome à partir de courtes séquences d'ADN ou short reads. Cette méthode est aujourd'hui devancée par <a href="http://www.biorigami.com/?tag=sequenceurs-3eme-generation">les séquenceurs de 3e génération</a> capable de séquencer des longs fragments d'ADN rendant toutes les notions abordées dans ce billet… complètement obsolètes !</p>
<h2>Références</h2>
<ul>
<li><a href="http://bioinformaticsalgorithms.com/">BioinformaticsAlgorithms</a></li>
<li><a href="https://www.youtube.com/channel/UCHtJVeNLyR1yuJ1_xCK1WRg">A la découverte des graphes</a></li>
<li><a href="https://fr.wikipedia.org/wiki/Assemblage_(bio-informatique)">Assemblage Wikipédia</a></li>
<li><a href="http://www.iro.umontreal.ca/~csuros/IFT6299/H2014/content/prez13-assembly.pdf">cours: Assemblage de novo</a></li>
<li><a href="https://omictools.com/genome-assembly-category">Outils d'assemblages</a></li>
</ul>
<h2>Remerciements</h2>
<p>Merci à <a href="https://twitter.com/natir_chan">@Natir</a> pour m'avoir fait comprendre que je ne comprend toujours rien !</p>Le théorème de Bayes en image2018-06-26T23:18:50+02:002018-06-29T02:38:02+02:00Sacha schutztag:dridk.me,2018-06-26:/le-theoreme-de-bayes.html<p>J'ai longtemps galéré avec les probabilités... <br>
C'est assez tard que j'ai compris qu'il s'agissait juste d'un problème de dénombrement. Par exemple, si vous cherchez à savoir la probabilité pour que la somme de deux dés lancés soit égale 8, il <a href="https://bestcase.files.wordpress.com/2011/01/dicediagram.jpg">suffit de dessiner un tableau 6x6</a> contenant toutes les combinaisons …</p><p>J'ai longtemps galéré avec les probabilités... <br>
C'est assez tard que j'ai compris qu'il s'agissait juste d'un problème de dénombrement. Par exemple, si vous cherchez à savoir la probabilité pour que la somme de deux dés lancés soit égale 8, il <a href="https://bestcase.files.wordpress.com/2011/01/dicediagram.jpg">suffit de dessiner un tableau 6x6</a> contenant toutes les combinaisons possibles et compter les cases contenant un 8. J'étais assez satisfait de cette conception des probabilités qu'on appelle <em><a href="https://fr.wikipedia.org/wiki/Interpr%C3%A9tations_de_la_probabilit%C3%A9#Fr%C3%A9quentisme">fréquentiste</a></em>. Sauf que voilà, il y a une autre vision des probabilités très tendance en informatique que l'on trouve en <a href="https://fr.wikipedia.org/wiki/Classification_na%C3%AFve_bay%C3%A9sienne">intelligence artificielle</a>, dans la <a href="https://hal.archives-ouvertes.fr/halsde-00193036/document">reconstruction des arbres phylogénétique</a>, dans <a href="https://fr.wikipedia.org/wiki/Analyse_syntaxique_de_la_langue_naturelle">l'analyse naturelle du langage</a> ou même dans <a href="https://software.broadinstitute.org/gatk/documentation/tooldocs/3.8-0/org_broadinstitute_gatk_tools_walkers_haplotypecaller_HaplotypeCaller.php">la détection des mutations génétique</a> sur des données de séquençage haut débit. Cette conception c'est le <em>bayésianisme</em>, un raisonnement basé sur le <a href="https://fr.wikipedia.org/wiki/Th%C3%A9or%C3%A8me_de_Bayes">théorème de Bayes</a>. Et en croire certain youtubeur (<a href="https://www.youtube.com/watch?v=3FOrWMDL8CY">Monsieur Phi</a> & <a href="https://www.youtube.com/watch?v=DgrRlP_GRRY">Science4All</a>) , cette vision des probabilités à l'effet pour le cerveau, d'un shoot de cocaïne accompagné d'un massage thaïlandais! Donc forcément, j'ai voulu comprendre. Et vous savez quoi ? Je n’ai rien compris en lisant les différentes démonstrations de la formule de Bayes. Étonnement, c'est seulement en reprenant ma casquette de fréquentiste et en faisant de jolis dessins que tout c'est éclairé. Et c'est ce que nous allons voir maintenant. </p>
<h2>Des malades et un test biologique</h2>
<p>Sur internet, les démonstrations de la formule s'aident souvent d'un exemple avec des patients et un test biologique. On va reprendre cet exemple en s'aidant d'un schéma et en utilisant les bons mots.
Voici 10 patients dont 6 sont malades. Sont entourés les individus dont le test biologique est positif (par exemple un test grippal). Voyez ça comme si tous les gens testés positifs étaient confinés dans une zone de quarantaine. </p>
<div class="figure">
<img src="../images/bayes/intro.png" />
<div class="legend"> En vert les patients sains, en rouge les patients malades. </div>
</div>
<h2>Sensibilité et Spécificité</h2>
<p>Commençons par un petit aparté sur l'efficacité d'un test qui s'évalue à l'aide de deux grandeurs. <a href="https://fr.wikipedia.org/wiki/Sensibilit%C3%A9_et_sp%C3%A9cificit%C3%A9">La sensibilité et la spécificité</a>. </p>
<div class="figure">
<img src="../images/bayes/sens_spec.png" />
<div class="legend">Sensibilité et spécificité d'un test biologique. Un test sensible détecte tous les malades. Un test spécifique ne se positive jamais chez des patients sains</div>
</div>
<p>Un test très sensible (droite de la figure) nous assure que tous les malades sont détectés quitte à avoir des faux positifs. Sa formule s'écrit:</p>
<div class="highlight"><pre><span></span><code>Sensibilité = Vrai positif / Tous les malades
Ou encore
Sensibilité = Vrai positif / (Vrai positif + Faux négatif)
</code></pre></div>
<p>Un test très spécifique (gauche de la figure) nous assure qu'aucun patient sain n'est détecté quitte à avoir des faux négatifs. Sa formule s'écrit: </p>
<div class="highlight"><pre><span></span><code>Specificité = Vrai négatif / Tous les sains
Ou encore
Spécificité = Vrai négatif / ( Vrai négatif + Faux positif)
</code></pre></div>
<p>L'idéal est d'avoir un test avec une sensibilité et une spécificité de 100%. Mais en pratique, c'est rarement le cas et le test est choisi en fonction de l'utilisation. Un test sensible est utilisé pour faire du dépistage sur une population (un <a href="https://fr.wikipedia.org/wiki/Test_de_grossesse">test de grossesse</a> sur les urines), tandis qu'un test spécifique est utilisé pour faire du diagnostic sur des patients ciblés (<a href="https://fr.wikipedia.org/wiki/Hormone_chorionique_gonadotrope_humaine">bêta-hCG</a> sur une prise de sang ). <br>
Gardons tout cela en tête, car cela servira pour la suite.</p>
<h2>Savez-vous compter ?</h2>
<p>Revenons à nos 10 individus et posons-nous les questions suivantes.</p>
<h4>Combien avons-nous de malades ?</h4>
<div class="figure">
<img src="../images/bayes/sick_count.gif" width="250px" />
<p>6 personnes sur 10 sont malades. Soit p(M) = 6/10</p>
</div>
<h4>Combien de personnes ont un test positif?</h4>
<div class="figure">
<img src="../images/bayes/test_count.gif" width="250px" />
<p>5 personnes sur 10 ont un test postif. Soit p(T) = 5/10</p>
</div>
<h4>Combien de personnes sont malades ET avec un test positif?</h4>
<div class="figure">
<img src="../images/bayes/inter_count.gif" width="250px" />
<p>4 personnes sur 10 sont malade avec un test postif. Soit p(M et T) = 4/10</p>
</div>
<p>Maintenant, passons aux probabilités conditionnelles. Et pour cela, voici une subtilité du langage que je vous conseille d'utiliser.
Ne dites pas « <em>La probabilité de A </em><em>sachant</em><em> B </em>» mais « <em>La probabilité de A </em><em>parmi</em><em> B</em> »</p>
<h4>Combien avons-nous de malades parmi les patients testés positifs ?</h4>
<div class="figure">
<img src="../images/bayes/sick_in_test.gif" width="250px" />
<p>Parmi les 5 tests positifs il y a 4 malades. <br/>
Soit p(M|T) = p(M et T) / p(T) = 4 / 5</p>
</div>
<h4>Combien avons-nous de personnes testées positive parmi les malades?</h4>
<div class="figure">
<img src="../images/bayes/test_in_sick.gif" width="250px" />
<p>Parmi les 6 malades, 4 ont un test positif. <br/>
Soit p(T|M) = p(M et T) / p(M) = 4 / 6.
Cette dernière formule correspond à la sensibilité du test </p>
</div>
<h2>Et la formule de Bayes surgit</h2>
<p>Vous constaterez que dans les 2 formules précédentes, <strong>p(T|M)</strong> et <strong>p(M|T)</strong>, il y a un terme en commun: <strong>p(M et T)</strong> qui correspond au nombre d'individus à la fois malades et testés positivement. <br>
En remplaçant ce terme, nous pouvons alors exprimer <strong>p(M|T)</strong> en fonction de <strong>p(T|M)</strong>. </p>
<div class="highlight"><pre><span></span><code>On a :
p(T|M) = p(M et T) / p(M)
et donc:
p(M et T) = p(M) * p(T|M)
en remplaçant :
p(M|T) = p(T|M) * p(M) / p(T)
</code></pre></div>
<p>Et nous voilà alors, avec la fameuse formule de Bayes : </p>
<p><center>
<img src="../images/bayes/bayes.gif" /></p>
<p></p>
<p></center></p>
<p>On peut tout de suite vérifier sur nos 10 individus que nous trouvons par le calcul la même chose que ce que nous observons. <br>
Calculons p(M/T) et vérifions que c'est égal à 4/5:</p>
<div class="highlight"><pre><span></span><code>p(M) = 6/10
p(T) = 5/10
p(T/M) = 4/6
p(M/T) = ( p(M) * p(T/M) ) / p(T) = 6/10 * 4/6 / 5/10 = 4/5
</code></pre></div>
<h2>La loi totale de Bayes</h2>
<p>En pratique, on utilise le théorème de Bayes en médecine pour estimer le risque qu'un individu soit malade sachant que son test est positif.
Malheureusement nous n'avons pas toutes les informations nécessaires pour appliquer la formule de Bayes aussi facilement que dans notre exemple. <br>
Les seuls éléments que nous ayons à disposition sont la <a href="https://fr.wikipedia.org/wiki/Pr%C3%A9valence">prévalence</a> de la maladie dans la population p(M) et la sensibilité/spécificité du test correspondant respectivement à p(T|M) et p(nonT|nonM). <br>
Il faut alors réussir à calculer p(T).</p>
<div class="figure">
<img src="../images/bayes/final.png" />
<p>p(T) est la somme de A=p(M et T) et B=p(non M et T) sur les 10 individus</p>
</div>
<p>p(T) se calcul en sommant <mark style="background-color:#F84AA9">le nombre de patients malades ET testés positifs p(M et T)</mark> avec <mark style="background-color:#92D050">le nombre de patients sains ET testés positifs p(non M et T)</mark>. Et comme vu précédemment, nous pouvons exprimer chacun de ces termes par : </p>
<div class="highlight"><pre><span></span><code>p(M et T) = p(M) * (T|M)
p(non M et T) = p(non M) * (T|non M)
</code></pre></div>
<p>On peut alors écrire la loi totale de Bayes :</p>
<p><center>
<img src="../images/bayes/total_bayes.gif" /></p>
<p>Loi totale de Bayes</p>
<p></center></p>
<h2>Un exemple avec la mucoviscidose</h2>
<p>On s'intéresse ici au patient porteur d'une mutation dans le gène <a href="https://fr.wikipedia.org/wiki/G%C3%A8ne_et_prot%C3%A9ine_CFTR">CFTR</a> qui est impliqué dans la <a href="https://fr.wikipedia.org/wiki/Mucoviscidose">mucoviscidose</a>.
En France, <a href="http://www.anpgm.fr/index.php/arbres-decisionels?download=181:anpgm-074-v3-cftr&start=60">1 personne sur 34</a> [p(M)=<strong>1/34</strong>] est porteuse de la mutation , la plus fréquente étant la <a href="https://fr.wikipedia.org/wiki/%CE%94F508">ΔF508</a>. ( cela n'implique pas d'être malade, car il s'agit d'une <a href="https://fr.wikipedia.org/wiki/Transmission_autosomique_r%C3%A9cessive">maladie autosomique récessive</a>). Il existe un <a href="http://www.medicalexpo.fr/prod/fujirebio-europe-nv/product-95077-831367.html">test</a> pouvant détecter ces mutations avec une sensibilité de 85% [p(T|M)=<strong>1/85</strong>] et une spécificité avoisinant les 100% [p(Tneg|non M)=<strong>1</strong>]. <br>
Après vous avoir fait le test qui s'est négativé, quelle est la probabilité que vous soyez tout de même porteur ? </p>
<p><center>
<img src="../images/bayes/muco.gif" /></p>
<p>Attention subtilité: Ici p(Tneg|M) est égal à 1-sensibilité.<br/>La probabilité d'être porteur malgré la négativité du test est d'environ 1 chance sur 220 </p>
<p></center></p>
<h2>Conclusion</h2>
<p>En résumé la probabilité conditionnelle p(A|B) c'est le nombre d'évènement A parmi un sous ensemble B. Et le théorème de Bayes est la formule mathématique qui permet d'exprimer p(A|B) en fonction de p(B|A). <br>
J'espère donc que vous visualisez aussi bien que moi la formule de Bayes maintenant. Personnellement, en faisant les dessins sur papiers, je retrouve très facilement les formules. Donc inutile de les apprendre par coeur.
J'espère maintenant devenir un vrai Bayesien pour pouvoir frimer en soirée et même changer ma façon de penser. En effet, je ne sais pas si vous connaissez le <a href="https://fr.wikipedia.org/wiki/Probl%C3%A8me_de_Monty_Hall">problème de Monty Hall</a>. C'est une experience complétement contre intuitif et parait que seul des r̶e̶p̶t̶i̶l̶i̶e̶n̶s bayésiens ont le pouvoir de trouver ça logique.</p>
<h3>Réferences</h3>
<ul>
<li><a href="https://www.youtube.com/watch?v=3FOrWMDL8CY">Monsieur Phi</a></li>
<li><a href="https://laboutique.edpsciences.fr/produit/1035/9782759822614/La%20formule%20du%20savoir">Livre: La formule du savoir</a></li>
<li><a href="http://folk.uio.no/jonmic/Statkurs/03%20-%20Bayes%20law.%20Sensitivity,%20specificity.pdf">Bayes Law. Sensitivity, specificity</a></li>
<li><a href="http://www.anpgm.fr/index.php/arbres-decisionels?download=181:anpgm-074-v3-cftr&start=60">bonnes pratiques des etudes du gene cftr - anpgm</a></li>
</ul>Le maximum de vraisemblance2018-06-05T22:48:39+02:002018-06-06T23:48:33+02:00Sacha Schutztag:dridk.me,2018-06-05:/maximum-de-vraissemblance.html<p>Je continue ma lancée avec ce billet traitant d'un sujet important aussi bien en statistique qu'en intelligence artificielle: <strong><a href="https://fr.wikipedia.org/wiki/Maximum_de_vraisemblance">Le maximum de vraisemblance</a></strong>. Je rappelle que je ne suis ni statisticien ni mathématicien et que j'essaie d'expliquer ces concepts avec un simple regard naïf de programmeur. (C'est à dire sans formule …</p><p>Je continue ma lancée avec ce billet traitant d'un sujet important aussi bien en statistique qu'en intelligence artificielle: <strong><a href="https://fr.wikipedia.org/wiki/Maximum_de_vraisemblance">Le maximum de vraisemblance</a></strong>. Je rappelle que je ne suis ni statisticien ni mathématicien et que j'essaie d'expliquer ces concepts avec un simple regard naïf de programmeur. (C'est à dire sans formule de math ;D). <br>
Le maximum de vraisemblance est une méthode statistique permettant de trouver les paramètres d'un modèle de probabilité les plus "<em>vraisemblables</em>" pour expliquer des données observées. On peut comparer cela avec une <a href="https://fr.wikipedia.org/wiki/R%C3%A9gression_lin%C3%A9aire">régression linéaire</a> où l'objectif est d'identifier les paramètres a et b de l'équation y = ax+b. Dans la suite de ce billet, ce ne sera pas les paramètres d'une droite, mais les paramètres d'une <a href="https://fr.wikipedia.org/wiki/Loi_normale">loi normale</a> que nous essayerons de déterminer.</p>
<h3>Nos données observées</h3>
<p>Imaginons une série de valeurs, disons l'âge de 1000 étudiants pris au hasard dans une fac. En traçant l'histogramme de ces données, nous obtenons : </p>
<div class="highlight"><pre><span></span><code><span class="nv">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">np</span>.<span class="k">random</span>.<span class="nv">normal</span><span class="ss">(</span><span class="mi">24</span>,<span class="w"> </span><span class="nv">MYSTERE</span><span class="w"> </span>,<span class="mi">1000</span><span class="ss">)</span><span class="w"></span>
</code></pre></div>
<div class="figure">
<img src="../images/maximum_vraisemblance/normal_dist.png" />
<div class="legend">distribution des âges suivant une loi normale. Les données ont été générées avec np.random.normal. Le paramètre MYSTERE a volontairement été caché</div>
</div>
<p>On peut voir ici que la distribution des valeurs suit approximativement une loi normale avec une moyenne aux alentours de 24 et un écart-type difficile à évaluer au premier coup d'œil. Ce dernier est le paramètre MYSTERE que nous allons découvrir en cherchant l'équation de la loi normale qui s'ajuste au mieux aux données.</p>
<h3>La fonction de la loi normale</h3>
<p>La loi normale a une fonction de densité de probabilité p paramétrée par <strong>mu</strong> et <strong>sigma</strong> définissant respectivement le centre de la courbe (<a href="https://fr.wikipedia.org/wiki/Esp%C3%A9rance_math%C3%A9matique">l'espérance</a>) et sa largeur (<a href="https://fr.wikipedia.org/wiki/Variance_(statistiques_et_probabilit%C3%A9s)">la variance</a>). </p>
<div class="figure">
<img src="../images/maximum_vraisemblance/equation.png" />
<div class="legend">fonction définissant une loi normale</div>
</div>
<p>En python cette fonction est implémentée dans la librairie <a href="https://docs.scipy.org/doc/scipy-0.16.1/reference/generated/scipy.stats.norm.html">scipy</a>. Pour tracer cette fonction, il suffit de faire :</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">scipy</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="nn">plt</span>
<span class="k">def</span> <span class="nf">loi_normale</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">mu</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">,</span><span class="n">sigma</span> <span class="o">=</span> <span class="mi">1</span><span class="p">):</span>
<span class="k">return</span> <span class="n">scipy</span><span class="o">.</span><span class="n">stats</span><span class="o">.</span><span class="n">norm</span><span class="o">.</span><span class="n">pdf</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">loc</span> <span class="o">=</span> <span class="n">mu</span><span class="p">,</span> <span class="n">scale</span><span class="o">=</span><span class="n">sigma</span><span class="p">)</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="o">-</span><span class="mi">10</span><span class="p">,</span><span class="mi">10</span><span class="p">,</span><span class="mf">0.1</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">loi_normale</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span>
</code></pre></div>
<div class="figure">
<img src="../images/maximum_vraisemblance/loi_normale.png" />
<div class="legend">Différentes lois normales d'espérance mu=0 et de variance sigma=2,3,4 et 5</div>
</div>
<p>En faisant varier <em>mu</em> et <em>sigma</em>, vous verrez différentes formes de cloche. Le but est donc de trouver quelles sont les meilleures valeurs de ces deux paramètres pouvant expliquer la distribution de nos données.</p>
<h3>Calcul de la vraisemblance</h3>
<p>Pour faire simple, nous allons uniquement évaluer le paramètre <em>sigma</em> et fixer <em>mu</em> à 24. Pour cela, on va d'abord attribuer à chaque valeur possible de <em>sigma</em> un indicateur appelé <strong>vraisemblance</strong> que l'on note <em>L(sigma)</em>. Cette indicateur est la probabilité d'obtenir notre distribution des âges sous le paramètre <em>sigma</em>. Il s'obtient en faisant le produit de la fonction <em>p(x)</em> pour toute valeur <em>x</em> provenant de nos données observées.</p>
<div class="highlight"><pre><span></span><code>L(sigma) = p(x1) * p(x2) * p(x3) * ....
</code></pre></div>
<p>Son implémentation en python est la suivante : </p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">vraisemblance</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">sigma</span><span class="p">):</span>
<span class="n">L</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">loi_normale</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">mu</span> <span class="o">=</span> <span class="mi">24</span><span class="p">,</span> <span class="n">sigma</span> <span class="o">=</span> <span class="n">sigma</span><span class="p">)</span>
<span class="n">L</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>
<span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">prod</span><span class="p">(</span><span class="n">L</span><span class="p">)</span>
</code></pre></div>
<p>On préfère cependant utiliser le <em>log</em> pour remplacer les multiplications par des additions.</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">log_vraissemblance</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">sigma</span><span class="p">):</span>
<span class="n">L</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">loi_normale</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">mu</span> <span class="o">=</span> <span class="mi">24</span><span class="p">,</span> <span class="n">sigma</span> <span class="o">=</span> <span class="n">sigma</span><span class="p">)</span>
<span class="n">L</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">np</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="n">y</span><span class="p">))</span>
<span class="k">return</span> <span class="n">np</span><span class="o">.</span><span class="n">sum</span><span class="p">(</span><span class="n">L</span><span class="p">)</span>
</code></pre></div>
<h3>Le maximum de vraisemblance</h3>
<p>En réfléchissant 2 minutes, vous comprendrez tout de suite que la valeur idéale de <em>sigma</em> est celle qui va maximiser la vraisemblance. <br>
On peut tout de suite confirmer cette intuition en testant différentes valeurs de sigma et identifier celle dont la vraisemblance est maximale. </p>
<div class="highlight"><pre><span></span><code><span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mf">0.1</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">sigma</span> <span class="ow">in</span> <span class="n">x</span><span class="p">:</span>
<span class="n">y</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">log_vraissemblance</span><span class="p">(</span><span class="n">data</span><span class="p">,</span><span class="n">sigma</span><span class="p">))</span>
<span class="n">plt</span><span class="o">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span>
</code></pre></div>
<div class="figure">
<img src="../images/maximum_vraisemblance/vraisemblance_test.png" />
<div class="legend">Vraisemblance en fonction de sigma</div>
</div>
<p>En recherchant la valeur de sigma qui donne la plus grande vraisemblance, on trouve sigma ~ 2,1</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
<span class="n">df</span><span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">({</span><span class="s2">"x"</span><span class="p">:</span><span class="n">x</span><span class="p">,</span><span class="s2">"y"</span><span class="p">:</span><span class="n">y</span><span class="p">})</span>
<span class="c1"># Liste des valeur x et y</span>
<span class="c1"># 1.0 -3110.531663</span>
<span class="c1"># 1.1 -2825.482705</span>
<span class="c1"># 1.2 -2623.199764</span>
<span class="c1"># 1.3 -2478.103466</span>
<span class="c1"># 1.4 -2373.570530</span>
<span class="c1"># 1.5 -2298.445032</span>
<span class="c1"># 1.6 -2245.033229</span>
<span class="c1"># 1.7 -2207.903507</span>
<span class="c1"># 1.8 -2183.142831</span>
<span class="c1"># 1.9 -2167.881929</span>
<span class="c1"># 2.0 -2159.983996</span>
<span class="c1"># 2.1 -2157.835771 <=</span>
<span class="c1"># 2.2 -2160.204391</span>
<span class="c1"># 2.3 -2166.137473</span>
<span class="c1"># 2.4 -2174.892189</span>
<span class="c1"># 2.5 -2185.884166</span>
<span class="c1"># Ou plus simplement avec idxmax</span>
<span class="n">df</span><span class="o">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s2">"y"</span><span class="p">]</span><span class="o">.</span><span class="n">idxmax</span><span class="p">()]</span>
<span class="c1">#x 2.1</span>
<span class="c1">#y -2157.835771</span>
</code></pre></div>
<p>On peut alors traçer sur la distribution des âges, une fonction normale d'esperance <em>mu</em>=24 et de variance prédis <em>sigma</em>=2.1. Vous constaterez alors que la courbe en cloche s'ajuste parfaitement aux données. Et voilà ! </p>
<div class="figure">
<img src="../images/maximum_vraisemblance/adjusted.png" />
<div class="legend">Modèle ajusté à nos données</div>
</div>
<h3>Conclusion</h3>
<p>L'utilisation dans ce billet d'un algorithme itératif, pour trouver sigma, n'a qu'un but pédagogique. En réalité, pour une loi normale, le maximum de vraisemblance se calcule de manière analytique. C'est à dire avec une formule mathématique. (Il suffit de calculer le point ou la dérivé de L(sigma) s'annule.) Vous trouverez une démonstration <a href="http://www.jybaudot.fr/Inferentielle/exmaxvrais.html">ici</a> pour la loi normale et la loi exponentielle.
En revanche pour des lois plus complexes, on peut être amené à utiliser <a href="https://fr.wikipedia.org/wiki/Algorithme_esp%C3%A9rance-maximisation">l'algorithme d'espérance-maximisation</a> qui permet par exemple d'extraire deux lois normales à partir d'un jeu de données mélangées. J'y reviendrai… Quand j'aurais bien compris !</p>
<p>Merci à @andré pour la relecture !</p>La distribution de χ22018-05-23T22:50:33+02:002018-05-25T00:42:07+02:00Sacha Schutztag:dridk.me,2018-05-23:/la-distribution-de-ki2.html<p>Si vous avez touché un tant soit peu les statistiques, vous connaissez certainement le <a href="https://fr.wikipedia.org/wiki/Loi_du_%CF%87%C2%B2">test de χ²</a>. Et comme moi, vous avez certainement du jongler avec des formules ou des notions comme le "degré de liberté" sans vraiment comprendre d'où ça venait. Ce soir, par un élan de motivation sans précédent …</p><p>Si vous avez touché un tant soit peu les statistiques, vous connaissez certainement le <a href="https://fr.wikipedia.org/wiki/Loi_du_%CF%87%C2%B2">test de χ²</a>. Et comme moi, vous avez certainement du jongler avec des formules ou des notions comme le "degré de liberté" sans vraiment comprendre d'où ça venait. Ce soir, par un élan de motivation sans précédent, je tente de démystifier la loi du χ², avec le regard du simple programmeur !</p>
<h2>Une distribution aléatoire</h2>
<p>Une distribution aléatoire, c'est juste une liste de nombres obtenus par une loi de probabilité. Il en existe plusieurs. Par exemple, si vous voulez générer 10000 nombres, vous pouvez lancer un même dé plusieurs fois. En python ça donnerait qqch de ce genre : </p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">random</span>
<span class="n">x</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10000</span><span class="p">):</span>
<span class="n">x</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">7</span><span class="p">))</span>
<span class="c1"># [2, 1, 6, 3, 5, 6, 2, 3, 6, 3, 3, 1, 5, 1, 1, 5, 3, 4, 4, 1 ....]</span>
</code></pre></div>
<p>Si vous comptez la fréquence de chaque chiffre, c'est à dire combien de fois il y a de 2, de 3 etc ... Vous obtiendrez approximativement 1/6 qui correspond à la probabilité du dé pour chaque chiffre. Cette distribution suit une <a href="https://fr.wikipedia.org/wiki/Loi_de_probabilit%C3%A9">loi de probabilité</a> dite "<a href="https://fr.wikipedia.org/wiki/Loi_uniforme_discr%C3%A8te">uniforme</a>". Graphiquement, ça ressemble à ça :</p>
<div class="figure"> <img src="../images/distribution-ki2/uniform.png" /> <div class="legend"> Distribution uniforme. L'axe des abscisses représente le chiffre et l'axe des ordonnées le nombre de fois que ce chiffre est obtenu </div> </div>
<h3>La distribution normale</h3>
<p>On peut très bien imaginer une autre loi aléatoire ou certains nombres sont choisi préférentiellement à d'autres. La <a href="https://fr.wikipedia.org/wiki/Loi_normale">loi normale</a> en est une. Elle est définie par 2 valeurs ( l'<a href="https://fr.wikipedia.org/wiki/Esp%C3%A9rance_math%C3%A9matique">espérance</a> et la <a href="https://fr.wikipedia.org/wiki/Variance_(statistiques_et_probabilit%C3%A9s)">variance</a> ). Les nombres sont choisis préférentiellement autour de l'espérance et s'écarte plus ou moins fortement avec la variance.<br>
Par exemple, pour générer une distribution de 10000 valeurs avec une espérance de 0 et une variance de 1, on obtiendrait ça: </p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">import</span> <span class="nn">seaborn</span> <span class="k">as</span> <span class="nn">sns</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">1000</span><span class="p">)</span>
<span class="c1">#0.26 -0.38 -1.15 -0.81 1.53 1.11 0.45 -1.09 -0.15 ....</span>
<span class="n">sns</span><span class="o">.</span><span class="n">distplot</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
</code></pre></div>
<div class="figure"> <img src="../images/distribution-ki2/normal.png" /> <div class="legend"> Distribution normale. La majorité des valeurs tourne autour de 0</div> </div>
<h3>La distribution de χ2</h3>
<p>La distribution de χ2 est obtenu en sommant les carrés de k nombres indépendants choisis au hasard dans une distribution normale d'espérance 0 et de variance 1.
Par exemple, tirons aux hasards 2 nombres (xa et xb) depuis la distribution normale vu précédemment et calculons une nouvelle variable X1 comme étant la somme des carrés de xa et xb: Disons -1.15 et 1.53. </p>
<div class="highlight"><pre><span></span><code>X1 = xa^2 + xb^2 = (-1.15)^2 + (1.53)^2 = 3.66
</code></pre></div>
<p>Recommençons, en calculant X2 avex deux nouveaux tirages</p>
<div class="highlight"><pre><span></span><code>X2 = xa^2 + xb^2 = (0.45)^2 + (0.26)^2 = 0.27
</code></pre></div>
<p>Puis X3,X4 et ainsi de suite .... <br>
Cette nouvelle distribution (X1,X2,X3...) suit une loi de χ2 et de degré de liberté k=2. Avec un degré de liberté supérieur, disons 5, nous aurions des tirages de 5 valeurs (xa, xb, xc, xd et xe). C'est simple non ? <br>
Au niveau du code, on peut créer la fonction suivante : </p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">dist_ki2</span><span class="p">(</span><span class="n">ddl</span><span class="p">,</span> <span class="n">size</span><span class="p">):</span>
<span class="sd">''' ddl : degré de liberté </span>
<span class="sd"> size : taille de la distribution à générée</span>
<span class="sd">'''</span>
<span class="n">X</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">x</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">normal</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="n">size</span><span class="p">)</span>
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">size</span><span class="p">):</span>
<span class="n">X</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">sum</span><span class="p">([</span><span class="n">n</span><span class="o">*</span><span class="n">n</span> <span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">np</span><span class="o">.</span><span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">ddl</span><span class="p">)]))</span>
<span class="k">return</span> <span class="n">X</span>
</code></pre></div>
<p>En testant avec différents degrés de liberté :</p>
<div class="highlight"><pre><span></span><code><span class="k">for</span> <span class="n">ddl</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">):</span>
<span class="n">sns</span><span class="o">.</span><span class="n">distplot</span><span class="p">(</span><span class="n">dist_ki2</span><span class="p">(</span><span class="n">ddl</span><span class="p">,</span> <span class="mi">1000</span><span class="p">))</span>
</code></pre></div>
<div class="figure"> <img src="../images/distribution-ki2/ki2_anim.gif" /> <div class="legend"> Différente distribution de ki2 </div> </div>
<p>Essayer pour voir avec un degré de liberté > 100. Vous constaterez qu'on se retrouve avec une distribution d'allure normale d'espérance k et de variance 2k. </p>
<h2>Et donc ?</h2>
<p>Et bien rien de plus ... En tout cas pour le moment. Je voulais surtout comprendre d’où venait cette loi. <br>
<a href="https://fr.wikipedia.org/wiki/Test_du_%CF%87%C2%B2">Le test de χ2 </a> utilise cette distribution pour tester la différence entre des données catégorielles. Je n'ai pas eu le temps de me pencher sur la démonstration mathématique, car ça demande un peu plus de temps. Mais si j'ai la motivation, je compléterai ce billet.</p>Convertir HPO en base de données Sqlite2018-05-08T14:00:45+02:002018-05-08T14:00:45+02:00Sacha schutztag:dridk.me,2018-05-08:/hpo2sqlite.html<p>Pour mon projet <a href="https://github.com/labsquare/CuteVariant">cutevariant</a>, j'ai été amené à devoir convertir l'ontologie <a href="http://human-phenotype-ontology.github.io/">HPO</a> (disponible au format <a href="http://purl.obolibrary.org/obo/hp.obo">obo</a>) en base de données <a href="https://fr.wikipedia.org/wiki/SQLite">SQLite</a>. Pour ceux qui ne connaissent pas, HPO (Human Phenotype Ontology) est une <a href="https://fr.wikipedia.org/wiki/Ontologie">ontologie</a> décrivant des signes cliniques. C'est-à-dire un vocabulaire standardisé et hiérarchisé afin d'aider les ordinateurs à comprendre …</p><p>Pour mon projet <a href="https://github.com/labsquare/CuteVariant">cutevariant</a>, j'ai été amené à devoir convertir l'ontologie <a href="http://human-phenotype-ontology.github.io/">HPO</a> (disponible au format <a href="http://purl.obolibrary.org/obo/hp.obo">obo</a>) en base de données <a href="https://fr.wikipedia.org/wiki/SQLite">SQLite</a>. Pour ceux qui ne connaissent pas, HPO (Human Phenotype Ontology) est une <a href="https://fr.wikipedia.org/wiki/Ontologie">ontologie</a> décrivant des signes cliniques. C'est-à-dire un vocabulaire standardisé et hiérarchisé afin d'aider les ordinateurs à comprendre le charabia des médecins. Si je vous donne par exemple le mot <em>céphalée</em> (maux de tête) il y a un terme anglais <em><a href="http://compbio.charite.de/hpoweb/showterm?id=HP:0000118#id=HP:0002315">Headache</a></em> associé à l'identifiant <a href="http://compbio.charite.de/hpoweb/showterm?id=HP:0000118#id=HP:0002315">HPO:0002315</a>. Ce terme est enfant du terme <em>Abnormality of nervous system physiology</em>, lui même enfant de <em>Abnormality of the nervous system</em>, lui même enfant de <em>Organ abnormality</em> qui est la racine de l'ontologie. Jeter un oeil sur <a href="http://compbio.charite.de/phenomizer/">phenomizer</a> pour explorer cette ontologie. <br>
Afin de réaliser cette transformation (en l'occurrence un fichier hpo.obo en fichier hpo.sqlite), je me suis vu écrire plein de ligne de code et faire du parsing dans tous les sens. Lorsque j'ai réussi à réaliser cette transformation en 10 lignes à peine à l'aide de <a href="https://networkx.github.io/">networkx</a>, c'est à ce moment que j'ai eu la révélation.... Les <a href="https://fr.wikipedia.org/wiki/Graphe">graphes</a> c'est vraiment GÉNIAL !!!!!!!! </p>
<h2>Imbrication d'ensemble</h2>
<p>Les données dans HPO ressemblent à un arbre. Je me suis alors rappelé d'une méthode pour représenter des données hiérarchisées dans une base de données relationnelle qu'on appelle l'<a href="https://fr.wikipedia.org/wiki/Imbrication_d%27ensembles">imbrication d'ensemble</a>. <br>
Naïvement, pour sauvegarder un arbre dans une base de donnée SQL on ferait un truc simple de ce genre:</p>
<div class="highlight"><pre><span></span><code>Table Node
- id (primary key)
- name (string)
- parent (foreign key)
</code></pre></div>
<p>Mais dans ce cas, certaines requêtes peuvent être complexes. Par exemple si vous demandez tous les enfants d'un noeud particulier, cela nécessitera d'écrire une requête récursive gourmande. <br>
La méthode d'imbrication consiste à associer à chaque noeud des bornes droites et gauches correspondant aux indices d'un parcours d'arbre en profondeur. </p>
<div class="highlight"><pre><span></span><code>Table Node
- id (primary key)
- name (string)
- left (integer)
- right (integer)
</code></pre></div>
<p>Par exemple dans l'arbre suivant, on part de la borne gauche (1) de la racine <strong>Food</strong> et on descend l'arbre jusqu'aux feuilles et ainsi de suite, jusqu'à revenir sur la borne droite (18) de la racine. </p>
<div class="figure">
<img src="../images/hpo2sqlite/imbrication.png" />
<div class="legend"> </div>
</div>
<p>Grâce à ça, en une seul requête il est facile d'obtenir tous les enfants d'un noeud. Par exemple pour sélectionner tous les enfants de <strong>fruit</strong>, il suffit de sélectionner tous les noeuds avec une borne gauche <strong>> 2</strong> et une borne droite <strong>< 11</strong>. Facile non ? </p>
<div class="highlight"><pre><span></span><code><span class="k">SELECT</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">node</span><span class="w"> </span><span class="k">WHERE</span><span class="w"> </span><span class="k">left</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="k">right</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="mi">11</span><span class="w"></span>
</code></pre></div>
<h2>Convertion d'un DAG en arbre</h2>
<p>Le problème c'est que l'ontologie HPO n'est pas un arbre. C'est un <a href="https://fr.wikipedia.org/wiki/Graphe_orient%C3%A9_acyclique">graphe orienté acyclique (DAG)</a>. C'est-à-dire que certains noeuds peuvent avoir plusieurs parents. Par chance, la lib <a href="https://networkx.github.io/">networkx</a> en python permet de convertir un DAG en arbre en dupliquant les noeuds qui pose problème. <br>
Prenons un graphe simple avec le noeud D ayant deux parents B et C. </p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">networkx</span> <span class="k">as</span> <span class="nn">nx</span>
<span class="n">g</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">DiGraph</span><span class="p">()</span>
<span class="n">g</span><span class="o">.</span><span class="n">add_nodes_from</span><span class="p">([</span><span class="s2">"A"</span><span class="p">,</span><span class="s2">"B"</span><span class="p">,</span><span class="s2">"C"</span><span class="p">,</span><span class="s2">"D"</span><span class="p">])</span>
<span class="n">g</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="s2">"A"</span><span class="p">,</span><span class="s2">"B"</span><span class="p">)</span>
<span class="n">g</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="s2">"A"</span><span class="p">,</span><span class="s2">"C"</span><span class="p">)</span>
<span class="n">g</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="s2">"B"</span><span class="p">,</span><span class="s2">"D"</span><span class="p">)</span>
<span class="n">g</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="s2">"C"</span><span class="p">,</span><span class="s2">"D"</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx</span><span class="p">(</span><span class="n">g</span><span class="p">)</span>
</code></pre></div>
<div class="figure">
<img src="../images/hpo2sqlite/dag.png" />
<div class="legend"> </div>
</div>
<p>On peut alors transformer ce DAG en arbre avec : </p>
<div class="highlight"><pre><span></span><code><span class="n">tree</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">dag_to_branching</span><span class="p">(</span><span class="n">g</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx</span><span class="p">(</span><span class="n">tree</span><span class="p">)</span>
</code></pre></div>
<div class="figure">
<img src="../images/hpo2sqlite/tree.png" />
<div class="legend"> </div>
</div>
<p>Tous les noeuds ont été renommés avec un identifiant unique et le noeud D a été dupliqué. <br>
Pour savoir à quels noeuds ces identifiants correspondent : </p>
<div class="highlight"><pre><span></span><code><span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">tree</span><span class="o">.</span><span class="n">nodes</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="s2">"source"</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="n">node</span><span class="p">)</span>
<span class="p">(</span><span class="s1">'3b62eb6b-52c0-11e8-87d5-10bf48bcfa69'</span><span class="p">,</span> <span class="s1">'A'</span><span class="p">)</span>
<span class="p">(</span><span class="s1">'3b62eb6c-52c0-11e8-87d5-10bf48bcfa69'</span><span class="p">,</span> <span class="s1">'B'</span><span class="p">)</span>
<span class="p">(</span><span class="s1">'3b62eb6d-52c0-11e8-87d5-10bf48bcfa69'</span><span class="p">,</span> <span class="s1">'D'</span><span class="p">)</span>
<span class="p">(</span><span class="s1">'3b62eb6e-52c0-11e8-87d5-10bf48bcfa69'</span><span class="p">,</span> <span class="s1">'C'</span><span class="p">)</span>
<span class="p">(</span><span class="s1">'3b62eb6f-52c0-11e8-87d5-10bf48bcfa69'</span><span class="p">,</span> <span class="s1">'D'</span><span class="p">)</span>
</code></pre></div>
<h2>Parcours de l'arbre en profondeur</h2>
<p>Pour sauvegarder cet arbre dans une base de donnée SQL, il faut dans un premier temps parcourir l'arbre en profondeur, et associer à chaque noeud les bornes gauche et droite. Pour cela, rien de plus simple avec les algorithmes de parcours en profondeur de networkx (<a href="https://networkx.github.io/documentation/networkx-1.10/reference/algorithms.traversal.html">dfs</a>): </p>
<div class="highlight"><pre><span></span><code><span class="n">index</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">nx</span><span class="o">.</span><span class="n">dfs_labeled_edges</span><span class="p">(</span><span class="n">tree</span><span class="p">):</span>
<span class="n">node_name_1</span> <span class="o">=</span> <span class="n">i</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">node_name_2</span> <span class="o">=</span> <span class="n">i</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">sens</span> <span class="o">=</span> <span class="n">i</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="k">if</span> <span class="n">sens</span> <span class="o">==</span> <span class="s2">"forward"</span><span class="p">:</span>
<span class="n">tree</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">node_name_2</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="s2">"left"</span><span class="p">:</span> <span class="n">index</span><span class="p">})</span>
<span class="k">if</span> <span class="n">sens</span> <span class="o">==</span> <span class="s2">"reverse"</span><span class="p">:</span>
<span class="n">tree</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">node_name_2</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="s2">"right"</span><span class="p">:</span> <span class="n">index</span><span class="p">})</span>
<span class="n">index</span><span class="o">+=</span><span class="mi">1</span>
</code></pre></div>
<p>Au final, il suffit de reparcourir l'arbre et faire des INSERT SQL pour chaque noeud. <br>
Étant donné qu'il y a des noeuds dupliqués, il est plus intéressant de créer 2 tables. L'une contenant les noeuds réels (Nodes) et l'autre contenant les noeuds dupliqués (Trees). On peut également rajouter comme information la profondeur du noeud dans l'arbre ainsi que son noeud parent.</p>
<div class="highlight"><pre><span></span><code>Table Nodes
- id (primary key)
- name (string)
Table Trees
- id (primary key)
- node_id (foreign key)
- left (int)
- right (int)
- depth (int)
- parent_id (foreign_key)
</code></pre></div>
<h2>Hpo2Sqlite sur github</h2>
<p>Le code source pour convertir hpo.obo en hpo.sqlite, ainsi que la base de données sqlite sont dispo à ces adresses:</p>
<ul>
<li><a href="https://github.com/dridk/hpo2sqlite">https://github.com/dridk/hpo2sqlite</a></li>
<li><a href="https://github.com/dridk/hpo2sqlite/releases">https://github.com/dridk/hpo2sqlite/releases</a></li>
</ul>
<p>Cette méthode est compatible avec l'ontologie HPO parce que toutes les relations sont de type "is_a". Donc en théorie, pour n'importe quelle autre ontologie du même type, cet algorithme peut fonctionner. </p>
<p>PS:
Merci à mes profs Olivier Dameron (ontologie) et Emmanuelle Becker (Graphe) de m'avoir appris toutes ces notions!</p>Les TADs et l'organisation spatiale du génome2018-05-08T11:12:11+02:002018-05-08T12:32:09+02:00Sacha schutztag:dridk.me,2018-05-08:/tad.html<p>Lors de la <a href="https://fr.wikipedia.org/wiki/Mitose">mitose</a>, l'ADN des cellules <a href="https://fr.wikipedia.org/wiki/Eukaryota">eucaryotes</a> s'organise en <a href="https://fr.wikipedia.org/wiki/Chromosome">chromosomes</a> condensés et bien délimités. C'est l'image que nous avons tous d'un chromosome. Mais le reste du temps, pendant l'<a href="https://fr.wikipedia.org/wiki/Interphase">interphase</a>, ces chromosomes ressemblent davantage à une boule de spaghetti emmêlée dans tous les sens : ce que l'on appelle la …</p><p>Lors de la <a href="https://fr.wikipedia.org/wiki/Mitose">mitose</a>, l'ADN des cellules <a href="https://fr.wikipedia.org/wiki/Eukaryota">eucaryotes</a> s'organise en <a href="https://fr.wikipedia.org/wiki/Chromosome">chromosomes</a> condensés et bien délimités. C'est l'image que nous avons tous d'un chromosome. Mais le reste du temps, pendant l'<a href="https://fr.wikipedia.org/wiki/Interphase">interphase</a>, ces chromosomes ressemblent davantage à une boule de spaghetti emmêlée dans tous les sens : ce que l'on appelle la <a href="https://fr.wikipedia.org/wiki/Chromatine">chromatine</a>. <br>
Aujourd'hui, les technologies de <a href="https://en.wikipedia.org/wiki/Chromosome_conformation_capture">Capture de Conformation des Chromosomes</a> nous révèlent l'organisation spatiale de cette chromatine, qui en réalité semble loin de l'anarchie mais plutôt organisée de façon fonctionnelle. C'est ce que nous allons découvrir tout de suite avec les <a href="https://en.wikipedia.org/wiki/Topologically_associating_domain">TADs</a> (Topologically Associated Domain).</p>
<h2>Analyser l'organisation spatiale de la chromatine</h2>
<p>Il existe toute une famille de technologies permettant d'évaluer l'organisation spatiale des chromosomes au moment de l'interphase. C'est la <a href="https://en.wikipedia.org/wiki/Chromosome_conformation_capture">Capture de Conformation des chromosomes (Chromosom Conformation Capture)</a>. Cette méthode se décline sous plusieurs formes que vous trouverez sous le nom de <a href="https://en.wikipedia.org/wiki/Chromosome_conformation_capture#Original_methods">(3C,4C,5C,HiC,ChiA-PET)</a>. Elles reposent toutes sur le même principe qui est d'identifier sur la chromatine, des régions en contact physique.
Imaginez la chromatine comme un long ruban d'ADN, formant plein de boucles en se repliant sur elle-même. Par ces technologies, vous allez pouvoir savoir qu'une région <strong>x</strong> de ce ruban est en contact physique avec une autre région <strong>y</strong>. </p>
<div class="figure">
<img src="../images/tad/principe.png" />
<div class="legend">Figure 1. Haut. Vision linéaire du génome. Bas. Vision spatiale du génome et identification d'une zone de contact (orange)</div>
</div>
<h3>Comment ça fonctionne ?</h3>
<p>L'idée générale consiste à capturer les deux régions d'ADN en contact (<strong>x</strong> et <strong>y</strong>) et construire un fragment d'ADN hybride contenant le fragment <strong>x</strong> à une extrémité et le fragment <strong>y</strong> de l'autre (Figure 2). Ce fragment hybride est alors identifié par différents techniques de biologie moléculaire. <br>
Tout d'abord, les régions de contact sont figées en créant des liaisons covalentes grâce à du <a href="https://en.wikipedia.org/wiki/Formaldehyde">formaldéhyde</a>. C'est l'étape du <em>cross-linking</em>. L'ADN est ensuite digéré avec des <a href="https://fr.wikipedia.org/wiki/Enzyme_de_restriction">enzymes de restriction</a> pour ne garder que les régions de contact. Puis on réalise une <a href="https://fr.wikipedia.org/wiki/Ligase">ligation</a> des extrémités du cross-link pour obtenir des fragments d'ADN hybrides.
Ces fragments peuvent alors être identifiés par les différentes méthodes de biologie moléculaire. Par exemple, la méthode 3C est une simple <a href="https://fr.wikipedia.org/wiki/R%C3%A9action_en_cha%C3%AEne_par_polym%C3%A9rase">PCR</a> tandis que la méthode <a href="https://en.wikipedia.org/wiki/Chromosome_conformation_capture#Hi-C_(all-vs-all)">Hi-C</a> est un <a href="ngs.html">séquençage haut débit</a> de l' ensemble de fragments hybrides obtenus à partir d'un génome. C'est cette dernière que je vais détailler.</p>
<div class="figure">
<img src="../images/tad/methode.png" />
<div class="legend">Figure 2. Fixation des régions de contact avec du formaldéhyde (cross-linking) puis digestion de l'ADN avec une enzyme de restriction. Grâce à une ligase, les deux extrémités du cross-link sont reliées. Après un reverse cross-linking, le fragment hybride est obtenu. Celui-ci va pouvoir être séquencé en paired-end sur de <a href="https://www.illumina.com/science/technology/next-generation-sequencing/paired-end-vs-single-read-sequencing.html">l'Illumina</a>. Le read R1 correspondra à la région x et le read R2 à la région y.</div>
</div>
<h3>Méthode Hi-C</h3>
<p>À partir de la méthode décrite au-dessus, on va pouvoir créer une <a href="ngs.html">libraire</a> de séquençage, c'est-à-dire générer un ensemble de fragments hybrides correspondant à l'ensemble des zones de contact de la chromatine. Cette librairie est lue sur un séquenceur <a href="https://fr.wikipedia.org/wiki/Illumina">Illumina</a> qui a la particularité de faire du <a href="https://www.france-genomique.org/spip/spip.php?article235">séquençage en paire</a> <em>(paired-end)</em>, c'est-à-dire pouvoir lire un fragment d'ADN dans les deux sens. Pour chaque fragment d'ADN lu, nous obtenons ainsi une paire de reads <strong>R1</strong> et <strong>R2</strong> qui correspondent aux deux régions de contact <strong>x</strong> et <strong>y</strong> (Figure 2). On aligne ces reads sur <a href="naviguer-dans-votre-adn.html">le génome de référence</a> afin de leur attribuer des coordonnées génomiques. Connaissant les paires de reads, nous pouvons enfin savoir si une région <strong>x</strong> est en contact avec une région <strong>y</strong>. <br>
Par exemple, si dans nos données, il existe un read <strong>R1</strong> s'alignant sur le gène <em>A</em> et un read <strong>R2</strong> s'alignant sur le gène <em>B</em>, nous pouvons "conclure" qu'il y a interaction entre le gène <em>A</em> et le gène <em>B</em>. </p>
<h3>Visualiser les données Hi-C</h3>
<p>Pour représenter l'ensemble des régions de contact provenant d'une expérience Hi-C, on utilise une carte de chaleur (<a href="https://en.wikipedia.org/wiki/Heat_map">heatmap</a>). Cette carte est une matrice n x n montrant le nombre d'interactions entre deux positions données du même chromosome. La technologie ne permettant pas d'avoir une résolution à la base exacte, les positions sont des intervalles de taille fixe.
La valeur de chaque cellule est le nombre de paires de reads entre deux positions données. Plus la couleur d'une cellule est rouge, plus il y a d'interaction entre les deux positions correspondant à cette cellule. <br>
La figure 3 gauche, montre comment construire une <em>heatmap</em> pour un chromosome. La figure 3 droite, montre une <em>heatmap</em> sur des données réelles Hi-C pour le chromosome 14. La diagonale rouge vif signifie que les régions très proches dans la séquence, sont en contact physique, ce qui semble logique. Notons par ailleurs que la matrice est symétrique. En effet, "<strong>x</strong>" interagit avec "<strong>y</strong>", est équivalent à "<strong>y</strong>" interagit avec "<strong>x</strong>". Pour cette raison, on préfère représenter les données Hi-C par une demi <em>heatmap</em>, ce qui nous donne un triangle (figure 4).</p>
<div class="figure">
<img src="../images/tad/tad_correlation_matrix.png" />
<div class="legend">Figure 3. Gauche : le chromosome est découpé en intervalles de taille fixe. Après alignement, chaque read est associé à un intervalle. On comptabilise alors le nombre de paires existantes pour deux intervalles donnés. Sur la figure de gauche, il y a 2 paires entre les deux extrémités "p" et une paire entre l'extrémité "p" et "q". Droite : données réelles Hi-C sur le chromosome 14. Notez la symétrie de la matrice autour de la diagonale ainsi qu'une allure en damier. <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2858594/">source</a> </div>
</div>
<h2>Les TADs</h2>
<p>En observant la heatmap de plus près (Figure 4), vous distinguerez des triangles rouges d'allure fractale qui ressortent clairement. Ces triangles correspondent à un ensemble de régions qui interagissent toutes ensemble mais qui sont isolées du reste. Ces domaines, ce sont nos fameux TAD. Imaginez-les comme des boules de noeud sur notre ruban D'ADN. Chaque noeud contient des régions qui interagissent avec les autres régions de ce même noeud mais jamais avec d'autres. Pour vous faire une idée, deux TADs sont magnifiquement illustrés par mes soins en bas de la figure 4.</p>
<div class="figure">
<img src="../images/tad/tad_ex.png" />
<div class="legend">Figure 4. Visualisation d'une région du chromosome 3. Les TADs sont des domaines qui interagissent et sont observés ici par des triangles rouges. Sur cette figure, la région x,y et z sont à egale distance les unes des autres. Cependant x et y appartiennent au même TAD tandis que z appartient à un autre différent. <a href="http://promoter.bx.psu.edu/hi-c/">source</a> </div>
</div>
<h3>Fonction des TADs</h3>
<p>Aujourd'hui, la fonction des TAD n'est pas totalement élucidée. Mais il est clair qu'ils jouent un rôle important dans la <a href="https://fr.wikipedia.org/wiki/R%C3%A9gulation_de_l%27expression_des_g%C3%A8nes">régulation de l'expression des gènes</a>. Nous savons depuis longtemps que les gènes sont régulés par des séquences <a href="https://fr.wikipedia.org/wiki/Promoteur_(biologie)">promotrices</a> situées en amont des gènes. Mais il existe aussi des régions très éloignées du gène qui peuvent moduler la transcription. Ce sont les <a href="https://fr.wikipedia.org/wiki/Amplificateur_(biologie)">amplificateurs (enhancers)</a> et les <a href="https://fr.wikipedia.org/wiki/Inactivateur">inactivateurs (silencers)</a> qui respectivement activent ou répriment la <a href="https://fr.wikipedia.org/wiki/Transcription_(biologie)">transcription</a>. Par exemple, en repliant l'ADN dans l'espace, l'enhancer et le promoteur vont pouvoir interagir et moduler la transcription (Figure 5). </p>
<div class="figure">
<img src="../images/tad/regulation.png" />
<div class="legend">Figure 5. Schéma de la régulation de la transcription via les amplificateurs. En se répliant, l'ADN met en contact l'amplificateur et le promoteur d'un gène.</div>
</div>
<p>Il est alors évident que pour agir, un amplificateur doit se situer dans le même TAD que ses gènes cibles. Plusieurs gènes au sein du même TAD peuvent ainsi être co-régulés par le même amplificateur. </p>
<div class="figure">
<img src="../images/tad/regulation_tad.png" />
<div class="legend">Figure 6. Un amplificateur peut interagir avec les gènes de son TAD mais pas avec un autre. </div>
</div>
<p>Une autre région importante dans la régulation est <a href="https://fr.wikipedia.org/wiki/Isolateur_(biologie)">l'isolateur (insulator)</a> qui se situe entre deux TAD en empêchant leur fusion. Une <a href="https://www.ncbi.nlm.nih.gov/pubmed/25701871">étude</a> a par exemple montré qu'une délétion dans un isolateur est responsable de la fusion de deux TADs en un seul. Les deux noeuds bien distincts ne forment plus qu'un seul gros noeuds. Les enhancers du premier TAD sont alors capables d'interagir avec un gène du deuxième TAD, entraînant une sur-expression délétère pour l'organisme. </p>
<h3>Formation des TADs</h3>
<p>La formation des TADs a été récemment mise en évidence en validant le modèle de <a href="https://www.sciencedirect.com/science/article/pii/S2211124716305307">Loop extrusion</a>. Ce mécanisme fait intervenir la <a href="https://fr.wikipedia.org/wiki/Coh%C3%A9sine">cohésine</a> et les protéines <a href="https://fr.wikipedia.org/wiki/CTCF">CTCF</a> qui reconnaissent des motifs autour des TADs, et font glisser la chromatine au travers d'anneaux. Les deux vidéos suivantes vous montrent clairement la formation de ces structures.</p>
<div class="figure">
<iframe width="560" height="315" src="https://www.youtube.com/embed/Tn5qgEqWgW8?start=23" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<div class="legend"> Simulation du modèle Loop extrusion </div>
</div>
<div class="figure">
<iframe width="560" height="315" src="https://www.youtube.com/embed/47v3RLfLXho" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<div class="legend"> Visualisation de Loop extrusion temps-réel </div>
</div>
<h2>Conclusion</h2>
<p>La découverte d'une organisation spatiale de la chromatine a changé notre vision du génome. Les chromosomes étaient le support rigide de l'information génétique. Ils sont maintenant les acteurs d'une régulation fine contrôlé par l'épigénétique. L'exploration dans ce domaine nous permettra de mieux comprendre le fonctionnement du génome dans son intégralité, et justifiera certainement le séquençage complet des patients atteints de maladies génétiques.</p>
<h2>Références</h2>
<ul>
<li><a href="https://dumas.ccsd.cnrs.fr/dumas-01628629/document">La thèse d'un collègue </a></li>
<li><a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4556012/">Analysis methods for studying the 3D architecture of the genome</a></li>
<li><a href="https://www.nature.com/articles/nature11082">Topological domains in mammalian genomes identified by analysis of chromatin interactions</a></li>
<li><a href="http://bioinformaticsinstitute.ru/sites/default/files/tad_calling_methods_part_1_-_sidorov_16-dec-2016.pdf">bioinformaticsinstitute</a></li>
<li><a href="https://bioinfo-fr.net/hi-c-explication-des-bases">bioinfo-fr</a></li>
<li><a href="http://3dgb.cbi.pku.edu.cn/disease/">Outil: TAD disease</a></li>
<li><a href="http://promoter.bx.psu.edu/hi-c/">Outil: Hi-C Browser</a></li>
</ul>ADN et jeu du chaos2017-12-17T21:30:00+01:002017-12-17T21:30:00+01:00Sacha schutztag:dridk.me,2017-12-17:/adn-et-jeu-du-chaos.html<p>Vous connaissez le <a href="https://fr.wikipedia.org/wiki/Jeu_du_chaos">jeu du chaos</a>? Il s'agit d'une construction géométrique très simple permettant de faire apparaitre des fractales. La construction la plus connue est le <a href="https://fr.wikipedia.org/wiki/Triangle_de_Sierpi%C5%84ski">triangle de Sierpinski</a> que vous pouvez dessiner vous-même avec un papier et un crayon: </p>
<ul>
<li>Dessiner un triangle en numérotant les trois sommets A,B …</li></ul><p>Vous connaissez le <a href="https://fr.wikipedia.org/wiki/Jeu_du_chaos">jeu du chaos</a>? Il s'agit d'une construction géométrique très simple permettant de faire apparaitre des fractales. La construction la plus connue est le <a href="https://fr.wikipedia.org/wiki/Triangle_de_Sierpi%C5%84ski">triangle de Sierpinski</a> que vous pouvez dessiner vous-même avec un papier et un crayon: </p>
<ul>
<li>Dessiner un triangle en numérotant les trois sommets A,B,C. </li>
<li>Puis dessiner dedans un point P choisi au hasard . </li>
<li>Tirer alors un nombre aléatoire correspondant à A,B ou C. </li>
<li>Si par exemple vous tirez le A, dessiner le point correspondant au milieu du segment [PA].</li>
<li>Ce nouveau point appelez le P, puis répéter la procédure de façon itérative en partant du nouveau point. </li>
</ul>
<p>Si tout se passe bien, et avec beaucoup de temps, vous devrez voir apparaitre le triangle de Sierpinski. </p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/IGlGvSXkRGI" frameborder="0" gesture="media" allow="encrypted-media" allowfullscreen></iframe>
<h2>Le jeu du chaos appliqué à l'ADN</h2>
<p>Au lieu d'utiliser un dé, nous pouvons utiliser une séquence d'ADN pour choisir les sommets avec cette fois un carré ou chaque sommet correspond aux nucléotides A,C,G,T. Pour chaque base lue dans la séquence, dessiner le point correspondant au centre du segment [P-nucléotide] puis continuer comme vu précédement jusqu'au dernier nucléotide. </p>
<div class="figure"> <img src="../images/fractal_dna/CGR_DNA.png" /> <div class="legend">Construction d'une CGR pour la séquence CGT. A partir du centre, trouver le point P2 centre du segment [P1-C]. Puis P3 centre du segment [P2-G] et enfin P4 centre de [P3-T].</div> </div>
<p>Avec un programme informatique c'est plus rapide. On peut alors executer l'algorithme sur de très longues séquences comme des génomes entiers. Et ça donne de très jolies images:</p>
<div class="figure"> <img src="../images/fractal_dna/CGR_exemple.png" /> <div class="legend">Exemple de CGR obtenu à partir de plusieurs espèces. <a href="https://bmcbioinformatics.biomedcentral.com/articles/10.1186/s12859-016-1157-8">source</a></div> </div>
<p>Pour comprendre ces graphiques appelés <a href="https://www.ncbi.nlm.nih.gov/pubmed/2336393">CGR</a> (Chaos Game Representation), garder à l'esprit qu'à chaque point correspond une partie de la séquence lue. Par exemple il y a un point correspondant aux 4 premiers nucléotides et un autre point correspondant aux 20 premiers nucléotides. Si vous réfléchissez un peu, vous devinerez que toutes séquences commençant par un A dessine un point dans le quart inférieur gauche, celles commençant par un G dans le quart supérieur droit, ainsi de suite. Mais nous pouvons aller encore plus loin. Toutes les séquences commençant par CG, se trouvent dans le quart supérieur gauche du quart droit. Toutes les séquences commençant par TAG, dans le quart inférieur droit, du quart inférieur gauche, du quart supérieur droit. Cette dichotomie illustrée sur la figure ci-dessous permet d'associer à chaque séquence une coordonnée unique. Et si vous n'avez pas compris, allez faire un tour sur <a href="http://ws.g-language.org/db/cgr/NT_011512/">cette page</a> et tapper n'importe quel séquence dans la barre de recherche.</p>
<div class="figure"> <img src="../images/fractal_dna/CGR_zoom.png" /> <div class="legend">Dichotomie de la CGR. Par exemple, toutes les séquences commencant par TAG se trouve dans une zone précise.</div> </div>
<h2>Une méthode pour compresser l'ADN</h2>
<p>À part être jolie, à quoi ça sert ? Et bien plusieurs choses. Cette représentation apporte une information globale (sur toute la séquence) et une information locale (sur le contenu de la séquence). Par exemple, sur la figure suivante, vous pouvez voir un "trou" dans le quart G (supérieure droite). Ce motif se répète à plusieurs échelles ( dans les sous-quarts) et correspond à une dispersion des répétitions CG. ( <a href="https://www.ncbi.nlm.nih.gov/pubmed/2336393">Ce pattern serait observé uniquement chez les vertébrés</a> ). </p>
<div class="figure"> <img src="../images/fractal_dna/game7.png" /> <div class="legend">CGR d'une région contenant le gène de la beta globuline sur le chromosome 11. <a href="https://www.ncbi.nlm.nih.gov/pubmed/2336393"> source </a> </div> </div>
<p>On peut s'en servir aussi <a href="https://bmcbioinformatics.biomedcentral.com/articles/10.1186/s12859-016-1157-8">comme une signature</a>. Ou encore pour visualiser des réarrangements... <br>
Mais ce que je préfère c'est l'utilisation de cet algorithme pour compresser une séquence d'ADN. En effet, plus haut je vous ai dit qu'à chaque séquence il y a un unique point. Par exemple avec la séquence ACGT, les coordonnées du dernier point sont unique à la séquence. Il n'y a que la séquence ACGT qui permet de produire ce point. On peut donc représenter n'importe quelle séquence par un couple de coordonnées (x,y) ! <br>
Avec l'algorithme que nous venons de voir et nos ordinateurs actuels nous pouvons compresser 32 nucléotides en utilisant un couple de nombres à virgule (x,y). C'est pas mal, mais il y a mieux. Un <a href="https://arxiv.org/abs/1712.04546">article récent</a> montre qu'il est possible de compresser 1024 nucléotides avec un couple d'entiers (x,y) en modifiant la méthode de calcul. Au lieu de calculer le milieu d'un segment, la somme entre les deux points est calculé en utilisant une puissance de 2 dans l'équation. <br>
N'importe quelle séquence de moins de 1024 nucléotides peut ainsi être écrite en utilisant 3 nombres : la longueur de la séquence, et les coordonnées x, y.<br>
On pourrait alors très bien imaginer un algorithme, qui découpe une très longue séquence d'ADN en bloc de 1024 nucléotides et compresse chaque morceau avec l'ensemble mis bout à bout. Génial non ? </p>
<div class="highlight"><pre><span></span><code>Ceci est une séquence de 3072 (1024*3) nucléotides écrit sur une ligne!!!
(52332,12313)(5744,14)(1242,75575)
</code></pre></div>
<h2>Source</h2>
<ul>
<li><a href="http://www.lifenscience.com/bioinformatics/chaos-game-representation">lifenscence</a></li>
<li><a href="https://www.ncbi.nlm.nih.gov/pubmed/2336393">Chaos game representation of gene structure.(Jeffrey, H. J. 1990).</a></li>
<li><a href="https://bmcbioinformatics.biomedcentral.com/articles/10.1186/s12859-016-1157-8">Additive methods for genomic signatures</a></li>
<li><a href="https://arxiv.org/abs/1712.04546">Encoding DNA sequences by integer chaos game representation</a></li>
</ul>
<h2>Remerciements</h2>
<p>Merci à @Natir pour cette découverte</p>Les algorithmes avec la STL2017-12-11T17:16:31+01:002017-12-11T17:16:31+01:00Sacha schutztag:dridk.me,2017-12-11:/cpp-stl-1.html<p>J'utilise de plus en plus dans mon code C++, les <a href="http://en.cppreference.com/w/cpp/algorithm">algorithmes</a> de la <a href="https://fr.wikipedia.org/wiki/Standard_Template_Library">librairie standard</a>. Couplés avec les <a href="http://fr.cppreference.com/w/cpp/language/lambda">lambdas expression</a>, j'évite d'écrire des tas de boucles for, et mon code est plus lisible. Sans oublier que cette programmation générique est compatible avec les containers <a href="https://www.qt.io/">Qt</a>. Donc forcément, j'adore. <br>
Voici donc …</p><p>J'utilise de plus en plus dans mon code C++, les <a href="http://en.cppreference.com/w/cpp/algorithm">algorithmes</a> de la <a href="https://fr.wikipedia.org/wiki/Standard_Template_Library">librairie standard</a>. Couplés avec les <a href="http://fr.cppreference.com/w/cpp/language/lambda">lambdas expression</a>, j'évite d'écrire des tas de boucles for, et mon code est plus lisible. Sans oublier que cette programmation générique est compatible avec les containers <a href="https://www.qt.io/">Qt</a>. Donc forcément, j'adore. <br>
Voici donc quelques fonctions que j'utilise à foison: </p>
<h2>Copier un vecteur A dans un vecteur B</h2>
<div class="highlight"><pre><span></span><code><span class="nt">std</span><span class="p">::</span><span class="nd">vector</span><span class="o"><</span><span class="nt">int</span><span class="o">></span><span class="w"> </span><span class="nt">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="err">1,2,3,4,5,6</span><span class="p">}</span><span class="o">;</span><span class="w"></span>
<span class="nt">std</span><span class="p">::</span><span class="nd">vector</span><span class="o"><</span><span class="nt">int</span><span class="o">></span><span class="w"> </span><span class="nt">b</span><span class="o">;</span><span class="w"></span>
<span class="nt">std</span><span class="p">::</span><span class="nd">copy</span><span class="o">(</span><span class="nt">a</span><span class="p">.</span><span class="nc">begin</span><span class="o">(),</span><span class="w"> </span><span class="nt">a</span><span class="p">.</span><span class="nc">end</span><span class="o">(),</span><span class="w"> </span><span class="nt">std</span><span class="p">::</span><span class="nd">back_inserter</span><span class="o">(</span><span class="nt">b</span><span class="o">));</span><span class="w"></span>
<span class="o">//</span><span class="w"> </span><span class="nt">b</span><span class="w"> </span><span class="nt">est</span><span class="w"> </span><span class="nt">égal</span><span class="w"> </span><span class="nt">à</span><span class="w"> </span><span class="p">{</span><span class="err">1,2,3,4,5,6</span><span class="p">}</span><span class="w"></span>
</code></pre></div>
<h2>Insérer un vecteur B dans un vecteur A à la position 3</h2>
<div class="highlight"><pre><span></span><code><span class="nt">std</span><span class="p">::</span><span class="nd">vector</span><span class="o"><</span><span class="nt">int</span><span class="o">></span><span class="w"> </span><span class="nt">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="err">1,2,3,4,5,6</span><span class="p">}</span><span class="o">;</span><span class="w"></span>
<span class="nt">std</span><span class="p">::</span><span class="nd">vector</span><span class="o"><</span><span class="nt">int</span><span class="o">></span><span class="w"> </span><span class="nt">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="err">0,0,0</span><span class="p">}</span><span class="o">;</span><span class="w"></span>
<span class="nt">std</span><span class="p">::</span><span class="nd">copy</span><span class="o">(</span><span class="nt">b</span><span class="p">.</span><span class="nc">begin</span><span class="o">(),</span><span class="w"> </span><span class="nt">b</span><span class="p">.</span><span class="nc">end</span><span class="o">(),</span><span class="w"> </span><span class="nt">std</span><span class="p">::</span><span class="nd">inserter</span><span class="o">(</span><span class="nt">a</span><span class="o">,</span><span class="w"> </span><span class="nt">a</span><span class="p">.</span><span class="nc">begin</span><span class="o">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nt">3</span><span class="o">));</span><span class="w"></span>
<span class="o">//</span><span class="w"> </span><span class="nt">a</span><span class="w"> </span><span class="nt">est</span><span class="w"> </span><span class="nt">égal</span><span class="w"> </span><span class="nt">à</span><span class="w"> </span><span class="p">{</span><span class="err">1,</span><span class="w"> </span><span class="err">2,</span><span class="w"> </span><span class="err">3,</span><span class="w"> </span><span class="err">0,</span><span class="w"> </span><span class="err">0,</span><span class="w"> </span><span class="err">0,</span><span class="w"> </span><span class="err">4,</span><span class="w"> </span><span class="err">5,</span><span class="w"> </span><span class="err">6</span><span class="p">}</span><span class="w"></span>
</code></pre></div>
<h2>Calculer la dérivée d'une fonction</h2>
<div class="highlight"><pre><span></span><code><span class="nt">std</span><span class="p">::</span><span class="nd">vector</span><span class="o"><</span><span class="nt">double</span><span class="o">></span><span class="w"> </span><span class="nt">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="err">0,1,4,9,16,25,36</span><span class="p">}</span><span class="o">;</span><span class="w"></span>
<span class="nt">std</span><span class="p">::</span><span class="nd">vector</span><span class="o"><</span><span class="nt">double</span><span class="o">></span><span class="w"> </span><span class="nt">b</span><span class="o">;</span><span class="w"></span>
<span class="nt">std</span><span class="p">::</span><span class="nd">adjacent_difference</span><span class="o">(</span><span class="nt">a</span><span class="p">.</span><span class="nc">begin</span><span class="o">(),</span><span class="nt">a</span><span class="p">.</span><span class="nc">end</span><span class="o">(),</span><span class="w"></span>
<span class="w"> </span><span class="nt">std</span><span class="p">::</span><span class="nd">back_inserter</span><span class="o">(</span><span class="nt">b</span><span class="o">),</span><span class="w"></span>
<span class="w"> </span><span class="cp">[]</span><span class="o">(</span><span class="nt">double</span><span class="w"> </span><span class="nt">a</span><span class="o">,</span><span class="nt">double</span><span class="w"> </span><span class="nt">b</span><span class="o">)</span><span class="p">{</span><span class="err">return</span><span class="w"> </span><span class="err">(a-b)/2</span><span class="p">;}</span><span class="o">);</span><span class="w"></span>
<span class="o">//</span><span class="w"> </span><span class="nt">a</span><span class="w"> </span><span class="nt">est</span><span class="w"> </span><span class="nt">une</span><span class="w"> </span><span class="nt">parabole</span><span class="w"> </span><span class="nt">x</span><span class="o">^</span><span class="nt">2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="err">0,1,4,9,16,25,36</span><span class="p">}</span><span class="o">;</span><span class="w"></span>
<span class="o">//</span><span class="w"> </span><span class="nt">b</span><span class="w"> </span><span class="nt">est</span><span class="w"> </span><span class="nt">la</span><span class="w"> </span><span class="nt">dérivé</span><span class="w"> </span><span class="nt">de</span><span class="w"> </span><span class="nt">x</span><span class="o">^</span><span class="nt">2</span><span class="o">,</span><span class="w"> </span><span class="nt">soit</span><span class="w"> </span><span class="nt">une</span><span class="w"> </span><span class="nt">droite</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="err">0,</span><span class="w"> </span><span class="err">0.5,</span><span class="w"> </span><span class="err">1.5,</span><span class="w"> </span><span class="err">2.5,</span><span class="w"> </span><span class="err">3.5,</span><span class="w"> </span><span class="err">4.5,</span><span class="w"> </span><span class="err">5.5</span><span class="p">}</span><span class="w"></span>
</code></pre></div>
<h2>Supprimer toutes les valeurs superieurs à 4</h2>
<div class="highlight"><pre><span></span><code><span class="nt">std</span><span class="p">::</span><span class="nd">vector</span><span class="o"><</span><span class="nt">int</span><span class="o">></span><span class="w"> </span><span class="nt">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="err">0,1,4,9,16,25,36</span><span class="p">}</span><span class="o">;</span><span class="w"></span>
<span class="nt">a</span><span class="p">.</span><span class="nc">erase</span><span class="o">(</span><span class="nt">std</span><span class="p">::</span><span class="nd">remove_if</span><span class="o">(</span><span class="nt">a</span><span class="p">.</span><span class="nc">begin</span><span class="o">(),</span><span class="nt">a</span><span class="p">.</span><span class="nc">end</span><span class="o">(),</span><span class="cp">[]</span><span class="o">(</span><span class="nt">int</span><span class="w"> </span><span class="nt">v</span><span class="o">)</span><span class="p">{</span><span class="err">return</span><span class="w"> </span><span class="err">v</span><span class="w"> </span><span class="err">></span><span class="w"> </span><span class="err">4</span><span class="p">;}</span><span class="o">),</span><span class="w"> </span><span class="nt">a</span><span class="p">.</span><span class="nc">end</span><span class="o">());</span><span class="w"></span>
<span class="o">//</span><span class="w"> </span><span class="nt">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="err">0,1,4</span><span class="p">}</span><span class="w"></span>
</code></pre></div>
<h2>Elever les valeurs d'un vecteur à la puissance 2</h2>
<div class="highlight"><pre><span></span><code><span class="nt">std</span><span class="p">::</span><span class="nd">vector</span><span class="o"><</span><span class="nt">int</span><span class="o">></span><span class="w"> </span><span class="nt">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="err">1,2,3,4,5,6,7</span><span class="p">}</span><span class="o">;</span><span class="w"></span>
<span class="nt">std</span><span class="p">::</span><span class="nd">transform</span><span class="o">(</span><span class="nt">a</span><span class="p">.</span><span class="nc">begin</span><span class="o">(),</span><span class="nt">a</span><span class="p">.</span><span class="nc">end</span><span class="o">(),</span><span class="w"> </span><span class="nt">a</span><span class="p">.</span><span class="nc">begin</span><span class="o">(),</span><span class="w"> </span><span class="cp">[]</span><span class="o">(</span><span class="nt">int</span><span class="w"> </span><span class="nt">v</span><span class="o">)</span><span class="p">{</span><span class="err">return</span><span class="w"> </span><span class="err">v*v</span><span class="p">;}</span><span class="o">);</span><span class="w"></span>
<span class="o">//</span><span class="w"> </span><span class="nt">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="err">1,</span><span class="w"> </span><span class="err">4,</span><span class="w"> </span><span class="err">9,</span><span class="w"> </span><span class="err">16,</span><span class="w"> </span><span class="err">25,</span><span class="w"> </span><span class="err">36,</span><span class="w"> </span><span class="err">49</span><span class="p">}</span><span class="w"></span>
</code></pre></div>
<h2>Faire la somme d'un vecteur</h2>
<div class="highlight"><pre><span></span><code><span class="nt">std</span><span class="p">::</span><span class="nd">vector</span><span class="o"><</span><span class="nt">int</span><span class="o">></span><span class="w"> </span><span class="nt">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="err">1,1,1,1,1</span><span class="p">}</span><span class="o">;</span><span class="w"></span>
<span class="nt">int</span><span class="w"> </span><span class="nt">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nt">std</span><span class="p">::</span><span class="nd">accumulate</span><span class="o">(</span><span class="nt">a</span><span class="p">.</span><span class="nc">begin</span><span class="o">(),</span><span class="nt">a</span><span class="p">.</span><span class="nc">end</span><span class="o">(),</span><span class="nt">0</span><span class="o">);</span><span class="w"></span>
<span class="o">//</span><span class="w"> </span><span class="nt">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nt">5</span><span class="w"></span>
</code></pre></div>
<h2>Toutes mes valeurs sont elles superieurs à 0 ?</h2>
<div class="highlight"><pre><span></span><code><span class="nt">std</span><span class="p">::</span><span class="nd">vector</span><span class="o"><</span><span class="nt">int</span><span class="o">></span><span class="w"> </span><span class="nt">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="err">1,2,3,4,5</span><span class="p">}</span><span class="o">;</span><span class="w"></span>
<span class="nt">bool</span><span class="w"> </span><span class="nt">success</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nt">std</span><span class="p">::</span><span class="nd">all_of</span><span class="o">(</span><span class="nt">a</span><span class="p">.</span><span class="nc">begin</span><span class="o">(),</span><span class="w"> </span><span class="nt">a</span><span class="p">.</span><span class="nc">end</span><span class="o">(),</span><span class="w"> </span><span class="cp">[]</span><span class="o">(</span><span class="nt">int</span><span class="w"> </span><span class="nt">x</span><span class="o">)</span><span class="p">{</span><span class="err">return</span><span class="w"> </span><span class="err">x>0</span><span class="p">;}</span><span class="o">);</span><span class="w"></span>
<span class="o">//</span><span class="w"> </span><span class="nt">success</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nt">True</span><span class="w"></span>
</code></pre></div>Changer l'humanité avec le « gene drive »2017-11-19T23:50:00+01:002017-11-19T23:50:00+01:00Sacha Schutztag:dridk.me,2017-11-19:/gene-drive.html<p>C'est le 2 août 1939 qu'<a href="https://fr.wikipedia.org/wiki/Albert_Einstein">Albert Einstein</a> publie <a href="http://www.deslettres.fr/lettre-dalbert-einstein-au-president-franklin-d-roosevelt-des-bombes-dun-genre-nouveau-et-dune-extreme-puissance-pourraient-etre-construites/">une lettre</a> au <a href="https://fr.wikipedia.org/wiki/Franklin_Delano_Roosevelt">Président Roosevelt</a> pour le prévenir du risque de voir apparaître une bombe atomique après la découverte de <a href="https://fr.wikipedia.org/wiki/R%C3%A9action_en_cha%C3%AEne">la réaction en chaîne</a>.
Six ans plus tard, quasiment jour pour jour, la bombe atomique tombe sur Hiroshima.
Pourquoi je vous …</p><p>C'est le 2 août 1939 qu'<a href="https://fr.wikipedia.org/wiki/Albert_Einstein">Albert Einstein</a> publie <a href="http://www.deslettres.fr/lettre-dalbert-einstein-au-president-franklin-d-roosevelt-des-bombes-dun-genre-nouveau-et-dune-extreme-puissance-pourraient-etre-construites/">une lettre</a> au <a href="https://fr.wikipedia.org/wiki/Franklin_Delano_Roosevelt">Président Roosevelt</a> pour le prévenir du risque de voir apparaître une bombe atomique après la découverte de <a href="https://fr.wikipedia.org/wiki/R%C3%A9action_en_cha%C3%AEne">la réaction en chaîne</a>.
Six ans plus tard, quasiment jour pour jour, la bombe atomique tombe sur Hiroshima.
Pourquoi je vous parle de ça ? Parce qu'aujourd'hui, une nouvelle technologie fait son apparition en biologie moléculaire. Elle est tout aussi fascinante qu'effarante, car elle permet de modifier génétiquement toute la population d'une espèce en quelques générations. Et ironie du sort, cette technologie s'appelle MCR : « <a href="https://en.wikipedia.org/wiki/Gene_drive">Mutagenic Chain Reaction</a> ».</p>
<h2>Le principe</h2>
<p>Nous et d'autres espèces sexuées sommes <a href="https://fr.wikipedia.org/wiki/Diplo%C3%AFde">diploïdes</a>. C'est-à-dire que nous possédons chacun de nos gènes en deux exemplaires. Une version (<a href="https://fr.wikipedia.org/wiki/All%C3%A8le">allèle</a>) provient de la mère et l'autre provient du père. Lors de la formation des gamètes, le mécanisme de <a href="https://fr.wikipedia.org/wiki/M%C3%A9iose">méiose</a> choisit aléatoirement une version de ce gène pour fabriquer un spermatozoïde ou un ovocyte. Ainsi, lors de la fécondation, chaque allèle a une chance sur deux de se transmettre à la descendance. <br>
La technologie de « forçage génétique » ou « <em>gene drive</em> » biaise ce mécanisme de l'hérédité en rendant le gène souhaité héritable à presque 100 %. En quelques générations seulement, un trait génétique peut alors se répandre dans toute la population. <br>
Comment ça fonctionne ? Je vous le donne en mille. Encore un coup de ce <a href="https://fr.wikipedia.org/wiki/Cas9">CRISPR-Cas9</a>...</p>
<div class="figure"> <img src="../images/post29/CRISP_mosquito_french.png" /> <div class="legend">À gauche : hérédité normale avec 50 % de chance de transmettre un allèle à la prochaine génération. À droite : hérédité biaisée avec 100 % de chance de transmettre l'allèle. <a href="https://www.sciencenews.org/"><br/>source de l'image</a> </div> </div>
<h2>Un gène vraiment égoïste</h2>
<p>L'idée est de créer un gène artificiel de sorte qu'il puisse détruire son allèle homologue sauvage et s'y copier à la place.
Pour cela, on associe au gène d'intérêt une séquence codant pour l'endonucléase <a href="https://fr.wikipedia.org/wiki/Cas9">Cas9</a> ainsi que l'<a href="https://en.wikipedia.org/wiki/Guide_RNA">ARN guide</a> qui cible le même gène à l'état sauvage grâce à des séquences homologues (H1, et H2 sur le schéma). Cet ensemble s'apelle une « cassette ».
Si dans une cellule, l'allèle sauvage se trouve avec cette cassette, il est localisé et découpé par le complexe Cas9-ARN guide. Le trou béant qui en résulte est <a href="https://fr.wikipedia.org/wiki/Recombinaison_homologue">corrigé en prenant comme modèle la séquence homologue</a> de l'allèle disparu qui n'est autre que la séquence de la cassette. On passe d'un état <a href="https://fr.wikipedia.org/wiki/H%C3%A9t%C3%A9rozygote">hétérozygote</a> à une cassette à un état <a href="https://fr.wikipedia.org/wiki/Homozygote">homozygote</a> à deux cassettes. Lors de la fécondation, la probabilité de transférer ce nouveau gène passe ainsi de 50 % à 100 %.</p>
<div class="figure"> <img src="../images/post29/Molecular_mechanism_of_gene_drive.svg.png" /> <div class="legend">À gauche : création d'un organisme modifié, par exemple, on peut, à l'aide d'un plasmide, modifier un embryon pour qu'il soit homozygote pour le gène artificiel. À droite : fécondation entre un organisme sauvage et l'organisme modifié. Sans intervention humaine, l'embryon passe de l'état hétérozygote à homozygote. <br/> H1, H2 : site de reconnaissance de l'ARN guide. Payload gene : gène que l'on désire voir se propager. gRNA : ARN guide. Cas9 : endonucléase <br/><a href="https://en.wikipedia.org/wiki/Gene_drive">source de l'image</a> </div> </div>
<h2>Un moyen de lutte contre le paludisme</h2>
<p>Une des premières applications de cette technologie serait de lutter contre la propagation du <a href="https://fr.wikipedia.org/wiki/Paludisme">paludisme</a> par les moustiques. Il suffirait d'introduire quelques moustiques disposant d'un gène les empêchant de transmettre le parasite. En quelques générations, ce nouveau trait génétique se répandrait dans toute la population. Et cela même si le gène n'apporte aucun avantage au moustique, voire même, si dans une moindre mesure, il est délétère. Il s'agit d'un face à face entre l'ingéniosité humaine et la sélection naturelle.</p>
<h2>Le danger ?</h2>
<p>Les applications de la technologie <em>gene drive</em> sont infinies et nombreux sont ceux qui vont vouloir jouer avec, que ce soit pour lutter contre des maladies ou pour l'amélioration de l'exploitation agricole. Et pourquoi pas plus tard, pour améliorer l'homme en le rendant plus fort et en meilleure santé ? <br>
Derrière ces belles promesses, il y aura, je pense, inévitablement des effets de bord et toutes les précautions devront être prises. Qu'adviendrait-il par exemple si un mauvais gène était introduit lors d'un <em>gene drive</em> chez l'homme? Et si le gène passait d'une espèce à l'autre ? Quelles seraient les répercussions sur l'écosystème ? Que se passerait-il si une mutation apparaissait dans une cassette avec un effet non escompté ? <br>
Bref, une technologie à mon sens imprédictible, dont <a href="http://www.nature.com/news/gene-drive-moratorium-shot-down-at-un-biodiversity-meeting-1.21216">le moratoire mondial a été rejeté</a> lors de la réunion de la biodiversité de l'Organisation des Nations Unies en décembre 2016.</p>
<h2>Références</h2>
<ul>
<li><a href="http://journals.plos.org/plosgenetics/article?id=10.1371/journal.pgen.1007039">The creation and selection of mutations resistant to a gene drive over multiple generations in the malaria mosquito</a></li>
<li><a href="http://rspb.royalsocietypublishing.org/content/270/1518/921">Site-specific selfish genes as tools for the control and genetic engineering of natural populations</a></li>
<li><a href="https://www.normalesup.org/~vorgogoz/gene-drive.html">Faut-il relâcher le « gene drive » dans la nature ?</a></li>
<li><a href="http://www.genetics.org/content/201/2/425">Modeling the Manipulation of Natural Populations by the Mutagenic Chain Reaction</a></li>
</ul>
<h2>Remerciements</h2>
<p><a href="https://github.com/Oodnadatta">@Oodnadatta </a> <br>
<a href="https://github.com/Aluriak">@Aluriak </a> </p>La sélection génomique de la semaine #52017-09-25T11:17:50+02:002017-09-25T11:17:50+02:00Sacha Schutztag:dridk.me,2017-09-25:/selection-5.html<p>Voici ma sélection de l'actualité en génétique/génomique de la semaine du 18/09/2017.</p><p>Voici ma sélection de l'actualité en génétique/génomique de la semaine du 18/09/2017.</p>
<h2>Des souris guéries de la sclérose en plaques par une immunothérapie "génétique"</h2>
<p>La <a href="https://fr.wikipedia.org/wiki/Scl%C3%A9rose_en_plaques">sclérose en plaques</a> est une <a href="https://fr.wikipedia.org/wiki/Maladie_auto-immune">maladie auto-immune</a> ou le système immunitaire s'attaque à la <a href="https://fr.wikipedia.org/wiki/My%C3%A9line">myéline</a> du système nerveux central. Cette maladie se manifeste par différents signes neurologiques évoluant par poussée en s'aggravant suivant les formes. <br>
Dans cette étude les chercheurs ont voulu rendre le système immunitaire plus tolérant à la myéline en augmentant le nombre de <a href="https://fr.wikipedia.org/wiki/Lymphocyte_T_r%C3%A9gulateur">lymphocytes T régulateurs</a> spécifiques à la myéline. Ces dernières ont la propriété d'inhiber la prolifération des <a href="https://fr.wikipedia.org/wiki/Lymphocyte_T">lymphocytes T effecteurs</a> responsables de la réaction auto-immune. <br>
Pour cela, ils ont choisi d'injecter le gène de la myéline dans les cellules du foie d'une souris maladie par l'intermédiaire d'un <a href="https://fr.wikipedia.org/wiki/Vecteur_viral">vecteur viral</a>. Ce nouveau gène ou <a href="https://fr.wikipedia.org/wiki/Transg%C3%A9n%C3%A8se">transgène</a> s'exprime alors dans les <a href="https://fr.wikipedia.org/wiki/H%C3%A9patocyte">hépatocytes</a> et engendre des lymphocytes T régulateurs tolérants à la myéline qui vont aller dans le système nerveux central pour diminuer la réaction auto-immune. <br>
Les effets de cette <em><a href="https://en.wikipedia.org/wiki/Tolerogenic_therapy">thérapie tolérogène</a></em> sont très encourageants comme vous pouvez le voir sur cette vidéo. </p>
<p><a href="http://www.cell.com/molecular-therapy-family/molecular-therapy/fulltext/S1525-0016(17)30413-6">http://www.cell.com/molecular-therapy-family/molecular-therapy/fulltext/S1525-0016(17)30413-6</a></p>
<p><center> <video width="512" height="288" controls> <source src="../images/selection5/mmc2.mp4" type="video/mp4">
Your browser does not support the video tag.
</video> </center></p>
<h2>SwissLipid</h2>
<p>Vous connaissez peut-être <a href="org">SwissProt</a>, la base de données des protéines. Maintenant vous avez SwissLipid, la base de données des lipides. </p>
<p><a href="http://www.swisslipids.org/">http://www.swisslipids.org/</a></p>
<h2>CRISPR-Cas9 devient encore plus précis</h2>
<p>Le problème avec <a href="https://fr.wikipedia.org/wiki/Cas9">CRISPR-Cas9</a>, ce sont les <a href="http://www.nature.com/nmeth/journal/v14/n6/fig_tab/nmeth.4293_SF4.html?foxtrotcallback=true">effets off-target</a>. C'est à dire des mutations involontaires qui surviennent sur des séquences ressemblant à la cible.
En modifiant un acide aminé dans la protéine Cas9, le complexe CRISPR-Cas9 gagne en précision.</p>
<p><a href="http://www.genengnews.com/gen-news-highlights/mutations-making-crispr-hyper-accurate-discovered/81254955">http://www.genengnews.com/gen-news-highlights/mutations-making-crispr-hyper-accurate-discovered/81254955
</a></p>
<h2>Le premier embryon humain knockout</h2>
<p>En génétique, pour connaitre l'effet d'un gène, on le désactive pour voir ce que ça donne. C'est ce qu'on appelle du <a href="https://fr.wikipedia.org/wiki/Knock-out_(g%C3%A9n%C3%A9tique)">knockout</a>. Ces expériences sont en général réalisées chez des organismes d'étude comme les rats ou les bactéries.
Et bien pour la première fois, un embryon humain a été knockout pour un gène. En l'occurrence le gène <a href="http://www.genecards.org/cgi-bin/carddisp.pl?gene=POU5F1&keywords=OCT4">OCT4</a> qui a montré son implication dans le développement du placenta.</p>
<p><a href="https://www.sciencenews.org/article/first-human-embryos-edited-explore-gene-function">https://www.sciencenews.org/article/first-human-embryos-edited-explore-gene-function
</a></p>
<h2>Pourquoi certaines mutations dynamiques ne sont pas stables ?</h2>
<p>Les mutations dynamiques sont des séquences répétées du génome, qui augmente de taille au cours des générations. Elles sont responsables de différentes maladies. (<a href="https://dridk.me/maladie-huntigton.html">Voir mon billet sur la maladie d'Huntington</a>). Pourquoi certaine et pas d'autre? Probablement la conformation 3D de la <a href="https://fr.wikipedia.org/wiki/Chromatine">chromatine</a> d'après cette étude.</p>
<p><a href="https://www.biorxiv.org/content/early/2017/09/20/191213">https://www.biorxiv.org/content/early/2017/09/20/191213
</a></p>
<h2>Des anticorps trispécifiques contre le VIH</h2>
<p>Un anticorps trispécifique est un <a href="https://fr.wikipedia.org/wiki/Anticorps">anticorps</a> construit pour cibler 3 antigènes différents par ses trois extrémités. De tels anticorps ont été utilisés chez le macaque pour lutter contre le VIH. Les résultats sont plutôt concluants.</p>
<p><a href="http://science.sciencemag.org/content/early/2017/09/19/science.aan8630/tab-pdf">http://science.sciencemag.org/content/early/2017/09/19/science.aan8630/tab-pdf
</a></p>
<div class="figure"> <img src="../images/selection5/anticorps-tri.png" /> <div class="legend">Exemple d'un anticorps tri-specifique</div></div>La sélection génomique de la semaine #42017-09-17T12:22:09+02:002017-09-17T12:22:09+02:00Sacha Schutztag:dridk.me,2017-09-17:/selection-4.html<p>Voici ma sélection de l'actualité en génétique/génomique de la semaine du 11/09/2017.</p><p>Voici ma sélection de l'actualité en génétique/génomique de la semaine du 11/09/2017.</p>
<h3>Craig Venter répond à la critique sur les portraits robots génomiques</h3>
<p>Suite à l'article <em><a href="http://www.biorxiv.org/content/early/2017/09/07/185330.1">major flaws in: "Identification of individuals by trait prediction using whole-genome sequencing data"</a></em>(<a href="selection-3">voir la semaine dernière</a>), Craig Venter répond par un autre article, intitulé tout simplement : <em><a href="http://www.biorxiv.org/content/early/2017/09/11/187542.1">No major flaws in "Identification of individuals by trait prediction using whole-genome sequencing data</a>"</em>.<br>
C'est pas très difficile de trouver un bon titre finalement ... </p>
<p><a href="http://www.biorxiv.org/content/early/2017/09/11/187542.1">http://www.biorxiv.org/content/early/2017/09/11/187542.1 </a></p>
<h3>Le nouveau programme pour les internes de génétique médicale</h3>
<p>Ce que doit savoir un généticien en médecine c'est ici, dans le nouveau programme. <br>
<a href="http://cncem.fr/wikicncem/doku.php?id=cycle3:genetique">http://cncem.fr/wikicncem/doku.php?id=cycle3:genetique </a></p>
<h3>Une nouvelle version d'ENSEMBL</h3>
<p>Pour rappel, Ensembl est une base de donnée contenant différents génomes annotés. <br>
<a href="http://www.ensembl.info/blog/2017/09/12/ensembl-genomes-37-is-now-live/">http://www.ensembl.info/blog/2017/09/12/ensembl-genomes-37-is-now-live/</a></p>
<h3>Un serveur d'articles scientifiques médicaux en prépublication</h3>
<p>Vous connaissez certainement <a href="biorxiv.org">biorxiv.org</a>, un site web qui vous permet d'accéder aux articles en prépublication sans avoir été relus par les paires. Idéal pour partager ses articles rapidement à travers la communauté.<br>
Et bien, une version dédiée aux publications médicales est bientôt disponible.</p>
<p><a href="http://yoda.yale.edu/medarxiv">http://yoda.yale.edu/medarxiv</a></p>
<h3>La première espèce dont tous les individus ont été séquencés</h3>
<p>Il s'agit de <a href="https://fr.wikipedia.org/wiki/Strigops_kakapo">Strigops kakapo</a>, une drôle d'oiseau de nouvelle Zélande. Ce n'était pas très difficile, car l'espèce est en voie d'extinction et il ne reste plus que 125 individus.</p>
<p><a href="https://www.geneticrescue.science/projects/genome-sequencing/kakapo">https://www.geneticrescue.science/projects/genome-sequencing/kakapo</a></p>
<h3>Encore une étude GWAS sur l'intelligence humaine</h3>
<p>Je rappelle qu'une explication génétique ne veut pas forcément dire héréditaire. Beaucoup de nos traits sont multigéniques. </p>
<p><a href="https://www.ncbi.nlm.nih.gov/pubmed/28530673">https://www.ncbi.nlm.nih.gov/pubmed/28530673</a></p>
<h3>Des Nano-bras robot fait avec de l'ADN</h3>
<div class="figure"> <img src="../images/selection4/nanorobot.gif" /> <div class="legend">SOURCE: PNAS</div> </div>
<p><a href="http://mobile.the-scientist.com/article/50325/cargo-sorting-dna-robots">http://mobile.the-scientist.com/article/50325/cargo-sorting-dna-robots</a></p>
<h3>Conférence sur l'évolution artificielle le 25-27 octobre à Paris</h3>
<p><a href="https://ea2017.inria.fr/">https://ea2017.inria.fr/</a></p>
<h3>ProteinAtlas : Une base de données des Cancers</h3>
<p>Une chouette base de données des cancers regroupant notamment de la protéomique et de la transcriptomique.</p>
<p><a href="http://www.proteinatlas.org">http://www.proteinatlas.org </a></p>
<h3>Un extrait du livre : "Il était une fois le gène"</h3>
<p>Ce livre, je vous en parlais la semaine la dernière. Il raconte toute l'histoire de la génétique de Mendel à CRISPR-Cas9. Il me reste 200 page sur 600 mais je peux déjà vous dire que ce livre est top. Sur twitter, vous trouverez plusieurs extraits et anecdotes qui m'ont marqués.</p>
<p><center><blockquote class="twitter-tweet" data-lang="fr"><p lang="fr" dir="ltr">"Le racisme ne vient pas d'une déduction de la race à partir du génome, mais de déduire des caractéristiques à partir de la race"</p>— Sacha schutz (@dridk) <a href="https://twitter.com/dridk/status/909377147638308864">17 septembre 2017</a></blockquote></p>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p></center></p>
<h2>Twitter</h2>
<p>Pour plus de news ou me faire part des vôtres, suivez-moi sur <a href="https://twitter.com/dridk">twitter @dridk</a></p>La sélection génomique de la semaine #32017-09-11T12:22:09+02:002017-09-11T12:22:09+02:00Sacha Schutztag:dridk.me,2017-09-11:/selection-3.html<p>Voici ma sélection de l'actualité en génétique/génomique de la semaine du 04/09/2017.</p><p>Voici ma sélection de l'actualité en génétique/génomique de la semaine du 04/09/2017.</p>
<h2>Craig Venter publie un article montrant comment reconstruire un portrait robot à partir d'un génome... Quelques heures après, le papier se prend une sévère critique.</h2>
<div class="figure"> <img src="../images/selection3/face.png" /> <div class="legend">SOURCE: PNAS</div> </div>
<p>C'était l'ambiance sur twitter jeudi dernier, suite à <a href="http://www.pnas.org/content/early/2017/08/29/1711125114.abstract">la dernière publication</a> de <a href="https://fr.wikipedia.org/wiki/Craig_Venter">Craig Venter</a> et de son équipe <a href="http://www.humanlongevity.com/">Human Longevity</a>. Le papier sorti le 5 septembre dans <a href="http://www.pnas.org/">PNAS</a> propose de reconstruire numériquement le visage, la voix, la couleur de la peau, l'âge et la taille d'un individu simplement à partir de son ADN. Pour cela, ils ont entrainé un algorithme sur 1061 patients en recherchant une corrélation entre les <a href="https://fr.wikipedia.org/wiki/Polymorphisme_nucl%C3%A9otidique">SNPs</a> de leurs génomes et leurs valeurs biométriques. Puis ils ont testé leur intelligence artificielle avec une série de génomes anonymisés pour reconstruire leurs visages avec 74% de réussite! <br>
Quelques heures après, c'est un déluge de critique qui tombe sur twitter. Et notamment <a href="http://www.biorxiv.org/content/early/2017/09/06/185330">une review salée</a> de <a href="https://twitter.com/erlichya?lang=fr">Yaniv Erlich</a> dans <a href="http://www.biorxiv.org/content/early/2017/09/06/185330">biorxiv</a> publiée en des temps records. En résumé, les visages reconstruits ne sont pas assez précis pour reconnaitre un individu. À part si vous devez trouver un individu noir parmi 999 individus blancs. <br>
Bref, ce n’est pas encore au point... Mais gardons quand même à l'esprit que la reconstruction d'un visage à partir d'un génome est en théorie possible vu que deux jumeaux se ressemblent comme deux gouttes d'eau.</p>
<p><a href="http://www.pnas.org/content/early/2017/08/29/1711125114.abstract">http://www.pnas.org/content/early/2017/08/29/1711125114.abstract</a> <br>
<a href="http://www.biorxiv.org/content/early/2017/09/06/185330">http://www.biorxiv.org/content/early/2017/09/06/185330 </a> <br>
<a href="http://www.nature.com/news/geneticists-pan-paper-that-claims-to-predict-a-person-s-face-from-their-dna-1.22580">http://www.nature.com/news/geneticists-pan-paper-that-claims-to-predict-a-person-s-face-from-their-dna-1.22580 </a> </p>
<h2>Un algorithme de reconnaissance faciale qui reconnait l'homosexualité</h2>
<p>Dans le même registre, cette news à la limite de l'éthique dont je me passerais de commentaires... </p>
<p><a href="https://www.theguardian.com/technology/2017/sep/07/new-artificial-intelligence-can-tell-whether-youre-gay-or-straight-from-a-photograph">https://www.theguardian.com/technology/2017/sep/07/new-artificial-intelligence-can-tell-whether-youre-gay-or-straight-from-a-photograph </a></p>
<h2>23andme vu par un célèbre youtubeur américain</h2>
<p><a href="https://www.youtube.com/user/destinws2">@SmarterEveryDay</a>, un youtubeur américain, très influençant dans la vulgarisation scientifique, fait la publicité de la société <a href="https://fr.wikipedia.org/wiki/23andMe">23andMe</a> en filmant toute la logistique de l'intérieur. Après avoir précisé qu'il avait la liberté de paroles, il en dépeint un joli portrait.
Sauf que... <br>
Voilà, le CEO de 23andMe (<a href="https://fr.wikipedia.org/wiki/Anne_Wojcicki">Anne Wojcicki</a>) n'est autre que la soeur du CEO de YouTube (<a href="https://fr.wikipedia.org/wiki/Susan_Wojcicki">Susan Wojcicki</a>). Il n' y aura pas à s'étonner de voir cette vidéo excessivement mise en avant sur YouTube...</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/U3EEmVfbKNs?rel=0" frameborder="0" allowfullscreen></iframe>
<h2>Sortie du livre : « Il était une fois le gène »</h2>
<p>Écrit par l'indien <a href="https://fr.wikipedia.org/wiki/Siddhartha_Mukherjee">Siddhartha Mukherjee</a>, médecin chercheur et gagnant du prix Pulitzer pour le livre « <a href="https://www.babelio.com/livres/Siddhartha-Lempereur-de-toutes-les-maladies--Une-biographie/527260">L'Empereur de toutes les maladies</a> ».</p>
<p><a href="http://editions.flammarion.com/Catalogue/hors-collection/sciences/il-etait-une-fois-le-gene">http://editions.flammarion.com/Catalogue/hors-collection/sciences/il-etait-une-fois-le-gene</a></p>
<h2>Personal Genom project</h2>
<p>Je ne connaissais pas. Une plateforme pour partager et télécharger des génomes.
<a href="http://www.personalgenomes.org/harvard">http://www.personalgenomes.org/harvard </a></p>
<h2>AddGene: De la biologie moléculaire bien expliquée</h2>
<p>AddGene est une base de données de plasmide à but non lucratif. Mais le site contient surtout, pas mal de docs très claires sur des concepts clés en génétique moléculaire (CRISPR, plasmide, vecteur..)
<a href="http://www.addgene.org/crispr/guide/">http://www.addgene.org/crispr/guide/ </a></p>
<h2>Single base editing avec CRISPR</h2>
<p>Encore un autre variant de CRISPR-CAS9. En l'associant à la protéine <a href="https://en.wikipedia.org/wiki/APOBEC">APOBEC</a>, on peut switcher <a href="https://fr.wikipedia.org/wiki/%C3%89dition_(biologie)#Cytidine_en_Uridine">une Cytosine en Uracile</a> sans faire de coupure. </p>
<div class="figure"> <img src="../images/selection3/singleBaseEditing_MG_2016_8_12-01.png" /> </div>
<p><a href="http://blog.addgene.org/single-base-editing-with-crispr"> http://blog.addgene.org/single-base-editing-with-crispr </a></p>
<h2>connaissez-vous les thérapies anti-sens ?</h2>
<p>Les <a href="https://fr.wikipedia.org/wiki/Th%C3%A9rapie_antisens">thérapies anti-sens</a> permettent de traiter des maladies génétiques en injectant l'ARN anti-sens du gène muté. Par exemple le <strong>Nusinersen</strong> utilisé dans l'amyotrophie spinale. </p>
<p><a href="https://en.m.wikipedia.org/wiki/Nusinersen">https://en.m.wikipedia.org/wiki/Nausinersen </a></p>
<h2>Twitter</h2>
<p>Pour plus de news ou me faire part des vôtres, suivez-moi sur <a href="https://twitter.com/dridk">twitter @dridk</a></p>La thérapie cellulaire adoptive2017-09-08T11:34:32+02:002017-09-08T11:34:32+02:00Sacha Schutztag:dridk.me,2017-09-08:/therapie-cellulaire-adoptive.html<p>C'était <a href="https://www.novartis.com/news/media-releases/novartis-receives-first-ever-fda-approval-car-t-cell-therapy-kymriahtm-ctl019">la news</a> de la semaine dernière. La première thérapie génique appelée <strong>Kymriah™</strong> a été autorisée aux États-Unis par la <a href="https://fr.wikipedia.org/wiki/Food_and_Drug_Administration">FDA</a> dans le traitement d'un cancer, en l'occurrence la <a href="https://fr.wikipedia.org/wiki/Leuc%C3%A9mie#Leuc.C3.A9mies_aigu.C3.ABs_lymphoblastiques">leucémie aiguë lymphoblastique</a>.
Ce traitement est une <a href="https://fr.wikipedia.org/wiki/Immunoth%C3%A9rapie">immunothérapie</a> et va plus loin que l'immunothérapie classique à base d'anticorps <a href="https://fr.wikipedia.org/wiki/Ipilimumab">anti-CTLA4</a>/<a href="https://fr.wikipedia.org/wiki/Nivolumab">anti-PD1</a> (<a href="https://www.youtube.com/watch?v=gxtqGhhomQE">voir …</a></p><p>C'était <a href="https://www.novartis.com/news/media-releases/novartis-receives-first-ever-fda-approval-car-t-cell-therapy-kymriahtm-ctl019">la news</a> de la semaine dernière. La première thérapie génique appelée <strong>Kymriah™</strong> a été autorisée aux États-Unis par la <a href="https://fr.wikipedia.org/wiki/Food_and_Drug_Administration">FDA</a> dans le traitement d'un cancer, en l'occurrence la <a href="https://fr.wikipedia.org/wiki/Leuc%C3%A9mie#Leuc.C3.A9mies_aigu.C3.ABs_lymphoblastiques">leucémie aiguë lymphoblastique</a>.
Ce traitement est une <a href="https://fr.wikipedia.org/wiki/Immunoth%C3%A9rapie">immunothérapie</a> et va plus loin que l'immunothérapie classique à base d'anticorps <a href="https://fr.wikipedia.org/wiki/Ipilimumab">anti-CTLA4</a>/<a href="https://fr.wikipedia.org/wiki/Nivolumab">anti-PD1</a> (<a href="https://www.youtube.com/watch?v=gxtqGhhomQE">voir la vidéo sur le cancer</a> de <a href="https://www.youtube.com/user/ScienceEtonnante">@scienceEtonnante</a>, il en parle dans sa conclusion). <br>
Elle repose sur ce qu'on appelle un « <a href="https://fr.wikipedia.org/wiki/Transfert_adoptif_de_cellules">transfert adoptif de cellules</a> »: </p>
<ul>
<li>on prend les cellules immunitaires du patient (<a href="https://fr.wikipedia.org/wiki/Lymphocyte_T">lymphocyte T</a>);</li>
<li>on les modifie génétiquement pour qu'ils ciblent les cellules cancéreuses; </li>
<li>puis on les réinjecte au patient; </li>
</ul>
<p>Génial non ? Alors, voyons de plus près comment fonctionne cette thérapie étape par étape.</p>
<div class="figure"> <img src="../images/post28/etapes.jpg" /> <div class="legend">Schéma résumant les étapes de la thérapie. Chaque étape est décrite dans le texte <br/> <a href='http://clincancerres.aacrjournals.org/content/22/8/1875'>source de l'image</a></div> </div>
<h2>Étape 1 : Leucophérèse et récupération des lymphocytes T</h2>
<p>La première étape consiste à extraire du sang, les lymphocytes T.
On réalise pour cela une <a href="https://en.wikipedia.org/wiki/Leukapheresis">leucophérèse</a>. C'est un peu comme une prise de sang, sauf qu'ici tous les globules blancs (<a href="https://fr.wikipedia.org/wiki/Leucocyte">leucocytes</a>) sont filtrés et le reste (globule rouge, plaquettes ...) retourne directement dans la circulation sanguine. <br>
De ces leucocytes, on récupère les lymphocytes T en utilisant <a href="http://e-sante.futura-sciences.com/_forum/separation-cellules-sang.html">différentes techniques</a> de séparation comme la centrifugation ou encore des <a href="https://www.ncbi.nlm.nih.gov/pubmed/17680228">billes magnétiques couplées à des anticorps spécifiques</a>.</p>
<h2>Étape 2 : Culture cellulaire</h2>
<p>À partir de là, on a besoin de mettre les cellules en culture pour qu'elles se divisent. Un prérequis pour la <a href="https://fr.wikipedia.org/wiki/Transfection">transfection virale</a> qui fera suite. <br>
À l'état normal, les cellules T se divisent après activation par des <a href="https://fr.wikipedia.org/wiki/Cellule_pr%C3%A9sentatrice_d%27antig%C3%A8ne">cellules présentatrices d'antigènes</a> ou <a href="https://fr.wikipedia.org/wiki/Cellule_dendritique">dendrocytes</a> (voir <a href="https://www.youtube.com/watch?v=Mpn87TQbRJE">les supers vidéos de @unPeuPointu</a>). On pourrait en ajouter, mais le risque c'est qu'au moment de la réinjection au patient, ces cellules étrangères déclenchent un rejet immunitaire. On préfère alors utiliser des billes magnétiques recouvertes d'anticorps qui se font passer pour des dendrocytes artificielles. Après l'activation, il suffira de les enlever avec un aimant. </p>
<h2>Étape 3 : Transfection virale et récepteurs chimériques</h2>
<p>C'est maintenant que la manipulation génétique commence. <a href="https://fr.wikipedia.org/wiki/Virus_%C3%A0_ARN">Un virus ARN</a> utilisé comme vecteur, va venir intégrer un gène dans le génome du lymphocyte T pour qu'il exprime à sa surface un récepteur chimérique appelé <a href="https://fr.wikipedia.org/wiki/R%C3%A9cepteur_antig%C3%A9nique_chim%C3%A9rique">CAR (Chimeric antigen recepteur)</a> capable de reconnaitre les cellules tumorales. C'est le même mécanisme qu'avec n'importe quel virus ARN comme le <a href="https://fr.wikipedia.org/wiki/Syndrome_d%27immunod%C3%A9ficience_acquise">VIH</a>. </p>
<div class="figure"> <img src="../images/post28/biobiz.jpg" /> <div class="legend">Transfection virale de l'ADN du récepteur chimérique CAR<br/><a href='http://www.the-scientist.com/?articles.view/articleNo/42462/title/The-CAR-T-Cell-Race/'>source de l'image</a></div></div>
<p>Les <em>CAR</em> ou <em>CAR-T</em> sont dits chimériques, car ils sont constitués artificiellement d'un domaine extramembranaire similaire à la portion variable des anticorps. Et d'une partie intracytoplasmique similaire aux <a href="https://fr.wikipedia.org/wiki/R%C3%A9cepteur_des_cellules_T">récepteurs des cellules T</a> permettant de déclencher le signal d'activation du lymphocyte (un motif <a href="https://fr.wikipedia.org/wiki/Motif_d%E2%80%99activation_des_r%C3%A9cepteurs_immuns_bas%C3%A9_sur_la_tyrosine">ITAM</a> pour les connaisseurs). </p>
<div class="figure"> <img src="../images/post28/CAR-t.jpg" /> <div class="legend">Representation d'un CAR (Chimeric antigen recepteur). En orange le domaine variable (scFC : single chain variable fragment) qui reconnait l'antigène tumoral. Et en bleu la partie intra-cellulaire qui déclenche l'activation du lymphocyte.<br/><a href='http://www.the-scientist.com/?articles.view/articleNo/42462/title/The-CAR-T-Cell-Race/'>source de l'image</a></div> </div>
<div class="figure"> <img src="../images/post28/car.gif" /> <div class="legend"> Il existe différents types de CAR-T<br/><a href='https://jitc.biomedcentral.com/articles/10.1186/s40425-017-0230-9'>source de l'image</a></div></div>
<p>Dans le cas du <strong>Kymriah™</strong>, les <em>CAR-T</em> sont conçus pour qu'ils reconnaissent spécifiquement les antigènes <a href="https://en.wikipedia.org/wiki/CD19">CD-19</a> présents à la surface des cellules cancéreuses (mais aussi des <a href="https://fr.wikipedia.org/wiki/Lymphocyte_B">lymphocytes B normaux</a>). Lorsque ces nouveaux lymphocytes T génétiquement modifiés seront en contact avec les cellules cancéreuses, ils s'activeront et entraîneront une réponse immunitaire ciblée. </p>
<h2>Étape 4 : Préparation du produit</h2>
<p>Il ne reste plus qu'à préparer nos cellules pour l'injection. Les billes magnétiques sont retirées. Les microbes éliminés en utilisant des rayons UV. Etape critique, car on s'apprête à réinjecter un produit dans la circulation du patient. </p>
<h2>Étape 5 : Adminstration au patient</h2>
<p>Les lymphocytes T génétiquement modifiés sont administrés au patient. En général, le patient est préparé à recevoir le traitement avec une chimiothérapie lympho-déplétive. L'activation des cellules T est aussi soutenue par l'administration d'<a href="https://fr.wikipedia.org/wiki/Interleukine_2">interleukine-2</a>, une molécule stimulant les lymphocytes T. <br>
Quant aux effets indésirables, ils existent. Le relargage excessif des cytokines par les lymphocytes T activés est responsable du <a href="http://dictionnaire.doctissimo.fr/definition-syndrome-de-relargage-des-cytokines.htm">syndrome de relargage des cytokines</a>. Et n'oublions pas que ces CAR-T anti-CD19 ciblent également les lymphocytes B avec le risque d'un déficit de l'immunité.</p>
<div class="figure"> <img src="../images/post28/juno-leukapherisis.jpg" /> <div class="legend">Résumé général</div> </div>
<h1>Et l'efficacité du traitement ?</h1>
<p>D'après <a href=", https://jhoonline.biomedcentral.com/articles/10.1186/s13045-017-0423-1,">cette étude</a>, l'efficacité des <em>CAR-T</em> anti-CD19 est vraiment bonne avec <strong>90%</strong> de rémission complète dans la leucémie lymphoïde aiguë. <br>
D'autres chercheurs ont déjà essayé la thérapie cellulaire adoptive sur d'autres cancers, notamment les cancers solides. Des résultats concluants ont déjà été obtenus dans le mélanome métastatique. Dans ce cas, les lymphocytes expriment un récepteur reconnaissant des antigènes spécifiques du mélanome (<a href="https://en.wikipedia.org/wiki/MLANA">MART-1</a>). </p>
<p>Malheureusement la complexité technique de ces thérapies personnalisées rend inaccessible le traitement. Le <strong>Kymriah™</strong> couterait environ 475 000 dollars!!!
Avec ce nouveau traitement sur le marché, il y a de quoi creuser les inégalités dans la santé... surtout aux États-Unis.</p>
<h1>Reference</h1>
<ul>
<li><a href="https://www.revmed.ch/RMS/2016/RMS-N-519/Principes-de-la-therapie-cellulaire-par-transfert-adoptif-a-base-de-Tumor-Infiltrating-Lymphocytes">Principes de la thérapie cellulaire par transfert adoptif à base de Tumor Infiltrating Lymphocytes</a></li>
<li><a href="https://www.cancer.gov/about-cancer/treatment/research/car-t-cells">CAR T Cells: Engineering Patients’ Immune Cells to Treat Their Cancers</a></li>
<li><a href="https://jitc.biomedcentral.com/articles/10.1186/s40425-017-0230-9">Current approaches to increase CAR T cell potency in solid tumors: targeting the tumor microenvironment</a></li>
<li><a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4931286/">Safe engineering of CAR T cells for adoptive cell therapy of cancer using long‐term episomal gene transfer</a></li>
<li><a href="https://jhoonline.biomedcentral.com/articles/10.1186/s13045-017-0444-9">Chimeric antigen receptor T cells: a novel therapy for solid tumors</a></li>
</ul>
<p>Merci aux relecteurs <br>
@Jnsll
@HervePerdry </p>La sélection génomique de la semaine #22017-09-03T20:59:15+02:002017-09-03T20:59:15+02:00Sacha Schutztag:dridk.me,2017-09-03:/selection-2.html<p>Voici ma sélection de l'actualité en génétique/génomique de la semaine du 28/08/2017.</p><p>Voici ma sélection de l'actualité en génétique/génomique de la semaine du 28/08/2017.</p>
<h3>Premiere thérapie génique approuvée sur le marché aux États-Unis</h3>
<p>Certainement la news de la semaine. Un nouveau traitement "<strong>Kymriah</strong>" permet de traiter certaines <a href="https://fr.wikipedia.org/wiki/Leuc%C3%A9mie_aigu%C3%AB_lymphoblastique">leucémies aiguës lymphoblastiques B</a> en modifiant génétiquement les <a href="https://fr.wikipedia.org/wiki/Lymphocyte_T">lymphocytes T </a>des patients pour qu'ils s'attaquent aux cellules cancéreuses. <br>
Les lymphocytes T sont extraits du patient par <a href="https://fr.wikipedia.org/wiki/Leucaph%C3%A9r%C3%A8se">leucaphérèse</a> puis envoyés à <a href="https://fr.wikipedia.org/wiki/Novartis">Novartis</a> pour être reprogrammés. Après manipulations, elles expriment de nouveaux récepteurs T chimériques (<a href="(https://fr.wikipedia.org/wiki/R%C3%A9cepteur_antig%C3%A9nique_chim%C3%A9rique)">CAR-T</a>) ciblant les cellules cancereuses. <br>
Elles sont alors réinjectées chez les patients pour la modique somme de 475 000 dollars !</p>
<p><a href="http://trustmyscience.com/nouveau-traitement-contre-le-cancer-approuve-par-la-fda/">http://trustmyscience.com/nouveau-traitement-contre-le-cancer-approuve-par-la-fda/</a> <br>
<a href="https://www.multivu.com/players/English/8163751-novartis-kymriah-fda-approval/docs/kymriahfactsheet-1503105905473-697015272.pdf">https://www.multivu.com/players/English/8163751-novartis-kymriah-fda-approval/docs/kymriahfactsheet-1503105905473-697015272.pdf</a> <br>
<a href="http://labiotech.eu/car-t-approval-fda-novartis-kymriah/">http://labiotech.eu/car-t-approval-fda-novartis-kymriah/</a></p>
<div class="figure"><a href="../images/selection2/car-t.png"><img src="../images/selection2/car-t.png" width="20%" height="20%" /></a> <div class="legend">cliquer pour agrandir </div> </div>
<h3>Un kit pour séquencer votre génome sur Amazon.fr</h3>
<p>La société <a href="https://www.dantelabs.com/">Dante Labs</a>, propose depuis plusieurs mois déjà, un kit de prélèvement salivaire pour séquencer votre génome complet. Vous pouvez le commander tout de suite sur amazone pour 850 euros, sans passer pas un médecin ni un conseiller en génétique.
La pratique est en principe illégale en France... pour le moment. <br>
L'info est d'ailleurs passé au JT de 20h sur France 2. <br>
<a href="https://www.amazon.fr/dp/B072BGP88H/ref=cm_sw_r_tw_dp_x_hx5Pzb9E0XREQ">https://www.amazon.fr/dp/B072BGP88H/ref=cm_sw_r_tw_dp_x_hx5Pzb9E0XREQ </a> <br>
<a href="https://www.france.tv/france-2/journal-20h00/233891-edition-du-samedi-2-septembre-2017.html">https://www.france.tv/france-2/journal-20h00/233891-edition-du-samedi-2-septembre-2017.html</a> </p>
<h3>Remise en cause du papier sur l'edition d'embryon</h3>
<p>Je vous en parlais dans un <a href="edition-embryon-humain.html">précédant l'article</a>. Une équipe avait réussi à éditer le génome d'un embryon avec <a href="https://fr.wikipedia.org/wiki/Cas9">CRISPR-Cas9</a>. Après le buzz médiatique, une autre équipe remet en cause ces résultats. <br>
En résumé, leurs arguments sont : </p>
<ul>
<li>Au moment de l'injection de CRISPR-Cas9, les <a href="https://fr.wikipedia.org/wiki/Nucl%C3%A9us">nucleis</a> mâles et femelles sont séparés physiquement empêchant la correction par recombinaison homologue.</li>
<li>Les mutations ne sont pas détectées tout simplement parce que CRISPR-Cas9 délète les cibles d'amorces de PCR nécessaire pour détecter la mutation.</li>
</ul>
<p><a href="https://ipscell.com/2017/08/doubts-raised-on-key-points-of-nature-paper-on-crispr-gene-editing-of-human-embryos/">https://ipscell.com/2017/08/doubts-raised-on-key-points-of-nature-paper-on-crispr-gene-editing-of-human-embryos/</a></p>
<h3>23andme propose le dépistage de la DMLA et l'hémochromatose</h3>
<p>Petit à petit, la société <a href="https://www.23andme.com/en-int/">23andme</a> (alias google), fait son chemin dans le dépistage des maladies génétiques non médicalisé. Après l'autorisation, en avril dernier, par la <a href="https://fr.wikipedia.org/wiki/Food_and_Drug_Administration">FDA</a> de faire du dépistage, la société se dote cette semaine de 2 nouveaux tests génétiques: Pour la <a href="https://fr.wikipedia.org/wiki/D%C3%A9g%C3%A9n%C3%A9rescence_maculaire_li%C3%A9e_%C3%A0_l%27%C3%A2ge">DMLA</a> et l'<a href="https://fr.wikipedia.org/wiki/H%C3%A9mochromatose">hémochromatose</a>. <br>
<a href="https://blog.23andme.com/health-traits/23andme-adds-new-genetic-health-risk-reports/">https://blog.23andme.com/health-traits/23andme-adds-new-genetic-health-risk-reports/</a></p>
<h3>DroNc-seq</h3>
<p>Après le <a href="https://fr.wikipedia.org/wiki/RNA-Seq">RNA-seq</a>, après le <a href="https://en.wikipedia.org/wiki/Single_cell_sequencing">single cell RNA-seq</a>, voici le single-nucleus RNA seq. Une méthode permettant le séquençage du transcriptome sur noyaux unique. <br>
Voir<a href="sc-rna-seq.html"> mon article</a> sur le single cell RNA-seq publié cette semaine. <br>
<a href="http://www.genengnews.com/gen-news-highlights/single-nucleus-rna-seq-merges-with-microfluidics/81254868">http://www.genengnews.com/gen-news-highlights/single-nucleus-rna-seq-merges-with-microfluidics/81254868</a></p>
<h3>Des tomates sous licence libre</h3>
<p>Une découverte cette semaine, c'est une licence libre, similaire aux licences en informatique (ex:<a href="https://en.wikipedia.org/wiki/GNU_General_Public_License">GPL</a>), mais appliquée aux semences de l'agriculture.<br>
En gros, vous protégez vos créations génétiques avec une licence pour contrer les grosses boites comme <a href="https://fr.wikipedia.org/wiki/Monsanto">Monsanto</a>.</p>
<p><a href="http://www.opensourceseeds.org/fr">http://www.opensourceseeds.org/fr</a> <br>
<a href="https://www.arte.tv/fr/videos/076697-000-A/des-tomates-libres-de-droits-pour-tous">https://www.arte.tv/fr/videos/076697-000-A/des-tomates-libres-de-droits-pour-tous</a></p>
<h3>Comparaison des caryotypes de l'homme et du chimpanzé</h3>
<p>Je termine par le tweet de la semaine. J'avais publié une belle image montrant les événements génétiques différenciant l'homme et le singe. Je n'ai pas trouvé la source de l'image, certainement un livre scolaire.
Quoi qu'il en soit, on voit très bien, sur ce caryotype, que le chromosome 2 humain est le résultat d'une fusion entre les deux chromosomes simiens. Encore une preuve pour la théorie de l'évolution ! </p>
<blockquote class="twitter-tweet" data-lang="fr"><p lang="fr" dir="ltr">Comparaison des caryotypes de l'homme et du chimpanzé <a href="https://t.co/JUdYzx1Xkp">pic.twitter.com/JUdYzx1Xkp</a></p>— Sacha schutz (@dridk) <a href="https://twitter.com/dridk/status/902653437728493576">29 août 2017</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<h2>Twitter</h2>
<p>Pour plus de news ou me faire part des vôtres, suivez-moi sur <a href="https://twitter.com/dridk">twitter @dridk</a></p>Séquençage des ARNm sur cellules uniques2017-09-01T21:36:32+02:002017-09-01T21:36:32+02:00Sacha Schutztag:dridk.me,2017-09-01:/sc-rna-seq.html<p>Toutes les cellules de votre corps sont constituées du même génome. Vous obtiendrez toujours le même texte en séquençant l'ADN provenant d'un morceau d'estomac, de cerveau ou de peau (sauf cas très particuliers: <a href="https://fr.wikipedia.org/wiki/Mosa%C3%AFque_(g%C3%A9n%C3%A9tique)">mosaïques</a>).<br>
Ce qui fait la différence, c'est l'expression des gènes ou « <em><a href="https://fr.wikipedia.org/wiki/Transcriptome">transcriptome</a></em> ». C'est-à-dire l'ensemble des <a href="https://fr.wikipedia.org/wiki/Acide_ribonucl%C3%A9ique_messager">ARNs messagers …</a></p><p>Toutes les cellules de votre corps sont constituées du même génome. Vous obtiendrez toujours le même texte en séquençant l'ADN provenant d'un morceau d'estomac, de cerveau ou de peau (sauf cas très particuliers: <a href="https://fr.wikipedia.org/wiki/Mosa%C3%AFque_(g%C3%A9n%C3%A9tique)">mosaïques</a>).<br>
Ce qui fait la différence, c'est l'expression des gènes ou « <em><a href="https://fr.wikipedia.org/wiki/Transcriptome">transcriptome</a></em> ». C'est-à-dire l'ensemble des <a href="https://fr.wikipedia.org/wiki/Acide_ribonucl%C3%A9ique_messager">ARNs messagers (ARNm)</a> transcrits dans la cellule dont la traduction est responsable du <a href="https://fr.wikipedia.org/wiki/Ph%C3%A9notype_cellulaire">phénotype cellulaire</a>. Par exemple, les cellules de votre rétine expriment d'autres gènes que votre estomac. Leurs transcriptomes sont différents.<br>
Une des méthodes pour évaluer le transcriptome est le séquençage des <a href="https://fr.wikipedia.org/wiki/Acide_ribonucl%C3%A9ique_messager">ARN messager</a> ou <a href="https://fr.wikipedia.org/wiki/RNA-Seq">RNA-seq</a>. <br>
En résumant rapidement (figure ci-dessous) :
À partir d'un tissu, toutes les cellules sont lysées puis les ARNs messagers sont capturés (en général par leurs <a href="https://fr.wikipedia.org/wiki/Polyad%C3%A9nylation">queues polyadénylées</a>). Ils sont ensuite convertis en <a href="https://fr.wikipedia.org/wiki/ADN_compl%C3%A9mentaire">ADN complémentaire</a> (ADNc) par une <a href="https://fr.wikipedia.org/wiki/Transcriptase_inverse">rétrotranscriptase</a>, amplifiés, puis séquencés. L'étape bio-informatique consiste à aligner les <a href="https://dridk.me/ngs.html">reads</a> sur un génome de référence et faire des normalisations pour évaluer quels gènes sont exprimés. Le nombre d'ARNm séquencés d'un gène correspond à son niveau d'expression ou « <em>abondance »</em>. <br>
Finalement, en analysant différents tissus, on obtient une <em>matrice d'expression</em> (voir tableau ci-dessous). <br>
Pour plus de détails sur l'analyse bio-informatique, je vous invite à jeter un oeil sur l'<a href="https://bioinfo-fr.net/lanalyse-de-donnees-rna-seq-mode-demploi">article de bioinfo-fr</a> traitant de ce sujet. </p>
<div class="figure"> <img src="../images/post27/rnaseq-overview.png" /> <div class="legend">Schéma général de la technologie RNAseq. Dans cet exemple, le séquençage est réalisé sur deux échantillons (tumeur et normal). Les ARNs sont capturés grâce leurs queues polyA, sont convertis en ADNc puis séquencés. Les reads sont alignés sur un génome de référence afin de mesurer l'expression de chaque gène. Cette expression est proportionnelle aux nombres d'ARN s'alignant sur un gène donné </br>Source : <a href="https://fr.wikipedia.org/wiki/RNA-Seq">Wikipedia</a></div> </div>
<div class="figure"> <img src="../images/post27/expression-matrix.png" /> <div class="legend">Exemple d'une matrice d'expression comparant deux tissus. Les valeurs du tableau correspondent aux quantités d'ARNm retrouvées par gène et par tissu. L'expression des gènes dans le tissu 1 est différente de celle dans le tissu 2</div> </div>
<h2>ScRNA-seq : Nouvelle approche plus résolutive</h2>
<p>Le défaut avec la technologie RNA-seq est qu'elle mesure l'expression d'un tissu et pas l'expression d'une cellule. En effet, dans un morceau de cerveau par exemple, il y aura différents types cellulaires (neurone, <a href="https://fr.wikipedia.org/wiki/Astrocyte">astrocytes</a>, <a href="https://fr.wikipedia.org/wiki/Oligodendrocyte">oligodendrocytes</a> ...) avec des profils d'expression différents. Le RNA-seq vous informe seulement du niveau d'expression de cet ensemble de cellules. <br>
Aujourd'hui, une autre méthode permet de séquencer le transcriptome d'<strong>une seule</strong> cellule. C'est ce qu'on appelle du <a href="https://en.wikipedia.org/wiki/Single-cell_transcriptomics">Single Cell RNA Seq (ScRNA-Seq)</a>.
L'idée est de créer une <a href="ngs.html">librairie</a> (Ensemble des fragments d'ADN destinés au séquençage) où chaque ARNm se voit greffer une séquence identifiant sa cellule d'origine (<a href="https://fr.wikipedia.org/wiki/Barcoding_mol%C3%A9culaire">barcode</a>). On peut alors, après séquençage, regrouper les <a href="https://dridk.me/ngs.html">reads</a> entre eux grâce à leurs barcodes et obtenir une matrice d'expression par cellules et par gènes. <br>
Comment étiqueter chaque fragment d'ADN avec sa cellule d'origine ? C'est ce qu'on va voir tout de suite avec la méthode de <a href="https://fr.wikipedia.org/wiki/Microfluidique">microfluidique</a> de <a href="https://www.10xgenomics.com/">10xGenomics</a>.</p>
<h2>Isoler les cellules en microfluidique</h2>
<p>La microfluidique est une technologie manipulant des fluides dans des microcanaux. Grâce à cette technique, on va pouvoir isoler chaque cellule dans une gouttelette d'huile contenant des réactifs (polymérase, oligonucléotide, retrotranscriptase...) et une bille particulière appelée <strong>GEM</strong> (Gel bead in EMulsion). </p>
<div class="figure"> <img src="../images/post27/GEM.png" /> <div class="legend">Microgoutelette avec une cellule et une GEM (Gel bead in EMulsion) </br> Source : <a href="https://www.10xgenomics.com/single-cell/">10xGenomics</a> </div> </div>
<div class="figure"> <img src="../images/post27/gem-formation.gif" /> <div class="legend">Animation montrant la formation des microgoutelettes en microfluidique. Les GEMs sont définies par un barcode unique représenté ici par une couleur</br> Source : <a href="https://www.10xgenomics.com/single-cell/">10xGenomics</a> </div> </div>
<div class="figure"> <img src="../images/post27/gem-formation2.gif" /> <div class="legend">Vidéo de microfluidique </br> Source : <a href="https://www.youtube.com/watch?v=zQoHc6PtIFk">Dolomite Microfluidics</a> </div> </div>
<h2>Chaque cellule a son barcode unique</h2>
<p>Chaque GEM est recouverte (figure ci-dessous) de séquences adaptatrices uniques contenant un <strong>barcode</strong>, un <strong><a href="https://en.wikipedia.org/wiki/Unique_molecular_identifier">UMI</a></strong> et la <strong>séquence PolyT</strong> . <br>
- Le <strong>barcode</strong> est l'identifiant unique à la bille, et donc unique à la cellule. 10xGenomics propose 750 000 barcodes environ. <br>
- L'<strong>UMI</strong> (Unique Molecular Identifiers) est une courte séquence aléatoire unique à chaque fragment entourant la bille. Il y a donc plusieurs UMI par bille. Cet identifiant est utilisé pour éviter les biais d'amplifications. Si une séquence est malencontreusement trop amplifiée dans une goutte, elle sera détectée, car le même UMI sera représenté plusieurs fois. <br>
- <strong>La séquence polyT</strong> va permettre la fixation des ARNs messagers par complémentarité avec leurs queues polyA.</p>
<div class="figure"> <img src="../images/post27/gem-zoom.png" /> <div class="legend">Zoom sur une GEM et les séquences la recouvrant</br> Source : <a href="https://www.10xgenomics.com/single-cell/">10xGenomics</a> </div> </div>
<p>La réaction de RNA-seq peut alors se faire dans ce microréacteur. Après lyse de la cellule, les ARNs messagers sont capturés à la surface de la GEM par leurs queues polyA. Et les nouvelles séquences Barcode+UMI+ARNm sont converties en ADNc.</p>
<h2>Création d'une librairie et séquençage</h2>
<p>Il ne reste plus alors qu'à créer la librairie pour le séquençage. Tous les fragments d'ADNs identifiés par leurs barcodes sont poolés ensemble après avoir enlevé l'huile. Les adaptateurs de séquençage (<a href="https://www.youtube.com/watch?v=fCd6B5HRaZ8&t=3s">Illumina</a>) sont ajoutés afin d'obtenir la librairie. <br>
Après le séquençage et l'alignement, il suffira de regrouper les reads provenant d'une même cellule en comparant leurs barcodes pour obtenir une matrice d'expression (tableau ci-dessous).</p>
<div class="figure"> <img src="../images/post27/expression-matrix-cell.png" /> <div class="legend">Exemple d'une matrice d'expression en Single Cell RNA Seq. En réalité, il y a des milliers de cellules (autant que de barcode) et au moins 23 000 gènes (pour l'homme). Les valeurs du tableau correspondent à la quantité d'ARNm retrouvé par gène et par cellule</div> </div>
<h2>Représentation graphique</h2>
<p>On peut alors représenter la matrice d'expression dans un graphique en réalisant une <a href="https://fr.wikipedia.org/wiki/Analyse_en_composantes_principales">analyse en composantes principales</a> (10x genomics utilise une <a href="https://fr.wikipedia.org/wiki/Algorithme_t-SNE">t-SNE</a>).
Chaque point correspond à une cellule. Plus les cellules sont proches sur le graphique, plus leurs expressions génétiques sont similaires. </p>
<div class="figure"> <img src="../images/post27/blood_example.png" /> <div class="legend">Profil d'expression obtenu à partir des cellules du sang (2,700 cellules mononuclées du sang périphérique <a href="https://fr.wikipedia.org/wiki/Cellule_mononucl%C3%A9%C3%A9e_sanguine_p%C3%A9riph%C3%A9rique)))">PBMC</a>. On visualise après clusterisation les différentes familles.</br> Source : <a href="http://satijalab.org/seurat/get_started_v1_4.html">http://satijalab.org/seurat/get_started_v1_4.html</a></div> </div>
<p>Encore plus parlant, <a href="https://www.10xgenomics.com/single-cell/?wvideo=z54e2lemhd">cette vidéo </a> qui montre le profil d'expression des cellules du tissu cérébral dans un repère à 3 axes animé.</p>
<h2>What next ?</h2>
<p>À l'heure où j'écrivais ce post, je suis tombé sur un article décrivant la technique <a href="http://www.genengnews.com/gen-news-highlights/single-nucleus-rna-seq-merges-with-microfluidics/81254868">DropNc-Seq</a>. Une méthode similaire à ce qui vient d'être décrit. Mais au lieu des cellules, ce sont les noyaux qui sont isolés pour le séquençage. On obtient alors le transcriptome nucléaire... Cool hein ? </p>
<h2>Références</h2>
<ul>
<li><a href="https://bioinfo-fr.net/lanalyse-de-donnees-rna-seq-mode-demploi">RNASeq sur bioinfo-fr</a></li>
<li><a href="https://www.10xgenomics.com/single-cell/">10xGenomics</a></li>
<li><a href="https://www.youtube.com/watch?v=zQoHc6PtIFk">Dolomite Microfluids</a></li>
<li><a href="https://www.ncbi.nlm.nih.gov/pubmed/28091601">Massively parallel digital transcriptional profiling of single cells</a></li>
<li><a href="https://www.youtube.com/watch?v=kIGwv0Kpgro">Vidéo commerciale</a></li>
</ul>La sélection génomique de la semaine #12017-08-27T18:30:55+02:002017-08-27T18:30:55+02:00Sacha Schutztag:dridk.me,2017-08-27:/selection-1.html<p>Pour ceux qui ne me suivent pas sur <a href="https://twitter.com/dridk">twitter</a>, je vais maintenant publier sur le blog une fois par semaine, l'actualité en génomique et bioinformatique que j'ai dénichée sur le net.
Si jamais je passe à côté de la news, n'hésitez pas à me le faire savoir pour que je …</p><p>Pour ceux qui ne me suivent pas sur <a href="https://twitter.com/dridk">twitter</a>, je vais maintenant publier sur le blog une fois par semaine, l'actualité en génomique et bioinformatique que j'ai dénichée sur le net.
Si jamais je passe à côté de la news, n'hésitez pas à me le faire savoir pour que je l'ajoute à ce fil hebdomadaire. </p>
<h4>Nouvelle version d'Ensembl</h4>
<p>La nouvelle version d' <a href="http://www.ensembl.org/index.html">Ensembl</a> est sortie dans sa version 90. <br>
Pour rappel, Ensembl est une base de données de génome avec leurs annotations.
Cette nouvelle version propose 19 nouveaux génomes de rongeurs.
L'annotation de la souris, de l'homme et du poisson-zèbre a également été mise à jour.
Pour voir l'ensemble des changements: <br>
<a href="http://www.ensembl.info/blog/2017/08/22/ensembl-90-has-been-released/">http://www.ensembl.info/blog/2017/08/22/ensembl-90-has-been-released/ </a></p>
<h4>Human genom Project-write</h4>
<p>J'ai découvert le <em>Human Genom Project-write</em> ou GP-write annoncé il y a un peu plus d'un an.
À l'instar du projet visant à séquencer le génome humain (GP-read), celui-ci a comme objectif de synthétiser un génome complet. <br>
En résumé, c'est le Préquelle de Frankenstein ... <br>
<a href="http://engineeringbiologycenter.org/">http://engineeringbiologycenter.org/</a></p>
<h4>Phenotate</h4>
<p>Phenotate propose de créer une base de données collaborative de sémiologie clinique des maladies rares. Vous êtes médecins ou étudiants, vous devez compléter la liste des signes cliniques d'une maladie pour gagner des points.
Cette base de données se veut plus précise que <a href="http://human-phenotype-ontology.github.io/">HPO</a>. <br>
<a href="http://phenotate.org/">http://phenotate.org/</a></p>
<h4>Dépistage prénatal des maladies monogéniques</h4>
<p>Après le dépistage prénatal des trisomies (<a href="dpni.html">voir article</a>), une étude a montré qu'il était possible de détecter des maladies monogénétiques (<a href="https://fr.wikipedia.org/wiki/Mucoviscidose">Mucoviscidose</a>) chez le foetus sur une prise de sang en séquençant l' ADN circulant. <br>
Pour distinguer les séquences d'ADN du foetus et de la mère, ils ont d'abord détecté les haplotypes des parents puis la mutation associée à l'haplotype du foetus.<br>
D'ici 2 ans, il y a de grande chances que ces tests deviennent d'usage courant. <br>
<a href="http://www.cell.com/ajhg/fulltext/S0002-9297(17)30290-2">http://www.cell.com/ajhg/fulltext/S0002-9297(17)30290-2</a></p>
<h4>Stratos</h4>
<p>Statos est ma découverte de la semaine. C'est une technologie de séquençage haut débit permettant d'améliorer la détection du signal sur <a href="https://fr.wikipedia.org/wiki/Nanopore">nanopore</a>.
Cette technologie clone la molécule d'ADN en remplaçant les nucléotides A,C,G,T par des grosses molécules appelées <em>xpandomer</em>. Cette nouvelle séquence de xpandomer qui contient l'information génétique peut alors être séquencée plus facilement.<br>
<a href="https://www.stratosgenomics.com/">https://www.stratosgenomics.com/</a></p>
<p> <iframe width="560" height="315" src="https://www.youtube.com/embed/ADzIXItP4hE" frameborder="0" allowfullscreen></iframe> </p>
<h2>Twitter</h2>
<p>Pour plus de news ou me faire part des vôtres, suivez-moi sur <a href="https://twitter.com/dridk">twitter @dridk</a></p>Le génome d'un embryon humain a été édité2017-08-06T22:49:20+02:002017-08-06T22:49:20+02:00Sacha Schutztag:dridk.me,2017-08-06:/edition-embryon-humain.html<p>Si vous êtes passé à côté de la news de la semaine, sachez qu'une équipe américaine a réussi à corriger une mutation génétique lors d'une <a href="https://fr.wikipedia.org/wiki/F%C3%A9condation_in_vitro">fécondation in vitro</a> à l'aide du couteau suisse moléculaire <a href="https://fr.wikipedia.org/wiki/Cas9">CRISPR-Cas9</a>.
Une grande étape a été franchie en thérapie génique avec tous les problèmes éthiques qui …</p><p>Si vous êtes passé à côté de la news de la semaine, sachez qu'une équipe américaine a réussi à corriger une mutation génétique lors d'une <a href="https://fr.wikipedia.org/wiki/F%C3%A9condation_in_vitro">fécondation in vitro</a> à l'aide du couteau suisse moléculaire <a href="https://fr.wikipedia.org/wiki/Cas9">CRISPR-Cas9</a>.
Une grande étape a été franchie en thérapie génique avec tous les problèmes éthiques qui en découlent comme l'eugénisme ou le transhumanisme.
Je me dois de vous faire un résumé rapide de cet article "<em>Correction of a pathogenic gene mutation in human embryos</em>" disponible <a href="http://www.nature.com/nature/journal/vaop/ncurrent/full/nature23305.html">ici</a>. </p>
<h2>Correction d'une maladie autosomique dominante</h2>
<p>L'équipe a choisi de corriger une mutation sur le gène <a href="https://ghr.nlm.nih.gov/gene/MYBPC3">MYBPC3</a> responsable d'une <a href="http://www.rythmo.fr/la-cardiomyopathie-hypertrophique/">cardiomyopathie hypertrophique héréditaire</a>. C'est la maladie du sportif qui fait une mort subite en plein match.<br>
C'est une maladie <a href="https://fr.wikipedia.org/wiki/Transmission_autosomique_dominante">autosomique dominante</a>. C'est-à-dire qu'un seul allèle muté suffit pour provoquer la maladie. C'est important pour la suite, car l'édition du gène a besoin de la présence d'un allèle sain.
La mutation cible est une délétion de 4 nucléotides dans l'exon 16 du gène.</p>
<h2>Édition avec CRISPR-cas9</h2>
<p>L'édition du gène a été réalisée après fécondation in vitro entre le spermatozoïde d'un patient porteur de la mutation et un ovocyte sain.
Le complexe CRISPR-Cas9 a été injecté dans l'oeuf 18h après fécondation par <a href="https://www.youtube.com/watch?v=_v9xckdeVhU">micro-injection (vidéo)</a>.
CRISPR-Cas9 fait une coupure double brin pour retirer la région d'ADN contenant la mutation. Puis une <a href="https://fr.wikipedia.org/wiki/Polym%C3%A9rase">polymérase</a> entre en action et corrige ce trou béant en utilisant l'allèle homologue non muté comme modèle. C'est ce qu'on appelle une <a href="https://fr.wikipedia.org/wiki/Recombinaison_homologue">réparation par recombinaison homologue</a> ou HDR (Homology Directed Repear). Pour cette raison, seules les mutations hétérozygotes peuvent être corrigées avec ce protocole.
Un autre mécanisme de réparation non conservatrice peut avoir lieu, la <a href="https://fr.wikipedia.org/wiki/Jonction_d%27extr%C3%A9mit%C3%A9s_non_homologues">Jonction d'extrémités non homologues</a> ou NHEJ (Non-Homologous End-Joining). Cette dernière ne corrige rien, et l'on cherche à l'eviter autant que possible.</p>
<div class="figure">
<img src="../images/post26/crispr-homolog.png" />
<div class="legend">réparation par recombinaison homologue</div>
</div>
<p>L'expérience a été répétée plusieurs fois. Au total dans l'étude il y a eu <strong>19</strong> embryons témoins non injectés et <strong>54</strong> embryons injectés. L'ensemble des embryons ont ensuite été séquencés au stade 4-8 cellules pour voir si l'édition a réussi.</p>
<div class="figure">
<img src="../images/post26/gene_correction.png" />
<div class="legend">1. Fécondation avec un spermatozoïde muté. 2. Injection de CRISPR-CAS9. 3. Plusieurs cas sont alors possibles. ça ne marche pas;ça marche à moitié (mosaïque);ça marche; HDR (Homology directed repair), NHEJ (Non-Homologous End-Joining) </div>
</div>
<h2>bien, mais pas encore au point !</h2>
<p>Chez les témoins, comme on s'y attend, la moitié des embryons ont été fécondés par un spermatozoïde muté (hétérozygote: <strong>10/19</strong>) ou par un spermatozoïde non muté (homozygote: <strong>9/19</strong>). Je rappelle que le père est hétérozygote pour la mutation et donc que la moitié de ses spermatozoïdes porte la mutation.
En revanche, dans les embryons injectés <strong>66.7% (36/54)</strong> sont homozygotes sains et seulement <strong>9.3% (13/54)</strong> sont hétérozygotes mutés. Les <strong>24% (5/54)</strong> restant, corresponde à des embryons en <a href="https://fr.wikipedia.org/wiki/Mosa%C3%AFque_(g%C3%A9n%C3%A9tique)">mosaiques</a>. Ce sont des embryons où certaines cellules ont été corrigées et d'autre non.
En conclusion, ça marche, mais la technique n'est pas encore au point, car il reste pas mal de mosaïssisme. Pour y remédier, l'idée proposée est de faire l'injection CRISPR-cas9 au même moment que l'injection du spermatozoïde.
Il y a également le risque des mutations induit par CRISPR-Cas9. Les fameuses <a href="https://www.lequotidiendumedecin.fr/actualites/article/2017/05/29/crispr-des-mutations-targets-encore-plus-inattendues_847911">mutations off-target</a>. Aucune n'a été détectée dans cette étude. </p>
<div class="figure">
<img src="../images/post26/results.png" />
<div class="legend">Gauche: Témoin sans injection CRISPR-Cas9. 50% des embryons sont mutés . Droite: Avec injection CRISPR-Cas9. 66.7% des embryons sont sains. </div>
</div>
<h2>Et l'éthique dans tout ça ?</h2>
<p>Pour l'heure, l'<a href="http://www.cell.com/ajhg/fulltext/S0002-9297(17)30247-1">ASHG a donné son autorisation</a> sur l'édition des embryons tant que les recherches ne conduisent pas à une grossesse et qu'il y a un rationnel scientifique et éthique derrière. <br>
Mais un pas a tout de même été franchi, et je pense que rapidement, l'édition des génomes deviendra aussi courante que le <a href="https://fr.wikipedia.org/wiki/Diagnostic_pr%C3%A9implantatoire">diagnostic préimplantatoire</a>.
Avec l'apparition croissante des start-up en génomique, comme <a href="https://www.23andme.com/">23andMe</a> ou <a href="https://www.helix.com/">Helix</a> qui s'affranchissent de la barrière médicale, les enjeux éthiques vont vite prendre de l'ampleur. Et les bébés conçus à la carte sur internet seront peut-être monnaie courante. <br>
D'autre part, l'éradication des maladies génétiques peut paraitre merveilleuse. Mais à l'échelle des populations cela implique la diminution de la diversité génétique et donc une diminution de notre capacité d'aptation dans l'évolution biologique.<br>
<em><a href="https://www.youtube.com/watch?v=7u3RrbNpRUQ">Bienvenue à GATTACCA</a></em> n'a jamais été aussi proche.</p>
<div class="figure">
<img src="../images/post26/gattaca.gif" />
</div>Fabrication des sondes de captures par technologie MAS2017-07-23T11:26:45+02:002017-07-23T11:26:45+02:00Sacha Schutztag:dridk.me,2017-07-23:/puce-adn-mas.html<p>Pour séquencer un <a href="https://fr.wikipedia.org/wiki/Exome">exome</a>, il faut d'abord capturer toutes les séquences exoniques. Une méthode est d'utiliser des sondes <a href="https://fr.wikipedia.org/wiki/Oligonucl%C3%A9otide">oligonucléotidiques</a> qui s'hybrident spécifiquement sur les <a href="https://fr.wikipedia.org/wiki/Exon">exons</a>. Ce qui demande une connaissance préalable des séquences codantes, mais aussi une technologie capable de fabriquer des millions de sondes avec leurs séquences déterminées.<br>
Comment …</p><p>Pour séquencer un <a href="https://fr.wikipedia.org/wiki/Exome">exome</a>, il faut d'abord capturer toutes les séquences exoniques. Une méthode est d'utiliser des sondes <a href="https://fr.wikipedia.org/wiki/Oligonucl%C3%A9otide">oligonucléotidiques</a> qui s'hybrident spécifiquement sur les <a href="https://fr.wikipedia.org/wiki/Exon">exons</a>. Ce qui demande une connaissance préalable des séquences codantes, mais aussi une technologie capable de fabriquer des millions de sondes avec leurs séquences déterminées.<br>
Comment ces sondes sont produites ? </p>
<h1>Technologie Maskless Array Synthesis (MAS)</h1>
<p><a href="http://sequencing.roche.com/products/nimblegen-seqcap-target-enrichment.html">Roche/NimbleGen</a> utilise une technique de synthèse des sondes sur lame <em>in situ</em>. C'est-à-dire que les sondes sont directement synthétisées sur la lame et non déposées par un robot comme les techniques classiques (<a href="https://fr.wikipedia.org/wiki/Puce_%C3%A0_ADN#Par_d.C3.A9p.C3.B4t_.28spotted.29">Microarray spotting</a>).<br>
Pour cela ils utilisent la <a href="https://fr.wikipedia.org/wiki/Photolithographie">photolithographie</a> associée à une <a href="https://fr.wikipedia.org/wiki/Matrice_de_micro-miroirs">matrice de micro-miroirs</a>. Cette technologie consiste à utiliser des rayons lumineux dirigés par des miroirs pour guider la synthèse des sondes.
Chaque nucléotide est protégé par une <a href="https://en.wikipedia.org/wiki/Photolabile_protecting_group">groupement photolabile</a> qui empêche l'association avec un autre nucléotide. En présence de lumière, cette molécule est supprimé, un nouveau nucléotide peut alors se lier.<br>
Pour faire simple :</p>
<ul>
<li>Prener une lame et déposez-y des nucléotides protégés. </li>
<li>Éclairer certains nucléotides pour les déprotéger. </li>
<li>Inonder votre lame avec plein de nucléotides 'G' qui se fixe uniquement sur les nucléotides libérés. </li>
</ul>
<p>Recommencer la procédure, mais cette fois en inondant avec que du C, et ainsi de suite.<br>
La vidéo ci-dessous résume bien ce cycle de synthèse. </p>
<div class="figure">
<img src="../images/post25/MAS1.png" />
<div class="legend">Illustration de la technologie MAS</div>
</div>
<div class="figure">
<video controls src="../images/post25/media2.webm"> Synthèse des oligonucléotides</video>
</div>
<h2>Digital Micromirror Device (DMD)</h2>
<p>Maintenant, comment eclairer les milliers de sondes spécifiquement ?
Ils utilisent pour cela, des matrices de micro-miroirs de 16µm chacun. Il s'agit d'une grille composée de millions de petits miroirs qui peuvent s'incliner independement dans deux conformations ON ou OFF. En eclairant tout la grille, les rayons lumineux sont réfléchis vers la lame suivant l'orientation des miroirs. Anis, en programmant les états ON/OFF des micros-miroirs pendant le cycle de synthèse, on peut synthétiser des millions de sondes en spécifiant leurs séquences.<br>
Jetez un oeil sur cette dernière vidéo résumant mes propos.</p>
<div class="figure">
<video controls src="../images/post25/media1.webm"> Matrices de micro-miroirs</video>
</div>
<h2>Références</h2>
<ul>
<li><a href="http://bitesizebio.com/7463/how-dna-microarrays-are-built/">Les methodes de fabrication des puces à ADN</a></li>
<li><a href="http://sequencing.roche.com/products/nimblegen-seqcap-target-enrichment.html">Roche nimblegen</a></li>
<li><a href="https://fr.wikipedia.org/wiki/Puce_%C3%A0_ADN#Fabrication">Wikipedia: Fabrication des puces</a></li>
</ul>Raccourci git sous zsh2017-07-22T13:28:22+02:002017-07-22T13:28:22+02:00Sacha schutztag:dridk.me,2017-07-22:/git-sous-zsh.html<p>Raccourci pour utiliser git sous zsh</p><p>Si vous utilisez git sous <a href="https://fr.wikipedia.org/wiki/Z_Shell">zsh</a> avec le plugin <a href="https://github.com/robbyrussell/oh-my-zsh">oh-my-zsh</a>, avez vous notez l'ensemble des alias <a href="https://fr.wikipedia.org/wiki/Git">git</a> disponible ?
Au lieu de taper mes commandes git en entier, par exemple : </p>
<div class="highlight"><pre><span></span><code>git commit -a
</code></pre></div>
<p>J'ai juste à taper : </p>
<div class="highlight"><pre><span></span><code>gca
</code></pre></div>
<p>Il y en a des tonnes. Les commandes usuelles que j'utilise : </p>
<div class="highlight"><pre><span></span><code>gp => git push
gl => git pull
gca => git commit -a
gco => git checkout
gb => git branch
glg = > git log
</code></pre></div>
<p>Allez jeter un oeil <a href="https://github.com/robbyrussell/oh-my-zsh/blob/master/plugins/git/git.plugin.zsh">ici</a> pour voir la liste complete. Il y en a un bon paquet !</p>Un hook git pour mon blog2017-07-13T00:53:37+02:002017-07-13T00:53:37+02:00Sacha Schutztag:dridk.me,2017-07-13:/un-hook-git-pour-mon-blog.html<p>Vous l'avez sûrement remarqué, j'écris mon blog avec <a href="http://docs.getpelican.com/en/stable/">pelican</a>.
Lorsque je suis prêt à publier, je commit mon blog sur <a href="https://github.com/">github</a>, puis dans un second temps je synchronise mon dossier html généré sur mon serveur web.
Et comme je suis fainéant, je veux que ces deux étapes se fassent en …</p><p>Vous l'avez sûrement remarqué, j'écris mon blog avec <a href="http://docs.getpelican.com/en/stable/">pelican</a>.
Lorsque je suis prêt à publier, je commit mon blog sur <a href="https://github.com/">github</a>, puis dans un second temps je synchronise mon dossier html généré sur mon serveur web.
Et comme je suis fainéant, je veux que ces deux étapes se fassent en même temps. Pour cela j'utilise les <a href="https://git-scm.com/book/gr/v2/Customizing-Git-Git-Hooks">hooks</a> de git coté client. </p>
<h1>Les hooks</h1>
<p>Les hooks sont des scripts qui peuvent s’exécuter côté client (mais aussi côté serveur) après un événement git.
Dans mon cas, je veux uploader mon dossier html sur mon serveur web à chaque fois que je fais un <em>git push</em>. La commande a exécuté et fourni dans le <em>Makefile</em> de pelican. Elle synchronise les fichiers html sur mon serveur web avec <em>rsync</em> et ma clef ssh. </p>
<div class="highlight"><pre><span></span><code><span class="n">make</span><span class="w"> </span><span class="n">rsync_upload</span><span class="w"></span>
</code></pre></div>
<p>Pour exécuter cette commande à chaque <em>git push</em>, il me suffit d'écrire un script dans le dossier <em>.git/hooks</em> et de lui donner le bon nom de fichier. Tous les fichiers d'extensions <em>.sample</em> déjà présent sont des exemples avec les noms appropriés correspondant à l'étape d'exécution. Supprimer l'extension <em>.sample</em> pour que le script s’exécute. Dans mon cas, je veux lancer ma synchronisation avant chaque <em>push</em>. J'écris tout simplement la commande précédente dans le fichier <em>.git/hooks/pre-push</em>. </p>
<div class="highlight"><pre><span></span><code><span class="n">echo</span><span class="w"> </span><span class="s2">"make rsync_upload"</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="o">.</span><span class="n">git</span><span class="o">/</span><span class="n">hooks</span><span class="o">/</span><span class="n">pre</span><span class="o">-</span><span class="n">push</span><span class="w"></span>
</code></pre></div>
<h1>zsh et ssh-agent</h1>
<p>Afin d'éviter de retaper mes mots de passe plusieurs fois, aussi bien pour github que pour la synchro sur mon serveur web, j'utilise des clefs ssh.
Par default, <em>ssh-agent</em> ne marche pas avec <a href="https://fr.wikipedia.org/wiki/Z_Shell">zsh</a>. Il faut modifier le script ~/.zshrc et modifier la ligne plugin et relancer zsh:</p>
<div class="highlight"><pre><span></span><code>vim ~/.zshrc
plugins=(git ssh-agent)
</code></pre></div>
<p>Voilà. Maintenant à chaque <em>push</em> et sans me demander mon mot de passe, mon blog est envoyé sur github puis sur mon serveur web.</p>
<p>PS : Je vais essayer de publier plus de notes courtes de ce type, si ça ne vous embête pas. C'est moins long à faire, et comme ça je peux partager ce que j'apprends plus rapidement. </p>Le séquençage de nouvelle génération2017-07-13T00:23:31+02:002017-07-13T00:23:31+02:00Sacha Schutztag:dridk.me,2017-07-13:/ngs.html<p><a href="https://fr.wikipedia.org/wiki/S%C3%A9quen%C3%A7age_de_l%27ADN#S.C3.A9quen.C3.A7age_haut_d.C3.A9bit_.28HTS.29">Le séquençage de nouvelle génération </a>(<em>NGS: Next Generation Sequencing</em>) est la révolution biotechnologique de ces dernières années, en permettant de séquencer de grandes quantités d'ADN en des temps records.
À titre d'exemple, le projet <a href="https://en.wikipedia.org/wiki/Human_genome">human genome</a> a coûté 3 milliards de dollars sur 13 ans entre 1990 et 2003 pour …</p><p><a href="https://fr.wikipedia.org/wiki/S%C3%A9quen%C3%A7age_de_l%27ADN#S.C3.A9quen.C3.A7age_haut_d.C3.A9bit_.28HTS.29">Le séquençage de nouvelle génération </a>(<em>NGS: Next Generation Sequencing</em>) est la révolution biotechnologique de ces dernières années, en permettant de séquencer de grandes quantités d'ADN en des temps records.
À titre d'exemple, le projet <a href="https://en.wikipedia.org/wiki/Human_genome">human genome</a> a coûté 3 milliards de dollars sur 13 ans entre 1990 et 2003 pour séquencer le génome humain en utilisant des séquenceurs de type <em><a href="https://en.wikipedia.org/wiki/Sanger_sequencing">Sanger</a></em> répartis dans plusieurs laboratoires à travers le monde. Aujourd'hui, avec un séquenceur NGS <a href="https://www.illumina.com/systems/sequencing-platforms/hiseq-x.html">Illumina HiSeq X</a>, en trois jours, on peut séquencer trois génomes humains pour <a href="http://www.nature.com/news/is-the-1-000-genome-for-real-1.14530">1000 dollars</a> chacun. Le graphique ci-dessous, que vous verrez régulièrement, montre l'évolution du coût de séquençage par million de nucléotides au cours du temps. Et encore, ce graphique s'arrête en 2015. La société Illumina a déjà promis le génome à <a href="https://www.illumina.com/company/news-center/press-releases/press-release-details.html?newsid=2236383">$100</a> d'ici deux ans avec le nouveau séquenceur <a href="https://www.illumina.com/systems/sequencing-platforms/novaseq.html">Illumina NovaSeq</a>.<br>
Cet article est un avant-gout très vulgarisé pour découvrir les bases du séquençage haut débit. </p>
<div class="figure"> <img src="../images/post22/moore.png" /> <div class="legend">Diminutions du coût du séquençage par nucléotides au cours des dernières années</div> </div>
<h1>Un séquençage à haut-débit</h1>
<p>Imaginez que votre génome s'assimile à un gros livre de plus de 3 milliards de caractères (nucléotides) écrit avec les lettres A,C,G et T. Séquencer, c'est lire le contenu de ce livre. Vous pouvez soit le lire entièrement, c'est-à-dire séquencer l'ensemble de votre génome. Soit lire certaines pages ou chapitre, c'est-à-dire faire du séquençage ciblé.
Les séquenceurs actuels ne peuvent lire que des courts fragments d'ADN qu'il faut ensuite assembler pour reconstruire le texte d'origine. Par exemple, les séquenceurs de premières générations de type <a href="https://fr.wikipedia.org/wiki/S%C3%A9quen%C3%A7age_de_l%27ADN#M.C3.A9thode_de_Sanger">Sanger</a> sont capables de lire des fragments d'environ 800 caractères en 1 heure sur 1 capillaire. Si vous faites le calcul, vous verrez rapidement que pour atteindre les 3 milliards de nucléotides, il vous faudra plus d'une vie pour réussir à séquencer votre génome (>400 ans). Pour aller plus vite, l'idée est de lire plusieurs fragments en même temps, c'est-à-dire paralléliser le séquençage. Les plus performants des séquenceurs Sanger, peuvent paralléliser jusqu'à <a href="https://www.thermofisher.com/order/catalog/product/3730XL">96 fois</a> en utilisant 96 capillaires. On a donc 96 x 800 nucléotides lus en 1 heure. C'est pas encore ça. Les séquenceurs NGS de deuxièmes générations sont capables, eux, de lire des fragments de 150 à 300 pb mais jusqu'à <a href="https://www.illumina.com/systems/sequencing-platforms/novaseq.html">20 milliards</a> de fragments à la fois!!! </p>
<h1>Librairie de séquençage</h1>
<p>Ce qu'on appelle une <strong>librairie</strong>, est l'ensemble des fragments d'ADN que l'on veut séquencer. Pour créer une librairie, deux méthodes sont à retenir si l'on veut séquencer l'ensemble du génome ou des régions d'intérêts. </p>
<h3>Méthode globale</h3>
<p>Lancez le livre en l'air et tirez dessus au shotgun pour faire une pluie de fragments d'ADN aléatoire. C'est ce qu'on appelle <em>stricto sensu</em>, la <a href="https://fr.wikipedia.org/wiki/S%C3%A9quen%C3%A7age_de_l%27ADN#M.C3.A9thode_globale_ou_Shotgun">stratégie shotgun</a>. Cette méthode est utilisée par exemple pour séquencer des génomes entiers.</p>
<div class="figure"> <img src="../images/post22/shotgun.png" /> <div class="legend">La stratégie shotgun consiste à fragmenter l'ADN en séquence aléatoire puis à les séquencer.</div> </div>
<p>Plusieurs méthodes existent pour fragmenter l'ADN:</p>
<ul>
<li><strong>Fragmentation par sonication</strong> : En envoyant des ultra-sons à la bonne fréquence, on casse l'ADN en morceaux de tailles précises.</li>
<li><strong>Fragmentation enzymatique</strong> : L'utilisation d'<a href="https://fr.wikipedia.org/wiki/Enzyme_de_restriction">enzymes de restriction</a> permet de couper l'ADN au niveau de certains motifs. </li>
</ul>
<h3>Méthode ciblée</h3>
<p>On ne veut pas forcément lire l'ensemble du génome. On peut vouloir par exemple séquencer uniquement la partie codante (<a href="https://fr.wikipedia.org/wiki/Exome">exome</a>), qui je le rappelle, représente <a href="https://dridk.me/genome_chiffre_1.html">moins de 2%</a> ; ou simplement séquencer une liste de gènes (<a href="https://www.gatc-biotech.com/fr/expertise/sequencage-cible/panel-de-genes.html">panel de gènes</a>) associée à une maladie. <br>
Dans tous les cas, il faut enrichir la librairie en sélectionnant uniquement les fragments d'ADN désirés. Deux techniques sont à retenir:</p>
<ul>
<li><strong>L'enrichissement <a href="https://www.ncbi.nlm.nih.gov/pubmed/18330355">par capture</a></strong> : Après fragmentation, les fragments d'ADN sont filtrés en s'hybridant à des séquences complémentaires disposées sur une plaque ou en milieu liquide. Les fragments d'ADN qui ne s'hybrident pas sont éliminés. </li>
</ul>
<div class="figure"> <img src="../images/post22/capture.png" /> <div class="legend">Exemple d'enrichissement en phase liquide grâce à des billes magnétiques</div> </div>
<ul>
<li><strong>Enrichissement par PCR</strong> : Les fragments désirés sont amplifiés par <a href="https://fr.wikipedia.org/wiki/PCR">PCR</a>. Nous pouvons amplifier une seule région avec un couple d'amorces (simplex), ou alors amplifier plusieurs régions avec plusieurs couples d'amorces (multiplex). Dans cette stratégie, toutes les séquences d'un même <a href="https://fr.wikipedia.org/wiki/Amplicon">amplicon</a> seront identiques. </li>
</ul>
<div class="figure"> <img src="../images/post22/amplicon.png" /> <div class="legend">La stratégie par amplicon produit des séquences identiques</div> </div>
<h1>Sequençage</h1>
<p>Il existe différentes méthodes de séquençage:</p>
<ul>
<li>Le séquençage par synthèse (<a href="https://www.illumina.com/">Illumina</a>).</li>
<li>Le pyroséquençage (<a href="https://fr.wikipedia.org/wiki/Technique_de_s%C3%A9quen%C3%A7age_454">Roche 454</a>).</li>
<li>La ligation (<a href="https://www.thermofisher.com/fr/fr/home/life-science/sequencing/next-generation-sequencing/solid-next-generation-sequencing.html">SOLid</a> <a href="https://www.thermofisher.com/fr/fr/home.html">Thermofisher</a>).</li>
<li>La détection des ions H+ (<a href="https://www.thermofisher.com/fr/fr/home/life-science/sequencing/next-generation-sequencing/ion-torrent-next-generation-sequencing-workflow/ion-torrent-next-generation-sequencing-run-sequence/ion-proton-system-for-next-generation-sequencing.html">Proton</a> <a href="https://www.thermofisher.com/fr/fr/home.html">Thermofisher</a>).</li>
</ul>
<p>Dans l'ensemble, le principe général reste le même. Chaque fragment est d'abord cloné plusieurs fois afin d'amplifier le signal. Puis le brin complémentaire de chaque fragment cloné est synthétisé. À chaque incorporation d'un nucléotide, un signal est détecté. De la lumière pour Illumina ou une variation de pH sur du Proton.
À la fin du séquençage, chaque fragment a été séquencé en parallèle. L'ensemble des données est enregistré dans un fichier <em>Fastq</em>.</p>
<h2>Exemple de séquençage sur Proton</h2>
<div class="figure"> <img src="../images/post22/ion.png" /> <div class="legend">Schéma simplifié d'un séquençage type Proton</div> </div>
<p>Pour plus de détail sur les techniques de séquençage, jettez un oeil sur les belles vidéos commerciales ci-dessous: </p>
<ul>
<li><a href="https://www.youtube.com/watch?v=WYBzbxIfuKs">Ion Torrent™ next-gen sequencing technology</a></li>
<li><a href="https://www.youtube.com/watch?v=fCd6B5HRaZ8">Illumina Sequencing by Synthesis</a> </li>
</ul>
<h1>Alignement des séquences</h1>
<p>À la fin du séquençage, la chimie fait place à la bioinformatique. Les séquences des fragments, qu'on appelle maintenant des "reads", sont sauvegardées dans un fichier <a href="https://fr.wikipedia.org/wiki/FASTQ">Fastq</a> contenant les séquences et leurs scores de qualité (<a href="https://fr.wikipedia.org/wiki/Score_de_qualit%C3%A9_phred">score Phred</a>). Ce score évalue la confiance du séquençage. Par exemple le séquenceur vous dira que pour tel reads, la probablité que le quatrième nucléotide soit un 'A' est de 99,9%. Ce score appelé 'Q score' est encodé en caractère <a href="https://fr.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange">ASCII</a> pour chaque nucléotide d'un read.<br>
Télécharger <a href="http://www.internationalgenome.org/data-portal/sample">ici</a> un exemple pour voir à quoi ça ressemble. </p>
<div class="figure"> <img src="../images/post22/fastq_fig.jpg" /> <div class="legend">Aperçu d'un read dans un fichier fastq. Le score de qualité associe à chaque nucléotide un caractère <a href="https://fr.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange) correspondant à un score"> ASCII </a> </div> </div>
<p>Mais le travail est loin d'être fini. Ce que nous avons, ce sont uniquement des courtes séquences de 150 pb en général. Ce que nous voulons, c'est obtenir la séquence complète d'un gène ou d'un génome entier. Pour cela, il faut reconstruire un puzzle en réalisant un <a href="https://fr.wikipedia.org/wiki/Alignement_de_s%C3%A9quences">alignement</a>. Deux méthodes existent :</p>
<ul>
<li><strong>Assemblage de novo</strong> : Il s'agit de résoudre un puzzle sans son modèle. Les fragments d'ADN qui sont chevauchants permettent petit à petit de reconstruire ce qu'on appelle un <a href="https://fr.wikipedia.org/wiki/Contig">contig</a>. L'assemblage des contigs entre eux permet d'obtenir un scaffold. Cette technique est très couteuse en termes de calcul. Des algorithmes bioinformatiques comme les <a href="https://fr.wikipedia.org/wiki/Graphe_de_de_Bruijn">graphe de Bruijn</a>, permettent de résoudre ce problème. Cette méthode est principalement employée pour reconstruire des génomes non connus.</li>
</ul>
<div class="figure"> <img src="../images/post22/aligndenovo.png" /> <div class="legend">L'alignement de novo consiste à aligner les reads entre eux</div> </div>
<ul>
<li><strong>Alignement avec référence</strong>: Il s'agit toujours de résoudre un puzzle. Mais cette fois, en s'aidant d'un modèle. Par exemple, une version du génome humain (<a href="https://en.wikipedia.org/wiki/Reference_genome#Human_reference_genome">hg19</a>). <br>
Chaque read est aligné sur cette référence. La complexité de calcul est plus simple qu'avec l'alignement de novo. On utilise en général l'algorithme de <a href="https://dridk.me/bwt.html">Burrows Wheeler</a> permettant de rechercher de manière efficace une correspondance entre les reads et la référence. Après cet alignement, on obtient un fichier <a href="https://en.wikipedia.org/wiki/SAM_(file_format)">BAM</a> associant à chaque reads ses coordonnées génomiques. C'est à dire le chromosome et la position. <br>
On appelle la <strong>profondeur</strong>, le nombre moyen de reads qui se superpose et <strong>recouvrement</strong>, l'étalement des reads sur la zone d'intérêt. </li>
</ul>
<div class="figure"> <img src="../images/post22/alignref.png" /> <div class="legend">L'alignement avec référence consiste à aligner les reads sur une référence</div> </div>
<div class="figure"> <a href="../images/post22/samtools.png"><img src="../images/post22/samtools_thumb.png" /> </a> <div class="legend">Visualisation d'un alignement réel avec <a href="http://samtools.sourceforge.net/">Samtools</a></div> </div>
<h1>Évaluation d'un séquenceur</h1>
<p>Avec tout ça, vous êtes capable d'évaluer la capacité d'un séquenceur comme vous le feriez avant l'achat d'un PC ou d'une voiture. <br>
Les capacités d'un séquenceur sont définies par : </p>
<ul>
<li>La longueur des reads produits (L)</li>
<li>Le nombre de reads produits (n)</li>
<li>Le nombre de nucléotides lu: (L x n)</li>
<li>Le temps de séquençage </li>
<li>La qualité du séquençage</li>
</ul>
<p>Allez faire un tour sur <a href="https://www.illumina.com/systems/sequencing-platforms.html">le site d'Illumina</a> pour comparer les modèles entre eux.</p>
<h1>Pour finir, les séquenceurs de 3ème génération</h1>
<p>À peine sortie, ces technologies sont déjà devancées par les séquenceurs de 3ème générations. Ce sont des séquenceurs capables de générer de très longs reads sans avoir besoin de cloner les fragments pour amplifier le signal. C'est pour cette raison qu'on les appelle aussi "Single molecule sequencing". En revanche, ces nouvelles techniques produisent encore beaucoup d'erreurs de séquençage. Les deux leaders de ce Next Next Generation Sequencing sont <a href="https://nanoporetech.com/">Nanopore</a> et <a href="https://www.google.fr/search?q=Pacific+bioscience&oq=Pacific+bioscience&aqs=chrome..69i57j0l5.4887j0j4&sourceid=chrome&ie=UTF-8">PacBio Science</a> qui termine une <a href="http://www.frontlinegenomics.com/news/10714/pacbio-lawsuit-oxford-nanopore/">guerre de brevet</a>. <br>
La miniaturisation de ces séquenceurs sera peut être un jour disponible chez tout bon médecin généraliste qui vous diagnostiquera votre prédisposition d'infarctus ou d'Alzheimer en quelques heures. Effrayant ou rassurant, à vous de choisir! </p>
<ul>
<li><a href="https://www.youtube.com/watch?v=v8p4ph2MAvI">Vidéo Pacific Biosciences Technologies</a></li>
<li><a href="https://www.youtube.com/watch?v=3UHw22hBpAk">Vidéo Oxford Nanopore Technologies</a></li>
</ul>
<div class="figure"> <a href="../images/post22/samtools.png"><img src="../images/post22/smidgion.jpg" /> </a> <div class="legend">vous ne rêvez pas... C'est le <a href="https://nanoporetech.com/products/smidgion">SmidgIon</a> d'Ofxord Nanopore, un séquenceur qui se branche sur un IPhone</div> </div>
<h2>Références</h2>
<ul>
<li><a href="https://www.abmgood.com/marketing/knowledge_base/next_generation_sequencing_introduction.php#similarities">ABMGOOD: tout comprendre sur le NGS</a></li>
<li><a href="https://fr.coursera.org/learn/bioinformatics-pku/lecture/Wu9kW/from-sequencing-to-ngs">Coursera : cours NGS</a></li>
<li><a href="http://bioinformaticsalgorithms.com/">Bioinformatics Algorithms </a></li>
</ul>
<h2>Remerciements</h2>
<p><a href="https://github.com/pausrrls">@pausrrls</a> </p>La maladie de Huntington2017-05-13T15:07:59+02:002017-05-13T15:07:59+02:00Sacha Schutztag:dridk.me,2017-05-13:/maladie-huntigton.html<p><a href="https://fr.wikipedia.org/wiki/Liste_des_maladies_g%C3%A9n%C3%A9tiques_%C3%A0_g%C3%A8ne_non_identifi%C3%A9">Un nombre important de maladies génétiques</a> sont causées par des <a href="https://fr.wikipedia.org/wiki/Mutation_ponctuelle">mutations ponctuelles</a>, c'est-à-dire des mutations à l'échelle du nucléotide. Les mécanismes sous-jacents, que vous devez certainement connaître, sont la substitution, la délétion ou l'insertion de nucléotides dans la séquence d'un gène.
Les mutations dynamiques sont peut-être moins connues mais elles …</p><p><a href="https://fr.wikipedia.org/wiki/Liste_des_maladies_g%C3%A9n%C3%A9tiques_%C3%A0_g%C3%A8ne_non_identifi%C3%A9">Un nombre important de maladies génétiques</a> sont causées par des <a href="https://fr.wikipedia.org/wiki/Mutation_ponctuelle">mutations ponctuelles</a>, c'est-à-dire des mutations à l'échelle du nucléotide. Les mécanismes sous-jacents, que vous devez certainement connaître, sont la substitution, la délétion ou l'insertion de nucléotides dans la séquence d'un gène.
Les mutations dynamiques sont peut-être moins connues mais elles sont pourtant responsables de plusieurs maladies génétiques héréditaires. Notamment une <a href="https://fr.wikipedia.org/wiki/Maladie_neurod%C3%A9g%C3%A9n%C3%A9rative">maladie neurodégénérative</a> appelée la maladie de Huntigton.</p>
<h2>Définition</h2>
<p>La maladie de Huntigton est une maladie génétique autosomique dominante touchant environ <a href="http://www.orpha.net/consor/cgi-bin/OC_Exp.php?Lng=FR&Expert=399">1 personne sur 10 000</a>. Elle est causée par une anomalie du gène <em><a href="http://www.genecards.org/cgi-bin/carddisp.pl?gene=HTT">HTT</a></em> (anciennement IT15) situé sur le chromosome 4 et codant pour la protéine <a href="https://fr.wikipedia.org/wiki/Huntingtine">Huntigtine</a>. La mutation d'un seul des deux allèles suffit pour provoquer la maladie. Un parent a donc une chance sur deux de la transmettre.<br>
Cliniquement, la maladie s'accompagne d'une altération de la fonction intellectuelle et du comportement. Les mouvements anormaux sont très caractéristiques. Ce sont des mouvements brusques incontrôlés de la face et des membres qu'on appelle chorée de Huntigton (vidéo ci-dessous).
La maladie survient généralement entre 30 et 50 ans, mais comme nous allons le voir, peut survenir plus tôt en fonction de la mutation.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/8lItaU0ftK8" frameborder="0" allowfullscreen></iframe>
<h1>Mutation dynamique</h1>
<p>Le mécanisme mutationnel de la maladie de Huntigton est lié à l'expansion d'un motif de nucléotides (CAG) dans la partie codante de l'exon 1 du gène. Nous avons déjà discuté de ces répétitions dans l'article sur <a href="empreinte_genetique.html">les empreintes génétiques</a>. Le codon CAG code pour l'acide aminé <a href="https://fr.wikipedia.org/wiki/Glutamine">glutamine</a>. Son expansion se traduit donc par une augmentation d'homopolymère de glutamine dans la protéine qui lui confère un pouvoir toxique dans le cerveau. Plus précisément l'atteinte se situe au niveau des neurones <a href="https://fr.wikipedia.org/wiki/R%C3%A9cepteur_GABAA">GABAergiques</a> du <a href="https://fr.wikipedia.org/wiki/Striatum">striatum</a>.
Chez les sujets sains, la taille de la répétition varie entre 6 et 35. Entre 41 et 180, elle est pathologique. La zone intermédiaire entre 35 et 41 définit une zone floue, parfois symptomatique, parfois asymptomatique, qu'on appelle zone de pénétrance réduite. </p>
<div class="figure">
<img src="../images/post21/cag.png" />
<div class="legend">Expansion des triplets CAG dans la maladie de Huntigton. Sur cette figure, il y a 9 répétitions</div>
</div>
<h1>Phénomène d'anticipation</h1>
<p><a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3048807/">Plusieurs études</a> ont montré que la longueur de la répétition est corrélée à l'âge où débute la maladie. Les longues répétitions sont responsables des formes juvéniles qui peuvent apparaître avant 20 ans. Par ailleurs, dans une lignée familiale, les symptômes apparaissent de plus en plus tôt au cours des générations. C'est ce qu'on appelle le <a href="https://fr.wikipedia.org/wiki/Anticipation_(g%C3%A9n%C3%A9tique)">phénomène d'anticipation</a>. À chaque génération, l'expansion des triplets CAG augmente.
Cette expansion est d'autant plus forte qu'elle est transmise par le père. Effectivement, il semblerait que l'instabilité des répétitions CAG survient préférentiellement lors de la spermatogenèse.</p>
<h1>Diagnostic</h1>
<p>De la même façon que la détection des <a href="empreinte_genetique.html">empreintes génétiques</a>, le diagnostic moléculaire repose sur une analyse de la taille des zones répétées après amplification en <a href="https://fr.wikipedia.org/wiki/R%C3%A9action_en_cha%C3%AEne_par_polym%C3%A9rase">PCR</a>. La visualisation des tailles peut se faire soit sur gel soit en analyse de fragments (<a href="empreinte_genetique.html">lire mon article pour comprendre cette technique</a>).</p>
<div class="figure">
<img src="../images/post21/patient.jpeg" />
<div class="legend">Analyse en fragment chez un sujet sain (a) et un patient atteint de la maladie de Huntigton (b). Le gène du patient (a) présente un allèle à 17 répétitions et un autre à 18 répétitions. Le patient (b) présente un allèle avec une répétition de 40.
</div>
</div>
<h1>Enjeux éthiques</h1>
<p>L'absence de traitement fait de cette maladie un cas d'école en éthique médicale. Effectivement, les premiers symptômes peuvent apparaître tardivement et donner le diagnostic ne conduirait à aucune action thérapeutique. C'est donc après discussion entre le patient et une équipe pluridisciplinaire ( Psychologue, généticien, neurologue ...) que le diagnostic pré-symptomatique peut être entrepris. Dans tous les cas, un délai de réflexion est donné au patient. <br>
<a href="https://fr.wikipedia.org/wiki/Diagnostic_pr%C3%A9natal">Le diagnostic prénatal</a> peut également être réalisé au cours de la grossesse en réalisant une <a href="https://fr.wikipedia.org/wiki/Amniocent%C3%A8se">amniocentèse</a>. Là aussi la décision est prise à plusieurs lors du CPDPN (Centre Pluridisciplinaire de Diagnostic Pré-Natal) et seulement si les parents sont favorables à une interruption de grossesse. On ne fera jamais de diagnostic chez le fœtus avant d'avoir fait celui des parents. Car si aucun des deux parents n'est porteur de la mutation alors il n'y a aucun risque de transmission au fœtus. <br>
Ces enjeux éthiques sont spécifiques aux maladies génétiques qui se déclarent tardivement. Et lorsque l'on voit que la <a href="https://fr.wikipedia.org/wiki/Food_and_Drug_Administration">FDA</a> a autorisé <a href="https://www.23andme.com/en-int/">23andMe</a> (alias google) à dépister les gènes de susceptibilité à la maladie d'<a href="https://fr.wikipedia.org/wiki/Maladie_d%27Alzheimer">Alzheimer</a>, sans passer pas une équipe médicale, on a de quoi se poser des questions. </p>
<h1>Un futur traitement ?</h1>
<p>Toujours pas de traitement à ce jour. Mais un espoir avec <a href="https://fr.wikipedia.org/wiki/Cas9">CRISPR-Cas9</a>. Allez jeter un œil sur cet article prometteur : <a href="https://academic.oup.com/hmg/article-abstract/25/20/4566/2525895/Permanent-inactivation-of-Huntington-s-disease?redirectedFrom=fulltext">"Permanent inactivation of Huntington's disease mutation by personalized allele-specific CRISPR/Cas9"</a></p>
<h2>Références</h2>
<ul>
<li><a href="https://www.elsevier-masson.fr/genetique-medicale-9782294745218.html">Génétique médicale 2016</a></li>
<li><a href="http://www.unitheque.com/Livre/elsevier_-_masson/Genetique_medicale-3681.html">Génétique médicale 2004</a></li>
</ul>Introduction à la métagénomique2016-12-06T22:00:00+01:002016-12-06T22:00:00+01:00Sacha Schutztag:dridk.me,2016-12-06:/metagenomique.html<p>Le <a href="https://fr.wikipedia.org/wiki/Microbiote">microbiote</a> et la <a href="https://fr.wikipedia.org/wiki/M%C3%A9tag%C3%A9nomique">métagénomique</a> sont les deux mots tendances de ces dernières années dans les laboratoires de microbiologie. Derrière eux se cacherait les réponses à de nombreuses maladies comme le <a href="https://fr.wikipedia.org/wiki/Diab%C3%A8te">diabète</a>, la <a href="https://fr.wikipedia.org/wiki/Maladie_de_Crohn">maladie de Crohn</a> et même l'<a href="https://fr.wikipedia.org/wiki/Autisme">autisme</a> ou la <a href="https://fr.wikipedia.org/wiki/Schizophr%C3%A9nie">schizophrénie</a>. <br>
Commençons donc par définir ces deux termes …</p><p>Le <a href="https://fr.wikipedia.org/wiki/Microbiote">microbiote</a> et la <a href="https://fr.wikipedia.org/wiki/M%C3%A9tag%C3%A9nomique">métagénomique</a> sont les deux mots tendances de ces dernières années dans les laboratoires de microbiologie. Derrière eux se cacherait les réponses à de nombreuses maladies comme le <a href="https://fr.wikipedia.org/wiki/Diab%C3%A8te">diabète</a>, la <a href="https://fr.wikipedia.org/wiki/Maladie_de_Crohn">maladie de Crohn</a> et même l'<a href="https://fr.wikipedia.org/wiki/Autisme">autisme</a> ou la <a href="https://fr.wikipedia.org/wiki/Schizophr%C3%A9nie">schizophrénie</a>. <br>
Commençons donc par définir ces deux termes: <br>
- Le <strong>microbiote</strong> est l'ensemble des micro-organismes (bactéries, virus, champignons, levures) vivants dans un environnement spécifique appelé <strong><a href="https://fr.wikipedia.org/wiki/Microbiome">microbiome</a></strong>. L'exemple typique est le microbiote intestinal. Votre intestin est composé de millions d'espèces bactériennes différentes formant une communauté écologique en symbiose avec votre organisme et nécessaire à son bon fonctionnement. Il joue entre autre un rôle de barrière vis-à-vis d'autres agents microbiens pathogènes. La destruction du microbiote intestinal par des antibiotiques est par exemple responsable des infections intestinales par <em><a href="https://fr.wikipedia.org/wiki/Clostridium_difficile">Clostridium difficile</a></em>. <br>
Pour vous prouver l'importance du microbiome, retenez que le génome humain est composé d'environ 23 000 gènes. Le nombre de gènes retrouvés dans l'ensemble des micro-organismes du microbiome intestinal se compte en millions. <br>
- La <strong>métagénomique</strong> est la méthode d'étude du microbiote. C'est une technique de <a href="https://fr.wikipedia.org/wiki/S%C3%A9quen%C3%A7age">séquençage</a> et d'analyse de l'ADN contenu dans un milieu. A l'inverse de la <a href="https://fr.wikipedia.org/wiki/G%C3%A9nomique">génomique</a> qui consiste à séquencer un unique génome, la métagénomique séquence les génomes de plusieurs individus d'espèces différentes dans un milieu donné. Une analyse typique de métagénomique vous donnera la composition d'un microbiome. C'est à dire quelles espèces sont présentes, leurs abondances et leurs diversités. <br>
C'est en partie grâce à l’évolution majeure des technologies de séquençage haut débit et à la bioinformatique, que la métagénomique est aujourd'hui à notre portée. <br>
Dans la suite de cet article, nous verrons uniquement la métagénomique bactérienne, plus particulièrement la métagénomique ciblé sur l'<a href="https://fr.wikipedia.org/wiki/ARN_ribosomique_16S">ARN 16S</a>. Mais gardez bien en tête que les métagénomiques virales et fongiques, bien que plus rares, existent aussi. </p>
<h1>Stratégie en métagénomique</h1>
<p>Il existe deux grandes stratégies de séquençage en métagénomique : la stratégie globale et la stratégie ciblée. </p>
<ul>
<li><strong>La métagénomique globale</strong> consiste à fragmenter <strong>tous</strong> les ADNs présents dans un échantillon en courts fragments et les séquencer à l'aide d'un <a href="https://fr.wikipedia.org/wiki/S%C3%A9quen%C3%A7age_de_l'ADN">séquenceur haut débit</a>. D’où le nom de <em><a href="https://en.wikipedia.org/wiki/Shotgun_sequencing">Shotgun sequencing</a></em>. Les séquences (ou <em>reads</em>) obtenues sont ré-assemblées bioinformatiquement afin de reconstruire les génomes bactériens d'origine. </li>
</ul>
<div class="figure">
<img src="../images/post20/shotgun_sequencing.png" />
<div class="legend">Stratégie globale : L'ensemble des ADNs présents dans un échantillon de microbiote sont séquencés.</div>
</div>
<ul>
<li><strong>La métagénomique ciblée</strong> n'est pas de la métagénomique à proprement parler, mais de la <em>métagénétique</em>. Cette stratégie consiste à séquencer un unique gène au lieu d'un génome complet. Cependant le terme de <em>métagénomique</em> étant plus régulièrement employé pour décrire cette stratégie, je continuerai ainsi. Ce gène doit être commun à plusieurs espèces tout en présentant des régions suffisamment variables afin de discriminer une espèce. En bactériologie, le gène utilisé est celui de l'ARN 16S. Il s'agit d'un gène présent uniquement chez les bactéries. </li>
</ul>
<div class="figure">
<img src="../images/post20/target_sequencing.png" />
<div class="legend">Stratégie ciblé : Seuls les ADNs du gène cible sont séquencés. En bactériologie, le gène cible est l'ARN 16S. </div>
</div>
<p>Chaque stratégie a son avantage. La métagénomique globale est plus précise dans le sens où elle séquence l'ensemble du génome d'une bactérie alors que la seconde ne s’intéresse qu'à un seul gène. Cette première stratégie permet par exemple de décrire le fonctionnement global du microbiote en séquençant l'ensemble des gènes présents. <br>
La stratégie ciblée est quant à elle plus sélective. En effet, le gène de l'ARN 16S est présent uniquement chez les bactéries qui seules seront séquencées. La stratégie globale va séquencer tous les ADN présents dans le milieu sans discernement, qu'ils soient bactériens, viraux ou encore humains.
Enfin, les algorithmes de traitements des données issues d'un séquençage ciblé sont beaucoup plus simples que les assemblages de génomes nécessaires dans le séquençage global. Pour comprendre cette complexité, essayez de mélanger toutes les pièces de 200 puzzles différents et tentez de retrouver les modèles originaux. C'est la problématique de la métagénomique globale. <br>
On ne s’intéressera ici qu'à la stratégie 16S, utilisée en bactériologie. C'est un bon point de départ pour commencer !</p>
<h2>L' ARN 16S</h2>
<p>Vous connaissez les <a href="https://fr.wikipedia.org/wiki/Ribosome">ribosomes</a> ? Ces petits organelles dans la cellule formés de deux sous-unités permettant la traduction de l'ARN en protéine. Et bien chez la bactérie, et uniquement chez elle, la petite sous unité est formée de l'ARN 16S. </p>
<div class="figure">
<a href="../images/post20/ARN16s.jpg"><img src="../images/post20/ARN16s_thumb.jpg" /> </a>
<div class="legend">Structure secondaire de l'ARN 16S avec ses différentes boucles.</div>
</div>
<p>Il s'agit d'un <a href="https://fr.wikipedia.org/wiki/ARN_non_codant">ARN non codant</a> composé d'environ 1500 nucléotides possédant des régions constantes et variables. Il suffit d'aligner la séquence d'ARN 16S de différentes espèces bactériennes pour s'en rendre compte. Comme vous pouvez le voir sur la figure ci-dessous, certaines régions sont constantes entre les bactéries alors que d'autres régions sont variables. </p>
<div class="figure">
<img src="../images/post20/alignment.png" />
<div class="legend">Similarités des séquences d'ARN 16S entre plusieurs bactéries. Sous le graphique figurent les différents couples d'amorces utilisables.</div>
</div>
<p>Les régions variables n'ont pas de rôle fonctionnel important et peuvent diverger au cours de l’évolution sous l'effet des <a href="https://fr.wikipedia.org/wiki/%C3%89volution_des_taux_de_mutation">mutations neutres</a>.<br>
C'est ce qui va nous permettre de discriminer les <a href="https://fr.wikipedia.org/wiki/Taxon">taxons</a> bactériens au sein du microbiome. A chaque taxon correspondra une séquence particulière au niveau des régions variables. Il s'agit de la signature du taxon.
Les régions constantes vont permettre quant à elles de capturer l'ensemble des ARN 16S. Ces régions étant identiques chez toutes les bactéries, il est possible de construire des <a href="https://fr.wikipedia.org/wiki/Amorce_(g%C3%A9n%C3%A9tique)">amorces</a> comme pour une <a href="https://fr.wikipedia.org/wiki/PCR">PCR</a> afin de sélectionner la région d’intérêt. <br>
En réalité, seule une partie de l'ARN 16S est séquencée car les séquenceurs haut débit ne peuvent pas séquencer d'un coup les 1500 nucléotides de l'ARN 16S (enfin... sauf le <a href="http://www.pacb.com/">Pacbio</a>). Le couple d'amorce V3-V5, que vous pouvez voir sur la figure 3, permet par exemple de séquencer une région de 500 nucléotides contenant 3 régions variables. </p>
<h2>Assignent taxonomique</h2>
<p>Une fois le séquençage réalisé, c'est au tour des bioinformaticiens de prendre le relais. Un fichier contenant l'ensemble des reads (séquences) est obtenu après séquençage. Après plusieurs étapes de filtrage et de nettoyage de ces données, il faut assigner à chaque séquence le nom de la bactérie. Pour cela, deux stratégies existent.</p>
<ul>
<li>La stratégie <em><a href="http://qiime.org/tutorials/otu_picking.html#closed-reference-otu-picking">close-reference</a></em> consiste à comparer chaque séquence aux séquences présentes dans une base de donnéees avec un seuil en général de 97% de similarité. <a href="http://greengenes.lbl.gov/cgi-bin/nph-index.cgi">Greengene</a>, <a href="https://www.arb-silva.de/">Silva</a> et <a href="https://rdp.cme.msu.edu/">RDP</a> sont les bases de données d'ARN 16S les plus connues. Cette stratégie a le mérite d'être rapide mais son principal problème est d'ignorer les séquences absentes des bases de données. Pour palier à ce problème, la deuxième stratégie peut être utilisée. </li>
</ul>
<div class="figure">
<img src="../images/post20/close_reference.png" />
<div class="legend">Stratégie 1. Chaque séquence est recherchée dans une base de données et assignée à son taxon.</div>
</div>
<ul>
<li>La stratégie appelée <em><a href="http://qiime.org/tutorials/otu_picking.html#open-reference-otu-picking">de novo</a></em>, n'utilise pas de base données mais consiste à comparer les séquences entre elles puis les regrouper par similarité. Les <a href="https://fr.wikipedia.org/wiki/Partitionnement_de_donn%C3%A9es">clusters</a> ainsi formés élisent une <a href="https://fr.wikipedia.org/wiki/S%C3%A9quence_consensus">séquence consensus</a> qui peut à son tour être annotée par une base de données ou rester comme telle définissant alors une espèce inconnue. </li>
</ul>
<div class="figure">
<img src="../images/post20/de_novo.png" />
<div class="legend">Stratégie 2. Les séquences sont comparées entre elles pour former des groupes similaires ou clusters.</div>
</div>
<p>Une fois l’assignation taxonomique réalisée, il suffit de compter le nombre d'espèces présentes dans chaque échantillon et de construire la table des <a href="https://fr.wikipedia.org/wiki/OTU">OTUs</a>.</p>
<h2>La table des OTUs</h2>
<p>Le point de départ de toutes analyses en métagénomique est la construction de la table des OTUs (operationnal taxonomic unit). La notion d'espèce est difficile avec les bactéries, on parle plutôt d'OTU pour définir un ensemble de bactéries similaires à plus de 97 %. <br>
La table des OTUs est un tableau à double entrées contenant le nombre de séquences par OTU et par échantillon. On parle d'<em>abondance</em>. Ces abondances absolues sont normalisées afin de rendre les échantillons comparables. Plusieurs méthodes de normalisation existent, mais la plus courante est d'utiliser les pourcentages. Sur la figure ci-dessous, les échantillons 1 et 3 ont tous les deux une abondance absolue de 3 en bactéries rouges. En pourcentage, leurs abondances relatives deviennent 42,8 % et 75 % respectivement. </p>
<div class="figure">
<img src="../images/post20/otu_table2.png" />
<div class="legend">Tables des OTUs obtenues à partir de plusieurs échantillons</div>
</div>
<h2>Analyse des données</h2>
<h3>Diversité Alpha</h3>
<p>La <a href="https://fr.wikipedia.org/wiki/Richesse_sp%C3%A9cifique">diversité alpha</a> est une mesure indiquant la diversité d'un échantillon unique.
Le nombre d'espèce est par exemple un indicateur d'alpha diversité.</p>
<div class="figure">
<img src="../images/post20/alpha1.png" />
<div class="legend">B est plus diversifié que A car il contient deux fois plus d'espèces</div>
</div>
<p>Mais comme vous pouvez le voir dans la figure ci-dessous, Le nombre d'espèce n'est pas toujours adapté. C'est pour cette raison que d'autres indicateurs existent.</p>
<div class="figure">
<img src="../images/post20/alpha2.png" />
<div class="legend">B contient plus d'espèce mais semble moins diversifié</div>
</div>
<p>L'indice de Shannon ou entropie de Shannon est un exemple d'alpha diversité répondant à ce problème. Cette indice reflète aussi bien le nombre d'espèce que leurs abondances. Sa formule est la suivante : </p>
<div class="figure">
<img src="../images/post20/shannon.svg" />
<div class="legend">Indice de Shannon. Pour chaque espèce faire la somme des fréquences multiplié par le log des fréquences </div>
</div>
<p>La figure A précédente contient 13 espèces, dont 4 vertes, 5 rouges et 4 bleues. La diversité de shannon pour A est donc : </p>
<div class="figure">
<img src="../images/post20/eq1.gif" />
</div>
<p>En faisant de même pour B, on retrouve alors une diversité plus faible de 0.72.</p>
<div class="figure">
<img src="../images/post20/alpha3.png" />
<div class="legend">L'entropie de A est supérieur à celle de B</div>
</div>
<p>Les autres indicateurs répondent chacun à des problèmes différents. L'indice <a href="http://www.evolution.unibas.ch/walser/bacteria_community_analysis/2015-02-10_MBM_tutorial_combined.pdf">Chao1</a> estime le nombre d'espèce réel dans l'environnement à partir du nombre d'espèce dans l'échantillon. Il y a aussi l'indice de <a href="http://www.countrysideinfo.co.uk/simpsons.htm">Simpson</a>, de <a href="http://groundvegetationdb-web.com/ground_veg/home/diversity_index">Fisher</a> et l'<a href="http://www.evolution.unibas.ch/walser/bacteria_community_analysis/2015-02-10_MBM_tutorial_combined.pdf">indice ACE</a>. Faite un tour sur <a href="http://www.evolution.unibas.ch/walser/bacteria_community_analysis/2015-02-10_MBM_tutorial_combined.pdf">ce site</a> pour avoir plus des informations plus détaillées. <br>
Le graphique ci-dessous montre les différences de diversité alpha du microbiote intestinal en fonction du régime alimentaire. </p>
<div class="figure">
<img src="../images/post20/alpha_diversity.jpg" />
<div class="legend">Diversité alpha du microbiote intestinal en fonction du régime alimentaire. <br/><i> <a href="https://peerj.com/articles/659/">Source </a></i></div>
</div>
<h3>Diversité Beta</h3>
<p>La <a href="https://fr.wikipedia.org/wiki/Diversit%C3%A9_b%C3%AAta">diversité bêta</a> consiste à mesurer la diversité des espèces entre les échantillons. On procède le plus souvent à l'<a href="https://fr.wikipedia.org/wiki/Statistique_multivari%C3%A9e">analyse multivariée</a> de la matrice des OTUs en ayant recours aux méthodes d'<a href="https://en.wikipedia.org/wiki/Ordinate">ordinations</a> comme l'<a href="https://fr.wikipedia.org/wiki/Analyse_en_composantes_principales">analyse en composantes principales</a>. Pour faire simple, imaginons que notre table des OTUs soit composée de 2 bactéries et 6 échantillons. La représentation sur un graphique serait facile en utilisant 2 axes (1 par bactérie). Chaque point de ce graphique serait un échantillon dont les coordonnées représentent l'abondance pour chaque bactérie. La figure de gauche ci-dessous illustre cet exemple. En colorant ces points sur une variable attachée aux échantillons, comme le site de prélèvement, on pourrait découvrir des groupes distincts, comme l'illustre la figure de droite.</p>
<div class="figure">
<img src="../images/post20/2dplot.png" />
<div class="legend">Chaque point représente un échantillon réparti sur les deux axes en fonction de leurs abondances. Certains échantillons semblent associées entre eux. </div>
</div>
<p>Bien entendu, il y a plus de deux bactéries différentes dans un microbiome. Ce qui nécessite un nombre d'axe impossible à représenter graphiquement. Les méthodes d'ordination répondent à ce problème en projetant la variabilité de tous ces axes sur 2 axes pouvant être visualisés.
L'analyse en composantes principales (ACP) est un exemple d'ordination. Il en existe bien évidemment d'autres. La plus couramment utilisée en métagénomique est une jumelle de l'ACP, <a href="https://en.wikipedia.org/wiki/Multidimensional_scaling#Types">l'analyse en coordonnées principales</a> (PCoA) que je ne détaillerai pas. <br>
Une fois la représentation réalisée, on cherche alors des groupes de points et la variable explicative que l'on visualise à l'aide d'une couleur. Sur la figure ci-dessous, l'analyse de plusieurs échantillons provenant de différents sites anatomiques révèle les compositions propres à chaque site.</p>
<div class="figure">
<img src="../images/post20/beta_diversity.png" />
<div class="legend">Analyse en composantes principales de différents échantillons microbiens provenant de différents sites anatomiques. <br/><i><a href="http://www.nature.com/nature/journal/v486/n7402/full/nature11234.html"> Source </a> </i></div>
</div>
<h1>Conclusion</h1>
<p>La métagénomique est un sujet complexe en plein essor qui nécessite une connaissance précise des différentes techniques pour éviter tout écueil. De nombreux biais peuvent intervenir à toutes les étapes, tant du coté biologique que bioinformatique. D'ailleurs, l'assignation taxonomique que je décris dans cet article reste simple et naïve. D'autres méthodes plus complexes mais valables statistiquement sont préférables. Par exemple la méthode dite de « <a href="http://www.nature.com/ismej/journal/v9/n4/full/ismej2014195a.html">Minimum Entropy Decomposition</a> » permet de classer les OTU en s'abstenant du seuil théorique des 97 %. <br>
Enfin, si vous voulez approfondir la métagénomique, je vous invite très fortement à regarder <a href="https://www.youtube.com/watch?v=htbeJhtFAXw&list=PLOPiWVjg6aTzsA53N19YqJQeZpSCH9QPc">les vidéos de Dan Knights</a> (un dieu en métagénomique) disponibles sur YouTube! </p>
<h2>Références</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=htbeJhtFAXw&list=PLOPiWVjg6aTzsA53N19YqJQeZpSCH9QPc">Cours en vidéo de Dan Knights</a></li>
<li><a href="https://www.revmed.ch/RMS/2014/RMS-N-450/Genomique-et-metagenomique-bacteriennes-applications-cliniques-et-importance-medicale">Génomique et métagénomique bactérienne: applications cliniques et importance médicale</a></li>
<li><a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3728647/">Enterotype of the human gut microbiome</a></li>
<li><a href="http://www.nature.com/nature/journal/v486/n7402/full/nature11234.html">Structure, function and diversity of the healthy human microbiome</a></li>
<li><a href="http://qiime.org/">Outil : QIIME</a></li>
<li><a href="https://github.com/torognes/vsearch">Outil : Vsearch </a></li>
<li><a href="https://joey711.github.io/phyloseq/">Outil :Philoseq</a></li>
</ul>
<h2>Remerciements</h2>
<p><a href="https://twitter.com/Thibaud_GS">@Thibaud_GS </a> <br>
<a href="https://github.com/Piplopp">@Piplopp </a> <br>
<a href="https://github.com/pausrrls">@pausrrls </a> <br>
<a href="https://github.com/Oodnadatta">@Oodnadatta</a> </p>Répartition des variants sur le génome entre J.Watson et C.Venter2016-08-02T21:42:51+02:002016-08-02T21:42:51+02:00Sacha Schutztag:dridk.me,2016-08-02:/localisation_snp.html<p>Nous avions vu dans un <a href="https://dridk.me/genome_chiffre_1.html">précédent post</a> que le génome de <a href="https://fr.wikipedia.org/wiki/James_Dewey_Watson">James Watson</a> comptait un peu plus de 2 millions de variants par rapport au génome de référence; et qu'environ la moitié de ces variants étaient partagés avec <a href="https://fr.wikipedia.org/wiki/Craig_Venter">Craig Venter</a>.<br>
Aujourd'hui, j'ai cherché à savoir si les densités des mutations …</p><p>Nous avions vu dans un <a href="https://dridk.me/genome_chiffre_1.html">précédent post</a> que le génome de <a href="https://fr.wikipedia.org/wiki/James_Dewey_Watson">James Watson</a> comptait un peu plus de 2 millions de variants par rapport au génome de référence; et qu'environ la moitié de ces variants étaient partagés avec <a href="https://fr.wikipedia.org/wiki/Craig_Venter">Craig Venter</a>.<br>
Aujourd'hui, j'ai cherché à savoir si les densités des mutations à travers leurs génomes étaient semblables. Pour cela, j'ai fragmenté le génome en intervalles réguliers que j'appelle <em>bins</em>. J'ai ensuite compté pour chaque <em>bin</em> le nombre de variants chez Watson puis chez Venter. J'ai alors calculé la différence entre Watson et Venter pour chaque <em>bin</em> à l'aide d'un z-score.<br>
Et voilà les résultats!</p>
<h2>Pipeline</h2>
<p>J'ai tout codé dans un pipeline disponible sur <a href="https://github.com/dridk/snp_location">github</a>.<br>
Vous aurez besoin de <a href="https://bitbucket.org/johanneskoester/snakemake/wiki/Home">Snakemake</a>, de <a href="http://bedtools.readthedocs.io/en/latest/">bedtools</a> et du package R <a href="https://www.bioconductor.org/packages/release/bioc/html/IdeoViz.html">IdeoViz</a> disponible depuis le site <a href="https://www.bioconductor.org/">bioconductor</a>.<br>
Aucune donnée n'est nécessaire; tout se télécharge directement depuis le <a href="http://hgdownload.cse.ucsc.edu/goldenpath/hg19/database/">golden path d'UCSC</a>. Vous pouvez d’ailleurs, si vous le voulez, lancer le pipeline sur d'autres génomes.</p>
<h2>Exécution</h2>
<p>La commande que j'utilise est la suivante :</p>
<div class="highlight"><pre><span></span><code>snakemake -F --core 4 --config bin_size=100000 first=pgVenter second=pgWatson
</code></pre></div>
<ul>
<li><strong>bin_size</strong> correspond à la taille des <em>bins</em>.</li>
<li><strong>first</strong> et <strong>second</strong> sont les noms des fichiers correspondant aux "<em>personal genom (pg)</em>" retrouvés dans <a href="http://hgdownload.cse.ucsc.edu/goldenpath/hg19/database/">UCSC</a>.</li>
<li><strong>F</strong> sert à régénérer l'ensemble des fichiers dans le cas d'une seconde exécution.</li>
<li><strong>core</strong> spécifie le nombre de cœurs à utiliser. </li>
</ul>
<p>Le schéma suivant représente les différentes étapes du pipeline. </p>
<div class="figure">
<img src="../images/post19/pipeline.png" />
<div class="legend">Graph du pipeline snakemake</div>
</div>
<h2>Résultats</h2>
<p>Si tout se passe bien vous devriez obtenir 3 images : <em>correlation.png</em>, <em>both.png</em> et <em>ideogram.png</em> que vous pouvez voir ci-dessous.</p>
<div class="figure">
<img src="../images/post19/correlation.png" />
<div class="legend">Corrélation du nombre de SNP par bin entre Watson et Venter avec des bins de 1 Mpb</div>
</div>
<p>Le graphique <em>correlation.png</em> représente le nombre de SNP par <em>bin</em> entre Watson et Venter en utilisant des <em>bins</em> d'1 million de paires de bases.<br>
La corrélation est nette. Les régions riches en SNP chez Watson le sont également chez Venter.</p>
<div class="figure">
<img src="../images/post19/both.png" />
<div class="legend">Densités en variants par bin pour Watson (orange) et Venter (bleue)</div>
</div>
<p>Le graphique <em>both.png</em> montre les densités des variants par <em>bin</em> pour Watson (orange) et Venter (bleu).
Les tendances générales des courbes semblent similaires. </p>
<div class="figure">
<img src="../images/post19/ideogram.png" />
<div class="legend">Différence des SNPs par bin entre Watson et Venter sur tout le génome.</div>
</div>
<p>Le graphique <em>ideogram.png</em> montre les différences du nombre de SNP par <em>bin</em> entre Watson et Venter sur tout le génome. La différence est ici normalisée par un z-score. En zoomant, vous pouvez voir que les différences sont rarement significatives en restant inférieures à 2. En revanche, certaines régions notamment sur le bras long du chromosome X (avant dernier), montrent de grandes différences.</p>
<h2>Conclusion</h2>
<p>Les régions riches en mutations chez Watson le sont aussi chez Venter en utilisant des <em>bins</em> d'1 Mpb. Ceci peut s'expliquer par le contenu de la séquence. Il est possible que certaines régions soient plus susceptibles de muter à cause de leurs teneurs en non-codants, en zones répétées ou en autres choses. Il faudrait d'ailleurs que je regarde s'il y a une corrélation avec la teneur en exons, en GC...<br>
La distribution dans le génome, fluctue quant à elle de la même façon chez Watson et Venter. On retrouve cependant quelques différences dans des zones précises. Peut-être des CNV... <br>
Bref, prochain objectif, comparer ces courbes avec des données d'annotations style 1000 génomes et SNP !</p>Transition et transversion dans le génome humain2016-07-24T18:39:23+02:002016-07-24T18:39:23+02:00Sacha Schutztag:dridk.me,2016-07-24:/transition_transversion.html<p>Aujourd'hui, J'ai eu une soudaine envie de calculer les fréquences des différents types de substitutions dans le génome de <a href="https://fr.wikipedia.org/wiki/James_Dewey_Watson">James Watson</a>. <br>
A partir d'un fichier contenant des variations par rapport au génome de référence, je me suis amusé à compter le nombre et le type de substitutions nucléotidiques. Et le …</p><p>Aujourd'hui, J'ai eu une soudaine envie de calculer les fréquences des différents types de substitutions dans le génome de <a href="https://fr.wikipedia.org/wiki/James_Dewey_Watson">James Watson</a>. <br>
A partir d'un fichier contenant des variations par rapport au génome de référence, je me suis amusé à compter le nombre et le type de substitutions nucléotidiques. Et le résultat est loin d'être aléatoire... <br>
Mais d'abord quelques définitions.</p>
<h2>Transition et Transversion</h2>
<p>On classe les <a href="https://fr.wikipedia.org/wiki/Base_azot%C3%A9e">bases azotées</a> ( Adénine,Guanine,Cytosine,Tymine ) en 2 familles: les <a href="https://fr.wikipedia.org/wiki/Purine">purines</a> et les <a href="https://fr.wikipedia.org/wiki/Pyrimidine">pyrimidines</a>.
l'<em>Adénine</em> et la <em>Guanine</em> sont des <em>purines</em>, composées de deux cycles aromatiques.<br>
La <em>Thymine</em> et la <em>Cytosine</em> sont des <em>pyrimidines</em> composées d'un seul cycle.<br>
Gravez-vous en tête que C<strong>Y</strong>tosine et T<strong>Y</strong>mine sont des P<strong>Y</strong>rimidines car ces trois mots contiennent un <strong>Y</strong> ! <br>
Une <a href="https://fr.wikipedia.org/wiki/Transition_(g%C3%A9n%C3%A9tique)">transition</a> est une substitution entre deux bases sans changement de famille. C'est à dire une purine qui devient une autre purine, ou alors une pyrimidine qui devient une autre pyrimidine. <br>
Une <a href="https://fr.wikipedia.org/wiki/Transversion">transversion</a> est associée à un changement de famille. C'est une purine qui se transforme en pyrimidine ou l'inverse. <br>
L'image ci-dessous résume tous les cas possibles. </p>
<div class="figure">
<img src="../images/post17/transition_transversion.png">
<div class="legend">Schéma de toutes les substitutions possibles. En bleu les transitions , en rouge les transversions. Il y a 2 fois plus de transversions que de transitions</div>
</div>
<h2>Notation consensus</h2>
<p>Une substitution s'écrit souvent sous la forme X>Y et se lit <em>X donne Y</em>. Par exemple la substitution A>T signifie que l'allèle de référence est un A tandis que l'allèle alternative est un T.<br>
Si nous résumons tous les cas possibles, il y a au total : </p>
<ul>
<li>4 transitions : A>G, G>A, C>T, T>C</li>
<li>8 transversions : A>C,C>A,G>T,T>G,G>C,C>G,A>T,T>A </li>
</ul>
<p>Mais rappelons-nous que l'ADN est double brin avec une complémentarité des bases. L'<em>Adénine</em> est toujours en face d'une <em>Tymine</em> et la <em>Guanine</em> toujours en face d'une <em>Cytosine</em>. Si il y a une mutation sur un brin, disons un A>G , alors il y a sur le brin complémentaire un T>C. Ces deux notations sont donc équivalente. On utilisera toujours par la suite la notation ou la base de référence est soit une Tymine soit une Cytosine. (T>C au lieu de A>G). <br>
En reprenant notre combinatoire précédente, on se retrouve alors avec : </p>
<ul>
<li>2 transitions : C>T, T>C </li>
<li>4 transversions : C>A, T>G, C>G, T>A </li>
</ul>
<p>Si les mutations sont aléatoires alors nous devons observer 2 fois plus de transversions que de transitions.<br>
Vérifions cela en regardant quelles sont les mutations substitutives qui différencient James Watson au génome de référence hg19.<br>
Allez directement au résultat si Linux vous donne des boutons. </p>
<h2>Téléchargement des données nécessaires</h2>
<h3>Génome de référence: hg19.fa</h3>
<p>Le génome humain dans sa version hg19 est disponible sur <a href="https://genome.ucsc.edu/">ucsc</a>. </p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">hgdownload</span><span class="o">.</span><span class="n">cse</span><span class="o">.</span><span class="n">ucsc</span><span class="o">.</span><span class="n">edu</span><span class="o">/</span><span class="n">goldenPath</span><span class="o">/</span><span class="n">hg19</span><span class="o">/</span><span class="n">bigZips</span><span class="o">/</span><span class="n">hg19</span><span class="o">.</span><span class="mi">2</span><span class="n">bit</span><span class="w"></span>
</code></pre></div>
<p>Il faut utiliser l'outil twoBitToFa pour convertir le génome au format fasta. </p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">hgdownload</span><span class="o">.</span><span class="n">cse</span><span class="o">.</span><span class="n">ucsc</span><span class="o">.</span><span class="n">edu</span><span class="o">/</span><span class="n">admin</span><span class="o">/</span><span class="n">exe</span><span class="o">/</span><span class="n">linux</span><span class="o">.</span><span class="n">x86_64</span><span class="o">/</span><span class="n">twoBitToFa</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">chmod</span><span class="w"> </span><span class="o">+</span><span class="n">x</span><span class="w"> </span><span class="n">twoBitToFa</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="o">./</span><span class="n">twoBitTo</span><span class="w"> </span><span class="n">hg19</span><span class="o">.</span><span class="mi">2</span><span class="n">bit</span><span class="w"> </span><span class="n">hg19</span><span class="o">.</span><span class="mi">2</span><span class="n">bit</span><span class="w"> </span><span class="n">hg19</span><span class="o">.</span><span class="n">fa</span><span class="w"></span>
</code></pre></div>
<h3>Substitution de James Watson: pgWatson.txt.gz</h3>
<p>Ce fichier contient l'ensemble des variations de James Watson par rapport au génome de référence. </p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">hgdownload</span><span class="o">.</span><span class="n">cse</span><span class="o">.</span><span class="n">ucsc</span><span class="o">.</span><span class="n">edu</span><span class="o">/</span><span class="n">goldenpath</span><span class="o">/</span><span class="n">hg19</span><span class="o">/</span><span class="n">database</span><span class="o">/</span><span class="n">pgWatson</span><span class="o">.</span><span class="n">txt</span><span class="o">.</span><span class="n">gz</span><span class="w"></span>
</code></pre></div>
<h3>Téléchargement de bedtools</h3>
<p><a href="http://bedtools.readthedocs.io/en/latest/">bedtools</a> est un outil permettant de manipuler des fichiers au <a href="https://genome.ucsc.edu/FAQ/FAQformat.html#format1">format bed</a>. Ce sont des fichiers contenant des régions génomiques de la forme : </p>
<div class="highlight"><pre><span></span><code>chromosome debut fin
</code></pre></div>
<p>C'est un peu le couteau suisse du bioinformaticien. Si vous ne l'avez toujours pas, Veuillez suivre les instructions pour l'installer ou taper les commandes suivantes. </p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">arq5x</span><span class="o">/</span><span class="n">bedtools2</span><span class="o">/</span><span class="n">releases</span><span class="o">/</span><span class="n">download</span><span class="o">/</span><span class="n">v2</span><span class="o">.</span><span class="mf">25.0</span><span class="o">/</span><span class="n">bedtools</span><span class="o">-</span><span class="mf">2.25</span><span class="o">.</span><span class="mf">0.</span><span class="n">tar</span><span class="o">.</span><span class="n">gz</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">tar</span><span class="w"> </span><span class="o">-</span><span class="n">zxvf</span><span class="w"> </span><span class="n">bedtools</span><span class="o">-</span><span class="mf">2.25</span><span class="o">.</span><span class="mf">0.</span><span class="n">tar</span><span class="o">.</span><span class="n">gz</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">cd</span><span class="w"> </span><span class="n">bedtools2</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">make</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">sudo</span><span class="w"> </span><span class="n">make</span><span class="w"> </span><span class="n">install</span><span class="w"></span>
</code></pre></div>
<h2>Bash pour Nidja</h2>
<h3>Récupérer les régions des variants de James Watson</h3>
<p>Les trois première colonnes du fichier <em>pgWatson.txt.gz</em> correspondent à la région génomique (chromosome-début-fin) de la substitution. C'est notre fichier bed que nous allons générer avec la commande suivante. </p>
<div class="highlight"><pre><span></span><code><span class="n">zcat</span><span class="w"> </span><span class="n">pgWatson</span><span class="p">.</span><span class="n">txt</span><span class="p">.</span><span class="n">gz</span><span class="o">|</span><span class="n">cut</span><span class="w"> </span><span class="o">-</span><span class="n">f1</span><span class="p">,</span><span class="mh">2</span><span class="p">,</span><span class="mh">3</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">region</span><span class="p">.</span><span class="n">bed</span><span class="w"></span>
</code></pre></div>
<h3>Récupération des bases de référence</h3>
<p>Le fichier <em>region.bed</em> nous permet de récupérer les bases de références depuis hg19. A l'aide de bedtools, créer le fichier <em>ref_bases.txt</em>. </p>
<div class="highlight"><pre><span></span><code><span class="n">bedtools</span><span class="w"> </span><span class="n">getfasta</span><span class="w"> </span><span class="o">-</span><span class="n">fi</span><span class="w"> </span><span class="n">hg19</span><span class="o">.</span><span class="n">fa</span><span class="w"> </span><span class="o">-</span><span class="n">bed</span><span class="w"> </span><span class="n">region</span><span class="o">.</span><span class="n">bed</span><span class="w"> </span><span class="o">-</span><span class="n">fo</span><span class="w"> </span><span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">stdout</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">awk</span><span class="w"> </span><span class="s1">'NR%2 == 0 {print $0}'</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">ref_bases</span><span class="o">.</span><span class="n">txt</span><span class="w"></span>
</code></pre></div>
<h3>Récupération des bases alternative</h3>
<p>Créez aussi le fichier <em>alt_bases.txt</em> contenant les bases alternatives depuis pgWatson.txt.gz à la colonne 5.</p>
<div class="highlight"><pre><span></span><code>zcat pgWatson.txt.gz|cut -f5|awk -F "/" 'NF==2{print $2} NF==1{print $1}' > alt_bases.txt
</code></pre></div>
<h3>Concaténation des deux fichiers</h3>
<p>On fusionne <em>ref_bases.txt</em> et <em>alt_bases.txt</em> dans un fichier. Celui ci contient alors une colonne pour la base de référence et une autre pour la base alternative. Les bases sont toutes converties en majuscules. </p>
<div class="highlight"><pre><span></span><code>paste -d '' ref_bases.txt alt_bases.txt|tr '[:lower:]' '[:upper:]' > substitution.txt
</code></pre></div>
<h3>Notation consensus</h3>
<p>Toutes les substitutions du fichier précédent sont transformées de façon à toujours avoir une Cytosine ou une Tymine en référence.</p>
<div class="highlight"><pre><span></span><code>cat substitution.txt |sed -e 's/AG/TC/' -e 's/GA/CT/' -e 's/AC/TG/' -e 's/GT/CA/' -e 's/GC/CG/' -e 's/AT/TA/' > consensus.txt
</code></pre></div>
<h3>Compatage des substitutions</h3>
<div class="highlight"><pre><span></span><code>cat consensus.txt|sort|uniq -c
</code></pre></div>
<p>Nous obtenons alors : </p>
<div class="highlight"><pre><span></span><code> 697641 CT
683841 TC
183890 CA
173279 TG
172228 CG
146872 TA
466 GG
403 AA
395 CC
369 TT
</code></pre></div>
<p>Il ne reste plus qu'à faire un jolie graphique!</p>
<h2>Resultats</h2>
<div class="figure">
<img src="../images/post17/chart.jpg">
<div class="legend">Représentation des différentes substitutions retrouvées dans le génome de James Watson.</div>
</div>
<p>Ce graphique représente les différente substitutions retrouvées chez James Watson par rapport au génome de référence. Et comme vous pouvez le constater, cela ne colle absolument pas avec notre hypothèse des mutations aléatoires. Les 2 transitions possibles représentent deux tiers des substitutions, la où les 4 transversions ne représentent qu'un tiers. Il y a donc 2 fois plus de transitions que de transversions. <br>
Ce phénomène est bien connu et s'explique par le fait qu'une transition est plus facile chimiquement à réaliser qu'une transversion. Les structures chimiques étant semblable. <br>
D'après la littérature, ce rapport passe de 2 à 3 dans les régions codantes. En effet une transversion est plus susceptible de modifier l'acide aminé et se retrouve éliminée par la sélection naturelle. <br>
La connaissance de ce rapport est utilisé dans les modèles d’évolution moléculaire comme <a href="www7.inra.fr/internet/Projets/agroBI/PHYLO/Gouy.pdf">le modèle de Kimura</a>. <br>
Il s'agit aussi d'un indicateur de qualité de séquençage haut débit. Si le rapport n'est pas retrouvé, il y a fort à parier que des erreurs de séquences se sont produites. <br>
Voilà ! Si vous avez d'autres explications je suis preneur ! </p>
<h2>Références</h2>
<ul>
<li><a href="http://genome.sph.umich.edu/wiki/SNP_Call_Set_Properties">Center for statistical genetics</a></li>
<li><a href="https://www.biostars.org/p/149708/">Biostar</a></li>
<li><a href="http://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-15-125">Effective filtering strategies to improve data quality from population-based whole exome sequencing studies</a></li>
</ul>Le dépistage prénatal non-invasif de la trisomie 212016-07-12T18:59:16+02:002016-07-12T18:59:16+02:00Sacha Schutztag:dridk.me,2016-07-12:/dpni.html<p>La trisomie 21 est un syndrome polymalformatif avec un retard mental, lié dans la majorité des cas à la présence d'un chromosome 21 surnuméraire. <br>
En France, le <a href="http://www.has-sante.fr/portail/jcms/c_1165790/fr/strategies-de-depistage-de-la-trisomie-21-impact-et-mise-en-oeuvre">dépistage de la trisomie 21</a> est proposé à toutes les femmes enceintes au 1er trimestre de grossesse. Ce dépistage consiste à calculer un …</p><p>La trisomie 21 est un syndrome polymalformatif avec un retard mental, lié dans la majorité des cas à la présence d'un chromosome 21 surnuméraire. <br>
En France, le <a href="http://www.has-sante.fr/portail/jcms/c_1165790/fr/strategies-de-depistage-de-la-trisomie-21-impact-et-mise-en-oeuvre">dépistage de la trisomie 21</a> est proposé à toutes les femmes enceintes au 1er trimestre de grossesse. Ce dépistage consiste à calculer un score en <a href="http://acces.ens-lyon.fr/acces/ressources/sante/epidemiologie/depistage_trisomie21/Points/points_marqueurs_seriques">fonction de marqueurs sanguins</a> (AFP, Papp-A, beta HCG) et des signes d'appel échographique comme <a href="https://fr.wikipedia.org/wiki/Clart%C3%A9_nucale">la clarté nuccale</a>. Si ce score dépasse un certain seuil, un diagnostic cytogénétique est proposé pour confirmer la trisomie. Il consiste à prélever des cellules fœtales par des techniques invasives comme l'<a href="https://fr.wikipedia.org/wiki/Amniocent%C3%A8se">amniocentèse</a> et de dénombrer le nombre de chromosomes sur un <a href="https://fr.wikipedia.org/wiki/Caryotype">caryotype</a> comme illustré ci-dessous. </p>
<div class="figure">
<img src="../images/post18/caryotype.jpg" />
<div class="legend">Caryotype présentant 3 chromosomes 21 au lieu de 2</div>
</div>
<p>Malheureusement ces gestes invasifs ne sont pas anodins. On estime entre <a href="http://www.agence-biomedecine.fr/annexes/bilan2013/donnees/diag-prenat/01-diag_prenat/synthese.htm">0.5% et 1%</a> le risque de fausse couche lié à l'amniocentèse.<br>
Cela peut sembler faible, mais le dépistage actuel souffre d'une très mauvaise spécificité. C'est à dire que beaucoup de femmes répondent positif au dépistage alors que leur fœtus est indemne. Par conséquence beaucoup trop d'amniocentèses sont réalisées inutilement avec le risque de fausse couche qui en découle. <br>
Mais depuis l’avènement récent du séquençage haut débit, un nouveau test de dépistage beaucoup plus puissant en terme de sensibilité et de spécificité voit le jour. Il s'agit du DPNI pour Dépistage Prénatal Non Invasif. (Vous lirez souvent <em>diagnostic</em> , mais il s'agit pour l'heure de dépistage). Ce nouveau test consiste à quantifier sur une simple prise de sang un excès d'ADN fœtal circulant provenant du chromosome 21. </p>
<h2>L'ADN fœtal circulant</h2>
<p>Il y a des fragments d'ADN double brin qui circulent librement dans votre sang. En général ce sont les vôtres sauf si vous faites des expériences tordues dans votre laboratoire ou ... si vous êtes enceinte. En effet chez les femmes enceintes environ 10% de ces fragments proviennent du fœtus. Plus précisément ces fragments proviennent de la lyse des cellules trophoblastiques, un composant du placenta ayant la même origine embryologique que le fœtus. <br>
L'idée derrière le DPNI c'est de quantifier l' excès d'ADN circulant provenant du chromosome 21 à l'aide des nouvelles technologies de séquençage haut débit.<br>
La figure ci-dessous illustre la quantification d'ADN circulant chez une mère sans et avec fœtus trisomique. En mesurant une différence significative entre une patient et des témoins sains, il est possible de conclure à un excès de d'ADN circulant provenant du chromosome 21.</p>
<div class="figure">
<img src="../images/post18/chromosomes.png" />
<div class="legend">On considère que 90% de l'ADN circulant provient de la mère et 10% du foetus. L'excès du chromosome 21 chez le foetus est caractérisé par une différence significatif entre 2.1 et 2.0</div>
</div>
<h2>Le Séquençage de nouvelle génération</h2>
<p>Le NGS (Next Generation Sequencing) est une technologie récente permettant le séquençage de l'ADN de façon très rapide grâce à un haut niveau de parallèlisation. Sans entrer dans les détails (<a href="https://www.abmgood.com/marketing/knowledge_base/next_generation_sequencing_introduction.php#similarities">super site ici</a>), les fragments d'ADN provenant du sang maternel, qu'on appellera <em>reads</em> à présent, sont séquencés puis alignés sur le génome de référence via des algorithmes de bioinformatique.
On obtient alors un fichier contenant la liste des reads associés à leurs positions sur le génome. C'est à dire qu'à chaque fragment séquencé, son chromosome lui est associé. <br>
La figure ci-dessous résume les étapes du séquençage ainsi que les différents formats de fichier. </p>
<div class="figure">
<img src="../images/post18/ngs.png" />
<div class="legend">Les reads sont séquencés et sauvegardés dans un fichier fastQ. Les reads sont ensuite alignés sur le génome de référence hg19. En vert les reads provenant du foetus. En violet les reads maternels</div>
</div>
<h2>Quantification et test statistique</h2>
<p>Une trisomie 21 se caractérise par un excès de reads s’alignant sur le chromosome 21. Pour mesurer cet excès il nous faut des valeurs de référence obtenues chez des femmes enceintes témoins dont le fœtus est sain.
Avec un nombre suffisant de témoins, la moyenne et l'écart-type du nombre de reads par chromosome sont calculés. <br>
Pour savoir si une patiente présente trop de reads, il suffit de rechercher une différence significative à l'aide d'un Z-score en comparant les données de la patiente et les valeurs de référence. <br>
Le logiciel <a href="http://www.ncbi.nlm.nih.gov/pubmed/24990604">RapidR</a> créé par le NHS utilise cette approche. Un exemple de résultats est présenté dans la figure suivante. </p>
<div class="figure">
<img src="../images/post18/rapidR.png" />
<div class="legend">En ordonnée le Z-score, en abscisse les chromosomes. Sur ce graphique, la patiente présente un excès significatif en read s’alignant sur le chromosome 21</div>
</div>
<p>Un autre logiciel, <a href="http://www.ncbi.nlm.nih.gov/pubmed/?term=wisecondor">Wisecondor</a> approche différemment le problème et propose d'utiliser les autres chromosomes comme références au sein du même échantillon. C'est une approche plus complexe, mais peut se résumer ainsi. <br>
Tout d'abord, le génome est segmenté en régions de 10 kilobases appelé <em>bin</em>. Le nombre de reads est comptabilisé par bin au lieu d'être comptabilisé par chromosome comme précédemment. <br>
A partir des mesures chez les témoins sains, les bins du chromosome 21 sont associés aux autres bins du génome lorsqu'ils contiennent plus ou moins le même nombre de reads. La figure suivante est une représentation de ces associations. </p>
<div class="figure">
<img src="../images/post18/wisecondor.png" />
<div class="legend">Chaque chromosome est représenté avec leurs bins sur la circonférence du disque. Tous les bins du chromosome 21 sont associés aux bins des autres chromosomes. Ces relations sont utilisées comme référence témoins au sein du même échantillon. </div>
</div>
<p>Ce logiciel permet donc de mesurer l'excès de reads mappant le chromosome 21 en le comparant aux autres chromosomes. Cette technique à l'avantage de se passer des biais de mesure, car le séquençage de la référence et du patient sont réalisés en même temps. </p>
<h2>Stratégie de dépistage</h2>
<p>En Novembre 2015, la Haute autorité de santé <a href="http://www.has-sante.fr/portail/jcms/c_2573090/fr/trisomie-21-de-nouveaux-tests-appellent-la-revision-des-modalites-de-depistage-actuelles">a évalué positivement ce nouveau test de dépistage</a>. La sensibilité et la spécificité avoisine les 100%.
Le risque de faux négatif est lié à l'absence d'ADN fœtal si le prélèvement est réalisé trop tôt. Un risque de faux positif est également possible dans les cas de <a href="https://fr.wikipedia.org/wiki/Mosa%C3%AFque_(g%C3%A9n%C3%A9tique)">mosaïcisme fœtal</a>. <br>
Aujourd'hui toutes les femmes enceintes, quel que soit leur âge, sont informées de la possibilité de recourir à ce test. <br>
La stratégie actuelle est de proposer le dépistage standard. Si celui ci revient positif, au lieu de proposer directement un geste invasif, le DPNI est proposé. Si celui ci est à son tour positif, alors le geste invasif et le diagnostic cytogénétique est réalisé.
A l'heure actuelle les laboratoire <a href="http://www.lab-cerba.com/">Cerba</a> et <a href="http://www.dpni-biomnis.com/">Biomnis</a> proposent le DPNI. Mais depuis janvier 2016 certains centres hospitaliers proposent ce test qui n'est malheureusement pas encore remboursé et avoisine les 800€. </p>
<h2>Référence</h2>
<ul>
<li><a href="http://www.has-sante.fr/portail/jcms/c_1165790/fr/strategies-de-depistage-de-la-trisomie-21-impact-et-mise-en-oeuvre">Stratégies de dépistage de la trisomie 21</a></li>
<li><a href="https://www.has-sante.fr/portail/upload/.../recommandation_trisomie_21.pdf">Les performances des tests ADN libre circulant </a></li>
<li><a href="http://www.illumina.com/content/dam/.../intl-presentation-0042-vc-french.pdf">La valeur d'un dépistage préatal non invasif ( Illumina)</a></li>
<li><a href="http://www.ncbi.nlm.nih.gov/pubmed/24990604">RapidR</a></li>
<li><a href="http://www.ncbi.nlm.nih.gov/pubmed/24170809">Wisecondor</a></li>
</ul>
<h2>Remerciement</h2>
<p><a href="https://twitter.com/Thibaud_GS">@Thibaud_GS </a></p>Le génome en chiffre - part 12016-04-29T12:55:48+02:002016-04-29T12:55:48+02:00Sacha Schutztag:dridk.me,2016-04-29:/genome_chiffre_1.html<p>Ça faisait longtemps que j'avais envie de faire une description numérique du génome. Vous savez ces chiffres repères qui nous permettent de faire des comparaisons et de répondre à des questions du genre : "<em>Est-ce que cette montagne est grande ?</em>" Si vous n'avez pas de référence, comme la taille du Mont …</p><p>Ça faisait longtemps que j'avais envie de faire une description numérique du génome. Vous savez ces chiffres repères qui nous permettent de faire des comparaisons et de répondre à des questions du genre : "<em>Est-ce que cette montagne est grande ?</em>" Si vous n'avez pas de référence, comme la taille du Mont Blanc, ça va être difficile de vous faire une idée... <br>
Nous allons faire pareil sur le génome humain ! Et pour être sûr qu'une organisation maçonnique n'a pas volontairement mis des faux chiffres sur internet, nous allons tout calculer par nous-même ! Ça sera l'occasion de faire un peu de <a href="https://fr.wikipedia.org/wiki/Bourne-Again_shell">bash</a> et d'apprendre quelques commandes ! </p>
<h2>Télécharger le génome humain</h2>
<p>Tout d'abord si vous n'avez pas le génome de référence, télécharger le depuis le <a href="http://hgdownload.cse.ucsc.edu/goldenpath/hg19/bigZips/">goldenpath d'UCSC</a>. C'est le fichier <em>hg19.2bit</em> qui fait 778M.</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">hgdownload</span><span class="o">.</span><span class="n">soe</span><span class="o">.</span><span class="n">ucsc</span><span class="o">.</span><span class="n">edu</span><span class="o">/</span><span class="n">goldenPath</span><span class="o">/</span><span class="n">hg19</span><span class="o">/</span><span class="n">bigZips</span><span class="o">/</span><span class="n">hg19</span><span class="o">.</span><span class="mi">2</span><span class="n">bit</span><span class="w"></span>
</code></pre></div>
<p>Ce fichier est compressé. En fait chaque base est codée sur 2 bits au lieu de 8. On peut le convertir en fichier texte standard avec la commande <strong>twoBitToFa</strong> disponible également sur UCSC. </p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">hgdownload</span><span class="o">.</span><span class="n">cse</span><span class="o">.</span><span class="n">ucsc</span><span class="o">.</span><span class="n">edu</span><span class="o">/</span><span class="n">admin</span><span class="o">/</span><span class="n">exe</span><span class="o">/</span><span class="n">linux</span><span class="o">.</span><span class="n">x86_64</span><span class="o">/</span><span class="n">twoBitToFa</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">chmod</span><span class="w"> </span><span class="o">+</span><span class="n">x</span><span class="w"> </span><span class="n">twoBitToFa</span><span class="w"> </span>
<span class="o">$</span><span class="w"> </span><span class="o">./</span><span class="n">twoBitToFa</span><span class="w"> </span><span class="n">hg19</span><span class="o">.</span><span class="mi">2</span><span class="n">bit</span><span class="w"> </span><span class="n">hg19</span><span class="o">.</span><span class="n">fa</span><span class="w"></span>
</code></pre></div>
<p>Vous voilà avec un fichier <a href="https://fr.wikipedia.org/wiki/FASTA_%28format_de_fichier%29">fasta</a>, contenant les séquences de chaque chromosome humain... Chaque.. En fait, non! Ce fichier contient des chromosomes en double avec des séquences alternatives ainsi que le chromosome mitochondrial.
Tapez cette commande pour voir tous les noms des chromosomes du fichier <em>hg19.fa</em>.</p>
<div class="highlight"><pre><span></span><code>$ cat hg19.fa<span class="p">|</span>grep <span class="s2">">chr"</span>
</code></pre></div>
<p>Nous allons plutôt créer un fichier avec uniquement les chromosomes nucléaires de 1 à 22 et les deux chromosomes sexuels X et Y. Il y a un outil <strong>faSomeRecords</strong> sur UCSC qui fait très bien le travail. Il prend en argument notre génome <em>hg19.fa</em> et un fichier avec la liste des chromosomes souhaités. </p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">hgdownload</span><span class="o">.</span><span class="n">cse</span><span class="o">.</span><span class="n">ucsc</span><span class="o">.</span><span class="n">edu</span><span class="o">/</span><span class="n">admin</span><span class="o">/</span><span class="n">exe</span><span class="o">/</span><span class="n">linux</span><span class="o">.</span><span class="n">x86_64</span><span class="o">/</span><span class="n">faSomeRecords</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">chmod</span><span class="w"> </span><span class="o">+</span><span class="n">x</span><span class="w"> </span><span class="n">faSomeRecords</span><span class="w"></span>
<span class="c1">#Création d'une liste de chromosomes </span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="p">{</span><span class="mf">1.</span><span class="o">.</span><span class="mi">22</span><span class="p">};</span><span class="w"> </span><span class="n">do</span><span class="w"> </span><span class="n">echo</span><span class="w"> </span><span class="n">chr</span><span class="o">$</span><span class="n">i</span><span class="p">;</span><span class="w"> </span><span class="n">done</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">chromosomes</span><span class="o">.</span><span class="n">list</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">echo</span><span class="w"> </span><span class="n">chrX</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="n">chromosomes</span><span class="o">.</span><span class="n">list</span><span class="w"> </span>
<span class="o">$</span><span class="w"> </span><span class="n">echo</span><span class="w"> </span><span class="n">chrY</span><span class="w"> </span><span class="o">>></span><span class="w"> </span><span class="n">chromosomes</span><span class="o">.</span><span class="n">list</span><span class="w"> </span>
<span class="o">$</span><span class="w"> </span><span class="o">./</span><span class="n">faSomeRecords</span><span class="w"> </span><span class="n">hg19</span><span class="o">.</span><span class="n">fa</span><span class="w"> </span><span class="n">chromosomes</span><span class="o">.</span><span class="n">list</span><span class="w"> </span><span class="n">hg19_clean</span><span class="o">.</span><span class="n">fa</span><span class="w"></span>
</code></pre></div>
<p>Voilà, un fichier tout propre contenant uniquement les 24 chromosomes du génome humain. </p>
<h2>Quel est la taille du génome humain ?</h2>
<p>Il suffit de compter le nombre de bases! On supprime tous les retours à la ligne du fichier fasta et on compte avec la commande wc -c ! </p>
<div class="highlight"><pre><span></span><code>$ cat hg19_clean.fa<span class="p">|</span>grep -v <span class="s2">"chr."</span> <span class="p">|</span> tr --delete <span class="s2">"\n"</span> <span class="p">|</span> wc -c
$ <span class="m">3095677412</span>
</code></pre></div>
<p><strong>3'095'677'412</strong> c'est le nombre de nucléotides qu'il y a dans le fichier du génome humain. Retenez donc que le génome est constitué d'environ 3 milliards de paires de base. </p>
<h2>Pourcentage en GC du génome humain ?</h2>
<p>Pour ça, je vous propose d'utiliser un de mes outils préférés : <a href="http://bedtools.readthedocs.io/en/latest/">bedtools</a> ! Le couteau suisse du bioinformaticien. Il est en principe dans les dépôts d'Ubuntu mais je vous conseille la dernière version depuis le site officiel : </p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">arq5x</span><span class="o">/</span><span class="n">bedtools2</span><span class="o">/</span><span class="n">releases</span><span class="o">/</span><span class="n">download</span><span class="o">/</span><span class="n">v2</span><span class="o">.</span><span class="mf">25.0</span><span class="o">/</span><span class="n">bedtools</span><span class="o">-</span><span class="mf">2.25</span><span class="o">.</span><span class="mf">0.</span><span class="n">tar</span><span class="o">.</span><span class="n">gz</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">tar</span><span class="w"> </span><span class="o">-</span><span class="n">zxvf</span><span class="w"> </span><span class="n">bedtools</span><span class="o">-</span><span class="mf">2.25</span><span class="o">.</span><span class="mf">0.</span><span class="n">tar</span><span class="o">.</span><span class="n">gz</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">cd</span><span class="w"> </span><span class="n">bedtools2</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">make</span><span class="w"> </span>
<span class="o">$</span><span class="w"> </span><span class="n">sudo</span><span class="w"> </span><span class="n">make</span><span class="w"> </span><span class="n">install</span><span class="w"></span>
</code></pre></div>
<p>Pour connaître le pourcentage en base A,C,G,T on utilise <strong>bedtools nuc</strong>. Cette commande permet de compter les pourcentages en base A,C,G,T dans un fichier fasta à partir des régions chromosomiques définies dans un fichier bed. On va calculer ces pourcentages pour chaque chromosome. <br>
Pour aller plus vite, on peut télécharger le fichier <em>hg19.chrom.sizes</em>. Celui-ci contient sur chaque ligne, le nom du chromosome et sa taille en bases. On va s'en servir pour créer le fichier nécessaire à bedtools. </p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">hgdownload</span><span class="o">.</span><span class="n">soe</span><span class="o">.</span><span class="n">ucsc</span><span class="o">.</span><span class="n">edu</span><span class="o">/</span><span class="n">goldenPath</span><span class="o">/</span><span class="n">hg19</span><span class="o">/</span><span class="n">bigZips</span><span class="o">/</span><span class="n">hg19</span><span class="o">.</span><span class="n">chrom</span><span class="o">.</span><span class="n">sizes</span><span class="w"></span>
<span class="o">$</span><span class="w"> </span><span class="n">cat</span><span class="w"> </span><span class="n">hg19</span><span class="o">.</span><span class="n">chrom</span><span class="o">.</span><span class="n">sizes</span><span class="o">|</span><span class="n">grep</span><span class="w"> </span><span class="o">-</span><span class="n">we</span><span class="w"> </span><span class="s2">"chr[0-9XY]*"</span><span class="o">|</span><span class="n">awk</span><span class="w"> </span><span class="s1">'BEGIN{OFS="</span><span class="se">\t</span><span class="s1">"}{print $1,0,$2}'</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">hg19_clean</span><span class="o">.</span><span class="n">sizes</span><span class="o">.</span><span class="n">bed</span><span class="w"></span>
</code></pre></div>
<p>Assurez-vous que la somme des tailles des chromosomes tombe bien sur les 3 milliards précédents.</p>
<div class="highlight"><pre><span></span><code>$ cat hg19_clean.sizes.bed<span class="p">|</span>cut -f3<span class="p">|</span>paste -sd <span class="s2">"+"</span><span class="p">|</span>bc
</code></pre></div>
<p>Lancer alors la commande :</p>
<div class="highlight"><pre><span></span><code>$ bedtools nuc -fi hg19_clean.fa -bed hg19_clean.sizes.bed > hg19.stat
</code></pre></div>
<p>Vous obtenez un fichier contenant pour chaque chromosome, le nombre de nucléotides A,T,C,G,N avec le pourcentage en AT et CG. N’hésiter pas à regarder l'aide de la commande. <br>
Le pourcentage en GC du génome humain tourne autour de <strong>37%</strong>. Avec comme extrêmes le chromosome 19 (<strong>48%</strong>) et le chromosome Y (<strong>25%</strong>). </p>
<h2>Pourcentage en base A,C,G,T</h2>
<p>Dans le fichier <em>hg19.stat</em> précédemment généré, on observe aussi le nombre de bases A,C,G,T. On faisant la somme, on obtient sur tout le génome :</p>
<ul>
<li>846093191 bases T soit 27.2%</li>
<li>844862932 bases A soit 27.3% </li>
<li>585012752 bases C soit 18.8% </li>
<li>585358256 bases G soit 18.9% </li>
</ul>
<p>Olaa.. Attendez c'est quoi ce truc ? Il y a quasiment autant de base A que de T, et autant de base C que de G. Détrompez-vous, si vous pensez que c'est <a href="https://fr.wikipedia.org/wiki/R%C3%A8gles_de_Chargaff">la loi de Chargaff</a> expliquant la complémentarité des brins, car cette répartition est sur un seul brin d'ADN ! Pas de double brin dans l'histoire ! C'est comme si dans un livre de 3 milliards de lettre, il y avait autant de "s" que de "a". <br>
Bien sûr j'ai recherché, j'ai demandé, j'ai eu toutes les réponses inimaginables. En fait c'est ce qu'on appelle la seconde loi de Chargaff, beaucoup moins connu! Et je vous assure, je n'ai pas encore trouvé d'explication, si ce n'est <a href="http://www.basic.northwestern.edu/g-buehler/genomes/g_chargaff.htm">celle-ci</a></p>
<h2>Combien de gènes dans le génome humain ?</h2>
<p>Dans le génome il y a des gènes constitués d'intron et d'exon. Et chaque gène défini plusieurs transcrits. <br>
On peut télécharger <a href="https://en.wikipedia.org/wiki/RefSeq">refseq</a>, une base de donnée contenant tous les gènes officiels ! Dans le fichier, ces colonnes vont nous intéresser par la suite. </p>
<ul>
<li>colonne 3 : le chromosome </li>
<li>colonne 5 : le début du transcrit</li>
<li>colonne 6 : la fin du transcrit</li>
<li>colonne 7 : début du CDS </li>
<li>colonne 8 : fin du CDS </li>
<li>colonne 9 : le nombre d'exons</li>
<li>colonne 10: liste des débuts d'exons</li>
<li>colonne 11: liste des fins d'exons </li>
<li>colonne 13 : le nom du gène</li>
</ul>
<p>Pour télécharger : </p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">hgdownload</span><span class="o">.</span><span class="n">cse</span><span class="o">.</span><span class="n">ucsc</span><span class="o">.</span><span class="n">edu</span><span class="o">/</span><span class="n">goldenPath</span><span class="o">/</span><span class="n">hg19</span><span class="o">/</span><span class="n">database</span><span class="o">/</span><span class="n">refGene</span><span class="o">.</span><span class="n">txt</span><span class="o">.</span><span class="n">gz</span><span class="w"></span>
</code></pre></div>
<p>Compter le nombre de gènes uniques : </p>
<div class="highlight"><pre><span></span><code>$ zcat refGene.txt.gz<span class="p">|</span>cut -f13<span class="p">|</span>sort -u <span class="p">|</span> wc -l
$ <span class="m">27048</span>
</code></pre></div>
<p>Votre Deuxième chiffre à retenir ! Environ <strong>27000</strong> gène constitue le génome humain !</p>
<h3>Quel est le pourcentage d'exons ?</h3>
<p>Dans le fichier refseq, colonne 10 et 11, nous avons tous les débuts et les fins des exons. J'ai juste fait la somme des différences entre fin d'exon et début d'exon sur tous les gènes uniques. Avec awk, ça se fait tout seul : </p>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">zcat</span><span class="w"> </span><span class="n">refGene</span><span class="p">.</span><span class="n">txt</span><span class="p">.</span><span class="n">gz</span><span class="o">|</span><span class="n">sort</span><span class="w"> </span><span class="o">-</span><span class="n">u</span><span class="w"> </span><span class="o">-</span><span class="n">k</span><span class="w"> </span><span class="mi">13</span><span class="p">,</span><span class="mi">13</span><span class="o">|</span><span class="n">awk</span><span class="w"> </span><span class="s1">'{SUM=0;split($10,s,","); split($11,e,",");for(i=1;i<length(s);i++){SUM+=e[i] - s[i]};print SUM}'</span><span class="o">|</span><span class="n">paste</span><span class="w"> </span><span class="o">-</span><span class="n">sd</span><span class="w"> </span><span class="ss">"+"</span><span class="o">|</span><span class="n">bc</span><span class="w"> </span>
<span class="err">$</span><span class="w"> </span><span class="mi">72090466</span><span class="w"></span>
</code></pre></div>
<p>On obtient <strong>72090466</strong>, le nombre de bases dans les exons. En le divisant par la taille du génome, on se retrouve avec : <strong>2.32 %</strong> du génome est constitué d'exon.</p>
<h3>Quel est le pourcentage de bases codantes ?</h3>
<p>Pour cela, j'ai crée un fichier bed qui contient la position de tous les exons. Et un second fichier contenant la position de toutes les <a href="https://fr.wikipedia.org/wiki/S%C3%A9quence_codante">cds</a>. J'ai ensuite fait l'intersection avec bedtools. </p>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">zcat</span><span class="w"> </span><span class="n">refGene</span><span class="p">.</span><span class="n">txt</span><span class="p">.</span><span class="n">gz</span><span class="o">|</span><span class="n">sort</span><span class="w"> </span><span class="o">-</span><span class="n">u</span><span class="w"> </span><span class="o">-</span><span class="n">k</span><span class="w"> </span><span class="mi">13</span><span class="p">,</span><span class="mi">13</span><span class="o">|</span><span class="n">awk</span><span class="w"> </span><span class="s1">'BEGIN{OFS="\t"}{SUM=0;split($10,s,","); split($11,e,",");for(i=1;i<length(s);i++){print $3,s[i],e[i]} }'</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">exons</span><span class="p">.</span><span class="n">bed</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">zcat</span><span class="w"> </span><span class="n">refGene</span><span class="p">.</span><span class="n">txt</span><span class="p">.</span><span class="n">gz</span><span class="o">|</span><span class="n">sort</span><span class="w"> </span><span class="o">-</span><span class="n">u</span><span class="w"> </span><span class="o">-</span><span class="n">k</span><span class="w"> </span><span class="mi">13</span><span class="p">,</span><span class="mi">13</span><span class="o">|</span><span class="n">awk</span><span class="w"> </span><span class="s1">'BEGIN{OFS="\t"}{print $3,$7,$8 }'</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">cds</span><span class="p">.</span><span class="n">bed</span><span class="w"></span>
<span class="err">$</span><span class="w"> </span><span class="n">bedtools</span><span class="w"> </span><span class="ow">intersect</span><span class="w"> </span><span class="o">-</span><span class="n">a</span><span class="w"> </span><span class="n">exons</span><span class="p">.</span><span class="n">bed</span><span class="w"> </span><span class="o">-</span><span class="n">b</span><span class="w"> </span><span class="n">cds</span><span class="p">.</span><span class="n">bed</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">awk</span><span class="w"> </span><span class="s1">'{print $3-$2}'</span><span class="o">|</span><span class="n">paste</span><span class="w"> </span><span class="o">-</span><span class="n">sd</span><span class="w"> </span><span class="ss">"+"</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">bc</span><span class="w"></span>
</code></pre></div>
<p>On obtient <strong>35269084</strong>, le nombre de base codante. Ce qui fait <strong>1.13 %</strong> du génome. 1% du génome est codant. Oui... C'est vraiment pas beaucoup !</p>
<h3>Quel est le pourcentage d'intron ?</h3>
<p>Même logique, j'ai fait les zones transcrites soustraites des exons. Ce qui nous donne les introns avec les UTR. </p>
<div class="highlight"><pre><span></span><code>$ zcat refGene.txt.gz<span class="p">|</span>sort -u -k <span class="m">13</span>,13<span class="p">|</span>awk <span class="s1">'BEGIN{OFS="\t"}{print $3,$5,$6 }'</span> > transcrits.bed
$ bedtools substract -a transcrits.bed -b exons.bed <span class="p">|</span> awk <span class="s1">'{print $3-$2}'</span><span class="p">|</span>paste -sd <span class="s2">"+"</span> <span class="p">|</span> bc
</code></pre></div>
<p>On obtient <strong>1184956505</strong> bases dans les introns/UTRs soit <strong>38.2 %</strong> du génome !
Il reste tout de même plus de 60% d'inconnu ! Dans un prochain article, on s'y attaque ! </p>
<h3>Combien de mutations me distinguent du génome de référence ?</h3>
<p>On ne va pas prendre mon génome... Mais celui de <a href="https://fr.wikipedia.org/wiki/James_Dewey_Watson">James Watson</a> co-découvreur de la structure de l'ADN avec <a href="https://fr.wikipedia.org/wiki/Francis_Crick">Francis Crick</a> et <a href="https://fr.wikipedia.org/wiki/Rosalind_Franklin">Rosalind Franklin</a>. Son génome a été séquencé et distribué librement. Nous allons télécharger un fichier contenant uniquement les différences entre le génome de Watson et le génome de référence. C'est-à-dire un fichier contenant sur chaque ligne, la position et la base alternative.</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">hgdownload</span><span class="o">.</span><span class="n">cse</span><span class="o">.</span><span class="n">ucsc</span><span class="o">.</span><span class="n">edu</span><span class="o">/</span><span class="n">goldenpath</span><span class="o">/</span><span class="n">hg19</span><span class="o">/</span><span class="n">database</span><span class="o">/</span><span class="n">pgWatson</span><span class="o">.</span><span class="n">txt</span><span class="o">.</span><span class="n">gz</span><span class="w"></span>
</code></pre></div>
<p>En comptant le nombre de ligne : </p>
<div class="highlight"><pre><span></span><code>$ cat pgWatson.txt.gz <span class="p">|</span> wc -l
</code></pre></div>
<p>On obtient <strong>2059384</strong> variants. Environs <strong>2 millions</strong> de bases distinguent James Watson du génome de référence. En pourcentage, ça nous fait : <strong>0.06 %</strong></p>
<h3>Combien de mutations je partage avec un autre individu ?</h3>
<p>On va regarder les variants que partagent <a href="https://fr.wikipedia.org/wiki/Craig_Venter">Craig Venter</a> et James Watson.
Même chose que précédemment, on récupère les données de Venter. </p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="w"> </span><span class="n">wget</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">hgdownload</span><span class="o">.</span><span class="n">cse</span><span class="o">.</span><span class="n">ucsc</span><span class="o">.</span><span class="n">edu</span><span class="o">/</span><span class="n">goldenpath</span><span class="o">/</span><span class="n">hg19</span><span class="o">/</span><span class="n">database</span><span class="o">/</span><span class="n">pgVenter</span><span class="o">.</span><span class="n">txt</span><span class="o">.</span><span class="n">gz</span><span class="w"></span>
</code></pre></div>
<p>Ensuite on transforme le fichier de Watson et Craig en fichier bed. </p>
<div class="highlight"><pre><span></span><code>$ zcat pgVenter.txt.gz <span class="p">|</span>cut -f2,3,4<span class="p">|</span>sort > venter.bed
$ zcat pgWatson.txt.gz <span class="p">|</span>cut -f2,3,4<span class="p">|</span>sort > watson.bed
</code></pre></div>
<p>Puis on fait l'intersection : </p>
<div class="highlight"><pre><span></span><code>$ bedtools intersect -a venter.bed -b watson.bed<span class="p">|</span>wc -l
</code></pre></div>
<p>On trouve alors <strong>1'192'314</strong> de variants en commun entre Venter et Watson! </p>
<h1>Conclusion</h1>
<p>Nous allons nous arrêter là pour le moment, sinon on ne finira jamais ! Pour cette fois retenez ceci : Votre ADN est composé de <strong>3 millards</strong> de paires bases. <strong>1%</strong> constitue le génome codant pour <strong>25 000</strong> gènes. Et <strong>1 million</strong> de variants vous distinguent d'un autre individu. <br>
Dans le prochain article, nous allons poser d'autres questions beaucoup plus précises. Où se trouvent les variations ? Qu'y a-t-il dans les 60% de l'ADN ? Quelles sont les mutations les plus fréquentes ? Posez vos questions dans les commentaires, j'essaierai d'y répondre! </p>
<h2>Remerciement</h2>
<p><a href="https://www.twitter.com/ZaZo0o">@ZaZo0o</a> </p>Le paludisme2016-04-29T12:55:48+02:002016-04-29T12:55:48+02:00Thibaud Guillaud-Saumurtag:dridk.me,2016-04-29:/paludisme.html<p>« <em>Quel est l’animal le plus meurtrier au monde ?</em> » On entend souvent cette question, et une fois passés les requins blancs, serpents et autres méduse-boîtes vient toujours un petit malin pour répondre « <em>Le moustique !</em> ».
Bon ok il n’a pas tort le petit malin. Mais pour être plus précis le …</p><p>« <em>Quel est l’animal le plus meurtrier au monde ?</em> » On entend souvent cette question, et une fois passés les requins blancs, serpents et autres méduse-boîtes vient toujours un petit malin pour répondre « <em>Le moustique !</em> ».
Bon ok il n’a pas tort le petit malin. Mais pour être plus précis le moustique n’est qu’un taxi pour le vrai tueur numéro 1 sur cette planète. On l’appelle la <strong>Malaria</strong>, le « mauvais air » mais la maladie est plus connue sous le nom de <strong>Paludisme</strong> et cause <a href="http://www.who.int/mediacentre/factsheets/fs094/fr/">500 000 morts par an dans le monde</a>. Le parasite en cause est un protozoaire appelé <em>Plasmodium</em> qui regroupe plusieurs espèces (<em>P. falciparum</em>, <em>P. malariae</em>, <em>P. vivax</em>, etc).
Parler de ce tueur en série c’est l’occasion de parler un peu d’immunité, d’évolution, mais avant tout c’est l’occasion de parler des parasites !</p>
<h2>Parasitisme</h2>
<p>Avant d’aller plus loin une petite définition s’impose : qu’est-ce qu’un <a href="https://fr.wikipedia.org/wiki/Parasite">parasite</a> ? Les dictionnaires vous diront que c’est un organisme qui vit aux dépens d’un autre organisme appelé hôte.
Un peu comme ce colocataire qui profite du toit, du micro-onde et de la connexion wifi mais qui ne paie jamais le loyer.
On l’oppose souvent à la <a href="https://fr.wikipedia.org/wiki/Symbiose">symbiose</a>, où les deux êtres vivants ont besoin l’un de l’autre. En effet le parasite va utiliser à son profit les ressources de son hôte, sans lui être indispensable, voire lui être néfaste...
Plus de fromage rapé dans le frigo ? C’est le parasite.
Il est important de préciser que ce n’est qu’un mode de vie parmi d’autre. Un moyen pour un organisme de trouver l’énergie suffisante pour se reproduire. Nous, humains, avons trouvé une autre méthode commune à de nombreux autres animaux sur cette planète : la prédation. Le prédateur va chasser et tuer sa proie. La relation entre le prédateur et la proie est courte et sanglante, l’un imposant une pression de sélection sur l’autre. Les proies plus adaptées à échapper à leur prédateur vont survivre, se reproduire, et transmettre ce caractère à leur descendance perpétuant leurs gènes. Tandis que l'information génétique des proies tuées est perdu.</p>
<p align="center">
<img src="../images/post15/predationproie.png">
</p>
<p>Dans le cas du parasitisme si le bilan est le même, un transfert d'énergie entre deux organismes, la relation différente. Notre parasite vit au contact de son hôte, parfois pendant une courte période de sa vie, mais parfois pendant des années comme le ver solitaire ou <a href="https://fr.wikipedia.org/wiki/Taenia_saginata">Ténia</a>. Les deux organismes se côtoient de manière très étroite et le système immunitaire de l’hôte joue un peu le rôle du prédateur qui cherche à éliminer le parasite. Et comme la gazelle qui a évolué pour fuir plus rapidement les lions, les parasites évoluent également pour échapper à notre système immunitaire… Et pour cela ils redoublent d’ingéniosité !</p>
<h2>Le globule rouge : une planque idéale</h2>
<p>Dans un <a href="reconnaissance_soi.html">article précédent</a> de ce blog, vous avez pu apprendre que nos cellules ont un mécanisme efficace pour se protéger d’un organisme qui voudrait vivre à l’intérieur, comme un virus, il s’agit des <a href="https://fr.wikipedia.org/wiki/CMH">molécules de CMH</a>. Or, toutes les cellules n’en possèdent pas !
Par exemple les <a href="https://fr.wikipedia.org/wiki/%C3%89rythrocyte">globules rouges</a> qui transportent l’oxygène dans le sang via l’<a href="https://fr.wikipedia.org/wiki/H%C3%A9moglobine">hémoglobine</a> sont totalement dépourvues de ce système de défense.
Ce n’est pas un problème contre les <a href="https://fr.wikipedia.org/wiki/Virus">virus</a> car les globules rouges sont des cellules sans noyau, relativement simples. Or le virus, très simple également, aime les cellules qui lui fourniront tous les outils pour sa réplication. Bref, pour envahir le globule rouge il faut venir avec son propre matériel et ça n’intéresse pas le virus partisan du moindre effort.
Pourtant c’est la cachette qu’a choisi le paludisme ! Il n’a pas choisi la facilité, mais une fois à l’intérieur il passe totalement incognito... ou presque.</p>
<p align="center">
<img src="../images/post15/blood.jpg">
</p>
<p>Le globule rouge est fortement modifié par son squatteur et de nombreuses protéines du parasite sont exprimées à la surface de la cellule. Parmi celles-ci on peut citer la <a href="http://www.ncbi.nlm.nih.gov/pubmed/11698301"><em>Plasmodium falciparum</em> erythrocyte membrane protein 1</a>, ou plus court mais tout aussi galère à prononcer : PfEMP1. Cette protéine permet entre autres au globule rouge parasité d’adhérer à la surface de nos vaisseaux sanguins. Une habile stratégie pour échapper au piège de la <a href="https://fr.wikipedia.org/wiki/Rate">rate</a>, l’organe qui filtre notre sang.
Mais le paludisme aurait-il fait l’erreur de trahir sa présence ? Voilà des protéines à la surface du globule rouge qui ne sont pas humaines ! Que fait l’immunité ?!... Sauf que <em>Plasmodium</em> est plus malin que ça. PfEMP1 est codé par des gènes particuliers appelés <a href="http://biologie.univ-mrs.fr/upload/p87/kraemer_2006.pdf">var gene</a>. Ces var gene sont au nombre d’une soixantaine, un seul est exprimé à la fois, ce qui veut dire qu’une seule forme de PfEMP1 est exprimée à la fois. Le temps que des <a href="https://fr.wikipedia.org/wiki/Anticorps">anticorps</a> soient produits contre ces protéines, <em>Plasmodium</em> produit une nouvelle fournée de PfEMP1, juste assez différentes pour ne pas être reconnues par notre système immunitaire. Les nouvelles PfEMP1 remplacent les anciennes et le parasite continue de se balader en costume de globule rouge.</p>
<p align="center">
<img src="../images/post15/redcell.png">
</p>
<p>C’est la force du paludisme, comme de beaucoup d’autres parasites, d’être variable pour lutter contre la pression que leur impose notre immunité. C’est cette même variabilité antigénique qui rend si difficile l’élaboration d’un vaccin contre le fléau du paludisme !
Mais leur variabilité s’étend encore au-delà… Puisque les parasites doivent souvent s’adapter à plusieurs hôtes comme c’est le cas ici avec le moustique et l’être humain. Et dans chaque hôte, ils sont capables de se transformer pour s’adapter à différentes parties de l’organisme.</p>
<h2>Le cycle du paludisme</h2>
<p align="center">
<img src="../images/post15/cycle.png">
</p>
<p>Puisqu’il faut prendre un point de départ dans un cycle, prenons la piqure du moustique.
La piqure du moustique (Anophèle) va injecter dans la peau de l’homme le <em>Plasmodium</em> sous une forme mobile appelée <a href="https://fr.wikipedia.org/wiki/Sporozo%C3%AFte">sporozoïte</a> (1). Le sporozoïte va rapidement rejoindre le foie dont il va parasiter des cellules pendant quelques jours (2). Ce n’est qu’après cette première multiplication dans le foie que le paludisme va rejoindre le sang sous forme de <a href="https://fr.wikipedia.org/wiki/M%C3%A9rozo%C3%AFte">mérozoites</a> et infecter nos globules rouges. A chacune de ces étapes, notre immunité monte une garde vigilante et toutes les stratégies du parasite pour y échapper ne sont pas encore élucidées.
Une fois bien installé dans le globule rouge, le parasite va croitre et se multiplier à l’intérieur. Cette multiplication a une durée bien précise, de 2 à 3 jours selon les espèces et se termine par l’explosion du globule rouge… Ou plus précisément de tous les globules rouges infectés, simultanément. Les globules rouges déversent alors une grande quantité de mérozoites qui vont infecter à nouveau d’autres globules rouges (3). C’est cette abondance de mérozoites dans le sang au moment de l’explosion des globules rouges qui cause la fièvre du paludisme. Certains globules rouges parasités vont se transformer en gamétocytes (4), mâles ou femelles. Ce sont les équivalents de nos spermatozoïdes et ovules.
Si un moustique pique l’être humain parasité il va se nourrir de son sang, et au passage des gamétocytes. Les gamétocytes se fécondent dans le moustique, pour donner un zygote puis un oocyste. Ce dernier libérera une nouvelle génération de sporozoïtes prête à être injectée à une autre victime humaine (5)… Et le cycle est bouclé !</p>
<h2>La course à l'adaptation</h2>
<p>Le paludisme n'est pas le seul à s'adapater à son hôte. L'hôte également cherche à se protéger du parasite. Ou plutôt dans le cas des parasites mortels comme le paludisme, l'hôte résistant au parasite peut être sélectionné.</p>
<p>Un des exemples les plus frappants concerne la <a href="https://fr.wikipedia.org/wiki/Dr%C3%A9panocytose">drépanocytose</a>. Cette maladie génétique touche la molécule d'hémoglobine, contenue dans le globule rouge. L'hémoglobine mutée (HbS) transporte moins efficacement l'oxygène et entraîne une forme plus rigide "<em>en faucille</em>" du globule rouge. Etre porteur d'un seul allèle muté sur les deux permet de vivre normalement et il a été montré qu'être porteur de la drépanocytose <a href="http://www.ncbi.nlm.nih.gov/pubmed/21529713">protégeait de l'infection par le paludisme!</a>. On observe effectivement que cette maladie génétique et le paludisme sont présents dans les mêmes régions d'Afrique (cartes de gauche et du milieu). Les humains porteurs de la maladie génétique ont donc pu être sélectionnés, car moins sujets à des formes mortelles de paludisme.</p>
<p>Un autre exemple concerne les groupes sanguins. Nos groupes sanguins sont des antigènes (faits de protéines, glucides et lipides) à la surface de nos globules rouges. Les groupes A, B, O sont les plus connus, mais il en existe d'autres et un des groupes sanguins mineurs, le <a href="https://fr.wikipedia.org/wiki/Syst%C3%A8me_Duffy">groupe Duffy</a>, est nécessaire à l'entrée de l'espèce <em>Plasmodium vivax</em> dans le globule rouge... On observe que cette espèce est absente de toute l'Afrique de l'ouest où la grande majorité de la <a href="http://www.ncbi.nlm.nih.gov/pubmed/17607593">population est Duffy Négative!</a> Malheureusement, <em>Plasmodium vivax</em> a été remplacée dans ces régions par d'autres espèces de <em>Plasmodium</em> qui n'ont pas besoin de Duffy pour rentrer dans nos globules rouges (cartes du milieu et de droite).</p>
<p align="center">
<img src="../images/post15/carte.png">
</p>
<p>A quoi servent ces groupes sanguins d'ailleurs ?... Voilà une question qui sera traitée dans un prochain article sur ce blog !</p>
<h2>Conclusion</h2>
<p>Les parasites sont des organismes complexes qui ont su s’adapter à de nombreux organismes. Les stratégies d’échappement sont multiples. Nous avons parlé de la <strong>variabilité antigénique</strong>, mais d’autres parasites excellent dans l’art du <strong>camouflage</strong> ou du <strong>leurre</strong>. Ces systèmes de survie ne doivent pas être confondues par une intention ou une intelligence du parasite. Il s’agit plutôt d’un équilibre qui a été obtenu sur du long terme. Un parasite qui côtoie un hôte depuis suffisamment de générations (on parle ici de millions d’année de co-évolution entre l’hôte et son parasite) peut devenir totalement anodin pour l’organisme qu’il occupe. On peut ainsi imaginer que certaines symbioses ne sont que des parasitismes qui se sont adaptés à la perfection. Le couple paludisme-homme a donc encore du chemin à faire…</p>
<p>Moralité : si votre coloc, pour échapper à votre colère immune décide de vous faire des pizzas pour détourner votre attention … vous pourriez bien finir par l’accueillir comme une machine à pizza tout à fait légitime qui a sa place dans votre appartement ! (toute ressemblance avec la symbiose entre les mitochondries et nos cellules est totalement fortuite)</p>
<h2>Références</h2>
<ul>
<li><a href="http://www.cdc.gov/dpdx/resources/pdf/benchAids/malaria/Congo_Bench_Aid_vF.pdf">Diagnostic microscopique du paludisme</a></li>
<li><a href="http://biologie.univ-mrs.fr/upload/p87/kraemer_2006.pdf">Kraemer, S. M. & Smith, J. D. A family affair: var genes, PfEMP1 binding, and malaria disease. Curr. Opin. Microbiol. 9, 374–380 (2006).</a></li>
<li><a href="http://www.who.int/mediacentre/factsheets/fs094/fr/">OMS</a></li>
<li><a href="http://www.ncbi.nlm.nih.gov/pubmed/21529713">Ferreira, A. et al. Sickle hemoglobin confers tolerance to Plasmodium infection. Cell 145, 398–409 (2011).</a></li>
<li><a href="http://www.ncbi.nlm.nih.gov/pubmed/17607593">Langhi, D. M. & Bordin, J. O. Duffy blood group and malaria. Hematol. Amst. Neth. 11, 389–398 (2006).</a></li>
<li><a href="http://www.remede.org/documents/parasitoses-et-mycoses-des-regions.html">Parasitoses et mycoses des régions tempérées et tropicales, Auteur : Association Française des Enseignants de Parasitologie médicales ANOFEL, Editeur : ELSEVIER / MASSON paru le : 09/2014 (3ème édition)</a></li>
</ul>La reconnaissance du soi2016-02-27T10:57:22+01:002016-02-27T10:57:22+01:00Sacha Schutztag:dridk.me,2016-02-27:/reconnaissance_soi.html<p>Si vous lisez mon blog, vous avez sûrement constaté ma tendance à tracer des parallèles entre l'informatique et la génétique, notamment entre séquence d'ADN et séquence binaire. Dans cet article, nous allons à nouveau faire un parallèle qui peut paraître tout aussi surprenant : <strong>La reconnaissance du soi</strong>. <br>
Du point de …</p><p>Si vous lisez mon blog, vous avez sûrement constaté ma tendance à tracer des parallèles entre l'informatique et la génétique, notamment entre séquence d'ADN et séquence binaire. Dans cet article, nous allons à nouveau faire un parallèle qui peut paraître tout aussi surprenant : <strong>La reconnaissance du soi</strong>. <br>
Du point de vue de l'informatique, il s'agit de vérifier si un fichier est bien le votre et qu'il n'a pas été modifié par un virus. <br>
Du point de vue de la biologie, on rencontre le même problème: vérifier qu'une cellule est saine et qu'elle n'a pas été infectée par un virus !<br>
Dans les deux cas nous allons utiliser des "<strong>signatures</strong>" et toute anomalie dans celles-ci révélera l'imposture. </p>
<h2>Signature d'un fichier</h2>
<p>La <em>signature</em> ou <em>empreinte</em> d'un fichier est une séquence de caractères associée de façon unique à un fichier. Par exemple, le fichier <strong>superMario.exe</strong> peut avoir comme empreinte <em>f6c51c6bb1ce72508313dad3dc3c6776</em>. Toute modification du fichier, même minime, entraînera une modification de l'empreinte. <br>
Cette prouesse est réalisée à l'aide des <a href="https://fr.wikipedia.org/wiki/Fonction_de_hachage">fonctions de hachages</a>. Les algorithmes <a href="https://fr.wikipedia.org/wiki/MD5">MD5</a> et <a href="https://fr.wikipedia.org/wiki/SHA-1">SHA-1</a> sont les plus connus. <br>
Depuis un terminal <a href="https://fr.wikipedia.org/wiki/Unix">Unix</a>, vous pouvez récupérer l'empreinte de n'importe quel fichier en tapant : </p>
<div class="highlight"><pre><span></span><code>md5sum superMario.exe
## Retourne: 50e6b5cd621b4f9de2cc78669cd0c350
</code></pre></div>
<p>L'empreinte obtenue est une séquence de 128 bits soit une chaîne hexadécimale de 32 caractères. La probabilité que deux fichiers aient la même empreinte est extrèmement faible mais une telle éventualité est possible, on parle alors de "<em>collision</em>". <br>
Lorsque vous distribuez un fichier, l'empreinte peut être données depuis votre page web, ce qui permettra aux utilisateurs d'en vérifier l'authenticité. Par exemple, à partir de la <a href="http://cdimage.ubuntu.com/kubuntu/releases/wily/release/">page de téléchargement de kubuntu</a>, il est possible de récupérer les empreintes des images ISO à partir du fichier <a href="http://cdimage.ubuntu.com/kubuntu/releases/wily/release/MD5SUMS">MD5SUMS</a>.
Les antivirus utilisent également cet outil. Ils peuvent calculer l'empreinte de l'ensemble de vos fichiers et si un virus contamine l'un d'eux, l'empreinte est modifiée et notre cher <a href="https://fr.wikipedia.org/wiki/Avast!">Avast</a> va sonner l'alarme !</p>
<h2>Signature d'une cellule</h2>
<p>Quel rapport avec une cellule ? Et bien, la majorité de nos cellules possèdent à leur surface une empreinte formée par le <strong><a href="https://fr.wikipedia.org/wiki/Complexe_majeur_d'histocompatibilit%C3%A9">complexe majeur d'histocompatibilité</a></strong> qu'on appelle plus couramment par son acronyme <strong>CMH</strong>. Toute modification de cette empreinte (par un virus par exemple), sera reconnue par le système immunitaire et déclenchera la mort de la cellule. C'est également à cause de ce même mécanisme que les greffes d'organes sont rejetées, car reconnues étrangères. </p>
<h3>Les molécules du CMH.</h3>
<p>Les molécules du CMH sont des <a href="https://fr.wikipedia.org/wiki/Glycoprot%C3%A9ine">glycoprotéines</a> situées sur la membrane de la quasi totalité de nos cellules. Leur rôle est de présenter des courts fragments peptidiques au système immunitaire. Il en existe différents types, codés par des gènes localisés sur le bras court du chromosome 6 et regroupés en plusieurs classes. Dans cet article, nous nous intéressons uniquement à la <a href="https://fr.wikipedia.org/wiki/Complexe_majeur_d'histocompatibilit%C3%A9#CMH_de_classe_I">classe I</a>, composée des 3 gènes: <a href="http://www.ensembl.org/Homo_sapiens/Gene/Summary?db=core;g=ENSG00000206503;r=6:29941260-29945884">HLA-A</a>, <a href="http://www.ensembl.org/Homo_sapiens/Gene/Summary?db=core;g=ENSG00000234745;r=6:31353872-31357188">HLA-B</a> et <a href="http://www.ensembl.org/Homo_sapiens/Gene/Summary?db=core;g=ENSG00000204525;r=6:31268749-31272130">HLA-C</a>.<br>
Ces gènes codent chacun pour une glycoprotéine membranaire composée d'un pochoir où se lie un peptide par complémentarité. Il s'agit donc d'une liaison spécifique, c'est à dire que les molécules HLA-A ne fixent pas les mêmes peptides que les molécule HLA-B. </p>
<h3>La fonction de hachage cellulaire</h3>
<p>Une cellule est définie par ses constituants. Dans notre cas, l'ensemble des protéines synthétisées par la cellule participera à la création d'une empreinte. Ces protéines sont découpées en petits fragments de 9 acides-aminées par le <a href="https://fr.wikipedia.org/wiki/Prot%C3%A9asome">protéasome</a>. Ceux-ci se fixent ensuite par complémentarité sur les molécules du CMH à destination de la membrane cellulaire. <br>
La combinaison des peptides présentée à la surface est la signature ou l'empreinte de la cellule. </p>
<p align="center">
<img src="../images/post14/cell_hla.png">
</p>
<h3>La reconnaissance du CMH</h3>
<p>Les <a href="https://fr.wikipedia.org/wiki/Lymphocyte_T_cytotoxique">lymphocytes T cytotoxiques</a> (TCD8) sont des globules blancs dont la mission est de tester l'intégrité des cellules en vérifiant leurs CMH par leurs récepteurs TCR. Ils reconnaissent à la fois la molécule du CMH et le peptide associé. <br>
Au cours de la formation du système immunitaire, par un mécanisme encore non élucidé, les lymphocytes T deviennent tolérants aux peptides du soi. C'est à dire aux peptides présentés normalement par le CMH. <br>
Plus tard, lors d'une infection par un virus, celui-ci génère de nouvelles protéines dans la cellule, dont les fragments se retrouvent présentés aux lymphocytes T via le CMH. Les lymphocytes reconnaissent alors l'intrusion, et peuvent sonner l'alarme déclenchant tout une cascade de processus aboutissant à la destruction des cellules infectées. </p>
<p align="center">
<img src="../images/post14/lymphoT.png">
</p>
<h3>Le polymorphisme du CMH</h3>
<p>Du point de vue d'un virus, la meilleure façon de réussir son intrusion, c'est de le faire incognito. C'est à dire en produisant des protéines non reconnues par les molécules du CMH, qui ne peuvent donc plus présenter les <a href="https://fr.wikipedia.org/wiki/Antig%C3%A8ne">antigènes</a> viraux (peptides) aux lymphocytes. Pour contrecarrer ces plans, il faut raisonner à l’échelle des populations. C'est la population qui s'adapte au virus et non l'individu. <br>
La variation allélique du CMH dans la population est la plus grande du génome. Il existe [tableau] 1519 allèles du gène HLA-A, 2069 HLA-B et 1016 HLA-C. En rajoutant les allèles maternelles et paternelles, le nombre de combinaisons pour chaque individu est énorme. C'est-à-dire que deux individus non-apparentés ont une chance infime d'avoir l'ensemble de leurs molécules du CMH identiques. En prenant l'ensemble des molécules HLA de toute la population, aucune protéine virale ne peux se cacher. <br>
Telle une armée de soldats possédant chacun une arme différente, chaque individu possède une combinaison unique capable potentiellement de reconnaître les protéines virales. Ça passe ou ça casse ! Les individus qui réussissent à reconnaître le virus sont sélectionnés avec leurs allèles et vont à leur tour enrichir le patrimoine des gènes du CMH. </p>
<p align="center">
<img src="../images/post14/frequence.jpg">
</p>
<h3>Greffe et rejet</h3>
<p>La variation allélique des gènes du CMH permet à une population de lutter contre un virus. En revanche, cela pose problème lors des greffes d'organes. Nous l'avons vu plus haut, les lymphocytes T reconnaissent aussi bien le peptide que la molécule du CMH. Un organe d'un donneur, ne possède pas les mêmes molécules HLA que le receveur. Cette greffe sera donc reconnue comme étrangère par les lymphocytes T du receveur. Pour y remédier, on peut utiliser des immunosuppresseurs qui musèlent le système immunitaire. Mais c'est surtout la recherche d'une <a href="http://biblio.hmr.qc.ca/ciup/Publications_pdf/T/typage_hla_onc011.pdf">compatibilité HLA</a> qui est systématiquement recherchée lors d'une greffe. Plus les allèles sont proches et moins le rejet sera sévère. On cherche donc à typer le profil HLA du donneur et du greffé. On fait appel à une nomenclature internationale définie sur <a href="http://hla.alleles.org/">hla.alleles.org</a> et qui donne un identifiant pour chaque gène HLA. La figure suivante identifie un allèle pour le gène HLA-A. </p>
<p align="center">
<img src="../images/post14/nomenclature.png">
</p>
<h2>Conclusion</h2>
<p>J'espère que vous avez un peu compris, même partiellement en lisant cet article. L'immunologie est une discipline assez complexe, et il m'est difficile de tout résumer en quelques lignes. <br>
Retenez que chaque cellule dispose d'une empreinte composée de peptides et de molécules HLA. Toute modification soit du peptide ( virus ), soit du HLA ( greffe) est reconnu comme étrangère et entraîne l'activation du système immunitaire. L'homologie avec les systèmes de sécurités informatiques est flagrante. Et je pense que les ingénieurs ont tout à gagner à s'inspirer du meilleur système de défense biologique de la planète! </p>
<h2>Références</h2>
<ul>
<li><a href="http://www.assim.refer.org/raisil/raisil/L02_files/page82-4.-complexe-majeur-d0027histocompatibilite.pdf">Le complexe majeur d'histocompatibilité</a></li>
<li><a href="http://nfs.unipv.it/nfs/minf/dispense/immunology/lectures/files/loci_abs_tcr_mhc.html">The antibody, T cell receptor and MHC loci</a></li>
<li><a href="http://hla.alleles.org/">HLA nomenclature</a></li>
<li><a href="http://biblio.hmr.qc.ca/ciup/Publications_pdf/T/typage_hla_onc011.pdf">Typage HLA pour tous</a></li>
</ul>
<h2>Remerciement</h2>
<p><a href="https://github.com/pausrrls">@pausrrls</a></p>Les empreintes génétiques2016-02-07T13:20:34+01:002016-02-07T13:20:34+01:00Sacha Schutztag:dridk.me,2016-02-07:/empreinte_genetique.html<p>Envie d'identifier le criminel qui vous a volé au boulot votre bic 4 couleurs en votre absence ? Dans ce cas, cet article est fait pour vous ! Dans ce billet nous allons voir comment, à l'aide des séquences répétées dans le génome humain, il est possible d'identifier une personne en lui …</p><p>Envie d'identifier le criminel qui vous a volé au boulot votre bic 4 couleurs en votre absence ? Dans ce cas, cet article est fait pour vous ! Dans ce billet nous allons voir comment, à l'aide des séquences répétées dans le génome humain, il est possible d'identifier une personne en lui attribuant un « code-barres génétique ». <br>
On se met tout de suite la <a href="https://www.youtube.com/watch?v=gY5rztWa1TM">musique des experts Manhatthan</a> et on commence ! </p>
<h1>Les séquences répétées</h1>
<p>10 % du génome humain est constitué de séquences d'ADN répétées en tandem. Il s'agit de séquences plus ou moins longues, appelées « <strong>noyaux</strong> », « <strong>motifs</strong> » ou encore « <strong>unités de répétition</strong> » (ex : GAAA), et se répètent successivement un certain nombre de fois (ex : GAAAGAAAGAAAGAAAGAAA). </p>
<p align="center">
<img src="../images/post13/satellite.png">
</p>
<p>Ces séquences répétées sont présentes partout dans le génome, principalement dans les <a href="https://fr.wikipedia.org/wiki/T%C3%A9lom%C3%A8re">télomères</a> et les <a href="https://fr.wikipedia.org/wiki/Centrom%C3%A8re">centromères</a>. Parfois, ces séquences se trouvent à proximité de gènes codants et une modification du nombre de répétitions peut alors entraîner des répercussions cliniques. L'exemple type est la <a href="https://fr.wikipedia.org/wiki/Maladie_de_Huntington">maladie de Huntington</a>. Cette atteinte neurodégénérative héréditaire est caractérisée par une expansion de triplets CAG supérieure à 30 dans le gène HTT de l'<a href="https://fr.wikipedia.org/wiki/Huntingtine">huntingtine</a>.<br>
On distingue 2 types de séquences répétées en fonction de la taille du motif. Les <a href="https://fr.wikipedia.org/wiki/Minisatellite">minisatellites</a> ou VNTR (<em>Variable Number Tandem Repeat</em>) contiennent un motif de 9 à 80 bases et les <a href="https://fr.wikipedia.org/wiki/Microsatellite_%28biologie%29">microsatellites</a> ou STR (<em>Short Tandem Repeat</em>) un motif de 2 à 5 bases. Ce sont ces dernières qui sont utilisées pour l'identification des personnes par empreinte génétique.</p>
<h1>Le polymorphisme</h1>
<p>La variation du nombre de répétitions varie fortement dans la population. Par exemple, pour une position génomique donnée, un individu (bleu) pourrait avoir sur son chromosome paternel la répétition (CG)<sub>6</sub> et sur son chromosome maternel la répétition (CG)<sub>8</sub>. Un autre individu (rouge) pourrait porter sur ses chromosomes les allèles (CG)<sub>6</sub> et (CG)<sub>9</sub>.</p>
<p align="center">
<img src="../images/post13/satellite_poly.png">
</p>
<p>L'identification de plusieurs régions répétées au sein du génome permet d'associer à un individu une combinaison unique. Une palette de 13 loci + 2 loci (oui, un locus... des loci) sur les chromosomes sexuels est aujourd'hui utilisée par la police scientifique pour identifier n'importe quel individu. Le caryotype ci-dessous montre la position et le nom de ces STR sur les chromosomes.</p>
<p align="center">
<img src="../images/post13/codis.jpg">
</p>
<h1>Identification des STR</h1>
<p>Pour créer une empreinte génétique, il suffit tout simplement de mesurer la taille de ces 13 régions répétées en les amplifiant par <a href="https://fr.wikipedia.org/wiki/PCR">PCR</a>. Pour cela, pour chaque STR, on utilise un couple d'amorces flanquant le STR en question. Une des deux amorces est couplée à un fluorochrome qui permet ensuite l'identification de la séquence par <a href="https://fr.wikipedia.org/wiki/%C3%89lectrophor%C3%A8se_capillaire">électrophorèse capillaire</a>. Les séquences des amorces sont disponibles <a href="http://www.cstl.nist.gov/biotech/strbase/multiplx.htm">ici</a>.</p>
<p align="center">
<img src="../images/post13/PCR_multiplexe.png">
</p>
<p>À la fin de la PCR, on obtient des <a href="https://fr.wikipedia.org/wiki/Amplicon">amplicons</a> dont la taille est proportionnelle à celle du STR. Une <a href="https://cmgg.be/fr/content/analyse-de-fragments">analyse de fragments</a> est ensuite réalisée à l'aide d'un séquenceur capillaire. En d'autres termes, les amplicons migrent dans un capillaire plus ou moins vite et leur temps de passage est mesuré lors de la détection du fluorochrome par un laser. Les résultats sont représentés par des pics de fluorescence dont la position sur l'axe des abscisses correspond à la taille du STR. <br>
Prenons par exemple un individu homozygote pour le locus <a href="http://www.sciencedirect.com/science/article/pii/S0531513103017746">vWA</a>. À ce locus, cet individu possède 4 répétitions TCTG à la fois sur le chromosome maternel et sur le chromosome paternel. Son génotype pourrait s'écrire : (TCTG)<sub>4</sub> / (TCTG)<sub>4</sub>. Dans ce cas, la PCR amplifie des amplicons tous de la même taille et un seul pic est détecté avec l'analyse de fragments. </p>
<p align="center">
<img src="../images/post13/homozygote.png">
</p>
<p>En revanche, si le patient est hétérozygote avec le génotype suivant : (TCTG)<sub>4</sub> / (TCTG)<sub>5</sub>, on observe 2 pics et une diminution des amplitudes. </p>
<p align="center">
<img src="../images/post13/heterozygote.png">
</p>
<p>Pour créer une empreinte génétique, il suffit de refaire la même chose pour les 13 loci. On fait une <a href="http://www.ozyme.fr/documentation/techozyme/techozyme20-pcr-multiplexe.asp">PCR multiplexe</a> en mélangeant tous les couples d'amorces et en discriminant chaque locus à l'aide de 4 fluorochromes différents ainsi que par des tailles de STR différentes. En traçant l'ensemble des pics, on obtient l'empreinte génétique. La probabilité que deux individus (non jumeaux) aient le même profil est extrêmement faible, de l'ordre de 10<sup>-10</sup>. <br>
Voici le profil d'un individu que j'ai trouvé sur Google !</p>
<p align="center">
<img src="../images/post13/fingerprint.jpg">
</p>
<p>On retrouve nos 13 loci ainsi que 2 loci sur les chromosomes sexuels XY, qui nous informent sur le sexe. Sur la première ligne en bleu, on peut observer 3 loci (TPOX, FGA et vWA). L'individu est hétérozygote pour le premier locus avec 2 allèles présentant 14 et 15 répétitions respectivement ; puis un deuxième locus également hétérozygote (18/20) et enfin un troisième locus, cette fois homozygote avec 24 répétitions.
Vous pouvez refaire la même chose pour les autres loci et avoir le profil complet de cette empreinte génétique. <br>
Notons également, que chaque allèle observé provient d'un des parents. Par exemple pour le premier locus (14/15), l'allèle 14 peut provenir de la mère et l'allèle 15 du père. En recherchant les empreintes génétiques chez les parents, nous pourrions confirmer le lien de filiation. </p>
<h1>Conclusion</h1>
<p>Voilà, vous savez faire une empreinte génétique. Vous allez maintenant pouvoir la comparer avec une banque de données. C'est aux États-Unis en 1994 que la première banque de données d'empreintes génétiques a été créée sous l'égide du FBI, sous le label <a href="https://fr.wikipedia.org/wiki/Combined_DNA_index_system">CODIS</a>. En France, suite à l'affaire du tueur parisien <a href="https://fr.wikipedia.org/wiki/Guy_Georges">Guy Georges</a>, la loi du 17 juin 1998 acte la création du fichier national (<a href="https://fr.wikipedia.org/wiki/Fichier_national_automatis%C3%A9_des_empreintes_g%C3%A9n%C3%A9tiques">FNAEG</a>). Il recense aujourd'hui 2 655 381 personnes. </p>
<h2>Références</h2>
<ul>
<li><a href="http://www.cstl.nist.gov/biotech/strbase/intro.htm">Brief Introduction to STRs</a></li>
<li><a href="http://www.cstl.nist.gov/biotech/strbase/multiplx.htm">Les kits commerciaux</a></li>
<li><a href="http://www.cstl.nist.gov/biotech/strbase/primer1.htm">Liste des amorces</a></li>
<li><a href="http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2585748/">The rarity of DNA profiles</a></li>
<li><a href="https://www.youtube.com/watch?v=43-OQTLtrwQ">Pour mieux comprendre l'analyse de fragments</a></li>
</ul>
<h2>Remerciement</h2>
<ul>
<li>@Piplopp </li>
<li>@Oodnadatta </li>
</ul>Un message immortel ...2016-01-25T17:00:00+01:002016-01-25T17:00:00+01:00Sacha Schutztag:dridk.me,2016-01-25:/message_immortel.html<p>Imaginez que vous vouliez transmettre un message à votre arrière arrière arrière petit-fils, à l'instar du Professeur Brown dans <a href="https://fr.wikipedia.org/wiki/Retour_vers_le_futur_2">Retour vers le futur 2</a>. Quelles solutions envisagez-vous ? Une enveloppe en papier? Aucune chance, risque de perte ou de dégradation, ça ne marche que dans les films.
Un Fichier numérique ? Vous …</p><p>Imaginez que vous vouliez transmettre un message à votre arrière arrière arrière petit-fils, à l'instar du Professeur Brown dans <a href="https://fr.wikipedia.org/wiki/Retour_vers_le_futur_2">Retour vers le futur 2</a>. Quelles solutions envisagez-vous ? Une enveloppe en papier? Aucune chance, risque de perte ou de dégradation, ça ne marche que dans les films.
Un Fichier numérique ? Vous voulez dire comme les photos numériques que nous avons tous perdu? C'est malheureusement encore moins fiable qu'une enveloppe. <br>
Aujourd'hui, je vous propose mieux: écrire votre message dans votre ADN, et le laisser traverser le temps jusqu'à votre descendance! La réception est garantie à 100% !</p>
<h1>De 10 doigts à 4 doigts</h1>
<p>Pour écrire un nombre, nous utilisons les 10 symboles suivants [0,1,2,3,4,5,6,7,8,9]. On appelle ça <a href="https://fr.wikipedia.org/wiki/Syst%C3%A8me_de_num%C3%A9ration">un système de numération</a> en base 10. Mais il est tout à fait possible d'utiliser plus ou moins de symboles. Par exemple, un ordinateur en utilise uniquement 2 ([1 et 0]), le nombre 3 en décimal s'écrit 11 en base 2, on appelle ça du binaire. Il existe d'autres systèmes de numération utilisés, comme l’<a href="https://fr.wikipedia.org/wiki/Syst%C3%A8me_hexad%C3%A9cimal">hexadécimal</a> 16 symboles [0,1,2,3,4,5,6,7,8,9,A,B,C,D,E] ou encore la <a href="https://fr.wikipedia.org/wiki/Base64">base64</a> [caractère alphanumérique]. <br>
L'ADN est un support d'information numérique, au même titre qu'un disque dur ou qu'une clef USB. Sauf qu'au lieu d'utiliser du binaire, l'ADN utilise un système en base 4 à l'aide des symboles A,C,G,T. Il est donc tout à fait possible de basculer d'un système décimal vers un système de numération en base 4 et d'utiliser l'ADN comme support de l'information.</p>
<h1>l'ASCII génomique</h1>
<p>Pour écrire un message on peut utiliser la <a href="https://fr.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange#Table_des_128_caract.C3.A8res_ASCII">table ASCII</a>. Celle-ci attribue à chaque lettre un nombre qui peut s'écrire en décimal, binaire, hexadécimal ... et en génomique, c'est-à-dire en base 4. <br>
J'ai utilisé la librarie <a href="https://pypi.python.org/pypi/python-baseconv/1.1.3">python-baseconv</a> pour faire les conversions entre les différents systèmes de numération. Par exemple, la lettre Z s'écrit 90 en décimal, 5A en hexadécimal, 1011010 en binaire et enfin CCGG en génomique.
A partir de là, il suffit pour un message donné, de remplacer chaque lettre par sa représentation génomique et obtenir la séquence de nucléotide que nous allons intégrer dans votre génome! <br>
Je vous ai fait un script JS pour que vous pussiez tester directement en ligne ! Cliquer sur <em>Décoder</em> pour convertir la séquence en texte. Vous pouvez aussi encoder du texte en séquence en cliquant sur <em>Encoder</em>. Attention, n'utilisez que des lettres de l'alphabet ! Pas de nombre ni de caractère spéciaux! </p>
<h2>ASCII genomic convertor</h2>
<form>
<textarea id="area" rows="4" cols="50">CAGGCGCCCCTTCTATCTCCCGGCCTATCCTTCTCACGTTCGTGCCTTCGACCGTGCGATTGGGCTCACTAGCGCCCCTTCGCCCTCACCTTCGGGCGCCCCTTCGTGCGACCGGCCCTTCTAGCGGCCGCCCGTGCCTTTGAACCTTCTCACGCCCCTTCGCACGGCCTAGCGCCCCTTCGCACGCCCCTTCTAACGTACTCCCTAT
</textarea> <br/>
<input type="button" value="encoder" onClick="start_encode()">
<input type="button" value="decoder" onClick="start_decode()">
<script>
function start_encode()
{
var textArea = document.getElementById("area");
// On remplace les caracteres space, car ils s'encode sur 3 et pas 4 symboles
textArea.value = encode(textArea.value.replace(/\s/g,"_"));
}
function start_decode()
{
var textArea = document.getElementById("area");
textArea.value = decode(textArea.value).replace(/_/g," ");
}
function encode(txt){
var code = ['A','C','G','T'];
var output = "";
for (var i in txt)
{
var raw = txt[i].charCodeAt(0).toString(4);
acgt = raw.replace(/0|1|2|3/g, function lambda(x){return code[x];});
output+=acgt;
}
return output;
}
//===========================================================================
function decode(txt){
var code = {'A':0,'C':1,'G':2,'T':3};
var output = "";
for (var i=0; i<txt.length; i+=4)
{
acgt = txt.substring(i,i+4);
bases = acgt.replace(/A|C|G|T/g, function lambda(x){return code[x];});
output+=String.fromCharCode(parseInt(bases,4));
}
return output;
}
</script>
</form>
<h1>Copier, Couper, Coller</h1>
<p>Nous avons la séquence. Comment l'insérer dans notre ADN ? Bon on ne va pas l'insérer dans toutes vos cellules, car uniquement les spermatozoïdes/ovocytes vont transmettre l'information à votre descendance. On aurait pu partir sur une stratégie de transfection virale. C'est-à-dire utiliser un virus dans lequel votre message est inséré, et infecter vos cellules germinales. Sur ce coup, je pense que ça va être difficile de trouver le virus! Peut être le virus ourlien qui provoque les oreillons et qui touche les testicules, mais pas sûr...
Je vous propose plutôt d'utiliser le tout dernier outil de biotechnologie, qui aboutira sûrement au prochain prix Nobel français, je parle bien sur du complexe enzymatique <a href="https://fr.wikipedia.org/wiki/Cas9">CRISPR-CAS9</a>, le couteau suisse de l'ADN. Ce complexe est capable de découper l'ADN à un endroit précis et d'y insérer n'importe quelle séquence d'ADN. C'est un outil assez révolutionnaire, un article entier y sera bientôt consacré. Contentez vous de cette vidéo pour l'instant:</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/2pp17E4E-O8" frameborder="0" allowfullscreen></iframe>
<p>Pour modifier nos spermatozoïdes, nous pourrions d'abord faire une biopsie testiculaire, extraire les cellules souches (spermatogonies) et insérer le message dans leurs ADN à l'aide de CRISPR-CAS9, comme l'illustre <a href="http://www.ncbi.nlm.nih.gov/pubmed/25772367">cet article</a> avec un premier succès chez le rat. Enfin, ces spermatogonies pourront être mis en culture pour devenir des spermatozoïdes compétents, grâce au succès récent d'<a href="http://www.cell.com/cell-stem-cell/abstract/S1934-5909%2812%2900587-5">une équipe française</a> qui a réussi la culture des spermatogonies. <br>
Voila, Il ne reste plus qu'à réaliser une fécondation in-vitro, et votre enfant disposera du message dans toutes ses cellules y compris dans ses spermatoizoïdes. A la prochaine génération, la moitié de son génome se diluera avec le génome de sa compagne ( votre belle-fille). Vous avez donc intérêt à dupliquer le message un peu partout sur son génome. Par exemple, en insérant le message sur le chromosome Y, vous êtes certain que votre arrière arrière arrière petit-fils héritera du message car le chromosome Y se transmet de père à fils.<br>
De même si vous arrivez à modifier l'ADN mitonchondriale d'un ovocyte chez votre compagne, c'est votre descendance féminine qui heritera du message. </p>
<h1>Et les mutations ?</h1>
<p>Bon on a oublié de prendre en compte les mutations. Plus on descend dans les générations, plus grand sera le risque de mutation. Par exemple des <a href="https://fr.wikipedia.org/wiki/Enjambement_%28g%C3%A9n%C3%A9tique%29">crossing-over</a>.ou des mutations ponctuelles.
En augmentant le nombre de messages, votre descendant pourra retrouver le message originel en faisant des alignements multiples entre tous les séquences. Mais bon, d'ici que le message ait disparu complètement, il faudra un certain temps! Je vais me pencher sur ce calcul d’ailleurs!</p>
<h1>Conclusion</h1>
<p>Bon, j'ai un peu déliré dans ce poste. Mais pourtant, derrière cette histoire se cache une réalité qui à le goût de <a href="https://fr.wikipedia.org/wiki/Bienvenue_%C3%A0_Gattaca">Bienvenue à Gattaca</a>. En effet, on peut ajouter un message, mais pourquoi pas modifier vos gènes. Supprimez toutes les maladies génétiques jusqu'à garder uniquement les grands bruns au yeux bleus. Une équipe chinoise a d'ailleurs franchi le pas en modifiant des <a href="http://www.ncbi.nlm.nih.gov/pubmed/25894090">embryons humains</a>. Nous ne sommes pas encore au niveau de ce film mais la technologie semble disponible! Gardez juste à l'esprit que l'<a href="https://fr.wikipedia.org/wiki/Eug%C3%A9nisme">eugénisme</a> en diminuant la variabilité des individus est un puissant frein à l'évolution du vivant...</p>
<h2>Référence</h2>
<ul>
<li><a href="https://pypi.python.org/pypi/python-baseconv/1.1.3">python-baseconv</a></li>
<li><a href="http://www.cell.com/cell-stem-cell/abstract/S1934-5909%2812%2900587-5">Stem Cell Therapy for Male Infertility Takes a Step Forward</a></li>
<li><a href="http://www.ncbi.nlm.nih.gov/pubmed/25772367">Targeted Germline Modifications in Rats Using CRISPR/Cas9 and Spermatogonial Stem Cells.</a></li>
<li><a href="http://www.nature.com/nmeth/journal/v10/n10/full/nmeth.2649.html">Cas9 as a versatile tool for engineering biology</a></li>
<li><a href="http://www.nature.com/news/chinese-scientists-genetically-modify-human-embryos-1.17378">Chine scientists genetically modify human embryos</a></li>
</ul>
<h2>Remerciement</h2>
<p>Merci à @Piplopp pour les corrections </p>Le filtre de bloom2016-01-16T17:00:00+01:002016-01-16T17:00:00+01:00Sacha Schutztag:dridk.me,2016-01-16:/bloom-filter.html<p>Un filtre de bloom est une structure de donnée permettant de savoir si un élément est présent ou non dans une liste. Cette structure est très efficace d'un point de vue mémoire lorsque vous travaillez sur de grande liste. En python, l'utilisation d'un filtre de Bloom peut s'écrire : </p>
<div class="highlight"><pre><span></span><code><span class="n">L</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"mario …</span></code></pre></div><p>Un filtre de bloom est une structure de donnée permettant de savoir si un élément est présent ou non dans une liste. Cette structure est très efficace d'un point de vue mémoire lorsque vous travaillez sur de grande liste. En python, l'utilisation d'un filtre de Bloom peut s'écrire : </p>
<div class="highlight"><pre><span></span><code><span class="n">L</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"mario"</span><span class="p">,</span><span class="s2">"zelda"</span><span class="p">,</span><span class="s2">"daisy"</span><span class="p">]</span>
<span class="n">has_item</span><span class="p">(</span><span class="n">L</span><span class="p">,</span><span class="s2">"sonic"</span><span class="p">)</span> <span class="c1"># Return False </span>
<span class="n">has_item</span><span class="p">(</span><span class="n">L</span><span class="p">,</span><span class="s2">"mario"</span><span class="p">)</span> <span class="c1"># Return True</span>
</code></pre></div>
<p>Le revers de la médaille, c'est qu'avec cette méthode il existe des faux positifs, c'est à dire que la fonction renvoie Vrai alors que le mot n'est pas dans la liste... Inutile vous me direz ? Non, car dans certain cas, on se fiche des faux positifs. Par exemple, on peut être amené à savoir si un mot est bien absent de la liste. Et dans ce cas, c'est tout à fait possible avec les filtres de Bloom, car il n'y a pas de faux négatifs!<br>
Dans d'autre cas, notamment dans l'analyse des <a href="https://fr.wikipedia.org/wiki/Big_data">Big data</a>, les performances d'un algorithme sont prioritaires au risque de faux positifs. On pourra alors paramétrer l'algorithme de façon à minimiser le nombre de faux positifs. </p>
<h1>Fonction de hachage</h1>
<p>Les filtres de Bloom utilisent des fonctions de hachage. Une <a href="https://fr.wikipedia.org/wiki/Fonction_de_hachage">fonction de hachage</a> est une fonction qui, à partir d'une entrée renvoie une "<em>empreinte</em>" ou encore une "<em>signature</em>" permettant d’identifier l'entrée. Les fonctions de hachage sont utilisées dans de nombreux cas, notamment en cryptographie ou dans les structures de données de type <a href="http://jipe.developpez.com/articles/algo/table-hachage/?page=page_1">dictionnaire</a>.<br>
Dans le cas des filtres de Bloom, une fonction de hachage renvoie un unique entier compris entre <strong>0 et n</strong>, choisi de façon uniforme. On peut créer autant de fonction de hachage qu'on le désire.</p>
<div class="highlight"><pre><span></span><code><span class="c1"># Une fonction de hachage </span>
<span class="n">hash1</span><span class="p">(</span><span class="s2">"mario"</span><span class="p">)</span> <span class="c1"># Return 3</span>
<span class="n">hash1</span><span class="p">(</span><span class="s2">"zelda"</span><span class="p">)</span> <span class="c1"># Return 4</span>
<span class="n">hash1</span><span class="p">(</span><span class="s2">"daisy"</span><span class="p">)</span> <span class="c1"># Return 3 .. Collision</span>
<span class="c1"># Une autre fonction de hachage</span>
<span class="n">hash2</span><span class="p">(</span><span class="s2">"mario"</span><span class="p">)</span> <span class="c1"># Return 7</span>
<span class="n">hash2</span><span class="p">(</span><span class="s2">"zelda"</span><span class="p">)</span> <span class="c1"># Return 5</span>
<span class="n">hash2</span><span class="p">(</span><span class="s2">"zelda"</span><span class="p">)</span> <span class="c1"># Return 3</span>
<span class="c1"># Encore une autre ... </span>
<span class="n">hash3</span><span class="p">(</span><span class="s2">"mario"</span><span class="p">)</span> <span class="c1"># Return 54</span>
</code></pre></div>
<p>Attention tout de même! Avec des fonctions de hachage il peut se produire des collisions, c'est-à-dire que pour deux entrées différentes il y a un même hash. En jouant avant la taille de <strong>n</strong> et connaissant les entrées, on peut minimiser la probabilité de collision.</p>
<h1>Utilisation du filtre de bloom</h1>
<p>L’utilisation d'un filtre de Bloom comprend 2 étapes. La première consiste à hacher tous les éléments de notre liste et les "<em>installer</em>" dans un vecteur booléen de taille <strong>n</strong> en utilisant <strong>k</strong> fonctions de hachage différentes. <br>
La deuxième, teste la présence d'un élément en recherchant son hash dans ce vecteur booléen . </p>
<h2>Création du vecteur booléen</h2>
<p>Choisissons pour l'exemple, un vecteur de taille <strong>n=10</strong>, et initialisons le avec des zéros. Puis choissons <strong>k=3</strong> fonctions de hachages différentes, que nous notons <strong>h0</strong>,<strong>h1</strong> et <strong>h2</strong>. Les hashs obtenus correspondent à une position dans le vecteur. Les valeurs possibles des hashs doivent être alors comprises entre <strong>0</strong> et <strong>9</strong>. </p>
<p align="center">
<img src="../images/post11/empty_hash.png">
</p>
<p>Enfin, commençons par <em>installer</em> notre liste, avec le première élément "<em>mario</em>", comme l'illustre la figure suivante : </p>
<p align="center">
<img src="../images/post11/mario_hash.png">
</p>
<p>Ajoutons maintenant le mot "<em>zelda</em>" : </p>
<p align="center">
<img src="../images/post11/zelda_hash.png">
</p>
<p>Avec le mot "<em>zelda</em>", il y a eu collision avec la fonction de hashage <strong>h2</strong>. C'est ce qui est l'origine des faux positifs. </p>
<h2>Test de présence</h2>
<p>Si vous avez compris jusque là, vous devriez comprendre comment tester la présence du mot "<em>sonic</em>". Si le mot a été "<em>installé</em>" , alors nous devrions retrouver tous les hashs obtenus par les 3 fonctions de hachages sur le mot "<em>sonic</em>". Ce qui n'est pas le cas ici, comme l'illustre la figure suivante. Le mot <em>sonic</em> n'est pas présent dans la liste.</p>
<p align="center">
<img src="../images/post11/sonic_hash.png">
</p>
<h1>Estimation des faux positifs</h1>
<p>Avec cette algorithme, il n'y a jamais de faux négatifs, mais des faux positifs. C'est-à-dire le fait de répondre qu'un élément est présent alors que non. <br>
Pour compenser ce problème, nous pouvons créer le filtre de façon à minimiser le nombre de faux positifs via les 3 paramètres suivants : </p>
<ul>
<li><strong>n</strong> = La taille du vecteur booléen (10)</li>
<li><strong>m</strong> = Le nombre d'élément d'une liste (3)</li>
<li><strong>k</strong> = Le nombre de fonction de hachage (3)</li>
</ul>
<p>Considérons une position <strong>j</strong> dans notre vecteur. La probabilité qu'une fonction de hachage fasse passer la valeur de <strong>j</strong> de 0 à 1 est de $\frac{1}{n}$. L'inverse, c'est-à-dire la probabilité que la valeur de <strong>j</strong> ne change pas, est donc de $1-\frac{1}{n}$. <br>
Après avoir rempli le vecteur booléen, avec <strong>m</strong> élément et <strong>k</strong> fonction de hachage, la probabilité de ne pas changer <strong>j</strong> est donc de $(1-\frac{1}{n})^{km}$. <br>
Cette équation peut se réduire en considérant l'égalité approximative suivante: </p>
<p>$(1-\frac{1}{n})^n\approx \frac{1}{e} = e^{-1}$</p>
<p>L'équation précédente peut se réduire alors : </p>
<p>$(1-\frac{1}{n})^{km} \approx e^{\frac{-km}{n}}$</p>
<p>Au final, la probabilité d'avoir des faux positifs équivaut à la probabilité d'avoir toutes les positions du vecteur booléen à 1, pour les <strong>k</strong> fonctions de hachage. On obtient ainsi la formule finale suivante : </p>
<p>$P_{faux-positif} = ( 1 - e^{\frac{-km}{n}})^k$</p>
<h1>Application</h1>
<p>Sachant que nous avons une liste de <strong>m</strong> élément, quelles sont les valeurs de <strong>k</strong> et <strong>n</strong> que nous pouvons choisir pour atteindre une probabilité <strong>p</strong> de faux positifs ? En faisant un peu d'algèbre, la meilleure valeur de <strong>k</strong> est : k = $ln(2)\frac{n}{m}$ <br>
Et le rapport suivant doit être satisfait: $\frac{n}{m} = 0.7ln(\frac{1}{p})$. </p>
<p>Par exemple, pour atteindre une probabilité $p<\frac{1}{1000}$, il suffit de choisir $\frac{n}{m} > 0.7ln(1000) \approx 7$. Avec <strong>m</strong> = 1000 éléments on choisira donc <strong>n</strong> = 7000 et <strong>k</strong> = 5. <br>
Pour plus d'information sur la démonstration mathématique, regardez la <a href="https://www.youtube.com/watch?v=bEmBh1HtYrw">vidéo youtube</a> en référence. </p>
<h1>Conclusion</h1>
<p>Avec toutes ces explications, vous pouvez je pense, réaliser votre propre filtre de Bloom. Utiliser la <a href="https://pypi.python.org/pypi/cityhash">librairie cityhash</a> pour les fonctions de hachage, ça devrait marcher. Mais si vous avez la flemme, j'ai vu qu'il existait une librairie toute faite <a href="https://pypi.python.org/pypi/pybloom/1.0.2">pybloom</a>. L'article sur le blog de <a href="http://www.maxburstein.com/blog/creating-a-simple-bloom-filter/">Max Burstein</a> est plus orienté code et explique pas à pas la création en python d'une class <em>BloomFilter</em>. <br>
Enfin, pour les bioinformaticiens, je vous invite à lire cette article : <a href="http://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-12-333">Efficient counting of k-mers in DNA sequences using a bloom filter</a>.</p>
<h2>Référence</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=bEmBh1HtYrw">Youtube Bloom Filter (anglais)</a></li>
<li><a href="http://bioinfo-fr.net/filtre-de-bloom">bioinfo-fr</a></li>
<li><a href="http://www.maxburstein.com/blog/creating-a-simple-bloom-filter/">Create a simple bloom filter</a></li>
<li><a href="http://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-12-333">Efficient counting of k-mers in DNA sequences using a bloom filter</a>.</li>
</ul>La transformation de Burrows-Wheeler2015-10-24T15:37:04+02:002015-10-24T15:37:04+02:00Sacha Schutztag:dridk.me,2015-10-24:/bwt.html<p>Au temps ou le téléphone portable était un objet de luxe et de démesure, la seule façon d'envoyer un message pendant un cours de philosophie, était d'utiliser un petit bout de papier que l'on faisait passer d'élève à élève. Il fallait écrire en petit pour maximiser la quantité d'information transmis …</p><p>Au temps ou le téléphone portable était un objet de luxe et de démesure, la seule façon d'envoyer un message pendant un cours de philosophie, était d'utiliser un petit bout de papier que l'on faisait passer d'élève à élève. Il fallait écrire en petit pour maximiser la quantité d'information transmis lors d'un envoi. De plus, pour éviter toute interception du message par le professeur certains avaient recours à des cryptages plus ou moins efficaces. A cette époque, ou je programmais sur calculette <a href="https://fr.wikipedia.org/wiki/TI-82">Ti-82</a> pendant mes cours de philo, j'aurais aimé connaître l'algorithme de la transformation de <strong>Burrows-Wheeler</strong>. J'aurai pu économiser encre et papier en compressant l'information de mes messages, mais surtout je me serais éclaté à coder un encodeur/décodeur de petits mots sur ma calculette. <br>
En effet, cette algorithme est utilisé dans 2 cas particuliers. La compression que nous allons aborder dans cette article, mais aussi l'indexation utilisée dans la recherche de motif textuel. Ce dernier point fera l'objet d'un prochain article. </p>
<h1>Compression du texte</h1>
<p>Une technique de compression appelée <a href="https://fr.wikipedia.org/wiki/Run-length_encoding">codage par plages</a>, souvent utilisée dans la compression d'image, consiste à remplacer des répétitions par le nombre d'occurrence de cette répétition. Par exemple, on peut remplacer la suite de pixel suivant : </p>
<div class="highlight"><pre><span></span><code>jaune-jaune-jaune-jaune-jaune-rouge
</code></pre></div>
<p>par : </p>
<div class="highlight"><pre><span></span><code><span class="mf">5</span><span class="n">jaune</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">rouge</span><span class="w"></span>
</code></pre></div>
<p>On peut appliquer cette méthode sur une chaîne de caractère. C'est à dire en remplaçant les répétitions de lettres consécutives par leurs nombres d’occurrences. Par exemple, avec le mot "<em>anticonstitutionnellement</em>" On obtient : </p>
<div class="highlight"><pre><span></span><code><span class="n">anticonstitutio2ne2lement</span><span class="w"></span>
</code></pre></div>
<p>Pas très efficace n'est ce pas ? En effet, remplacer 2 lettres par 1 chiffre + 1 lettre, ne diminue pas la longueur du message. il faudrait des répétitions de 3 lettres au minimum pour être compressible, et c'est rarement le cas dans un texte. C'est ici qu'intervient l'algorithme de <strong>Burrows-Wheeler</strong>. Il s'agit d'une transformation réversible d'une chaîne de caractère vers une autre ayant la propriété d'avoir des lettres identiques contiguës. Il est alors possible de compresser cette chaîne plus efficacement.</p>
<h1>Transformation de Burrows-Wheeler</h1>
<p>Dans ce qui suit, nous allons faire la transformation de <strong>Burrows-Wheeler</strong> en utilisant le mot "<em>banane</em>". <br>
Tout d'abord, rajoutons le caractère "<strong>$</strong>" à la fin du mot: <em>banane$</em>. Lorsque l'on range des lettres dans l'ordre lexicographique, le "<strong>$</strong>" se situe avant la lettre "<strong>A</strong>", de la même façon que le "<strong>B</strong>" se trouve avant le "<strong>C</strong>". Ce caractère nous servira de repère par la suite. <br>
Puis, nous allons créer la matrice suivante en décalant chaque ligne d'une lettre, en faisant une sorte de rotation (Figure ci dessous). La matrice obtenue est de taille L x L ou L est la longueur du mot. </p>
<p align="center">
<img src="../images/post10/matrix.png">
</p>
<p>Une fois la matrice construite, nous ordonnons les lignes dans l'ordre lexicographique. Les lignes commençant par un "<strong>A</strong>" sont en haut, et ainsi de suite. Nous obtenous alors la matrice ci-dessous. La transformation de <strong>Burrows-Wheeler</strong> correspond à la dernière colonne. C'est aussi simple que ça.</p>
<p align="center">
<img src="../images/post10/matrix2.png">
</p>
<p>La transformation du mot "<em>banane</em>", donne "<em>ebn$naa</em>". Et comme vous pouvez le constater, certaines lettres identiques sont réunies.<br>
Bon, c'est pas très impressionnant avec le mot <em>banane</em>. Mais avec le mot <em>anticonstitutionnellement</em>, on obtient : <em>t$inlmtttleenooeaicnnnusit</em>. Et cette fois, on observe des répétitions de plus de 2 lettres, qui nous permet de compresser le mot de cette façon : </p>
<div class="highlight"><pre><span></span><code><span class="n">t</span><span class="o">$</span><span class="n">inlm3tl2en2oeaic3nusit</span><span class="w"> </span><span class="c1">#24 lettres</span><span class="w"></span>
<span class="n">anticonstitutio2ne2lement</span><span class="w"> </span><span class="c1">#25 lettres</span><span class="w"></span>
</code></pre></div>
<p>Toujours pas impressionné ? Essayons cette fois avec un extrait de <a href="https://fr.wikipedia.org/wiki/De_l'origine_des_esp%C3%A8ces">l'origine des espèces</a> : </p>
<h4>Texte original ( 1102 lettres )</h4>
<div class="highlight"><pre><span></span><code><span class="n">Let</span><span class="w"> </span><span class="n">it</span><span class="w"> </span><span class="n">also</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">borne</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">mind</span><span class="w"> </span><span class="n">how</span><span class="w"> </span><span class="n">infinitely</span><span class="w"> </span><span class="n">complex</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">close</span><span class="o">-</span><span class="n">fitting</span><span class="w"> </span><span class="n">are</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">mutual</span><span class="w"> </span><span class="n">relations</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">all</span><span class="w"> </span><span class="n">organic</span><span class="w"> </span><span class="n">beings</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">each</span><span class="w"> </span><span class="n">other</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">their</span><span class="w"> </span><span class="n">physical</span><span class="w"> </span><span class="n">conditions</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">life</span><span class="p">;</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">consequently</span><span class="w"> </span><span class="n">what</span><span class="w"> </span><span class="n">infinitely</span><span class="w"> </span><span class="n">varied</span><span class="w"> </span><span class="n">diversities</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">structure</span><span class="w"> </span><span class="n">might</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">use</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">each</span><span class="w"> </span><span class="n">being</span><span class="w"> </span><span class="n">under</span><span class="w"> </span><span class="n">changing</span><span class="w"> </span><span class="n">conditions</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">life</span><span class="o">.</span><span class="w"> </span><span class="n">Can</span><span class="w"> </span><span class="n">it</span><span class="p">,</span><span class="w"> </span><span class="n">then</span><span class="p">,</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">thought</span><span class="w"> </span><span class="n">improbable</span><span class="p">,</span><span class="w"> </span><span class="n">seeing</span><span class="w"> </span><span class="n">that</span><span class="w"> </span><span class="n">variations</span><span class="w"> </span><span class="n">useful</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">man</span><span class="w"> </span><span class="n">have</span><span class="w"> </span><span class="n">undoubtedly</span><span class="w"> </span><span class="n">occurred</span><span class="p">,</span><span class="w"> </span><span class="n">that</span><span class="w"> </span><span class="n">other</span><span class="w"> </span><span class="n">variations</span><span class="w"> </span><span class="n">useful</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">some</span><span class="w"> </span><span class="n">way</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">each</span><span class="w"> </span><span class="n">being</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">great</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">complex</span><span class="w"> </span><span class="n">battle</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">life</span><span class="p">,</span><span class="w"> </span><span class="n">should</span><span class="w"> </span><span class="n">occur</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">course</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">many</span><span class="w"> </span><span class="n">successive</span><span class="w"> </span><span class="n">generations</span><span class="err">?</span><span class="w"> </span><span class="n">If</span><span class="w"> </span><span class="n">such</span><span class="w"> </span><span class="n">do</span><span class="w"> </span><span class="n">occur</span><span class="p">,</span><span class="w"> </span><span class="n">can</span><span class="w"> </span><span class="n">we</span><span class="w"> </span><span class="n">doubt</span><span class="w"> </span><span class="p">(</span><span class="n">remembering</span><span class="w"> </span><span class="n">that</span><span class="w"> </span><span class="n">many</span><span class="w"> </span><span class="n">more</span><span class="w"> </span><span class="n">individuals</span><span class="w"> </span><span class="n">are</span><span class="w"> </span><span class="n">born</span><span class="w"> </span><span class="n">than</span><span class="w"> </span><span class="n">can</span><span class="w"> </span><span class="n">possibly</span><span class="w"> </span><span class="n">survive</span><span class="p">)</span><span class="w"> </span><span class="n">that</span><span class="w"> </span><span class="n">individuals</span><span class="w"> </span><span class="n">having</span><span class="w"> </span><span class="n">any</span><span class="w"> </span><span class="n">advantage</span><span class="p">,</span><span class="w"> </span><span class="n">however</span><span class="w"> </span><span class="n">slight</span><span class="p">,</span><span class="w"> </span><span class="n">over</span><span class="w"> </span><span class="n">others</span><span class="p">,</span><span class="w"> </span><span class="n">would</span><span class="w"> </span><span class="n">have</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">best</span><span class="w"> </span><span class="n">chance</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">surviving</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">procreating</span><span class="w"> </span><span class="n">their</span><span class="w"> </span><span class="n">kind</span><span class="err">?</span><span class="w"> </span><span class="n">On</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">other</span><span class="w"> </span><span class="n">hand</span><span class="p">,</span><span class="w"> </span><span class="n">we</span><span class="w"> </span><span class="n">may</span><span class="w"> </span><span class="n">feel</span><span class="w"> </span><span class="n">sure</span><span class="w"> </span><span class="n">that</span><span class="w"> </span><span class="n">any</span><span class="w"> </span><span class="n">variation</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">least</span><span class="w"> </span><span class="n">degree</span><span class="w"> </span><span class="n">injurious</span><span class="w"> </span><span class="n">would</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">rigidly</span><span class="w"> </span><span class="n">destroyed</span><span class="o">.</span><span class="w"> </span><span class="n">This</span><span class="w"> </span><span class="n">preservation</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">favourable</span><span class="w"> </span><span class="n">individual</span><span class="w"> </span><span class="n">differences</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">variations</span><span class="p">,</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">destruction</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">those</span><span class="w"> </span><span class="n">which</span><span class="w"> </span><span class="n">are</span><span class="w"> </span><span class="n">injurious</span><span class="p">,</span><span class="w"> </span><span class="n">I</span><span class="w"> </span><span class="n">have</span><span class="w"> </span><span class="n">called</span><span class="w"> </span><span class="n">Natural</span><span class="w"> </span><span class="n">Selection</span><span class="p">,</span><span class="w"> </span><span class="ow">or</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">Survival</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">Fittest</span><span class="w"></span>
</code></pre></div>
<h4>Compression ( 893 lettres )</h4>
<div class="highlight"><pre><span></span><code><span class="mf">2</span><span class="n">t</span><span class="mf">.</span><span class="n">e</span><span class="p">,</span><span class="err">?</span><span class="n">d</span><span class="err">?</span><span class="n">le</span><span class="mf">.</span><span class="n">yftxt</span><span class="p">;</span><span class="n">g</span><span class="p">,</span><span class="n">rsgtshgxotd</span><span class="p">,</span><span class="mf">2</span><span class="n">hc4en</span><span class="p">,</span><span class="n">trdydgldetyeldhe3ofy2erIdnsd</span><span class="p">,</span><span class="n">telrgn2etwt2etnre3fotf2enyedoysne2sedselne</span><span class="p">,</span><span class="n">lhetr</span><span class="p">,</span><span class="n">rnsfle2</span><span class="p">,</span><span class="n">rnfyflyfne</span><span class="p">)</span><span class="n">g</span><span class="p">,</span><span class="n">gfrend2nengo</span><span class="p">,</span><span class="n">feyesldgef2syrtdyen</span><span class="p">,</span><span class="n">yes</span><span class="p">,</span><span class="w"> </span><span class="n">e2snrent2edtds2edesd4</span><span class="w"> </span><span class="err">$</span><span class="mf">5</span><span class="w"> </span><span class="n">rb3e</span><span class="w"> </span><span class="n">trcuvu</span><span class="w"> </span><span class="n">c2u</span><span class="w"> </span><span class="n">hmC2ch7</span><span class="w"> </span><span class="mf">2</span><span class="n">hgv</span><span class="w"> </span><span class="mf">2</span><span class="n">m4</span><span class="w"> </span><span class="mf">5</span><span class="n">v2e6heivl3irbN4hfmwo8</span><span class="w"> </span><span class="n">m</span><span class="w"> </span><span class="mf">2</span><span class="n">ai2</span><span class="w"> </span><span class="mf">2</span><span class="n">u2i3</span><span class="w"> </span><span class="n">u3o2nci2aua9</span><span class="w"> </span><span class="n">oueu3cel3nelnl4nenen</span><span class="w"> </span><span class="n">n3</span><span class="w"> </span><span class="mf">2</span><span class="n">n</span><span class="w"> </span><span class="mf">3</span><span class="n">nie2</span><span class="w"> </span><span class="n">n3ia3hrbv2hwvhnlrerhwrhlscbhbrvrbsvmsvglfs2f3</span><span class="w"> </span><span class="n">l2r2lirytrsf2sdbe2b2herS2tmrhrgushdh2vhnfbhvscirctb2dLw2l8oI4o</span><span class="w"> </span><span class="mf">3</span><span class="n">i</span><span class="w"> </span><span class="n">fi2n</span><span class="o">-</span><span class="mf">2</span><span class="n">e9nra</span><span class="w"> </span><span class="n">iu2in</span><span class="w"> </span><span class="n">en5ctc</span><span class="w"> </span><span class="n">c2tw3t4</span><span class="w"> </span><span class="mf">16</span><span class="n">twT2ts2</span><span class="w"> </span><span class="mf">3</span><span class="n">gp4rsnshg3vrt3ldmlr6</span><span class="w"> </span><span class="n">mk5</span><span class="w"> </span><span class="mf">2</span><span class="n">vtgeret2e2f2</span><span class="w"> </span><span class="mf">11</span><span class="n">t2r2eh2</span><span class="w"> </span><span class="mf">2</span><span class="n">ns2dFfvsv4dv2n</span><span class="w"> </span><span class="mf">3</span><span class="n">aualaeue3ubtb</span><span class="w"> </span><span class="n">el2p3</span><span class="w"> </span><span class="n">s2ac3ae2dbet4</span><span class="w"> </span><span class="n">eoe3</span><span class="w"> </span><span class="mf">2</span><span class="n">oi</span><span class="w"> </span><span class="mf">2</span><span class="n">aoai2oair3iOaeoae3ai5aiu2o3iure11iaia4i8oae4as4tdtr3</span><span class="w"> </span><span class="n">r12</span><span class="w"> </span><span class="n">s2c4i2c7ic</span><span class="w"> </span><span class="n">m</span><span class="w"> </span><span class="mf">2</span><span class="n">bhlp4</span><span class="w"> </span><span class="mf">2</span><span class="n">dh2whvc2i</span><span class="w"> </span><span class="mf">2</span><span class="n">hr</span><span class="w"> </span><span class="mf">2</span><span class="n">m2</span><span class="w"> </span><span class="n">m</span><span class="w"> </span><span class="mf">4</span><span class="n">euieieoe3ueaoa2uagcrg</span><span class="w"> </span><span class="p">(</span><span class="n">epo5a</span><span class="w"> </span><span class="n">e2u2o2ptueue2te3ue2l3neig2n2unrnru2o</span><span class="w"> </span><span class="mf">2</span><span class="n">une</span><span class="w"> </span><span class="n">syrs</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="n">o3ea2e6</span><span class="w"> </span><span class="n">sbi2ah2sh2ae3ahinb2it18</span><span class="w"> </span><span class="mf">4</span><span class="n">o2</span><span class="w"> </span><span class="n">it3a2ca2i4atn5</span><span class="w"> </span><span class="mf">3</span><span class="n">s2iauacdt2d2o2s2rqo2f3o2</span><span class="w"> </span><span class="mf">2</span><span class="n">co2ts2jcoS2s2o3</span><span class="w"> </span><span class="n">mid5</span><span class="w"> </span><span class="n">rai2aioe5ia3rao3</span><span class="w"> </span><span class="n">o4</span><span class="w"> </span><span class="mf">2</span><span class="n">en2lanlnlan2loh</span><span class="w"></span>
</code></pre></div>
<h1>Suffixe Array</h1>
<p>Si vous avez compris comment réaliser une <strong>Burrow-Wheeler</strong>, attendez avant de vous jeter sur l’implémentation du code et la création d'une matrice... <br>
Avez-vous pensé à la mémoire? Un texte de 100 000 mot, nécessite de construire une matrice de L x L, soit 100 000 * 100 000 = 10^10 bytes ! Ça fait beaucoup pour pas grand chose.<br>
Heureusement une autre méthode basée sur les <strong>suffix array</strong> permet d'économiser votre temps et votre mémoire pour réaliser cette transformation. <br>
La <strong>suffix array</strong>, d'un mot, est l'ensemble des suffixes de ce mot.<br>
Par exemple, le mot <em>banane$</em> , possède les suffixes suivant avec leurs rangs correspondants : </p>
<p align="center">
<img src="../images/post10/sa.png">
</p>
<p>Si nous ordonnons cette liste de suffixe dans l'ordre lexicographique, et que nous la comparons avec la matrice précédente, vous pouvez trouver une relation en faisant marcher vos méninges.</p>
<p align="center">
<img src="../images/post10/sa2.png">
</p>
<p>En effet, on observe que la nième lettre de la transformation de <strong>Burrow-Wheeler</strong> correspond dans le mot <em>banane</em>, au rang du suffix soustrait de 1... Rien compris? C'est normal. Lisez la suite, pour comprendre. <br>
Regardez le 6ème suffixe, "<em>nanes$</em>" , il est de rang 2. Puis chercher dans le mot <em>banane$</em> en bas, la lettre à l'index 2-1, soit l'index 1 . Il s'agit de la lettre "<strong>A</strong>" qui correspond bien à la 6ème lettre de la transformation de Burrow-Wheeler. <br>
Si vous avez pigé, il n'y a plus besoin de créer de matrice. La dernière colonne peut directement être obtenu en utilisant le suffix arrays. Vous avez juste besoin de créer une fonction qui retourne les rangs des suffixes après les avoir ordonnés lexicographiquement.<br>
Parfois un algorithme vaut mieux qu'une explication : </p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">suffixArray</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
<span class="sd">''' creation du suffixe array avec leurs rangs ordonnés '''</span>
<span class="n">satups</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">([(</span><span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">:],</span> <span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">)])</span>
<span class="k">return</span> <span class="nb">map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">satups</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">bwt</span><span class="p">(</span><span class="n">t</span><span class="p">):</span>
<span class="sd">''' transformation de Burrow-wheeler '''</span>
<span class="n">bw</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">si</span> <span class="ow">in</span> <span class="n">suffixArray</span><span class="p">(</span><span class="n">t</span><span class="p">):</span>
<span class="k">if</span> <span class="n">si</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="n">bw</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s1">'$'</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">bw</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">t</span><span class="p">[</span><span class="n">si</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
<span class="k">return</span> <span class="s1">''</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">bw</span><span class="p">)</span>
</code></pre></div>
<h1>Inverser la transformation</h1>
<p>C'est bien gentil tout ça, mais comment fait on marche arrière ? Comment à partir de la transformation de <strong>Burrow-Wheeler</strong> revenons nous au texte original? <br>
Tout d'abord, nous allons créer la première ( LC: Left Column ) et la dernière colonne (RC Right Column) de la matrice. La dernière colonne, c'est le texte transformé que nous avons en entrée. La première se calcule facilement, il suffit d'ordonner lexicographiquement les lettres de la dernière colonne. </p>
<p align="center">
<img src="../images/post10/reverse.png">
</p>
<p>Je ne vais pas vous le détailler ici, mais sachez que le rang des lettres dans la colonne de gauche correspond au même dans la colonne de droite. C'est à dire que le premier "<strong>A</strong>" de la colonne de gauche correspond au premier "<strong>A</strong>" de la colonne de droite. De même le deuxième "<strong>N</strong>" de la colonne de gauche est le même que le deuxième "<strong>N</strong>" de la colonne de droite.<br>
D'autre part, en se rappelant comment est construite la matrice, chaque lettre de la colonne de droite précède, dans le mot original, la lettre de la colonne de gauche.<br>
Sachant tout cela, on va pouvoir récrire le mot original en l'écrivant de droite à gauche. </p>
<p align="center">
<img src="../images/post10/reverse2.png">
</p>
<p>On part de la première ligne, et on lit toujours dans la colonne de droite. La première lettre correspond a "<strong>E1</strong>", c'est la dernière lettre du mot <em>banane</em>. On recherche ce même "<strong>E1</strong>" dans la colonne de gauche. La lettre qui précède ce E est le "<strong>N2</strong>". C'est l'avant dernière lettre du mot banane. On recherche de la même façon ce "<strong>N2</strong>" dans la colonne de gauche. La lettre qui le précède est "<strong>A2</strong>", c'est l'avant avant dernière lettre du mot banane etc....<br>
En continuant ce processus, l'intégralité du mot qui a servi d'entrée à la transformation de Burrow-wheeler est retrouvé. <br>
Et voici le code qui parlera plus à certain : </p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">rankBwt</span><span class="p">(</span><span class="n">bw</span><span class="p">):</span>
<span class="sd">''' Retourne les rangs '''</span>
<span class="n">tots</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<span class="n">ranks</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">bw</span><span class="p">:</span>
<span class="k">if</span> <span class="n">c</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">tots</span><span class="p">:</span>
<span class="n">tots</span><span class="p">[</span><span class="n">c</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">ranks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">tots</span><span class="p">[</span><span class="n">c</span><span class="p">])</span>
<span class="n">tots</span><span class="p">[</span><span class="n">c</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">return</span> <span class="n">ranks</span><span class="p">,</span> <span class="n">tots</span>
<span class="k">def</span> <span class="nf">firstCol</span><span class="p">(</span><span class="n">tots</span><span class="p">):</span>
<span class="sd">''' retourne la premiere colonne '''</span>
<span class="n">first</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">totc</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">c</span><span class="p">,</span> <span class="n">count</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">tots</span><span class="o">.</span><span class="n">iteritems</span><span class="p">()):</span>
<span class="n">first</span><span class="p">[</span><span class="n">c</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">totc</span><span class="p">,</span> <span class="n">totc</span> <span class="o">+</span> <span class="n">count</span><span class="p">)</span>
<span class="n">totc</span> <span class="o">+=</span> <span class="n">count</span>
<span class="k">return</span> <span class="n">first</span>
<span class="k">def</span> <span class="nf">reverseBwt</span><span class="p">(</span><span class="n">bw</span><span class="p">):</span>
<span class="sd">''' Retourne le texte original de la transformation bw '''</span>
<span class="n">ranks</span><span class="p">,</span> <span class="n">tots</span> <span class="o">=</span> <span class="n">rankBwt</span><span class="p">(</span><span class="n">bw</span><span class="p">)</span>
<span class="n">first</span> <span class="o">=</span> <span class="n">firstCol</span><span class="p">(</span><span class="n">tots</span><span class="p">)</span>
<span class="n">rowi</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">t</span> <span class="o">=</span> <span class="s2">"$"</span>
<span class="k">while</span> <span class="n">bw</span><span class="p">[</span><span class="n">rowi</span><span class="p">]</span> <span class="o">!=</span> <span class="s1">'$'</span><span class="p">:</span>
<span class="n">c</span> <span class="o">=</span> <span class="n">bw</span><span class="p">[</span><span class="n">rowi</span><span class="p">]</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">c</span> <span class="o">+</span> <span class="n">t</span>
<span class="n">rowi</span> <span class="o">=</span> <span class="n">first</span><span class="p">[</span><span class="n">c</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">ranks</span><span class="p">[</span><span class="n">rowi</span><span class="p">]</span>
<span class="k">return</span> <span class="n">t</span>
</code></pre></div>
<h1>Conclusion</h1>
<p>La transformation de Burrow-Wheeler, est utilisé en compression des données, notamment dans l'algorithme de compression <a href="https://fr.wikipedia.org/wiki/Bzip2">Bzip2</a>. Mais une autre utilisation en bioinformatique, est la recherche de plusieurs chaînes de caractères dans une plus grande, à l'aide d'un index appelé <a href="https://en.wikipedia.org/wiki/FM-index">FM-Index</a>. L'algorithme <a href="https://en.wikipedia.org/wiki/Bowtie_%28sequence_analysis%29">Bowtie2</a> et <a href="http://bio-bwa.sourceforge.net/">BWA</a> sont deux exemples d'utilisation de cette index. Ils permettent de retrouver rapidement, des séquences dans le génome humain. Nous verrons cette partie dans un prochain article ! </p>
<h2>Référence</h2>
<ul>
<li><a href="http://www.cs.jhu.edu/~langmea/resources/bwt_fm.pdf">Introduction to the Burrows-Wheeler Transform and FM Index</a> </li>
<li><a href="https://www.youtube.com/watch?v=4n7NPk5lwbI">video youtube</a></li>
<li><a href="http://www.allisons.org/ll/AlgDS/Strings/BWT/">Burrow wheeler online</a></li>
</ul>Renommer ses fichiers avec MMV2015-07-23T22:55:29+02:002015-07-23T22:55:29+02:00Sacha Schutztag:dridk.me,2015-07-23:/mmv.html<p>Cela vous est forcément déjà arrivé de devoir renommer une longue liste de fichiers. Pour les plus fainéant d'entre vous, vous allez cliquer sur un fichier, un par un , puis faire "F2" pour renommer. Bon, ça passe, avec 10 fichiers, mais pour certaine personne, renommer plus de 3 fichiers de …</p><p>Cela vous est forcément déjà arrivé de devoir renommer une longue liste de fichiers. Pour les plus fainéant d'entre vous, vous allez cliquer sur un fichier, un par un , puis faire "F2" pour renommer. Bon, ça passe, avec 10 fichiers, mais pour certaine personne, renommer plus de 3 fichiers de cette manière c'est déjà trop! Imaginez que vous voulez renommer toutes votre bibliothèque de série légale sous une forme <em>serie01e04.avi</em>, vous risquez de passer un bon bout de temps pour un résultat pas garantie. Heureusement, il existe plein de logiciels graphiques gratuits comme <a href="http://sourceforge.net/projects/renameit/">Rename-it</a> ou <a href="http://www.bulkrenameutility.co.uk/Main_Intro.php">Bulk Rename</a> pour vous aidez. Mais voilà, nous, on préfère les techniques de Jedi avec notre console Linux pour en mettre plein les yeux à nos copains. </p>
<h2>MMV : Mass Rename of files</h2>
<p>Comparé à d'autres outils comme <strong>rename</strong>, <strong>mmv</strong> permet de faire des choses simples sans utiliser d'expression régulière! Elle utilise la syntaxe de <strong>bash</strong> avec des étoiles (*), des points d'interrogation (?) ou encore des crochets ( [] ). Dans la plus part des cas, vous allez faire des choses simples...
C'est donc l'outil idéal. <br>
Par exemple, imaginez que nous ayons des fichiers avec l'extension <em>jpg</em> que nous voulons renommer en <em>jpeg</em> : </p>
<div class="highlight"><pre><span></span><code>file_001_loremipsum.jpg
file_002_dolor.jpg
file_003_sit.jpg
file_004_amet.jpg
file_105_randomness.jpg
</code></pre></div>
<p>On utilise alors la commande <strong>mmv</strong> avec la syntaxe <em>mmv -n "from" "to"</em>. <br>
Le paramètre <em>"-n"</em> permet d'ignorer la commande et vous affiche uniquement le résultat escompté. Effacez le, une fois satisfait pour appliquer les changements. </p>
<div class="highlight"><pre><span></span><code><span class="o">></span><span class="n">mmv</span><span class="w"> </span><span class="o">-</span><span class="n">n</span><span class="w"> </span><span class="s">"*.jpg"</span><span class="w"> </span><span class="s">"#1.jpeg"</span><span class="w"></span>
<span class="n">file_001_loremipsum</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">file_001_loremipsum</span><span class="p">.</span><span class="n">jpeg</span><span class="w"></span>
<span class="n">file_002_dolor</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">file_002_dolor</span><span class="p">.</span><span class="n">jpeg</span><span class="w"></span>
<span class="n">file_003_sit</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">file_003_sit</span><span class="p">.</span><span class="n">jpeg</span><span class="w"></span>
<span class="n">file_004_amet</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">file_004_amet</span><span class="p">.</span><span class="n">jpeg</span><span class="w"></span>
<span class="n">file_105_randomness</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">file_105_randomness</span><span class="p">.</span><span class="n">jpeg</span><span class="w"></span>
</code></pre></div>
<p>Le caractère étoile(*) du <em>from</em> est substitué par l'indice <em>#1</em>. Il y a autant d'indice que d'étoile. Cela nous permet de faire des trucs marrants comme : </p>
<div class="highlight"><pre><span></span><code><span class="o">></span><span class="n">mmv</span><span class="w"> </span><span class="o">-</span><span class="n">n</span><span class="w"> </span><span class="s">"file_*_*.jpg"</span><span class="w"> </span><span class="s">"#2-file-#1.jpg"</span><span class="w"></span>
<span class="n">file_001_loremipsum</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">loremipsum</span><span class="o">-</span><span class="n">file</span><span class="o">-</span><span class="mf">001.</span><span class="n">jpg</span><span class="w"></span>
<span class="n">file_002_dolor</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">dolor</span><span class="o">-</span><span class="n">file</span><span class="o">-</span><span class="mf">002.</span><span class="n">jpg</span><span class="w"></span>
<span class="n">file_003_sit</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">sit</span><span class="o">-</span><span class="n">file</span><span class="o">-</span><span class="mf">003.</span><span class="n">jpg</span><span class="w"></span>
<span class="n">file_004_amet</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">amet</span><span class="o">-</span><span class="n">file</span><span class="o">-</span><span class="mf">004.</span><span class="n">jpg</span><span class="w"></span>
<span class="n">file_105_randomness</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">randomness</span><span class="o">-</span><span class="n">file</span><span class="o">-</span><span class="mf">105.</span><span class="n">jpg</span><span class="w"></span>
</code></pre></div>
<h2>Majuscule / Minuscule</h2>
<p>On peut aussi s'amuser à changer la case en rajoutant avant l'indice, un "l" (lowercase) ou "u (uppercase)". </p>
<div class="highlight"><pre><span></span><code><span class="o">></span><span class="n">mmv</span><span class="w"> </span><span class="o">-</span><span class="n">n</span><span class="w"> </span><span class="s">"file_*_*.jpg"</span><span class="w"> </span><span class="s">"#u2-file-#1.jpg"</span><span class="w"></span>
<span class="n">file_001_loremipsum</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">LOREMIPSUM</span><span class="o">-</span><span class="n">file</span><span class="o">-</span><span class="mf">001.</span><span class="n">jpg</span><span class="w"></span>
<span class="n">file_002_dolor</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">DOLOR</span><span class="o">-</span><span class="n">file</span><span class="o">-</span><span class="mf">002.</span><span class="n">jpg</span><span class="w"></span>
<span class="n">file_003_sit</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">SIT</span><span class="o">-</span><span class="n">file</span><span class="o">-</span><span class="mf">003.</span><span class="n">jpg</span><span class="w"></span>
<span class="n">file_004_amet</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">AMET</span><span class="o">-</span><span class="n">file</span><span class="o">-</span><span class="mf">004.</span><span class="n">jpg</span><span class="w"></span>
<span class="n">file_105_randomness</span><span class="p">.</span><span class="n">jpg</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">RANDOMNESS</span><span class="o">-</span><span class="n">file</span><span class="o">-</span><span class="mf">105.</span><span class="n">jpg</span><span class="w"></span>
</code></pre></div>
<h2>Autres expressions</h2>
<p>Vous pouvez également utiliser le caractère "?" pour designer un seul caractère et les crochets "[]" pour faire une sélection.<br>
Imaginons que nous ayons 4 fichiers : </p>
<div class="highlight"><pre><span></span><code><span class="mf">1.</span><span class="n">png</span><span class="w"></span>
<span class="mf">2.</span><span class="n">png</span><span class="w"></span>
<span class="mf">3.</span><span class="n">png</span><span class="w"></span>
<span class="mf">4.</span><span class="n">png</span><span class="w"></span>
</code></pre></div>
<p>Et que nous voulons renommer uniquement les 3 premières fichiers. Nous utiliserons alors les crochets de cette façon : </p>
<div class="highlight"><pre><span></span><code><span class="o">></span><span class="n">mmv</span><span class="w"> </span><span class="o">-</span><span class="n">n</span><span class="w"> </span><span class="s">'[1-3].png'</span><span class="w"> </span><span class="s">'test#1.png'</span><span class="w"></span>
<span class="mf">1.</span><span class="n">png</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">test1</span><span class="p">.</span><span class="n">png</span><span class="w"></span>
<span class="mf">2.</span><span class="n">png</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">test2</span><span class="p">.</span><span class="n">png</span><span class="w"></span>
<span class="mf">3.</span><span class="n">png</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">test3</span><span class="p">.</span><span class="n">png</span><span class="w"></span>
</code></pre></div>
<h2>Autres méthodes</h2>
<p>Pour des choses plus complexe, comme l'utilisation d'expressions régulières, il faudra se tourner vers l'outil <em><a href="http://linux.die.net/man/2/rename">rename</a></em> qui reprend la même syntaxe que perl. </p>
<h2>Référence</h2>
<ul>
<li><a href="http://ss64.com/bash/mmv.html">MMV man page</a> </li>
<li><a href="http://stackoverflow.com/questions/417916/how-to-do-a-mass-rename">Stackoverflow</a></li>
</ul>Naviguer dans le Génome humain2015-04-06T16:25:55+02:002015-04-06T16:25:55+02:00Sacha Schutztag:dridk.me,2015-04-06:/naviguer-dans-votre-adn.html<p>Dans ce post, nous allons voir comment naviguer dans le génome humain. Celui ci a été entièrement séquencé grâce à un consortium international de chercheurs au sein du <em><a href="https://fr.wikipedia.org/wiki/Projet_g%C3%A9nome_humain">Human Genom Project</a></em> entre 1990 et 2003. Ce génome fait environ 3 milliards de bases, soit un fichier texte d'environ 3 GigaOctets …</p><p>Dans ce post, nous allons voir comment naviguer dans le génome humain. Celui ci a été entièrement séquencé grâce à un consortium international de chercheurs au sein du <em><a href="https://fr.wikipedia.org/wiki/Projet_g%C3%A9nome_humain">Human Genom Project</a></em> entre 1990 et 2003. Ce génome fait environ 3 milliards de bases, soit un fichier texte d'environ 3 GigaOctets que vous pouvez télécharger <a href="http://hgdownload.cse.ucsc.edu/goldenPath/hg38/bigZips/hg38.fa.gz">ici</a>. Aujourd'hui, le génome accompagné de ses annotations est disponible intégralement sur internet par l’intermédiaire de bases de données publiques. <br>
Pour se repérer dans ces méandres de données, il nous faut comprendre l'organisation du génome et connaître les différents systèmes de coordonnées et leurs nomenclatures. Ce post sera donc le prélude à votre voyage. </p>
<h1>L'ADN</h1>
<p>L'ADN est une longue molécule localisée dans les noyaux de nos cellules qui constitue un support biologique d'information. Au même titre qu'un fichier binaire, l'information est stocké numériquement. C'est à dire qu'au lieu d'utiliser 2 symboles comme un fichier binaire (1 et 0), l'ADN utilise 4 symboles matérialisés par les 4 bases azotées Adénine(A), Cytosine(C), Guanine(G), Tymine(T). D'ailleurs il est tout à fait possible de stocker des données informatiques dans un brin d'ADN comme le suggère <a href="http://www.ibtimes.com.au/worlds-first-biological-computer-decrypts-images-stored-dna-1293424">ce post </a>. </p>
<p align="center">
<img src="../images/post8/dna.png">
</p>
<p>Ces bases sont agencées linéairement sur un brin par l’intermédiaire d'un sucre (le désoxyribose) qui se lie à ses voisins par un liaison phosphodiester, soit par son carbone en 5' soit par son carbone en 3'(Voir schéma ci dessus).
Un brin d'ADN est ainsi polarisé, avec deux extrémités libres différentes (5' et 3'), et sa lecture se fait toujours dans le sens 5' vers 3'. C'est en effet dans ce sens, et uniquement dans ce sens, que s'effectue la synthèse ou polymérisation de l'ADN. Sur la figure précédente, le brin d'ADN de gauche est lu <strong>5'-ATCG-3'</strong>. <br>
L'information codé sur un brin d'ADN est doublée par la présence d'un brin complémentaire anti-parallèle (à droite). Celui-ci se forme par les liaisons hydrogènes entre A et T d'une part et C et G d'autre part. Les deux brins réunis forment la double hélice d'ADN. Cette parité de l'information autorise une correction d'erreur en cas de perte de base sur l'un des deux brins. Ce mécanisme évoque d'autres systèmes de correction, utilisé cette fois en informatique, comme le <a href="https://en.wikipedia.org/wiki/Parity_bit">parity bit</a>.
La séquence complémentaire étant anti-parallèle, elle se lit du bas vers le haut. Soit <strong>5'-CGAT-3'</strong> . </p>
<h2>Le génome humain</h2>
<p>Le génome humain est constitué d'une longue séquence de 3,2 milliards de bases réparties sur 24 chromosomes. Chaque chromosome est constitué d'une molécule d'ADN double brin.</p>
<p align="center">
<img src="../images/post8/caryotype.gif">
</p>
<p>Il ne faut pas confondre le génome humain avec le genotype d'une personne. En effet, chaque individu est l'expression de deux génomes combinés: Le génome maternel et le génome paternel. Chacune de nos cellules possède ainsi 22 <strong>paires</strong> de chromosomes et une paire de chromosome sexuelle XX ou XY. </p>
<h3>Un ou plusieurs génomes ?</h3>
<p>La variabilité du génome humain est responsable de la diversité de notre espèce. Chaque personne possède une séquence d'ADN qui lui est propre. Pourtant, on parle "<em>du génome humain</em>" comme d'une seul entité. <br>
Il s'agit en fait, d'une séquence consensus réalisée à partir de plusieurs individus où chaque base d'une position est la plus représentative parmi les génomes testés. On appelle ça un «<em><a href="https://en.wikipedia.org/wiki/Genome_project#Genome_assembly">genome assembly</a></em>». Cette séquence est continuellement mise à jour par le <a href="http://www.ncbi.nlm.nih.gov/projects/genome/assembly/grc/">GRC (Genome Reference Consortium)</a>. À ce jour, la dernière version du génome humain est la <a href="http://www.ncbi.nlm.nih.gov/projects/genome/assembly/grc/human/"><strong>GRCh38</strong></a> disponible sur NCBI. Vous pouvez également le trouver sur <a href="https://genome-euro.ucsc.edu/index.html">UCSC</a> sous le nom <a href="https://genome-euro.ucsc.edu/cgi-bin/hgGateway?db=hg38&redirect=manual&source=genome.ucsc.edu"><strong>hg38</strong></a>. Attention toute fois, la précédente version GRCh37 du NCBI correspond à la version hg19 de UCSC.<br>
Ce génome, comme n'importe quelle séquence d'ADN, est sauvegardé dans un fichier texte dont le format standard est le <strong><a href="https://fr.wikipedia.org/wiki/FASTA_%28format_de_fichier%29">fasta</a></strong>. Il existe aussi un format binaire <strong><a href="http://jcomeau.freeshell.org/www/genome/2bitformat.html">2bit</a></strong>, ou chaque base est codé sur 2 bits au lieu de 8 bits. Tout le génome humain passe alors de 3 Gigaoctets à 750 Megaoctets. Mais celui-ci étant moins pratique on lui préfère le fasta. (exemple ci dessous)</p>
<div class="highlight"><pre><span></span><code> >maSequence1 commentaire
GTGCCGAGCTGAGTTCCTTATAAGAATTAATCTTAATTTTGTATTTTTTCCTGTAAGACAATAGGCCATG
TTAATTAAACTGAAGAAGGATATATTTGGCTGGGTGTTTTCAAATGTCAGCTTAAAATTGGTAATTGAAT
GGAAGCAAAATTATAAGAAGAGGAAATTAAAGTCTTCCATTGCATGTATTGTAAACAGAAGGAGATGGGT
GATTCCTTCAATTCAAAAGCTCTCTTTGGAATGAACAATGTGGGCGTTTGTAAATTCTGGAAATGTCTTT
CTATTCATAATAAACTAGATACTGTTGATCTTTTAAAAAAAAAAAA
</code></pre></div>
<p>Essayez pour voir, de lire le fichier que vous avez téléchargé plus haut. Pour ceux qui sont sous linux, la commande <em>less</em> fera l'affaire. Ce fichier est le génome humain dans sa version hg38. Il contient toutes les séquences réparties sur les 24 chromosomes avec aussi l'ADN mitochondrial. Chacune de ces séquences est séparée par une ligne commençant par '>' associé au nom du chromosome.<br>
Depuis ce fichier, vous pouvez localiser n'importe quel gène... Mais avant ça, il faut savoir comment se localiser!</p>
<h1>Se localiser dans le génome</h1>
<h2>Les coordonnées chromosomiques</h2>
<p align="center">
<img src="../images/post8/band.png">
</p>
<p>Un chromosome est composé d'un bras court (p) et d'un bras long (q), séparés par un centromère. Grâce aux colorations réalisées en cytogénétique, on distingue des régions contenant des bandes qui elles-mêmes contiennent des sous-bandes.<br>
Les numéros des régions, des bandes et des sous-bandes sont attribués dans l'ordre croissant, depuis le centromère vers les extrémités appelées télomètres (Voir schéma ci dessus). Ainsi, pour localiser une zone d’intérêt dans le génome en coordonnées chromosomiques. on s'aide de la nomenclature suivante:</p>
<p>{chromosome}{bras}{region}{bande}.{sous-bande}</p>
<p>Par exemple, le gène <strong><a href="https://fr.wikipedia.org/wiki/G%C3%A8ne_et_prot%C3%A9ine_CFTR">CFTR</a></strong> impliqué dans la mucoviscidose se trouve dans la zone <strong>7q31.2</strong>. C'est à dire sur: le bras long du chromosome 7, la 3ième région, la bande 1, la sous-bande 2 .
La résolution d'une sous bande est de l'ordre de 2 millions de base. Ces coordonnés permettent uniquement de cibler des grandes zones du génome et sont principalement utilisées dans la détection de grandes mutations par les cytogénéticiens, à l'aide de techniques comme le <a href="https://fr.wikipedia.org/wiki/Caryotype">caryotype</a>, la <a href="https://fr.wikipedia.org/wiki/Hybridation_in_situ_en_fluorescence">FISH</a> ou la <a href="https://fr.wikipedia.org/wiki/Puce_d%27hybridation_g%C3%A9nomique_comparative">CGH array</a>. </p>
<h2>Les coordonnées génomiques</h2>
<p>Contrairement aux coordonnées chromosomiques, la résolution des coordonnées génomiques est de 1 base. La première base d'un chromosome depuis l'extrémité 5' du bras court, porte le nombre 1 (au grand malheur des développeurs qui auraient voulu commencer à zéro). La dernière base à l'extrémité 3' du bras long porte le nombre le plus élevé. Pour sélectionner une région, on s'aide de cette nomenclature:</p>
<p>{chromosome}:{position_début}-{position_fin}</p>
<p>Par exemple, le gène CFTR se trouve exactement dans la zone 7:117465784-117715971. <br>
Je vous invite à tester par vous même en utilisant l'API publique de <a href="http://rest.ensembl.org/documentation/info/sequence_region">Ensembl</a>. En substituant les derniers paramètres, vous allez pouvoir récupérer la séquence du gène CFTR au format Fasta:</p>
<p>*
<a href="http://rest.ensembl.org/sequence/region/human/7:117465784..117715971:1">http://rest.ensembl.org/sequence/region/human/7:117465784..117715971:1
</a>*</p>
<p>Maintenant, je suis sûr que vous allez vous demander un jour (si ce n'est pas tout de suite), comment récupérer la séquence du brin complémentaire. Celle que nous avons obtenue s'appelle la <strong>séquence forward</strong>. La séquence complémentaire, s'appelle <strong>séquence reverse</strong> et correspond aux bases complémentaires, mais attention, elle est orientée dans le sens 3'5'. Hors nous avons vu que toutes séquences s’écrient toujours dans le sens 5'3'. Il faut donc retourner la séquence pour pouvoir la lire.<br>
La requête suivante récupère donc le brin reverse:</p>
<p>*<a href="http://rest.ensembl.org/sequence/region/human/7:117465784..117715971:-1">http://rest.ensembl.org/sequence/region/human/7:117465784..117715971:-1</a>
*</p>
<p>Observer le schéma ci dessous, pour bien vous familiariser avec cette nomenclature. Dans ce schéma, un séquence de 10 bases à été sélectionnée.</p>
<p align="center">
<img src="../images/post8/strand.png">
</p>
<p>Les coordonnées génomiques sont utilisées en génétique pour localiser des zones précises du génome et pour décrire précisément des mutations. Par exemple la notation <strong>chr1:g.35227587C>G</strong> correspond à la substitution d'un C par un G en position 35227587 sur le chromosome 1. </p>
<h2>Les coordonnées exoniques</h2>
<p align="center">
<img src="../images/post8/exon.png">
</p>
<p>Au lieu d'utiliser le génome entier comme repère, on peut se servir du gène. Dans ce contexte, un gène est une séquence pouvant être transcrite et traduite en protéine. Un gène est composé d'introns (non transcrits) et d'exons (transcrits). <br>
Lorsqu'on se repère en coordonnée exonique, on doit obligatoirement faire référence à un gène. Puis on donne le numéro <strong>1</strong> à la première base qui sera traduite, c'est à dire le A du codon initiateur ATG. Comme d'habitude il n'y a pas de numéro 0... <em>« soupir »</em> <br>
Toutes les bases avant le codon initiateur sont numérotées <strong>-1,</strong> <strong>-2</strong> etc. Les bases après le codon stop mettant fin à la traduction sont numérotées <strong>1* </strong>,<strong> 2* </strong> etc.<br>
Les introns sont numérotés par rapport à l'exon le plus proche. Pour le début de l'intron <strong>e+1</strong>, <strong>e+2</strong> etc.. et pour la fin <strong>e-1</strong>, <strong>e-2</strong> etc...<br>
Cette nomenclature est définit par l'<a href="http://www.hgvs.org">HGVS</a>. Elle est utilisé majoritairement pour décrire les mutations retrouvées dans l'ADN. Je détaillerai cette nomenclature dans un prochain post. Notons juste comme exemple, la mutation principale retrouvée dans la mucoviscidose, une délétion de 3 bases (CTT) responsable d'une perte de phénylalanine dans la protéine CFTR se note : <strong>c.1521_1523delCTT </strong></p>
<h2>Conversion entre systèmes de coordonnées</h2>
<p>Convertir des coordonnées exoniques en génomiques n'est pas aussi simple qu'il n'y parait. En effet, un gène peut se trouver sur le brin forward ou reverse. Or, comme nous l'avons vu précédemment, les coordonnées génomiques sur le brin reverse se lisent à l'envers. Donc pour un gène situé sur le brin reverse, les positions 1,2,3,4 ( ordre croissant ) en cordonnées exoniques se lirons 1000, 999, 998 (ordre décroissant) en coordonnées génomiques. Faite un dessin, vous comprendrez... ! <br>
De plus pour compliquer le tout, les coordonnées génomiques varient en fonction de la version du génome que vous utilisez. Les coordonnées en GRCh38 ne sont pas les mêmes que ceux en GRCh37. <br>
Vérifiez toujours, lorsque vous étudiez un gène, sur quel brin vous êtes et quel génome vous utilisez. Aidez vous des outils pour faire vos conversions. Ensembl dispose d'une API REST pour faire ce <em>mapping</em> de coordonnées [ici].http://rest.ensembl.org/documentation/info/assembly_cdna) </p>
<h1>Travaux appliqués</h1>
<p>Pour s’exercer avec ce que vous avez appris, et faire plaisir à un ami du <a href="https://www.youtube.com/user/lepsylab">psylab</a>, essayons de rechercher des informations sur un gène, le gène CACNA1C impliqué dans la schizophrénie. <br>
Pour cela, allez sur le site <a href="http://www.ensembl.org/Homo_sapiens/Info/Index">ensembl</a> et recherchons le gène CACNA1C dans la barre de recherche. <br>
Vous retrouverez alors toutes les informations utiles à propos de ce gène sur cette <a href="http://www.ensembl.org/Homo_sapiens/Gene/Summary?db=core;g=ENSG00000151067;r=12:1970786-2697950">page</a>. </p>
<p align="center">
<img src="../images/post8/ensembl.png">
</p>
<p>Il s'agit d'un gène situé sur le chromosome 12, en position génomique 1970786-2697950 orienté sur le brin forward. Ce gène se trouve en position p13.33, soit une région du bras court du chromosome 12. </p>
<h1>Conclusion</h1>
<p>Pour finir, je vais vous laisse vous amuser avec différents <em>genome browser</em> existants. ce sont des sites web qui vous permettent de naviguer visuellement dans le génome, extraire des données et obtenir des informations complémentaires. Essayez par exemple, de retrouver , ou se trouve le gène HFE impliqué dans l'hémochromatose, sa position chromosomique et génomique ainsi que sa séquence.</p>
<ul>
<li><a href="http://www.ensembl.org/Homo_sapiens/Info/Index">Ensembl</a></li>
<li><a href="http://rest.ensembl.org/">Ensembl API REST</a></li>
<li><a href="http://genome.ucsc.edu/cgi-bin/hgTracks">UCSC</a></li>
<li><a href="http://www.ncbi.nlm.nih.gov/variation/tools/1000genomes/">1000genomes</a></li>
<li><a href="http://annmap.cruk.manchester.ac.uk/">Annmap</a></li>
</ul>
<h1>references</h1>
<ul>
<li><a href="https://wiki.dnanexus.com/Scientific-Notes/human-genome">dnanexus</a></li>
<li><a href="http://alternateallele.blogspot.fr/2012/03/genome-coordinate-conventions.html">alternateallele</a></li>
<li><a href="http://www.hgvs.org/mutnomen/refseq.html">HGVS</a></li>
<li><a href="http://www.ensembl.org/Homo_sapiens/Info/Index">ENSEMBL</a></li>
</ul>OpenSlide : La libraire des pathologistes !2014-08-06T19:33:48+02:002014-08-06T19:33:48+02:00Sacha Schutztag:dridk.me,2014-08-06:/openslide.html<p>Il y a quelques temps de cela, un collègue <a href="http://fr.wikipedia.org/wiki/Anatomo-pathologie">anatomo-pathologiste</a> était venu demander mon aide pour détecter des cellules sur des images histologiques d'amygdales. Ces images étaient issues d'un scanner à lame microscopique et stockées sous un format propriétaire Hamamatsu (.ndpi).<br>
Bref, c'était mes débuts dans l'analyse et le traitement …</p><p>Il y a quelques temps de cela, un collègue <a href="http://fr.wikipedia.org/wiki/Anatomo-pathologie">anatomo-pathologiste</a> était venu demander mon aide pour détecter des cellules sur des images histologiques d'amygdales. Ces images étaient issues d'un scanner à lame microscopique et stockées sous un format propriétaire Hamamatsu (.ndpi).<br>
Bref, c'était mes débuts dans l'analyse et le traitement de l'image! </p>
<p style="text-align:center">
<img src="/images/histology.jpg">
</p>
<!-- ![Alt text](/images/histology.jpg "Optional title"){float:right;} -->
<h3>Un scanner à lame ?</h3>
<p>Avec un microscope, on peut regarder un échantillon sous toutes ses coutures. Choisir le zoom de l'objectif, se déplacer sur la lame, régler la luminosité, le contraste etc... Tout ça sans jamais perdre en qualité. Une simple photo prise sur le vif, ne peut pas vous montrer l'échantillon dans son ensemble. Si par exemple, vous vouliez demander conseil à un collègue outre atlantique, il fallait lui envoyer la lame par la poste. Et pour les conserver, une grande armoire avec un grand cahier en papier (histoire de rester dans le même registre technologique...:D). <br>
Mais maintenant, il existe les "<strong>lames virtuelles</strong>" ! Ces lames sont des reproductions numériques du contenu optique d'une lame standard et sont obtenues grâce à un scanner à lame. La lecture se fait sur un ordinateur, et vous pouvez reproduire les mêmes manipulations qu'avec un microscope standard. Je vous propose de jeter un œil sur cette <a href="http://openslide.org/demo/">démo</a> depuis votre navigateur. </p>
<h4>Comment ça marche ?</h4>
<p>Il suffit de faire plein de photos à tous les zooms possibles et sur toute la lame, et d'assembler tout ça dans un fichier. Par exemple, au zoom le plus faible, on aura 4 images de l'ensemble de la lame. Et à plus fort zoom, une centaine. L'ensemble de ces images peut être représenté sous forme d'une pyramide :</p>
<p><img alt="pyramide ndpi" src="/images/scanner_lame.jpg" title="représentation schématique d'un fichier ndpi"> </p>
<p>Toutes ces images sont stockées ensemble dans un fichier accompagné de <a href="http://fr.wikipedia.org/wiki/M%C3%A9ta-donn%C3%A9e">métadonnée</a>. Les fichiers que j'utilise sont de <a href="https://www.openmicroscopy.org/site/support/bio-formats5/formats/hamamatsu-ndpi.html">format (.ndpi)</a>.
En contrepartie, ces fichiers sont de taille énorme, comparés aux formats d'images standards et peuvent atteindre sans problème le Gigaoctect. C'est pour ces raisons que rare sont les logiciels qui permettent d'ouvrir ce genre d'image. Même <a href="http://imagej.nih.gov/ij/">imageJ</a>, le saint graal des pathologistes, avait du mal à l'heure où je vous écris. Après c'est une application Java, ça se comprend ... :D [TROLL]!</p>
<h3>OpenSlide :</h3>
<p><a href="http://openslide.org/api/python/">OpenSlide</a> est une libraire écrit en C, permettant de gérer ce genre d'image. Il gère un tas de format (.ndpi, .vms, .vmu, .svs, .svslide ... ) et propose un <a href="http://fr.wikipedia.org/wiki/Binding">binding</a> pour notre langage préféré : python ! </p>
<h4>Installation</h4>
<p>Depuis une Debian faite : </p>
<div class="highlight"><pre><span></span><code><span class="n">apt</span><span class="o">-</span><span class="n">get</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">openslide</span><span class="o">-</span><span class="n">tools</span><span class="w"></span>
<span class="n">apt</span><span class="o">-</span><span class="n">get</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">openslide</span><span class="o">-</span><span class="n">python</span><span class="w"> </span><span class="c1"># Python 2</span><span class="w"></span>
<span class="n">apt</span><span class="o">-</span><span class="n">get</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">openslide</span><span class="o">-</span><span class="n">python3</span><span class="w"> </span><span class="c1"># Python 3</span><span class="w"></span>
</code></pre></div>
<p>Depuis un Mac avec port: </p>
<div class="highlight"><pre><span></span><code>port install openslide
port install py-openslide
</code></pre></div>
<p>Depuis un Mac avec brew:</p>
<div class="highlight"><pre><span></span><code>brew install openslide
</code></pre></div>
<p>Depuis pip : </p>
<div class="highlight"><pre><span></span><code>pip install openslide-python
</code></pre></div>
<p>Pour les autres, allez faire un tour sur <a href="http://openslide.org/download/">la page officiel</a></p>
<h4>Afficher une image ndpi</h4>
<p>Téléchargez un exemple d'image .ndpi depuis <a href="http://openslide.org/demo/">cette page</a> et testez le code qui suit. </p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">openslide</span> <span class="kn">import</span> <span class="n">OpenSlide</span>
<span class="n">img</span> <span class="o">=</span> <span class="n">OpenSlide</span><span class="p">(</span><span class="s2">"exemple.ndpi"</span><span class="p">)</span>
<span class="n">img</span><span class="o">.</span><span class="n">get_thumbnail</span><span class="p">((</span><span class="mi">1000</span><span class="p">,</span><span class="mi">1000</span><span class="p">))</span><span class="o">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div>
<p>Vous devriez voir une belle image d'histologie. Je n'ai pas besoin de commenter le code à part la dernière ligne. <strong>get_thumbnail</strong> retourne un aperçu de votre lame numérique dans sa totalité. L'image est un objet <a href="http://effbot.org/imagingbook/pil-index.htm">PIL.Image</a>,très utilisée pour manipuler des images en python. Cette fonction prend en paramètre la résolution maximum de votre thumbnail. En fait, il va essayer de trouver une image la plus proche de cette résolution. Mettez ce que vous voulez.<br>
Pour finir, j'appelle la méthode <strong>show</strong> de mon PIL.Image, qui affichera l'image directement dans un viewer. </p>
<h4>Récupérer des informations</h4>
<p>Plusieurs méthodes sont disponibles afin de connaitre les propriétés de votre lame virtuelle. </p>
<div class="highlight"><pre><span></span><code>img.dimensions # Retourne la dimension global
img.properties # Un tas de métadata
img.level_count # Retourne le nombre d’étage dans la pyramide
img.level_dimensions # Retourne les dimensions de chaque étages
img.level_downsamples # Retourne le zoom de chaque étages
</code></pre></div>
<h4>Récupérer une zone de l'image</h4>
<p>Et si vous voulez récupérer une zone rectangulaire, faites tout simplement </p>
<div class="highlight"><pre><span></span><code><span class="n">img</span><span class="p">.</span><span class="n">read_region</span><span class="p">(</span><span class="n">location</span><span class="o">=</span><span class="p">(</span><span class="mh">10</span><span class="p">,</span><span class="mh">10</span><span class="p">),</span><span class="w"> </span><span class="n">level</span><span class="o">=</span><span class="mh">2</span><span class="p">,</span><span class="w"> </span><span class="n">size</span><span class="o">=</span><span class="p">(</span><span class="mh">500</span><span class="p">,</span><span class="mh">500</span><span class="p">))</span><span class="w"></span>
</code></pre></div>
<p>Ou <strong>location</strong> est le coin supérieur gauche, <strong>level</strong> le numéro de l'étage et <strong>size</strong> les dimensions de votre zone.</p>
<h4>Conclusion</h4>
<p>Voilà, vous pouvez à présent lancer une discussion sérieuse avec un anatomo-pathologiste en lui expliquant que le microscope c'est <em>has-been</em>.<br>
Dans un prochain article, j'expliquerai différente technique d'analyse d'image.</p>
<hr>
<h4>Référence</h4>
<p><a href="http://openslide.org/">Site officiel de Openslide</a><br>
<a href="http://www.hamamatsu.com/jp/en/5007.html">Site officiel de Hamamatsu</a><br>
<a href="http://www.imnc.in2p3.fr/pagesperso/deroulers/software/ndpitools/">Une autre libraire par Christophe Deroulers</a> </p>Mémo sur les expressions régulières2014-07-29T19:13:15+02:002014-07-29T19:13:15+02:00Sacha Schutztag:dridk.me,2014-07-29:/expression-reguliere.html<!-- <p align="center">
<img src="../images/post6/regular_expression.png">
</p> -->
<p>Les expressions régulières, c'est super simple... Il suffit que quelqu'un les écrivent pour vous !<br>
En effet, j'ai longtemps galéré avec les expressions régulières.. En fait, dès que j'avais affaire à elles, je demandais à quelqu'un de me l'écrire. C’était beaucoup plus rapide que de réfléchir par moi même! ( technique …</p><!-- <p align="center">
<img src="../images/post6/regular_expression.png">
</p> -->
<p>Les expressions régulières, c'est super simple... Il suffit que quelqu'un les écrivent pour vous !<br>
En effet, j'ai longtemps galéré avec les expressions régulières.. En fait, dès que j'avais affaire à elles, je demandais à quelqu'un de me l'écrire. C’était beaucoup plus rapide que de réfléchir par moi même! ( technique souvent employée en programmation). Mais voilà, ça c'était avant !</p>
<h3>Définition</h3>
<p>Les expressions régulières permettent d'identifier dans un texte, des sous ensembles respectant un pattern particulier. Par exemple, imaginons que dans un article scientifique, je souhaite récupérer tous les noms d'auteur, sachant que le nom et le prénom commencent par une majuscule . Par exemple <strong>Ishigaki S</strong> ou <strong>Rossini-Beri AA</strong>. Je sais aussi que les noms ne contiennent jamais de chiffre ni de caractères spéciaux mis à part le tiret.
L'expression régulière que j'écrirai sera la suivante : </p>
<div class="highlight"><pre><span></span><code>\s[A-Z][a-z]+(\-[A-Z][a-z]+)?\s[A-Z]{1,2}
</code></pre></div>
<p>Incompréhensible n'est ce pas ? Ne vous inquiétez pas, je vais vous expliquer. Mais il va falloir pratiquer. Je vous conseil d'aller sur <a href="http://regexpal.com/">regexpal</a> pour tester en ligne vos expressions régulières. </p>
<h3>Expression simple</h3>
<p>Le pattern le plus simple, est un groupe de lettre. Dans le texte ci dessous , je recherche le pattern 'biologie'. </p>
<h4>exemple</h4>
<blockquote>
<p>Les recherches alliant physique quantique, ingénierie électrique, chimie et <strong>biologie</strong>, sont particulièrement pertinentes, car elles pourraient donner naissance à des thérapies entraînant beaucoup moins d’effets secondaires que les médicaments.</p>
</blockquote>
<p>Attention, ce n'est pas un mot que je cherche, mais un pattern. Ainsi, le pattern [et] me retournera le "<em>et</em>" seul et le "<em>et</em>" de "<em>effet</em>"</p>
<h4>exemple</h4>
<blockquote>
<p>Les recherches alliant physique quantique, ingénierie électrique, chimie <strong>et</strong> biologie, sont particulièrement pertinentes, car elles pourraient donner naissance à des thérapies entraînant beaucoup moins d’eff<strong>et</strong>s secondaires que les médicaments.</p>
</blockquote>
<h3>Caractère spéciaux</h3>
<p>Il existe plusieurs caractères reconnus dans les expressions régulières permettant de faire des recherches plus complexe:</p>
<div class="highlight"><pre><span></span><code> ^ . [ ] $ ( ) * + ? | { } \
</code></pre></div>
<p>Vous ne pouvez donc pas rechercher ces symboles directement dans le texte. Pour cela, vous devez les "<em>échapper</em>" avec l'antislash [ \ ].
Par exemple pour rechercher le pattern ' WTF???? '</p>
<div class="highlight"><pre><span></span><code>WTF\?\?\?\?
</code></pre></div>
<p>Voyons maintenant la signification des autres caractères spéciaux ...</p>
<h3>Le point</h3>
<p>Le point représente n'importe quels caractères. Si par exemple vous voulez rechercher le mot 'ARN' et le mot 'ADN', le pattern sera : </p>
<div class="highlight"><pre><span></span><code>A.N
</code></pre></div>
<p>Attention, quand je dis tous les caractères, c'est tous les caractères possibles! Ce pattern détectera aussi 'ATN' 'A-N' 'A?N' 'A.N' etc... Pour pouvoir détecter uniquement 'ARN' et 'ADN', on utilise des classes de caractères. </p>
<h3>Les classes de caractères</h3>
<p>Une classe de caractères représente toutes les substitutions autorisées dans notre pattern. Une classe est écrite à l'aide des crochets <strong>[ ]</strong> et contient la séquence substitutif. Pour détecter soit le mot ADN ou ARN : </p>
<div class="highlight"><pre><span></span><code><span class="n">A</span><span class="o">[</span><span class="n">RD</span><span class="o">]</span><span class="n">N</span><span class="w"></span>
</code></pre></div>
<p>La classe '[RD]' signifie : <em>A cette endroit, le caractère est soit la lettre R, soit la lettre D</em>. Simple non ? Mais maintenant, si au lieu de R et D, vous voulez toutes les lettres de l'alphabet ?</p>
<div class="highlight"><pre><span></span><code><span class="n">A</span><span class="o">[</span><span class="n">ABCDEFGIJKLMNOPQRSTUVWXYZ</span><span class="o">]</span><span class="n">N</span><span class="w"></span>
</code></pre></div>
<p>Ohé... Bein là, ça commence à faire lourd! Heureusement, les classes de caractères connaissent leurs alphabets. Cette expression peut être écrite : </p>
<div class="highlight"><pre><span></span><code>A[A-Z]N
</code></pre></div>
<p>On peut faire la même chose pour les minuscules et les chiffres. </p>
<div class="highlight"><pre><span></span><code>[a-z] de a à z
[0-9] de 0 à 9
[b-k] de b à k
[2-5] de 2 à 5
</code></pre></div>
<p>Bien entendu, on peut tout combiner. </p>
<div class="highlight"><pre><span></span><code>[a-zA-Z] de a à z et de A à Z
[a-zA-Z0-9] Tous les caractères alpha numérique
</code></pre></div>
<p>Il est enfin possible d'inverser la sélection avec le chapeau [ ^ ]. </p>
<div class="highlight"><pre><span></span><code>[^a-z] Tous les caractères QUI NE SONT PAS de a à z
</code></pre></div>
<p>Attention, le chapeau entre crochet n'a pas du tout la même signification qu'à l’extérieur des crochets.</p>
<h3>Chapeau et dollar</h3>
<p>Imaginez que vous voulez faire un détecteur de politesse dans un e-mail. Vous voulez tester si les messages commencent bien par <em>bonjour</em> et se terminent par <em>merci</em>. Pour réaliser cette prouesse technique, vous avez le symbole [^] signifiant '<em>rien avant</em>'. Et le symbole [$] signifiant '<em>rien après</em>'.</p>
<div class="highlight"><pre><span></span><code>Bonjour
</code></pre></div>
<blockquote>
<p><strong>Bonjour</strong> professeur, connaissez vous l'étymologie du mot "<strong>Bonjour</strong>" ? Merci</p>
</blockquote>
<div class="highlight"><pre><span></span><code>^Bonjour
</code></pre></div>
<blockquote>
<p><strong>Bonjour</strong> professeur, connaissez vous l'étymologie du mot "Bonjour" ? Merci</p>
</blockquote>
<div class="highlight"><pre><span></span><code><span class="nv">Merci</span><span class="p">$</span><span class="w"></span>
</code></pre></div>
<blockquote>
<p>Bonjour professeur, connaissez vous l'étymologie du mot "Bonjour" ? <strong>Merci</strong></p>
</blockquote>
<h3>Les quantificateurs</h3>
<p>Les quantificateurs sont les symboles: [ * + ? ].
Un quantificateur applique une règle au caractère qui le précède. (J'ai mis du temps à comprendre...) </p>
<h4>Le point d'interrogation</h4>
<p>Le point d’interrogation signifie : <em>le caractères est présent ou non</em>.
Par exemple, si je veux chercher toutes les occurrences du mot <em>ARN</em> ou <em>ARNm</em> </p>
<div class="highlight"><pre><span></span><code>ARNm?
</code></pre></div>
<blockquote>
<p>On dit <strong>ARN</strong> ou <strong>ARNm</strong> ?</p>
</blockquote>
<h4>L' étoile</h4>
<p>L'étoile signifie : <em>le caractère peut être absent ou répété une infinité de fois</em>.
Par exemple si je veux récupérer toutes les occurrences du mot <em>Broom</em> à <em>Broooooom</em>! </p>
<div class="highlight"><pre><span></span><code>BRo*M
</code></pre></div>
<blockquote>
<p>Démarrage du faucon millénium : <strong>BRooM</strong>!<br>
Démarrage du faucon millénium : <strong>BRoooooM</strong>!<br>
Démarrage du faucon millénium : <strong>BRM</strong>!.. WTF!?</p>
</blockquote>
<h4>le plus</h4>
<p>Dans l'exemple précédent, le pattern détecte aussi le mot "BRM". Le caractère "plus" et comme l'étoile, mais signifie : <em>le caractère doit être présent une fois ou répété une infinité de fois</em>. </p>
<div class="highlight"><pre><span></span><code>BRo+M
</code></pre></div>
<blockquote>
<p>Démarrage du faucon millénium : <strong>BRooM</strong>!<br>
Démarrage du faucon millénium : <strong>BRoooooM</strong>!<br>
Démarrage du faucon millénium : BRM!.. haha!</p>
</blockquote>
<p>Maintenant, que se passe-t-il si le caractère qui précède est un point, comme vu plus haut. </p>
<div class="highlight"><pre><span></span><code>BR.+M
</code></pre></div>
<blockquote>
<p>Démarrage du faucon millénium : <strong>BRiiiiiM</strong>!<br>
Démarrage du faucon millénium : <strong>BRaaaaaaM</strong>!<br>
Démarrage du faucon millénium : <strong>BRaaaiiiiyaaaaamaaaM</strong>! </p>
</blockquote>
<p>Oui, c'est magique! Cette expression régulière signifie : '<em>répète n’importe quel caractères une ou plusieurs fois</em>'.<br>
Et vous pouvez l'appliquer au point, mais aussi à une classe de caractère. Dans l'exemple suivant, on répète une lettre majuscule: </p>
<div class="highlight"><pre><span></span><code>[A-Z]+
</code></pre></div>
<p>Et si je veux détecter la répétition d'un mot ou d'un groupe de caractère ? Il suffit d'utiliser les parenthèses. Par exemple : </p>
<div class="highlight"><pre><span></span><code>(chat)+
</code></pre></div>
<blockquote>
<p><strong>chatchatchatchatchat</strong></p>
</blockquote>
<p>Et pour finir, on peut spécifier le nombre de répétition à l'aide des accolades <em>{}</em></p>
<div class="highlight"><pre><span></span><code>(chat){3} # 3 exactement
</code></pre></div>
<blockquote>
<p><strong>chatchatchat</strong>chatchat</p>
</blockquote>
<div class="highlight"><pre><span></span><code>(chat){3,5} # 3 à 5 fois
(chat)(3,) # Au minimum 3
</code></pre></div>
<h3>Les classes abrégées</h3>
<p>Pour finir, afin d'éviter de se fouler les doigts à écrire de longs patterns, vous pouvez utiliser ces raccourcis : </p>
<div class="highlight"><pre><span></span><code>\d # "digit" signifie [0-9]
\D # "Not digit" signifie [^0-9]
\w # "word" signifie [a-zA-Z0-9_]
\W # "Not world" signifie [^a-zA-Z0-9_]
\t # Tabulation
\n # Saut de ligne
\r # Retour chariot
\s # Espace blanc
\S # N'est pas un espace blanc
</code></pre></div>
<h3>Où utiliser les expressions régulières ?</h3>
<p>Partout!! Les expressions régulières vous vous permettre de faire des extractions de texte, des remplacements, des tests de validité sur des emails ou des IPs, des filtres pour vos logs systèmes et bien d'autre utilisation! L'autre jour, j'ai failli faire un malaise en voyant une collègue remplacer lignes après lignes, dans World, des numéros de titre...! En 2 secondes, c’était bouclé depuis sublime text!<br>
Mais les expressions régulières, c'est surtout l'apanage des ninja sous linux. Avec la commande <strong>grep</strong> et <strong>sed</strong> et surtout le langage <strong>Perl</strong> vous allez pouvoir épater la galerie! Il ne vous reste plus qu'à vous entrainer! Souvenez vous, dès que vous faites une tâche répétitive sur du texte, il s'agit sûrement d'un boulot pour un regexp.</p>
<hr>
<h4>Référence</h4>
<p><a href="http://fr.openclassrooms.com/informatique/cours/concevez-votre-site-web-avec-php-et-mysql/memento-des-expressions-regulieres">openclassrooms.com</a> <br>
<a href="http://fr.wikipedia.org/wiki/Expression_rationnelle">wikipedia</a> <br>
<a href="http://www.expreg.com/">http://www.expreg.com/</a> </p>Pygal, pour faire des graphiques en vectoriel !2014-06-23T18:25:30+02:002014-06-23T18:25:30+02:00Sacha Schutztag:dridk.me,2014-06-23:/pygal.html<!-- <p class="img-header">
<img src="../images/post5/header.png">
</p>
-->
<p>Il existe plusieurs façons de créer de jolis graphiques avec python. La plus connue est bien entendu <a href="http://matplotlib.org/">matplotlib</a> qui permet de faire du simple camembert au super graphique 3D isobarique spéctromotogramique. (je vous rassure ça veux rien dire). Il y en a aussi d'autres, moins connus que je cite en …</p><!-- <p class="img-header">
<img src="../images/post5/header.png">
</p>
-->
<p>Il existe plusieurs façons de créer de jolis graphiques avec python. La plus connue est bien entendu <a href="http://matplotlib.org/">matplotlib</a> qui permet de faire du simple camembert au super graphique 3D isobarique spéctromotogramique. (je vous rassure ça veux rien dire). Il y en a aussi d'autres, moins connus que je cite en exemple : <a href="http://pyqwt.sourceforge.net/">pyQwt</a>, <a href="https://plot.ly/api/">plotly</a>, <a href="https://pypi.python.org/pypi/vincent/0.1.6">Vincent</a> ( J'en parlerai dans un prochain post), <a href="http://pyla.codeplex.com/">pyla</a>, <a href="http://www.advsofteng.com/">chartDirector</a> etc...
Sans utiliser python, il y a aussi le <a href="http://www.r-project.org/">langage R</a> qui est un outil extrêmement puissant pour faire des statistiques et des graphiques scientifiques. Et enfin, <a href="http://www.gnuplot.info/">gnuplot</a>, logiciel à part entière, que vous exécutez directement depuis la console.
Dans ce poste, on va parler d'une n-ième <em>chart library</em>, que j'affectionne tout particulièrement, tant son rendu est stylé! Il s'agit de <a href="http://pygal.org/">pygal</a>, une librairie qui va non seulement nous générer des graphiques super classes, mais va les générer dans un format vectoriel! </p>
<h3>Des images vectorielles ?</h3>
<p>Bon, au cas ou vous ne savez pas ce qu'est du vectoriel, je vous l'explique rapidement. </p>
<h4>Image matricielle</h4>
<p>Les images aux formats <em>.png </em>.bmp, *.jpeg etc... sont des images matricielles. C'est à dire qu'elles sont définies par un tableau contenant la couleur des pixels. Par exemple une image de 3x3 pixels contiendra : </p>
<div class="highlight"><pre><span></span><code>bleu - blanc - rouge
bleu - blanc - rouge
bleu - blanc - rouge
</code></pre></div>
<p>Les différents formats (<em>.png </em>.bmp, *.jpeg), représentent différents algorithmes pour stocker et compresser ces informations. </p>
<h4>Image vectorielle</h4>
<p>Les images aux formats <em>.svg sont des images vectorielles. Il existe d'autres formats propriétaires comme </em>.ai (Adobe illustrator). mais retenez <em>.svg qui est un standard libre.<br>
Ces images sont définies par leurs </em>façons d'être dessiné* grâce à des objets géométriques simples. A contrario des images matricielles, l'image vectorielle sera constituée d'une série d'action. </p>
<div class="highlight"><pre><span></span><code>Rectangle(couleur=bleu, largeur=3, longueur = 2)
Rectangle(couleur=blanc,largeur=3, longueur = 2)
Rectangle(couleur=rouge, largeur=3, longueur = 2)
</code></pre></div>
<p>Toutes ces règles sont en fait écrites en xml, et ça donne plutôt ça :</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?xml version="1.0" encoding="utf-8"?></span>
<span class="nt"><svg</span> <span class="na">xmlns=</span><span class="s">"http://www.w3.org/2000/svg"</span> <span class="na">version=</span><span class="s">"1.1"</span> <span class="na">width=</span><span class="s">"300"</span> <span class="na">height=</span><span class="s">"200"</span><span class="nt">></span>
<span class="nt"><rect</span> <span class="na">width=</span><span class="s">"100"</span> <span class="na">height=</span><span class="s">"80"</span> <span class="na">x=</span><span class="s">"0"</span> <span class="na">y=</span><span class="s">"70"</span> <span class="na">fill=</span><span class="s">"green"</span> <span class="nt">/></span>
<span class="nt"></svg></span>
</code></pre></div>
<p>Les images vectorielles ont ainsi plusieurs avantages par rapport au images matricielles. Tout d'abord elle n'ont pas de résolution. A partir d'une image vectorielle, vous pouvez faire un icône ou un poster de 10 mètres sans jamais perdre de résolution. Également, de part leurs syntaxes xml, ils sont facilement éditables. Et devinez quoi ? Vous pouvez même y mettre du javascript pour faire des animations.
Ci-dessous, deux images, l'une vectorielle et l'autre matricielle. Vous pouvez les ouvrir séparément et zoomer dessus pour voir la différence. Enfin, vous la voyez déjà ! </p>
<p align="center">
<img src="/images/post5/vectoriel.svg" width="100px" alt="vectoriel" />
<img src="/images/post5/matriciel.png" width="100px" alt="matriciel"/>
</p>
<h3>Premier pas avec pygal</h3>
<h4>Installation</h4>
<p>Comme d'habitude ...</p>
<div class="highlight"><pre><span></span><code>pip install pygal
</code></pre></div>
<p>Attention, pour pouvoir exporter vos données vectorielles en <em>.png via </em><em>render_to_png</em>*, vous devez installer : </p>
<div class="highlight"><pre><span></span><code>pip install CairoSVG tinycss cssselect
</code></pre></div>
<h4>Création d'un <del>Livarot</del> Camembert</h4>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">pygal</span>
<span class="n">pie_chart</span> <span class="o">=</span> <span class="n">pygal</span><span class="o">.</span><span class="n">Pie</span><span class="p">()</span>
<span class="n">pie_chart</span><span class="o">.</span><span class="n">title</span> <span class="o">=</span> <span class="s1">'Activity'</span>
<span class="n">pie_chart</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s1">'Sleep'</span><span class="p">,</span> <span class="mi">60</span><span class="p">)</span>
<span class="n">pie_chart</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s1">'blog'</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span>
<span class="n">pie_chart</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s1">'code'</span><span class="p">,</span> <span class="mi">30</span><span class="p">)</span>
<span class="n">pie_chart</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s1">'study'</span><span class="p">,</span> <span class="mi">9</span><span class="p">)</span>
</code></pre></div>
<p>Faites maintenant <strong>pie_chart.render()</strong> Pour générer le code xml de votre image vectorielle... Bon, c'est juste du code xml qui s'affiche... Mais heureusement, pygal propose plusieurs méthodes : </p>
<div class="highlight"><pre><span></span><code>- pie_chart.render_in_browser() //Vous l'ouvrira dans le browser
- pie_chart.render_to_file("mypie.svg") //Création du fichier mypie.svg
- pie_chart.render_to_png("mypie.png") //Création du fichier mypie.png
</code></pre></div>
<p>Voilà le résultat final quand je l'insère dans mon code html de cette façon : </p>
<div class="highlight"><pre><span></span><code> <embed src="/images/post5/mypie.svg" type="image/svg+xml" width="100px" />
</code></pre></div>
<p><embed src="/images/post5/mypie.svg" type="image/svg+xml" /></p>
<p>Oui c'est beau ! J'espère que vous avez remarqué l'interactivité du graphique lorsque vous passez la souris dessus. <br>
Mais sinon, à part des camemberts, on peut faire tout un tas d'autres graphiques. </p>
<h4>Autres graphiques</h4>
<p>Je vous met dans cette section, une série de graphique réalisable avec pygal. Il y en a plein d'autre! Allez faire un tour sur cette page : <a href="http://pygal.org/chart_types/#idbar-charts-histograms">pygal charts type</a></p>
<h6>Line Charts</h6>
<div class="highlight"><pre><span></span><code>line_chart = pygal.Line()
line_chart.title = 'Browser usage evolution (in %)'
line_chart.x_labels = map(str, range(2002, 2013))
line_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1])
line_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3])
line_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1])
line_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5])
line_chart.render_to_file("line_chart.svg")
</code></pre></div>
<p><a href="/images/post5/line_chart.svg">Afficher le graphique</a></p>
<h4>Bar Charts</h4>
<div class="highlight"><pre><span></span><code>bar_chart = pygal.Bar()
bar_chart.title = 'Browser usage evolution (in %)'
bar_chart.x_labels = map(str, range(2002, 2013))
bar_chart.add('Firefox', [None, None, 0, 16.6, 25, 31, 36.4, 45.5, 46.3, 42.8, 37.1])
bar_chart.add('Chrome', [None, None, None, None, None, None, 0, 3.9, 10.8, 23.8, 35.3])
bar_chart.add('IE', [85.8, 84.6, 84.7, 74.5, 66, 58.6, 54.7, 44.8, 36.2, 26.6, 20.1])
bar_chart.add('Others', [14.2, 15.4, 15.3, 8.9, 9, 10.4, 8.9, 5.8, 6.7, 6.8, 7.5])
bar_chart.render_to_file("bar_chart.svg")
</code></pre></div>
<p><a href="images/post5/bar_chart.svg">Afficher le graphique</a></p>
<h4>Scatter plot</h4>
<div class="highlight"><pre><span></span><code>xy_chart = pygal.XY(stroke=False)
xy_chart.title = 'Correlation'
xy_chart.add('A', [(0, 0), (.1, .2), (.3, .1), (.5, 1), (.8, .6), (1, 1.08), (1.3, 1.1), (2, 3.23), (2.43, 2)])
xy_chart.add('B', [(.1, .15), (.12, .23), (.4, .3), (.6, .4), (.21, .21), (.5, .3), (.6, .8), (.7, .8)])
xy_chart.add('C', [(.05, .01), (.13, .02), (1.5, 1.7), (1.52, 1.6), (1.8, 1.63), (1.5, 1.82), (1.7, 1.23), (2.1, 2.23), (2.3, 1.98)])
xy_chart.render_to_file("scatter_plot.svg")
</code></pre></div>
<p><a href="images/post5/scatter_plot.svg">Afficher le graphique</a></p>
<h4>Box plot</h4>
<div class="highlight"><pre><span></span><code>box_plot = pygal.Box()
box_plot.title = 'V8 benchmark results'
box_plot.add('Chrome', [6395, 8212, 7520, 7218, 12464, 1660, 2123, 8607])
box_plot.add('Firefox', [7473, 8099, 11700, 2651, 6361, 1044, 3797, 9450])
box_plot.add('Opera', [3472, 2933, 4203, 5229, 5810, 1828, 9013, 4669])
box_plot.add('IE', [43, 41, 59, 79, 144, 136, 34, 102])
box_plot.render_to_file("box_plot.svg")
</code></pre></div>
<p><a href="images/post5/box_plot.svg">Afficher le graphique</a></p>
<p>Voilà, fini pour cette article! Je vais pas me casser la tête à faire plus, car la <a href="http://pygal.org/documentation/">documentation officiel</a> est parfaitement réalisée. Vous pouvez par exemple, customiser vos graphiques en changeant de thème, ou créer des thèmes personnalisés. Ou encore modifier le rendu en jouant sur les marges, les labels , les dimensions etc...</p>
<hr>
<h4>Référence</h4>
<p><a href="http://pygal.org/">pygal.org</a> <br>
<a href="http://pygal.org/documentation/">pygal Documentation</a> <br>
<a href="http://cabaret.pygal.org/">teste en ligne de pygal</a> </p>MongoDB, la base de donnée pour dire adieu à Sql.2014-06-14T16:51:24+02:002014-06-14T16:51:24+02:00Sacha Schutztag:dridk.me,2014-06-14:/MongoDB.html<!--
<p class="img-header">
<img src="/images/post4/header.png">
</p> -->
<p><a href="http://www.MongoDB.org/">MongoDB</a> est un système de gestion de base de données ou <a href="http://fr.wikipedia.org/wiki/Syst%C3%A8me_de_gestion_de_base_de_donn%C3%A9es">SGBD</a>, comme <a href="http://fr.wikipedia.org/wiki/Mysql">Mysql</a> ou <a href="http://fr.wikipedia.org/wiki/Postgresql">PostgreSql</a>, mais dont le mécanisme est complètement différent. Fini le temps ou il fallait créer un schéma de tables relationnelles et créer des requêtes Sql complexes. Grâce à MongoDB vous allez pouvoir stocker vos données …</p><!--
<p class="img-header">
<img src="/images/post4/header.png">
</p> -->
<p><a href="http://www.MongoDB.org/">MongoDB</a> est un système de gestion de base de données ou <a href="http://fr.wikipedia.org/wiki/Syst%C3%A8me_de_gestion_de_base_de_donn%C3%A9es">SGBD</a>, comme <a href="http://fr.wikipedia.org/wiki/Mysql">Mysql</a> ou <a href="http://fr.wikipedia.org/wiki/Postgresql">PostgreSql</a>, mais dont le mécanisme est complètement différent. Fini le temps ou il fallait créer un schéma de tables relationnelles et créer des requêtes Sql complexes. Grâce à MongoDB vous allez pouvoir stocker vos données un peu comme vous le feriez dans un fichier <a href="http://fr.wikipedia.org/wiki/JSON">JSON</a>. C'est à dire, une sorte de dictionnaire géant composé de clés et de valeurs. Ces données peuvent ensuite être exploitées par du <a href="http://fr.wikipedia.org/wiki/Javascript">javascript</a>, directement intégré dans MongoDB, mais peuvent également être exploitées par d'autre langage comme <a href="http://fr.wikipedia.org/wiki/Python_%28langage%29">python</a>. </p>
<h3>Collection et Documents</h3>
<p>Avant de commencer à voir en détail le fonctionnement de MongoDB, il faut comprendre différentes notions. MongoDB stocke ses données sous le même format qu'un document JSON. Pour être plus exact, c'est la version binaire du JSON appelé <a href="http://fr.wikipedia.org/wiki/BSON">BSON</a>. Mais alors, c'est quoi un document JSON ? </p>
<h4>Documents</h4>
<p>Un document JSON, c'est simplement un ensemble de clés et de valeurs dont la notation est la suivante : </p>
<div class="highlight"><pre><span></span><code>{
"first_name": "Richard",
"last_name": "Dawkins",
"job":"ethologist",
"age": 73
}
</code></pre></div>
<p>Dans cette exemple, <em>first_name</em> est la <strong>clé</strong> , <em>Richard</em> est la <strong>valeur</strong>.<br>
Plusieurs documents peuvent être imbriqués ensemble pour former un documents plus complexe : </p>
<div class="highlight"><pre><span></span><code>{
"first_name": "Richard",
"last_name": "Dawkins",
"job":"ethologist",
"age": 73
address : {
"street":"33 panda street",
"city":"Oxford",
"country":"UK"
}
}
</code></pre></div>
<p>Il est également possible de mettre des listes : </p>
<div class="highlight"><pre><span></span><code>{
"first_name": "Richard",
"last_name": "Dawkins",
"job":"ethologist",
"age": 73
books: [
{"title": "Selfish Gene", "date":"1976"},
{"title": "The blind watchmaker", "date":"1956"},
{"title":"The magic of Reality", date:"2011", "page_count":200}
]
</code></pre></div>
<p>Si vous regardez la liste de livres, vous remarquerez qu'il n'est pas nécessaire de respecter la cohérence des champs d'une base Sql. En effet, il y a deux champs <em>title</em> et <em>date</em> pour les deux premiers livres, et 3 pour le dernier. </p>
<h4>Collection</h4>
<p>Une collection est tous simplement un ensemble de document. On peut la comparer à une table. Par exemple, une collection de 50 auteurs contiendra 50 documents comme défini plus haut. MongoDB intègre des index notés <strong>_id</strong> unique pour chaque document. </p>
<div class="highlight"><pre><span></span><code> {
"_id" : 0
"first_name": "Richard",
"last_name": "Dawkins",
},
{
"_id" : 1
"first_name": "Stephen",
"last_name": "Jay Gould",
},
{
"_id" : 2
"first_name": "François",
"last_name": "Jacob",
},
</code></pre></div>
<p>Sachez que le format JSON, provient directement du langage Javascript. D'ailleurs JSON veut dire <strong>J</strong>ava<strong>S</strong>cript <strong>O</strong>bject <strong>N</strong>otation. C'est pour cette raison que MongoDB utilise javascript par defaut afin de manipuler sa base. </p>
<h1>Premier pas avec MongoDB</h1>
<h3>Installation</h3>
<p>Si vous êtes sous Linux ubuntu : </p>
<div class="highlight"><pre><span></span><code>sudo apt-get install MongoDB
</code></pre></div>
<p>Pour les autres OS, je vous invite à le télécharger depuis <a href="http://www.MongoDB.org/downloads">la page officiel</a><br>
MongoDB est livré avec plusieurs binaires. On retiendra <strong>mongod</strong> le serveur, et <strong>mongo</strong> le client console. </p>
<h3>Lancement du serveur</h3>
<p>Sous linux, un daemon est automatiquement crée. Pour l’exécuter : </p>
<div class="highlight"><pre><span></span><code>sudo /etc/init.d/mongod stop
</code></pre></div>
<p>Pour les autres, il suffit d’exécuter <strong>mongod</strong> en spécifiant un chemin de stockage:</p>
<div class="highlight"><pre><span></span><code>mongod --dbpath C:/mongoData
</code></pre></div>
<h3>Se connecter au serveur</h3>
<p>Tout d'abord, exécuter le client <strong>mongo</strong> depuis votre terminal. Par défaut, il se connecte au serveur <strong>mongod</strong> en localhost sur le port 27017. </p>
<div class="highlight"><pre><span></span><code><span class="n">schutz</span><span class="nv">@brest</span><span class="err">:</span><span class="o">~/</span><span class="n">Home</span><span class="err">$</span><span class="w"> </span><span class="n">mongo</span><span class="w"></span>
<span class="n">MongoDB</span><span class="w"> </span><span class="n">shell</span><span class="w"> </span><span class="nl">version</span><span class="p">:</span><span class="w"> </span><span class="mf">2.4.9</span><span class="w"></span>
<span class="n">connecting</span><span class="w"> </span><span class="k">to</span><span class="err">:</span><span class="w"> </span><span class="n">test</span><span class="w"></span>
<span class="n">Server</span><span class="w"> </span><span class="n">has</span><span class="w"> </span><span class="n">startup</span><span class="w"> </span><span class="nl">warnings</span><span class="p">:</span><span class="w"> </span>
<span class="n">Sat</span><span class="w"> </span><span class="n">Jun</span><span class="w"> </span><span class="mi">14</span><span class="w"> </span><span class="mi">13</span><span class="err">:</span><span class="mi">47</span><span class="err">:</span><span class="mf">38.813</span><span class="w"> </span><span class="o">[</span><span class="n">initandlisten</span><span class="o">]</span><span class="w"> </span>
<span class="n">Sat</span><span class="w"> </span><span class="n">Jun</span><span class="w"> </span><span class="mi">14</span><span class="w"> </span><span class="mi">13</span><span class="err">:</span><span class="mi">47</span><span class="err">:</span><span class="mf">38.813</span><span class="w"> </span><span class="o">[</span><span class="n">initandlisten</span><span class="o">]</span><span class="w"> </span><span class="o">**</span><span class="w"> </span><span class="nl">NOTE</span><span class="p">:</span><span class="w"> </span><span class="n">This</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="mi">32</span><span class="w"> </span><span class="nc">bit</span><span class="w"> </span><span class="n">MongoDB</span><span class="w"> </span><span class="nc">binary</span><span class="p">.</span><span class="w"></span>
<span class="n">Sat</span><span class="w"> </span><span class="n">Jun</span><span class="w"> </span><span class="mi">14</span><span class="w"> </span><span class="mi">13</span><span class="err">:</span><span class="mi">47</span><span class="err">:</span><span class="mf">38.813</span><span class="w"> </span><span class="o">[</span><span class="n">initandlisten</span><span class="o">]</span><span class="w"> </span><span class="o">**</span><span class="w"> </span><span class="mi">32</span><span class="w"> </span><span class="nc">bit</span><span class="w"> </span><span class="n">builds</span><span class="w"> </span><span class="k">are</span><span class="w"> </span><span class="n">limited</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="k">less</span><span class="w"> </span><span class="k">than</span><span class="w"> </span><span class="mi">2</span><span class="n">GB</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="k">data</span><span class="w"> </span><span class="p">(</span><span class="ow">or</span><span class="w"> </span><span class="k">less</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="o">--</span><span class="n">journal</span><span class="p">).</span><span class="w"></span>
<span class="n">Sat</span><span class="w"> </span><span class="n">Jun</span><span class="w"> </span><span class="mi">14</span><span class="w"> </span><span class="mi">13</span><span class="err">:</span><span class="mi">47</span><span class="err">:</span><span class="mf">38.813</span><span class="w"> </span><span class="o">[</span><span class="n">initandlisten</span><span class="o">]</span><span class="w"> </span><span class="o">**</span><span class="w"> </span><span class="n">See</span><span class="w"> </span><span class="nl">http</span><span class="p">:</span><span class="o">//</span><span class="n">dochub</span><span class="p">.</span><span class="n">MongoDB</span><span class="p">.</span><span class="n">org</span><span class="o">/</span><span class="n">core</span><span class="o">/</span><span class="mi">32</span><span class="nc">bit</span><span class="w"></span>
<span class="n">Sat</span><span class="w"> </span><span class="n">Jun</span><span class="w"> </span><span class="mi">14</span><span class="w"> </span><span class="mi">13</span><span class="err">:</span><span class="mi">47</span><span class="err">:</span><span class="mf">38.813</span><span class="w"> </span><span class="o">[</span><span class="n">initandlisten</span><span class="o">]</span><span class="w"></span>
</code></pre></div>
<h3>Afficher les bases de données</h3>
<p>Pour afficher les bases de données disponibles, utilisez <strong>show dbs</strong>. Normalement vous devriez avoir une base <strong>local</strong> propre à mongo et une base <strong>test</strong>: </p>
<div class="highlight"><pre><span></span><code><span class="k">show</span><span class="w"> </span><span class="nv">dbs</span><span class="w"></span>
<span class="nv">local</span><span class="w"> </span><span class="mi">0</span>.<span class="mi">03125</span><span class="nv">GB</span><span class="w"></span>
<span class="nv">test</span><span class="w"> </span><span class="ss">(</span><span class="nv">empty</span><span class="ss">)</span><span class="w"></span>
</code></pre></div>
<h3>Création d'une base de donnée</h3>
<p>Pour continuer ce tutoriel, je veux créer une base de donnée <strong>medical</strong> , et créer une collection de <strong>patients</strong>. Chaque patient sera défini par son <strong>nom</strong>, <strong>prenom</strong> et sa <strong>date de naissance</strong>.
Pour créer notre première base de données : </p>
<div class="highlight"><pre><span></span><code>use medical
</code></pre></div>
<p>Vous pouvez faire <strong>db</strong> pour voir la base de donnée courante. Attention, si vous faites <strong>show dbs</strong>, vous ne verrez pas encore votre base. En effet, mongo attend d'avoir du contenu pour créer votre base. </p>
<h3>Insertion</h3>
<p>Pour créer une collection, il suffit simplement d'ajouter un patient. Par exemple pour: </p>
<div class="highlight"><pre><span></span><code>{
"nom":"Dupond",
"prenom":"Jean Claude",
"ddn": new Date('May 18, 1984')
}
</code></pre></div>
<p>Je fais simplement : </p>
<div class="highlight"><pre><span></span><code>db.patients.insert({"nom":"jay gould", "prenom":"stephen", new Date('May 18, 1984')})
</code></pre></div>
<p>La collection <em>patients</em> se crée automatiquement lors de la première utilisation. Si vous faite maintenant : </p>
<div class="highlight"><pre><span></span><code>db.patients.find()
</code></pre></div>
<p>Vous pouvez voir le document que vous venez d'ajouter. Notez que MongoDB ajoute automatiquement un <strong>_index</strong> si rien n'est spécifié.<br>
En guise d'exemple, on va remplir notre collections en répétant cette procédure 50 fois. </p>
<div class="highlight"><pre><span></span><code><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="k">var</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o"><</span><span class="mi">50</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">){</span><span class="w"></span>
<span class="w"> </span><span class="n">db</span><span class="o">.</span><span class="n">patients</span><span class="o">.</span><span class="n">insert</span><span class="p">({</span><span class="s2">"nom"</span><span class="p">:</span><span class="s2">"jay gould"</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="s2">"prenom"</span><span class="p">:</span><span class="s2">"stephen"</span><span class="p">,</span><span class="w"> </span><span class="s2">"age"</span><span class="p">:</span><span class="w"> </span><span class="n">i</span><span class="p">})</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>
<p>Vérifions le nombre de patients : </p>
<div class="highlight"><pre><span></span><code>db.patients.count()
</code></pre></div>
<h3>Lister la collection</h3>
<h4>find(critère, projection)</h4>
<p>Utiliser <strong>find()</strong> pour retourner toute la liste de la collection patients.</p>
<div class="highlight"><pre><span></span><code> db.patients.find()
</code></pre></div>
<p>Pour récupérer les patients dont l'age = 5 </p>
<div class="highlight"><pre><span></span><code>db.patients.find({age:5})
</code></pre></div>
<p>On peut aussi utiliser des expressions régulières. Par exemple, tous les prénoms commençant par "<em>j</em>"</p>
<div class="highlight"><pre><span></span><code>db.patients.find({prenom: /^j*/})
</code></pre></div>
<p>Pour récupérer les patients dont l'age est supérieur à 40</p>
<div class="highlight"><pre><span></span><code><span class="x"> db.patients.find(</span><span class="cp">{</span><span class="nf">age</span><span class="o">:</span><span class="cp">{</span><span class="nv">$gt</span><span class="o">:</span><span class="m">40</span><span class="cp">}}</span><span class="x">)</span>
</code></pre></div>
<p><strong>$gt</strong> est un mot clef de mongo qui veut dire <em>greater than</em> (<em>supérieur à</em>). Pour voir <a href="http://docs.MongoDB.org/manual/reference/operator/query/">la liste complète c'est ici</a>. </p>
<p>Pour récupérer un seul élément (le premier) , utiliser <strong>findOne</strong> </p>
<div class="highlight"><pre><span></span><code><span class="x">db.patients.findOne(</span><span class="cp">{</span><span class="nf">age</span><span class="o">:</span><span class="cp">{</span><span class="nv">$gt</span><span class="o">:</span><span class="m">40</span><span class="cp">}}</span><span class="x">)</span>
</code></pre></div>
<p>Pour récupérer les patients dont l'âge est 5 ou 10 : </p>
<div class="highlight"><pre><span></span><code><span class="x">db.patients.find(</span><span class="cp">{</span><span class="nf">age</span><span class="o">:</span><span class="cp">{</span><span class="nv">$in</span><span class="o">:[</span><span class="m">5</span><span class="o">,</span><span class="m">10</span><span class="o">]</span><span class="cp">}}</span><span class="x">)</span>
</code></pre></div>
<p>Pour récupérer uniquement certaine clé, on utilise l'argument <em>projection</em> de find(). Par exemple, récupérer uniquement les noms des patients dont l'âge est supérieur à 40</p>
<div class="highlight"><pre><span></span><code><span class="x">db.patients.find(</span><span class="cp">{</span><span class="nf">age</span><span class="o">:</span><span class="cp">{</span><span class="nv">$gt</span><span class="o">:</span><span class="m">40</span><span class="cp">}}</span><span class="x">,</span><span class="cp">{</span><span class="s2">"nom"</span><span class="o">:</span><span class="kc">true</span><span class="cp">}</span><span class="x">)</span>
</code></pre></div>
<p>Pour limiter le nombre de résultat à 3 : </p>
<div class="highlight"><pre><span></span><code>db.patients.find().limit(3)
</code></pre></div>
<p>Pour ordonner la liste par âge décroissant. -1 pour décroissant et 1 pour croissant.</p>
<div class="highlight"><pre><span></span><code><span class="s s-Atom">db</span><span class="p">.</span><span class="s s-Atom">patients</span><span class="p">.</span><span class="nf">find</span><span class="p">().</span><span class="nf">sort</span><span class="p">(</span><span class="s s-Atom">age</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div>
<h3>Modifier la collection</h3>
<h4>update(query, update, options)</h4>
<p>Remplacer tous les prénoms <em>stephen</em> par <em>boby</em></p>
<div class="highlight"><pre><span></span><code><span class="x">db.patients.update(</span><span class="cp">{</span><span class="s2">"prenom"</span><span class="o">:</span><span class="s2">"stephen"</span><span class="cp">}</span><span class="x">,</span><span class="cp">{</span><span class="nv">$set</span><span class="o">:</span><span class="cp">{</span><span class="s2">"prenom"</span><span class="o">:</span><span class="s2">"boby"</span><span class="cp">}}</span><span class="x">,</span><span class="cp">{</span><span class="nf">multi</span><span class="o">:</span><span class="kc">true</span><span class="cp">}</span><span class="x">)</span>
</code></pre></div>
<p>Ajoute une clé <em>sexe</em> à tous les patients </p>
<div class="highlight"><pre><span></span><code><span class="x">db.patients.update(</span><span class="cp">{</span><span class="nf">prenom</span><span class="o">:</span><span class="s2">"boby"</span><span class="cp">}</span><span class="x">, </span><span class="cp">{</span><span class="nv">$set</span><span class="o">:</span><span class="cp">{</span><span class="na">sexe</span><span class="o">:</span><span class="s2">"male"</span><span class="cp">}}</span><span class="x">, </span><span class="cp">{</span><span class="nf">multi</span><span class="o">:</span><span class="kc">true</span><span class="cp">}</span><span class="x">)</span>
</code></pre></div>
<p>Ajoute un patient <em>olivier</em> s'il n'existe pas </p>
<div class="highlight"><pre><span></span><code><span class="x">db.patients.update(</span><span class="cp">{</span><span class="nf">prenom</span><span class="o">:</span><span class="s2">"olivier"</span><span class="cp">}</span><span class="x">, </span><span class="cp">{</span><span class="nv">$set</span><span class="o">:</span><span class="cp">{</span><span class="na">sexe</span><span class="o">:</span><span class="s2">"male"</span><span class="cp">}}</span><span class="x">, </span><span class="cp">{</span><span class="nf">upsert</span><span class="o">:</span><span class="kc">true</span><span class="cp">}</span><span class="x">)</span>
</code></pre></div>
<h4>save(document, writeConcern)</h4>
<p>La différence avec <strong>insert</strong> est que <strong>save</strong>, fait un <strong>update</strong> du document s'il existe déjà.</p>
<div class="highlight"><pre><span></span><code>db.patient.save({"prenom":"jean claude", "nom":"Van Damme"})
</code></pre></div>
<h3>Suppression</h3>
<h4>remove(query,justOne)</h4>
<p>Supprimer tous les patients qui s'appellent <em>olivier</em></p>
<div class="highlight"><pre><span></span><code>db.patients.remove({prenom:"olivier"})
</code></pre></div>
<h4>Supprimer la collection</h4>
<div class="highlight"><pre><span></span><code>db.patients.drop()
</code></pre></div>
<h4>Supprimer la base de donnée</h4>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="nt">use</span><span class="w"> </span><span class="nt">medical</span><span class="w"></span>
<span class="w"> </span><span class="nt">db</span><span class="p">.</span><span class="nc">runCommand</span><span class="o">(</span><span class="p">{</span><span class="n">dropDatabase</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">}</span><span class="o">);</span><span class="w"></span>
</code></pre></div>
<h1>Conclusion</h1>
<p>Voilà pour les bases de MongoDB. Il y a encore plein de chose à dire sur MongoDB. Comme l'<a href="http://docs.MongoDB.org/manual/core/aggregation-introduction/">agrégation</a> des données, La <a href="http://docs.MongoDB.org/manual/core/replication-introduction/">réplication</a> sur plusieurs serveurs ou la <a href="http://docs.MongoDB.org/manual/core/security-introduction/">sécurité</a>. Tous se trouve sur la <a href="http://docs.MongoDB.org/manual/">documentation officiel</a>.
Dans un prochain article, je m’intéresserai cette fois à l'interface entre python et MongoDB via <a href="http://api.MongoDB.org/python/current/">PyMongo</a>. Ce sera forcement un article court :D. Il faut que je jette aussi un coup d’œil à <a href="https://github.com/manuels/QtMongo">QtMongo</a>, une interface vers Qt/C++. </p>
<hr>
<h4>Référence</h4>
<p><a href="http://www.MongoDB.org/">MongoDB site officiel</a><br>
<a href="http://docs.MongoDB.org/manual/">MongoDB Documentation</a><br>
<a href="http://tuts.syrinxoon.net/tuts/installation-et-bases-de-MongoDB">Syrinxoon Tuts</a><br>
<a href="http://api.MongoDB.org/p">PyMongo</a></p>Module requests : Jouons avec Http et python2014-06-11T23:42:22+02:002014-06-11T23:42:22+02:00Sacha Schutztag:dridk.me,2014-06-11:/python-requests.html<!-- <p class="img-header">
<img src="images/post3/header.jpg">
</p> -->
<p><strong>Requests</strong> est un module python permettant d'utiliser le protocole http de façon ultra simple! Je l'ai découvert en voulant récupérer des données d'une page web au boulot à travers un proxy. Car en effet, il gère vraiment tout ! Les proxy, les cookies, ssl, les uploads multiparts et bien d'autres trucs …</p><!-- <p class="img-header">
<img src="images/post3/header.jpg">
</p> -->
<p><strong>Requests</strong> est un module python permettant d'utiliser le protocole http de façon ultra simple! Je l'ai découvert en voulant récupérer des données d'une page web au boulot à travers un proxy. Car en effet, il gère vraiment tout ! Les proxy, les cookies, ssl, les uploads multiparts et bien d'autres trucs sympas! Je vous propose dans ce poste, quelques exemples d'utilisations de cette librairie. Pour plus d'informations, il y a la <a href="http://fr.python-requests.org/en/latest/">page officiel en français.</a></p>
<h3>Installation</h3>
<p>Comme pour tous les modules python, je vous conseille d'utiliser <strong><a href="http://pip.readthedocs.org/en/latest/installing.html">pip</a></strong></p>
<div class="highlight"><pre><span></span><code>pip install requests
</code></pre></div>
<h3>Créer une requête</h3>
<p>Tout d'abord, importons le module Requests: </p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">requests</span>
</code></pre></div>
<p>Maintenant, essayons de récupérer la page de <a href="http://linuxfr.org/">linuxfr.org</a> et l'afficher dans le terminal. </p>
<div class="highlight"><pre><span></span><code>r = requests.get("http://linuxfr.org/")
print(r.text)
</code></pre></div>
<p>Voila, c'est tout simple ! Pour les autres verbes du protocole HTTP, il suffit de faire : </p>
<div class="highlight"><pre><span></span><code> r = requests.put("http://linuxfr.org/")
r = requests.delete("http://linuxfr.org/")
r = requests.patch("http://linuxfr.org/")
r = requests.post("http://linuxfr.org/")
r = requests.head("http://linuxfr.org/")
r = requests.options("http://linuxfr.org/")
</code></pre></div>
<h3>Utilisation d'un Proxy</h3>
<p>Si vous devez passer par un proxy, comme j'ai du le faire, c'est toujours aussi simple. </p>
<div class="highlight"><pre><span></span><code><span class="n">proxy</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">{</span><span class="ss">"http"</span><span class="err">:</span><span class="ss">"http://username:password@proxy:port"</span><span class="err">}</span><span class="w"></span>
<span class="n">r</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">requests</span><span class="p">.</span><span class="k">get</span><span class="p">(</span><span class="ss">"http://linuxfr.org/"</span><span class="p">,</span><span class="w"> </span><span class="n">proxies</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">proxy</span><span class="p">)</span><span class="w"></span>
</code></pre></div>
<h3>Lire la réponse</h3>
<p>Pour lire la réponse on a déjà vu <em>r.text</em> plus haut. Pour le reste, c'est toujours aussi simple, voici les plus sympas :</p>
<div class="highlight"><pre><span></span><code>r.text #Retourne le contenu en unicode
r.content #Retourne le contenu en bytes
r.json #Retourne le contenu sous forme json
r.headers #Retourne le headers sous forme de dictionnaire
r.status_code #Retourne le status code
</code></pre></div>
<h3>Envoyer des données</h3>
<p>Pour envoyer des données, toujours aussi simple. Par exemple pour l'envoi des données d'un formulaire : </p>
<div class="highlight"><pre><span></span><code>data = {"first_name":"Richard", "second_name":"Stallman"}
r = requests.post("http://linuxfr.org", data = data)
</code></pre></div>
<p>Pour envoyer une image par multipart, encore plus facile : </p>
<div class="highlight"><pre><span></span><code>file = {'file': open("photo.png", "rb")}
r = requests.post("http://linuxfr.org", files = file)
</code></pre></div>
<p>Bon, voila rapidement la base des fonctions du module requests. Qui, il faut l'avouer , est magique !! Je vous conseille vivement la lecture de <a href="http://fr.python-requests.org/en/latest/user/quickstart.html#creer-une-requete">cette page</a>, beaucoup plus détaillée. </p>
<hr>
<h4>Référence</h4>
<p><a href="http://fr.python-requests.org">fr.python-requests.org</a> <br>
<a href="http://docs.python-requests.org/en/v0.10.6/api/">docs.python-requests.org</a> </p>L'Open data en deux mots2014-04-27T00:06:39+02:002014-04-27T00:06:39+02:00Sacha Schutztag:dridk.me,2014-04-27:/open-data-en-deux-mots.html<!-- <p class="img-header">
<img src="../images/post2/header.jpg">
</p> -->
<p>L'<strong>Open Data</strong>, comme son nom l'indique, est un ensemble de données ouvertes sous <a href="http://fr.wikipedia.org/wiki/Open_Database_License">licence libre </a>, fournit par des organismes publiques ou privés. En d'autres mots, vous allez pouvoir utiliser gratuitement un tas de données, directement ou via une api, pour faire de la Recherche, des études statistiques et surtout …</p><!-- <p class="img-header">
<img src="../images/post2/header.jpg">
</p> -->
<p>L'<strong>Open Data</strong>, comme son nom l'indique, est un ensemble de données ouvertes sous <a href="http://fr.wikipedia.org/wiki/Open_Database_License">licence libre </a>, fournit par des organismes publiques ou privés. En d'autres mots, vous allez pouvoir utiliser gratuitement un tas de données, directement ou via une api, pour faire de la Recherche, des études statistiques et surtout... <strong>Des applications</strong>!
C'est vraiment le moment de surfer sur la vague de l'openData. Je ne connais pas encore les implications économiques sous-jacente, mais ça me fait plaisir de voir la philosophie de l'openSource se propager dans les plus hautes instances gouvernementales. Voici une liste de sites qui pourra vous être utiles.</p>
<h4>data.gouv.fr</h4>
<p>Le premier moteur de recherche d'opendata est le site du gouvernement : <a href="http://www.data.gouv.fr/">data.gouv.fr</a>. Il contient principalement des données publiques utilisables pour des applications mobiles, par exemple de transport en commun, mais surtout des données épidémiologiques. Je tape par exemple dans la barre de recherche : <em>sida</em> et j'obtiens plusieurs <em>base de données</em>, Notamment les causes de décès par SIDA de 1987 à 2010. Il me suffit de récupérer mes données CSV, de les importer dans un logiciel d'analyse <a href="http://www.r-project.org/">comme R</a>, et de faire de jolis graphiques pour frimer devant les virologistes.:D</p>
<h4>opendata.paris.fr</h4>
<p>Disponible à <a href="http://opendata.paris.fr/explore/">cette adressee</a>, contient plein de données sur paris. <a href="http://opendata.paris.fr/explore/dataset/mobilierstationnementparis2011/?tab=table">Vélib et Parking</a>, Résultats électoraux et bien d'autres. </p>
<h4>data.sncf.com</h4>
<p>La Sncf fournit aussi un <a href="http://data.sncf.com/">jolie site web</a> d'opendata. Je vais pouvoir enfin faire une application qui m’empêchera de
louper mon train.</p>
<h4>www.quandl.com</h4>
<p>Ce <a href="http://www.quandl.com">moteur de recherche</a>, est une version internationale, dans le style google, qui semble avoir beaucoup de succès. En attendant son rachat par g..., vous y retrouverez sûrement des données intéressantes. </p>
<h4>www.ign.fr</h4>
<p>Le <a href="http://www.ign.fr/institut/lign-lopen-data">site de l'ign</a> est l'outil qu'il vous faut si vous voulez faire de la cartographie. </p>
<hr>
<h4>Référence</h4>
<p><a href="http://lecubevert.fr/open-data-definitions-enjeux-et-perspectives/">L’OPEN DATA : DÉFINITION, ENJEUX ET PERSPECTIVES</a> <br>
<a href="http://www.data.gouv.fr/">data.gouv.fr</a><br>
<a href="http://opendata.paris.fr/explore/">opendata.paris.fr</a><br>
<a href="http://data.sncf.com/">data.sncf.com</a><br>
<a href="www.quandl.com">www.quandl.com</a><br>
<a href="http://www.ign.fr/institut/lign-lopen-data"> www.ign.fr</a> </p>Premier Blog avec Pelican2014-04-12T10:20:00+02:002014-04-12T10:20:00+02:00Sacha Schutztag:dridk.me,2014-04-12:/first-post.html<!-- <p class="img-header">
<img src="../images/post1/header.jpg">
</p> -->
<p>Hello, à tous !
Bon, j'ai enfin passé le cap de la création de blog. A vrai dire, j'avais déjà essayé auparavent d'autres systèmes de blog comme <a href="http://fr.wordpress.org/">wordpress</a> ou <a href="https://www.blogger.com/">blogger</a>. Mais j'ai pas tenu longtemps car je perdais vraiment tout mon temps à écrire du html et à checker le rendu …</p><!-- <p class="img-header">
<img src="../images/post1/header.jpg">
</p> -->
<p>Hello, à tous !
Bon, j'ai enfin passé le cap de la création de blog. A vrai dire, j'avais déjà essayé auparavent d'autres systèmes de blog comme <a href="http://fr.wordpress.org/">wordpress</a> ou <a href="https://www.blogger.com/">blogger</a>. Mais j'ai pas tenu longtemps car je perdais vraiment tout mon temps à écrire du html et à checker le rendu en ligne. Donc, j'ai enfin trouvé un système pour blogger idéalement! Il s'agit de <a href="http://docs.getpelican.com/en/3.3.0/">Pelican 3.3</a>, un générateur de page web static écrit en python. Il suffit d'écrire un article en <a href="http://fr.wikipedia.org/wiki/Markdown">Markdown</a> dans son éditeur préféré ( Vim pour les africanos ou <a href="http://www.sublimetext.com/">Sublime Text</a> comme moi) et Pelican se charge de créer toutes les pages html. Il ne reste alors plus qu'à automatiser l'envoi de ces pages sur un serveur nginx ou apache , et le tour est joué ! Vous n'avez même pas idée a quel point c'est agréable d'écrire sans html avec son éditeur préféré.
Je vous propose donc, dans ce premier poste, de vous détailler la création d'un blog avec Pelican.</p>
<h3>Installation</h3>
<p>L'installation suivante, a été faite sous Linux/ubuntu. Mais les exemples suivants devraient marcher sur tous les OS supportant python. Si vous êtes sous windows, je vous invite quand même à installer un vrai OS de développement :D
Vérifiez d'avoir une version de python compatible 2.7.x . Depuis votre terminal tapez : </p>
<div class="highlight"><pre><span></span><code>python --version
Python 2.7.5+
</code></pre></div>
<p>Si vous n'avez pas python, installez le en suivant ce <a href="http://fr.openclassrooms.com/informatique/cours/apprenez-a-programmer-en-python/installer-python-1">tutorial</a>.
Ensuite, assurez vous d'avoir le gestionnaire de package de python <strong>pip</strong>. Vous pouvez l'installer en suivant les indications de la <a href="http://www.pip-installer.org/en/latest/installing.html">page officiel</a>.<br>
Installer alors le package Pelican et le package Markdown que nous utiliserons par la suite. </p>
<div class="highlight"><pre><span></span><code>sudo pip install pelican
sudo pip install Markdown
</code></pre></div>
<h3>Création du blog</h3>
<p>Tout d'abord, créez le dossier de votre blog. Une fois à l’intérieur, lancer la commande <strong>pelican-quickstart</strong>. </p>
<div class="highlight"><pre><span></span><code>mkdir monBlog
cd monBlog
pelican-quickstart
</code></pre></div>
<p>Suivez les indications. Voici ce que j'ai mis. Si comme moi, vous avez un serveur accessible par ftp ou ssh, répondez 'Oui' et suivez les instructions. Ceci nous permettra d'envoyer automatiquement les fichiers html générés, vers un serveur. </p>
<div class="highlight"><pre><span></span><code><span class="k">Where</span><span class="w"> </span><span class="n">do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="k">create</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="vm">?</span><span class="w"> </span><span class="o">[</span><span class="n">.</span><span class="o">]</span><span class="w"> </span>
<span class="n">What</span><span class="w"> </span><span class="n">will</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">title</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="vm">?</span><span class="w"> </span><span class="n">MonBlog</span><span class="w"></span>
<span class="n">Who</span><span class="w"> </span><span class="n">will</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">author</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="vm">?</span><span class="w"> </span><span class="n">sacha</span><span class="w"> </span><span class="n">schutz</span><span class="w"></span>
<span class="n">What</span><span class="w"> </span><span class="n">will</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="k">default</span><span class="w"> </span><span class="k">language</span><span class="w"> </span><span class="k">of</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="vm">?</span><span class="w"> </span><span class="o">[</span><span class="n">en</span><span class="o">]</span><span class="w"> </span><span class="n">fr</span><span class="w"></span>
<span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">specify</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">URL</span><span class="w"> </span><span class="k">prefix</span><span class="vm">?</span><span class="w"> </span><span class="n">e</span><span class="p">.</span><span class="n">g</span><span class="p">.,</span><span class="w"> </span><span class="nl">http</span><span class="p">:</span><span class="o">//</span><span class="n">example</span><span class="p">.</span><span class="n">com</span><span class="w"> </span><span class="p">(</span><span class="n">Y</span><span class="o">/</span><span class="n">n</span><span class="p">)</span><span class="w"> </span>
<span class="n">What</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">URL</span><span class="w"> </span><span class="k">prefix</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">see</span><span class="w"> </span><span class="n">above</span><span class="w"> </span><span class="n">example</span><span class="p">;</span><span class="w"> </span><span class="k">no</span><span class="w"> </span><span class="k">trailing</span><span class="w"> </span><span class="n">slash</span><span class="p">)</span><span class="w"> </span><span class="nl">https</span><span class="p">:</span><span class="o">//</span><span class="n">dridk</span><span class="p">.</span><span class="n">me</span><span class="w"> </span>
<span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">enable</span><span class="w"> </span><span class="n">article</span><span class="w"> </span><span class="n">pagination</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">Y</span><span class="o">/</span><span class="n">n</span><span class="p">)</span><span class="w"> </span>
<span class="n">How</span><span class="w"> </span><span class="n">many</span><span class="w"> </span><span class="n">articles</span><span class="w"> </span><span class="n">per</span><span class="w"> </span><span class="n">page</span><span class="w"> </span><span class="n">do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="vm">?</span><span class="w"> </span><span class="o">[</span><span class="n">10</span><span class="o">]</span><span class="w"> </span>
<span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">generate</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">Fabfile</span><span class="o">/</span><span class="n">Makefile</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">automate</span><span class="w"> </span><span class="n">generation</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">publishing</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">Y</span><span class="o">/</span><span class="n">n</span><span class="p">)</span><span class="w"> </span>
<span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="n">an</span><span class="w"> </span><span class="n">auto</span><span class="o">-</span><span class="n">reload</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">simpleHTTP</span><span class="w"> </span><span class="n">script</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">assist</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="n">theme</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">site</span><span class="w"> </span><span class="n">development</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">Y</span><span class="o">/</span><span class="n">n</span><span class="p">)</span><span class="w"> </span>
<span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">website</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="n">FTP</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> </span>
<span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">website</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="n">SSH</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> </span>
<span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">website</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="n">Dropbox</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> </span>
<span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">website</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="n">S3</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> </span>
<span class="n">Do</span><span class="w"> </span><span class="n">you</span><span class="w"> </span><span class="n">want</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">website</span><span class="w"> </span><span class="k">using</span><span class="w"> </span><span class="n">Rackspace</span><span class="w"> </span><span class="n">Cloud</span><span class="w"> </span><span class="n">Files</span><span class="vm">?</span><span class="w"> </span><span class="p">(</span><span class="n">y</span><span class="o">/</span><span class="n">N</span><span class="p">)</span><span class="w"> </span>
<span class="n">Done</span><span class="p">.</span><span class="w"> </span><span class="n">Your</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">project</span><span class="w"> </span><span class="k">is</span><span class="w"> </span><span class="n">available</span><span class="w"> </span><span class="k">at</span><span class="w"> </span><span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">schutz</span><span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">monblog</span><span class="w"></span>
</code></pre></div>
<p>Les fichiers et dossiers intéressants sont les suivants : </p>
<p><strong>content/</strong> <em>Tous vos articles et pages doivent être ranger ici</em> <br>
<strong>output/</strong> <em>Les pages html static se trouverons ici</em><br>
<strong>pelicanconf.py</strong> <em>La fichier de configuration de votre site</em> <br>
<strong>publishconf.py</strong> <em>Le fichier de configuration pour la publication.</em><br>
<strong>Makefile</strong> <em>Un make nous permettant de faire plein de manipulation automatique</em> </p>
<h3>Tester votre blog</h3>
<p>Vous pouvez maintenant générer vos pages static via la commande suivante : </p>
<div class="highlight"><pre><span></span><code>make html
</code></pre></div>
<p>Puis testez votre blog en lançant un serveur via la commande suivante : </p>
<div class="highlight"><pre><span></span><code>make serve
</code></pre></div>
<p>N’hésitez pas à taper <strong>make help</strong> pour avoir plus d'information sur ces commandes. <br>
Si tout se passe bien, vous devriez obtenir cette page en vous rendant à l'adresse : <a href="http://localhost:8000">http://localhost:8000</a>. </p>
<p><img alt="Capture" src="/images/post1.png"> </p>
<h3>Créez votre premier poste.</h3>
<p>Maintenant, rien de plus simple! Depuis votre éditeur de texte préféré, créez un fichier <em>mon_premier_post.md</em> dans le dossier <em>content</em> et sauvegarder. </p>
<div class="highlight"><pre><span></span><code><span class="n">Title</span><span class="o">:</span><span class="w"> </span><span class="n">Mon</span><span class="w"> </span><span class="n">blog</span><span class="w"> </span><span class="n">avec</span><span class="w"> </span><span class="n">pelican</span><span class="w"></span>
<span class="n">Date</span><span class="o">:</span><span class="w"> </span><span class="mi">2010</span><span class="o">-</span><span class="mi">12</span><span class="o">-</span><span class="mi">03</span><span class="w"> </span><span class="mi">10</span><span class="o">:</span><span class="mi">20</span><span class="w"></span>
<span class="n">Tags</span><span class="o">:</span><span class="w"> </span><span class="n">linux</span><span class="o">,</span><span class="w"> </span><span class="n">python</span><span class="o">,</span><span class="w"> </span><span class="n">pelican</span><span class="w"></span>
<span class="n">Category</span><span class="o">:</span><span class="w"> </span><span class="n">python</span><span class="w"></span>
<span class="n">Slug</span><span class="o">:</span><span class="w"> </span><span class="n">first</span><span class="o">-</span><span class="n">post</span><span class="w"></span>
<span class="n">Author</span><span class="o">:</span><span class="w"> </span><span class="n">Sacha</span><span class="w"> </span><span class="n">Schutz</span><span class="w"></span>
<span class="n">Ceci</span><span class="w"> </span><span class="n">est</span><span class="w"> </span><span class="n">le</span><span class="w"> </span><span class="n">contenu</span><span class="w"> </span><span class="n">de</span><span class="w"> </span><span class="n">mon</span><span class="w"> </span><span class="n">premier</span><span class="w"> </span><span class="n">poste</span><span class="w"></span>
</code></pre></div>
<p>Régénérer votre code comme précédemment et voilà: </p>
<div class="highlight"><pre><span></span><code>make html
make serve
</code></pre></div>
<p>Une astuce, au lieu de faire à chaque fois make html et make serve, vous pouvez directement faire une seul fois:</p>
<div class="highlight"><pre><span></span><code>make devserver
</code></pre></div>
<p>Ceci créera un serveur en arrière plan se mettant à jour à chaque modification de vos fichiers. </p>
<h3>Publier votre blog</h3>
<p>Pour finir, la publication de vos pages statiques peut se faire soit manuellement, en envoyant le contenu du dossier output. Soit via une de ces commandes en fonction des paramètres de votre serveur.</p>
<div class="highlight"><pre><span></span><code><span class="n">make</span><span class="w"> </span><span class="n">ssh_upload</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="w"> </span><span class="n">via</span><span class="w"> </span><span class="n">SSH</span><span class="w"> </span>
<span class="n">make</span><span class="w"> </span><span class="n">rsync_upload</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="w"> </span><span class="n">via</span><span class="w"> </span><span class="n">rsync</span><span class="o">+</span><span class="n">ssh</span><span class="w"> </span>
<span class="n">make</span><span class="w"> </span><span class="n">dropbox_upload</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="w"> </span><span class="n">via</span><span class="w"> </span><span class="n">Dropbox</span><span class="w"> </span>
<span class="n">make</span><span class="w"> </span><span class="n">ftp_upload</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="w"> </span><span class="n">via</span><span class="w"> </span><span class="n">FTP</span><span class="w"> </span>
<span class="n">make</span><span class="w"> </span><span class="n">s3_upload</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="w"> </span><span class="n">via</span><span class="w"> </span><span class="n">S3</span><span class="w"> </span>
<span class="n">make</span><span class="w"> </span><span class="n">cf_upload</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="w"> </span><span class="n">via</span><span class="w"> </span><span class="n">Cloud</span><span class="w"> </span><span class="n">Files</span><span class="w"></span>
<span class="n">make</span><span class="w"> </span><span class="n">github</span><span class="w"> </span><span class="n">upload</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">web</span><span class="w"> </span><span class="n">site</span><span class="w"> </span><span class="n">via</span><span class="w"> </span><span class="n">gh</span><span class="o">-</span><span class="n">pages</span><span class="w"></span>
</code></pre></div>
<h3>Conclusion</h3>
<p>Voilà, j'espère que ce poste vous a aidé à comprendre le fonctionnement de Pelican. Je n'ai pas détaillé le reste. Mais sachez qu'il est possible d'ajouter plein <a href="http://pelican.readthedocs.org/en/latest/settings.html">d'options intéressantes</a> depuis le fichier de configuration. Vous pouvez installer des thèmes et des plugins que vous récupérez <a href="https://github.com/getpelican">ici depuis github</a>. Vous pouvez également créer des pages fixes en les sauvegardant dans contents/pages. </p>
<hr>
<h4>Référence</h4>
<p><a href="http://docs.getpelican.com/en/3.3.0/">Site officiel du project Pelican</a><br>
<a href="https://github.com/getpelican">Github du project Pelican (Theme et plugins)</a><br>
<a href="http://daringfireball.net/projects/markdown/">Markdown Syntax Guide</a><br>
<a href="http://pelican.readthedocs.org/en/latest/settings.html">Pelican Settings doc</a></p>