我试图通过解决我提出的一些问题来教自己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
但是如何设计一个函数来最小化我的predict_temp函数的参数k1和k2给定一个错误函数和我的past_temps数据?
具体来说,我想编写一个函数minim(args *),它采用预测函数,误差函数,一些训练数据,并使用一些搜索/优化方法(例如梯度下降)来估计和返回值k1和k2最小化给定数据的错误?
我不是在问如何实现优化方法。假设我能做到这一点。相反,我只想知道如何将我的预测和错误函数(和我的数据)传递给我的最小化函数,并且如何告诉我的最小化函数它应该优化参数k1和k2 ,这样我的最小化函数可以自动搜索k1和k2的一堆不同设置,每次将这些参数的预测函数应用于数据和计算错误(就像我手动为k1 = 0.5和k2 = 0.5以上)然后返回最佳结果。
我希望能够传递这些功能,以便我可以轻松交换不同的预测和错误功能(不仅仅是参数设置不同)。每个预测函数可能具有不同数量的自由参数。
我的最小化函数应该看起来像这样,但我不知道如何继续:
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了。
更严重的是,我认为我也开始讨论如何使用不同的预测函数来调整不同数量的参数。如果我只将所有自由参数作为一个元组,我可以保持函数的形式相同,以便于传递和使用。
答案 0 :(得分:13)
以下是如何将函数传递给另一个函数的示例。 apply_func_to
会将函数f
和数字num
作为参数并return 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
希望这有帮助。
答案 1 :(得分:2)
使用Python传递函数很简单,只需使用函数名作为包含函数本身的变量。
def predict(...):
...
minimize(predict, ..., mean_abs_error, ...)
关于问题的其余部分:我建议以SciPy implements this作为模型的方式。基本上,它们有一个函数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
函数。
我可以查看我最近做的一个例子,如果你想要更多的信息 - 或者你可以在网上找到例子,当然,但根据我的经验,它们并不是那么清楚。我编写的特定代码与你的场景有很好的关系。
答案 2 :(得分:1)
如David和Il-Bhima所示,函数可以像任何其他类型的对象一样传递到其他函数中。当您传入函数时,您只需像通常那样调用它。人们有时会通过说Python中的函数是 first class 来引用这种能力。稍微详细一点,您应该将Python中的函数视为一种可调用对象。 Python中另一种重要的可调用对象是类对象;在这种情况下,调用类对象会创建该对象的实例。详细讨论了这个概念here。
通常,您可能希望利用Python的位置和/或关键字参数功能,如here所述。这将允许您编写通用 最小化器,可以最小化采用不同参数集的预测函数。我写了一个例子---它比我想要的更复杂(使用生成器!)但它适用于具有任意参数的预测函数。我已经掩盖了一些细节,但这应该让你开始:
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)