1. 问题描述
在回归中,我们往往会碰到有约束的系数问题。
例如,在回归方程中中,人为规定:①回归系数全部在[0,1]之间,②系数之和为1。那么为了求解OLS方程,有约束的回归模型求解数学表达式为
那么该问题需要用到scipy.optimize解决。
2. 数据
3. 代码准备
import numpy as npimport pandas as pdfrom scipy.optimize import minimizedef get_coefficients(init_coeff, X, y, method):# 计算sum squared errorsfuncSSE = lambda k, X, y: sum((y - np.dot(X, np.array(k).reshape((-1, 1)))) ** 2)[0]# 等式约束条件:eqcons = ({'type':'eq', 'fun': lambda k: sum(k) - 1})# 如果有不等式约束条件,那么是ineq,且是≥。例如,k0>0 & k0<1。# cons = ({'type':'ineq', 'fun': lambda k: 1 - k[0]},# {'type':'ineq', 'fun': lambda k: k[0] - 0})# 参数的上下限bnds = ((0, 1), (0, 1), (0, 1), (0, 1), (0, 1), (0, 1))# optimize函数:# 输入函数fun,估计参数的初始值init_coeff,估计参数之外的参数args = (X,y),# 求解方法method,上下限bounds,精确度tol,约束条件constraints。result = minimize(fun=funcSSE,x0=init_coeff,args=(X, y),method=method,bounds=bnds,tol=0.001,constraints=cons)# 返回估计参数值return result
这里尝试了全部的求解方法,不仅要得到全局最优解,还要满足约束条件。
# 读取数据data = pd.read_csv(r'C:\Users\Administrator\Downloads\data.csv').Tdata.columns = data.iloc[0]data = data.iloc[2:]# 数据格式指定为float,否则后续回归会有问题。for var in list(data.columns):data[var] = data[var].apply(lambda x: float(x))# 设定X和y,以及初始参数X = np.array(data.iloc[:, :6]).reshape((-1, 6))y1 = np.array(data.iloc[:, 7]).reshape((-1, 1))init_coeff = [0, 0, 0, 0, 0.2, 0.8]# 设定SSE计算公式。funcSSE = lambda k, X, y: sum((y - np.dot(X, np.array(k).reshape((-1, 1)))) ** 2)[0]for m in ['Nelder-Mead', 'Powell', 'CG', 'BFGS', 'Newton-CG', 'L-BFGS-B', 'TNC', 'COBYLA','SLSQP', 'trust-constr', 'dogleg', 'trust-ncg', 'trust-exact', 'trust-krylov']:try:result = get_coefficients(init_coeff, X, y1, m)k_hat = result.xprint('method = %s.'%m)print('sum of coefficients is %0.4f.'%sum(k_hat))print('estimated coeff is ', k_hat)print('SSE of estimated coeff is %0.4f'%funcSSE(k_hat, X, y1))print('\n')except:continue
结果如下
method = Nelder-Mead.sum of coefficients is 0.0082.estimated coeff is [-0.00275149 0.00436154 0.00239604 0.00166577 0.01761348 -0.01503714]SSE of estimated coeff is 0.9582method = Powell.sum of coefficients is 0.0101.estimated coeff is [5.81772244e-03 2.11612816e-05 6.16658126e-05 6.61069614e-054.05846939e-03 6.61069614e-05]SSE of estimated coeff is 0.9780method = CG.sum of coefficients is 0.0091.estimated coeff is [ 0.00839106 0.00693108 -0.0215021 0.0058082 0.03196229 -0.02249176]SSE of estimated coeff is 0.9322method = BFGS.sum of coefficients is 0.0091.estimated coeff is [ 0.00839105 0.00693109 -0.02150201 0.00580812 0.03196221 -0.0224917 ]SSE of estimated coeff is 0.9322method = L-BFGS-B.sum of coefficients is 0.0101.estimated coeff is [0.00591175 0. 0. 0. 0.00415395 0. ]SSE of estimated coeff is 0.9775method = TNC.sum of coefficients is 0.0101.estimated coeff is [0.00591182 0. 0. 0. 0.00415385 0. ]SSE of estimated coeff is 0.9775method = SLSQP.sum of coefficients is 1.0000.estimated coeff is [1.68700952e-14 3.56512119e-01 4.81162901e-01 1.88647109e-151.62324980e-01 1.21545881e-14]SSE of estimated coeff is 160.4392method = trust-constr.sum of coefficients is 1.0000.estimated coeff is [3.48435748e-06 3.56479768e-01 4.81183407e-01 3.62541898e-051.62291535e-01 5.55114801e-06]SSE of estimated coeff is 160.4395
根据结果显示,只有SLSQP和trust-constr得到的解能够满足约束条件,而其他方案得到的解根本不满足约束。尽管SLSQP和trust-constr计算得到SSE很大,但是为了满足约束,因此推荐使用SLSQP和trust-constr进行规划求解。
4. 思考
那些指定了约束条件、但是依然没有满足的求解方法,得到的结果是怎么来的?这里,我们尝试了OLS直接回归。
import statsmodels.api as smlinear_reg = sm.OLS(np.array(data.iloc[:, 6:7]), np.array(data.iloc[:, :6])).fit()linear_reg.summary()
结果如下。观察到,OLS直接回归的系数结果和BFGS/CG一致。因此,BFGS/CG求解得到的是全局最优解,且置于约束条件不顾。
尽管SLSQP/trust-constr并非最优解,但是至少满足了约束条件。
