昨日のエントリ(zip関数のパフォーマンス)にて zip関数を for文と組み合わせて使った場合のパフォーマンスについて問題がありそうという記事をアップした。
せっかくなので、さらに高速化を図るため、map関数を使った場合の比較も行ってみた。
結果としては、range()でインデックスを作って回すループよりもmap関数を使ったほうが、倍ぐらいのパフォーマンスがありそう。
せっかくなのでリスト内包表記にも挑戦してみようかと思ったのだが、複数のシーケンスを同時に回す方法がわからず断念、、、
実際に動かしてみたスクリプトが以下。
#! /usr/bin/env python # -*- coding: utf-8 -*- from progressbar import * import random def startProgressBar(label, maxVal): widgets = ['%s: '%(label), Percentage(), ' ', Bar(), ' ', ETA()] return ProgressBar(widgets=widgets, maxval=maxVal).start() def average(a,b,c): return (a+b+c)/3 for n in [10**5, 10**6, 2*10**6, 5*10**6, 10**7]: 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 '--- zip ---' resZip = [] pbar = startProgressBar('zip',n) for (i,j,k) in zip(data1,data2,data3): resZip.append(average(i,j,k)) #pbar.update(i+1) pbar.finish() #print '--- index ---' resIndex = [] pbar = startProgressBar('index',n) for i in range(n): resIndex.append(average(data1[i],data2[i],data3[i])) #pbar.update(i+1) pbar.finish() #print '--- map ---' pbar = startProgressBar('map',n) resMap = map(average,data1,data2,data3) pbar.finish() if ((sum(resZip)/n == sum(resIndex)/n) and (sum(resIndex)/n == sum(resMap)/n)): print 'OK'
なるべく条件を同じにしたかったため、時間計測は「3つのtupleの平均値リストを作成する」処理に対して行った。
また、プログレスバーの表示にも時間がかかっていたため、これはコメントアウトして計測した。
zip + for | range + for | map | |
---|---|---|---|
10^5 | 0 | 0 | 0 |
10^6 | 3 | 1 | 0 |
2*10^6 | 13 | 2 | 0 |
5*10^6 | 69 | 5 | 2 |
10^7 | 284 | 10 | 4 |
、、、と数字だけでは、よくわからないので、グラフ(赤:zip + for, 緑:range + for, 青:map)にしてみた。