Accessibility Tools

- Le blog participatif de bioinformatique francophone depuis 2012 -

Mes très chers confrères ado­rés,

Comme vous le savez si vous lisez mes excel­lents articles d'opinion, tous géniaux (hum !), cela fait quelques années main­te­nant que je tra­vaille pour des toxi­co­logues.

Alors, c'est bien, j'ai appris plein de choses, au point de me défi­nir aujourd'hui comme « com­pu­ta­tio­nal toxi­co­lo­gist ». Mais j'ai sur­tout mis mon nez dans plein de trucs qui peuvent paraître insi­gni­fiants comme ça, mais qui peuvent vite vous rendre com­plè­te­ment chèvre meilleur dans votre tra­vail si vous vous y inté­res­sez un peu.

Aujourd'hui, j'aimerais par­ler de science repro­duc­tible, et sur­tout de repro­duc­ti­bi­li­té des résul­tats en fonc­tion de dif­fé­rents lan­gages de pro­gram­ma­tion. Au hasard, R, Python et un peu Mat­lab hein, fai­sons simple.

Pour­quoi est-ce inté­res­sant de se poser ce genre de ques­tions, si ce n'est pour la beau­té du code ? Soyons sin­cères, je me fiche de la beau­té du code. Donc si j'ai fini par faire ce genre de choses, c'est que der­rière il y avait une bonne rai­son. Voyons cela ensemble.

Un peu de contexte, histoire de râler sur mes anciens collègues avant de râler sur les nouveaux

Contexte de l’anecdote : Pen­dant ma thèse, et même avant, mon direc­teur de thèse ado­ré m'a fait un cadeau dont rêve tout bio­in­for­ma­ti­cien qui se res­pecte : une licence MATLAB. Com­bien d'entre vous uti­lisent MATLAB déjà ? Hum, pas beau­coup. Et pour­tant, je vais être sin­cère, pour faire de jolies visua­li­sa­tions de cartes chro­mo­so­miques, bah, c'était fort pra­tique.

Sauf que voi­là, quand on aime faire des chro­mo­somes en 3D, on est content, on a nos codes MATLAB, ça tourne. Mais vu que le bion­fo de base ne code pas en MATLAB, un jour, pen­dant l'été, tous les sta­giaires du cou­loir s'y sont mis et on a reco­dé toutes nos fonc­tions pré­fé­rées en Python, his­toire de pou­voir res­ter dans notre lan­gage pré­fé­ré.

L’exemple concret : Main­te­nant, rigo­lons un peu et racon­tons mes erreurs de débu­tant. Pour com­pa­rer deux cartes de contacts chro­mo­so­miques entre elles, il existe une méthode connue qui consiste à faire le ratio loga­rith­mique des deux matrices après nor­ma­li­sa­tion. Pen­dant que je fabri­quais des figures pour un papier, j'avais mes deux implé­men­ta­tions python et mat­lab de toutes les méthodes de nor­ma­li­sa­tion et il m'arrivait régu­liè­re­ment de faire tout mes trai­te­ments en python pour ensuite visua­li­ser en mat­lab. Pour­quoi ? Tout sim­ple­ment car j'arrivais à pro­duire des figures plus belles. Voi­ci les deux implé­men­ta­tions de la nor­ma­li­sa­tion de la SCN que nous avions.

La figure que j'essayais de pro­duire, issus de ce papier. La tu com­pare en log10 le ratio de deux matrices nor­ma­li­sé par SCN. Si la SCN est pas la même entre les deux matrices, il y aura pleins de points extrême qui appa­rai­trons car les matrices seront pas stric­te­ment homo­gène en frac­tion de contact

Alors oui, si on demande à n'importe quel inter­pré­teur de code (GPT ou autre), ces codes font la même chose dans l'esprit. Ils font une nor­ma­li­sa­tion ité­ra­tive des don­nées mises en entrée. Mais admet­tons qu'un bidouilleur prenne une matrice, la nor­ma­lise en Python d'un côté, en MATLAB de l'autre, et com­pare les deux, le résul­tat sera-t-il iden­tique ?

Pas du tout, il y aura des dif­fé­rences car le nombre total d'interactions dans une matrice ne sera pas stric­te­ment égal à son équi­valent dans un autre lan­gage, sur­tout vu la dif­fé­rence mas­sive d'implémentation. En dérou­lant le même trai­te­ment à mes don­nées, pas de sou­cis. Avec une fonc­tion qui, ici, a des légères dif­fé­rences et en pre­nant des résul­tats d'un lan­gage pour les com­pa­rer à un autre, j'aurais four­ni un résul­tat faux à mes col­lègues. Il faut alors ima­gi­ner cette figure pleine de bleu et de rouge car, en log10, une infime dif­fé­rence devient catas­tro­phique.

Pour pou­voir être com­pa­rées entre elles, les matrices doivent être trai­tées par les mêmes outils. Ici, la dif­fé­rence est fla­grante car le code n'est pas écrit de la même manière. Il a cepen­dant été ma pre­mière prise de conscience de l'impact du lan­gage et de l'implémentation sur un résul­tat pos­sible. Les exemples sui­vants ont vrai­ment com­men­cé à me griller les neu­rone à me rendre rigou­reux.

Bonne chance si vous voulez le même random forest en R et en Python

War­ning, cette par­tie est gran­de­ment, très gran­de­ment basée sur l'article en open access que je sou­met­trai un jour quelque part s'il est accep­té si j'ai le temps de mettre en œuvre les efforts néces­saires pour le rendre accep­table à tous.

Contexte de l’anecdote : Les années passent, les che­veux se perdent, et pour­tant on espère être meilleur chaque jour. Allez, me voi­là au début de mon tra­vail actuel, et je découvre que le poste que j'occupe était occu­pé par quelqu'un avant moi. Une per­sonne brillante et bien orga­ni­sée qui m'a lais­sé une myriade d'archives de tout ce qu'elle a fait… en R.

Dans cette myriade de sujet il y en avait un inache­vé d’une dizaines de ligne… Allez, je recode en Python, his­toire de me faire la main et de véri­fier que j'ai bien com­pris tout ce que mon col­lègue avait fait. En vou­lant repro­duire à l'identique ses résul­tats, je ne cherche pas à faire le code le plus opti­mal, mais sim­ple­ment à m'assurer que j'ai com­pris chaque infime détail des tra­vaux pré­cé­dents.

L’exemple concret : Là, on arrive sur un pro­blème que je cari­ca­tu­re­rais gros­siè­re­ment par : « Tu prends ces pro­duits cos­me­tiques (sham­poings et autre), tu envoies toutes les don­nées sur ces pro­duits cos­me­tiques dans un ran­dom forest que tu entraînes sur le type d'irritation défi­nis en labo­ra­toire avec des tubes a essais » (cf. le papier pour ceux qui veulent le détail). Là, je me dis, OK, facile, gloire à sci­kit-learn ! Je lance le code, para­mètres par défaut, sur les don­nées archi­vées. Et là, les résul­tats en R et en Python sont dif­fé­rents. Pas de beau­coup, juste quelques pour­cen­tages, mais tout de même pas STRICTEMENT iden­tiques sur quelques mil­liers de valeurs.

Ça c'est la dif­fé­rence que j'avais sur 920 pré­dic­tions entre 3 implé­men­ta­tions.

Alors oui, on est sur du machine lear­ning, qui repose sur une myriade d'éléments aléa­toires. Donc vous allez me dire : « C'est nor­mal, arrête de te prendre la tête, c'est peut-être la graine aléa­toire. » Mais en fait, je peux relan­cer son script, les résul­tats sont stables ; je relance le mien, les résul­tats sont stables aus­si, avec tou­jours cette petite dif­fé­rence de rien du tout. Je tente de faire conver­ger les graines aléa­toires, tou­jours des dif­fé­rences donc les implé­men­ta­tions ont des dif­fé­rences qui se tiennent.

Sauf que je bosse pour des toxi­co­logues. Donc si vous leur dites droit dans les yeux : « Bon alors, j'ai un modèle qui te dit que ce pro­duit n'est pas irri­tant, donc tu peux vali­der, il y aura aucun sou­ci. Quand j'ai repro­duit le code, j’ai une conclu­sion d’irritation, mais t'inquiète, c'est juste une graine aléa­toire dans mon modèle, on s'en fiche… », quelle va être la réac­tion de ces per­sonnes ? Ces per­sonnes qui ont pour res­pon­sa­bi­li­té de ne pas mettre de pro­duit irri­tant sur le mar­ché, sans quoi les consé­quences seraient ter­ribles ? Vous pen­sez qu'ils vont aimer ma preuve de concept et vali­der mon jouet avec un dis­cours pareil ? Bah vous creu­sez, vous creu­sez encore, en y pas­sant une semaine, puis deux, et là vous vous dites : « Bon, il y a un vrai os, j'ai tes­té plein de trucs de manière plus ou moins intel­li­gente, je ne trouve pas. »

On creuse tout, les effets aléa­toires, les implé­men­ta­tions sur les­quelles les ran­dom forests se basent, et là vous com­pre­nez qu'il y a plein de petites sub­ti­li­tés. Pri­mo, si vous ne vou­lez pas vous prendre la tête, vous remar­quez que R et Python se basent tous les deux sur la même biblio­thèque C++ pour faire un ran­dom forest si on passe par ran­ger.

Les moyens de faire des ran­dom forest en R et Python

En fait, même si les implé­men­ta­tions en C++ sont les mêmes, il y a quelques sub­ti­li­tés dans les librai­ries dans leur manière de l'appeler et de pré­pa­rer les don­nées. Il suf­fit de quelques dif­fé­rences sub­tiles de para­mètres par défaut pour don­ner cette varia­tion. La conclu­sion majeure est que pour que les dif­fé­rentes implé­men­ta­tions four­nissent des résul­tats simi­laires, il faut bien opti­mi­ser le para­mètre min_​node_​size (min_​sample_​split en sci­kit-learn, nombre mini­mum d’échantillons pour décou­per des nœuds). Si on met ce para­mètre à 1 on com­men­ce­ra à avoir des arbres iden­tiques mais il peut res­ter quelques arbres récal­ci­trants.

Pour aller plus loin dans la repro­duc­ti­bi­li­té, il est néces­saire de fixer l’aléatoire de la même manière entre les deux implé­men­ta­tions. Il se trouve que les ver­sions sci­kit-learn et R de l'algorithme ran­ger ne construise pas des arbres de la même manière. SKran­ger crée des arbres de pro­ba­bi­li­té basés sur l’argument max de la pro­ba­bi­li­té d’appartenance à une classe. Alors que l'implémentation en R repose sur un sys­tème de vote majo­ri­taire. Dans la majo­ri­té des cas les pré­dic­tions seront les mêmes mais cela peut dif­fé­rer de quelques pour­cen­tage (897 pré­dic­tions iden­tiques sur 920 dans nos tests). La seule astuce qu’on a trou­vée pour rendre les deux iden­tiques était de deman­der au code R de ne prendre que la classe qui a la pro­ba­bi­li­té la plus forte, comme ceci :

Avec ce code R et en ayant fixé les autres hyper­pa­ra­mètres, les deux codes ont le mêmes com­por­te­ment de bout en bout ! A-t-on essayé de rendre fixe, stable et iden­tique un algo­rithme qui contient le mot hasard dans son titre ? Fran­che­ment, oui, mais c'était for­te­ment ins­truc­tif et de toute manière j'aurais trou­vé un toxi­co­logue pour me poser ces ques­tions si je ne l'avais pas fait donc… Exemple sui­vant !

Coucou ANOVA, dis-moi, tu n'es pas exactement pensée pareille entre R et Python, non ?

Bon, si vous faites par­tie des cou­ra­geux qui ont encore envie de me lire en dépit de ma prose chao­tique, vous vous dou­tez qu'après les ran­dom forests, je ne pou­vais pas en res­ter là. Mais que s'est-il pas­sé dans ma fabu­leuse vie cette fois-ci, hein ?

Contexte de l’anecdote : Un jour, une per­sonne qu'on appel­le­ra Élise, pour lui don­ner un nom fic­tif, est venue me voir avec un truc qui avait l'air tout simple et si facile : « Bon alors, on avait mis en place ce pro­to­cole là avec un de tes col­lègues il y a dix ans ; on aime­rait voir si avec l'historique accu­mu­lé on aurais pas inté­rêt à chan­ger de stra­té­gie. On prend nos don­nées, on fait une ANOVA des­sus, on applique une cor­rec­tion de Tukey. Ensuite, on récu­père la matrice des com­pa­rai­sons par paires pour voir si nos scores sont meilleurs ou non que notre cible en fonc­tion de son groupe. Bien que cette stra­té­gie soit tou­jours par­fai­te­ment valide, penses-tu qu'il existe d'autres alter­na­tives inté­res­santes pour nos usages quo­ti­diens ? Ça devrait te prendre une seule jour­née, non ? » Ça sent le piège, hein ? Bin­go.

Col­lègue dif­fé­rent, pro­blème iden­tique, un script en R, je suis un papy grin­cheux avec ses habi­tudes. Je com­mence à me dire que faire le double contrôle dans un lan­gage dif­fé­rent est par­fois pra­tique sur ces pro­blèmes simples. Donc c'est par­ti, je passe deux heures à écrire le truc en Python. Mais… mais… mais… attends, je n'arrive pas à faire exac­te­ment les choses dans le même ordre logique. Pour­quoi ?

L’exemple concret : Python, au moment ou j’ai fait mes tests (novembre 2024), n'était pas rigou­reu­se­ment iden­tique à R dans la manière dont l'ANOVA est implé­men­tée. Les deux ANOVA marchent et sont repro­duc­tibles, mais avoir les mêmes résul­tats entre les deux lan­gages n'est pas tou­jours évident. Ici mon sou­ci était l'implémentation de la fonc­tion de Tukey. Le code de la cor­rec­tion de Tukey en R me retour­nait l'ensemble des groupes simi­laires les uns aux autres là où la cor­rec­tion de Tukey en Python ne me retourne que des paires de com­bi­nai­sons, sans les groupes.

On peut trou­ver quelques posts en ligne sur le sujet si on creuse bien mais en toute fran­chise quand j'ai décou­vert tout ça on voyait bien que ça n'est pas si grave… Il me res­tait juste à reco­der en R avec les mêmes packages que l'original si je vou­lais une copie 100 % iden­tique, ou à créer les fonc­tions man­quantes en Python, ou à me ser­vir de ce contexte com­pa­ra­tif comme base pour toutes les nou­velles ques­tions posées. Connais­sant votre humble ser­vi­teur, je vous laisse devi­ner quelle option j'ai choi­sie.

La reproductibilité doit-elle aller aussi loin ?

En écri­vant cet article, j'ai eu un léger sen­ti­ment de faire une petite publi­ci­té pour cer­taines de mes bafouilles lit­té­raires. En toute fran­chise, j'espère que le lec­teur moyen sau­ra com­prendre que ce n'était pas le but, mais bien de voir que cer­tains métiers peuvent ame­ner à se poser des ques­tions de pré­ci­sion qui, en fait, finissent par tous nous aider.

L'étude de la repro­duc­ti­bi­li­té entre lan­gages de pro­gram­ma­tion est un monde truf­fé de ques­tions ignobles et chro­no­phages pas­sion­nantes. Nous sommes tous de plus en plus sen­si­bi­li­sés à l'importance d'être capables de repro­duire nos résul­tats dans un même lan­gage et avec un même script. Atteindre ce niveau de maî­trise per­met de com­prendre fine­ment, dans les moindres rouages, tout ce que nous fai­sons au quo­ti­dien et l'impact de chaque vir­gule de code.

En toute fran­chise, je ne suis pas cer­tain que la majeure par­tie d'entre vous ait besoin d'aller à ce niveau de repro­duc­ti­bi­li­té quand vous par­lez de science repro­duc­tible. Dans votre quo­ti­dien, faire des tests uni­taires est la chose la plus impor­tante et, déjà, une garan­tie plus que suf­fi­sante pour avan­cer serei­ne­ment. Ensuite nous pour­rions éga­le­ment par­ler de toutes les tech­no­lo­gies pour avoir un envi­ron­ne­ment repro­duc­tible mais ce n’étais pas le but du billet du jour.

Tes­tez vos codes, faites vali­der les résul­tats sur chaque fonc­tion du code autant que pos­sible, et déjà là vous aurez un niveau de rigueur suf­fi­sant. En toute fran­chise, j'utilise main­te­nant le double contrôle dans un lan­gage dif­fé­rent uni­que­ment quand j'ai le sen­ti­ment que ça m'apportera une uti­li­té pré­cise : de la com­pré­hen­sion. Le chan­ge­ment de lan­gage me per­met de m'assurer qu'il n'y a aucun écart, même infime, entre ce qu'exprime un besoin d'un bio­lo­giste et la façon dont je l'écrirais. C'est un peu le test ultime, à mon sens : dire deux fois la même chose dans deux lan­gages dif­fé­rents, et si vous voyez que vous avez obte­nu exac­te­ment le même résul­tat, vous êtes sûr que votre pre­mière copie est la bonne, à condi­tion de l'avoir tes­tée. Dans le cadre d'un double contrôle qui se veut effi­cace, res­ter dans le même lan­gage et le même envi­ron­ne­ment pour voir si la conclu­sion est la même à la fin est un pré­li­mi­naire capi­tal à une base de test solide et robuste. Ça évite de se poser ces ques­tions d'implémentation et de devoir véri­fier un niveau de détails pas tou­jours utile au quo­ti­dien.

Mais si vous êtes un étu­diant de mas­ter qui aime réflé­chir à des ques­tions qui ennuient la plu­part des gens, pos­tu­lez à mes offres de stage ! La can­tine est fabu­leuse !

Allez, j'ai vrai­ment écrit beau­coup trop comme je pen­sais dans cet article, comme si j'étais en pause-café. Ciao les gens !

Mer­ci aux relec­teurs d'avoir, échan­gé, subi ce billet : Évo­lu­scope, Bonob, Jacques Dai­nat, Aze­rin, Lee Mariault.

Vous avez aimé ? Dites-le nous !

Moyenne : 0 /​ 5. Nb de votes : 0

Pas encore de vote pour cet article.

We are sor­ry that this post was not use­ful for you !

Let us improve this post !

Tell us how we can improve this post ?




Commentaires

Une réponse à “Trois exemples concrets qui m'ont fait m'intéresser à la reproductibilité entre langages”

  1. Mer­ci pour ton article, il est vrai­ment inté­res­sant !

    Quand on met en place un algo­rithme, le déve­lop­peur est sou­vent obli­gé de faire des choix qui influencent les résul­tats, l'article le montre bien.

    Sous un autre angle, avec les ran­dom forests, la diver­gence entre les modèles peut en fait conte­nir de l’info inté­res­sante. Ce serait sym­pa d’étudier la confiance des modèles pour les molécules/​ingrédients dont les pré­dic­tions divergent. Si la confiance est faible, on pour­rait conseiller aux toxi­co­logues de retour­ner aux tubes à essais !

Laisser un commentaire

Pour insérer du code dans vos commentaires, utilisez les balises <code> et <\code>.