在回归中使用 gurobi python 的荒谬解决方案

Absurd solution using gurobi python in regression

所以我是 gurobi 的新手,我决定开始使用它来解决一个众所周知的问题,如回归。我找到了 this 官方笔记本,其中解决了一个 L0 惩罚回归模型,我只从中取出了回归模型的一部分。然而,当我在gurobi中解决这个问题时,我得到了一个非常奇怪的解决方案,与实际正确的回归解决方案完全不同。

我运行的密码是:

import gurobipy as gp
from gurobipy import GRB
import numpy as np
from sklearn.datasets import load_boston
from itertools import product
boston = load_boston()
x = boston.data
x = x[:, [0, 2, 4, 5, 6, 7, 10, 11, 12]] # select non-categorical variables
response = boston.target

samples, dim = x.shape

regressor = gp.Model()

# Append a column of ones to the feature matrix to account for the y-intercept
x = np.concatenate([x, np.ones((samples, 1))], axis=1)

# Decision variables
beta = regressor.addVars(dim + 1, name="beta") # Beta

# Objective Function (OF): minimize 1/2 * RSS using the fact that
# if x* is a minimizer of f(x), it is also a minimizer of k*f(x) iff k > 0
Quad = np.dot(x.T, x)
lin = np.dot(response.T, x)
obj = sum(0.5 * Quad[i, j] * beta[i] * beta[j] for i, j in product(range(dim + 1), repeat=2))
obj -= sum(lin[i] * beta[i] for i in range(dim + 1))
obj += 0.5 * np.dot(response, response)

regressor.setObjective(obj, GRB.MINIMIZE)

regressor.optimize()
beta_sol_gurobi = np.array([beta[i].X for i in range(dim+1)])

这段代码提供的解决方案是

array([1.22933632e-14, 2.40073891e-15, 1.10109084e-13, 2.93142174e+00,
       6.14486489e-16, 3.93021623e-01, 5.52707727e-15, 8.61271603e-03,
       1.55963041e-15, 3.19117429e-13])

而真正的线性回归解应该是

from sklearn import linear_model
lr = linear_model.LinearRegression()
lr.fit(x, response)
lr.coef_
lr.intercept_

产量,

array([-5.23730841e-02, -3.35655253e-02, -1.39501039e+01,  4.40955833e+00,
       -7.33680982e-03, -1.24312668e+00, -9.59615262e-01,  8.60275557e-03,
       -5.17452533e-01])
29.531492975441015

所以gurobi的解决方案是完全不同的。对发生的事情有任何猜测/建议吗?我在这里做错了什么吗?

PD:我知道这个问题可以使用其他包,甚至其他优化框架来解决,但我对在 gurobi 中解决它特别感兴趣 python,因为我想在某些领域开始使用 gurobi更复杂的问题。

错误的结果是由于您的决策变量。由于Gurobi默认假定所有变量的下界为0,因此需要显式设置下界:

beta = regressor.addVars(dim + 1, lb = -GRB.INFINITY, name="beta") # Beta