首页 > 解决方案 > 如何将多目标二进制分类器优化(多类)从 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);

在蟒蛇

  1. 我们并不完全理解如何正确定义我们的问题类。我们试图遵循一些示例,但我们并不清楚如何根据我们的案例定义目标函数。

这是来自 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 在示例中是如何被调用和处理的?

  1. 如何为 GA 对象选择最佳参数?

过去两周我们一直停留在这一点上。我们非常感谢您的帮助

标签: pythonpython-3.xmatlaboptimizationgenetic-algorithm

解决方案


我在他们的官方页面中找到了一些实现。只需向下滚动到最后以了解有关参数的更多信息并在页面中返回。

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 参数然后在其上实现上述公式来定义的。


推荐阅读