Как я могу захватить возвращаемое значение с помощью модуля 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
и затем я использую декоратор для функции, которую я хочу время.