У меня есть оптимизация, которая имеет около 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)
ок, позвольте мне отредактировать весь код. Спасибо!
вам нужна сама целевая функция или этого достаточно?
Это все еще невозможно воспроизвести, но я все равно напишу неожиданный ответ.
что еще тебе нужно?
Ваши многочисленные ограничения на самом деле являются всего лишь одним ограничением. Самый компактный способ его представления — разреженный массив 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,
),
)
Ах да, я только что рассмотрел линейные ограничения. Это очень полезно.
В итоге это творило чудеса. Не осознавал, что я могу использовать разреженную матрицу для вычисления группы по суммам, а затем подача этого вектора в LinearConstraint была намного быстрее, чем наличие строки для каждого ограничения.
вы можете попробовать использовать 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()
на струнах не работает.
Думаю, мы можем использовать keyValue=np.unique(keyValue, return_inverse=True)[1]
в случае строки keyValue
перед вводом ее в функцию.
Не воспроизводимо. Если вы действительно покажете свой код, я смогу продемонстрировать, как объединить большинство (все?) ваших ограничений в одну линейную матрицу ограничений.