NumPy数组的维度滚动/增加

4
我目前正在尝试找到在Python中对N维数组执行以下操作的简单方法。为了简单起见,让我们从一个大小为4的一维数组开始。
X = np.array([1,2,3,4])

我想做的是创建一个新数组,叫做Y,使得:
Y = np.array([1,2,3,4],[2,3,4,1],[3,4,1,2],[4,1,2,3])

我想要做的是创建一个数组Y,使得:
Y[:,i] = np.roll(X[:],-i, axis = 0)

我知道如何使用for循环来完成这个任务,但我正在寻找一种更快的方法。我要处理的数组实际上是一个三维数组,称之为X。我正在寻找一种找到一个数组Y的方法,使得:
Y[:,:,:,i,j,k] = np.roll(X[:,:,:],(-i,-j,-k),axis = (0,1,2))

我可以使用itertools.product类和for循环来完成这个任务,但是这样做非常慢。如果有更好的方法,请告诉我。我还安装了CUPY和GTX-970,如果有一种使用CUDA更快速地完成此任务的方法,请告诉我。如果需要更多上下文,请告诉我。

以下是计算位置空间两点关联函数的原始代码。数组x0是一个n乘以n乘以n的实值数组,表示实标量场。函数iterate(j,s)运行j次迭代。每次迭代都会为每个晶格点生成一个介于-s和s之间的随机浮点数。然后它计算作用量的变化dS,并以min(1,exp^(-dS))的概率接受变化。

def momentum(k,j,s):
global Gxa
Gx = numpy.zeros((n,n,t))
for i1 in range(0,k):
    iterate(j,s)
    for i2,i3,i4 in itertools.product(range(0,n),range(0,n),range(0,n)):
        x1 = numpy.roll(numpy.roll(numpy.roll(x0, -i2, axis = 0),-i3, axis = 1),-i4,axis = 2)
        x2 = numpy.mean(numpy.multiply(x0,x1))
        Gx[i2,i3,i4] = x2
    Gxa = Gxa + Gx
Gxa = Gxa/k
1个回答

2

方法一

我们可以将这个想法扩展到我们的3D数组案例中。因此,只需沿着三个维度连接切片版本,然后使用基于np.lib.stride_tricks.as_stridedscikit-image的view_as_windows来高效地将最终输出作为连接版本的步幅视图获取,如下所示-

from skimage.util.shape import view_as_windows

X1 = np.concatenate((X,X[:,:,:-1]),axis=2)
X2 = np.concatenate((X1,X1[:,:-1,:]),axis=1)
X3 = np.concatenate((X2,X2[:-1,:,:]),axis=0)
out = view_as_windows(X3,X.shape)

方法 #2

对于非常大的数组,我们可能希望初始化输出数组,然后重新使用上一个方法中的 X3 进行切片赋值。这个切片过程比原始的滚动方式更快。实现方式如下:

m,n,r = X.shape
Yout = np.empty((m,n,r,m,n,r),dtype=X.dtype)
for i in range(m):
    for j in range(n):
        for k in range(r):
            Yout[:,:,:,i,j,k] = X3[i:i+m,j:j+n,k:k+r]

太棒了!我的速度强化得很大。不好的消息是,我现在在三个维度上被限制到最大晶格大小约为33(我正在模拟一个晶格量子场论),因为如果我超过那个大小就会出现内存错误,因为33的6次方是一个非常大的数字。有什么建议来解决这个问题吗? - chuckstables
它实际上并不起作用。我认为真正的内存消耗是当我使用np.multiply对新的六维矩阵和原始矩阵进行逐元素相乘时,因为我正在尝试计算晶格上相互作用理论的欧几里得(虚时间)格林函数。无论如何,使用您的方法,我可以探测到以前对我来说不可行的晶格尺寸,所以谢谢! - chuckstables
@chuckstables 你说的“它不起作用”是指approach2不起作用吗?如果是,你是指它很慢还是输出错误?我已经在我的端口检查了性能和正确性。 - Divakar
我的意思是第二种方法。它给出了正确的输出,看起来和第一种方法一样快,但我仍然遇到了内存限制。我会在有时间时运行更多测试,并告诉你我发现了什么。 - chuckstables
@chuckstables 只是好奇,你的roll方法是否也遇到了内存限制?如果是这样,我认为我们别无选择。 - Divakar
实际上,使用我的原始方法,我从未遇到过内存限制的问题。不过缺点是它非常慢,甚至计算一个包含大约15,000个点的晶格场构型的位置空间相关函数需要40多秒。如果您需要,我可以给您提供模拟代码;请注意,这些是我一生中编写的第一个程序,非常可怕。 - chuckstables

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