首页 > 解决方案 > R设置缺失因子值的默认值

问题描述

我经常使用formula对象,发现将离散变量重塑为因子非常方便。假设以下示例:

library(caret); library(data.table); data("iris"); iris <- as.data.table(iris)
dummy <- dummyVars(~ -1 + factor(Species, 
                                 levels = c("setosa", "versicolor", "virginica")
                                 ), data = iris)
predict(dummy, newdata = iris[1,])

它按预期返回正确的帧。

我的问题:

如果给出了新的未定义级别,Species则因子返回NA,同时还会弄乱最终输出:

predict(dummy, newdata = iris[1,][, Species:= "something_undefined"])

但是,在某些情况下,将新标签替换为默认值是有用的,即典型/中值标签而不是NA. 我能想到的一种可能方法是编写一个自定义custom.na.impute函数来处理这些值并将其用于 default na.action,即

predict(dummy, newdata = iris[1,][, Species:= "something_undefined"], 
        na.action = custom.na.impute)

但是,如果我理解正确,在这里我必须为所有不同的因素手动编写规则,并在包含新因素的情况下对其进行更新。相反,我正在寻找这样的东西

factor(Species, levels = c("setosa", "versicolor", "virginica"),
                na.value = "setosa")

也就是说,能够为 any 定义默认/缺失值factor并直接在公式对象中指定它,而不必乱用 custom na.actions

任何想法/建议将不胜感激!

标签: r

解决方案


评论我自己的问题,因为我无法在现有包中找到更清洁/实现的解决方案。但它可能对某人有用。

无论哪种情况,仍然欢迎更好的解决方案!

factor解决方案是通过以下方式修改现有功能:

factor2 <- function (x = character(), levels, labels = levels, exclude = NA, 
          ordered = is.ordered(x), nmax = NA, default = NA) 
{
  # --- Added rows
  if(!is.na(default)){
    levels <- unique(c(levels, default))
  }
  # ---

  if (is.null(x)) 
    x <- character()
  nx <- names(x)
  if (missing(levels)) {
    y <- unique(x, nmax = nmax)
    ind <- sort.list(y)
    y <- as.character(y)
    levels <- unique(y[ind])
  }
  force(ordered)
  exclude <- as.vector(exclude, typeof(x))
  x <- as.character(x)
  levels <- levels[is.na(match(levels, exclude))]

  # --- Modified rows
  f <- match(x, levels, nomatch = which(levels == default)[1])
  # ---

  if (!is.null(nx)) 
    names(f) <- nx
  nl <- length(labels)
  nL <- length(levels)
  if (!any(nl == c(1L, nL))) 
    stop(gettextf("invalid 'labels'; length %d should be 1 or %d", 
                  nl, nL), domain = NA)
  levels(f) <- if (nl == nL) 
    as.character(labels)
  else paste0(labels, seq_along(levels))
  class(f) <- c(if (ordered) "ordered", "factor")
  f
}

现在该default值要么作为新级别添加,要么在新值不是时更正匹配levels

现在预测正在按预期工作:

dummy <- dummyVars(~ -1 + factor2(Species, 
                                 levels = c("setosa", "versicolor", "virginica"),
                                 default = "versicolor"
), data = iris)

预测返回正确的默认级别,无需进一步修改任何代码:

predict(dummy, newdata = iris[1,][, Species:= "something_undefined"])

注意:代替factor2,assignInNamespace('factor', factor2, 'base')也应该可以工作,尽管它更具侵入性。


推荐阅读