Certains bio-informaticiens ne jurent que par R (j'en fais partie). Je suis amoureux de sa simplicité (sic), son élégance (re-sic), sa documentation et ses innombrables packages tous plus utiles les uns que les autres. Et surtout c'est le seul langage que je maîtrise un peu convenablement, alors forcément je trouve tous les autres langages nuls, en toute objectivité.
Et pourtant R est universellement reconnu comme étant un langage de programmation ésotérique. Il a fallu tout le talent de Patrick Burns et de son livre pour que j'ouvre enfin les yeux et découvre qu'en fait R, c'est l'enfer.
Descendez donc avec moi dans des profondeurs abyssales au travers de quelques exemples librement inspirés de the R inferno.
R ne sait pas calculer
Définissons un joli vecteur :
1 |
> myVect <- c(0.1/1, 0.2/2, 0.3/3, 0.4/4, 0.5/5, 0.6/6, 0.7/7) |
Mais à quoi ressemble-t-il ?
1 2 |
> myVect [1] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 |
Un bien beau vecteur. Vraiment. R saura-t-il trouver quelles valeurs sont égales à 0.1 ?
1 2 |
> myVect == 0.1 [1] TRUE TRUE FALSE TRUE TRUE FALSE FALSE |
Heu, bien joué R. Quatre bonnes réponses sur sept, c'est... encourageant. Surtout pour un programme de statistiques, très populaire, et très utilisé en bioinfo.
Reprenons :
1 2 3 4 5 6 |
> 0.1 == 0.1 [1] TRUE > 0.3/3 [1] 0.1 > 0.3/3 == 0.1 [1] FALSE |
Mais pourquoi donc ?
Le problème des nombres à virgule, c'est que la partie après la virgule peut être infinie, alors que la mémoire des ordinateurs ne l'est pas. Du coup, les ordinateurs décident plutôt de ne garder que quelques (dizaines de) nombres après la virgule, et d'oublier les autres. Ils font donc plein de petites erreurs de calcul débiles. Par défaut, R n'affiche pas tout ce qu'il sait d'un nombre, mais on peut lui demander d'en afficher plus (le nombre maximum de digits peut dépendre de votre configuration) :
1 2 3 4 |
> print(0.1, digits = 22) [1] 0.10000000000000001 > print(0.3/3, digits = 22) [1] 0.099999999999999992 |
Et l'on voit bien en effet que pour notre langage préféré, 0.1 n'est pas égal a 0.3/3. Youpi. C'est génial.
Comme en fait c'était quand même gravos, les concepteurs de R, dans leur infinie sagesse, ont décidé de faire une fonction qui donne le résultat attendu, la mal nommée all.equal . Cette fonction compare (entre autre) si la différence entre deux nombres est moins importante qu'une petite tolerance.
1 2 |
> all.equal(0.3/3, 0.1) [1] TRUE |
Quelques détails :
- le paramètre tolerance vaut par défaut 1,5.10-8.
- Les concepteurs de R ont décidé que
all.equal ne retournerait pas
FALSE (parce que). Du coup, comme ils étaient quand même bien embêtés, ils ont créé la fonction
isTRUE :
1234> all.equal(1, 2)[1] "Mean relative difference: 1"> isTRUE(all.equal(1, 2))[1] FALSE - Pour rendre le tout vraiment infernal,
all.equal n'est évidemment pas vectorisée, débrouillez-vous comme ça.
12> all.equal(myVect, 0.1)[1] "Numeric: lengths (7, 1) differ"
R, le maître troll des langages de programmation...
R est en moyenne assez peu cohérent
Les fonctions min et max retournent respectivement le minimum et le maximum d'une série de nombres :
1 2 3 4 |
> min(-1, 5, 118) [1] -1 > max(-1, 5, 118) [1] 118 |
Jusque là, tout va bien. La fonction mean est utilisée pour trouver la moyenne :
1 2 |
> mean(-1, 5, 118) [1] -1 |
...
Je pense que R devrait prendre quelques leçons de statistiques.
Sait-il calculer une médiane ?
1 2 |
> median(-1, 5, 118) "Error in median(-1, 5, 118) : unused argument (118)" |
Apparemment pas, mais au moins nous signale-t-il gentiment que quelque chose ne tourne pas rond.
Mais pourquoi donc ?
En fait, il vaut mieux utiliser ces fonctions sur des vecteurs, ce que tout le monde fait en pratique :
1 2 3 4 5 6 7 8 |
> min(c(-1, 5, 118)) [1] -1 > max(c(-1, 5, 118)) [1] 118 > mean(c(-1, 5, 118)) [1] 40.66667 > median(c(-1, 5, 118)) [1] 5 |
Notez tout de même que dans le premier cas, la fonction mean :
- ne retourne pas d’erreur.
- ne retourne pas de warning.
- retourne un résultat (faux) du type attendu (un nombre).
Quel machiavélisme ! Si l'utilisateur ne teste pas rigoureusement son code, il court droit à la catastrophe.
Le facteur numérique accidentel
Imaginons, par exemple, qu'un innocent vecteur numérique se retrouve par mégarde sous la forme d'un factor (par exemple, suite à une facétie des célèbres fonctions read.table ou data.frame, et de leur non moins célèbre paramètre stringsAsFactor dont la valeur par défaut est à l'origine de la majorité de mes bugs R). L'utilisateur averti pourrait se dire en toute confiance : "Pas de panique, je connais la fonction as.numeric".
Qui aurait pu imaginer qu'un tel désastre était imminent ?
1 2 3 4 5 6 7 8 9 10 11 |
> myVect <- factor(c(105:100, 105, 104)) > myVect [1] 105 104 103 102 101 100 105 104 Levels: 100 101 102 103 104 105 > myVect >= 103 [1] NA NA NA NA NA NA NA NA "Warning message: In Ops.factor(myVect, 103) : ‘>=’ not meaningful for factors" # Haha, je connais la fonction as.numeric ! Tu ne m'auras pas comme ça, R ! > as.numeric(myVect) >= 103 [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE |
Mais pourquoi donc ?
as.numeric ne fonctionne pas comme vous le pensez sur les factors :
1 2 |
> as.numeric(myVect) [1] 6 5 4 3 2 1 6 5 |
Du coup, il faut passer par un p'tit coup de as.character :
1 2 |
> as.numeric(as.character(myVect)) [1] 105 104 103 102 101 100 105 104 |
Ou alors, si vous êtes pédant :
1 2 |
> as.numeric(levels(myVect))[myVect] [1] 105 104 103 102 101 100 105 104 |
L'arrondi du coin
Parfois, il est bien utile d’arrondir un peu tous ces nombres compliqués avec plein de virgules. La fonction round fait, en général, assez bien son travail :
1 2 3 4 |
> round(0.2) [1] 0 > round(7.86) [1] 8 |
Il y a toujours cette petite hésitation quant à savoir comment sera arrondi 0.5 , en 0 ou en 1 ?
1 2 |
> round(0.5) [1] 0 |
OK. R fait donc partie de ces langages qui arrondissent X.5 à l'entier inférieur. Pourquoi pas. Ce n'est pas ce qu'on m'a appris à l'école, mais bon, pourquoi pas ?
1 2 |
> round(1.5) [1] 2 |
Hein ?! Mais R enfin, qu'est-ce que tu fais ? C'est trop te demander d’être cohérent pendant deux lignes ?
1 2 3 4 |
> 0:10 + 0.5 [1] 0.5 1.5 2.5 3.5 4.5 5.5 6.5 7.5 8.5 9.5 10.5 > round(0:10 + 0.5) [1] 0 2 2 4 4 6 6 8 8 10 10 |
♪♫ Lalala ♫♪ Je suis R. Je fais ce que je veux. ♪♫ Lalala ♫♪ J’arrondis X.5 à l'entier pair le plus proche si je veux. ♪♫ Lalala ♫♪
R
Mais pourquoi donc ?
Si on arrondit un grand échantillonnage de...
Si on réfléchit bien, on s’aperçoit que...
...potentiel biais dans...
Et bien en fait...
Les auteurs de R ont...
Heu, bon, passons.
Une matrice dans un tableau
Il est possible d'inclure une matrix comme colonne d'un data.frame . Comparez donc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
> myMat <- matrix(1:6, ncol = 2) > myMat [,1] [,2] [1,] 1 4 [2,] 2 5 [3,] 3 6 > myDF1 <- data.frame(X = 101:103, Y = myMat) > myDF2 <- data.frame(X = 101:103) > myDF2$Y <- myMat > myDF1 X Y.1 Y.2 1 101 1 4 2 102 2 5 3 103 3 6 > myDF2 X Y.1 Y.2 1 101 1 4 2 102 2 5 3 103 3 6 > dim(myDF1) [1] 3 3 > dim(myDF2) [1] 3 2 > myDF1$Y NULL > myDF2$Y [,1] [,2] [1,] 1 4 [2,] 2 5 [3,] 3 6 |
Mais pourquoi ?
You will surely think that allowing a data frame to have components with more than one column is an abomination. That will be your thinking unless, of course, you’ve had occasion to see it being useful.
Patrick Burns
Vous penserez sûrement qu'autoriser des composants de plus d'une colonne dans un data.frame est une abomination. Vous penserez cela, à moins bien sûr que vous n'ayez eu l'occasion de voir cela mis en pratique de façon utile.
L’échantillonnage approximatif
La fonction sample est bien pratique pour échantillonner au hasard un vecteur, avec ou sans remise :
1 2 3 |
> myVect <- c(2.71, 3.14, 42) > sample(myVect, size = 5, replace = TRUE) [1] 2.71 3.14 42.00 3.14 3.14 |
Le programmeur expérimenté se dira que ce bout de code a l'air dangereux dans le cas où myVect est vide. En effet, mais R a la décence de nous prévenir :
1 2 3 4 |
> myVect <- numeric(0) > sample(myVect, size = 5, replace = TRUE) "Error in sample.int(length(x), size, replace, prob) : invalid first argument" |
Le cas où myVect ne contient qu'un unique élément semble bien moins problématique (hahaha ! Bande de naïfs) :
1 2 3 |
> myVect <- 3.14 > sample(myVect, size = 5, replace = TRUE) [1] 3 4 2 2 3 |
Notez bien :
- Pas de message d’erreur.
- Pas de warning.
- Un résultat sous la forme de 5 nombres, comme attendu.
Pourtant, ce n'était peux-être pas ce que vous désiriez. Je blêmis à l'idée du nombre de bugs non résolus causés par ce petit twist.
Mais pourquoi ?
Dans certains cas, c'est bien pratique de pouvoir faire sample(100, 5) et d'obtenir :
1 |
[1] 59 70 30 23 58 |
R se montre compréhensif, et essaye de nous prévenir dans les petites lignes de bas de page du manuel :
If x has length 1, is numeric (in the sense of is.numeric ) and x >= 1 , sampling via sample takes place from 1:x . Note that this convenience feature may lead to undesired behaviour when x is of varying length in calls such as sample(x) .
help(sample)
Si x a une longueur de 1, est numérique (tel que défini par is.numeric) et x >= 1, l’échantillonnage via sample a lieu sur 1:x. Notez bien que cette caractéristique peut aboutir à un comportement indésiré lorsque la longueur de x varie lors d'appels tels que sample(x).
Noitaréti à l'envers
Si vous essayez d'écrire en douce une petite boucle for , comme ça, ni vu ni connu (en général, quand on est pédant et qu'on fait du R, on préfère faire de la programmation fonctionnelle) (mais sinon, les boucles for ont la réputation d'être lentes en R. C'est assez faux. Elles ne sont pas plus lentes que le reste, du moment que vous ne faîtes pas grandir des objets dedans. Pensez à pré-allouer le résultat) (mais reprenons) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
> myTable <- data.frame(x1 = 1:5, x2 = letters[1:5]) > myTable x1 x2 1 1 a 2 2 b 3 3 c 4 4 d 5 5 e > > for (i in 1:nrow(myTable)) { + message(paste("row:", i)) + message(paste("x1:", myTable[i, "x1"], "x2:", myTable[i, "x2"])) + } row: 1 x1: 1 x2: a row: 2 x1: 2 x2: b row: 3 x1: 3 x2: c row: 4 x1: 4 x2: d row: 5 x1: 5 x2: e |
Que se passe-t-il si myTable est vide ?
1 2 3 4 5 6 7 8 9 10 11 12 |
myTable <- data.frame(x1 = NULL, x2 = NULL) > myTable data frame with 0 columns and 0 rows > > for (i in 1:nrow(myTable)) { + message(paste("row:", i)) + message(paste("x1:", myTable[i, "x1"], "x2:", myTable[i, "x2"])) + } row: 1 x1: x2: row: 0 x1: x2: |
Mais pourquoi ?
Et oui, nrow(myTable) vaut 0 , et 1:0 retourne [1] 1 0 ! Ça alors, c'est pas de chance ! Préférez donc seq_len(nrow(myTable)) .
Javascript, sort de ce coRps !
1 2 |
> 50 < "7" [1] TRUE |
Mais pourquoi ?
1 2 3 4 |
> 50 < as.numeric("7") [1] FALSE > "a" < "b" [1] TRUE |
Le message d’erreur le plus utile du monde
1 2 3 4 |
> i <- 1 > if (i == pi) message("pi!") > else message("papi!") Error: unexpected 'else' in "else" |
Mais pourquoi ?
If you aren’t expecting 'else' in "else", then where would you expect it?
While you may think that R is ludicrous for giving you such an error message, R thinks you are even more ludicrous for expecting what you did to work.Patrick Burns
Si tu ne t’attends pas à un 'else' dans "else", où donc t'attends-tu à en voir un, R ?
Vous penserez peut-être que c'est ridicule pour R de retourner un tel message d'erreur. R pense que vous êtes encore plus ridicule d’espérer que ce que vous aviez fait fonctionnerait.
En vrac
- La fonction read.table retourne un data.frame, et pas une table . La fonction table retourne une table.
- La fonction sort.list ne sert pas à trier les listes.
-
12> seq(5:10)[1] 1 2 3 4 5 6
(╯°□°)╯︵ ┻━┻
Bonus
Votre collègue s'est absenté en laissant sa session R ouverte ? Profitez-en, soyez infernal ! Voici quelques petites commandes amusantes à taper dans sa session :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
> F <- TRUE > T <- FALSE > c <- function(...) list(...) > return <- function(x) x + 1 > > # admirez le résultat : > c(1, 5) [[1]] [1] 1 [[2]] [1] 5 > double <- function(x) return(2 * x) > double(10) [1] 21 |
Le petit mot de fin
Tout ceci décrit le comportement de R 3.3.1. Il est possible que certaines incohérences soient résolues dans les prochaines versions. Cela me semble assez peu probable cependant, pour des raisons de rétro-compatibilité.
Vous ne l'aurez peut-être pas compris, mais ce n'est aucunement un article à charge. Il s'agit juste d'une mise en pratique de l’adage "qui aime bien châtie bien".
Si vous en redemandez, n'hésitez pas à remonter ma source : The R Inferno !
Merci à mes talentueux relecteurs Bebatut, Chopopope, Estel et Lroy !
GrumpyStat
septembre 21, 2016 à 9:45
Bonjour,
Alors je veux bien admettre qu'il y a quelques soucis avec R mais là vous poussez le bouchon très loin. La moitié de vos "surprise" vient de ce que vous n'avez pas lu le manuel avant d'utiliser une commande (typiquement, la fonction agit différent sur un vecteur que sur des nombre rentrés directement). Franchement pas de quoi crier au loup quand c'est dit explicitement dans le manuel.
Le round a une logique, oui. Par exemple, si vous faites la moyenne de 0.5 1.5 2.5 3.5 4.5 vous obtenez 2.5 et de round de cette liste vous obtenez 2.4 avec R. Alors que si vous aviez un "floor" au lieu de ça (l'entier du dessous) ben vous avez une moyenne de 2 ! Alors oui ça fait une belle différence quand on traite des échantillons, et c'est plutôt malin.
Mais bien plus grave, votre "erreur inutile"
> i if (i == pi) message("pi!")
> else message("papi!")
Error: unexpected 'else' in "else"
vient simplement du fait que vous avez tapé "entrer" avant d'entrer la commande else. Si on finit une commande, R va pas deviner tout seul qu'en fait il fallait attendre la suite avant d'interpréter le "if". Donc la, lui il ne voit que un "else" sans un "if".
Faites l'essaie:
> if (i == pi) message("pi!") else message("papi")
papi
A bon entendeur !
Lucas
septembre 21, 2016 à 11:28
Ce n'est pas parce qu'il y a une logique que c'est justifié ; INTERCAL suit une logique imparable, et si on ne l'utilise pas (au-delà du fait qu'il s'agit d'un pur langage ésotérique),
c'est parce que cette logique ne permet pas de travailler dans des conditions minimale d'hygiène mentale, c'est-à-dire avec un niveau d’abstraction suffisant.
R, tel que je l'ai vu durant mes quelques heures d'utilisation, et tel que je le vois là, est un grenier de comportements mal abstraits.
L'abstraction est une bonne chose quand elle est bien faite, et de toute évidence ce n'est pas le cas dans R.
J'imagine qu'il est possible de passer outre tous ces problèmes, en ajoutant/modifiant légèrement le code. Mais cela nécessite le développement d'une expertise qui devient un frein à la fois quand il s'agit de faire apprendre le langage, mais aussi lors de son usage.
A-ton vraiment envie d'avoir un tel coût d'exploitation pour ce qui ne doit rester qu'un outils ?
C'est selon moi la différence entre un «bon» langage et un «mauvais» langage,
(indépendamment de toute notion d'outils rattaché au langage,
python serais bien moins brillant sans pip, et C++ moins intéressants sans boost)
Un exemple de cette opposition, c'est COBOL et Ada.
Le premier est un langage difficile parce qu'il est, dans un registre un peu différent de R, complexe à l'usage et à la maintenance.
Le second est complexe également, mais pour une raison beaucoup plus saine: Ada aborde la notion d'orienté objet avec une approche différente des langages plus habituels (c++, java).
L'un et l'autre des langages ont un coups d'apprentissage conséquent, mais l'un des deux demande la compréhension d'un paradigme, là où l'autre demande la compréhension de détails d'implémentation, d'effets de bords et de comportements.
En clair, quand vous apprenez Ada, vous ne perdez pas votre temps sur le langage, mais sur la conception. Ce qui est réutilisable partout, et une fois acquis, totalement transparent.
C'est l'inverse pour R. On perd du temps et de l'énergie avec ce langage, même après apprentissage, alors que tout ce dont on a besoin, c'est d'un outils de haut niveau pour étudier les données. Et tout le monde perd ce temps. Même les experts doivent penser en permanences à ces détails, et,
plutôt que manipuler abstraitement leurs données, sont en permanence en train de compenser le langage.
Que round ait un comportement bizarre est une chose (même les rounding qui suivent la norme IEEE font parfois des surprises), mais que ce genre d'abstraction mal fichue soit aussi répandu dans la base de code, c'est la marque d'un langage «broken by design».
Ça donne l'impression un langage patché/développé dans tous les sens, sans cohérence globale, qui n'est pas sans rappeler PHP ou javascript.
Certes, comme pour PHP, R propose une doc conséquente...
Mais ce n'est pas suffisant pour justifier une mauvaise abstraction !
«oui, je sais, ma méthode to_int renvois une string, mais je l'ai expliqué dans la doc ! Tout va bien !».
En somme, ce sont des langages dont la seule véritable feature est l'absence d'alternative.
(en fait, elles existent, mais sont trop peu utilisées/matures)
Pour donner des exemples de ce que je considère comme de «bon» langages, et pourquoi ils le sont, il y a Ada, mais aussi Python, Haskell, et bien d'autres.
Ces langages ne réussissent pas pour la même raison.
Pour Ada, c'est des impératifs professionnels qui nécessitent que le langage soit au top.
Pour Python, c'est un BDFL compétent et cohérent.
Pour Haskell, c'est le pari d'implémenter à fond un paradigme.
Ils ne sont évidemment pas exempts de (terribles) défauts, mais s'ils n'en ont pas autant que R, PHP et javascript, c'est probablement pas un hasard.
Quelques liens:
- PHP: https://secure.phabricator.com/book/phabflavor/article/php_pitfalls/
- Python: http://stackoverflow.com/questions/530530/python-2-x-gotchas-and-landmines
- INTERCAL: https://en.wikipedia.org/wiki/INTERCAL
Et, comme je suis très orienté python et que moi aussi, je défends, objectivement n'est-ce pas, mon bout de gras: http://mechanicalcat.net/cgi-bin/log/python/anti-pitfalls.html
GrumpyStat
septembre 21, 2016 à 12:13
Je suis plutôt d'accord avec vous sur les faiblesses de R en tant que langage de programmation, étant plutôt C++ que R moi-même.
C'est la faiblesse des argument de ce blogpost qui m'a remontée. Typiquement, il aurait été intéressant de pousser plus loin les comportements étranges de R (i.e. pourquoi ils existent), que de se contenter de taper sur 2-3 exemples bidons qui ne surprendra pas n'importe quel utilisateur régulier de R. Pour n'importe quel autre langage il serait facile de trouver des exemples similaires.
rems
septembre 21, 2016 à 2:41
"Pour n'importe quel autre langage il serait facile de trouver des exemples similaires."
Pas si sûr, R est un très bon candidat quand même 🙂
Sinon il y a javascript qui est connu pour être du grand n'importe quoi (d'où le nombre incroyable de librairies (jquery, angular...) qui en sont sortie car il reste très pratique) 🙂
Sinon pour C++ et boost, j'avais bien aimé l'avis de notre ami Linus :
http://harmful.cat-v.org/software/c++/linus
Ahah
Lins`
septembre 21, 2016 à 11:08
Ce n'est pas vraiment un bon argument. Si je crée un langage où il faut mettre un else avant le if, et où le "==" teste une inégalité, mais que je mets tout ça dans le manuel, est-ce que ça ne serait pas un problème de cohérence pour autant ? Dans un bon langage, tout ce qui est à même de tromper l'utilisateur lambda est à éviter, sinon le langage peut être effectivement qualifié d'ésotérique.
Personnellement je trouve qu'arrondir un vecteur avant d'en faire la moyenne est une aberration statistique. Je ne vois pas non plus en quoi avoir une moyenne de 2.4 est mieux qu'avoir une moyenne de 2. Pourquoi est-ce qu'on s'attendrait à ce que l'arrondi conserve une moyenne non arrondie ? Le comportement du floor est bien plus cohérent (la moyenne de l'arrondi est égale à l'arrondi de la moyenne).
On est d'accord, il y a bien une erreur et R le signale. Le problème n'est pas là. Le problème c'est que le message d'erreur est là pour se foutre de la gueule de l'utilisateur, et est complètement non informatif. En gros, ça correspond bien au fait que R est un langage écrit par des trolls et pour des trolls 🙂 .
Natir
septembre 21, 2016 à 11:47
Mon honnête me pousse à défendre R, et cela en étonnera certain.
Le premier point, qui concerne les égalités de nombre flottant, est en fait commun a presque tous les langages je dis presque car je n'est pas vérifié tous les langages. Le problème est inhérent a comment on représente un nombre en virgule flottant et comment on réalise une comparaison. En fait R ne fait ni mieux ni moins bien que les autres langages.
Un autre point quel que peu bancale et la comparaison entre les nombres et les chaines de caractère. Ce problème vient du faite que R est un langage a typage faible (comme le javascript mais ce n'est pas le seul), quand on réalise une opération entre deux type différent le langage tente de convertir l'un des types en l'autre. Problème cette conversion ce fait souvent silencieusement (même pas un petit warning) et pas comme on le crois instinctivement. Encore une fois R n'est pas pire mais certainement pas meilleur que les autres.
Sur le fond je suis tout a fait d'accord R est l'un des pires langages qui existe mais ces deux arguments sont faibles.
Bisous
Ps: vive python et panda
Yoann M.
septembre 21, 2016 à 11:48
Personnellement l'article m'a bien fait rire 🙂
Ensuite je partage complétement le commentaire de Lucas (et les orientations programmistiques ^^).
Je rajoute d'ailleurs un petit lien informatif sur quelques bizarreries du coté de python histoire de prouver ma bonne foi : https://access.redhat.com/blogs/766093/posts/2592591
Merci encore @ Guillaume pour l'article !
Guillaume Devailly
septembre 21, 2016 à 12:02
https://www.youtube.com/watch?v=TihnYw_Kr9U&feature=youtu.be&t=23
Calmez-vous ! Calmez-vous !
C'est juste un petit article rigolo. Pas de quoi se disputer.
De tout façon, R c'est le futuR:
https://github.com/gdevailly/R_future_Edinbr_Presentation/blob/master/Rfuture2.md
Natir
septembre 21, 2016 à 12:14
Vue que cette article parle surtout d'incohérence et de chose étrange dans les langages de programmation je vous invite a lire ce file stackoverflow https://stackoverflow.com/questions/1995113/strangest-language-feature
On y trouve de nombreuse chose amusante loufoque ou même stupide.
bli
novembre 23, 2016 à 3:19
Une petite précision concernant ce passage:
> Le problème des nombres à virgule, c'est que la partie après la virgule peut être infinie, alors que la mémoire des ordinateurs ne l'est pas. Du coup, les ordinateurs décident plutôt de ne garder que quelques (dizaines de) nombres après la virgule, et d'oublier les autres. Ils font donc plein de petites erreurs de calcul débiles
On pourrait s'étonner que 0.1 pose problème car il n'a apparemment pas un nombre infini de chiffres après la virgule. En fait si je me souviens bien de mes cours d'info, c'est sa décomposition en somme de puissances de 2 qui nécessiterait un nombre infini de puissances de 2 (négatives, ici) pour représenter sa valeur exacte.
À propos des difficultés que pose R, hier même, dans un moment de frustration j'ai cherché du réconfort sur l'internet en cherchant "Why I hate R", et je suis tombé sur cet article qui me semble assez juste:
http://www.talyarkoni.org/blog/2012/06/08/r-the-master-troll-of-statistical-languages/
Résumé simplifié : L'article dit que dès qu'on cherche à faire le malin avec R, on se fait en général avoir, à moins d'être vraiment super au point.
bli
novembre 23, 2016 à 3:23
Ah, ben je vois que l'article que je mentionne était en fait cité dès juste après le passage auquel je réagissais. Ça m'apprendra à réagir avant d'avoir tout lu.
bli
novembre 29, 2016 à 3:02
R m'a de nouveau mordu. Un autre cas de comportement apparemment incohérent de R: http://stackoverflow.com/questions/40867703
Kawah
novembre 7, 2017 à 1:14
L'article date un peu, et même si je comprends tout à fait le ton humoristique du contenu, la quasi totalité des "incohérences" présentées ici ne le sont pas :
"R ne sait pas calculer" : bah oui mais si on comprend un peu comment sont encodés les flottants, on se dit vite que c'est presque normal (et surtout, pas propre à R)
"R est en moyenne assez peu cohérent" : sauf que pour le coup, c'est l'exemple qui est incohérent. mean() c'est une fonction, qui prend plusieurs arguments. mean(x,y,z) fait la moyenne de l'objet X; donc forcément si tu lui passes mean(-1,5,118) il fait la moyenne sur -1, c'est pas si choquant après tout. [Et sur median, qui ne prend que 2 arguments, l'erreur est pourtant très claire]
"Le facteur numérique accidentel" : sauf qu'en fait, y a aucune raison pour que tes facteurs soient considérés comme des nombres, donc la méthode as.numeric() sur facteurs, ça renvoie le numéro du niveau, en toute logique.
"L'arrondi du coin" : c'est un standard, il porte même un chouette nom : IEC 60559
"Une matrice dans un tableau" : l'exemple est sympa, mais pas pour l'incohérence que l'auteur pointe, parce qu'il ne fait pas la différence entre "=" et "<-" et pourtant la différence est grande !
"L’échantillonnage approximatif" : bon je reviens pas dessus, l'auteur l'explique très bien
"Noitarité à l'envers" : c'est ce qu'on appelle la décrémentation, on ne va quand même pas reprocher à R de comprendre tout seul (c'est à dire sans avoir besoin de lui dire --i au lieu de ++i) que pour passer de 1 à 0 il doit décrémenter, si ?
-"JS sors de ce corps" : l'incohérence c'est de vouloir comparer deux types différents entre eux, pas tellement la réponse qui ici dépend juste du terme qui sera converti
"Le message d'erreur le plus utile du monde" : il me paraît pourtant limpide ce message, tu travailles en consoles, tes lignes de codes sont indépendantes si tu tape entrée, donc forcément le else se retrouve sans if et bah ça n'est pas possible quoi... (la prochaine fois suffit d'essayer shift+entrée :))
"En vrac" : read.table et sort.list on est d'accord c'est drôle; en revanche seq() bah même remarque que pour mean(), faut comprendre ce qu'est une fonction et un argument
"Bonus" : j'adore, j'y penserai 😀
Sinon, l'article est sympa (tout comme le livre duquel il s'inspire d'ailleurs), je comprends son utilité et saisi le ton humoristique, R est en effet un langage... surprenant, et parfois difficile à appréhender voir contre intuitif (cependant pas sur les exemples repris ci-dessus, en fait), Mais il faut le prendre comme il l'est, le petit, non pas un langage de programmation destiné à coder tout et n'importe quoi mais un langage avec visu intégré pour faire de l'analyse de données sympatoche.
Kawah
novembre 7, 2017 à 1:23
Hmm, commentaire parti trop vite, je reformule ma dernière phrase mal construite :
<< Mais il faut le prendre comme il est, non pas un langage de programmation destiné à coder tout et n'importe quoi mais un ensemble de fonctions ad hoc avec visualisation intégrée pour faire de l'analyse de données >>
serait plus correct !