110 votes

« niveaux <-'(quelle sorcellerie s’agit-il ?

Dans une réponse à une autre question, @Marek posté la solution suivante: http://stackoverflow.com/a/10432263/636656

dat <- structure(list(product = c(11L, 11L, 9L, 9L, 6L, 1L, 11L, 5L, 
                                  7L, 11L, 5L, 11L, 4L, 3L, 10L, 7L, 10L, 5L, 9L, 8L)), .Names = "product", row.names = c(NA, -20L), class = "data.frame")

`levels<-`(
  factor(dat$product),
  list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12)
  )

Qui produit en sortie:

 [1] Generic Generic Bayer   Bayer   Advil   Tylenol Generic Advil   Bayer   Generic Advil   Generic Advil   Tylenol
[15] Generic Bayer   Generic Advil   Bayer   Bayer  

C'est juste l'impression d'un vecteur, pour ainsi stocker vous pouvez faire encore plus de confusion:

res <- `levels<-`(
  factor(dat$product),
  list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12)
  )

Clairement, c'est une sorte d'appel à des niveaux de fonction, mais je n'ai aucune idée de ce qui est fait ici. Quel est le terme pour ce genre de sorcellerie, et comment puis-je augmenter ma capacité magique dans ce domaine?

100voto

Owen Points 14439

Les réponses ici sont bons, mais ils ne sont pas un point important. Laissez-moi essayer de le décrire.

R est un langage fonctionnel et n'aime pas muter ses objets. Mais il permet à des instructions d'affectation, à l'aide des fonctions de remplacement:

levels(x) <- y

est équivalent à

x <- `levels<-`(x, y)

Le truc est, cette réécriture se fait par <-; il n'est pas fait par levels<-. levels<- est juste une simple fonction qui prend en entrée et donne une sortie; il n'a pas de muter n'importe quoi.

Une conséquence de ceci est que, selon la règle ci-dessus, <- doit être récursive:

levels(factor(x)) <- y

est

factor(x) <- `levels<-`(factor(x), y)

est

x <- `factor<-`(x, `levels<-`(factor(x), y))

C'est une sorte de beau que ce pur-transformation fonctionnelle (jusqu'à la toute fin, où l'affectation a lieu) est équivalent à ce que la cession serait dans un langage impératif. Si je me souviens bien, cette construction dans les langages fonctionnels est appelé un objectif.

Mais ensuite, une fois que vous avez défini les fonctions de remplacement comme levels<-, vous obtenez un autre, gain inattendu: vous ne vous contentez pas avoir la capacité de faire des assignations, vous avez une fonction très pratique qui prend en facteur, et donne un autre facteur à différents niveaux. Il n'y a vraiment rien de "cession" à ce sujet!

Donc, le code que vous décrivez est tout simplement faire de l'utilisation de cet autre interprétation de l' levels<-. J'avoue que le nom de l' levels<- est un peu déroutant, car elle suggère une affectation, mais ce n'est pas ce qui se passe. Le code est simplement la configuration d'une sorte de pipeline:

  • Commencez avec dat$product

  • Convertir un facteur

  • Modifier les niveaux

  • Magasin qui en res

Personnellement, je pense que cette ligne de code est très belle ;)

31voto

Joshua Ulrich Points 68776

Pas de sorcellerie, c'est juste la façon de (sous -) attribution de fonctions sont définies. levels<- est un peu différente, car elle est une primitive de (sous -) affecter les attributs d'un facteur, et non des éléments eux-mêmes. Il y a beaucoup d'exemples de ce type de fonction:

`<-`              # assignment
`[<-`             # sub-assignment
`[<-.data.frame`  # sub-assignment data.frame method
`dimnames<-`      # change dimname attribute
`attributes<-`    # change any attributes

D'autres opérateurs binaires peut être appelé comme ça aussi:

`+`(1,2)  # 3
`-`(1,2)  # -1
`*`(1,2)  # 2
`/`(1,2)  # 0.5

Maintenant que vous savez que quelque chose comme cela devrait vraiment souffler votre esprit:

Data <- data.frame(x=1:10, y=10:1)
names(Data)[1] <- "HI"              # How does that work?!? Magic! ;-)

30voto

Tommy Points 16323

La raison de cette « magie », c’est que la forme de « cession » doit avoir une variable réelle à travailler sur. Et le `` n’a pas été assignés à quoi que ce soit.

16voto

Gavin Simpson Points 72349

Pour l'utilisateur, le code, je me demande pourquoi un tel langage manipulations sont utilisés de la sorte? Vous vous demandez ce qu'est la magie et d'autres ont souligné que vous appelez la fonction de remplacement qui a le nom de l' levels<-. Pour la plupart des gens, c'est magique et vraiment l'utilisation prévue est - levels(foo) <- bar.

Le cas d'utilisation de vous montrer, c'est différent, car product n'existe pas dans l'environnement global, de sorte qu'il n'a jamais existe dans l'environnement local de l'appel à levels<- ainsi le changement que vous voulez faire ne persiste pas - il n'y a pas de réaffectation d' dat.

Dans ces circonstances, within() est la fonction idéale à utiliser. Vous voudra naturellement à écrire

levels(product) <- bar

dans la R mais, bien sûr, product n'existe pas en tant qu'objet. within() est-ce parce qu'il met en place l'environnement que vous souhaitez exécuter votre R code contre et évalue votre expression au sein de cet environnement. Affectation de l'objet de retour de l'appel à la within() donc réussit à l'correctement modifié bloc de données.

Voici un exemple (vous n'avez pas besoin de créer de nouveaux datX - je viens de le faire donc les étapes intermédiaires restent à la fin)

## one or t'other
#dat2 <- transform(dat, product = factor(product))
dat2 <- within(dat, product <- factor(product))

## then
dat3 <- within(dat2, 
               levels(product) <- list(Tylenol=1:3, Advil=4:6, 
                                       Bayer=7:9, Generic=10:12))

Ce qui donne:

> head(dat3)
  product
1 Generic
2 Generic
3   Bayer
4   Bayer
5   Advil
6 Tylenol
> str(dat3)
'data.frame':   20 obs. of  1 variable:
 $ product: Factor w/ 4 levels "Tylenol","Advil",..: 4 4 3 3 2 1 4 2 3 4 ...

J'ai du mal à voir comment les constructions comme celle que vous montrez sont utiles dans la majorité des cas - si vous souhaitez modifier les données, modifier les données, ne pas créer une autre copie et modifier (ce qui est tout l' levels<- appel est en train de faire, après tout).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X