<p>作为一般的经验法则,尽可能遵循<code>scipy</code>和<code>numpy</code>实现,因为它们是矢量化的,并且比本机Python代码快得多。(主要原因是:在C中实现,矢量化消除了循环的类型检查开销。)</p>
<p>(旁白:我的答案不包括精确性,但我认为同样的原则也适用于精确性和效率。)</p>
<p>作为一点额外的收获,我将提供一些关于如何配置代码以衡量效率的信息。如果您使用的是IPython解释器,那么秘诀就是使用<code>%prun</code>行魔术。</p>
<pre><code>In [1]: import numpy
In [2]: from scipy.spatial import distance
In [3]: c1 = numpy.array((52, 106, 35, 12))
In [4]: c2 = numpy.array((33, 153, 75, 10))
In [5]: %prun distance.euclidean(c1, c2)
35 function calls in 0.000 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 linalg.py:1976(norm)
1 0.000 0.000 0.000 0.000 {built-in method numpy.core.multiarray.dot}
6 0.000 0.000 0.000 0.000 {built-in method numpy.core.multiarray.array}
4 0.000 0.000 0.000 0.000 numeric.py:406(asarray)
1 0.000 0.000 0.000 0.000 distance.py:232(euclidean)
2 0.000 0.000 0.000 0.000 distance.py:152(_validate_vector)
2 0.000 0.000 0.000 0.000 shape_base.py:9(atleast_1d)
1 0.000 0.000 0.000 0.000 misc.py:11(norm)
1 0.000 0.000 0.000 0.000 function_base.py:605(asarray_chkfinite)
2 0.000 0.000 0.000 0.000 numeric.py:476(asanyarray)
1 0.000 0.000 0.000 0.000 {method 'ravel' of 'numpy.ndarray' objects}
1 0.000 0.000 0.000 0.000 linalg.py:111(isComplexType)
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
2 0.000 0.000 0.000 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {built-in method builtins.issubclass}
4 0.000 0.000 0.000 0.000 {built-in method builtins.len}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
2 0.000 0.000 0.000 0.000 {method 'squeeze' of 'numpy.ndarray' objects}
In [6]: %prun numpy.linalg.norm(c1 - c2)
10 function calls in 0.000 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 linalg.py:1976(norm)
1 0.000 0.000 0.000 0.000 {built-in method numpy.core.multiarray.dot}
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 numeric.py:406(asarray)
1 0.000 0.000 0.000 0.000 {method 'ravel' of 'numpy.ndarray' objects}
1 0.000 0.000 0.000 0.000 linalg.py:111(isComplexType)
1 0.000 0.000 0.000 0.000 {built-in method builtins.issubclass}
1 0.000 0.000 0.000 0.000 {built-in method numpy.core.multiarray.array}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
</code></pre>
<p><code>%prun</code>所做的是告诉您一个函数调用需要多长时间才能运行,包括一些跟踪来找出瓶颈可能在哪里。在这种情况下,<code>scipy.spatial.distance.euclidean</code>和<code>numpy.linalg.norm</code>实现都非常快。假设您定义了一个函数<code>dist(vect1, vect2)</code>,那么您可以使用相同的IPython magic调用进行分析。另一个额外的好处是,<code>%prun</code>也可以在Jupyter笔记本中工作,您可以通过简单地将<code>%%prun</code>设为该单元格的第一行来对整个代码单元格(而不仅仅是一个函数)进行<code>%%prun</code>配置。</p>