[英]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是最簡單的方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.