我经常使用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
。
任何想法/建议都将不胜感激!
答案 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')
也应该有效,但它更具侵入性。