2016-08-04 97 views
5

NumPy在創建數組時非常有用。如果numpy.array的第一個參數具有__getitem____len__方法,則基於它們可能是有效序列來使用它們。防止numpy創建多維數組

不幸的是我想創建一個包含dtype=object而不是NumPy「有幫助」的數組。

分解爲一個最小的例子中,類將是這樣的:

import numpy as np 

class Test(object): 
    def __init__(self, iterable): 
     self.data = iterable 

    def __getitem__(self, idx): 
     return self.data[idx] 

    def __len__(self): 
     return len(self.data) 

    def __repr__(self): 
     return '{}({})'.format(self.__class__.__name__, self.data) 

,如果「iterables」有不同的長度,一切都很好,我得到正是我想要的結果:

>>> np.array([Test([1,2,3]), Test([3,2])], dtype=object) 
array([Test([1, 2, 3]), Test([3, 2])], dtype=object) 

但NumPy的創建一個多維數組,如果這些發生在具有相同的長度:

>>> np.array([Test([1,2,3]), Test([3,2,1])], dtype=object) 
array([[1, 2, 3], 
     [3, 2, 1]], dtype=object) 

不幸的是,只有ndmin的論點,所以我想知道是否有一種方法來執行ndmax或以某種方式防止NumPy將自定義類解釋爲另一維(不刪除__len____getitem__)?

回答

3

一種解決方法是當然的創建所需要的形狀的陣列,然後複製數據:

In [19]: lst = [Test([1, 2, 3]), Test([3, 2, 1])] 

In [20]: arr = np.empty(len(lst), dtype=object) 

In [21]: arr[:] = lst[:] 

In [22]: arr 
Out[22]: array([Test([1, 2, 3]), Test([3, 2, 1])], dtype=object) 

請注意,在任何情況下,我也不會感到驚訝如果numpy的行爲w.r.t.解釋可迭代對象(這是你想要使用的,對吧?)是依賴於numpy的版本。可能還有越野車。或者,也許這些錯誤中的一些實際上是功能。無論如何,當一個numpy版本發生變化時,我會警惕破碎。

相反,複製到預先創建的數組應該更健壯。

5

此行爲已經過多次討論(例如Override a dict with numpy support)。 np.array試圖使盡可能高的維數組。模型案例是嵌套列表。如果它可以迭代並且子列表的長度相等,它將「向下鑽取」。

這走下2層中遇到不同長度的名單之前:

In [250]: np.array([[[1,2],[3]],[1,2]],dtype=object) 
Out[250]: 
array([[[1, 2], [3]], 
     [1, 2]], dtype=object) 
In [251]: _.shape 
Out[251]: (2, 2) 

沒有形狀也沒有辦法知道我是否希望它是(2,)(2,2)的方式ndmax參數。這兩種方法都適用於dtype。

它是編譯好的代碼,所以很難確切地看到它使用的是什麼測試。它試圖迭代列表和元組,但不能在集合或字典上進行迭代。

,使具有給定尺寸的對象陣列的最可靠的方法是用空的啓動,並填寫

In [266]: A=np.empty((2,3),object) 
In [267]: A.fill([[1,'one']]) 
In [276]: A[:]={1,2} 
In [277]: A[:]=[1,2] # broadcast error 

的另一種方式是開始與至少一個不同的元件(例如一個None) ,然後替換它。

還有一個更原始的創造者,是ndarray初具規模:

In [280]: np.ndarray((2,3),dtype=object) 
Out[280]: 
array([[None, None, None], 
     [None, None, None]], dtype=object) 

但是,這是基本相同的np.empty(除非我給它一個緩衝)。

這些都是虛假,但它們並不昂貴(時間明智)。

=====(編輯)

https://github.com/numpy/numpy/issues/5933Enh: Object array creation function.是一個增強請求。另外https://github.com/numpy/numpy/issues/5303the error message for accidentally irregular arrays is confusing

開發人員的情緒似乎贊成單獨的函數來創建dtype=object數組,其中一個對初始維度和迭代深度具有更多的控制權。他們甚至可能會加強錯誤檢查,以防止np.array創建「不規則」陣列。

這樣的函數可以檢測到一個規則的嵌套可迭代到指定深度的形狀,並構建一個要填充的對象類型數組。

def objarray(alist, depth=1): 
    shape=[]; l=alist 
    for _ in range(depth): 
     shape.append(len(l)) 
     l = l[0] 
    arr = np.empty(shape, dtype=object) 
    arr[:]=alist 
    return arr 

隨着各種深度:

In [528]: alist=[[Test([1,2,3])], [Test([3,2,1])]] 
In [529]: objarray(alist,1) 
Out[529]: array([[Test([1, 2, 3])], [Test([3, 2, 1])]], dtype=object) 
In [530]: objarray(alist,2) 
Out[530]: 
array([[Test([1, 2, 3])], 
     [Test([3, 2, 1])]], dtype=object) 
In [531]: objarray(alist,3) 
Out[531]: 
array([[[1, 2, 3]], 

     [[3, 2, 1]]], dtype=object) 
In [532]: objarray(alist,4) 
... 
TypeError: object of type 'int' has no len() 
+0

我試圖尋找類似的問題,但我還沒有發現任何。也許我只是搜索錯誤的短語。如果您有任何提及較早的問題,那就太棒了。謝謝你的回答,但我實際上並沒有尋找解決方法。我更關心的是如何在事先不知道確切長度的情況下定義數組的最大深度(維),或者禁用numpy將自定義類實例解釋爲序列。 – MSeifert

+0

通過將您的類更改爲子類'dict',我可以阻止它在您的實例上迭代。這表明'np.array'正在測試多於'__getitem__'。但是我一直無法找到執行這種檢查的代碼。 – hpaulj

+0

http://stackoverflow.com/questions/36663919/override-a-dict-with-numpy-support - 與同一問題的鬥爭;控制'np.array'是否迭代你的自定義類。同樣的解決方法。 – hpaulj