2016-11-29 161 views
1

我想使用從this answer解決方案的特定列(就地)排序numpy數組。在大多數情況下它的工作原理,但它不能在任何陣列的另一個數組一個觀點:現在就地排序按列排序失敗

In [35]: columnnum = 2 

In [36]: a = np.array([[1,2,3], [4,7,5], [9,0,1]]) 

In [37]: a 
Out[37]: 
array([[1, 2, 3], 
     [4, 7, 5], 
     [9, 0, 1]]) 

In [38]: b = a[:,(0, 2)] 

In [39]: b 
Out[39]: 
array([[1, 3], 
     [4, 5], 
     [9, 1]]) 

In [40]: a.view(','.join([a.dtype.str] * a.shape[1])).sort(order=['f%d' % columnnum], axis=0) 

In [41]: a 
Out[41]: 
array([[9, 0, 1], 
     [1, 2, 3], 
     [4, 7, 5]]) 

In [42]: b.view(','.join([b.dtype.str] * b.shape[1])).sort(order=['f%d' % columnnum], axis=0) 
ValueError: new type not compatible with array. 

它看起來像numpy的不支持的意見的意見,這使得一定的意義,但我無法弄清楚如何獲得我需要的任何數組的視圖,無論它本身是否爲視圖。到目前爲止,我一直無法找到任何方式來獲取關於我必須構建我需要的新視圖的必要信息。

現在,我正在使用l = l[l[:,columnnum].argsort()]就地排序方法,它工作正常,但由於我在大型數據集上運行,因此我想避免argsort()調用的額外內存開銷(列表的索引)。有沒有辦法獲得關於視圖的必要信息或按列進行分類?

+0

我的預感是你會走運。我對這些numpy的內部信息不是很瞭解,但是在我看來,就像你試圖將視角超越可以在不復制數據的情況下所做的那樣。 – BrenBarn

+0

@BrenBarn:可能。我只是想看看這裏有沒有人有任何聰明的黑客。我目前的解決方案只是錯誤的數據,無法查看,並告訴調用者首先做一個副本......醜陋的,但至少我可以提供一個有用的錯誤消息。 – Linuxios

回答

1
In [1019]: a=np.array([[1,2,3],[4,7,5],[9,0,1]]) 
In [1020]: b=a[:,(0,2)] 

這是您正在排序的a;具有3個字段的結構化數組。它使用相同的數據緩衝區,但將3個整數組解釋爲字段而不是列。

In [1021]: a.view('i,i,i') 
Out[1021]: 
array([[(1, 2, 3)], 
     [(4, 7, 5)], 
     [(9, 0, 1)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')]) 

通過同樣的邏輯,試圖viewb

In [1022]: b.view('i,i') 
/usr/local/bin/ipython3:1: DeprecationWarning: Changing the shape of non-C contiguous array by 
descriptor assignment is deprecated. To maintain 
the Fortran contiguity of a multidimensional Fortran 
array, use 'a.T.view(...).T' instead 
    #!/usr/bin/python3 
.... 
ValueError: new type not compatible with array. 

但是,如果使用3個字段,而不是2,它的工作原理(但具有相同的警告):

In [1023]: b.view('i,i,i') 
/usr/local/bin/ipython3:1: DeprecationWarning:... 
Out[1023]: 
array([[(1, 4, 9), (3, 5, 1)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')]) 

問題是bFortran order。檢查b.flags

In [1026]: a.strides 
Out[1026]: (12, 4) 
In [1027]: b.strides 
Out[1027]: (4, 12) 

b是一個副本,而不是一個視圖。我不知道,爲什麼這個建築b改變了順序。

聽從警告,我可以這樣做:

In [1047]: b.T.view('i,i,i').T 
Out[1047]: 
array([[(1, 4, 9), (3, 5, 1)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')]) 

默認複製(順序c)中的b可被視爲2個字段:

In [1042]: b1=b.copy() 
In [1043]: b1.strides 
Out[1043]: (8, 4) 
In [1044]: b1.view('i,i') 
Out[1044]: 
array([[(1, 3)], 
     [(4, 5)], 
     [(9, 1)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4')]) 

腳註上:https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html

高級索引結果的內存佈局針對每個索引操作進行了優化,並且沒有特定的內存ory命令可以被假定。

====================

在這種情況下b用高級索引構成,並且因此是一個拷貝,即使是真正的視圖可能不是這樣既可見:

In [1052]: a[:,:2].view('i,i') 
.... 
ValueError: new type not compatible with array. 

In [1054]: a[:,:2].copy().view('i,i') 
Out[1054]: 
array([[(1, 2)], 
     [(4, 7)], 
     [(9, 0)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4')]) 

的觀點是選擇值的子集: '我,我,X,I,I,X,I,I,X ...',和這不會轉化爲結構化的dtype。

a的結構化視圖的作用: '(I,I,I),(I,I,I),...'

可以選擇一種結構化陣列的字段的子集:

In [1059]: a1=a.view('i,i,i') 
In [1060]: a1 
Out[1060]: 
array([[(1, 2, 3)], 
     [(4, 7, 5)], 
     [(9, 0, 1)]], 
     dtype=[('f0', '<i4'), ('f1', '<i4'), ('f2', '<i4')]) 
In [1061]: b1=a1[['f0','f2']] 
In [1062]: b1 
Out[1062]: 
array([[(1, 3)], 
     [(4, 5)], 
     [(9, 1)]], 
     dtype=[('f0', '<i4'), ('f2', '<i4')]) 

但是對於這樣的視圖你可以做什麼是有限度的。值可以在a1中更改,並在ab1中查看。但是如果我嘗試更改b1中的值,則會發生錯誤。 這是發展的邊緣。

+0

感謝您的詳細解答!那麼我是否有理由認爲檢查'a.flags.c_contiguous'是否爲'True'就足以保證數組能夠以這種方式被查看? – Linuxios

+0

它可能是;我沒有用過那種測試。 – hpaulj

+0

謝謝。我假設沒有其他方法可以按列排序,是嗎? – Linuxios