Улучшить скорость задачи оптимизации - PullRequest
1 голос
/ 08 июня 2011

У меня есть следующее приложение, которое оптимизирует следующий pb. Код работает, но я нашел его немного медленным. Есть идеи по улучшению производительности (без написания кода на c), которые можно сделать, чтобы лучше использовать python, numpy и scipy? Мне кажется, что функция интерполяции является основной трудоемкой частью.

from scipy.optimize import leastsq
from scipy.interpolate import interp1d
import timeit


class Bond(object):
  def __init__(self, years, cpn):
    self.years = years 
    self.coupon = cpn
    self.cashflows = [(0.0, -1.0)]
    self.cashflows.extend([(float(i),self.coupon) for i in range(1,self.years)])
    self.cashflows.append((float(self.years), 1.0 + self.coupon))

  def pv(self, market):
    return sum([cf[1] * market.df(cf[0]) for cf in self.cashflows])

class Market(object):
  def __init__(self, instruments):
    self.instruments = sorted(
        instruments, key=lambda instrument : instrument.cashflows[-1][0])
    self.knots = [0.0]
    self.knots.extend([inst.cashflows[-1][0] for inst in self.instruments])
    self.dfs = [1.0]
    self.dfs.extend([1.0] * len(self.instruments))
    self.interp = interp1d(self.knots, self.dfs)

  def df(self, day):
    return self.interp(day)

  def calibrate(self):
    leastsq(self.__target, self.dfs[1:])

  def __target(self, x):
    self.dfs[1:] = x
    self.interp = interp1d(self.knots, self.dfs)
    return [bond.pv(self) for bond in self.instruments]


def main():
  instruments = [Bond(i, 0.02) for i in xrange(1, numberOfInstruments + 1)]
  market = Market(instruments)
  market.calibrate()
  print('CALIBRATED')

numberOfTimes = 10
numberOfInstruments = 50
print('%.2f' % float(timeit.timeit(main, number=numberOfTimes)/numberOfTimes))

Ответы [ 2 ]

2 голосов
/ 08 июня 2011

Вы должны попытаться векторизовать суммы и обращения к процедуре интерполяции.Например, вот так:

import numpy as np

class Bond(object):
  def __init__(self, years, cpn):
    self.years = years
    self.coupon = cpn

    self.cashflows = np.zeros((self.years + 1, 2))
    self.cashflows[:,0] = np.arange(self.years + 1)
    self.cashflows[:,1] = self.coupon
    self.cashflows[0,:] = 0, -1
    self.cashflows[-1,:] = self.years, 1.0 + self.coupon

  def pv(self, market):
    return (self.cashflows[:,1] * market.df(self.cashflows[:,0])).sum()

, что, похоже, дает ~ 10-кратное ускорение.Вы также можете заменить списки knots и dfs в Market массивами аналогичным образом.

Причина, по которой повторная калибровка занимает много времени, заключается в том, что leastsq должен еще раз проверить, чтоэто действительно сидит на местном минимуме.Это требует численного дифференцирования целевой функции, что требует времени, так как у вас есть много свободных переменных.Задача оптимизации довольно проста, поэтому она сходится за несколько шагов, что означает, что проверка минимума занимает почти столько же времени, сколько и решение проблемы.

0 голосов
/ 02 августа 2011

@ pv ответ, скорее всего, правильный, но этот ответ показывает простой способ убедиться и показать, есть ли что-то еще, что вы могли бы сделать.

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