¿Cómo puedo capturar el valor de retorno con el módulo de Python timeit?

Estoy ejecutando varios algoritmos de aprendizaje automático con sklearn en un bucle for y quiero ver cuánto tarda cada uno de ellos. El problema es que también tengo que devolver un valor y NO quiero tener que ejecutarlo más de una vez porque cada algoritmo toma mucho tiempo. ¿Hay alguna manera de capturar el valor de retorno ‘clf’ usando el módulo timeit de python o uno similar con una función como esta …

def RandomForest(train_input, train_output): clf = ensemble.RandomForestClassifier(n_estimators=10) clf.fit(train_input, train_output) return clf 

Cuando llamo a la función como esta

 t = Timer(lambda : RandomForest(trainX,trainy)) print t.timeit(number=1) 

PD: Tampoco quiero establecer un ‘clf’ global porque es posible que desee realizar multiproceso o multiprocesamiento más adelante.

El problema se reduce a que timeit._template_func no devuelve el valor de retorno de la función:

 def _template_func(setup, func): """Create a timer function. Used if the "statement" is a callable.""" def inner(_it, _timer, _func=func): setup() _t0 = _timer() for _i in _it: _func() _t1 = _timer() return _t1 - _t0 return inner 

Podemos doblar el timeit a nuestra voluntad con un poco de parches de mono:

 import timeit import time def _template_func(setup, func): """Create a timer function. Used if the "statement" is a callable.""" def inner(_it, _timer, _func=func): setup() _t0 = _timer() for _i in _it: retval = _func() _t1 = _timer() return _t1 - _t0, retval return inner timeit._template_func = _template_func def foo(): time.sleep(1) return 42 t = timeit.Timer(foo) print(t.timeit(number=1)) 

devoluciones

 (1.0010340213775635, 42) 

El primer valor es el resultado de timeit (en segundos), el segundo valor es el valor de retorno de la función.

Tenga en cuenta que el parche de mono anterior solo afecta el comportamiento de timeit cuando se pasa una timeit.Timer . Si pasa una instrucción de cadena, entonces tendría que (de manera similar) poner un mono en la cadena timeit.template .

Curiosamente, también estoy aprendiendo a máquina, y tengo un requisito similar 😉

Lo resolví de la siguiente manera, escribiendo una función, que:

  • ejecuta tu función
  • imprime el tiempo de ejecución, junto con el nombre de su función
  • devuelve los resultados

Digamos que quieres tiempo:

 clf = RandomForest(train_input, train_output) 

Entonces hazlo:

 clf = time_fn( RandomForest, train_input, train_output ) 

Stdout mostrará algo como:

 mymodule.RandomForest: 0.421609s 

Código para time_fn:

 import time def time_fn( fn, *args, **kwargs ): start = time.clock() results = fn( *args, **kwargs ) end = time.clock() fn_name = fn.__module__ + "." + fn.__name__ print fn_name + ": " + str(end-start) + "s" return results 

Para Python 3.5 puede anular el valor de timeit.template

 timeit.template = """ def inner(_it, _timer{init}): {setup} _t0 = _timer() for _i in _it: retval = {stmt} _t1 = _timer() return _t1 - _t0, retval """ 

La respuesta de unutbu funciona para Python 3.4 pero no 3.5, ya que la función _template_func parece haber sido eliminada en 3.5

Si lo entiendo bien, después de Python 3.5 puede definir globales en cada instancia de Timer sin tener que definirlos en su bloque de código. No estoy seguro de si tendría los mismos problemas con la paralelización.

Mi enfoque sería algo como:

 clf = ensemble.RandomForestClassifier(n_estimators=10) myGlobals = globals() myGlobals.update({'clf'=clf}) t = Timer(stmt='clf.fit(trainX,trainy)', globals=myGlobals) print(t.timeit(number=1)) print(clf) 

Un enfoque que estoy usando es “agregar” el tiempo de ejecución a los resultados de la función cronometrada. Entonces, escribo un decorador muy simple usando el módulo “tiempo”:

 def timed(func): def func_wrapper(*args, **kwargs): import time s = time.clock() result = func(*args, **kwargs) e = time.clock() return result + (es,) return func_wrapper 

Y luego uso el decorador para la función que quiero medir.