对'N'维numpy数组的操作

时间:2015-11-30 18:31:06

标签: python arrays numpy slice

我试图概括一些Python代码来操作任意维度的数组。这些操作应用于数组中的每个向量。因此对于1D阵列,只有一个操作,对于2-D阵列,它将是行和列(线性,因此顺序无关紧要)。例如,1D数组(a)很简单:

b = operation(a)

其中'operation'期待一维数组。对于2D阵列,操作可以按

进行
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语句。 对于1或2维通用的解决方案是可以的,但是优选完全通用的解决方案。实际上,我认为不需要任何高于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{:});

4 个答案:

答案 0 :(得分:1)

如果您正在寻找一种编程方式来将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]]]

答案 1 :(得分:1)

您可以使用numpy.ndarray.flat,它允许您在n维numpy数组上线性迭代。您的代码应该如下所示:

{{1}}

答案 2 :(得分:1)

在Octave中,您的MATLAB代码执行:

(n[i]<n[smallest])

然后它使用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。通过这些尺寸,它可以“滚动”4号尺寸。

对于5和6,索引列表将是:

ain

2 3 4 5 1 3 4 5 6 1 2 中的等价物是:

numpy

除了基于0的索引之外,我还使用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]]]) 来重构索引。 MATLAB和np.ix_使用不同的语法来索引值块。

下一步是使用代码构建numpy,这是一种直接的翻译。

我可以使用[0,1],[0,1,2],[1,2,3,0]作为将2个切片转换为索引数组的捷径:

np.r_

并通过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_

在这种情况下,如果2个维度没有滚动任何内容,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]]]) 可以替换它们:

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) 是另一个构造索引数组的函数(并将其转换为元组以进行索引)。

答案 3 :(得分:0)

上述人员提供了多种适当的解决方案。为了完整起见,这是我的最终解决方案。在这个玩具示例中,对于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可以是在1D向量上运行的任意函数。

展平矢量也会起作用;我之所以选择不去追求,只是因为记账更加困难,而且apply_along_axis是最简单的方法。

apply_along_axis reference page