У меня есть следующее приложение, которое оптимизирует следующий 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))
Вам следует попытаться векторизовать суммы и вызовы в подпрограмму интерполяции. Например, например:
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()
который, кажется, дает ускорение ~ 10x. Вы также можете заменить списки knots
и dfs
в Market
массивами аналогичным образом.
Причина, по которой калибровка re- требует времени, заключается в том, что leastsq
должен снова проверить, что она действительно находится на локальном минимуме. Это требует численного дифференцирования целевой функции, что требует времени, так как у вас много свободных переменных. Проблема оптимизации довольно проста, поэтому она сходится в несколько шагов, что означает, что проверка минимума занимает почти столько же времени, сколько и решение проблемы.
@pv ответ, скорее всего, прав, но этот ответ показывает простой способ убедиться, и показать, есть ли что-нибудь еще, что вы могли бы сделать.