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")
でも、2 番目の部分が実行されます)。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 よりもハードコアであると理解しています)。