Как мне подогнать рекуррентные отношения, используя scipy.optimize.fmin_l_bfgs_b? - PullRequest
0 голосов
/ 10 февраля 2020

Я недавно смотрел видео Veritasium , где он проходил увлекательное обсуждение карты logisti c . Это заставило меня задуматься о рекуррентных отношениях и о том, как параметрические c рекуррентные отношения могут соответствовать данным.

Я бы хотел параметризовать $ \ theta $ в $ \ hat y_ {n + 1} = \ theta \ hat y_ {n} (1- \ hat y_ {n}) $ на последовательности $ y_k \ in [0, 1] $, где $ k = n + 1 $, путем минимизации среднеквадратичной ошибки с использованием L- Алгоритм BFGS-B доступен в Scipy . Этот пример будет полезным для меня, чтобы обобщить для подгонки других рекуррентных отношений к реальным данным. Как реализовать целевую функцию, где прогнозируемые значения являются выходом рекуррентного отношения таким образом, чтобы его можно было передать в аргумент func fmin_l_bfgs_b?

1 Ответ

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

Если я правильно понимаю ваш вопрос, вы хотите найти значение $ \ theta $, минимизирующее $ \ sum_ {n = 0} ^ {N-1} (\ hat y_ {n + 1} - \ theta \ hat y_ {n} (1 - \ hat y_ {n})) ^ 2 $, учитывая последовательность $ {\ hat y_k} _ {k = 0} ^ N $. Если это так, предполагая, что ваши данные ys и ваши начальные предположения x0, вы можете сделать это с помощью

def f(l): 
    t = l[0] 
    return ((ys[1:] - (t * ys[:-1] * (1 - ys[:-1])))**2).sum()

fmin_l_bfgs_b(f, x0=(x0,), approx_grad=True)

Например, если мы создадим некоторые данные, для которых theta равно приблизительно 3:

In [43]: import numpy as np 
    ...: ys = [0.3] 
    ...: theta = 3 
    ...: for _ in range(100): 
    ...:     ys.append((np.random.uniform(-0.02, 0.02) + theta)*ys[-1] * (1 - ys[-1])) 
    ...: ys = np.array(ys) 
    ...:                                                                                        

In [44]: def f(l): 
    ...:     t = l[0] 
    ...:     return ((ys[1:] - (t * ys[:-1] * (1 - ys[:-1])))**2).sum() 
    ...: fmin_l_bfgs_b(f, x0=(0.5,), approx_grad=True)                                          
Out[44]: 
(array([2.99949454]),
 0.0006258145273212467,
 {'grad': array([-5.70908338e-07]),
  'task': b'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL',
  'funcalls': 6,
  'nit': 2,
  'warnflag': 0})

Здесь, конечно, вы также можете указать градиент; Я был немного ленив.

Однако, если это действительно то, что вы пытаетесь сделать, скорее всего, вы захотите что-то с учетом задач наименьших квадратов (таких как Левенберг - Марквардт); в SciPy такие методы доступны в scipy.optimize.least_squares. С их помощью ваша проблема сводится к следующему:

def F(t): 
    return ys[1:] - (t * ys[:-1] * (1 - ys[:-1]))

least_squares(F, x0=x0)

С данными сверху:

In [53]: def F(t): 
    ...:     return ys[1:] - (t * ys[:-1] * (1 - ys[:-1])) 
    ...:                                                                                        

In [54]: least_squares(F, x0=0.5)                                                               
Out[54]: 
 active_mask: array([0.])
        cost: 0.00031290726365087974
         fun: ...
        grad: array([-2.43698605e-09])
         jac: ...
     message: '`gtol` termination condition is satisfied.'
        nfev: 4
        njev: 4
  optimality: 2.4369860459044074e-09
      status: 1
     success: True
           x: array([2.9994946])
...