Python 如何在不使用双for循环的情况下加快矩阵的构造

Python 如何在不使用双for循环的情况下加快矩阵的构造,python,performance,numpy,for-loop,matrix,Python,Performance,Numpy,For Loop,Matrix,我想加速以下双for循环: 我怎么做呢?我的想法是:计算一个包含从0到n-1的所有元素的向量v: 然后构造两个矩阵I和J,一个矩阵的所有行等于v,另一个矩阵的所有列等于v。如果我没弄错的话,那么我可以用 A = twopi * I*J/n 这是正确的吗?如何构建I和J?有更好的方法吗?类似这样的方法: from numpy import outer, pi, arange n = 10 i = arange(n) A = 2 * pi / n * outer(i, i) 外部产品满足您的要

我想加速以下双for循环:

我怎么做呢?我的想法是:计算一个包含从0到n-1的所有元素的向量v:

然后构造两个矩阵I和J,一个矩阵的所有行等于v,另一个矩阵的所有列等于v。如果我没弄错的话,那么我可以用

A = twopi * I*J/n
这是正确的吗?如何构建I和J?有更好的方法吗?

类似这样的方法:

from numpy import outer, pi, arange

n = 10
i = arange(n)
A = 2 * pi / n * outer(i, i)
外部产品满足您的要求

编辑: 测试性能的简单方法如下所示:

from time import time

n = 10000
t = time()
for _ in range(10):
    i = arange(n)
    A = 2 * pi / n * outer(i, i)

t = time() - t
print("Time used [s]", t)

对我来说,这10次重复需要5秒钟,range和arange之间没有显著差异。

你可以使用列表理解:

A = np.array([   
        [twopi*i*j/n for j in range(n)] 
    for i in range(n)])
默认情况下,范围从零开始,因此范围0,n而不是范围是冗余的

In [118]: matrix = np.array([np.arange(n) for _ in range(n)])

In [119]: matrix
Out[119]:
array([[   0,    1,    2, ..., 9997, 9998, 9999],
       [   0,    1,    2, ..., 9997, 9998, 9999],
       [   0,    1,    2, ..., 9997, 9998, 9999],
       ...,
       [   0,    1,    2, ..., 9997, 9998, 9999],
       [   0,    1,    2, ..., 9997, 9998, 9999],
       [   0,    1,    2, ..., 9997, 9998, 9999]])

In [120]: matrix [0,1]
Out[120]: 1

In [121]: for j in range(n): matrix[:,j] *= j

In [122]: matrix
Out[122]:
array([[       0,        1,        4, ..., 99940009, 99960004, 99980001],
       [       0,        1,        4, ..., 99940009, 99960004, 99980001],
       [       0,        1,        4, ..., 99940009, 99960004, 99980001],
       ...,
       [       0,        1,        4, ..., 99940009, 99960004, 99980001],
       [       0,        1,        4, ..., 99940009, 99960004, 99980001],
       [       0,        1,        4, ..., 99940009, 99960004, 99980001]])

In [123]: matrix = matrix/n

In [124]: matrix = matrix * np.pi*2

In [125]: matrix
Out[125]:
array([[0.00000000e+00, 6.28318531e-04, 2.51327412e-03, ...,
        6.27941596e+04, 6.28067228e+04, 6.28192873e+04],
       [0.00000000e+00, 6.28318531e-04, 2.51327412e-03, ...,
        6.27941596e+04, 6.28067228e+04, 6.28192873e+04],
       [0.00000000e+00, 6.28318531e-04, 2.51327412e-03, ...,
        6.27941596e+04, 6.28067228e+04, 6.28192873e+04],
       ...,
       [0.00000000e+00, 6.28318531e-04, 2.51327412e-03, ...,
        6.27941596e+04, 6.28067228e+04, 6.28192873e+04],
       [0.00000000e+00, 6.28318531e-04, 2.51327412e-03, ...,
        6.27941596e+04, 6.28067228e+04, 6.28192873e+04],
       [0.00000000e+00, 6.28318531e-04, 2.51327412e-03, ...,
        6.27941596e+04, 6.28067228e+04, 6.28192873e+04]])
和脚本一样:

matrix = np.array([np.arange(n) for _ in range(n)])
for j in range(n): matrix[:,j] *= j
matrix = matrix/n
matrix = matrix * np.pi*2
答复 您确实可以使用numpy的广播功能

import numpy as np
n = 10000
twopi = 2.0 * np.pi / n
A = np.arange(n) * np.arange(n).reshape(-1, 1) * twopi
第二个np.arange的重塑驱动产品播放

这与调用np.outer as非常相似,即使从时间性能的角度来看也是如此

基准 配置:

import numpy as np
n = 10000
twopi = 2 * np.pi / n
时代:

# List comprehension
A = np.array([   
    [twopi*i*j for j in range(n)] 
for i in range(n)])
# timeit > 10.2 s ± 129 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

# Outer
i = np.arange(n)
A = twopi * np.outer(i, i)
# timeit > 234 ms ± 6.87 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

# Product
A = np.arange(n) * np.arange(n).reshape(-1, 1) * twopi
# timeit > 208 ms ± 41.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
如上所述,外部和产品方法非常相似。
但是列表理解并不是因为它违背了numpy的目的,numpy的目的是使用分布式子任务和(通常)低级优化对数组计算进行矢量化。

谢谢!快速提问:重塑-1,1的含义是什么?在这个特定的例子中,它从1维1万形数组生成,2维1万形数组生成。这就像从行向量生成列向量一样。-1参数表示拟合所有值所需的数量,这里是10000。在其他情况下,作为示例,您可以通过执行_数组将形状8的数组重塑为形状2、2、2的数组。重塑2、2、2。最后一个问题:您是如何生成timeit数字的?你有没有一个链接显示如何做?当然。这是文件:。我个人在笔记本电脑Jupyter中使用它,在我想要测量执行时间的任何单元格的第一行使用魔法命令%%timeit。看起来很酷!看到abenchmark发布到目前为止的一些最佳解决方案将是一件有趣的事情。如果你不想修改你的答案,包括一个,你能告诉我一个现有的答案,这有助于我做到这一点吗?我现在没有时间,对不起。。。但有一件事需要考虑:Numpy的arange实际上在内存中创建了该数组,而内置范围则没有。我只是不知道在这一点上,外部函数是否会用参数生成一个数组。因此:我建议使用range和arange来执行测试。这样读代码有点困难。你能把它格式化成一个脚本,而不是一系列的REPL命令吗?@DeltaIV:检查编辑器!我们需要以此为基准。如果@Dr.V不想包括一些基准测试,也许你会?
import numpy as np
n = 10000
twopi = 2 * np.pi / n
# List comprehension
A = np.array([   
    [twopi*i*j for j in range(n)] 
for i in range(n)])
# timeit > 10.2 s ± 129 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

# Outer
i = np.arange(n)
A = twopi * np.outer(i, i)
# timeit > 234 ms ± 6.87 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

# Product
A = np.arange(n) * np.arange(n).reshape(-1, 1) * twopi
# timeit > 208 ms ± 41.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)