LoginSignup
3
3

itertoolsで多重ループを回避してみる

Last updated at Posted at 2018-12-20

なにをしたいのか

多重forループは実行速度を低下させる原因になるので、itertoolsでこれを回避し、速度の比較をしてみる。
(おまけ:numpyのbroadcastを全力で使ってfor文に対抗する)

方法

  • 2重のforループ、3重のforループ、4重のforループのそれぞれと、itertools.productで1重にした場合とを比較する。
  • 0から99の数字を総当たりで掛け合わせて、これらの合計を計算する。
  • 一応resultとして検算しておきます。

結果

うわっ…私の実行速度、遅すぎ…?
itertoolsの方が処理が遅いんですがなんででしょうか。

--- double_for ---
result 24502500
time : 0.000659942626953125
--- double_product ---
result 24502500
time : 0.0007491111755371094

--- triple_for ---
result 121287375000
time : 0.08507108688354492
--- triple_product ---
result 121287375000
time : 0.10134720802307129

--- quadruple_for ---
result 600372506250000
time : 11.622879981994629
--- quadruple_product ---
result 600372506250000
time : 13.198912858963013

実行したスクリプト

nested_loop.py
from itertools import product
import time


base_list = list(range(100))


def double_for():
    result = 0
    for i in base_list:
        for j in base_list:
            result += i * j
    print("result", result)


def double_product():
    result = 0
    pools = product(base_list, base_list)
    for i, j in pools:
        result += i * j
    print("result", result)


def triple_for():
    result = 0
    for i in base_list:
        for j in base_list:
            for k in base_list:
                result += i * j * k
    print("result", result)


def triple_product():
    result = 0
    pools = product(base_list, base_list, base_list)
    for i, j, k in pools:
        result += i * j * k
    print("result", result)


def quadruple_for():
    result = 0
    for i in base_list:
        for j in base_list:
            for k in base_list:
                for l in base_list:
                    result += i * j * k * l
    print("result", result)


def quadruple_product():
    result = 0
    pools = product(base_list, base_list, base_list, base_list)
    for i, j, k, l in pools:
        result += i * j * k * l
    print("result", result)


if __name__ == '__main__':
    print("-" * 3, "double_for", "-" * 3)
    t = time.time()
    double_for()
    print("time : ", time.time() - t)

    print("-" * 3, "double_product", "-" * 3)
    t = time.time()
    double_product()
    print("time : ", time.time() - t)

    print("-" * 3, "triple_for", "-" * 3)
    t = time.time()
    triple_for()
    print("time : ", time.time() - t)

    print("-" * 3, "triple_product", "-" * 3)
    t = time.time()
    triple_product()
    print("time : ", time.time() - t)

    print("-" * 3, "quadruple_for", "-" * 3)
    t = time.time()
    quadruple_for()
    print("time : ", time.time() - t)

    print("-" * 3, "quadruple_product", "-" * 3)
    t = time.time()
    quadruple_product()
    print("time : ", time.time() - t)

おまけ(これってnumpyで処理したほうが早いじゃん)

圧倒的ですね。

--- double_for ---
result 24502500
time : 0.0006780624389648438
--- double_numpy ---
result 24502500
time : 0.00026702880859375

--- triple_for ---
result 121287375000
time : 0.09470272064208984
--- triple_numpy ---
result 121287375000
time : 0.005362987518310547

--- quadruple_for ---
result 600372506250000
time : 12.442141771316528
--- quadruple_numpy ---
result 600372506250000
time : 0.5840020179748535

nested_loop_np.py
import numpy as np
import time


base_list = list(range(100))


def double_for():
    result = 0
    for i in base_list:
        for j in base_list:
            result += i * j
    print("result", result)


def double_np():
    a = np.arange(100).reshape(1, 1, 100)
    b = a.T
    result = np.sum(a * b)
    print("result", result)


def triple_for():
    result = 0
    for i in base_list:
        for j in base_list:
            for k in base_list:
                result += i * j * k
    print("result", result)


def triple_np():
    a = np.arange(100).reshape(1, 1, 100)
    b = a.reshape(1, 100, 1)
    c = a.reshape(100, 1, 1)
    result = np.sum(a * b * c)
    print("result", result)


def quadruple_for():
    result = 0
    for i in base_list:
        for j in base_list:
            for k in base_list:
                for l in base_list:
                    result += i * j * k * l
    print("result", result)


def quadruple_np():
    a = np.arange(100).reshape(1, 1, 1, 100)
    b = a.reshape(1, 1, 100, 1)
    c = a.reshape(1, 100, 1, 1)
    d = a.reshape(100, 1, 1, 1)
    result = np.sum(a * b * c * d)
    print("result", result)


if __name__ == '__main__':
    print("-" * 3, "double_for", "-" * 3)
    t = time.time()
    double_for()
    print("time : ", time.time() - t)

    print("-" * 3, "double_numpy", "-" * 3)
    t = time.time()
    double_np()
    print("time : ", time.time() - t)

    print("-" * 3, "triple_for", "-" * 3)
    t = time.time()
    triple_for()
    print("time : ", time.time() - t)

    print("-" * 3, "triple_numpy", "-" * 3)
    t = time.time()
    triple_np()
    print("time : ", time.time() - t)

    print("-" * 3, "quadruple_for", "-" * 3)
    t = time.time()
    quadruple_for()
    print("time : ", time.time() - t)

    print("-" * 3, "quadruple_numpy", "-" * 3)
    t = time.time()
    quadruple_np()
    print("time : ", time.time() - t)

3
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3