Весьма антиклиматический ответ на вопрос « Кто-нибудь знает, почему это так? » Заключается в том, что просто никто не заботится о том, чтобы реализовать процедуру отрицательной регрессии гребня. Одна из основных причин заключается в том, что люди уже начали внедрять
подпрограммы неотрицательных эластичных сетей (например, здесь и здесь ). Эластичная сеть включает в себя регрессию гребня как особый случай (по существу, для детали LASSO задается нулевой вес). Эти работы являются относительно новыми, поэтому они еще не включены в scikit-learn или аналогичный пакет общего пользования. Возможно, вы захотите спросить авторов этих документов для кода.
РЕДАКТИРОВАТЬ:
Поскольку @amoeba и я обсуждали комментарии, фактическая реализация этого относительно проста. Скажем, у кого-то есть следующая проблема регрессии:
y=2x1−x2+ϵ,ϵ∼N(0,0.22)
где и оба являются стандартными нормалями, такими как: . Обратите внимание, что я использую стандартизированные переменные предиктора, поэтому мне не нужно нормализовать потом. Для простоты я также не включаю перехват. Мы можем немедленно решить эту проблему регрессии, используя стандартную линейную регрессию. Так что в R это должно быть примерно так:x 2 x p ∼ N ( 0 , 1 )x1x2xp∼N(0,1)
rm(list = ls());
library(MASS);
set.seed(123);
N = 1e6;
x1 = rnorm(N)
x2 = rnorm(N)
y = 2 * x1 - 1 * x2 + rnorm(N,sd = 0.2)
simpleLR = lm(y ~ -1 + x1 + x2 )
matrixX = model.matrix(simpleLR); # This is close to standardised
vectorY = y
all.equal(coef(simpleLR), qr.solve(matrixX, vectorY), tolerance = 1e-7) # TRUE
Обратите внимание на последнюю строку. Почти все процедуры линейной регрессии используют QR-разложение для оценки . Мы хотели бы использовать то же самое для нашей задачи регрессии гребня. На данный момент прочитайте этот пост @whuber; мы будем реализовывать именно эту процедуру. Короче говоря, мы будем расширять нашу оригинальную конструкцию матрицы с диагональная матрица и наш ответ вектор с нулей. Таким образом, мы сможем повторно выразить исходную проблему регрессии гребня как гдеX √βXyp(XTX+λI) - 1 XTy( ˉ X T ˉ X ) - 1 ˉ X T ˉ y ¯λ−−√Ipyp(XTX+λI)−1XTy(X¯TX¯)−1X¯Ty¯¯символизирует дополненную версию. Проверьте полноты слайдов 18-19 из этих заметок , я нашел их довольно простыми. Таким образом, в R мы хотели бы следующее:
myLambda = 100;
simpleRR = lm.ridge(y ~ -1 + x1 + x2, lambda = myLambda)
newVecY = c(vectorY, rep(0, 2))
newMatX = rbind(matrixX, sqrt(myLambda) * diag(2))
all.equal(coef(simpleRR), qr.solve(newMatX, newVecY), tolerance = 1e-7) # TRUE
и это работает. Итак, мы получили часть регрессии гребня. Мы могли бы решить по-другому, хотя, мы могли бы сформулировать это как задачу оптимизации, где остаточная сумма квадратов является функцией стоимости, а затем оптимизировать ее, т.е. . Конечно же, мы можем сделать это:minβ||y¯−X¯β||22
myRSS <- function(X,y,b){ return( sum( (y - X%*%b)^2 ) ) }
bfgsOptim = optim(myRSS, par = c(1,1), X = newMatX, y= newVecY,
method = 'L-BFGS-B')
all.equal(coef(simpleRR), bfgsOptim$par, check.attributes = FALSE,
tolerance = 1e-7) # TRUE
который, как и ожидалось, снова работает. Так что теперь мы просто хотим: где . Это просто та же самая проблема оптимизации, но ограниченная, так что решение неотрицательно.minβ||y¯−X¯β||22β≥0
bfgsOptimConst = optim(myRSS, par = c(1,1), X=newMatX, y= newVecY,
method = 'L-BFGS-B', lower = c(0,0))
all(bfgsOptimConst$par >=0) # TRUE
(bfgsOptimConst$par) # 2.000504 0.000000
которая показывает, что исходную задачу неотрицательной регрессии гребня можно решить, переформулировав ее как простую ограниченную задачу оптимизации. Некоторые предостережения:
- Я использовал (практически) нормализованные предикторы. Вам нужно будет самостоятельно учесть нормализацию.
- То же самое касается и отсутствия нормализации перехвата.
- Я использовал
optim
«с L-BFGS-B аргумент. Это самый ванильный R решатель, который принимает границы. Я уверен, что вы найдете десятки лучших решателей.
- В общем случае линейные задачи наименьших квадратов представляют собой задачи квадратичной оптимизации . Это перебор для этого поста, но имейте в виду, что при необходимости вы можете получить лучшую скорость.
- Как упомянуто в комментариях, вы можете пропустить ребро-регрессию как часть расширенной линейной регрессии и напрямую закодировать функцию стоимости ребра в качестве задачи оптимизации. Это было бы намного проще, и этот пост значительно меньше. Ради аргумента я добавляю и это второе решение.
- Я не полностью разговорный Python , но по существу вы можете повторить эту работу, используя Numpy в linalg.solve и SciPy в Оптимизируйте функции.
- Чтобы выбрать гиперпараметр и т. Д., Вы просто делаете обычный CV-шаг, который вы сделали бы в любом случае; ничего не меняется.λ
Код для пункта 5:
myRidgeRSS <- function(X,y,b, lambda){
return( sum( (y - X%*%b)^2 ) + lambda * sum(b^2) )
}
bfgsOptimConst2 = optim(myRidgeRSS, par = c(1,1), X = matrixX, y = vectorY,
method = 'L-BFGS-B', lower = c(0,0), lambda = myLambda)
all(bfgsOptimConst2$par >0) # TRUE
(bfgsOptimConst2$par) # 2.000504 0.000000