Ответ 1
Вступление
Что такое "ошибка контрастов", хорошо объяснено: у вас есть фактор, который имеет только один уровень (или меньше). Но в действительности этот простой факт может быть легко скрыт, потому что данные, которые фактически используются для подгонки модели, могут сильно отличаться от того, что вы передали. Это происходит, когда у вас есть NA
в ваших данных, вы поднастроили свои данные, фактор имеет неиспользуемые уровни, или вы преобразовали свои переменные и где-то получили NaN
. Вы редко находитесь в этой идеальной ситуации, когда одноуровневый фактор может быть обнаружен непосредственно из str(your_data_frame)
напрямую. Многие вопросы в StackOverflow относительно этой ошибки не воспроизводимы, поэтому предложения людей могут работать, а могут и не работать. Поэтому, хотя на данный момент существует 118 сообщений по этой проблеме, пользователи все еще не могут найти адаптивное решение, чтобы этот вопрос поднимался снова и снова. Этот ответ - моя попытка решить этот вопрос "раз и навсегда" или, по крайней мере, предоставить разумное руководство.
Этот ответ содержит богатую информацию, поэтому позвольте мне сначала сделать краткое резюме.
Я определил для вас 3 вспомогательные функции: debug_contr_error
, debug_contr_error2
, NA_preproc
.
Я рекомендую вам использовать их следующим образом.
- запустить
NA_preproc
чтобы получить более полные случаи; - запустите вашу модель, и если вы получаете "ошибку контрастов", используйте
debug_contr_error2
для отладки.
Большая часть ответа показывает вам шаг за шагом, как и почему эти функции определены. Вероятно, нет никакого вреда, чтобы пропустить этот процесс разработки, но не пропустите разделы из "Воспроизводимых тематических исследований и обсуждений".
Пересмотренный ответ
Оригинальный ответ отлично работает для ОП и успешно помог другим. Но он потерпел неудачу где-то еще из- за отсутствия адаптивности. Посмотрите на вывод str(ad.train)
в вопросе. Переменные OP являются числовыми или факторами; нет персонажей. Первоначальный ответ был для этой ситуации. Если у вас есть символьные переменные, хотя они будут приведены к факторам во время glm
lm
и glm
, они не будут сообщаться кодом, так как они не были предоставлены как факторы, поэтому is.factor
будет их пропускать. В этом расширении я сделаю оригинальный ответ более адаптивным.
Пусть dat
будет вашим набором данных, переданным в lm
или glm
. Если у вас нет такого фрейма данных, то есть все ваши переменные разбросаны в глобальной среде, вам нужно собрать их в фрейм данных. Следующее может быть не лучшим способом, но это работает.
## 'form' is your model formula, here is an example
y <- x1 <- x2 <- x3 <- 1:4
x4 <- matrix(1:8, 4)
form <- y ~ bs(x1) + poly(x2) + I(1 / x3) + x4
## to gather variables 'model.frame.default(form)' is the easiest way
## but it does too much: it drops 'NA' and transforms variables
## we want something more primitive
## first get variable names
vn <- all.vars(form)
#[1] "y" "x1" "x2" "x3" "x4"
## 'get_all_vars(form)' gets you a data frame
## but it is buggy for matrix variables so don't use it
## instead, first use 'mget' to gather variables into a list
lst <- mget(vn)
## don't do 'data.frame(lst)'; it is buggy with matrix variables
## need to first protect matrix variables by 'I()' then do 'data.frame'
lst_protect <- lapply(lst, function (x) if (is.matrix(x)) I(x) else x)
dat <- data.frame(lst_protect)
str(dat)
#'data.frame': 4 obs. of 5 variables:
# $ y : int 1 2 3 4
# $ x1: int 1 2 3 4
# $ x2: int 1 2 3 4
# $ x3: int 1 2 3 4
# $ x4: 'AsIs' int [1:4, 1:2] 1 2 3 4 5 6 7 8
## note the 'AsIs' for matrix variable 'x4'
## in comparison, try the following buggy ones yourself
str(get_all_vars(form))
str(data.frame(lst))
Шаг 0: явное подмножество
Если вы использовали аргумент subset
lm
или glm
, начните с явного подмножества:
## 'subset_vec' is what you pass to 'lm' via 'subset' argument
## it can either be a logical vector of length 'nrow(dat)'
## or a shorter positive integer vector giving position index
## note however, 'base::subset' expects logical vector for 'subset' argument
## so a rigorous check is necessary here
if (mode(subset_vec) == "logical") {
if (length(subset_vec) != nrow(dat)) {
stop("'logical' 'subset_vec' provided but length does not match 'nrow(dat)'")
}
subset_log_vec <- subset_vec
} else if (mode(subset_vec) == "numeric") {
## check range
ran <- range(subset_vec)
if (ran[1] < 1 || ran[2] > nrow(dat)) {
stop("'numeric' 'subset_vec' provided but values are out of bound")
} else {
subset_log_vec <- logical(nrow(dat))
subset_log_vec[as.integer(subset_vec)] <- TRUE
}
} else {
stop("'subset_vec' must be either 'logical' or 'numeric'")
}
dat <- base::subset(dat, subset = subset_log_vec)
Шаг 1: удалить незавершенные дела
dat <- na.omit(dat)
Вы можете пропустить этот шаг, если вы прошли шаг 0, так как subset
автоматически удаляет незавершенные случаи.
Шаг 2: проверка режима и конвертация
Столбец фрейма данных обычно представляет собой атомарный вектор с режимом из следующих: "логический", "числовой", "сложный", "символ", "необработанный". Для регрессии переменные разных режимов обрабатываются по-разному.
"logical", it depends
"numeric", nothing to do
"complex", not allowed by 'model.matrix', though allowed by 'model.frame'
"character", converted to "numeric" with "factor" class by 'model.matrix'
"raw", not allowed by 'model.matrix', though allowed by 'model.frame'
Логическая переменная хитрая. Она может быть либо обработана как фиктивная переменная (1
для TRUE
; 0
для FALSE
), следовательно, "числовая", либо может быть приведена к двухуровневому коэффициенту. Все зависит от того, считает ли model.matrix
принуждение "к фактору" из спецификации формулы вашей модели. Для простоты мы можем понять это как таковое: оно всегда приводится к фактору, но результат применения контрастов может в итоге привести к той же матрице модели, как если бы она была обработана как фиктивная напрямую.
Некоторые люди могут задаться вопросом, почему "целое число" не включено. Потому что целочисленный вектор, как 1:4
, имеет "числовой" режим (попробуйте mode(1:4)
).
Столбец фрейма данных также может быть матрицей с классом "AsIs", но такая матрица должна иметь "числовой" режим.
Наша проверка состоит в том, чтобы произвести ошибку, когда
- найден "сложный" или "сырой";
- найдена матричная переменная "логический" или "символьный";
и приступить к преобразованию "логический" и "символ" в "числовой" класса "фактор".
## get mode of all vars
var_mode <- sapply(dat, mode)
## produce error if complex or raw is found
if (any(var_mode %in% c("complex", "raw"))) stop("complex or raw not allowed!")
## get class of all vars
var_class <- sapply(dat, class)
## produce error if an "AsIs" object has "logical" or "character" mode
if (any(var_mode[var_class == "AsIs"] %in% c("logical", "character"))) {
stop("matrix variables with 'AsIs' class must be 'numeric'")
}
## identify columns that needs be coerced to factors
ind1 <- which(var_mode %in% c("logical", "character"))
## coerce logical / character to factor with 'as.factor'
dat[ind1] <- lapply(dat[ind1], as.factor)
Обратите внимание, что если столбец фрейма данных уже является факторной переменной, он не будет включен в ind1
, поскольку факторная переменная имеет "числовой" режим (попробуйте mode(factor(letters[1:4]))
).
Шаг 3: сбросить неиспользованные уровни факторов
У нас не будет неиспользованных факторных уровней для факторных переменных, преобразованных из шага 2, т. ind1
Индексированных по ind1
. Однако факторные переменные, которые идут с dat
могут иметь неиспользуемые уровни (часто в результате шага 0 и шага 1). Нам нужно отбросить любые возможные неиспользованные уровни от них.
## index of factor columns
fctr <- which(sapply(dat, is.factor))
## factor variables that have skipped explicit conversion in step 2
## don't simply do 'ind2 <- fctr[-ind1]'; buggy if 'ind1' is 'integer(0)'
ind2 <- if (length(ind1) > 0L) fctr[-ind1] else fctr
## drop unused levels
dat[ind2] <- lapply(dat[ind2], droplevels)
шаг 4: суммировать факторные переменные
Теперь мы готовы увидеть, что и сколько факторных уровней фактически используется lm
или glm
:
## export factor levels actually used by 'lm' and 'glm'
lev <- lapply(dat[fctr], levels)
## count number of levels
nl <- lengths(lev)
Чтобы сделать вашу жизнь проще, я обернул эти шаги в функцию debug_contr_error
.
Входные данные :
-
dat
- ваш фрейм данных, переданный вlm
илиglm
через аргументdata
; -
subset_vec
- индексный вектор, передаваемый вlm
илиglm
через аргументsubset
.
Вывод: список с
-
nlevels
(список) дает количество уровней факторов для всех факторов факторов; -
levels
(вектор) дает уровни для всех факторных переменных.
Функция выдает предупреждение, если нет полных дел или факторных переменных для суммирования.
debug_contr_error <- function (dat, subset_vec = NULL) {
if (!is.null(subset_vec)) {
## step 0
if (mode(subset_vec) == "logical") {
if (length(subset_vec) != nrow(dat)) {
stop("'logical' 'subset_vec' provided but length does not match 'nrow(dat)'")
}
subset_log_vec <- subset_vec
} else if (mode(subset_vec) == "numeric") {
## check range
ran <- range(subset_vec)
if (ran[1] < 1 || ran[2] > nrow(dat)) {
stop("'numeric' 'subset_vec' provided but values are out of bound")
} else {
subset_log_vec <- logical(nrow(dat))
subset_log_vec[as.integer(subset_vec)] <- TRUE
}
} else {
stop("'subset_vec' must be either 'logical' or 'numeric'")
}
dat <- base::subset(dat, subset = subset_log_vec)
} else {
## step 1
dat <- stats::na.omit(dat)
}
if (nrow(dat) == 0L) warning("no complete cases")
## step 2
var_mode <- sapply(dat, mode)
if (any(var_mode %in% c("complex", "raw"))) stop("complex or raw not allowed!")
var_class <- sapply(dat, class)
if (any(var_mode[var_class == "AsIs"] %in% c("logical", "character"))) {
stop("matrix variables with 'AsIs' class must be 'numeric'")
}
ind1 <- which(var_mode %in% c("logical", "character"))
dat[ind1] <- lapply(dat[ind1], as.factor)
## step 3
fctr <- which(sapply(dat, is.factor))
if (length(fctr) == 0L) warning("no factor variables to summary")
ind2 <- if (length(ind1) > 0L) fctr[-ind1] else fctr
dat[ind2] <- lapply(dat[ind2], base::droplevels.factor)
## step 4
lev <- lapply(dat[fctr], base::levels.default)
nl <- lengths(lev)
## return
list(nlevels = nl, levels = lev)
}
Вот построенный крошечный пример.
dat <- data.frame(y = 1:4,
x = c(1:3, NA),
f1 = gl(2, 2, labels = letters[1:2]),
f2 = c("A", "A", "A", "B"),
stringsAsFactors = FALSE)
# y x f1 f2
#1 1 1 a A
#2 2 2 a A
#3 3 3 b A
#4 4 NA b B
str(dat)
#'data.frame': 4 obs. of 4 variables:
# $ y : int 1 2 3 4
# $ x : int 1 2 3 NA
# $ f1: Factor w/ 2 levels "a","b": 1 1 2 2
# $ f2: chr "A" "A" "A" "B"
lm(y ~ x + f1 + f2, dat)
#Error in 'contrasts<-'('*tmp*', value = contr.funs[1 + isOF[nn]]) :
# contrasts can be applied only to factors with 2 or more levels
Хорошо, мы видим ошибку. Теперь мой debug_contr_error
что f2
заканчивается одним уровнем.
debug_contr_error(dat)
#$nlevels
#f1 f2
# 2 1
#
#$levels
#$levels$f1
#[1] "a" "b"
#
#$levels$f2
#[1] "A"
Обратите внимание, что оригинальный короткий ответ здесь безнадежен, так как f2
предоставляется как символьная переменная, а не как факторная переменная.
## old answer
tmp <- na.omit(dat)
fctr <- lapply(tmp[sapply(tmp, is.factor)], droplevels)
sapply(fctr, nlevels)
#f1
# 2
rm(tmp, fctr)
Теперь давайте рассмотрим пример с матричной переменной x
.
dat <- data.frame(X = I(rbind(matrix(1:6, 3), NA)),
f = c("a", "a", "a", "b"),
y = 1:4)
dat
# X.1 X.2 f y
#1 1 4 a 1
#2 2 5 a 2
#3 3 6 a 3
#4 NA NA b 4
str(dat)
#'data.frame': 4 obs. of 3 variables:
# $ X: 'AsIs' int [1:4, 1:2] 1 2 3 NA 4 5 6 NA
# $ f: Factor w/ 2 levels "a","b": 1 1 1 2
# $ y: int 1 2 3 4
lm(y ~ X + f, data = dat)
#Error in 'contrasts<-'('*tmp*', value = contr.funs[1 + isOF[nn]]) :
# contrasts can be applied only to factors with 2 or more levels
debug_contr_error(dat)$nlevels
#f
#1
Обратите внимание, что фактор-переменная без уровней также может вызывать "ошибку контрастов". Вы можете задаться вопросом, как возможен фактор нулевого уровня. Ну это законно: nlevels(factor(character(0)))
. Здесь вы получите 0-уровневые факторы, если у вас нет завершенных дел.
dat <- data.frame(y = 1:4,
x = rep(NA_real_, 4),
f1 = gl(2, 2, labels = letters[1:2]),
f2 = c("A", "A", "A", "B"),
stringsAsFactors = FALSE)
lm(y ~ x + f1 + f2, dat)
#Error in 'contrasts<-'('*tmp*', value = contr.funs[1 + isOF[nn]]) :
# contrasts can be applied only to factors with 2 or more levels
debug_contr_error(dat)$nlevels
#f1 f2
# 0 0 ## all values are 0
#Warning message:
#In debug_contr_error(dat) : no complete cases
Наконец, давайте посмотрим на ситуацию, когда f2
- логическая переменная.
dat <- data.frame(y = 1:4,
x = c(1:3, NA),
f1 = gl(2, 2, labels = letters[1:2]),
f2 = c(TRUE, TRUE, TRUE, FALSE))
dat
# y x f1 f2
#1 1 1 a TRUE
#2 2 2 a TRUE
#3 3 3 b TRUE
#4 4 NA b FALSE
str(dat)
#'data.frame': 4 obs. of 4 variables:
# $ y : int 1 2 3 4
# $ x : int 1 2 3 NA
# $ f1: Factor w/ 2 levels "a","b": 1 1 2 2
# $ f2: logi TRUE TRUE TRUE FALSE
Наш отладчик предскажет "ошибку контрастов", но действительно ли это произойдет?
debug_contr_error(dat)$nlevels
#f1 f2
# 2 1
Нет, по крайней мере, это не сбоит (коэффициент NA
связан с недостатком ранга модели; не волнуйтесь):
lm(y ~ x + f1 + f2, data = dat)
#Coefficients:
#(Intercept) x f1b f2TRUE
# 0 1 0 NA
Мне сложно привести пример с ошибкой, но в этом также нет необходимости. На практике мы не используем отладчик для прогнозирования; мы используем его, когда действительно получаем ошибку; и в этом случае отладчик может найти переменную фактора-нарушителя.
Возможно, некоторые могут утверждать, что логическая переменная ничем не отличается от фиктивной. Но попробуйте простой пример ниже: это зависит от вашей формулы.
u <- c(TRUE, TRUE, FALSE, FALSE)
v <- c(1, 1, 0, 0) ## "numeric" dummy of 'u'
model.matrix(~ u)
# (Intercept) uTRUE
#1 1 1
#2 1 1
#3 1 0
#4 1 0
model.matrix(~ v)
# (Intercept) v
#1 1 1
#2 1 1
#3 1 0
#4 1 0
model.matrix(~ u - 1)
# uFALSE uTRUE
#1 0 1
#2 0 1
#3 1 0
#4 1 0
model.matrix(~ v - 1)
# v
#1 1
#2 1
#3 0
#4 0
Более гибкая реализация с использованием метода "model.frame"
lm
Вам также рекомендуется пройти R: как отлаживать ошибку "фактор имеет новые уровни" для линейной модели и прогнозирования, которая объясняет, что делают lm
и glm
под капотом в вашем наборе данных. Вы поймете, что шаги с 0 по 4, перечисленные выше, просто пытаются имитировать такой внутренний процесс. Помните, что данные, которые фактически используются для подбора модели, могут сильно отличаться от данных, которые вы передали.
Наши шаги не полностью соответствуют такой внутренней обработке. Для сравнения вы можете получить результат внутренней обработки, используя method = "model.frame"
в lm
и glm
. Попробуйте это на ранее построенном крошечном примере данных dat
где f2
- символьная переменная.
dat_internal <- lm(y ~ x + f1 + f2, dat, method = "model.frame")
dat_internal
# y x f1 f2
#1 1 1 a A
#2 2 2 a A
#3 3 3 b A
str(dat_internal)
#'data.frame': 3 obs. of 4 variables:
# $ y : int 1 2 3
# $ x : int 1 2 3
# $ f1: Factor w/ 2 levels "a","b": 1 1 2
# $ f2: chr "A" "A" "A"
## [.."terms" attribute is truncated..]
На практике model.frame
будет выполнять только шаг 0 и шаг 1. Он также удаляет переменные, предоставленные в вашем наборе данных, но не в формуле модели. Таким образом, у рамки модели может быть меньше строк и столбцов, чем у lm
и glm
. Принудительное приведение типов, как было сделано в нашем шаге 2, выполняется более поздней model.matrix
где может возникнуть "ошибка контрастов".
Есть несколько преимуществ: сначала получить этот внутренний фрейм модели, а затем передать его в debug_contr_error
(чтобы он по существу выполнял только шаги 2–4).
Преимущество 1: переменные, не используемые в формуле модели, игнорируются
## no variable 'f1' in formula
dat_internal <- lm(y ~ x + f2, dat, method = "model.frame")
## compare the following
debug_contr_error(dat)$nlevels
#f1 f2
# 2 1
debug_contr_error(dat_internal)$nlevels
#f2
# 1
Преимущество 2: способность справляться с преобразованными переменными
Допустимо преобразовать переменные в формулу модели, и model.frame
запишет преобразованные переменные вместо исходных. Обратите внимание, что даже если ваша исходная переменная не имеет NA
, преобразованная может иметь.
dat <- data.frame(y = 1:4, x = c(1:3, -1), f = rep(letters[1:2], c(3, 1)))
# y x f
#1 1 1 a
#2 2 2 a
#3 3 3 a
#4 4 -1 b
lm(y ~ log(x) + f, data = dat)
#Error in 'contrasts<-'('*tmp*', value = contr.funs[1 + isOF[nn]]) :
# contrasts can be applied only to factors with 2 or more levels
#In addition: Warning message:
#In log(x) : NaNs produced
# directly using 'debug_contr_error' is hopeless here
debug_contr_error(dat)$nlevels
#f
#2
## this works
dat_internal <- lm(y ~ log(x) + f, data = dat, method = "model.frame")
# y log(x) f
#1 1 0.0000000 a
#2 2 0.6931472 a
#3 3 1.0986123 a
debug_contr_error(dat_internal)$nlevels
#f
#1
Учитывая эти преимущества, я пишу еще одну функцию, обертывающую model.frame
и debug_contr_error
.
Вход:
-
form
- это ваша модельная формула; -
dat
- набор данных, переданный вlm
илиglm
через аргументdata
; -
subset_vec
- индексный вектор, передаваемый вlm
илиglm
через аргументsubset
.
Вывод: список с
-
mf
(фрейм данных) дает фрейм модели (с пропущенным атрибутом "Terms"); -
nlevels
(список) дает количество уровней факторов для всех факторов факторов; -
levels
(вектор) дает уровни для всех факторных переменных.
## note: this function relies on 'debug_contr_error'
debug_contr_error2 <- function (form, dat, subset_vec = NULL) {
## step 0
if (!is.null(subset_vec)) {
if (mode(subset_vec) == "logical") {
if (length(subset_vec) != nrow(dat)) {
stop("'logical' 'subset_vec' provided but length does not match 'nrow(dat)'")
}
subset_log_vec <- subset_vec
} else if (mode(subset_vec) == "numeric") {
## check range
ran <- range(subset_vec)
if (ran[1] < 1 || ran[2] > nrow(dat)) {
stop("'numeric' 'subset_vec' provided but values are out of bound")
} else {
subset_log_vec <- logical(nrow(dat))
subset_log_vec[as.integer(subset_vec)] <- TRUE
}
} else {
stop("'subset_vec' must be either 'logical' or 'numeric'")
}
dat <- base::subset(dat, subset = subset_log_vec)
}
## step 0 and 1
dat_internal <- stats::lm(form, data = dat, method = "model.frame")
attr(dat_internal, "terms") <- NULL
## rely on 'debug_contr_error' for steps 2 to 4
c(list(mf = dat_internal), debug_contr_error(dat_internal, NULL))
}
Попробуйте предыдущий пример преобразования log
.
debug_contr_error2(y ~ log(x) + f, dat)
#$mf
# y log(x) f
#1 1 0.0000000 a
#2 2 0.6931472 a
#3 3 1.0986123 a
#
#$nlevels
#f
#1
#
#$levels
#$levels$f
#[1] "a"
#
#
#Warning message:
#In log(x) : NaNs produced
Попробуйте также subset_vec
.
## or: debug_contr_error2(y ~ log(x) + f, dat, c(T, F, T, T))
debug_contr_error2(y ~ log(x) + f, dat, c(1,3,4))
#$mf
# y log(x) f
#1 1 0.000000 a
#3 3 1.098612 a
#
#$nlevels
#f
#1
#
#$levels
#$levels$f
#[1] "a"
#
#
#Warning message:
#In log(x) : NaNs produced
Подгонка модели по группе и NA как уровни факторов
Если вы подбираете модель по группе, вы, скорее всего, получите "ошибку контрастов". Вам нужно
- разделить ваш фрейм данных с помощью переменной группировки (см.
?split.data.frame
); - работайте с этими кадрами данных один за другим, применяя
debug_contr_error2
(функцияlapply
может быть полезна для выполнения этого цикла).
Некоторые также сказали мне, что они не могут использовать na.omit
в своих данных, потому что в итоге будет слишком мало строк, чтобы сделать что-нибудь разумное. Это может быть расслаблено. На практике это NA_integer_
и NA_real_
которые должны быть опущены, но NA_character_
может быть сохранено: просто добавьте NA
как уровень фактора. Для этого вам нужно перебрать переменные в вашем фрейме данных:
- если переменная
x
уже является фактором, аanyNA(x)
-TRUE
, выполнитеx <- addNA(x)
. "И" важно. Если уx
нетNA
,addNA(x)
добавит неиспользуемый уровень<NA>
. - если переменная
x
является символом, выполнитеx <- factor(x, exclude = NULL)
чтобы привести его к фактору.exclude = NULL
сохранит<NA>
в качестве уровня. - если
x
является "логическим", "числовым", "необработанным" или "сложным", ничего не должно быть изменено.NA
это простоNA
.
Уровень фактора <NA>
не будет сбрасываться ни по droplevels
ни по na.omit
, и он действителен для построения модельной матрицы. Проверьте следующие примеры.
## x is a factor with NA
x <- factor(c(letters[1:4], NA)) ## default: 'exclude = NA'
#[1] a b c d <NA> ## there is an NA value
#Levels: a b c d ## but NA is not a level
na.omit(x) ## NA is gone
#[1] a b c d
#[.. attributes truncated..]
#Levels: a b c d
x <- addNA(x) ## now add NA into a valid level
#[1] a b c d <NA>
#Levels: a b c d <NA> ## it appears here
droplevels(x) ## it can not be dropped
#[1] a b c d <NA>
#Levels: a b c d <NA>
na.omit(x) ## it is not omitted
#[1] a b c d <NA>
#Levels: a b c d <NA>
model.matrix(~ x) ## and it is valid to be in a design matrix
# (Intercept) xb xc xd xNA
#1 1 0 0 0 0
#2 1 1 0 0 0
#3 1 0 1 0 0
#4 1 0 0 1 0
#5 1 0 0 0 1
## x is a character with NA
x <- c(letters[1:4], NA)
#[1] "a" "b" "c" "d" NA
as.factor(x) ## this calls 'factor(x)' with default 'exclude = NA'
#[1] a b c d <NA> ## there is an NA value
#Levels: a b c d ## but NA is not a level
factor(x, exclude = NULL) ## we want 'exclude = NULL'
#[1] a b c d <NA>
#Levels: a b c d <NA> ## now NA is a level
Как только вы добавите NA
в качестве уровня фактора/персонажа, ваш набор данных может внезапно иметь более полные случаи. Тогда вы можете запустить свою модель. Если вы по-прежнему получаете "ошибку контрастов", используйте debug_contr_error2
чтобы увидеть, что произошло.
Для вашего удобства я пишу функцию для предварительной обработки NA
.
Вход:
-
dat
- это ваш полный набор данных.
Выход:
- фрейм данных, с NA, добавленным как уровень для фактора/символа.
NA_preproc <- function (dat) {
for (j in 1:ncol(dat)) {
x <- dat[[j]]
if (is.factor(x) && anyNA(x)) dat[[j]] <- base::addNA(x)
if (is.character(x)) dat[[j]] <- factor(x, exclude = NULL)
}
dat
}
Воспроизводимые тематические исследования и обсуждения
Следующие материалы специально отобраны для воспроизводимых тематических исследований, поскольку я только что ответил на них с помощью трех вспомогательных функций, созданных здесь.
- Как сделать GLM, когда "контрасты могут применяться только к факторам с 2 или более уровнями"?
- R: Ошибка контрастов при подгонке линейных моделей с помощью 'lm'
Есть также несколько других высококачественных потоков, решаемых другими пользователями StackOverflow:
- Факторы, не распознаваемые в lm с помощью map() (это касается подбора модели по группе)
- Как отказаться от наблюдения NA факторов условно при выполнении линейной регрессии в R? (это похоже на случай 1 в предыдущем списке)
- Ошибка фактора/уровня в смешанной модели (еще один пост о подборе модели по группе)
Этот ответ направлен на отладку "ошибки контрастов" во время подбора модели. Однако, эта ошибка может оказаться при использовании predict
для прогнозирования. Такое поведение не с помощью predict.lm
или predict.glm
, а с методами прогнозирования из некоторых пакетов. Вот несколько связанных тем на StackOverflow.
- Прогноз в R - GLMM
- Ошибка в "контрастах" Ошибка
- Прогноз SVM на фрейме данных с различными уровнями факторов
- Используя прогнозирование со svyglm
- набор данных должен содержать все факторы в SVM в R
- Вероятностные прогнозы с кумулятивными смешанными моделями связей
- набор данных должен содержать все факторы в SVM в R
Также обратите внимание, что философия этого ответа основана на философии lm
и glm
. Эти две функции являются стандартом кодирования для многих процедур подбора моделей, но, возможно, не все процедуры подбора моделей ведут себя одинаково. Например, следующее не выглядит прозрачным для меня, будут ли полезны мои вспомогательные функции.
- Ошибка с svychisq - "контраст может применяться к факторам с 2 или более уровнями"
- R-пакеты эффектов & plm: "ошибка в контрастах" при попытке построения маргинальных эффектов
- Контрасты могут применяться только к фактору
- R: lawstat :: levene.test не работает, пока Fligner Killeen работает, как и машина :: leveneTest
- R - geeglm Ошибка: контрасты могут применяться только к факторам с 2 или более уровнями
Хотя это и немного не по теме, все же полезно знать, что иногда "контрастная ошибка" просто возникает из-за написания неправильного фрагмента кода. В следующих примерах OP передал имя своих переменных, а не их значения, lm
. Поскольку имя является символом с одним значением, оно позднее приводится к одноуровневому коэффициенту и вызывает ошибку.
- Ошибка в 'контрастах <-' ('* tmp *', value = contr.funs [1 + isOF [nn]]): контрасты могут применяться только к факторам с 2 или более уровнями
- Переберите символьный вектор для использования в функции
Как устранить эту ошибку после отладки?
На практике люди хотят знать, как решить этот вопрос, либо на статистическом уровне, либо на уровне программирования.
Если вы подбираете модели в своем полном наборе данных, то, вероятно, не существует статистического решения, если только вы не можете рассчитать пропущенные значения или собрать больше данных. Таким образом, вы можете просто обратиться к решению для кодирования, чтобы удалить некорректную переменную. debug_contr_error2
возвращает nlevels
которые помогут вам легко их найти. Если вы не хотите отбрасывать их, замените их вектором 1 (как описано в разделе Как сделать GLM, когда "контрасты могут применяться только к факторам с 2 или более уровнями"?) И разрешите lm
или glm
иметь дело с результирующий ранг-дефицит.
Если вы подбираете модели на подмножестве, могут быть статистические решения.
Подгонка моделей по группам не обязательно требует разделения набора данных по группам и подбора независимых моделей. Следующее может дать вам приблизительное представление:
- R регрессионный анализ: анализ данных по определенной этнической принадлежности
- Нахождение наклона для нескольких точек в выбранных столбцах
- R: построить отдельные модели для каждой категории
Если вы делите свои данные явно, вы можете легко получить "ошибку контрастов", поэтому вам придется скорректировать формулу модели для каждой группы (то есть вам нужно динамически генерировать формулы модели). Более простое решение - пропустить построение модели для этой группы.
Вы также можете произвольно разделить ваш набор данных на обучающее подмножество и подмножество тестирования, чтобы вы могли выполнить перекрестную проверку. Р: как отлаживать ошибку "фактор имеет новые уровни" для линейной модели и прогнозирования, вкратце упоминается об этом, и вам лучше сделать стратифицированную выборку, чтобы обеспечить успех как оценки модели в обучающей части, так и прогнозирования в тестирующей части.