속도 측정에 편리한 jupyter의 매직 커맨드 %timeit 같은 녀석을 Python으로 자전 구현

할 일



jupyter의 %timeit 같은 사람을 구현합니다.
이것의 반환값을 변수로서 사용하고 싶다.

ipynb
%timeit -r 100 -n 10 test()
-r , -n 이외에도 옵션이 있습니다만, 이번은 이 2개 이외 구현하지 않습니다.

%timeit -r 100 -n 10 test() 란 무엇입니까?


  • test() 를 100회 반복해, 그 중에서 가장 실행 속도의 빠른 값을 돌려준다.
  • 1을 10회 반복하고 평균을 취한다.

  • 즉, 가장 빠른 10개의 평균값을 내고 있습니다.
    (덧붙여서 %%timeit -r 100 -n 10 라고 하면 셀 단위의 처리 속도를 계측할 수 있습니다.)



    표준 라이브러리의 timeit 그럼 괜찮습니까?


  • test() 를 100회 반복해, 그 중에서 가장 실행 속도의 빠른 값을 돌려준다.

  • ↑ 이것을 하는 메소드가 없을 것 같아?
    일단 공부도 겸해 자전으로 실장해 봅니다.

    디렉토리 구성


    .
    ├── utils
    │   ├── speed_test.py
    │   └── __init__.py
    └── main.py
    

    코드



    모듈



    speed_test.py
    import time
    
    
    class Measurer(object):
        def mean_time(self, num=10):
            """
            num回実行した結果の平均を返すデコレータ。
            """
            def outer_wrapper(func):
                def wrapper(*args, **kwargs):
                    fast_time_list = [func(*args, **kwargs) for _ in range(num)]
                    mean = sum(fast_time_list) / len(fast_time_list)
                    return mean
                return wrapper
            return outer_wrapper
    
        def fast_time(self, repeat=10):
            """
            repeat回実行した中で最小値(実行速度の一番早かった値)を返すデコレータ。
            """
            def outer_wrapper(func):
                def wrapper(*args, **kwargs):
                    result_list = [func(*args, **kwargs) for _ in range(repeat)]
                    # print(result_list)
                    min_time = min(result_list)
                    # print(result_list)
                    # print(min_time)
                    return min_time
                return wrapper
            return outer_wrapper
    
        def onece_time(self, func):
            """
            引数に渡された関数の実行速度を返すデコレータ。
            """
            def wrapper(*args, **kwargs):
                # print('test start')
                start_time = time.time()
                func(*args, **kwargs)
                finish_time = time.time()
                elapsed_time = finish_time - start_time
                # print('elapsed_time => {:.10f}sec'.format(elapsed_time))
                # print('test finish')
                return elapsed_time
            return wrapper
    
        def execute(self, func, *args, num, repeat):
            """
            1. repeat回実行した中で最も速度の早かった値を算出。
            2. 1をnum回繰り返し、num個の最速の値の平均値を返す。
            """
            @self.mean_time(num=num)
            @self.fast_time(repeat=repeat)
            @self.onece_time
            def _execute(fn, *args):
                return fn(*args)
            return _execute(func, *args)
    

    실행 파일



    main.py
    from utils import speed_test
    
    
    # 計測用の関数を定義
    def test(max_count):
        count = 0
        for _ in range(max_count):
            count += 1
    
    
    def main():
        max_count = 100
        num = 10
        repeat = 100
    
        measurer = speed_test.Measurer()
        # 第2引数以降、可変長で複数の引数を渡せる
        result = measurer.execute(test, max_count, num=num, repeat=repeat)
        print('result -> {:.12f}'.format(result))
    
    
    if __name__ == '__main__':
        main()
    

    시각화할 패턴



    반환값을 취할 수 있으므로 가시화해 비교도 간단하게.

    py:main.py
    import pandas as pd
    import matplotlib.pyplot as plt
    from IPython.display import display
    
    from utils import speed_test
    
    
    def test1(str_list):
        """
        文字列リストの全ての要素を数値変換する①
        """
        int_list = [int(i) for i in str_list]
    
    
    def test2(str_list):
        """
        文字列リストの全ての要素を数値変換する②
        """
        int_list = list(map(int, str_list))
    
    
    def main():
        num = 10
        repeat = 100
    
        # 文字列リストを生成
        str_list = [str(i) for i in range(10000)]
        # ['0', '1', '2', ... '9997', '9998', '9999']
    
        measurer = speed_test.Measurer()
        # 第2引数以降、可変長で複数の引数を渡せる
        result1 = measurer.execute(test1, str_list, num=num, repeat=repeat)
        result2 = measurer.execute(test2, str_list, num=num, repeat=repeat)
        # print('result -> {:.12f}'.format(result))
    
        df = pd.DataFrame({
            'for': [result1],
            'map': [result2]
        })
    
        display(df)
    
        x = ['for', 'map']
        y = [result1, result2]
        plt.bar(x, y)
        plt.show
    
    
    if __name__ == '__main__':
        main()
    
    for         map
    0.001499    0.00109
    

    좋은 웹페이지 즐겨찾기