<p>需要意识到的一个重要事实是,您可以使用<a href="https://stackoverflow.com/questions/47624948/calculating-the-outer-product-for-a-sequence-of-numpy-ndarrays">broadcasting to solve this problem efficiently</a>。所以对于2D的情况你可以</p>
<pre><code>d1, d2 = (3, 4)
A = numpy.sqrt(numpy.arange(d1)[:, None] * numpy.arange(d2)[None, :])
# array([[0. , 0. , 0. , 0. ],
# [0. , 1. , 1.41421356, 1.73205081],
# [0. , 1.41421356, 2. , 2.44948974]])
</code></pre>
<p>一旦您对使用广播来做这些外部产品(或总和,或比较等)感到满意,我们就可以尝试解决nD的情况。你知道吗</p>
<p>查看上面代码的输入数组,我们发现它们有形状</p>
<pre><code>(d1, 1)
( 1, d2)
</code></pre>
<p>所以要在nD中实现这一点,我们需要找到一种方法,它采用线性索引数组,并自动创建形状数组</p>
<pre><code>(d1, 1, 1, ...)
( 1, d2, 1, ...)
( 1, 1, d3, ...)
</code></pre>
<p>Numpy提供了这样一个函数:<code>numpy.meshgrid(..., sparse=True)</code></p>
<pre><code>numpy.meshgrid(numpy.arange(3), numpy.arange(4), sparse=True)
</code></pre>
<p>知道了这一点,我们就可以把它放在一行:</p>
<pre><code>D = (3, 4, 5)
numpy.sqrt(numpy.prod(numpy.meshgrid(*[numpy.arange(d) for d in D], sparse=True, indexing='ij')))
# array([[[0. , 0. , 0. , 0. , 0. ],
# [0. , 0. , 0. , 0. , 0. ],
# [0. , 0. , 0. , 0. , 0. ]],
#
# [[0. , 0. , 0. , 0. , 0. ],
# [0. , 1. , 1.41421356, 1.73205081, 2. ],
# [0. , 1.41421356, 2. , 2.44948974, 2.82842712]],
#
# [[0. , 0. , 0. , 0. , 0. ],
# [0. , 1.41421356, 2. , 2.44948974, 2.82842712],
# [0. , 2. , 2.82842712, 3.46410162, 4. ]],
#
# [[0. , 0. , 0. , 0. , 0. ],
# [0. , 1.73205081, 2.44948974, 3. , 3.46410162],
# [0. , 2.44948974, 3.46410162, 4.24264069, 4.89897949]]])
</code></pre>
<h2>绩效评估</h2>
<p>为了评估这三种解决方案的性能,让我们计算几个不同张量大小的速度:</p>
<pre><code>D=(2,3,4,5)
%timeit np.fromfunction(function=myfunc2, shape=D)
# 501 µs ± 9.34 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit np.fromfunction(function=creation_function, shape=D)
# 24.2 µs ± 455 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit numpy.sqrt(numpy.prod(numpy.meshgrid(*[numpy.arange(d) for d in D], sparse=True, indexing='ij')))
# 30.9 µs ± 1.02 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
D=(20,30,40,50)
%timeit np.fromfunction(function=myfunc2, shape=D)
# 4.64 s ± 36.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit np.fromfunction(function=creation_function, shape=D)
# 36.7 ms ± 1.17 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit numpy.sqrt(numpy.prod(numpy.meshgrid(*[numpy.arange(d) for d in D], sparse=True, indexing='ij')))
# 9 ms ± 237 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
D=(200,30,40,50)
%timeit np.fromfunction(function=myfunc2, shape=D)
# never completed
%timeit np.fromfunction(function=creation_function, shape=D)
# 508 ms ± 7.41 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit numpy.sqrt(numpy.prod(numpy.meshgrid(*[numpy.arange(d) for d in D], sparse=True, indexing='ij')))
# 88.1 ms ± 1.63 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
D=(200,300,40,50)
%timeit np.fromfunction(function=myfunc2, shape=D)
# never completed
%timeit np.fromfunction(function=creation_function, shape=D)
# 5.8 s ± 565 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit numpy.sqrt(numpy.prod(numpy.meshgrid(*[numpy.arange(d) for d in D], sparse=True, indexing='ij')))
# 1.29 s ± 15.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
</code></pre>