<p><strong>TL;DR</strong>上面的第二个代码只在点的维数上循环(对于3D点,循环次数是for循环的3倍),因此循环次数不多。上面第二个代码的真正加速是它更好地利用Numpy的能力,以避免在找到点之间的差异时创建一些额外的矩阵。这减少了内存使用和计算工作量。在</p>
<p><strong>更长的解释</strong>
我认为<code>calcDistanceMatrixFastEuclidean2</code>函数的循环可能在欺骗你。它只是在点的维数上循环。对于1D点,循环只执行一次,对于2D,执行两次,对于3D,执行三次。这真的不是什么循环。在</p>
<p>让我们分析一下代码,看看为什么其中一个比另一个快。<code>calcDistanceMatrixFastEuclidean</code>我将调用<code>fast1</code>,而{<cd1>}将是{<cd5>}。在</p>
<p><code>fast1</code>是基于Matlab的做事方式的,<code>repmap</code>函数就证明了这一点。在本例中,<code>repmap</code>函数创建了一个数组,它只是反复重复的原始数据。但是,如果查看函数的代码,则效率非常低。它使用许多Numpy函数(3<code>reshape</code>s和2<code>repeat</code>s)来实现这一点。<code>repeat</code>函数还用于创建一个数组,该数组包含每个数据项重复多次的原始数据。如果我们的输入数据是<code>[1,2,3]</code>,那么我们将从<code>[1,1,1,2,2,2,3,3,3]</code>中减去{<cd13>}。Numpy不得不在运行Numpy的C代码之间创建大量额外的矩阵,这是可以避免的。在</p>
<p><code>fast2</code>使用了更多Numpy的重担,而没有在Numpy调用之间创建那么多的矩阵。<code>fast2</code>遍历点的每个维度,进行减法,并保持每个维度之间的平方差的累计。只有到最后才算平方根。到目前为止,这听起来不像<code>fast1</code>那么有效,但是<code>fast2</code>通过使用Numpy的索引避免了<code>repmat</code>的工作。为了简单起见,让我们看一下1D案例。<code>fast2</code>生成数据的1D数组,并从2D(nx1)数组中减去它。这将在每个点和所有其他点之间创建差分矩阵,而不必使用<code>repmat</code>和<code>repeat</code>,从而避免了创建大量额外的数组。这就是我认为真正的速度差异所在。<code>fast1</code>在矩阵之间创建了很多额外的元素(它们的创建是非常昂贵的计算)来发现点之间的差异,而{<cd5>}则更好地利用Numpy的能力来避免这些差异。在</p>
<p>{cd5>稍微快一点</p>
<pre><code>def calcDistanceMatrixFastEuclidean3(nDimPoints):
nDimPoints = array(nDimPoints)
n,m = nDimPoints.shape
data = nDimPoints[:,0]
delta = (data - data[:,newaxis])**2
for d in xrange(1,m):
data = nDimPoints[:,d]
delta += (data - data[:,newaxis])**2
return sqrt(delta)
</code></pre>
<p>不同的是,我们不再创建delta作为零矩阵。在</p>