需要帮助理解Python中的函数传递。

4

我正在通过解决一些问题来学习Python,并且需要帮助理解如何传递函数。

假设我想根据今天和昨天的温度预测明天的温度,我已经编写了以下函数:

def predict_temp(temp_today, temp_yest, k1, k2):
    return k1*temp_today + k2*temp_yest

我还编写了一个错误函数,用于将预测温度列表与实际温度进行比较并返回平均绝对误差:

def mean_abs_error(predictions, expected):
    return sum([abs(x - y) for (x,y) in zip(predictions,expected)]) / float(len(predictions))

如果我有一段过去某个时间间隔内每日温度的列表,我可以看到我的预测函数在具有特定k1和k2参数的情况下会表现如何:

>>> past_temps = [41, 35, 37, 42, 48, 30, 39, 42, 33]
>>> pred_temps = [predict_temp(past_temps[i-1],past_temps[i-2],0.5,0.5) for i in xrange(2,len(past_temps))]
>>> print pred_temps
[38.0, 36.0, 39.5, 45.0, 39.0, 34.5, 40.5]
>>> print mean_abs_error(pred_temps, past_temps[2:])
6.5

但是,我该如何设计一个函数来最小化我的预测温度函数的参数 k1 和 k2 呢?考虑到一个错误函数和我的过去温度数据。

具体来说,我想编写一个名为 minimize(args*) 的函数。它需要接收一个预测函数、一个误差函数、一些训练数据,使用某种搜索/优化方法(例如梯度下降)来估计并返回最小化误差的 k1 和 k2 的值。

我不是在询问如何实现优化方法。假设我已经能够这样做了。相反,我只是想知道如何将我的预测和误差函数(以及我的数据)传递给我的 minimize 函数,以及如何告诉我的 minimize 函数它应该对参数 k1 和 k2 进行优化,以便我的 minimize 函数可以自动搜索不同的 k1 和 k2 设置,每次使用这些参数应用于数据并计算误差(就像我手动为 k1=0.5 和 k2=0.5 时所做的那样),然后返回最佳结果。

我希望能够传递这些函数,以便轻松地更换不同的预测和误差函数(除了参数设置之外,还可能有其他区别)。每个预测函数可能具有不同数量的自由参数。

我的 minimize 函数应该像这样,但是我不知道该如何继续:

def minimize(prediction_function, which_args_to_optimize, error_function, data):
    # 1: guess initial parameters
    # 2: apply prediction function with current parameters to data to compute predictions
    # 3: use error function to compute error between predictions and data
    # 4: if stopping criterion is met, return parameters
    # 5: update parameters
    # 6: GOTO 2

编辑:这就是这么简单吗?这没意思。我要回到Java。

更严肃的是,我认为我也被卡住了,不知道如何使用具有不同参数数量的不同预测函数进行调整。如果我将所有自由参数放在一个元组中,我可以保持函数的形式相同,使其易于传递和使用。


如果你只是在询问如何将一个函数作为参数传递给另一个函数,那么这个问题就太长了;) - user3850
是的,我试图在提出一般性问题和给出具体示例之间找到一个好的平衡,以防其他解决方案在上下文中更好。但我惨败了 ;) - Imran
顺便说一句,我认为你的意思是*args,而不是args。 - Nikhil
3个回答

13

这是一个将一个函数传递给另一个函数的示例。 apply_func_to 函数将接受一个函数 f 和一个数字 num 作为参数,并返回 f(num) 的结果。

def my_func(x):
    return x*x

def apply_func_to(f, num):
    return f(num)

>>>apply_func_to(my_func, 2)
4

如果你想要变得聪明一些,你可以使用lambda表达式(也称为匿名函数)。它们允许你在不必单独定义函数的情况下"即时"传递函数。

>>>apply_func_to(lambda x:x*x, 3)
9

希望这可以帮助到你。


2

在Python中,函数传递非常简单,您只需要使用函数名称作为包含函数本身的变量。

def predict(...):
    ...

minimize(predict, ..., mean_abs_error, ...)

关于问题的其余部分:我建议看一下SciPy是如何实现这个模型的。基本上,他们有一个函数leastsq,它最小化残差平方和(我假设您知道什么是最小二乘法;-)。你传递给leastsq的是一个计算残差的函数、参数的初始猜测以及一个任意参数,该参数会传递给你的残差计算函数(闭包),其中包括数据:
# params will be an array of your k's, i.e. [k1, k2]
def residuals(params, measurements, times):
    return predict(params, times) - measurements

leastsq(residuals, initial_parameters, args = (measurements, times))

请注意,SciPy实际上并不关心您如何得出残差。`measurements`数组只是未经修改地传递给您的`residuals`函数。
如果您需要更多信息,我可以查找我最近做过的示例 - 当然,您也可以在网上找到示例,但根据我的经验,它们不太清晰。我编写的特定代码片段将与您的情况相关联。

谢谢提供 SciPy 的信息,我一定会去查看的。 - Imran

1
DavidIl-Bhima所指出的,函数可以像任何其他类型的对象一样传递到其他函数中。当您传递一个函数时,您只需像通常一样调用它即可。有时人们会通过说函数在Python中是“一等公民”来提到这种能力。在稍微详细一些的层次上,您应该将Python中的函数视为一种可调用对象。Python中另一个重要的可调用对象类型是类对象;在这种情况下,调用类对象会创建该对象的实例。这个概念在这里中有详细讨论。
通常情况下,您可能希望利用Python的位置和/或关键字参数功能,如此处所述。这将允许您编写一个通用的最小化器,可以最小化采用不同参数集的预测函数。我写了一个例子——它比我想象中的要复杂(使用生成器!),但它适用于具有任意参数的预测函数。我略过了一些细节,但这应该能让您开始:
def predict(data, k1=None, k2=None):
    """Make the prediction."""
    pass

def expected(data):
    """Expected results from data."""
    pass

def mean_abs_err(pred, exp):
    """Compute mean absolute error."""
    pass

def gen_args(pred_args, args_to_opt):
    """Update prediction function parameters.

    pred_args : a dict to update 
    args_to_opt : a dict of arguments/iterables to apply to pred_args

    This is a generator that updates a number of variables 
    over a given numerical range.  Equivalent to itertools.product.

    """

    base_args = pred_args.copy() #don't modify input

    argnames = args_to_opt.keys()
    argvals = args_to_opt.values()
    result = [[]]
    # Generate the results
    for argv in argvals:
        result = [x+[y] for x in result for y in argv]
    for prod in result:
        base_args.update(zip(argnames, prod))
        yield base_args

def minimize(pred_fn, pred_args, args_to_opt, err_fn, data):
    """Minimize pred_fn(data) over a set of parameters.

    pred_fn : function used to make predictions
    pred_args : dict of keyword arguments to pass to pred_fn
    args_to_opt : a dict of arguments/iterables to apply to pred_args
    err_fn : function used to compute error
    data : data to use in the optimization

    Returns a tuple (error, parameters) of the best set of input parameters.
    """
    results = []
    for new_args in gen_args(pred_args, args_to_opt):
        pred = pred_fn(data, **new_args) # Unpack dictionary
        err = err_fn(pred, expected(data))
        results.append((err, new_args))
    return sorted(results)[0]

const_args = {k1: 1}
opt_args = {k2: range(10)}
data = [] # Whatever data you like.
minimize(predict, const_args, opt_args, mean_abs_err, data)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接