Нужна помощь в понимании передачи функций в Python - PullRequest
4 голосов
/ 23 февраля 2009

Я пытаюсь научить себя 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 моей функцииprept_temp с учетом функции ошибки и моих данных past_temps?

В частности, я хотел бы написать функцию минимизации (аргументы *), которая принимает функцию прогнозирования, функцию ошибки, некоторые обучающие данные и использует некоторый метод поиска / оптимизации (например, градиентный спуск) для оценки и возврата значений. 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

Редактировать: Это так просто ?? Это не весело. Я возвращаюсь на Яву.

Что касается более серьезной ноты, я думаю, что я также был зациклен на том, как использовать различные функции прогнозирования с различным количеством параметров для настройки. Если я просто возьму все свободные параметры в один кортеж, я смогу сохранить форму функции такой же, чтобы ее было легко передавать и использовать.

Ответы [ 3 ]

13 голосов
/ 23 февраля 2009

Вот пример того, как передать функцию в другую функцию. 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

Надеюсь, это поможет.

2 голосов
/ 23 февраля 2009

Передача функции в 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.

Я могу посмотреть пример, который я недавно сделал, если вам нужна дополнительная информация - или вы можете найти примеры в Интернете, конечно, но, по моему опыту, они не так ясны. Конкретный фрагмент кода, который я написал, будет хорошо соответствовать вашему сценарию.

1 голос
/ 23 февраля 2009

Поскольку David и Il-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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...