Я понимаю, что это очень конкретный вопрос!
Чтобы помочь в объяснении: я изучаю использование линейного оптимизатора, чтобы продемонстрировать, как острые «утесы» в функциональной поверхности могут привести к неоптимальным решениям. Воспроизводимый код в R выглядит следующим образом:
library(glmnet)
library(mice)
# Load data
df <- read.csv(paste0('https://raw.githubusercontent.com/jbrownlee/Datasets',
'/master/pima-indians-diabetes.data.csv'), header = F)
colnames(df) <- c('Pregnancies', 'Glucose', 'BloodPressure', 'SkinThickness',
'Insulin', 'BMI', 'DiabetesPedigreeFunction', 'Age', 'Outcome')
set.seed(40)
# Impute 0 (missing) values for columns 2 through 8 (Glucose - Age)
df[2:8] <- lapply(df[2:8], function(x) replace(x, x %in% 0, NA))
micedf <- mice(df)
df <- complete(micedf)
# Create train/test split
sample_size <- floor(0.75 * nrow(df))
train_index <- sample(seq_len(nrow(df)), size = sample_size)
train <- df[train_index,]
test <- df[-train_index,]
# Generate model matrix format for glmnet
x <- as.matrix(train[,1:8])
y <- train$Outcome
# Fitting function
GLM_tune <- function(alpha) {
set.seed(40)
cvglmnet <- glmnet::cv.glmnet(x, y, nfolds = 5, family = "binomial",
alpha = alpha, type.measure = "auc",
parallel = F)
return (cvglmnet$cvm[cvglmnet$lambda == cvglmnet$lambda.1se]) }
Теперь, если я введу значение где-то между 0 и 1 следующим образом:
optim(par = 0.9, fn = GLM_tune, lower = 0, upper = 1,
control = list(fnscale = -1, trace=3), method = c("L-BFGS-B"))
# >> $par = 0.86
Оптимизатор поднимается до локальных максимумов, которые я тестировал, исследуя всю площадь поверхности, используя:
surf <- data.frame(alpha = 0, auc = 0)
for (a in seq(from=0, to=1000)) {
surf[a+1,1] <- a/1000
surf[a+1,2] <- GLM_tune(a/1000)
}
library(ggplot2)
ggplot() +
geom_point(data=surf, size = 1.2, color = "black", aes(alpha, auc))
Однако когда я устанавливаю альфа = 1 в качестве начальной точки, алгоритм переходит к альфа = 0 во время второй итерации, а затем завершается как «окончательное» решение:
optim(par = 1, fn = GLM_tune, lower = 0, upper = 1,
control = list(fnscale = -1, trace=3), method = c("L-BFGS-B"))
# >> $par = 0
Почему это так? Ясно, что я не полностью понимаю алгоритм, но я предположил, что шаг по умолчанию равен 0,001 в функции optim (см. ndeps) — так почему же он должен перейти к противоположной крайности в качестве следующего шага? Я пропустил важный параметр, который должен быть установлен для этих проблем?