`水平<-`(这是什么巫术?
在回答另一个问题时,@Marek发布了以下解决scheme: https ://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) )
作为输出产生:
[1] Generic Generic Bayer Bayer Advil Tylenol Generic Advil Bayer Generic Advil Generic Advil Tylenol [15] Generic Bayer Generic Advil Bayer Bayer
这只是一个vector的打印输出,所以要存储它,你可以做更多的混淆:
res <- `levels<-`( factor(dat$product), list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12) )
显然这是对关卡function的一种调用,但我不知道这里正在做什么。 这种巫术的术语是什么,如何提高我在这个领域的魔法能力?
这里的答案是好的,但是他们缺less重要的一点。 让我试着描述一下。
R是一种function语言,不喜欢改变它的对象。 但它确实允许使用replace函数的赋值语句:
levels(x) <- y
相当于
x <- `levels<-`(x, y)
诀窍是,这个重写是通过<-
; 它不是由levels<-
完成的。 levels<-
只是一个正则函数,它接受一个input并给出一个输出; 它不会改变任何东西。
其中的一个后果就是根据上述规则,必须recursion:
levels(factor(x)) <- y
是
factor(x) <- `levels<-`(factor(x), y)
是
x <- `factor<-`(x, `levels<-`(factor(x), y))
这种纯粹function的转换(直到最后,分配发生的地方)等同于命令式语言中的分配是相当美丽的。 如果我没有记错的话,这个函数式语言的结构被称为镜头。
但是,一旦你定义了替代函数如levels<-
,你会得到另一个意想不到的意外收获:你不仅有能力进行任务分配,还有一个方便的函数来接受一个因素,并给出另一个因素不同的层次。 关于它的确没有任何“任务”!
所以,你所描述的代码就是利用这个levels<-
其他解释levels<-
。 我承认,名称levels<-
有点令人困惑,因为它表明了一个任务,但这不是发生的事情。 代码只是build立一种pipe道:
-
从
dat$product
开始 -
把它转换成一个因子
-
更改级别
-
将其存储在
res
就我个人而言,我认为这行代码很漂亮;)
这个“魔术”的原因是“分配”forms必须有一个真正的variables来处理。 而factor(dat$product)
没有分配给任何东西。
# This works since its done in several steps x <- factor(dat$product) levels(x) <- list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12) x # This doesn't work although it's the "same" thing: levels(factor(dat$product)) <- list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12) # Error: could not find function "factor<-" # and this is the magic work-around that does work `levels<-`( factor(dat$product), list(Tylenol=1:3, Advil=4:6, Bayer=7:9, Generic=10:12) )
没有巫术,只是(子)赋值函数是如何定义的。 levels<-
有点不同,因为它是一个基本的(子)分配一个因素的属性,而不是元素本身。 这种types的function有很多例子:
`<-` # assignment `[<-` # sub-assignment `[<-.data.frame` # sub-assignment data.frame method `dimnames<-` # change dimname attribute `attributes<-` # change any attributes
其他二元运算符也可以这样调用:
`+`(1,2) # 3 `-`(1,2) # -1 `*`(1,2) # 2 `/`(1,2) # 0.5
现在你知道了,这样的事情应该真的让你心碎:
Data <- data.frame(x=1:10, y=10:1) names(Data)[1] <- "HI" # How does that work?!? Magic! ;-)
对于用户代码,我不明白为什么要使用这种语言操作? 你问这是什么魔术,而其他人指出你正在调用名称levels<-
的replace函数。 对于大多数人来说,这是神奇的,真正的目的是使用levels(foo) <- bar
。
你显示的用例是不同的,因为product
不存在于全局环境中,所以它只存在于调用levels<-
的本地环境中levels<-
因此,你想要做的改变不会持久 – 没有重新分配dat
。
在这种情况下, within()
是理想的使用function。 你当然希望写
levels(product) <- bar
在R但当然product
不存在作为一个对象。 within()
解决了这个问题,因为它build立了你希望运行你的R代码的环境,并在那个环境中评估你的expression式。 将调用的返回对象分配给within()
可以正确修改dataframe。
这里是一个例子(你不需要创build新的datX
– 我只是这样做,所以中间步骤仍然在最后)
## 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))
这使:
> 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 ...
我很努力地看到,在大多数情况下,你所显示的结构是如何有用的 – 如果你想改变数据,改变数据,不要创build另一个副本,并改变它(这是所有的levels<-
调用是毕竟做)。