ここではパフォーマンスはそれほど重要ではないと思いますが、抵抗することはできません。zip()関数は、両方のベクトル(実際には行列転置の詳細)を完全に再コピーして、「Pythonic」の順序でデータを取得します。ナットとボルトの実装の時間を計ることは興味深いでしょう:
import math
def cosine_similarity(v1,v2):
"compute cosine similarity of v1 to v2: (v1 dot v2)/{||v1||*||v2||)"
sumxx, sumxy, sumyy = 0, 0, 0
for i in range(len(v1)):
x = v1[i]; y = v2[i]
sumxx += x*x
sumyy += y*y
sumxy += x*y
return sumxy/math.sqrt(sumxx*sumyy)
v1,v2 = [3, 45, 7, 2], [2, 54, 13, 15]
print(v1, v2, cosine_similarity(v1,v2))
Output: [3, 45, 7, 2] [2, 54, 13, 15] 0.972284251712
これは、要素を1つずつ抽出するCのようなノイズを通過しますが、配列の一括コピーを行わず、1つのforループで重要なすべての処理を実行し、1つの平方根を使用します。
ETA:print呼び出しを関数に更新しました。(オリジナルは3.3ではなくPython 2.7でした。現在のバージョンはPython 2.7で実行され、from __future__ import print_function
ステートメントを実行しています。)出力はどちらの方法でも同じです。
3.0 GHz Core 2 Duo上のCPYthon 2.7.3:
>>> timeit.timeit("cosine_similarity(v1,v2)",setup="from __main__ import cosine_similarity, v1, v2")
2.4261788514654654
>>> timeit.timeit("cosine_measure(v1,v2)",setup="from __main__ import cosine_measure, v1, v2")
8.794677709375264
したがって、この場合、Pythonを使わない方法の方が約3.6倍高速です。