计算一次,在Python类中使用多次

2024-09-29 23:17:48 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图定义一个类,在这个类中,许多变量的函数都得到了优化。通常我要处理500-1000个变量。在这个类中,我需要将函数及其导数传递给scipy中的minimize,以找到最小化这个函数的x0。你知道吗

下面是这个概念的一个简单的工作示例,它工作得很好。但正如您所见,函数(f)及其导数(df)都依赖于另一个函数g(在本例中,它看起来很简单,可以用另一种方式编写,但实际函数要复杂得多)。你知道吗

我想知道是否可以在每次迭代中只计算一次g,然后在类中使用该值。考虑到fdfminimize中被多次更新,因此在每个步骤g也应该重新评估。你知道吗

谢谢!你知道吗

from scipy.optimize import minimize

class Minimization(object):
    '''A class to optimizae a function'''

    def __init__(self,x,y):
        self.x = x
        self.y = y
        self.p = np.array([x,y])

    def g(self,x,y):
        return x-y

    def f(self,p):
        return (self.g(*p) - 1)**2

    def df(self,p):
        fprime = 2*(self.g(*p) - 1)
        return np.array([fprime,-fprime])

    def optimize(self):
        P1 = minimize(fun=self.f, x0=self.p, args=(), method='Newton-CG',jac=self.df)
        return P1

    m = Minimization(2,4)
    m.optimize()
     #fun: 0.0
    # jac: array([ 0., -0.])
 #message: 'Optimization terminated successfully.'
  #  nfev: 3
   # nhev: 0
    # nit: 2
    #njev: 6
  #status: 0
 #success: True
  #     x: array([ 3.5,  2.5])

Tags: 函数selfdfreturndefnpscipyarray
3条回答

你想要的是所谓的“记忆化”。当函数g计算一个值时,它将结果存储在一个字典中,由参数x,y索引。每次调用g时,它都会检查字典,看它需要的值是否已经存储在那里。如果需要重置值,请清除字典。像这样:

class Minimization(object):
    '''A class to optimizae a function'''

    def __init__(self,x,y):
        self.x = x
        self.y = y
        self.p = np.array([x,y])
        self.cache = {}  # previously computed values of g

    def g(self,x,y):
        cache_index = (x, y)
        if cache_index in self.cache:  # check cache first
            return self.cache[cache_index]
        value = x - y
        self.cache[cache_index] = value  # save for later
        return value

    def f(self,p):
        return (self.g(*p) - 1)**2

    def df(self,p):
        fprime = 2*(self.g(*p) - 1)
        return np.array([fprime,-fprime])

    def optimize(self):
        self.cache.clear()  # Blow the cache
        P1 = minimize(fun=self.f, x0=self.p, args=(), method='Newton-CG',jac=self.df)
        return P1

在没有深入研究代码本身的情况下,下面是一个示例类,演示如何一次计算一个值并避免在每次调用时重新计算它。你也可以把它变成一个财产。你知道吗

class StackOverflow:
     def __init__(self, value=None):
             self._value = value
     def compute_value(self):
             if self._value is None:
                     self._value = 100  # Compute value here
             return self._value

为了补充Paul的回答,您可以定义一个类聚合类似缓存的方法,然后(重新)使用这些方法作为装饰器。你知道吗

import functools as ft #<    used to keep meth-related docstring

class Cache(object):
    def __init__(self):
        self._cache = {}

    @classmethod
    def _property(cls, meth):
        @property
        @ft.wraps(meth)
        def __property(cls):
            meth_name = meth.__name__
            if meth_name not in cls._cache:
                cls._cache[meth_name] = meth(cls)
            return cls._cache[meth_name]
        return __property

    @classmethod
    def _method(cls, meth):
        @ft.wraps(meth)
        def __method(cls, *args, **kwargs):
            meth_key = '{}_{}'.format(meth.__name__, args)# <   considered as string so as avoid unhashable-type errors
            if meth_key not in cls._cache:
                cls._cache[meth_key] = meth(cls, *args, **kwargs)
            return cls._cache[meth_key]
        return __method

然后使用类Cache作为Minimization的祖先,如下所示

import numpy as np
from scipy.optimize import minimize

class Minimization(Cache):#<     Inherits of Cache instead of object
    '''A class to optimizae a function'''

    def __init__(self,x,y):
        super(Minimization,self).__init__()
        self.x0 = x               # I changed the names because as it stands, 
        self.y0 = y               # these attributes are actually used as first guesses
        self.p0 = np.array([x,y]) # for the resolution process

    @Cache._method
    def g(self, x, y):
        return x - y

    #@Cache._method
    def f(self,p):
        return (self.g(*p) - 1)**2

    #@Cache._method
    def df(self,p):
        fprime = 2*(self.g(*p) - 1)
        return np.array([fprime,-fprime])

    @Cache._property
    def optimized(self):#<  - I changed the name into optimized to make it representative of what it is, a property
        return minimize(fun=self.f, x0=self.p0, args=(), method='Newton-CG',jac=self.df)

用例(在Python 2.7.11和3.6.1下测试)

>>> m = Minimization(2,4)
>>> # Take care to clear the cache if optimized is not called for the first time and that you changed one of its "dependencies", doing m._cache.clear().
>>> # something you may want to do is simply removing the @Cache._property decorator 
>>> m.optimized
  status: 0
 success: True
    njev: 6
    nfev: 3
     fun: 0.0
       x: array([ 3.5,  2.5])
 message: 'Optimization terminated successfully.'
    nhev: 0
     jac: array([ 0., -0.])

相关问题 更多 >

    热门问题