base::levels
帮助文件https://stat.ethz.ch/R-manual/R-devel/library/base/html/levels.html包含以下修改变量级别的示例:
z <- gl(3, 2, 12, labels = c("apple", "salad", "orange"))
z
levels(z) <- c("fruit", "veg", "fruit")
z
假设这些东西位于数据框内:
mydata <- data.frame(z=gl(3, 2, 12, labels = c("apple", "salad", "orange")), n=1:12)
我想编写一个函数来转换将数据框和变量名称作为输入的级别:
modify_levels <- function(df,varname,from,to) {
### MAGIC HAPPENS
}
这样就modify_levels(mydata,z,from=c("apple","orange"),to="fruit")
完成了转换的一部分(并且modify_levels(mydata,z,from=c("salad","broccoli"),to="veg")
完成了第二部分,即使该级别broccoli
可能不存在于我的数据集中)。
使用一些非标准的评估巫毒,我可以缩小我需要修改的内容:
where_are_levels <- function(df,varname,from,to,verbose=FALSE) {
# input checks
if ( !is.data.frame(df) ) {
stop("df is not a data frame")
}
if ( !is.factor(eval(substitute(varname),df)) ) {
stop("df$varname is not a factor")
}
if (verbose==TRUE) {
cat("df$varname is",
paste0(substitute(df),"$",substitute(varname)))
cat(" which evaluates to:\n")
print( eval(substitute(varname),df) )
}
if (length(to)!=1) {
stop("Substitution is ambiguous")
}
# figure out what the cases are with the supplied source values
for (val in from) {
r <- (eval(substitute(varname),df) == val)
if (verbose==TRUE) {
print(r)
cat( paste0(substitute(df),"$",substitute(varname)),"==",val)
cat(": ",sum(r), "case(s)\n")
}
}
}
到目前为止,一切都很好(to
尽管该选项没有任何作用):
> where_are_levels(mydata,z,from=c("apple","orange"),to="",verbose=TRUE)
## df$varname is mydata$z which evaluates to:
## [1] apple apple salad salad orange orange apple apple salad salad orange orange
## Levels: apple salad orange
## [1] TRUE TRUE FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE FALSE FALSE
## mydata$z == apple: 4 case(s)
## [1] FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE FALSE FALSE TRUE TRUE
## mydata$z == orange: 4 case(s)
现在,对于下一步,我认为我需要做的是将目标变量的级别附加一个附加级别,并更改该变量的值。在互动工作中,我会
# to <- "fruit" # passed as a function argument
l1 <- levels(mydata$z)
levels(mydata$z) <- union(l1,to)
mydata[r,"z"] <- to
其中我只能在val
循环中以编程方式获得第一行:
l1 <- levels(eval(substitute(varname),df))
这将在val
循环内发生。
请注意,我想保留现有的苹果和橙子级别,而不是仅仅改变整个事情(如帮助文件中的大修示例中所做的那样)。
如果解决方案更容易通过dplyr
从头开始编程来实现,那对我来说很好(尽管我的理解是带有它的 NSE 甚至dplyr
比基础 R 中更核心)。