兩個n維向量u=[u1,u2,...un]
和v=[v1,v2,...,vn]
的點積由u1*v1 + u2*v2 + ... + un*vn
給出。Python中的優化點積
posted yesterdayposted yesterday這個問題鼓勵我找到使用標準庫,沒有第三方模塊或C/Fortran/C++調用的Python中計算點積的最快方法。
我定時了四種不同的方法;到目前爲止最快似乎是sum(starmap(mul,izip(v1,v2)))
(其中starmap
和izip
來自itertools
模塊)。
對於下面提供的代碼,這些都是經過時間(以秒爲一次百萬運行):
d0: 12.01215
d1: 11.76151
d2: 12.54092
d3: 09.58523
你能想到的一個更快的方法來做到這一點?
import timeit # module with timing subroutines
import random # module to generate random numnbers
from itertools import imap,starmap,izip
from operator import mul
def v(N=50,min=-10,max=10):
"""Generates a random vector (in an array) of dimension N; the
values are integers in the range [min,max]."""
out = []
for k in range(N):
out.append(random.randint(min,max))
return out
def check(v1,v2):
if len(v1)!=len(v2):
raise ValueError,"the lenght of both arrays must be the same"
pass
def d0(v1,v2):
"""
d0 is Nominal approach:
multiply/add in a loop
"""
check(v1,v2)
out = 0
for k in range(len(v1)):
out += v1[k] * v2[k]
return out
def d1(v1,v2):
"""
d1 uses an imap (from itertools)
"""
check(v1,v2)
return sum(imap(mul,v1,v2))
def d2(v1,v2):
"""
d2 uses a conventional map
"""
check(v1,v2)
return sum(map(mul,v1,v2))
def d3(v1,v2):
"""
d3 uses a starmap (itertools) to apply the mul operator on an izipped (v1,v2)
"""
check(v1,v2)
return sum(starmap(mul,izip(v1,v2)))
# generate the test vectors
v1 = v()
v2 = v()
if __name__ == '__main__':
# Generate two test vectors of dimension N
t0 = timeit.Timer("d0(v1,v2)","from dot_product import d0,v1,v2")
t1 = timeit.Timer("d1(v1,v2)","from dot_product import d1,v1,v2")
t2 = timeit.Timer("d2(v1,v2)","from dot_product import d2,v1,v2")
t3 = timeit.Timer("d3(v1,v2)","from dot_product import d3,v1,v2")
print "d0 elapsed: ", t0.timeit()
print "d1 elapsed: ", t1.timeit()
print "d2 elapsed: ", t2.timeit()
print "d3 elapsed: ", t3.timeit()
注意,文件的名稱必須是dot_product.py
的腳本運行;我在Mac OS X 10.5.8版上使用了Python 2.5.1。
編輯:
我跑了劇本N = 1000,這是結果(以秒爲一次百萬運行):
d0: 205.35457
d1: 208.13006
d2: 230.07463
d3: 155.29670
我想這是安全的假設,的確,選項三是最快的,選項二是最慢的(提出的四個)。
@Arrieta:您可以通過將'from dot_product'替換爲'__main__'來取消文件被稱爲dot_product.py的要求。 – unutbu 2009-12-01 19:30:02
@unutbu:當然,我只是覺得爲了快速運行而保存帶有該名稱的文件比修改腳本更簡單。謝謝。 – Escualo 2009-12-01 19:35:35
我的結果是: 已過期d0:13.4328830242 已過期d1:9.52215504646 已過期d2:10。1050257683 已過期d3:9.16764998436 務必檢查d1和d3之間的差異是否具有統計顯着性。 – liori 2009-12-01 19:44:22