Using a Function Defined In a Function

时间:2019-04-16 23:38:17

标签: python numpy scipy

I'm trying to use a function inside a function I already wrote, and it works with list comprehension and partial functions but not with lambda functions.

So my function is:

import numpy as np
from scipy.optimize import minimize
from _functools import partial
from sklearn.metrics import mean_squared_error

arpdau = np.random.randint(0,100,15)

def fitARPDAU(arpdau, max_cohortday, method, par=None):

  valid = {'log', 'power', 'all'}
  if method not in valid:
      raise ValueError("results: method must be one of %r." % valid)

  values = par

  if method == 'log':

    if values == None:
      a = 1
      b = 0
      c = 1
      values = [a, b, c]
      bounds = [(1e-10, None), (1e-10, None), (None, None)]

    def getArpdauFunction(x, values):
      return values[0] * np.log(x + values[1]) + values[2]
  elif method == 'power':

    if values == None:
      a = 1
      b = 0
      c = .5
      d = 0
      values = [a, b, c, d]
      bounds = [(1e-10, None), (None, None), (1e-10, 1), (None, None)]


    def getArpdauFunction(x, values):
      return values[0] * (x + values[1]) ** values[2]+ values[3]

  elif method == 'all':

    log_loss = fitARPDAU(arpdau, max_cohortday, method='log', par=par)
    power_loss = fitARPDAU(arpdau, max_cohortday, method='power', par=par)

    combined_models = [log_loss, power_loss]
    losses = map(lambda x: x[0].fun, combined_models)
    return combined_models[np.argmin(losses)]

  def getLossOptim(values):

    # import ipdb; ipdb.set_trace()
    # arpdau_pred = [getArpdauFunction(x, values) for x in range(max_cohortday)]
    arpdau_pred_1 = map(lambda x: getArpdauFunction(x, values), range(max_cohortday))
    # arpdau_pred_2 = partial(getArpdauFunction, values=values)(range(271))
    return mean_squared_error(arpdau, arpdau_pred_1[:len(arpdau)])

  result = minimize(getLossOptim, values, method='L-BFGS-B', bounds=bounds)

  return result, [getArpdauFunction(x, result.x) for x in range(max_cohortday)], result.x, method, getArpdauFunction

print fitARPDAU(arpdau, 100, method='all', par=None)

Is there any reason in getLossOptim that the partial and list comprehension work, but the lambda function doesn't?

The lambda function returns

NameError: global name 'getArpdauFunction' is not defined

Thanks!


2 个答案:

答案 0 :(得分:2)

This has nothing to do with a function being defined inside of another function. If method is not 'log' or 'power', then getArpdauFunction() is never defined.

You should probably define it for everything, then overload it if method is 'log' or 'power'.

This doesn't have to do with your problem, but you also shouldn't ever use if x == None. Because None is a singleton, it's more efficient and pythonic to use if x is None

答案 1 :(得分:0)

As I said in my comment, your problem has nothing to do with a function being defined inside another function. The reason why you are getting an error is because the function is sometimes undefined; if method is neither 'log' nor 'power', then getArpdauFunction() is never defined.

This is easy to fix. The cleanest method I can see for now is to declare several functions and then dynamically pick one:

def identity(x): return x
def pp(x): return x+1
def mm(x): return x-1

functions = {
  "++": pp,
  "--": mm
}

default_function = identity

print(functions.get("++", default_function)(2)) # 3
print(functions.get("--", default_function)(2)) # 1
print(functions.get("non existing function name", default_function)(2)) # 2

If your functions are very short (as in this example, then you can directly write:

functions = {
  "++": lambda x: x+1,
  "--": lambda x: x-1
}