Otimização de recursos do produto com restrições

Siddhant Tandon

Eu treinei um modelo Lightgbm para aprender a classificar o conjunto de dados. O modelo prevê a pontuação de relevância de uma amostra. Quanto maior a previsão, melhor. Agora que o modelo aprendeu, gostaria de encontrar os melhores valores de alguns recursos que me dão a pontuação de previsão mais alta.

Então, digamos que eu tenha recursos u,v,w,x,y,ze os recursos que gostaria de otimizar x,y,z.

maximize f(u,v,w,x,y,z) w.r.t features x,y,z where f is a lightgbm model
subject to constraints : 
y = Ax + b
z = 4 if y < thresh_a else 4-0.5 if y >= thresh_b  else 4-0.3
thresh_m < x <= thresh_n

Os números são compostos aleatoriamente, mas as restrições são lineares.

A função objetivo em relação a se xparece com o seguinte:

insira a descrição da imagem aqui

Portanto, a função é muito pontiaguda, não lisa. Eu também não tenho as informações do gradiente, pois fé um modelo lightgbm.

Usando a resposta de Nathan, escrevi a seguinte aula:

class ProductOptimization:
    
    def __init__(self, estimator,  features_to_change, row_fixed_values, 
                 bnds=None):
        self.estimator = estimator 
        self.features_to_change = features_to_change
        self.row_fixed_values = row_fixed_values
        self.bounds = bnds
                    
    def get_sample(self, x):
        
        new_values = {k:v for k,v in zip(self.features_to_change, x)}
        
        return self.row_fixed_values.replace({k:{self.row_fixed_values[k].iloc[0]:v} 
                                  for k,v in new_values.items()})
    
    def _call_model(self, x):
        
        pred = self.estimator.predict(self.get_sample(x))
        return pred[0]
    
    def constraint1(self, vector):
        x = vector[0]
        y = vector[2]
        return # some float value
    
    def constraint2(self, vector):
        x = vector[0]
        y = vector[3] 
        return #some float value
    
    def optimize_slsqp(self, initial_values):
        
        con1 = {'type': 'eq', 'fun': self.constraint1}
        con2 = {'type': 'eq', 'fun': self.constraint2}
        cons = ([con1,con2])

        
        result = minimize(fun=self._call_model,
                          x0=np.array(initial_values),
                          method='SLSQP',
                          bounds=self.bounds,
                          constraints=cons)
        return result

Os resultados que obtenho estão sempre em torno da estimativa inicial. E eu acho que é por causa da não suavidade da função e da ausência de qualquer informação de gradiente que é importante para o otimizador SLSQP. Algum conselho sobre como devo lidar com esse tipo de problema?

Nathan

Já se passou um bom minuto desde a última vez que escrevi algum código sério, então peço desculpas se não estiver totalmente claro o que tudo faz, sinta-se à vontade para pedir mais explicações

As importações:

from sklearn.ensemble import GradientBoostingRegressor
import numpy as np
from scipy.optimize import minimize
from copy import copy

Primeiro, defino uma nova classe que me permite redefinir valores facilmente. Esta classe possui 5 entradas:

  1. valor: este é o valor 'base'. Na sua equação y=Ax + bé a bparte
  2. mínimo: este é o valor mínimo que este tipo avaliará como
  3. máximo: este é o valor máximo que este tipo avaliará como
  4. multiplicadores: o primeiro complicado. É uma lista de outros objetos InputType. O primeiro é o tipo de entrada e o segundo, o multiplicador. No seu exemplo, y=Ax +bvocê teria [[x, A]], se a equação fosse y=Ax + Bz + Cd, seria[[x, A], [z, B], [d, C]]
  5. relações: o mais complicado. É também uma lista de outros objetos InputType, tem quatro itens: o primeiro é o tipo de entrada, o segundo define se é um limite superior que você usa min, se é um limite inferior que você usa max. O terceiro item da lista é o valor do limite, e o quarto é o valor de saída conectado a ele

Cuidado se você definir seus valores de entrada de maneira muito estranha, tenho certeza de que há um comportamento estranho.

class InputType:

    def __init__(self, value=0, minimum=-1e99, maximum=1e99, multipliers=[], relations=[]):
        """

        :param float value: base value
        :param float minimum: value can never be lower than x
        :param float maximum: value can never be higher than y
        :param multipliers: [[InputType, multiplier], [InputType, multiplier]]
        :param relations: [[InputType, min, threshold, output_value], [InputType, max, threshold, output_value]]
        """
        self.val = value
        self.min = minimum
        self.max = maximum
        self.multipliers = multipliers
        self.relations = relations

    def reset_val(self, value):
        self.val = value

    def evaluate(self):
        """
        - relations to other variables are done first if there are none then the rest is evaluated

        - at most self.max
        - at least self.min
        - self.val + i_x * w_x
        i_x is input i, w_x is multiplier (weight) of i
        """
        for term, min_max, value, output_value in self.relations:
            # check for each term if it falls outside of the expected terms
            if min_max(term.evaluate(), value) != term.evaluate():
                return self.return_value(output_value)

        output_value = self.val + sum([i[0].evaluate() * i[1] for i in self.multipliers])
        return self.return_value(output_value)

    def return_value(self, output_value):
        return min(self.max, max(self.min, output_value))

Usando isso, você pode corrigir os tipos de entrada enviados do otimizador, conforme mostrado em _call_model:

class Example:

    def __init__(self, lst_args):
        self.lst_args = lst_args

        self.X = np.random.random((10000, len(lst_args)))
        self.y = self.get_y()
        self.clf = GradientBoostingRegressor()
        self.fit()

    def get_y(self):
        # sum of squares, is minimum at x = [0, 0, 0, 0, 0 ... ]
        return np.array([[self._func(i)] for i in self.X])

    def _func(self, i):
        return sum(i * i)

    def fit(self):
        self.clf.fit(self.X, self.y)

    def optimize(self):
        x0 = [0.5 for i in self.lst_args]
        initial_simplex = self._get_simplex(x0, 0.1)
        result = minimize(fun=self._call_model,
                          x0=np.array(x0),
                          method='Nelder-Mead',
                          options={'xatol': 0.1,
                                   'initial_simplex': np.array(initial_simplex)})
        return result

    def _get_simplex(self, x0, step):
        simplex = []
        for i in range(len(x0)):
            point = copy(x0)
            point[i] -= step
            simplex.append(point)

        point2 = copy(x0)
        point2[-1] += step
        simplex.append(point2)
        return simplex

    def _call_model(self, x):
        print(x, type(x))
        for i, value in enumerate(x):
            self.lst_args[i].reset_val(value)

        input_x = np.array([i.evaluate() for i in self.lst_args])
        prediction = self.clf.predict([input_x])
        return prediction[0]

Posso definir o seu problema conforme mostrado abaixo (certifique-se de definir as entradas na mesma ordem da lista final, caso contrário, nem todos os valores serão atualizados corretamente no otimizador!) :

A = 5
b = 2
thresh_a = 5
thresh_b = 10
thresh_c = 10.1
thresh_m = 4
thresh_n = 6

u = InputType()
v = InputType()
w = InputType()
x = InputType(minimum=thresh_m, maximum=thresh_n)
y = InputType(value = b, multipliers=([[x, A]]))
z = InputType(relations=[[y, max, thresh_a, 4], [y, min, thresh_b, 3.5], [y, max, thresh_c, 3.7]])


example = Example([u, v, w, x, y, z])

Chamando os resultados:

result = example.optimize()
for i, value in enumerate(result.x):
    example.lst_args[i].reset_val(value)
print(f"final values are at: {[i.evaluate() for i in example.lst_args]}: {result.fun)}")

Este artigo é coletado da Internet.

Se houver alguma infração, entre em [email protected] Delete.

editar em
0

deixe-me dizer algumas palavras

0comentários
loginDepois de participar da revisão

Artigos relacionados

Atribuição da equipe do Hackathon com restrições de programação e otimização

Otimização de restrições com as ferramentas de pesquisa operacional do Google

Otimização de array Python com duas restrições

Unindo a tabela de atributos do produto com a tabela do produto para exibir o produto

A expressão do produto faz com que os recursos não sejam renderizados

O desempenho do monitoramento mundial está sendo afetado por restrições de recursos

configuração para problema de otimização R com restrições de pesos

Otimização de agendamento para minimizar o número de timeslots (com restrições)

Layout de restrição do Android, visualizações com peso?

Otimização de portfólio SciPy com restrições de nível de indústria

Otimização de Nelder-Mead com restrições de igualdade

Como fazer a otimização de portfólio com restrições no número de ativos?

Woocommerce seleção de variação de produto com botões em vez do menu suspenso?

Resolvendo problemas de otimização quadrática com restrições complexas em R

Alterar o pedido de modelos de produto único do Woocommerce com base na tag do produto

Otimização com limites de junta / restrição simbólica

Como fazer upload do aplicativo laravel no servidor do produto com o modo de produto

Otimização com restrição "adicionar a 1" na variável de otimização

Pandas, k de n combinações com soma do produto

Soma da fórmula do Excel; o produto precisa de otimização

Combine as dimensões do produto com a expressão regular

Marcação de produto com fórmula do Excel

Analisando a descrição do produto de XML com PHP

Envie a descrição do produto de comércio de woocommerce do gateway de pagamento ao lado do nome do produto

Otimização não convexa com restrições lineares

otimização de uma função objetivo linear com restrições lineares e variáveis binárias em python

Android Studio: combinação de sabor do produto com mais de duas dimensões de sabor (grupos de sabor)

Android Studio: combinação de sabor do produto com mais de duas dimensões de sabor (grupos de sabor)

Maximize a otimização com duas restrições usando Scipy

TOP lista

quentelabel

Arquivo