Glmnet отказывается прогнозировать

У меня есть модель glm, которая работает. Поскольку я хотел бы добавить (хребет) регуляризацию, я думал, что перейду на glmnet. По какой-то причине я не могу заставить glmnet работать. Кажется, всегда предсказывает первый класс, а не второй, что приводит к низкой точности и kappa = 0.

Ниже приведен код для воспроизведения проблемы. Что я делаю неправильно?

Полученные тестовые данные выглядят следующим образом:

Поскольку данные не могут быть линейно разделены, добавляются два полиномиальных члена A ^ 2 и B ^ 2.

Модель glm правильно предсказывает данные (с точностью = 1 и kappa = 1). Вот его граница предсказания:

В то время как модель glmnet всегда имеет kappa = 0, независимо от того, какую лямбду она пытается:

lambda Accuracy Kappa Accuracy SD Kappa SD
 0 0.746 0 0.0295 0 
 1e-04 0.746 0 0.0295 0 
 0.01 0.746 0 0.0295 0 
 0.1 0.746 0 0.0295 0 
 1 0.746 0 0.0295 0 
 10 0.746 0 0.0295 0

Код для воспроизведения проблемы:

library(caret)
# generate test data
set.seed(42)
n <- 500; m <- 100
data <- data.frame(A=runif(n, 98, 102), B=runif(n, 98, 102), Type="foo")
data <- subset(data, sqrt((A-100)^2 + (B-100)^2) > 1.5)
data <- rbind(data, data.frame(A=rnorm(m, 100, 0.25), B=rnorm(m, 100, 0.25), Type="bar"))
# add a few polynomial features to match ellipses
polymap <- function(data) cbind(data, A2=data$A^2, B2=data$B^2)
data <- polymap(data)
plot(x=data$A, y=data$B, pch=21, bg=data$Type, xlab="A", ylab="B")
# train a binomial glm model
model.glm <- train(Type ~ ., data=data, method="glm", family="binomial",
 preProcess=c("center", "scale"))
# train a binomial glmnet model with ridge regularization (alpha = 0)
model.glmnet <- train(Type ~ ., data=data, method="glmnet", family="binomial",
 preProcess=c("center", "scale"),
 tuneGrid=expand.grid(alpha=0, lambda=c(0, 0.0001, 0.01, 0.1, 1, 10)))
print(model.glm) # <- Accuracy = 1, Kappa = 1 - good!
print(model.glmnet) # <- Accuracy = low, Kappa = 0 - bad!

Вызов glmnet напрямую (без каретки) приводит к той же проблеме:

x <- as.matrix(subset(data, select=-c(Type)))
y <- data$Type
model.glmnet2 <- cv.glmnet(x=x, y=y, family="binomial", type.measure="class")
preds <- predict(model.glmnet2, x, type="class", s="lambda.min")
# all predictions are class 1...

EDIT: график масштабированных данных и граница решения, найденная с помощью glm:

Модель: -37 + 6317 * A + 6059 * B - 6316 * A2 - 6059 * B2

1 ответ

Вы должны центрировать и масштабировать данные до создания полиномиальных версий предиктора. Численно, все работает лучше:

set.seed(42)
n <- 500; m <- 100
data <- data.frame(A=runif(n, 98, 102), B=runif(n, 98, 102), Type="foo")
data <- subset(data, sqrt((A-100)^2 + (B-100)^2) > 1.5)
data <- rbind(data, data.frame(A=rnorm(m, 100, 0.25), B=rnorm(m, 100, 0.25), Type="bar"))
data2 <- data
data2$A <- scale(data2$A, scale = TRUE)
data2$B <- scale(data2$B, scale = TRUE)
data2$A2 <- data2$A^2
data2$B2 <- data2$B^2
# train a binomial glm model
model.glm2 <- train(Type ~ ., data=data2, method="glm")
# train a binomial glmnet model with ridge regularization (alpha = 0)
model.glmnet2 <- train(Type ~ ., data=data2, method="glmnet", 
 tuneGrid=expand.grid(alpha=0, 
 lambda=c(0, 0.0001, 0.01, 0.1, 1, 10)))

Из них:

> getTrainPerf(model.glm2)
 TrainAccuracy TrainKappa method
1 1 1 glm
> getTrainPerf(model.glmnet2)
 TrainAccuracy TrainKappa method
1 1 1 glmnet

Max

licensed under cc by-sa 3.0 with attribution.