Как я могу захватить возвращаемое значение с помощью модуля Python timeit?
Im работает несколько алгоритмов машинного обучения со sklearn в цикле for и хочет увидеть, как долго каждый из них занимает. Проблема в том, что мне также нужно вернуть значение и не хочу запускать его больше одного раза, потому что каждый алгоритм занимает так много времени. Есть ли способ захватить возвращаемое значение "clf", используя модуль timeit python или аналогичный с такой функцией...
def RandomForest(train_input, train_output):
clf = ensemble.RandomForestClassifier(n_estimators=10)
clf.fit(train_input, train_output)
return clf
когда я вызываю функцию, как это
t = Timer(lambda : RandomForest(trainX,trainy))
print t.timeit(number=1)
P. S. Я тоже не хочу чтобы установить глобальный "clf", потому что я могу захотеть сделать многопоточность или многопроцессорность позже.
5 ответов
проблема сводится к timeit._template_func не возвращает возвращаемое значение функции:
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
мы можем согнуть timeit по нашей воле с обезьяньей заплаткой:
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))
возвращает
(1.0010340213775635, 42)
первое значение-результат timeit (в секундах), второе значение-возвращаемое значение функции.
обратите внимание, что обезьяна-патч выше влияет только на поведение timeit когда вызвать is прошло timeit.Timer. Если вы передадите строковый оператор, вам придется (аналогично) исправлять timeit.template строку.
для Python 3.5 вы можете переопределить значение timeit.шаблон
timeit.template = """
def inner(_it, _timer{init}):
{setup}
_t0 = _timer()
for _i in _it:
retval = {stmt}
_t1 = _timer()
return _t1 - _t0, retval
"""
unutbu это работает для python 3.4, но не 3.5, поскольку функция _template_func, похоже, была удалена в 3.5
как ни странно, я также занимаюсь машинным обучением и имею аналогичное требование; -)
Я решил это следующим образом, написав функцию, которая:
- выполняет функции
- печатает время работы вместе с именем вашей функции
- возвращает результаты
допустим, вы хотите время:
clf = RandomForest(train_input, train_output)
затем выполните:
clf = time_fn( RandomForest, train_input, train_output )
Stdout покажет что-то например:
mymodule.RandomForest: 0.421609s
код для 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
Если я хорошо понимаю, после python 3.5 вы можете определять глобалы в каждом экземпляре таймера без необходимости определять их в своем блоке кода. Я не уверен, что у него будут те же проблемы с распараллеливанием.
мой подход будет что-то вроде:
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)
подход, который я использую, - это "добавить" время работы к результатам функции timed. Итак, я пишу очень простой декоратор, используя модуль "время":
def timed(func):
def func_wrapper(*args, **kwargs):
import time
s = time.clock()
result = func(*args, **kwargs)
e = time.clock()
return result + (e-s,)
return func_wrapper
и затем я использую декоратор для функции, которую я хочу время.