2015-11-30 50 views
1

我试图推广一些Python代码来对任意维度的数组进行操作。这些操作应用于数组中的每个向量。因此,对于一维数组,只需一次操作,对于一个二维数组,它将是行列式(线性,因此顺序无关紧要)。例如,一维数组(a)很简单:对'N'维numpy数组的操作

b = operation(a) 

其中'操作'期待1D数组。对于一个二维数组,该操作可能继续作为

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]) 

我想提出这个一般,我并不需要知道数组的维事前,而不是有一大套的,如果/ 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{:}); 
+1

您可以详细介绍一下'操作'的含义吗?它是某种复杂的函数还是算术运算? – Daniel

+1

我不得不运行MATLAB的各个部分,但我认为它构造了一个大小为'nd'的单元数组,每个维都有一个索引范围/切片。像'apply_along/over_axis'这样的'numpy'函数做类似的事情,除了必须创建一个'tuple'。 – hpaulj

+0

@Ophion它只是一个将单个向量(1D数组)作为输入的函数。所以它更像是一个复杂的函数,而不是一个简单的算术运算。 –

回答

1

在八度,你的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。有了这些尺寸,它就可以“滚动”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是构建索引阵列另一个函数(和将其变成索引的元组)。

+0

沿着轴线应用正是我正在寻找的功能。我可以简单地遍历ndim并使用b = np.apply_along_axis(operation,a,ii)。谢谢。 –

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

你可以使用numpy.ndarray.flat,它允许您线性迭代正维数组numpy的。然后,您的代码应该是这个样子:

b = np.asarray(x) 
for i in range(len(x.flat)): 
    b.flat[i] = operation(x.flat[i]) 
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 ' ' 

在第一和最后一个元素将所得三维阵列具有1在每个元件上的“边界”数组中间的数字保持不变。这当然是一个玩具的例子;然而操作可以是任何在一维矢量上运行的任意函数。

展平载体也将工作;我选择不去追求这一点,仅仅是因为簿记更加困难,而apply_along_axis是最简单的方法。

apply_along_axis reference page