Существует ли функция numpy / scipy для расчета штрафа за исходящие платежи? - PullRequest
0 голосов
/ 25 февраля 2020

В моей проблеме минимизации все ограниченные методы минимизации, такие как 'L-BFGS-B', 'TN C', не сходятся, но 'Nelder-Mead' сходится очень хорошо. Поэтому я предпочитаю использовать «Nelder-Mead» с измененной функцией минимизации, например:

def outbound_penalty(x, bounds):
    o1 = (bounds[:, 0]-x).max()
    o2 = (x-bounds[:, 1]).max()
    outbound = max(o1, o2, 0)
    rez = 100500*outbound

def bounded_fun(x, bounds):
    return fun(x) + outbound_penalty(x, bounds)

x - это numpy форма массива (4), границы имеют форму (2, 4), границы [ 0] - нижние границы, границы [1] - верхние границы. Это на удивление не так быстро, как я ожидал. При 4 * 10 ^ 6 вызовах это занимает 40 секунд собственного времени на процессоре. Конечно, я запомнил это. Но я должен спросить. Существуют ли некоторые очень оптимизированные функции в numpy / scipy, которые я могу использовать для создания исходящих штрафов?

sss = np.zeros((2, 1000))
sss[0] = np.random.uniform(-100, 300, 1000)
sss[1] = np.random.uniform(-100, 300, 1000)
smpls = sss.T

bnd = np.array([[0, 100+np.random.randint(100)], [0, 100+np.random.randint(100)]])
np_bounds = np.array(bnd)

def outbound_penalty(x, bs):
    o1 = (bs[:, 0] - x).max()
    o2 = (x - bs[:, 1]).max()
    outbound = max(o1, o2, 0)
    return 1000000 * outbound

def outbound_penalty_fast(x, bs):
    o1 = (bs[:, 0, None] - x).max(axis=0)
    o2 = (x - bs[:, 1, None]).max(axis=0)
    outbound = np.clip(np.maximum(o1, o2), a_max=None, a_min=0)
    return 1000000 * outbound

%timeit [outbound_penalty(x, np_bounds) for x in smpls]
22.6 ms ± 198 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit [outbound_penalty_fast(x, np_bounds) for x in smpls]
68.6 ms ± 1.62 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit outbound_penalty(smpls[0], np_bounds)
22.5 µs ± 109 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit outbound_penalty_fast(smpls[0], np_bounds)
68.2 µs ± 1.39 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Эта версия outbound_penalty_fast возвращает одно число с плавающей точкой, как и ожидал вызывающий:

def outbound_penalty_fast(x, bs):
    o1 = (bs[:, 0, None] - x).max(axis=0)
    o2 = (x - bs[:, 1, None]).max(axis=0)
    outbound = np.clip(np.maximum(o1, o2), a_max=None, a_min=0)
    rez = 1000000 * outbound.max()
    return rez

1 Ответ

1 голос
/ 25 февраля 2020

Вы можете использовать широковещание для выполнения исходящего поэлементного вызова функции в одном go и, конечно, использовать np.max() вместо сравнения y с mx в a для l oop:

import numpy as np


def outbound_penalty(x, bs):
    o1 = (bs[:, 0] - x).max()
    o2 = (x - bs[:, 1]).max()
    outbound = max(o1, o2, 0)
    return 1000000 * outbound


def outbound_penalty_fast(x, bs):
    o1 = (bs[:, 0, None] - x).max(axis=0)
    o2 = (x - bs[:, 1, None]).max(axis=0)
    outbound = np.clip(np.maximum(o1, o2), a_max=None, a_min=0)
    return 1000000 * outbound


bnd = np.random.randint(100, 200, size=(2, 2))
bnd[:, 0] = 0
sss = np.random.uniform(-100, 300, size=(2, 1000))

%timeit np.max(np.array([outbound_penalty(x, bnd) for x in sss.T]))
# 9.44 ms ± 166 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit np.max(outbound_penalty_fast(sss, bnd))
# 38.1 µs ± 1.33 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

mx = np.max(np.array([outbound_penalty(x, bnd) for x in sss.T]))
mx_fast = np.max(outbound_penalty_fast(sss, bnd))

mx == mx_fast  # True
...