python - 生成具有不同参数的python函数

标签 python function numpy scipy

背景

我有一个函数,它接受多个参数并返回一个错误度量,然后我想将其最小化(使用 scipy.optimize.leastsq,但现在这不是重点)。

作为玩具示例,让我们假设我的优化函数采用四个参数 a、b、c、d:

def f(a,b,c,d):
    err = a*b - c*d
    return err

然后优化器需要一个带有签名 func(x, *args) 的函数,其中 x 是参数向量。

也就是说,我的函数目前是这样写的:

def f_opt(x, *args):
    a,b,c,d = x
    err = a*b - c*d
    return err

但是,现在我想做一些实验,在这些实验中我修复了一些参数,同时在优化步骤中保留了一些参数。

我当然可以这样做:

def f_ad_free(x, b, c):
    a, d = x
    return f(a,b,c,d)

但这会很麻烦,因为我有超过 10 个参数,这意味着不同数量的自由参数与固定参数的组合可能会非常大。

第一种使用字典的方法

我的一个解决方案是用关键字参数而不是位置参数编写我的内部函数 f,然后像这样包装解决方案:

def generate(func, all_param, fixed_param):
    param_dict = {k : None for k in all_param}
    free_param = [param for param in all_param if param not in fixed_param]
    def wrapped(x, *args):
        param_dict.update({k : v for k, v in zip(fixed_param, args)})
        param_dict.update({k : v for k, v in zip(free_param, x)})
        return func(**param_dict)
    return wrapped

创建一个修复 'b' 和 'c' 的函数然后变成以下内容:

all_params = ['a','b','c']
f_bc_fixed = generate(f_inner, all_params, ['b', 'c'])
a = 1
b = 2
c = 3
d = 4
f_bc_fixed((a,d), b, c)

提问时间!

我的问题是是否有人能想出更简洁的方法来解决这个问题。由于最终函数将在优化步骤中运行,我不能接受每个函数调用的开销太大。 生成优化函数所需的时间无关紧要。

最佳答案

我可以想出几种方法来避免像上面那样使用闭包,但在进行一些测试后,我不确定这两种方法是否会更快。一种方法可能是跳过包装器,只编写一个接受

  1. 向量
  2. 免费名称列表
  3. 字典将名称映射到值。

然后做一些与你上面做的非常相似的事情,但是在函数本身:

def f(free_vals, free_names, params):
    params.update(zip(free_names, free_vals))
    err = params['a'] * params['b'] - params['c'] * params['d']
    return err

对于多次使用变量名的代码,将 vars 设置为本地变量,例如

a = params['a']
b = params['b']

等等。这可能看起来很麻烦,但它的优点是使一切都明确,避免了可能使闭包变慢的 namespace 搜索。

然后通过 args 参数将自由名称列表和固定参数字典传递给 optimize.leastsq。 (请注意,params 字典是可变的,这意味着理论上可能存在副作用;但在这种情况下,这无关紧要,因为只有自由参数被 update< 覆盖,所以为了速度我省略了复制步骤。)

这种方法的主要缺点是它将一些复杂性转移到了对 optimize.leastsq 的调用中,并且降低了代码的可重用性。第二种方法避免了这些问题,尽管它可能没有那么快:使用可调用类。

class OptWrapper(object):
    def __init__(self, func, free_names, **fixed_params):
        self.func = func
        self.free_names = free_names
        self.params = fixed_params

    def __call__(self, x, *args):
        self.params.update(zip(self.free_names, x))
        return self.func(**self.params)

你可以看到我简化了__init__的参数结构;固定参数在这里作为关键字参数传递,用户必须确保 free_namesfixed_pa​​rams 没有重叠的名称。我认为简单性值得权衡,但您可以像在包装代码中所做的那样轻松地强制执行两者之间的分离。

我最喜欢第二种方法;它具有基于闭包的方法的灵 active ,但我发现它更具可读性。所有名称都在(或可以通过)本地命名空间中,我认为这会加快速度——但经过一些测试后,我认为有理由相信闭包方法仍会比这更快;访问 __call__ 方法似乎每次调用都会增加大约 100 ns 的开销。如果性能是一个真正的问题,我强烈建议进行测试。

关于python - 生成具有不同参数的python函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18735999/

相关文章:

python - 简化循环内的 numpy.dot

python - 为什么形状是空的?

python - 如何将 Counter 对象转换为可用的对列表?

python - 制作具有精确长度的 sin 'arc'

sql - 雪花函数中的 DDL 语句

c - 了解如何将 main(){} 中出现的一段代码转换为 C 中的一个或多个函数

python - 获取 np.linalg.svd 的奇异值作为矩阵

python - 如果一个较小字典的所有值都存在于一个较大字典中,则返回 true

Python:这个类定义有什么问题(缩进错误)

c++ - 如何从包含的类中执行函数