Scipy linprog报错整理
最近在做Learning from data的习题,要解决一个线性优化问题,但是碰到一个坑,这里记录一下,具体题目可以参考Learning from data的第三章的Problem3.6,题目的大概意思是从线性规划角度解决分类问题,我先产生1000组数据。
import numpy as np
import matplotlib.pyplot as plt
#参数
rad=10
thk=5
sep=5
#n为产生点的个数,x1,y1为上半个圆环的坐标
def generatedata(rad,thk,sep,n,x1=0,y1=0):
#上半个圆的圆心
X1=x1
Y1=y1
#下半个圆的圆心
X2=X1+rad+thk/2
Y2=Y1-sep
#上半个圆环的点
top=[]
#下半个圆环的点
bottom=[]
#后面要用到的参数
r1=rad+thk
r2=rad
cnt=1
while(cnt<=n):
#产生均匀分布的点
x=np.random.uniform(-r1,r1)
y=np.random.uniform(-r1,r1)
d=x**2+y**2
if(d>=r2**2 and d<=r1**2):
if (y>0):
top.append([X1+x,Y1+y])
cnt+=1
else:
bottom.append([X2+x,Y2+y])
cnt+=1
else:
continue
return top,bottom
n=1000
top,bottom=generatedata(rad,thk,sep,n)
X1=[i[0] for i in top]
Y1=[i[1] for i in top]
X2=[i[0] for i in bottom]
Y2=[i[1] for i in bottom]
plt.scatter(X1,Y1,s=1)
plt.scatter(X2,Y2,s=1)
plt.show()
显然这组数据是可分的,但是我带入scipy的linprog函数确始终解不出来。
from scipy.optimize import linprog
#加上偏移项
x1=[[1]+i for i in top]
x2=[[1]+i for i in bottom]
c=np.array([1.0,1.0,1.0])
A=np.concatenate((np.array(x1),np.array(x2)*(-1)))*(-1)
b=np.ones(n)*(-1.0)
result=linprog(c,A_ub=A,b_ub=b,options=dict(bland=True))
result
fun: 71.923242295321842
message: 'Optimization failed. Unable to find a feasible starting point.'
nit: 1000
status: 2
success: False
x: nan
看到有这样一个报错‘Optimization failed. Unable to find a feasible starting point.’,意思是没有解,但是显然有解啊,我就非常郁闷,上网查阅了一下,看到有人说100组数据以上linprog会解不出,于是我试了下50组数据。
n=50
top,bottom=generatedata(rad,thk,sep,n)
#加上偏移项
x1=[[1]+i for i in top]
x2=[[1]+i for i in bottom]
c=np.array([1.0,1.0,1.0])
A=np.concatenate((np.array(x1),np.array(x2)*(-1)))*(-1)
b=np.ones(n)*(-1.0)
result=linprog(c,A_ub=A,b_ub=b)
result
fun: 0.68978181507748448
message: 'Optimization terminated successfully.'
nit: 55
slack: array([ 8.25582251, 1.39579263, 5.45099168, 7.89511373,
4.07001065, 7.5398225 , 6.36340605, 5.19580442,
0. , 7.88915867, 7.21006349, 5.61077845,
0.80448989, 5.84426297, 1.22033368, 5.00423168,
4.2392862 , 2.43914755, 0.67341515, 9.26841422,
6.22546989, 8.54254805, 6.22844178, 12.44853646,
8.24740109, 9.51136402, 4.8966531 , 11.47498782,
9.10895613, 11.81051557, 12.51911944, 7.09788684,
3.43465829, 10.05898861, 11.83502706, 10.34493975,
8.90589327, 11.95815476, 9.4623471 , 2.78260225,
6.77083725, 9.6965408 , 10.10390994, 5.0151723 ,
3.2516008 , 4.95376907, 11.83342563, 7.88599283,
2.53952582, 8.34889399])
status: 0
success: True
x: array([ 0. , 0. , 0.68978182])
一看还真是这个问题,于是网上查阅了下有没有其他的工具,看到cvxopt是一个比较不错的凸优化工具,于是下载了后尝试了一下,效果不错,需要注意的一点是cvxopt的数据格式一定是浮点数,我一开始因为这个还报错了。
from cvxopt import matrix, solvers
n=1000
top,bottom=generatedata(rad,thk,sep,n)
#加上偏移项
x1=[[1]+i for i in top]
x2=[[1]+i for i in bottom]
c=np.array([1.0,1.0,1.0])
A=np.concatenate((np.array(x1),np.array(x2)*(-1)))*(-1)
b=np.ones(n)*(-1.0)
#要转换为matrix
c=matrix(c)
A=matrix(A)
b=matrix(b)
sol = solvers.lp(c,A,b)
print(sol)
pcost dcost gap pres dres k/t
0: 3.4242e-01 1.0017e+03 2e+03 2e+00 7e+03 1e+00
1: 3.4061e+01 4.7700e+04 8e+06 9e+01 3e+05 2e+02
2: 7.0763e-01 4.3232e+02 6e+02 7e-01 3e+03 5e+01
3: 8.4793e-01 5.2743e+02 1e+03 9e-01 3e+03 6e+01
4: 1.8868e+00 7.3869e+01 1e+02 7e-02 3e+02 3e+01
5: 1.8724e+00 3.3409e+00 5e+00 2e-03 8e+00 3e-01
6: 1.4143e+00 1.8996e+00 1e+00 7e-04 3e+00 1e-01
7: 1.4221e+00 1.8726e+00 1e+00 6e-04 2e+00 1e-01
8: 1.3924e+00 1.5287e+00 3e-01 2e-04 8e-01 2e-02
9: 1.3752e+00 1.3953e+00 5e-02 3e-05 1e-01 2e-03
10: 1.3731e+00 1.3733e+00 6e-04 4e-07 1e-03 3e-05
11: 1.3730e+00 1.3730e+00 6e-06 4e-09 1e-05 3e-07
12: 1.3730e+00 1.3730e+00 6e-08 4e-11 1e-07 3e-09
13: 1.3730e+00 1.3730e+00 6e-10 4e-13 1e-09 3e-11
Optimal solution found.
{'x': <3x1 matrix, tc='d'>, 'y': <0x1 matrix, tc='d'>, 's': <1000x1 matrix, tc='d'>, 'z': <1000x1 matrix, tc='d'>, 'status': 'optimal', 'gap': 6.385522247857282e-10, 'relative gap': 4.65067372803741e-10, 'primal objective': 1.3730316552293447, 'dual objective': 1.3730316554698367, 'primal infeasibility': 3.958299300636158e-13, 'dual infeasibility': 1.4801406159663262e-09, 'primal slack': 9.474745058411444e-13, 'dual slack': 9.915311930562724e-14, 'residual as primal infeasibility certificate': None, 'residual as dual infeasibility certificate': None, 'iterations': 13}
最后的结果是以字典形式存储的,比较重要的是’x’键所指的内容,我们的最优解对应的向量,这里作图看一下效果。
w=list((sol['x']))
#作图
r=2*(rad+thk)
X3=[-r,r]
Y3=[-(w[0]+w[1]*i)/w[2] for i in X3]
plt.scatter(X1,Y1,s=1)
plt.scatter(X2,Y2,s=1)
plt.plot(X3,Y3)
plt.show()
效果还是很不错的,以上就是这次报错的总结,所以以后大量数据的优化使用cvxopt比较好。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Doraemonzzz!
评论
ValineLivere