Data.table: Intégration avec magrittr

Créé le 5 juil. 2015  ·  39Commentaires  ·  Source: Rdatatable/data.table

Il s'agit d'une demande de fonctionnalité suite à la discussion sur la liste de diffusion .

Je pense qu'il serait utile d'avoir quelque chose comme ça comme forme abrégée :

DT[, a %<>% some.function] 

Jusqu'à présent, il faut taper

DT[, a := a %>% some.function]

ou sans magrittr

DT[, a := some.function(a)]

Ceci est particulièrement important si a est remplacé par une variable qui a un nom long, qui est alors difficile à saisir et à lire. Je pense qu'il y a des économies significatives dans l'efficacité (du programmeur) à faire ici, en particulier avec des noms de variables longs.

Commentaire le plus utile

Pour résumer, le problème peut donc être finalement résolu.

Tout ce dont nous avons besoin est de gérer la traduction suivante.

DT[, a %<:>% fun] ## or "%:>%"

DT[, a := fun(a)]

Est-ce correct?

comment doit-il se comporter si a n'est pas un symbole mais une variable de caractère ?

DT[, "a" %<:>% fun]

DT[, "a" := fun(a)]   ## this?
DT[, "a" := fun("a")] ## or this?

et si sa longueur n'est pas 1 ?

DT[, c("a","b") %<:>% fun]

DT[, c("a","b") %<:>% fun(a, b)]
DT[, c("a","b") %<:>% fun("a","b")]
DT[, c("a","b") %<:>% lapply(list(a, b), fun)]
DT[, c("a","b") %<:>% lapply(c("a", "b"), fun)]

Personnellement, je le fermerais car cela ne résoudra pas car il ajoute beaucoup de complexité et ne résout aucun nouveau problème.
Je vois un accord là-dessus, donc fermant, nous pouvons toujours rouvrir si vraiment nécessaire.

Tous les 39 commentaires

DT[, a := some.function(a)]

Fonctionne parfaitement bien

Mais à mon humble avis

Complicated_data_table_variable_name[, a_very_very_very_very_long_variable_name := some.function(a_very_very_very_very_long_variable_name)]

n'est pas parfaitement bien. J'aime l'idée d'ajouter cette fonction de commodité.

Mais peut-être que %:>% serait mieux que %<>% ?

Vous ne devriez pas avoir de noms aussi étranges dans votre ensemble de données. Il est à la fois gênant et difficilement maintenable. En dehors de cela, vous pouvez stocker le nom de la colonne dans une variable, puis faire :

shortname <- "a_very_very_very_very_long_variable_name"
DT[, (shortname) := some.function(get(shortname))]

Vous avez raison, mais même avec des variables de longueur intermédiaire, je trouve toujours la syntaxe magrittr beaucoup plus pratique à lire et à écrire. Quoi qu'il en soit, ce n'est que mon avis personnel.

Je trouve qu'il est parfois préférable d'avoir des noms de variables longs dans des ensembles de données complexes pour indiquer clairement ce qui est enregistré dans une variable. C'est une question de préférence personnelle. Les fonctions de commodité ne sont par définition pas nécessaires pour effectuer une tâche, elles la rendent simplement plus rapide à coder et souvent plus facile à comprendre. Je n'ai aucun doute que cette fonction serait utile à de nombreux utilisateurs. Mais je comprends aussi que si les développeurs de data.table ne veulent pas implémenter/maintenir (trop) de fonctions de commodité, vous devez tracer la ligne quelque part ;)

Pour ceux d'entre vous qui sont abonnés à ce fil, veuillez ne pas tenir compte du dernier commentaire (maintenant supprimé). C'était idiot.

À partir du commentaire de @and3k , je vois une certaine valeur de :

DT[, a %:=>% some.function]

Pensez que cela se lit mieux (c'est-à-dire un := et un %>% ensemble). C'est une « pipe heureuse » ? Je suis fan des efforts visant à réduire la répétition des noms de variables, comme écrit ici : http://stackoverflow.com/a/10758086/403310

La partie => de l'opérateur :=> a une signification supplémentaire, peut-être :=: ?

DT[, a %:=:% some.function]

ou :=. qui correspond directement à := suivi de . passé à fun

Quelle signification supplémentaire a => ? Le > est sympa car il transmet le LHS comme argument à RHS. C'est pourquoi Hadley est passé du %.% à %>% .

J'ai cru comprendre qu'une grande partie de la motivation pour passer à %>% était qu'il est beaucoup plus facile de taper que %.% (je suppose que souvent en essayant de taper %.% entraînerait accidentellement %>% ).

Je veux dire opérateur _grand ou égal_.
Et qu'en est-il de %:>% ? Ce serait plus facile à saisir que %:=>% ou %:=:% .
and3k mentionne déjà celui-ci ci-dessus.

Mon vote est pour %:>% ou juste :> .

Les % ne sont là que parce que R n'autorise pas les opérateurs infixes à l'état sauvage, n'est-ce pas ? Autant garder les opérateurs à l'intérieur de DT[] parcimonieux.

Je n'avais pas pris en compte l'aspect de la frappe, c'est-à-dire que maintenir la touche Maj enfoncée pour tous les caractères de l'opérateur est plus facile, je suppose. Logique.
:> n'analyse malheureusement pas. Le contenu de [...] doit toujours être une syntaxe R valide (tous les arguments sont toujours analysés avant d'être transmis sans évaluation à la fonction), nous ne pouvons donc pas créer de nouveaux opérateurs à l'intérieur de [...] , nous devons toujours envelopper avec des % .
Ok alors %:>% me semble bien aussi. Ce n'est pas comme si c'était une grande priorité, mais ce ne serait pas difficile à mettre en œuvre et c'est bien d'en avoir discuté.

Merci, %:>% me semble bien.

Juste curieux, pourquoi :> n'analyse pas alors que := analyse à l'intérieur de [....] ? := n'est pas non plus une syntaxe R valide, n'est-ce pas ?

@my-R-help c'est une syntaxe valide, voir pourquoi := est autorisé comme opérateur infixe ?

+1 Je suis d'accord avec la demande de fonctionnalité OP et l'utilisation de la syntaxe magritr. C'est le choix le meilleur et le plus évident pour plusieurs raisons.

  • Les gens utilisent déjà beaucoup DT avec itmagrittr
  • la syntaxe de magrittr est omniprésente à ce stade... pourrait même obtenir son propre raccourci clavier rstudio... et tout autre choix syntaxique se terminera probablement par une confusion.

Je vous encourage fortement à ne pas trop réfléchir à ce FR en introduisant un nouvel opérateur dont le choix est tout aussi arbitraire que le choix de magrittr l'était.

Je vous encourage fortement à ne pas trop réfléchir à ce FR en introduisant un nouvel opérateur dont le choix est tout aussi arbitraire que le choix de magrittr l'était.

@ctbrown La proposition concerne un opérateur de pipe qui fait quelque chose de différent de la vanille %>% de magrittr, un package qui a également plusieurs autres opérateurs de pipe. Tant que cela n'entre en conflit avec aucun de ceux-ci, quel est le problème ?

Je pense que la demande FR du PO était suffisamment claire, c'est-à-dire
d'utiliser spécifiquement %<>% comme canal de transfert et affectation combinés
opérateur. Vraisemblablement, c'est parce que magrittr définit déjà %<>% pour
précisément cet objectif. Puisque magrittr semble être le tuyau dominant
mise en œuvre et de nombreuses personnes semblent utiliser %<>%, mes étudiants et
collègues parmi eux. Cela n'a pas de sens d'introduire un autre
opérateur dans le même but. Il est beaucoup plus logique de choisir un
syntaxe qui s'aligne sur ce à quoi la communauté a été exposée ou a déjà
adopté. Voir mon point sur l'ubiquité.

Permettez-moi de vous demander ce que vous espérez gagner en introduisant un autre opérateur
qui remplit exactement la même fonction dans un contexte différent ? je ne peux pas voir
tout avantage. Tout opérateur que vous choisirez sera aussi arbitraire que celui de magrittr.
Cela n'a-t-il donc pas de sens de rendre l'ensemble du système moins arbitraire en
suivre l'exemple de magrittr ici plutôt que de faire encore un autre arbitraire
décision syntaxique ?

Le jeu. 27 oct. 2016 à 11h41, franknarf1 [email protected]
a écrit:

Je vous encourage fortement à ne pas trop réfléchir à ce FR en introduisant un nouveau
opérateur dont le choix est tout aussi arbitraire que le choix de magrittr l'était.

@ctbrown https://github.com/ctbrown La proposition est pour un opérateur de canalisation
qui fait quelque chose de différent de la vanille %>% de magrittr, un
package qui a également plusieurs autres opérateurs de tuyaux. Tant que ce n'est pas
conflit avec l'un d'entre eux, quel est le problème ?

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/Rdatatable/data.table/issues/1208#issuecomment-256732710 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AC5xaxIp36dTUCz9d5a5mU7CJUV6PaxCks5q4PBDgaJpZM4FSJR5
.

Est-ce que %<>% attribue par référence ? Si ce n'est pas le cas, alors ils ne font pas exactement la même chose.

Techniquement, vous avez raison, le %<>% de magrittr n'attribue pas de référence,
mais ce n'est pas la question. Dans les attentes des utilisateurs, il n'y a pas
différence. L'affectation, qu'elle soit par référence ou par valeur, est une
problème de mise en œuvre pas un problème d'interface. Le PO a suggéré d'adopter
l'interface magritr et n'a pas nécessairement suggéré la mise en œuvre.
J'ai vu le mérite de la suggestion du PO. Voir les raisons ci-dessus. je ne
voir la justification de l'adoption de quelque chose comme '%:>% or anything as arbitrary. The merit of this has not been articulated. The %<>%`
opérateur existe déjà et est activement promu par magrittr (12e plus
paquet populaire selon METACRAN.) Autant que tout ce que cela semble
être la norme (au sein de la communauté R). L'avantage de suivre
la pratique établie réduit la confusion des utilisateurs et le besoin de
documentation complète. Vous obtenez : " Oh, c'est la même chose que magrittr, je
connaître ce tuyau avant et faire une mission", au lieu de "qu'est-ce que c'est
étrange %:>% ? C'est une nouvelle émoticône de clown ?"

Le jeu. 27 oct. 2016 à 14:18, Michael Chirico [email protected]
a écrit:

%<>% attribue-t-il par référence ? Si ce n'est pas le cas, alors ils ne font en fait _pas_
exactement la même chose.

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/Rdatatable/data.table/issues/1208#issuecomment -256772769,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AC5xa3ssE14PcamL2U9HlvCdfA8-7Iz8ks5q4RUagaJpZM4FSJR5
.

Dans les attentes des utilisateurs, il n'y a pas de différence.

Premièrement, je ne pense pas que ce soit vrai et que vous parlez au nom de tous les utilisateurs ; Je suis un utilisateur, par exemple. Deuxièmement, si c'est vrai, alors ces utilisateurs doivent en apprendre davantage sur la différence au fur et à mesure qu'ils apprennent à utiliser data.table.

Vos "raisons ci-dessus" ne tiennent pas debout avec moi. Cela ne va pas à l'encontre de magrittr d'implémenter un opérateur de tuyau sans chevauchement pour faire une chose distincte mais liée. Pour moi - et ce n'est que mon impression, tout autant que tout ce que vous avez dit est le vôtre - cela semble parfaitement cohérent avec la "pratique établie" de magrittr (que j'utilise presque aussi souvent que j'utilise data.table ).

Il est parfaitement possible que l'utilisation dans ce contexte attribue à plusieurs objets (colonnes) à la fois, ce qui, vous en conviendrez sûrement, est tout à fait différent de %<>% ..? je veux dire

DT[, (cols) %:>% lapply(as.character) ]

Et, en plus de modifier par référence et potentiellement de modifier plusieurs choses à la fois, nous avons le fait que nous modifions une partie d'une chose (la data.table), ce qui est assez différent de %<>% .

Quoi qu'il en soit, étant donné que les développeurs n'ont montré aucun signe de faire cette tâche de sitôt (en marquant ce FR avec une priorité ou un jalon), que diriez-vous de revoir cela si cela avance réellement ?

@ctbrown _by-reference_ n'est pas seulement différent dans la mise en œuvre et doit être différencié des fonctions _by-value_ dans l'interface utilisateur. C'est tout l'intérêt des fonctions set* et := opérateur

@franknarf1 ,

Premièrement, il n'y avait aucune prétention à parler pour TOUS les utilisateurs de R. C'est une affirmation ridicule. La référence aux "attentes des utilisateurs" était la mienne, probablement les PO et plusieurs de mes étudiants qui ont déjà essayé dt[ , var %<>% ... ] et qui ont demandé pourquoi cela ne fonctionnait pas. De plus, _Forcer_ les utilisateurs à "apprendre la différence lorsqu'ils apprennent à utiliser data.table" est dangereux si DT peut fonctionner comme on pourrait s'y attendre. Cela conduit à une mauvaise conception du logiciel.

Deuxièmement, comme vous le soulignez, il appartient à l'individu d'accepter ou de rejeter les arguments en faveur du suivi de la suggestion du PO de suivre la syntaxe magriitr. Certains arguments ont été avancés pour expliquer pourquoi cela serait bénéfique, mais peu d'arguments convaincants ont proposé pourquoi une alternative serait supérieure ou même bénéfique. Il semble y avoir un argument mineur parce que la mise en œuvre est différente, mais c'est un argument plutôt faible.

En outre,

  • Le %<>% pourrait également être implémenté pour gérer plusieurs arguments et aurait toujours un sens parfait dans le contexte tout en respectant les attentes des PO et des autres. La suggestion de l'OP ne précisait pas vraiment s'il souhaitait modifier plusieurs arguments.
  • Que vous modifiiez une partie ou un tout est une nit -- vous modifiez toujours une partie d'une chose, c'est-à-dire un environnement.
  • L'action ou l'inaction des développeurs est un autre faux-fuyant et n'a aucun rapport avec le bien-fondé de la proposition/demande du PO. Il s'agit d'un argument d'appel à l'autorité plutôt médiocre qui n'a pas vraiment offert d'opinion dans un sens ou dans l'autre.

S'il y a des arguments pour/contre la suggestion du PO, j'aimerais les entendre. Mais la seule chose que j'ai entendue, c'est que, "parce que c'est différent". Peut-être que certains verront cela comme valide, mais comparé à la suggestion originale du PO, l'alternative ne semble pas meilleure.

Tous ceux qui ont déjà utilisé data.table ont dû apprendre à un moment ou à un autre à utiliser := (probablement très peu de temps après avoir commencé). Oh non, effrayant ! Pourquoi n'est-ce pas <- ou = ?

La réponse à cette question est l'une des premières choses que tout le monde apprend sur l'utilisation de data.table . C'est le sujet de la seconde vignette d'introduction .

%<>% contre %<:>% (ou quoi que ce soit d'autre) est exactement la même distinction. La réponse est donc couverte par Matt ici :

http://stackoverflow.com/questions/7033106/why-has-data-table-defined-rather-than-overloading

@jangorecki

Premièrement, la plupart des utilisateurs n'ont pas besoin de connaître la différence entre par référence et par valeur. Ce n'est pas une condition préalable à l'utilisation de DT que vous le sachiez. Vraisemblablement, c'est pourquoi la syntaxe DT est si proche de DF. @mattdowle aurait pu clairement concevoir DT avec une interface purement fonctionnelle. Il ne l'a pas fait. Vraisemblablement, l'une des raisons était que DT pourrait fonctionner comme une baisse de remplacement.

En ce qui concerne les fonctions set* , celles-ci peuvent indiquer par référence, mais il est curieux de noter qu'elles n'étaient pas nommées set*ByRef ce qui aurait été plus clair. Les fonctions semblent exister principalement pour effectuer une opération efficace, transformer un DF en DT et régler une clé. Qu'elles puissent être interprétées comme indiquant une opération par référence semble secondaire.

En ce qui concerne := , je pense me souvenir que @mattdowle s'est fait demander à user UCLA pourquoi il a utilisé := au lieu de = . IIRC, il a dit qu'il ne pouvait pas utiliser = et que := était disponible. IIRC, il aurait préféré utiliser = .

WRT, la norme dans la communauté R -- connue pour son manque de normes -- magrittr est aussi bonne que possible : omniprésente utilisée et discutée. L'OP suggère que l'interopérabilité avec ce serait une fonctionnalité intéressante. Je suis d'accord. Si vous avez des doutes à ce sujet, jetez un œil à sa page CRAN . Les développeurs utilisent magrittr dans leurs propres packages. De plus, l'écriture de packages n'est pas la majorité des utilisateurs de R. Mais c'est vraiment une digression du sujet.

L'argument que vous proposez relève de : "DT est différent de magrittr puisque l'affectation est par référence donc la syntaxe est différente". A quoi la réponse est toujours : La mise en œuvre est différente, c'est vrai. mais l'interface doit être la même car il s'agit effectivement des mêmes opérations pour la plupart des utilisateurs, conforme aux attentes de l'utilisateur et dont le véritable fonctionnement peut être déduit du contexte.

@mattdowle aurait pu clairement concevoir DT avec une interface purement fonctionnelle. Il ne l'a pas fait.

Je suis content qu'il ne l'ait pas fait. Verrouiller en "purement fonctionnel" se traduit simplement par la suppression de certaines fonctionnalités importantes que l'utilisateur est désormais capable d'utiliser afin d'écrire du code plus rapide et plus efficace en mémoire. J'ai des projets (c'est-à-dire des modèles d'ancrage ) qui seraient fondamentalement peu pratiques à utiliser dans un cadre "purement fonctionnel".

@jangorecki
Je suis entièrement d'accord. Mais nous commençons à m'éloigner de la proposition initiale vers les mérites de DT.

@MichaelChirico

Merci d'avoir éclairé la discussion. Les références s'éloignent un peu de la proposition originale, mais elles aident à illustrer les points en faveur de la proposition du PO, à savoir,

  • Le choix des opérateurs est arbitraire. Matt Dowle en a essayé plusieurs avant := . Il a d'abord essayé les choses évidentes qui auraient été plus alignées sur la norme en premier : <- , <<- , := était juste tombé par hasard parce qu'il était disponible et des alternatives faites pour une syntaxe laide . Il était clair qu'il préférait les opérateurs existants à la définition d'un nouveau.
  • L'utilisateur saura comprendre à partir du contexte que l'affectation se produit par affectation par référence, mais peu importe comment elle se produit.
  • Etc.

Premièrement, il n'y avait aucune prétention à parler pour TOUS les utilisateurs de R. C'est une affirmation ridicule. La référence aux "attentes des utilisateurs" était la mienne, probablement les PO et plusieurs de mes étudiants

C'est un dispositif rhétorique contre-productif et distrayant, je dirais, de faire référence aux "utilisateurs" alors que vous ne parlez en réalité que de vous-même. Vous avez peut-être également remarqué que l'OP a dit " %:>% me va bien".

L'action ou l'inaction des développeurs est un autre faux-fuyant et n'a aucun rapport avec le bien-fondé de la proposition/demande du PO. Il s'agit d'un argument d'appel à l'autorité plutôt médiocre qui n'a pas vraiment offert d'opinion dans un sens ou dans l'autre.

Ce n'est pas un appel à l'autorité puisque je n'argumente pas là. C'est un appel à vous calmer. Cela peut même ne jamais être mis en œuvre, alors ne pouvez-vous pas reporter l'agitation? J'imagine que ce sera une question triviale de changer le nom de la fonction après sa mise en œuvre (le cas échéant), et nous aurons une meilleure idée de la fonctionnalité exacte que nous examinons à ce stade.

En ce qui concerne les arguments de fond :

  • Je pense qu'il est très peu probable que magrittr utilise %<>% pour modifier plusieurs objets sur son LHS, comme list(x, y) %<>% log , analogue à DT[, c("x", "y") := lappy(.SD, log), .SDcols = c("x","y")] .
  • De même, le vôtre est le premier indice que j'ai vu que %<>% pourrait être utilisé pour modifier une partie d'un objet comme x[ 2:4 ] %<>% log , qui est analogue à DT[ 2:4, x := log(x) ] .

J'ai hâte de voir vos FR pour ces fonctionnalités sur https://github.com/tidyverse/magrittr/issues et j'espère qu'ils passeront, car j'utiliserais certainement cette fonctionnalité.

@franknarf1 ,

Point pris ; J'avais raté que l'OP ait dit que "%:>% me semble bien".

Néanmoins, il n'y a pas que moi. L'OP a d'abord suggéré la syntaxe magritr. Vraisemblablement, il a pensé que c'était une bonne idée malgré avoir concédé une alternative plus tard. J'avais aussi pensé que c'était une bonne idée, c'est ce qui m'a amené ici et cela a été poussé par plusieurs étudiants qui l'ont essayé. Vraisemblablement, il y en a d'autres. Rejeter cela comme un point de vue isolé est un peu hors de propos, de toute façon.

Deuxièmement, l'argument était, en fait, un appel à l'autorité. Cela peut aussi être "un appel pour que je me calme", ​​bien que je sois parfaitement calme. En tout état de cause, le point semble hors sujet, il n'aborde pas le bien-fondé de la suggestion du PO. De plus, le fait qu'il soit très peu probable que cela soit mis en œuvre ne semble pas être pertinent pour le bien-fondé de la proposition.

Il doit en outre admettre que vous avez raison. Il sera trivial de changer le nom de la fonction une fois implémentée. Cependant, un tel changement pourrait casser et cassera probablement tout code développé utilisant la fonctionnalité. Il est parfaitement logique de passer du temps à discuter de l'interface avant de l'implémenter plutôt que de surcharger les utilisateurs avec un changement incompatible plus tard. On ne sait pas vraiment à quoi sert la fermeture de la discussion.

En ce qui concerne les arguments de fond, ils semblent plaider davantage pour une fonctionnalité accrue de magrittr que pour aborder la syntaxe %<>% proposée. (Sur une note personnelle, je suis d'accord avec vous pour dire que les gens de magrittr devraient mettre en œuvre vos suggestions, en particulier la première. Je ne sais pas si j'utiliserais autant la seconde. ) Quelle que soit la proposition faite aux gens de magrittr, il n'y a rien incohérent de la part de DT d'adopter vos améliorations et d'utiliser l'opérateur magrittr %<>% . Et je n'ai pas encore vraiment lu et un argument convaincant de la supériorité de %:=% (ou un autre) à %<>% .

Dans un effort pour revenir au sujet, j'ai pensé qu'il pourrait être utile de résumer les arguments pertinents.

Argument en faveur de %:>% :

  • qu'une affectation DT pipe-forward implémentera l'affectation par référence. Ceci doit être distingué chez les opérateurs car il indique clairement aux utilisateurs comment l'affectation est mise en œuvre. Cela peut éviter une confusion inutile.
  • il peut y avoir des cas (par exemple, affectation multiple, affectation partielle) où DT peut ajouter des fonctionnalités supplémentaires qui ne sont pas (encore ?) prises en charge par magrittr. Par conséquent, il est préférable de distinguer les opérations.
  • %<>% est aussi arbitraire que n'importe quel autre choix, %:>% ressemble plus à DT.

Arguments en faveur de %<>% :

  • magrittr a déjà implémenté des opérateurs d'affectation pipe-forward, il est largement utilisé et autant que tout semble être une norme. Suivre une norme, même implicite, signifie que les charges des développeurs DT sont réduites dans la quantité de documentation et d'explications nécessaires pour décrire le nouvel opérateur.
  • Les utilisateurs utilisent déjà magrittr avec DT dans le RHS de := . De plus, certaines preuves suggèrent que les utilisateurs s'attendent à/ont essayé la syntaxe magrittr %<>% . Son adoption serait conforme aux attentes de ces utilisateurs.
  • Déplacer le code vers-depuis dplyr/magrittr <--> DT serait plus simple et plus facile, car dans certains cas, la syntaxe peut être similaire.
  • Une augmentation du nombre d'opérateurs entraîne une complexité supplémentaire. Dans ce cas, la complexité n'est pas nécessaire puisque les opérateurs doivent spécifier l'action et doivent nécessairement spécifier l'implémentation -- c'est ainsi que fonctionnent les méthodes génériques.
  • %:>% est aussi arbitraire que %<>% .

Déplacer le code vers-depuis dplyr/magrittr <--> DT serait plus simple et plus facile, car dans certains cas, la syntaxe peut être similaire.

Vous ne savez absolument pas comment une modification par référence casserait terriblement ce genre de code porté.
Les endroits où vous saviez que votre objet d'origine ne changera pas changeront soudainement car la méthode d'affectation change, c'est vraiment pourquoi il est important de distinguer les opérateurs (et de garder la possibilité d'affecter par valeur (copie) dans la même ligne de code aussi).

C'est le même problème que lorsque vous copiez un data.table par rapport à un data.frame (dt2 <- dt), vous vous demandez soudain pourquoi votre dt d'origine a été mis à jour alors que vous ne travailliez que sur le second.

Cette précaution exacte à prendre, invalide également votre premier point, car elle nécessite une documentation précise de ce que fait l'opérateur, en utiliser une autre facilitera la recherche de la bonne documentation.

@tensibai,

Compris. Ainsi, la partie « peut-être » de l'assertion.​

Le mercredi 2 novembre 2016 à 01h32, Tensibai [email protected] a écrit :

Déplacer le code vers-depuis dplyr/magrittr <--> DT serait plus simple et plus facile,
car dans certains cas, la syntaxe peut être similaire.

Vous manquez absolument comment une modification par référence serait terriblement
casser ce genre de code porté. Lieux où vous connaissiez votre original
l'objet ne changera pas changera soudainement parce que la méthode d'affectation
changement, c'est vraiment pourquoi il est important de distinguer les opérateurs
(et de garder la possibilité d'attribuer par valeur (copie) dans la même ligne
de code aussi) .

C'est le même problème que lorsque vous copiez un data.table vs copiez un data.frame
(dt2 <- dt), soudain vous vous demandez pourquoi votre dt d'origine a
été mis à jour alors que vous ne travailliez que sur le second.

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/Rdatatable/data.table/issues/1208#issuecomment-257801913 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AC5xaxyWXkh4C7i5-GtjMFiQ0AY2L5BLks5q6EqIgaJpZM4FSJR5
.

Merci pour tous vos commentaires et réactions.

Juste une petite chose (peut-être qu'il me manque quelque chose) : est-ce que, dans ce cas spécifique, cela fait même une différence, qu'il s'agisse d'une attribution par référence ou par valeur ? Ce que nous voulons faire, c'est mettre à jour une colonne (ou plusieurs colonnes) à l'intérieur du data.table. L'utilisateur sait que l'ancienne colonne sera écrasée de toute façon. Il n'y a pas de place pour le malentendu, n'est-ce pas ? En revanche, c'est très différent de DTa=DTb vs DTa=copy(DTb) (dont je ne parle pas dans cette demande de fonctionnalité), où nous avons affaire à la data.table elle-même, et où cela fait une différence que nous attribuions par référence ou par valeur.

@my-R-help,

Votre intuition est correcte.

Cela ne fait aucune différence pour l'utilisateur comment cette opération est _implémentée_. Du point de vue des utilisateurs, les résultats sont les mêmes : les valeurs de la colonne sont réaffectées. Il y a eu quelques arguments indiquant qu'il devrait y avoir une certaine différenciation, il n'y a pas eu d'explication convaincante quant au _pourquoi_.

Votre proposition d'adopter la syntaxe %<>% est judicieuse. Il suppose correctement que l'implémentation est distincte de l'_interface_ et puisqu'il existe une pratique courante et existante pour effectuer l'opération, elle doit être adoptée. Ceci, en fait, suit les bonnes pratiques de conception de logiciels.

(En passant, j'ai été un peu découragé lorsque vous avez déclaré : " Merci (SIC), % : > % me va bien." merci pour la proposition. C'est génial qu'elle soit implémentée dans DT ou non,)

Merci pour ta réponse Christophe.

Juste pour clarifier, j'ai personnellement une préférence pour %<>% car il est plus cohérent avec magrittr et beaucoup de gens semblent l'utiliser. Cependant, si les développeurs de data.table préfèrent un autre opérateur (par exemple %:>% ), je peux aussi vivre avec ça (bien que je préfère personnellement la méthode magrittr).

J'aurais peut-être dû le formuler ainsi. Désolé si cela a causé une confusion.

L'utilisateur sait que l'ancienne colonne sera écrasée de toute façon. Il n'y a pas de place pour le malentendu, n'est-ce pas ?

La manière dont cette opération est mise en œuvre n'a aucune importance pour l'utilisateur. Du point de vue des utilisateurs, les résultats sont les mêmes : les valeurs de la colonne sont réaffectées.

J'ai toujours l'impression qu'il y a de la place pour le foot-gun avec jointures.

Avoir deux opérateurs se comportant un peu différemment sur leurs effets secondaires nommés de la même manière est sujet aux erreurs et _conduira_ à la confusion. Je ne peux pas discuter mieux que cela, mais il y a une raison pour laquelle R vous avertit lorsqu'un package masque une fonction de base ou lors du chargement d'un package surcharge une autre fonction de package.

À mon avis, cela fait une différence pour au moins certains utilisateurs d'avoir des opérateurs spécifiques lorsque les effets secondaires seront différents.

_Bonus_ en cherchant l'opérateur, vous vous retrouverez sur la page DT expliquant ses mises en garde/limitations sans aucun doute au lieu d'avoir deux choix dans l'aide.

Ici, nous parlons d'un langage, pas d'une interface utilisateur, alors que je suis d'accord sur le fait qu'un utilisateur final du logiciel ne devrait pas se soucier de l'implémentation derrière le bouton X, je ne suis pas du tout d'accord qu'un programmeur ne devrait pas se soucier de l'implémentation derrière une fonction.

L'objection majeure est : quelqu'un qui pense que %<>% se comportera de la même manière qu'à l'extérieur d'un DT deviendra fou quand il rayera ses colonnes DT alors que ce n'est pas prévu.

TL; DR : La programmation n'est pas une UX, vous devez être précis sur ce que vous voulez, donc la réutilisation de noms bien connus ne devrait pas se produire.

@Tensibai ,

L'affirmation selon laquelle les effets secondaires sont en quelque sorte différents est douteuse. Dans chaque cas, une réaffectation de variable est effectuée. Ce sont deux effets secondaires. L'implémentation (par référence ou par valeur) ne les distingue pas vraiment car les états finaux comparatifs des deux systèmes ont changé de manière analogue.

Même si les effets secondaires sont différents. La distinction est plutôt sans importance. Ce point a été soulevé à plusieurs reprises dans la discussion ci-dessus. Si la distinction était importante, il devrait être possible de fournir un exemple où cela ferait une différence pour l'utilisateur. L'absence d'un contre-exemple, bien qu'elle ne soit pas concluante, est une forte indication qu'il n'y a pas de distinction.

Par rapport à:

vous devez être précis sur ce que vous voulez, donc la réutilisation de noms bien connus ne devrait pas se produire.

C'est tout simplement faux. La réutilisation de noms communs et bien connus devrait non seulement se produire, mais elle est très courante et est considérée comme une bonne pratique de programmation. C'est ce qu'on appelle le polymorphisme. Il est parfaitement acceptable d'avoir des méthodes avec le même nom qui sont implémentées différemment :

personne.parle()
"Bonjour le monde"
chien.parle()
"trame"

speak été utilisé dans chaque cas. Est-ce une mauvaise pratique ? Non. En fait, si le polymorphisme n'était pas adopté, ce serait un désastre ; chaque fonction et méthode aurait son propre nom. Bien qu'il s'agisse d'un exemple assez générique basé sur les langages OO, R n'est pas différent. R a des méthodes S3 et une fonction générique qui fonctionnent de manière similaire.

La suggestion que :

Je ne suis pas du tout d'accord qu'un programmeur ne devrait pas se soucier de l'implémentation derrière une fonction.

est tout aussi défectueux et va à l'encontre de l'expérience de la plupart des utilisateurs. La plupart des programmeurs utilisent probablement des centaines de fonctions/méthodes. Ils le font sans connaître les détails de leur mise en œuvre. L'utilisateur a besoin de connaître l'entrée et la sortie/les effets secondaires pour que les fonctions soient utiles, mais comment y parvenir est le plus souvent sans importance. Certes, les utilisateurs ont parfois besoin de connaître les détails pour modifier ou déboguer la fonction, mais on peut affirmer que cela dans la grande minorité des cas. Considérez le monde où les utilisateurs devaient savoir comment chaque fonction fonctionnait à tous les niveaux. La charge cognitive serait immense ; programmer quoi que ce soit de complexe serait une tâche impossible. Par rapport à:

Bonus en recherchant l'opérateur, vous vous retrouverez sur la page DT expliquant ses mises en garde/limitations sans aucun doute au lieu d'avoir deux choix dans l'aide.

Ce n'est pas un _Bonus_, mais une responsabilité par a) introduisant de la confusion (en quoi est-ce différent des packages magrittr très populaires, exactement ?) et le b) créant le besoin d'une documentation supplémentaire inutile en premier lieu. Si la syntaxe magrittr, les développeurs DT peuvent dire : « allez-y et lisez-y les documents et la vignette ; DT prend en charge ce qu'ils font là-bas. » Cette coopération et ces emprunts croisés valorisent DT, magrittr et l'écosystème R. )

Enfin, on peut déduire que des commentaires sur « l'interface utilisateur », « bouton X » et « UX » impliquaient une interface utilisateur spécifique. Ce n'est tout simplement pas le cas. Et, alors qu'il est tout à fait clair que nous parlons d'une langue, il est erroné de dire que la langue manque d'interface. L'interface est sa syntaxe et elle est importante.

Pour résumer, le problème peut donc être finalement résolu.

Tout ce dont nous avons besoin est de gérer la traduction suivante.

DT[, a %<:>% fun] ## or "%:>%"

DT[, a := fun(a)]

Est-ce correct?

comment doit-il se comporter si a n'est pas un symbole mais une variable de caractère ?

DT[, "a" %<:>% fun]

DT[, "a" := fun(a)]   ## this?
DT[, "a" := fun("a")] ## or this?

et si sa longueur n'est pas 1 ?

DT[, c("a","b") %<:>% fun]

DT[, c("a","b") %<:>% fun(a, b)]
DT[, c("a","b") %<:>% fun("a","b")]
DT[, c("a","b") %<:>% lapply(list(a, b), fun)]
DT[, c("a","b") %<:>% lapply(c("a", "b"), fun)]

Personnellement, je le fermerais car cela ne résoudra pas car il ajoute beaucoup de complexité et ne résout aucun nouveau problème.
Je vois un accord là-dessus, donc fermant, nous pouvons toujours rouvrir si vraiment nécessaire.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

jameslamb picture jameslamb  ·  3Commentaires

st-pasha picture st-pasha  ·  3Commentaires

andschar picture andschar  ·  3Commentaires

jangorecki picture jangorecki  ·  3Commentaires

rafapereirabr picture rafapereirabr  ·  3Commentaires