簡體   English   中英

對'N'維numpy數組的操作

[英]Operations on 'N' dimensional numpy arrays

我試圖概括一些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{:});

如果您正在尋找一種編程方式來索引第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 ,它允許你線性迭代一個維度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 使用這些尺寸,它'滾動'尺寸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數組在“邊界”上的每個元素中都有一個1,數組中間的數字不變。 這當然是一個玩具的例子; 但是,ops可以是在1D向量上運行的任意函數。

展平矢量也將起作用; 我之所以選擇不去追求,只是因為簿記更加困難,而且apply_along_axis是最簡單的方法。

apply_along_axis參考頁面

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM