-2

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 よりもハードコアであると理解しています)。

4

3 に答える 3