Lorsque je dois filtrer un data.frame, c'est-à-dire extraire des lignes qui remplissent certaines conditions, je préfère utiliser la subset
fonction:
subset(airquality, Month == 8 & Temp > 90)
Plutôt que la [
fonction:
airquality[airquality$Month == 8 & airquality$Temp > 90, ]
Il y a deux raisons principales à ma préférence:
Je trouve que le code se lit mieux, de gauche à droite. Même les personnes qui ne connaissent rien à R pourraient dire ce que fait la
subset
déclaration ci-dessus.Étant donné que les colonnes peuvent être appelées variables dans l'
select
expression, je peux enregistrer quelques frappes. Dans mon exemple ci-dessus, je n'ai dû taperairquality
qu'une seule fois avecsubset
, mais trois fois avec[
.
Je vivais donc heureux, en utilisant subset
partout parce qu'il est plus court et se lit mieux, même en préconisant sa beauté à mes collègues codeurs R. Mais hier, mon monde s'est brisé. En lisant la subset
documentation, je remarque cette section:
Attention
Il s'agit d'une fonction pratique destinée à être utilisée de manière interactive. Pour la programmation, il est préférable d'utiliser les fonctions de sous-ensemble standard comme [, et en particulier l'évaluation non standard du sous-ensemble d'arguments peut avoir des conséquences imprévues.
Quelqu'un pourrait-il aider à clarifier ce que les auteurs veulent dire?
Premièrement, que veulent-ils dire par « pour une utilisation interactive »? Je sais ce qu'est une session interactive, par opposition à un script exécuté en mode BATCH mais je ne vois pas quelle différence cela devrait faire.
Ensuite, pourriez-vous expliquer " l'évaluation non standard du sous-ensemble d'arguments " et pourquoi elle est dangereuse, peut-être fournir un exemple?
with(airquality, airquality[Month == 8 & Temp > 90, ])
dplyr::filter
a le même problème. Autrement dit, si l'environnement possède une variable portant ce nom, il l'utilisera à la place de la variable dans le bloc de données. Rend le débogage déroutant!Réponses:
Cette question a été bien répondu dans les commentaires de @James, pointant une excellente explication par Hadley Wickham des dangers de
subset
(et des fonctions similaires) [ici] . Allez le lire!C'est une lecture assez longue, donc il peut être utile d'enregistrer ici l'exemple que Hadley utilise qui répond le plus directement à la question de "qu'est-ce qui peut mal tourner?":
Hadley suggère l'exemple suivant: supposons que nous voulons sous-ensemble puis réorganiser une trame de données en utilisant les fonctions suivantes:
Cela renvoie l'erreur:
car R ne "sait" plus où trouver l'objet appelé 'cyl'. Il souligne également les choses vraiment bizarres qui peuvent se produire si par hasard il y a un objet appelé «cyl» dans l'environnement mondial:
(Exécutez-les et voyez par vous-même, c'est assez fou.)
la source
subset(mtcars, cyl == 4)
(au niveau supérieur), où R recherche-t-il cyl? S'il regarde l'mtcars
objet qui est passé àsubset()
, alors ne devrait-il pas être capable de trouvercyl
même s'il sescramble
trouve dans une autre fonction, car il luimtcars
est toujours transmis? Si ma question n'a pas de sens, vous pouvez simplement expliquer pourquoi R ne peut plus trouvercyl
. Merci!subset.data.frame
, la chose que nous essayons d'évaluer à ce stade est justecondition
. Cela n'existe pasmtcars
.subset.data.frame
Utilise doncenclos = parent.frame()
pour s'assurer qu'ilcondition
est correctement évalué commecyl == 4
. Mais ensuite, nous avons remonté jusqu'au cadre englobant, et maintenant, lorsque R cherche,cyl
il ne regarde plus à l'intérieurmtcars
. Si nous ne l'utilisions pasenclos
, quelque chose comme çasubset(mtcars,cyl == a)
ne fonctionnerait pas du tout.subset.data.frame
estx[r, vars, drop = drop]
. Le problème est de savoir comment passer des arguments non citéssubset
et desselect
arguments à quelque chose que vous pouvez valablement transmettre[.data.frame
.[]
?Est également
[
plus rapide:la source
subset
contrairement à[
supprime les lignes où le filtre est évaluéNA
. Faites-le et vous verrez qu'ils sont tous les deux aussi rapides que comparés "assez":x <- do.call(rbind, rep(list(airquality), 100)); microbenchmark(subset(x, Month == 8 & Temp > 90),{ i <- x$Month == 8 & x$Temp > 90; x[!is.na(i) & i ,] })