Почему эта ограничительная функция намного медленнее, чем аналогичная, и как мне увеличить скорость в Scipy Optimize?

У меня есть оптимизация, которая имеет около 22 ограничительных функций. Я попытался превратить это в одну ограничивающую функцию, но оптимизатору потребовалось в 10 раз больше времени. Есть ли способ снизить скорость?

Ниже приведены исходные функции ограничений. Я включил только 2, но их около 22, каждый с жестко запрограммированными значениями ограничения неравенства. Параметры — это значения, которые ищет оптимизатор, а оптимизатор ищет около 50 значений. Например, для первого ограничения, по сути, говорится, что первые два значения параметра при суммировании не должны превышать 129:

def MaxConstraint000(parameters): 
    _count = np.sum(parameters[0:2])
    return (129 - _count)

def MaxConstraint001(parameters): 
    _count = np.sum(parameters[2:5])
    return (2571 - _count)

_Constraints = ({'type': 'ineq', 'fun': MaxConstraint000}
                , {'type': 'ineq', 'fun': MaxConstraint001})

Чтобы упростить свой код и вместо предварительного определения местоположения параметров, я попробовал что-то вроде этого, где я предоставляю значение ключа, которое извлекает местоположения индекса для значений параметров, а также постоянных значений [129, 2571 и т. д.). .] из фрейма данных. DFData имеет такое же количество строк, как и количество параметров. Ограничение идентично первому, за исключением того, что я указываю ключевое значение, которое позволяет мне искать максимальное значение, а также местоположения индекса.

def MaxConstraint(parameters, keyValue):
    _parameters= np.array(parameters)
    _index = np.where(DFData['KeyValues'].values == keyValue)[0] 
    
    _count = np.sum(_parameters[_index])
    _target = DFMaxValues.loc[[keyValue], ['MaxValue']].values[0][0]
    return (_target - _count )

_Constraints = ({'type': 'ineq', 'fun': MaxConstraint, 'args': ('keyValue1', )}
                , {'type': 'ineq', 'fun': MaxConstraint, 'args': ('keyValue2', )}

Это приводит к увеличению времени выполнения в 10 раз. Как мне снизить его примерно до той же скорости, что и первый? Я бы предпочел вторую реализацию, поскольку вместо того, чтобы вдаваться в каждое ограничение и изменять MaxValue, я могу вместо этого просто обновить словарь или CSV-файл. Кроме того, если строки данных смешиваются, у меня нет жестко закодированных значений индекса.

Спасибо!


Полный набор ограничений:

def MaxConstraint000(parameters):
    _count = np.sum(parameters[0:2])
    return (129 - _count)

def MaxConstraint001(parameters): 
    _count = np.sum(parameters[2:5])
    return (2571 - _count)

def MaxConstraint002(parameters): 
    _count = np.sum(parameters[5:8])
    return (3857 - _count)

def MaxConstraint003(parameters): 
    _count = np.sum(parameters[8:10])
    return (823 - _count)

def MaxConstraint004(parameters): 
    _count = np.sum(parameters[10:13])
    return (823 - _count)

def MaxConstraint005(parameters): 
    _count = np.sum(parameters[13:16])
    return (3857 - _count)

def MaxConstraint006(parameters): 
    _count = np.sum(parameters[16:21])
    return (4714 - _count)

def MaxConstraint007(parameters): 
    _count = np.sum(parameters[21:25])
    return (3429 - _count)

def MaxConstraint008(parameters): 
    _count = np.sum(parameters[25:28])
    return (3429 - _count)

def MaxConstraint009(parameters): 
    _count = np.sum(parameters[28:30])
    return (3429 - _count)

def MaxConstraint010(parameters): 
    _count = np.sum(parameters[30:33])
    return (2914 - _count)

def MaxConstraint011(parameters):
    _count = np.sum(parameters[33:38])
    return (6000 - _count)

def MaxConstraint012(parameters): 
    _count = np.sum(parameters[38:43])
    return (6000 - _count)

def MaxConstraint013(parameters): 
    _count = np.sum(parameters[43:45])
    return (429 - _count)

def MaxConstraint014(parameters): 
    _count = np.sum(parameters[45:47])
    return (1457 - _count)

def MaxConstraint015(parameters): 
    _count = np.sum(parameters[47:51])
    return (4286 - _count)

def MaxConstraint016(parameters): 
    _count = np.sum(parameters[51:53])
    return (2143 - _count)

def MaxConstraint017(parameters): 
    _count = np.sum(parameters[53:57])
    return (4286 - _count)

def MaxConstraint018(parameters): 
    _count = np.sum(parameters[57:64])
    return (2143 - _count)

def MaxConstraint019(parameters): 
    _count = np.sum(parameters[64:67])
    return (2571 - _count)

def MaxConstraint020(parameters): 
    _count = np.sum(parameters[67:72])
    return (1714 - _count)

def MaxConstraint021(parameters): 
    _count = np.sum(parameters[72:75])
    return (4286 - _count)
    
_Bounds = ((0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000)
           , (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000)
           , (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000)
           , (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000)
           , (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000)
           , (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000)
           , (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000)
           , (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000)
           , (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000), (0, 10000)
           , (0, 10000), (0, 10000), (0, 10000))

_Constraints = ({'type': 'ineq', 'fun': MaxConstraint000}
                , {'type': 'ineq', 'fun': MaxConstraint001}
                , {'type': 'ineq', 'fun': MaxConstraint002}
                , {'type': 'ineq', 'fun': MaxConstraint003}
                , {'type': 'ineq', 'fun': MaxConstraint004}
                , {'type': 'ineq', 'fun': MaxConstraint005}
                , {'type': 'ineq', 'fun': MaxConstraint006}
                , {'type': 'ineq', 'fun': MaxConstraint007}
                , {'type': 'ineq', 'fun': MaxConstraint008}
                , {'type': 'ineq', 'fun': MaxConstraint009}
                , {'type': 'ineq', 'fun': MaxConstraint010}
                , {'type': 'ineq', 'fun': MaxConstraint011}
                , {'type': 'ineq', 'fun': MaxConstraint012}
                , {'type': 'ineq', 'fun': MaxConstraint013}
                , {'type': 'ineq', 'fun': MaxConstraint014}
                , {'type': 'ineq', 'fun': MaxConstraint015}
                , {'type': 'ineq', 'fun': MaxConstraint016}
                , {'type': 'ineq', 'fun': MaxConstraint017}
                , {'type': 'ineq', 'fun': MaxConstraint018}
                , {'type': 'ineq', 'fun': MaxConstraint019}
                , {'type': 'ineq', 'fun': MaxConstraint020}
                , {'type': 'ineq', 'fun': MaxConstraint021}
               )

############# Solve Optim Problem ############### 
_OptimResultsConstraint = scipy_opt.minimize(ObjectiveFunction
                                             , x0 = [10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000,
                                                   10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000,
                                                   10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000,
                                                   10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000,
                                                   10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000,
                                                   10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000,
                                                   10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000,
                                                   10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000,
                                                   10000, 10000, 10000] # starting guesses
                                             , method = 'trust-constr' # trust-constr, SLSQP
                                             , options = {'maxiter': 1000000000}
                                             , bounds = _Bounds
                                             , constraints = _Constraints) 

Не воспроизводимо. Если вы действительно покажете свой код, я смогу продемонстрировать, как объединить большинство (все?) ваших ограничений в одну линейную матрицу ограничений.

Reinderien 24.04.2024 23:57

ок, позвольте мне отредактировать весь код. Спасибо!

we_are_all_in_this_together 24.04.2024 23:59

вам нужна сама целевая функция или этого достаточно?

we_are_all_in_this_together 25.04.2024 00:07

Это все еще невозможно воспроизвести, но я все равно напишу неожиданный ответ.

Reinderien 25.04.2024 00:10

что еще тебе нужно?

we_are_all_in_this_together 25.04.2024 00:12
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
5
69
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ваши многочисленные ограничения на самом деле являются всего лишь одним ограничением. Самый компактный способ его представления — разреженный массив CSR:

import numpy as np
from scipy.optimize import LinearConstraint
import scipy.sparse

A = scipy.sparse.csr_array(
    (
        np.ones(75),    # data
        np.arange(75),  # indices
        (
            0, 2, 5, 8, 10, 13, 16, 21, 25, 28,
            30, 33, 38, 43, 45, 47, 51, 53, 57,
            64, 67, 72, 75,
        ),
    ),
)

constraint = LinearConstraint(
    A=A,
    ub=(
        129, 2571, 3857, 823, 823, 3857, 4714, 3429, 3429, 3429,
        2914, 6000, 6000, 429, 1457, 4286, 2143, 4286, 2143, 2571,
        1714, 4286,
    ),
)

Ах да, я только что рассмотрел линейные ограничения. Это очень полезно.

we_are_all_in_this_together 25.04.2024 04:32

В итоге это творило чудеса. Не осознавал, что я могу использовать разреженную матрицу для вычисления группы по суммам, а затем подача этого вектора в LinearConstraint была намного быстрее, чем наличие строки для каждого ограничения.

we_are_all_in_this_together 03.05.2024 20:53

вы можете попробовать использовать np.bincount в своей функции,

def MaxConstraint(parameters, keyValue):
    _parameters= np.array(parameters)        
    _count = np.bincount(keyValue,weights=_parameters)
    _target = DFMaxValues.loc[[keyValue], ['MaxValue']].values[0][0]
    return (_target - _count )

Оценку _target, вероятно, тоже можно оптимизировать, но мне может понадобиться пример DFMaxValues, чтобы придумать альтернативу.

Хороший импульс - но np.bincount() на струнах не работает.

Nick ODell 25.04.2024 02:50

Думаю, мы можем использовать keyValue=np.unique(keyValue, return_inverse=True)[1] в случае строки keyValue перед вводом ее в функцию.

Zain 25.04.2024 03:04

Другие вопросы по теме