Как установить границы при минимизации с помощью scipy - PullRequest
0 голосов
/ 09 июня 2018

У меня есть несколько data в массиве numpy.

Я хотел бы масштабировать данные с использованием линейной функции в соответствии со следующими правилами:

  1. Среднее значение равнокак можно ближе к 65
  2. Наименьшее значение по крайней мере 50

Для моей первой попытки я сделал функцию оценки:

import numpy as np
from scipy.optimize import minimize
def score(x):
    return abs(np.mean(x[0]*data+x[1]) - 65) + abs(x[0]*np.min(data)+x[1] - 50)

Я добавил наabs(x[0]*np.min(data)+x[1] - 50) как тщетная попытка заставить его удовлетворить правило 2.

Затем я попытался:

x0 = [0.85,0]
res = minimize(score,x0)
np.set_printoptions(suppress=True)
print res

Это дает:

fun: 4.8516444911893615
hess_inv: array([[ 0.0047, -0.1532],
       [-0.1532,  5.2375]])
      jac: array([-50.9628,  -2.    ])
message: 'Desired error not necessarily achieved due to precision loss.'
     nfev: 580
      nit: 2
     njev: 142
   status: 2
  success: False
        x: array([0.7408, 1.4407])

Другими словамиоптимизация не удалась.

Я также хотел бы установить границы для коэффициентов, например, bounds = [(0.7,1.3),(-5,5)].

Мой вопрос заключается в том, как правильно выполнить оптимизацию с граничным условием, чтомасштабированное наименьшее значение составляет не менее 50?Кроме того, как я могу сделать так, чтобы оптимизация работала без сбоев?

Ответы [ 2 ]

0 голосов
/ 09 июня 2018

Извините, если я вас неправильно понял, но просто масштабировать данные в соответствии с этими двумя правилами - это прямая линейная алгебра:

e = np.mean(data)
m = e - np.min(data)

data * (65-50)/m + (65 - e*(65-50)/m)
# i.e. (data-e) * (65-50)/m + 65

Это в среднем означает 65 и минимум 50.

0 голосов
/ 09 июня 2018

Рассмотрим следующее:

import numpy as np
from scipy.optimize import minimize

data = np.array([ 59. ,  59.5,  61. ,  61.5,  62.5,  63. ,  63. ,  65.5,  66.5,
    67. ,  68. ,  69. ,  69.5,  70.5,  70.5,  70.5,  71. ,  72. ,
    72. ,  73.5,  73.5,  74. ,  75. ,  75.5,  78. ,  79. ,  79. ,
    79. ,  79.5,  80.5,  80.5,  80.5,  80.5,  80.5,  82.5,  82.5,
    82.5,  83. ,  83. ,  83. ,  83. ,  83. ,  83.5,  83.5,  84. ,
    84.5,  84.5,  84.5,  86. ,  86. ,  86. ,  86.5,  86.5,  87.5,
    88. ,  88. ,  88.5,  89. ,  90. ,  90.5,  90.5,  90.5,  91. ,
    91.5,  91.5,  92. ,  92. ,  93. ,  93. ,  93. ,  93.5,  93.5,
    94. ,  94. ,  94. ,  94. ,  94. ,  94. ,  94.5,  94.5,  94.5,
    94.5,  95.5,  95.5,  95.5,  95.5,  95.5,  95.5,  96. ,  96. ,
    96. ,  96.5,  96.5,  96.5,  98. ,  98. ,  98. ,  98. ,  98. ,
    98. ,  98. ,  98. ,  98.5,  98.5,  98.5,  98.5,  98.5, 100. ,
   100. , 100. , 100. ])

def scale(data, coeffs):
    m,b = coeffs
    return (m * data) + b

def score(coeffs):
    scaled = scale(data, coeffs)
    # Penalty components
    p_1 = abs(np.mean(scaled) - 65)
    p_2 = max(0, (50 - np.min(scaled)))
    return p_1 + p_2

res = minimize(score, (0.85, 0.0), method = 'Powell')
#np.set_printoptions(suppress=True)
print(res)

post = scale(data, res.x)

print(np.mean(post))
print(np.min(post))
print(score(res.x))

Выходы:

   direc: array([[ -3.05475495e-02,   2.62047576e+00],
       [  7.54828106e-07,  -6.47892698e-05]])
     fun: 1.4210854715202004e-14
 message: 'Optimization terminated successfully.'
    nfev: 360
     nit: 8
  status: 0
 success: True
       x: array([  0.55914442,  17.02691959])
print(np.mean(post))  # 65.0
print(np.min(post))   # 50.0164406291
print(score(res.x))   # 1.42108547152e-14

Несколько вещей:

  • Я добавил scale помощникфункция, чтобы немного очистить код, так как я использую его в функции score, а также в конце, чтобы показать масштабированные данные.
  • Функция score была исправлена ​​и разбита на два отдельныхштрафы (по одному на каждое требование) для ясности.Он вычисляет масштабированный вектор один раз (и вызывает его scaled), а затем вычисляет компоненты штрафа.
  • Примечание: эта функция оценки имеет нечетную негладкую область около min (data) = 50 из-за max звонок.Это может вызвать проблемы с некоторыми методами оптимизации.
  • Я использовал алгоритм Пауэлла, потому что я использовал его раньше, и он работал в аналогичной проблеме с использованием оператора min / max.Википедия говорит :

    Этот метод полезен для вычисления локального минимума непрерывной, но сложной функции, особенно без базового математического определения, поскольку нет необходимости брать производные

    Кто-то, более знакомый с методами оптимизации, может предложить лучшую альтернативу.

  • (Правка) Наконец, в связи с вашим вопросом о граничных условиях,Обычно, когда мы говорим о граничных условиях, мы говорим о границе независимой переменной, вектора, который мы оптимизируем (здесь, элементы coeffs или x) - например, "x [0] долженбыть меньше 0 ", или" x [1] должен быть между 0 и 1 "- не то, что вы, похоже, ищете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...