python - 如何将多目标二进制分类器优化(多类)从 matlab 转换为 python(使用 pymoo)?
问题描述
我目前正在与两个学生同事一起使用优化包 pymoo。我们已经在文档中进行了搜索,但我们仍在努力解决一些问题。主要挑战是定义和实施我们的问题。这个问题在于优化基于蛋白质的分类器。
我们的目标是最小化蛋白质的数量并最大化分类器(目标函数)的准确性。我们已经在 matlab 中实现了优化,但我们正打算在 Python 上复制它。
在matlab中,我们有:
X 是一个 mxn 特征矩阵(m=samples, n=features) Y 是一个多类向量(类:1,2,3,4)
[m,n]=size(X);
folds=5;
Indices=k_fold(folds,m);
首先,我们定义了问题的选项参数,它们是:多目标方法、50 代和 5 代的人口规模。这个问题是不受约束的。
options = optimoptions('gamultiobj','PopulationType','bitstring','PopulationSize',50,'PlotFcn',@gaplotpareto,'UseParallel',true,'Display','iter','MaxGenerations',5);
fcn 是接收归一化特征矩阵 Xn 和 Y 的目标函数(索引与 Kfold-cross 验证有关)
fcn=@(Sol)ObjFunc(Sol,Xn,Y,Indices);
通过这种方式,我们可以获得优化的输出,包括: BestSol 是找到最佳解决方案的向量。Fval 是一个 2 列向量,根据用于分类的特征数量匹配最佳解决方案。
[BestSol,Fval] = gamultiobj(fcn,n,[],[],[],[],[],[],options);
目的是获得表示最佳特征的二进制向量(0和1)(用于优化分类器)
整个代码的第一部分是:
[m,n]=size(X);
folds=5;
Indices=k_fold(folds,m);
options = optimoptions('gamultiobj','PopulationType','bitstring','PopulationSize',50,'PlotFcn',@gaplotpareto,'UseParallel',true,'Display','iter','MaxGenerations',5);
fcn=@(Sol)ObjFunc(Sol,Xn,Y,Indices);
[BestSol,Fval] = gamultiobj(fcn,n,[],[],[],[],[],[],options);
在蟒蛇
- 我们并不完全理解如何正确定义我们的问题类。我们试图遵循一些示例,但我们并不清楚如何根据我们的案例定义目标函数。
这是来自 pymoo 文档https://pymoo.org/problems/index.html#的示例
class SphereWithConstraint(Problem):
def __init__(self):
super().__init__(n_var=10, n_obj=1, n_constr=1, xl=0, xu=1)
def _evaluate(self, x, out, *args, **kwargs):
out["F"] = np.sum((x - 0.5) ** 2, axis=1)
out["G"] = 0.1 - out["F"]
在我们的例子中是这样的:
import numpy as np
from pymoo.model.problem import Problem
class ProteinClassifier(Problem):
def __init__(self):
super().__init__(n_var= *columns of X* , n_obj=2, n_constr=0)
def _evaluate(self, x, out, *args, **kwargs):
out["F"] = ??????????
out["G"] = ??????????
在这个例子中,他们创建了一个二进制单一目标优化https://pymoo.org/customization/binary_problem.html:
import numpy as np
from pymoo.algorithms.so_genetic_algorithm import GA
from pymoo.factory import get_crossover, get_mutation, get_sampling
from pymoo.optimize import minimize
from pymoo.problems.single.knapsack import create_random_knapsack_problem
problem = create_random_knapsack_problem(30)
algorithm = GA(
pop_size=200,
sampling=get_sampling("bin_random"),
crossover=get_crossover("bin_hux"),
mutation=get_mutation("bin_bitflip"),
eliminate_duplicates=True)
res = minimize(problem,
algorithm,
('n_gen', 100),
verbose=False)
print("Best solution found: %s" % res.X.astype(int))
print("Function value: %s" % res.F)
print("Constraint violation: %s" % res.CV)
我们想做一些类似的东西,但是为了多目标:
Best solution found: [1 0 0 0 1 0 1 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 0 1 0 0]
Function value: [-686]
Constraint violation: [0.]
查看 github 源代码,我们发现了这个,但不清楚他们在哪里定义了 x 代码应该作为 _evaluate 中的参数接收(应该是问题类中的装饰器):
def _evaluate(self, x, out, *args, **kwargs):
out["F"] = -anp.sum(self.P * x, axis=1)
out["G"] = (anp.sum(self.W * x, axis=1) - self.C)
问题源代码的工作方式如下:
def evaluate(self,
X,
*args,
return_values_of="auto",
return_as_dictionary=False,
**kwargs):
"""
Evaluate the given problem.
The function values set as defined in the function.
The constraint values are meant to be positive if infeasible. A higher positive values means "more" infeasible".
If they are 0 or negative, they will be considered as feasible what ever their value is.
但随后定义了一个装饰器:
@abstractmethod
def _evaluate(self, x, out, *args, **kwargs):
pass
该方法def _evaluate(self, x, out, *args, **kwargs):
接收参数x,但我们还没有找到在哪里定义和调用。因此,我们无法执行我们的目标函数,甚至无法将特征矩阵作为输入。
-我们如何以及在哪里定义目标函数?
- x 在示例中是如何被调用和处理的?
- 如何为 GA 对象选择最佳参数?
过去两周我们一直停留在这一点上。我们非常感谢您的帮助
解决方案
我在他们的官方页面中找到了一些实现。只需向下滚动到最后以了解有关参数的更多信息并在页面中返回。
import numpy as np
import autograd.numpy as anp
from pymoo.model.problem import Problem
class MyProblem(Problem):
def __init__(self, const_1=5, const_2=0.1):
# define lower and upper bounds - 1d array with length equal to number of variable
xl = -5 * anp.ones(10)
xu = 5 * anp.ones(10)
super().__init__(n_var=10, n_obj=1, n_constr=2, xl=xl, xu=xu, evaluation_of="auto")
# store custom variables needed for evaluation
self.const_1 = const_1
self.const_2 = const_2
def _evaluate(self, x, out, *args, **kwargs):
f = anp.sum(anp.power(x, 2) - self.const_1 * anp.cos(2 * anp.pi * x), axis=1)
g1 = (x[:, 0] + x[:, 1]) - self.const_2
g2 = self.const_2 - (x[:, 2] + x[:, 3])
out["F"] = f
out["G"] = anp.column_stack([g1, g2])
基本上,您启动类的实例,MyProblem
然后调用评估方法。
problem = MyProblem()
dict = problem.evaluate(self, x, out, return_as_dictionary=True)
Returns dict if `return_as_dictionary` is set True or you specify a values of list of strings to be exited
a, b, c, d, e = problem.evaluate(x, return_values_of=[a, b, c, d, e])
Allowed values are [“F”, “CV”, “G”, “dF”, “dG”, “dCV”, “feasible”] for the this argument.
我不太确定 GA 对象是什么意思,但我猜它是 g1 和 g2 对象,它们是通过传递 x 参数然后在其上实现上述公式来定义的。
推荐阅读
- python - 尝试在 python 上绘制等高线图/热图时插值不顺利
- git - 使用 git clone 命令从 azure devops 签出多个存储库时出错
- hyperledger-fabric - Hyperledger Fabric:使用 JsonPath 将新组织添加到现有通道
- jenkins - 如何使用电子邮件扩展将 Jenkins 构建作业状态设置为电子邮件的默认主题
- javascript - 当按钮单击 CHROME EXTENSION 时,如何从内容脚本打开选项页面?
- testing - Rust 禁用特定目标的所有测试
- android - 开始活动而不在屏幕上闪烁/闪烁
- python - 聚合到多索引,同时将一些列名设置为行名并通过它们汇总列集
- frontend - 有没有办法创建别名/变量/命令以在赛普拉斯测试中重复静态代码块?
- parsing - 为什么TPTP(千题...)公式的解析树中有二进制公式(thf_binary_formula)?