首页 > 解决方案 > 有效地将相同的输入映射到多个函数

问题描述

我正在使用自动构建的大型 ODE 系统。我有一个state长度数组n,并且同样数量的微分方程也存储在一个数组中。这里有 2 个,但在实际系统中,会超过 100 个。微分方程构造为一个类并通过 调用__call__,或者,创建 ODE 并使用 调用functools partial。我需要将完全相同的state时间和时间发送t到数组中的每个微分函数并填充导数状态向量dstate。我想知道最干净、最pythonic,最重要的是,最快的方法是什么。

import numpy as np
from scipy import integrate
import pandas as pd

class F1:
    def __init__(self):
        pass
    def __call__(self, state):
        return 2 - state[0]**2 * state[1]

class F2:
    def __init__(self):
        pass
    def __call__(self, state):
        return 3 - state[1]*state[0]

fs = np.array([F1(), F2()])
state0 = np.ones(2)*4

def change(t, state):
    """
    This is the function I would like to change for something better!

    Ideally there would be something like: dstate = map(input_to_apply, list_of_functions)
    """
    dstate = np.zeros(2)
    for i,f in enumerate(fs):
        dstate[i] = f(state = state)
    return dstate

sol = integrate.solve_ivp(fun = change, t_span = (0, 15), y0 = state0)
res = pd.DataFrame(sol.y.T, columns = ['A', 'B'])
res.index = sol.t
ax = res.plot()

标签: arrayspython-3.xnumpyscipyode

解决方案


至于编码,您所做的工作并没有(IMO)显着改进。您可以替换单行循环:

def change(t, state):
    return np.array([f(state=state) for f in fs])

至于效率,请查看在 Python 中按数组索引调用函数。您可以做的最好的事情是将功能捆绑在一起。在您的示例中:

class F_list:
    def __init__(self):
        pass
    def __call__(self, state):
        return 2 - state[0]**2 * state[1], 3 - state[1]*state[0] 
    def change(self, t, state):
        return self(state)

F = F_list()
sol = integrate.solve_ivp(fun = F.change, t_span = (0, 15), y0 = state0)

另请注意,使用deforlambda总是比 快__call__,如果你想要一个类并且除非你对实例有特定需求,你可以使用classmethod装饰器来避免不必要的实例


推荐阅读