'N' 维 numpy 数组的操作
Operations on 'N' dimensional numpy arrays
我正在尝试概括一些 Python 代码以对任意维度的数组进行操作。这些操作应用于数组中的每个向量。因此,对于一维数组,只有一个操作,对于二维数组,它将是行和列的(线性的,所以顺序无关紧要)。例如,一维数组 (a) 很简单:
b = operation(a)
其中 'operation' 需要一维数组。对于二维数组,操作可能会按
进行
for ii in range(0,a.shape[0]):
b[ii,:] = operation(a[ii,:])
for jj in range(0,b.shape[1]):
c[:,ii] = operation(b[:,ii])
我想在不需要事先知道数组维度的情况下进行一般化,并且不需要为每个可能的维度设置大量 if/elif 语句。
对于一维或二维通用的解决方案是可以的,但最好是完全通用的解决方案。实际上,我不认为任何大于 2 的维度都需要这个,但如果我能看到一个一般的例子,我会学到一些东西!
额外信息:
我有一个使用单元格做类似事情的 matlab 代码,但我不完全理解它是如何工作的。在这个例子中,每个向量都被重新排列(与numpy.fft中的fftshift基本相同的功能)。不确定这是否有帮助,但它对任意维度的数组进行操作。
function aout=foldfft(ain)
nd = ndims(ain);
for k = 1:nd
nx = size(ain,k);
kx = floor(nx/2);
idx{k} = [kx:nx 1:kx-1];
end
aout = ain(idx{:});
如果您正在寻找一种编程方式来为 k-th
维索引一个 n
维数组,那么 numpy.take
可能会对您有所帮助。
下面给出了foldfft
的实现作为例子:
In[1]:
import numpy as np
def foldfft(ain):
result = ain
nd = len(ain.shape)
for k in range(nd):
nx = ain.shape[k]
kx = (nx+1)//2
shifted_index = list(range(kx,nx)) + list(range(kx))
result = np.take(result, shifted_index, k)
return result
a = np.indices([3,3])
print("Shape of a = ", a.shape)
print("\nStarting array:\n\n", a)
print("\nFolded array:\n\n", foldfft(a))
Out[1]:
Shape of a = (2, 3, 3)
Starting array:
[[[0 0 0]
[1 1 1]
[2 2 2]]
[[0 1 2]
[0 1 2]
[0 1 2]]]
Folded array:
[[[2 0 1]
[2 0 1]
[2 0 1]]
[[2 2 2]
[0 0 0]
[1 1 1]]]
您可以使用 numpy.ndarray.flat,它允许您对 n 维 numpy 数组进行线性迭代。您的代码应如下所示:
b = np.asarray(x)
for i in range(len(x.flat)):
b.flat[i] = operation(x.flat[i])
在 Octave 中,您的 MATLAB 代码可以:
octave:19> size(ain)
ans =
2 3 4
octave:20> idx
idx =
{
[1,1] =
1 2
[1,2] =
1 2 3
[1,3] =
2 3 4 1
}
然后它使用 idx
元胞数组来索引 ain
。有了这些尺寸,它 'rolls' 尺寸 4 尺寸。
对于 5 和 6,索引列表将是:
2 3 4 5 1
3 4 5 6 1 2
numpy
中的等价物是:
In [161]: ain=np.arange(2*3*4).reshape(2,3,4)
In [162]: idx=np.ix_([0,1],[0,1,2],[1,2,3,0])
In [163]: idx
Out[163]:
(array([[[0]],
[[1]]]), array([[[0],
[1],
[2]]]), array([[[1, 2, 3, 0]]]))
In [164]: ain[idx]
Out[164]:
array([[[ 1, 2, 3, 0],
[ 5, 6, 7, 4],
[ 9, 10, 11, 8]],
[[13, 14, 15, 12],
[17, 18, 19, 16],
[21, 22, 23, 20]]])
除了基于 0 的索引之外,我还使用 np.ix_
来重塑索引。 MATLAB 和 numpy
使用不同的语法来索引值块。
下一步是用代码构造 [0,1],[0,1,2],[1,2,3,0]
,直接翻译。
我可以使用 np.r_
作为将 2 个切片转换为索引数组的快捷方式:
In [201]: idx=[]
In [202]: for nx in ain.shape:
kx = int(np.floor(nx/2.))
kx = kx-1;
idx.append(np.r_[kx:nx, 0:kx])
.....:
In [203]: idx
Out[203]: [array([0, 1]), array([0, 1, 2]), array([1, 2, 3, 0])]
并通过 np.ix_
传递它以生成适当的索引元组:
In [204]: ain[np.ix_(*idx)]
Out[204]:
array([[[ 1, 2, 3, 0],
[ 5, 6, 7, 4],
[ 9, 10, 11, 8]],
[[13, 14, 15, 12],
[17, 18, 19, 16],
[21, 22, 23, 20]]])
在这种情况下,2 个维度不滚动任何东西,slice(None)
可以替换那些:
In [210]: idx=(slice(None),slice(None),[1,2,3,0])
In [211]: ain[idx]
======================
np.roll
是:
indexes = concatenate((arange(n - shift, n), arange(n - shift)))
res = a.take(indexes, axis)
np.apply_along_axis
是另一个构造索引数组的函数(并将其变成元组进行索引)。
上面的人提供了多种合适的解决方案。为了完整起见,这是我的最终解决方案。在这个 3 维情况下的玩具示例中,函数 'ops' 将向量的第一个和最后一个元素替换为 1.
import numpy as np
def ops(s):
s[0]=1
s[-1]=1
return s
a = np.random.rand(4,4,3)
print '------'
print 'Array a'
print a
print '------'
for ii in np.arange(a.ndim):
a = np.apply_along_axis(ops,ii,a)
print '------'
print ' Axis',str(ii)
print a
print '------'
print ' '
生成的 3D 数组在 'border' 上的每个元素中都有一个 1,数组中间的数字不变。这当然是一个玩具示例;但是 ops 可以是对一维向量进行运算的任意函数。
扁平化矢量也可以;我之所以选择不这样做,仅仅是因为记账比较困难,而且 apply_along_axis 是最简单的方法。
我正在尝试概括一些 Python 代码以对任意维度的数组进行操作。这些操作应用于数组中的每个向量。因此,对于一维数组,只有一个操作,对于二维数组,它将是行和列的(线性的,所以顺序无关紧要)。例如,一维数组 (a) 很简单:
b = operation(a)
其中 'operation' 需要一维数组。对于二维数组,操作可能会按
进行for ii in range(0,a.shape[0]):
b[ii,:] = operation(a[ii,:])
for jj in range(0,b.shape[1]):
c[:,ii] = operation(b[:,ii])
我想在不需要事先知道数组维度的情况下进行一般化,并且不需要为每个可能的维度设置大量 if/elif 语句。 对于一维或二维通用的解决方案是可以的,但最好是完全通用的解决方案。实际上,我不认为任何大于 2 的维度都需要这个,但如果我能看到一个一般的例子,我会学到一些东西!
额外信息: 我有一个使用单元格做类似事情的 matlab 代码,但我不完全理解它是如何工作的。在这个例子中,每个向量都被重新排列(与numpy.fft中的fftshift基本相同的功能)。不确定这是否有帮助,但它对任意维度的数组进行操作。
function aout=foldfft(ain)
nd = ndims(ain);
for k = 1:nd
nx = size(ain,k);
kx = floor(nx/2);
idx{k} = [kx:nx 1:kx-1];
end
aout = ain(idx{:});
如果您正在寻找一种编程方式来为 k-th
维索引一个 n
维数组,那么 numpy.take
可能会对您有所帮助。
下面给出了foldfft
的实现作为例子:
In[1]:
import numpy as np
def foldfft(ain):
result = ain
nd = len(ain.shape)
for k in range(nd):
nx = ain.shape[k]
kx = (nx+1)//2
shifted_index = list(range(kx,nx)) + list(range(kx))
result = np.take(result, shifted_index, k)
return result
a = np.indices([3,3])
print("Shape of a = ", a.shape)
print("\nStarting array:\n\n", a)
print("\nFolded array:\n\n", foldfft(a))
Out[1]:
Shape of a = (2, 3, 3)
Starting array:
[[[0 0 0]
[1 1 1]
[2 2 2]]
[[0 1 2]
[0 1 2]
[0 1 2]]]
Folded array:
[[[2 0 1]
[2 0 1]
[2 0 1]]
[[2 2 2]
[0 0 0]
[1 1 1]]]
您可以使用 numpy.ndarray.flat,它允许您对 n 维 numpy 数组进行线性迭代。您的代码应如下所示:
b = np.asarray(x)
for i in range(len(x.flat)):
b.flat[i] = operation(x.flat[i])
在 Octave 中,您的 MATLAB 代码可以:
octave:19> size(ain)
ans =
2 3 4
octave:20> idx
idx =
{
[1,1] =
1 2
[1,2] =
1 2 3
[1,3] =
2 3 4 1
}
然后它使用 idx
元胞数组来索引 ain
。有了这些尺寸,它 'rolls' 尺寸 4 尺寸。
对于 5 和 6,索引列表将是:
2 3 4 5 1
3 4 5 6 1 2
numpy
中的等价物是:
In [161]: ain=np.arange(2*3*4).reshape(2,3,4)
In [162]: idx=np.ix_([0,1],[0,1,2],[1,2,3,0])
In [163]: idx
Out[163]:
(array([[[0]],
[[1]]]), array([[[0],
[1],
[2]]]), array([[[1, 2, 3, 0]]]))
In [164]: ain[idx]
Out[164]:
array([[[ 1, 2, 3, 0],
[ 5, 6, 7, 4],
[ 9, 10, 11, 8]],
[[13, 14, 15, 12],
[17, 18, 19, 16],
[21, 22, 23, 20]]])
除了基于 0 的索引之外,我还使用 np.ix_
来重塑索引。 MATLAB 和 numpy
使用不同的语法来索引值块。
下一步是用代码构造 [0,1],[0,1,2],[1,2,3,0]
,直接翻译。
我可以使用 np.r_
作为将 2 个切片转换为索引数组的快捷方式:
In [201]: idx=[]
In [202]: for nx in ain.shape:
kx = int(np.floor(nx/2.))
kx = kx-1;
idx.append(np.r_[kx:nx, 0:kx])
.....:
In [203]: idx
Out[203]: [array([0, 1]), array([0, 1, 2]), array([1, 2, 3, 0])]
并通过 np.ix_
传递它以生成适当的索引元组:
In [204]: ain[np.ix_(*idx)]
Out[204]:
array([[[ 1, 2, 3, 0],
[ 5, 6, 7, 4],
[ 9, 10, 11, 8]],
[[13, 14, 15, 12],
[17, 18, 19, 16],
[21, 22, 23, 20]]])
在这种情况下,2 个维度不滚动任何东西,slice(None)
可以替换那些:
In [210]: idx=(slice(None),slice(None),[1,2,3,0])
In [211]: ain[idx]
======================
np.roll
是:
indexes = concatenate((arange(n - shift, n), arange(n - shift)))
res = a.take(indexes, axis)
np.apply_along_axis
是另一个构造索引数组的函数(并将其变成元组进行索引)。
上面的人提供了多种合适的解决方案。为了完整起见,这是我的最终解决方案。在这个 3 维情况下的玩具示例中,函数 'ops' 将向量的第一个和最后一个元素替换为 1.
import numpy as np
def ops(s):
s[0]=1
s[-1]=1
return s
a = np.random.rand(4,4,3)
print '------'
print 'Array a'
print a
print '------'
for ii in np.arange(a.ndim):
a = np.apply_along_axis(ops,ii,a)
print '------'
print ' Axis',str(ii)
print a
print '------'
print ' '
生成的 3D 数组在 'border' 上的每个元素中都有一个 1,数组中间的数字不变。这当然是一个玩具示例;但是 ops 可以是对一维向量进行运算的任意函数。
扁平化矢量也可以;我之所以选择不这样做,仅仅是因为记账比较困难,而且 apply_along_axis 是最简单的方法。