Forループでsklearnを使用していくつかの機械学習アルゴリズムを実行していて、それぞれにかかる時間を確認したいと思います。問題は、値を返す必要があり、各アルゴリズムに非常に時間がかかるため、値を複数回実行する必要がないことです。 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」を設定したくありません。
問題は要約すると 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の結果(秒単位)で、2番目の値は関数の戻り値です。
上記のモンキーパッチは、callableがtimeit.Timer
に渡された場合のtimeit
の動作にのみ影響することに注意してください。文字列ステートメントを渡す場合は、(同様に)timeit.template
文字列にモンキーパッチを適用する必要があります。
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
"""
nutbuの答え は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)
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
私が使用しているアプローチは、timed関数の結果に実行時間を「追加」することです。そこで、「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
そして、時間を計りたい関数にデコレータを使用します。