使用 NumPy 优化非数字矩阵的创建

Optimizing the creation of a non-numeric matrix with NumPy

当我试图找到一种方法来优化巨大的二维矩阵的创建和打印时,我决定试用 NumPy。但是,对我来说不幸的是,相反地使用这个库会使情况变得更糟。 我的目标是创建一个矩阵,该矩阵将用其索引填充字符串。像这样(其中 n 是矩阵的大小):

python_matrix = [[f"{y}, {x}" for x in range(n)] for y in range(n)]

当我这样使用 NumPy 库的 array() 函数时:

numpy_matrix = numpy.array([[f"{y}, {x}" for x in range(n)] for y in range(n)])

创建矩阵的时间只会增加。例如,对于 n = 1000python_matrix 的创建时间为 0.032 秒,而 numpy_matrix 的创建时间为 0.419,即比 python 长 13 倍

此外,numpy_matrix 打印速度比 python_matrix 使用 for 循环

打印速度慢(如果您输出完整版本,而不是缩短版本)
n = 1000
def numpy_matrix(n):
    matrix = numpy.array([[f"{y}, {x}" for x in range(n)] for y in range(n)])
    with numpy.printoptions(threshold=numpy.inf):
        print(coordArr)
def python_matrix(n):
    matrix = [[f"{y}, {x}" for x in range(n)] for y in range(n)]
    def print_matrix():
        for arr in matrix:
            print(arr)
    print_matrix()
# time of numpy_matrix > time of python_matrix

  1. 是使用标准 Python 功能更好,还是 NumPy 实际上更高效,只是我没有正确使用它?
  2. 此外,如果我确实使用 NumPy,如何加速完整版矩阵的输出的问题仍然存在

运行 ipython 会话并使用其 timeit,我没有发现如此大的差异:

制作清单:

In [13]: timeit [[f"{y}, {x}" for y in range(N)] for x in range(N)]
492 ms ± 3.28 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

制作数组(同时制作列表):

In [14]: timeit np.array([[f"{y}, {x}" for y in range(N)] for x in range(N)])
779 ms ± 12.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

从以下时间删除列表创建步骤:

In [15]: %%timeit alist = [[f"{y}, {x}" for y in range(N)] for x in range(N)]
    ...: np.array(alist)
    ...: 
    ...: 
313 ms ± 12.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

因此,从现有列表创建数组的时间不会太长。

指定数据类型也有一点帮助:

In [18]: %%timeit alist = [[f"{y}, {x}" for y in range(N)] for x in range(N)]
    ...: np.array(alist, dtype='U8')
    ...: 
    ...: 
224 ms ± 2.67 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

虽然我们可以只对字符串格式化计时,但计时打印比较尴尬,str(x)。我不会显示时间,但是是的,数组格式化要慢得多。本质上 numpy 必须通过 Python 自己的字符串处理代码;它几乎没有自己的东西。

数字list/array

对于数值数组,相对差异较大:

In [29]: alist = [[(x,y) for y in range(N)] for x in range(N)]

In [30]: arr = np.array(alist)

In [31]: arr.shape
Out[31]: (1000, 1000, 2)

In [32]: timeit alist = [[(x,y) for y in range(N)] for x in range(N)]
171 ms ± 8.4 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

In [33]: timeit arr = np.array(alist)
832 ms ± 36.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

但是,如果使用数组方法创建相同的数组 - 即不通过列表的列表,时间会好得多:

In [40]: timeit np.stack(np.broadcast_arrays(np.arange(N)[:,None], np.arange(N)),axis=2)
8.51 ms ± 89.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

numpy 并不是在所有方面都优于列表。最适合现有数组的数学运算。从列表创建数组非常耗时。而且它并没有增加很多字符串处理。