Нужна помощь в понимании передачи функций в Python
Я пытаюсь научить себя 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 моей функции pred_temp с учетом функции ошибок и моих данных past_temps?
В частности, я хотел бы написать функцию минимизации (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.
Что касается более серьезного замечания, я думаю, что я также зацикливался на том, как использовать разные функции прогнозирования с разным количеством параметров для настройки. Если я просто возьму все свободные параметры в виде одного кортежа, я смогу сохранить форму функции такой же, чтобы ее было легко передавать и использовать.
Ответов (3)3
Вот пример того, как передать функцию другой функции. 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
Если вы хотите быть умным, вы можете использовать лямбда (также анонимные функции). Они позволяют передавать функции «на лету» без необходимости определять их отдельно.
>>>apply_func_to(lambda x:x*x, 3)
9
Надеюсь это поможет.
Как отмечают Дэвид и Ил-Бхима , функции могут передаваться другим функциям, как и любой другой тип объекта. Когда вы передаете функцию, вы просто вызываете ее, как обычно. Иногда люди ссылаются на эту способность, говоря, что функции в 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)
Передача функций в 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
функцию.
Я могу посмотреть пример, который я сделал недавно, если вам нужна дополнительная информация - или, конечно, вы можете найти примеры в Интернете, но, по моему опыту, они не так ясны. Конкретный фрагмент кода, который я написал, хорошо подошел бы вашему сценарию.