Journal Gnu R version 4.0.0 est disponible

Posté par  . Licence CC By‑SA.
Étiquettes :
28
27
avr.
2020

R est un langage de programmation et un logiciel libre destiné aux statistiques et à la science des données. La version 4.0.0 est sorti le 24 avril

La liste complète des changements est disponible ici : https://cran.r-project.org/doc/manuals/r-release/NEWS.html.

Une des évolutions est potentiellement relativement impactante sur les scripts existants. Dans les versions précédentes, les chaînes de caractères étaient par défaut transformées en factor dans les fonctions read.table et data.frame (paramètre par défaut StringsAsFactor=TRUE), ce n'est plus le cas dans la version 4.0.0, les chaînes restent des chaînes.

#version 3.5
dta<-data.frame(id=1:3, car=LETTERS[1:3])
str(dta)
'data.frame':   3 obs. of  2 variables:
 $ id : int  1 2 3
 $ car: Factor w/ 3 levels "A","B","C": 1 2 3

#version 4.0
dta<-data.frame(id=1:3, car=LETTERS[1:3])
str(dta)
'data.frame':   3 obs. of  2 variables:
 $ id : int  1 2 3
 $ car: chr  "A" "B" "C"

Personnellement, je préfére le nouveau comportement, je commençais régulièrement mes scripts par la commande :

options(stringsAsFactors = FALSE)

Ce qui n'est donc plus nécessaire.

Concernant la mise à jour. Sur Debian, pour ceux qui comme moi n'utilise pas la version de la distribution mais celle du cran, il est nécessaire de modifier le fichier sources.list

#la ligne
deb http://mon_miroir_cran/bin/linux/debian buster-cran35/
#doit être remplacé par 
deb http://mon_miroir_cran/bin/linux/debian buster-cran40

puis le classique apt update & apt upgrade

Une fois la mise à jour effectuée, il est nécessaire de réinstaller la totalité des packages (Cette réinstallation est nécessaire pour tous les OS)

Ce qui peut être réalisé pour les package du cran dans R grâce à la commande :

update.packages(ask=FALSE, checkBuilt=TRUE)
  • # Ma plus commune erreur

    Posté par  . Évalué à 3.

    Salut,

    J'avais déjà lu cette nouvelle, mais…

    StringsAsFactor=FALSE

    Oh ouais !

    Ça va éviter un tas de questions :)

    Tant pis pour la RAM…

    Matricule 23415

    • [^] # Re: Ma plus commune erreur

      Posté par  . Évalué à 4. Dernière modification le 27/04/20 à 14:34.

      Je viens de voir une erreur dans mon texte, il faut remplacer (paramètre par défaut StringsAsFactor=FALSE) par(paramètre par défaut StringsAsFactor=TRUE)

      • [^] # Re: Ma plus commune erreur

        Posté par  . Évalué à 3.

        "potentiellement relativement" ; un peu riche cette formulation ; bravo pour le reste.

        • [^] # Re: Ma plus commune erreur

          Posté par  . Évalué à 2. Dernière modification le 27/04/20 à 14:39.

          Je suis d'accord, j'ai hésité à le laisser. Comme pour le gouvernement et le déconfinement je me suis dit "Inchallah"

          • [^] # Re: Ma plus commune erreur

            Posté par  . Évalué à 2.

            Salut,

            Oui, ce serait bien de corriger si une personne de l'équipe a le temps.

            Mais si j'en crois ma simple expérience personnelle, qu'il fallait faire un breaking change, c'était bien celle-là.

            Je ne sais plus combien de fois je me suis auto-maudit à cause de "ça".

            Matricule 23415

      • [^] # Re: Ma plus commune erreur

        Posté par  (site Web personnel) . Évalué à 3.

        fait

        ウィズコロナ

    • [^] # Re: Ma plus commune erreur

      Posté par  . Évalué à 4.

      Ça va éviter un tas de questions :)

      Certes, mais ça va péter un certain nombre de scripts existants.

      Le problème n'est pas vraiment dans le code maintenu (CRAN sait très bien faire ça, les mainteneurs de packages sont constamment obligés de maintenir la compatbilité lors des changements de versions. Le problème est plutôt que R est énormément utilisé pour de l'analyse de données scientifiques, et les scripts d'analyse sont publiés dans une optique de recherche reproductible. Pas question de mise à jour ici, non seulement c'est du code qui n'a pas vocation à être exécuté dans d'autres contextes, mais en plus ça serait même contraire à l'idée de base (reproduire les résultats d'un article scientifique, erreurs comprises). Et dans ce cas, bah paf, on perd la reproductibilité. C'est facheux.

      • [^] # Re: Ma plus commune erreur

        Posté par  . Évalué à 3.

        Salut,

        Certes, mais ça va péter un certain nombre de scripts existants.

        Oui, et ?

        Si les scripts ne sont pas actualisés, c'est du code mort. S'il faut faire de la recherche reproductible, il faut se mettre dans le même contexte d'exécution.

        Il y a eu plein d'autres corrections de "bugs" dans R, qui font que tout n'est pas toujours reproductible. Celle-là est en effet un peu cassante, mais n'en reste pas moins (à mon humble avis) une très bonne. :)

        Matricule 23415

        • [^] # Re: Ma plus commune erreur

          Posté par  . Évalué à 2.

          S'il faut faire de la recherche reproductible, il faut se mettre dans le même contexte d'exécution.

          Oui, mais c'est en pratique infaisable (ne serait-ce que parce que seul le code R est en général fourni). On reste donc dans une définition faible de la reproductibilité : on exécute le truc, et on espère avoir à peu près le même résultat.

          Il y a eu plein d'autres corrections de "bugs" dans R, qui font que tout n'est pas toujours reproductible.

          Certes, mais c'est en général assez spécifique. C'est clair que R ne garantit aucunement la compatibilité (ni ascendante, ni descendante), mais en général les changements d'interface et de comportement font en sorte de minimiser les incompatibilités. Là c'est un changement qui potentiellement peut casser une grosse moitié de l'existant d'un coup.

          Après, c'est vrai qu'à ma connaissance, il n'existe aucun mécanisme simple dans R pour vérifier les versions (de R et des paquets) dans un script. Il y a donc une nette distinction entre les paquets (qui, eux, ont des mécanismes forts pour gérer les dépendances) et les simples scripts.

          • [^] # Re: Ma plus commune erreur

            Posté par  . Évalué à 1. Dernière modification le 29/04/20 à 10:20.

            Salut,

            Après, c'est vrai qu'à ma connaissance, il n'existe aucun mécanisme simple dans R pour vérifier les versions (de R et des paquets) dans un script.

            Au contraire, c'est super simple, ça se fait dans un fichier de métadata quand "on" (oui, je sais…) fait ça bien.

            Un petit exemple.

            Mais tu as raison, si seul le code R est fourni, là… c'est la galère :)

            NdM : modifié à la demande de l'auteur.

            Matricule 23415

            • [^] # Re: Ma plus commune erreur

              Posté par  . Évalué à 3.

              Oui oui, les metadata des systèmes de paquets sont très (trop) stricts avec les dépendances.

              Ceci dit, ces histoires de versions de dépendances, c'est bien, mais ça n'est pas magique. Souvent ça encourage les développeurs à être très restrictifs (par exemple, si on utilise la version 1.2.3 du paquet Truc, alors on force la version 1.2.3, comme ça on est sûr que ça marche… et on est sûr d'emm* tous les utilisateurs).

              En tant qu'utilisateur très régulier de R, je suis en désaccord sur un certain nombre de points avec la politique des dev de R core. Typiquement, les devs R considèrent que la "bonne manière" de faire les choses et de distribuer des paquets pour n'importe quel projet, ce qui, en effet, permet de bien structurer l'arborescence des projets, d'améliorer la reproductibilité, etc. Malheureusement, cette manière de travailler est aussi très rigide et très technique; pour qu'un paquet passe les checks il faut une documentation très rigide, et la moindre tâche devient pénible (par exemple, imaginons qu'on souhaite ajouter un paramètre optionnel à une fonction pour tester un truc : il faut modifier la fonction, modifier la doc, parfois modifier les metadata si on utilise une dépendance, reconstruire le paquet, le recharger dans son script de test (éventuellement avec les outils de R-devel si on ne veut pas réinstaller le nouveau paquet), et exécuter sa fonction. Zut, il y a une faute de frappe. Rebelotte, reconstruire le paquet, etc. C'est un workflow pourri de chez pourri, ça revient à perdre tous les avantages d'un langage de script où on colle ses constantes, ses dépendances, ses fonctions, et son code dans un même fichier, on exécute, et basta. Évidemment, il existe des utilitaires qui permettent d'automatiser un peu tout ça, mais ça revient à coller des pansements sur une jambe de bois.

              Pourtant, les devs utilisent l'existence de ce système de paquets (qui est excellent pour, en effet, distribuer des paquets) pour nier l'évidence sur les besoins des utilisateurs. Par exemple, il semble que n'importe qui utilisant R pour des projets de taille moyenne (quelques mois de travail personnel par exemple) a besoin de structurer son code en plusieurs fichiers, qui peuvent s'appeler les uns les autres. Or, il n'existe aucune fonction dans R pour gérer les chemins d'appel des scripts de manière fiable (en gros, pour connaitre le chemin complet du script qu'on est en train d'exécuter, il faut sans utiliser des variables système-spécifiques cachées dans les paramètres environnementaux). La réponse des devs est systématiquement "vous n'avez qu'à utiliser les paquets", et je ne comprends pas pourquoi. C'est un peu la même chose pour la gestion des environnements (qui définissent la visibilité des variables), qui reste cryptique et incohérente, mais qui est sans cesse renvoyée dans les dents des gens qui se plaignent des incohérences du langage.

              Je trouve ça un peu moche quand les devs d'un langage tellement utilisé ont du mal à comprendre les besoins de leurs utilisateurs (mais c'est souvent inévitable : les devs sont de très bons techniciens et ils connaissent parfaitement toutes les subtilités de leur outil, il est très difficile pour eux de comprendre pourquoi certaines procédures sont totalement hermétiques aux utilisateurs "normaux").

              • [^] # Re: Ma plus commune erreur

                Posté par  . Évalué à 1.

                Salut,

                D'abord, encore, je te présente mes excuses sincères pour avoir réagi trop vite et manqué la fin de ton message précédent.

                Donc dans celui-la, je vais essayer de ne pas effectuer la même erreur :)

                Tes remarques sont très justes du point de vue de l'utilisateur de R. C'est pénible de se retrouver "figé dans le temps", si on veut faire du reproductible. On ne peut pas bénéficier des nouveautés, etc. Et si on bouge, ça peut péter au moindre écart.

                Cet argument, je le comprend très bien, et il ne me pose pas de soucis particulier.

                Mon point de vue maintenant (même si je doute t'apprendre grand chose…).

                R a été commencé il y a bien longtemps (1993), et au départ pour fournir une alternative à S (plus vieux encore, donc). Et à cette époque, la RAM et l'espace disque étaient relativement limités. Il faisait donc tout à fait sens de prendre le choix de faire des facteurs par défaut. Depuis, il me semble que la situation a changé au sens où pour un même traitement, cette contrainte n'est plus valable.

                Sur un plan pratique, c'est quand même un gros numéro de version qui est incrémenté. Donc pas de la correction de "bug mineur", c'est clairement annoncé, il y a du breaking change. Ce sont des choses qui arrivent dans la vie de tous les logiciels. :)

                Matricule 23415

                • [^] # Re: Ma plus commune erreur

                  Posté par  . Évalué à 2. Dernière modification le 29/04/20 à 15:55.

                  Non non, pas de problème, je crois qu'on est plutôt d'accord. Je n'ai pas de solution non plus pour faire évoluer un langage sans tout péter.

                  Le choix d'interpréter les caractères comme des facteurs dans les jeux de données est problématique, puisque de toutes manières certains jeux de données peuvent contenir à la fois des colonnes de texte qui correspondent à des caractères et d'autres à des facteurs. Il aurait été tout à fait possible de développer des heuristiques pour se gourer le moins possible (par exemple, il est très peu probable qu'une colonne qui contienne des chaines de caractères toutes différentes puisse représenter un facteur), mais ça aurait été atroce en termes de maintenance. Un choix existait par défaut, il était critiquable, mais c'était comme ça. Ce qui est embêtant, c'est de changer, surtout qu'il existait quand même des arguments dans les deux sens, ansi qu'une option stringsAsFactors qui permettait de basculer entre les deux comportements. Mais bon, c'est fait, c'est fait…

                  Après, R possède de très nombreux bugs d'interface sur des fonctions de base; soit des noms de paramètres ou de fonctions incohérents (par exemple simplify dans sapply vs SIMPLIFY dans mapply, nrow mais row.names dans data.frame vs nrow() et rownames()), soit des interfaces hyper bugogènes (comme le premier paramètre dans sample() qui change de sens en fonction de sa longueur), soit des ordres de paramèters incohérents (do.call a la fonction qui vient en premier et qui s'appelle "what", lapply a la fonction qui vient en deuxième et qui s'appelle FUN…). Quitte à péter la compatibilité lors d'un changement majeur de version, autant le faire un bon coup et réparer plusieurs problèmes à la fois… La méthode choisie c'est plutôt de retirer le pansement millimètre par millimètre, je ne suis pas convaincu.

                  • [^] # Re: Ma plus commune erreur

                    Posté par  . Évalué à 1.

                    Salut,

                    Non non, pas de problème, je crois qu'on est plutôt d'accord.

                    Ok, ouf ! Merci :)

                    Il aurait été tout à fait possible de développer des heuristiques pour se gourer le moins possible […]

                    Le problème est dans le "moins possible". Des jeux de données un peu… hmmm… étranges dirais-je, j'en ai vu passer :)

                    A plusieurs reprises, il y a eu des envies, quand je développais pour un soft de stat proprio, de tenter des "trucs". Mais ça n'a jamais vu le jour, pas même une ligne de code.

                    A chaque fois, soit les fichiers étaient bien faits, et là, ok, super mais du coup ça sert à rien, soit c'était rendu à une ligne tellement loin que pour "tomber" dessus, il fallait en gros scanner tout le fichier.

                    Bonjour l'expérience utilisateur à chaque import avec une notion d'auto-typage… :)

                    Donc j'en suis resté à l'implémentation complètement basique faite avant moi : On regarde les 100 ou 1000 premières lignes et basta. :)

                    Matricule 23415

                    • [^] # Re: Ma plus commune erreur

                      Posté par  . Évalué à 2. Dernière modification le 29/04/20 à 17:33.

                      En fait, la question centrale est peut-être celle de l'utilité d'un type facteur dans un langage non-typé, puisque les facteurs vont forcément entrer en conflit avec les autres types de base. Il me semble tout à fait envisageable de laisser les fonctions transtyper en facteur quand elles en ont besoin (voire d'interpréter les strings comme des facteurs), alors que les routines de lecture/écriture/manipulation de données gèrent des chaines de caractères. Les problèmes de RAM sont évitables même avec les chaînes de caractère, c'est juste une histoire d'optimisation interne.

                      De toutes manières, l'auto-typage génère des bugs, c'est inévitable. Quand il y a une erreur de saisie triviale, style un "Na" au lieu de "NA", alors c'est toute la colonne de nombres qui devient facteur ou catactère; au contraire, on peut changer le type en appliquant un filtre (par exemple un grep \d+ sur une chaine de caractères, et pouf, le sous-jeu de données n'a pas le même type). Le plus vicieux, c'est un as.numeric sur une colonne interprétée comme un facteur, ce qui risque d'arriver de manière silencieuse avec du code écrit pour R-4.0 interprété par un R plus ancien: as.numeric(c("10","12")) donne c(10,12), alors que as.numeric(factor(c("10","12))) fait c(1,2). De bonnes soirées de débuggage poilu en perspective.

          • [^] # Re: Ma plus commune erreur

            Posté par  . Évalué à 1.

            Salut,

            Bon, je n'étais pas assez concentré, et ai dû manquer la fin de ton commentaire, toutes mes excuses.

            Matricule 23415

      • [^] # Re: Ma plus commune erreur

        Posté par  . Évalué à 2.

        Bah un petit (ou approchant, je ne suis pas un pro du bash)

        find . -type f -name \*.R -mtime 4 | xargs -I{} bash -c "sed -f - {} < <(sed 's/^/1i/' 'options(stringsAsFactors = TRUE)')"
        

        devrait faire l'affaire non ?

        • [^] # Re: Ma plus commune erreur

          Posté par  . Évalué à 1. Dernière modification le 28/04/20 à 17:57.

          Salut,

          Nope, du tout.

          Le 'options(stringsAsFactors = TRUE)') fait un changement "global" du comportement des scripts (et encore, juste pour la base core).

          Rien n'est garanti, par exemple pour les extentions, si on ne fait pas attention. C'est pour celà qu'il faut (heureusement ou malheureusement) tenir le code "vivant".

          Par exemple, dans le dernier projet que j'ai fait, je me suis (encore) fait avoir (pas longtemps, hein ;) ). Je lui passe un vecteur de "strings", elle me retourne un vecteur de "facteurs". Grrr. :)

          Matricule 23415

      • [^] # Re: Ma plus commune erreur

        Posté par  . Évalué à 4.

        Une bonne description de l'expérience destinée à permettre sa reproduction devrait inclure le logiciel utilisé et son numéro de version.
        Une bonne reproduction devrait reprendre exactement la même version pour la reproduire.

        Sinon on tombe dans une abîme sans fond de compatibilité ascendante:

        Si une correction de bug change un résultat publié il y a 3ans, est-ce qu'on laisse le bug en l'état par défaut avec une option à entrer pour avoir la correction?

        Si pBpG passe par ici, il pourra commenter sur la gestion par MS des correctifs de bugs qui cassent les scripts des gros clients.
        Je doute que l'équipe de dév de R ait les ressources, ni l'envie de toute façon, de se lancer dans une telle gestion.

  • # R et recherche reproductible

    Posté par  . Évalué à 2.

    Un mien collègue, utilisateur de R depuis de nombreuses années, à qui j'ai signalé ce journal, m'a fait les remarques suivantes qui seront peut-être pour vous des évidences, mais sait-on jamais :

    1/ Il y a plein d'outils en R pour faire de la recherche reproductible ( https://cran.r-project.org/web/views/ReproducibleResearch.html ), et notamment pour la mise en œuvre de versions spécifiques de R et des packages pour un script donné (voir la partie Package Reproducibility, et notamment le package checkpoint).

    2/ À propos du célèbre StringsAsFactors : l'introduction du tidyverse (https://www.tidyverse.org/) a complètement changé le paysage de R et la façon de programmer.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.