如何在Python中加速2D数组中的2D数组?

3
我正在研究如何加速我的函数。这个函数会用到许多相同大小的二维数组。我想将它们合并成一个4D数组,其中最后两个维度为3x3,并在以后获取整个数组的特征值。
我已经使用了两个嵌套的for循环来实现,但速度比我想要的慢一些,所以有没有好的方法可以加速代码?
def principal(xx, xy, xz, yy, yz, zz):

    import numpy as np

    xx = np.array(xx)
    xy = np.array(xy)
    xz = np.array(xz)
    yy = np.array(yy)
    yz = np.array(yz)
    zz = np.array(zz)

    size = np.shape(xx)
    Princ = np.empty((size[1], size[0], 3, 3))
    for j in range(size[1]):
        for i in range(size[0]):
            Princ[j, i, :, :] = np.array([[xx[i, j], xy[i, j], xz[i, j]],
                                          [xy[i, j], yy[i, j], yz[i, j]],
                                          [xz[i, j], yz[i, j], zz[i, j]]])
    Princ = np.linalg.eigvalsh(Princ)

    return Princ


import numpy as np

number_arrays_1 = 3
number_arrays_2 = 4

xx = np.ones((number_arrays_1, number_arrays_2))*80
xy = np.ones((number_arrays_1, number_arrays_2))*30
xz = np.ones((number_arrays_1, number_arrays_2))*0
yy = np.ones((number_arrays_1, number_arrays_2))*40
yz = np.ones((number_arrays_1, number_arrays_2))*0
zz = np.ones((number_arrays_1, number_arrays_2))*60

Princ = principal(xx, xy, xz, yy, yz, zz)
print(Princ)

我使用xx = np.array(xx)进行转换的原因是在较大的程序中,我将一个pandas dataframe而不是numpy数组传递到函数中。

你正在每次函数调用时导入numpy两次。你应该将它们移到脚本的顶部。 - Dogukan Altay
我定义的函数principal通常位于一个单独的文件中,然后我会将它导入到主文件中以供使用。我认为我必须导入每个函数中使用的模块,不是吗? - Raffe
1
@DogukanAltay,额外的导入不是问题。 - hpaulj
xx等是否总是np.ones(....)*c?还是这只是为了方便举例而已? - hpaulj
这只是针对此示例,它们将非常不同,因为它们是模拟输出。这只是为了让我看到它是否给出正确的值(我知道在最后评估的特征值是什么)。 - Raffe
在数据框上调用...values()可能比调用np.array(...)更快。 - Mad Physicist
1个回答

2
这似乎是一个简单的堆栈和重塑操作:
def principal(xx, xy, xz, yy, yz, zz):
    princ = np.stack((xx.T, xy.T, xz.T, xy.T, yy.T, yz.T, xz.T, yz.T, zz.T), axis=-1).reshape(*xx.shape[::-1], 3, 3)
    return = np.linalg.eigvalsh(princ)

如果输入已经是数组,您不需要显式调用np.array。在数据框上运行xx.values()应该返回numpy值。
另一种方法是构建数组,然后将3x3维度交换到后面。这可能不太高效,因为第一种方法使3x3维度连续,而这种方法则没有。
princ = np.array([[xx, xy, xz], [xy, yy, yz], [xz, yz, zz]]).T

虽然和主题不太相关,但是你可以用以下方法更快地生成数组:

target_shape = (3, 4)
values = np.array([80, 30, 0, 40, 0, 60])
xx, xy, xz, yy, yz, zz = np.full((6, *target_shape), values.reshape(-1, 1, 1))

事实上,如果您的数据允许,甚至可以节省解压缩:
data = np.full((6, *target_shape), values.reshape(-1, 1, 1))
principal(*data)

非常感谢,首先使用堆叠和重塑的方法几乎可以解决问题,但我必须转置xx、xy等才能得到正确的形状。在for循环中,我的上一个函数中的符号是Princ[j, i, :, :] = x[i, j]...因此它们由于数据如何输入和输出到函数中而被交换。但一旦我转置了数组,它就工作得很好,从大约3-4分钟的计算时间缩短到了约30秒,所以我认为这是一个胜利!还要感谢您提醒我跳过xx = np.array(xx)的转换,我认为这也节省了一些内存和时间。 - Raffe
也会尝试使用 .value() 或者在 Pandas 文档中提到的 .to_numpy(),看看它是否有帮助。 - Raffe
@RasmusSchützer。我已经修复了答案,以正确实现转置。 - Mad Physicist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接