zip関数のパフォーマンス

python の zip関数は for文と組み合わせて使うと、2つのシーケンスに対して同時にループ処理を行うことができるので、とても便利。

しかし、実際に使ってみると、zipするシーケンスのサイズが大きくなると、パフォーマンスがガタ落ちすることがわかった。

実際に動かしてみたスクリプトが以下。

#! /usr/bin/env python
# -*- coding: utf-8 -*-

from progressbar import *
import random

widgets_i = ['index: ', Percentage(),
             ' ', Bar(),
             ' ', ETA()]
widgets_z = ['zip: ', Percentage(),
             ' ', Bar(),
             ' ', ETA()]

for n in [10**5, 10**6, 2*10**6, 3*10**6, 5*10**6]:
        print '*** data size = %d ***' %(n)

        data1 = tuple([random.random() for i in range(n)])
        data2 = tuple([random.random() for i in range(n)])
        data3 = tuple([random.random() for i in range(n)])

        #print '--- index ---'
        val_i = 0
        pbar = ProgressBar(widgets=widgets_i, maxval=n).start()
        for i in range(n):
                val_i += (data1[i]+data2[i]+data3[i])/3
                pbar.update(i+1)
        pbar.finish()

        #print '--- zip ---'
        val_z = 0
        pbar = ProgressBar(widgets=widgets_z, maxval=n).start()
        for (i,j,k) in zip(data1,data2,data3):
                val_z += (i+j+k)/3
                pbar.update(i+1)
        pbar.finish()

        print 'index res = %f, zip res = %f, diff = %f'%(val_i/n, val_z/n, (val_i-val_z)/n)

実行結果は以下の通り。

$ python ./zip_progress.py
*** data size = 100000 ***
index: 100% |##########################################| Time: 0:00:00
zip: 100% |############################################| Time: 0:00:00
index res = 0.499342, zip res = 0.499342, diff = 0.000000
*** data size = 1000000 ***
index: 100% |##########################################| Time: 0:00:03
zip: 100% |############################################| Time: 0:00:05
index res = 0.500120, zip res = 0.500120, diff = 0.000000
*** data size = 2000000 ***
index: 100% |##########################################| Time: 0:00:06
zip: 100% |############################################| Time: 0:00:17
index res = 0.500008, zip res = 0.500008, diff = 0.000000
*** data size = 3000000 ***
index: 100% |##########################################| Time: 0:00:09
zip: 100% |############################################| Time: 0:00:33
index res = 0.500110, zip res = 0.500110, diff = 0.000000
*** data size = 5000000 ***
index: 100% |##########################################| Time: 0:00:16
zip: 100% |############################################| Time: 0:01:18
index res = 0.500025, zip res = 0.500025, diff = 0.000000
  • 計算結果は、indexを使ったループもzip関数でのループも同じ。
  • n=10^5 では差がない。
  • n=10^6 を超えても、indexでのループは要素数に比例した実行時間となる。
  • 一方、n=10^6 を超えたところから、zip関数のパフォーマンスが落ちる。
  • 実行環境のメモリサイズなどで、ボトルネックとなるシーケンスサイズは異なる可能性はあるが、予め大きなデータを扱うことがわかっている場合は、注意する必要がありそう。

言語仕様上のお話なのかは、ググってみたけれどわからず、、、

コメントをどうぞ

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*


次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <img localsrc="" alt="">