如何使用Python timeit模块捕获返回值?

时间:2014-07-17 19:47:02

标签: python python-2.7 scikit-learn timeit

我在for循环中使用sklearn运行了几个机器学习算法,并想看看每个算法需要多长时间。问题是我还需要返回一个值,并且DONT想要多次运行它,因为每个算法都需要很长时间。有没有办法使用python的timeit模块或类似函数捕获返回值'clf'...

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'因为我可能想稍后进行多线程处理或多处理。

9 个答案:

答案 0 :(得分:13)

问题归结为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结果(以秒为单位),第二个值是函数的返回值。

请注意,上面的猴子补丁仅在{em>可调用传递timeit时影响timeit.Timer的行为。如果你传递一个字符串语句,那么你必须(类似地)修补timeit.template字符串。

答案 1 :(得分:7)

有趣的是,我也在做机器学习,并且有类似的要求; - )

我通过写一个函数解决了它:

  • 运行您的功能
  • 打印运行时间以及功能名称
  • 返回结果

假设您想要时间:

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

答案 2 :(得分:7)

对于Python 3.5,您可以覆盖timeit.template

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

unutbu's answer适用于python 3.4但不适用于3.5,因为_template_func函数似乎已在3.5中删除

答案 3 :(得分:2)

如果我理解得很好,在python 3.5之后你可以在每个Timer实例定义全局变量而不必在你的代码块中定义它们。我不确定它是否会出现与并行化相同的问题。

我的方法是:

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)

答案 4 :(得分:1)

截至2020年,在ipython或jupyter笔记本中是

t = %timeit -n1 -r1 -o RandomForest(trainX, trainy)
t.best

答案 5 :(得分:0)

我使用它的方法是"追加"运行时间到定时功能的结果。所以,我使用" time"写了一个非常简单的装饰器。模块:

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

然后我使用装饰器来实现我想要的功能。

答案 6 :(得分:0)

对于Python 3.X,我使用这种方法:

# Redefining default Timer template to make 'timeit' return
#     test's execution timing and the function return value
new_template = """
def inner(_it, _timer{init}):
    {setup}
    _t0 = _timer()
    for _i in _it:
        ret_val = {stmt}
    _t1 = _timer()
    return _t1 - _t0, ret_val
"""
timeit.template = new_template

答案 7 :(得分:0)

在Python 3.5中,globals已添加到timeit,这使开发人员可以定义在其中运行代码的名称空间。在现有的Python名称空间中运行代码可启用以下timeit语法来计时返回值的函数。

import timeit
print(timeit.timeit("output = your_function(your_params)", number=1, globals = globals()))

它以number指定的次数打印运行该功能所花费的时间。在示例中,number参数设置为1。

(0.003316399990580976, 'your_functions ouput')

答案 8 :(得分:0)

如果您不想猴子timeit补丁,可以尝试使用全局列表,如下所示。这也将在python 2.7中工作,该Python 2.7在globals中没有timeit()参数:

from timeit import timeit
import time

# Function to time - plaigiarised from answer above :-)
def foo():
    time.sleep(1)
    return 42

result = []
print timeit('result.append(foo())', setup='from __main__ import result, foo', number=1)
print result[0]

将先打印时间,然后再打印结果。