”一般来说,批量创建线性约束的性能会比一次创建一个线性约束的性能更好。我只是想知道即使面对巨大的问题,是否也是如此。” – 一位睿智的程序员。
为了说明清楚,我有一个(35k x 40)的数据集,我想要对其进行SVM分析。我需要生成这个数据集的Gramm矩阵,这没问题,但将系数传递给CPLEX却是一团糟,需要几个小时,以下是我的代码:
nn = 35000 XXt = np.random.rand(nn,nn) # 数据集的Gramm矩阵 yy = np.random.rand(nn) # 数据集的标签向量 temp = ((yy*XXt).T)*yy xg, yg = np.meshgrid(range(nn), range(nn)) indici = np.dstack([yg,xg]) quadraric_part = [] for ii in xrange(nn): for indd in indici[ii][ii:]: quadraric_part.append([indd[0],indd[1],temp[indd[0],indd[1]]])
‘quadratic_part’ 是一个形如 [i,j,c_ij] 的列表,其中 c_ij 是存储在 temp 中的系数。它将被传递给 CPLEX Python API 的 ‘objective.set_quadratic_coefficients()’ 函数。
有没有更明智的方法来做这件事?
附注:我可能有内存问题,所以最好不要存储整个 ‘quadratic_part’ 列表,而是多次调用 ‘objective.set_quadratic_coefficients()’ 函数……你明白我的意思吧?!
回答:
在幕后,objective.set_quadratic 使用了 C 可调用库中的 CPXXcopyquad 函数。而 objective.set_quadratic_coefficients 使用了 CPXXcopyqpsep。
这里有一个例子(请注意,我不是numpy专家;可能有更好的方法来处理这部分):
import numpy as npimport cplexnn = 5 # 这里是一个小样本大小XXt = np.random.rand(nn,nn) # 数据集的Gramm矩阵yy = np.random.rand(nn) # 数据集的标签向量temp = ((yy*XXt).T)*yy# 创建对称矩阵tempu = np.triu(temp) # 上三角矩阵iu1 = np.triu_indices(nn, 1)tempu.T[iu1] = tempu[iu1] # 将上三角复制到下三角ind = np.array([[x for x in range(nn)] for x in range(nn)])qmat = []for i in range(nn): qmat.append([np.arange(nn), tempu[i]])c = cplex.Cplex()c.variables.add(lb=[0]*nn)c.objective.set_quadratic(qmat)c.write("test2.lp")
你的Q矩阵是完全稠密的,因此根据你拥有的内存量,这种技术可能无法扩展。然而,当可能时,你应该通过使用 objective.set_quadratic
来初始化你的Q矩阵以获得更好的性能。或许你需要使用某种混合技术,同时使用 set_quadratic
和 set_quadratic_coefficients
。