R设置缺失因子值

时间:2018-05-18 13:10:12

标签: 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函数来处理这些值并将其用于默认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")

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

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

1 个答案:

答案 0 :(得分:0)

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

在任何一种情况下,仍然欢迎更好的解决方案!

解决方案是以下列方式修改现有的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')也应该有效,但它更具侵入性。