2014-07-22 88 views
3

我有一個問題。問題是:我想創建一個numpy數組的子類,然後創建一個該類型的對象數組。當我引用該數組中的項目時,我希望它仍然是該子類的一個實例。相反,它是numpy數組的一個實例。numpy的子類的數組

這是一個失敗的試驗:

import numpy as np 


class ImageWrapper(np.ndarray): 

    def __new__(cls, image_data): 
     assert image_data.ndim in (2, 3) 
     return image_data.view(cls) 

    @property 
    def n_colours(self): 
     return 1 if self.ndim==2 else self.shape[2] 


n_frames = 10 
frames = [ImageWrapper(np.random.randint(255, size = (20, 15, 3)).astype('uint8')) for _ in xrange(n_frames)] 
video = np.array(frames) 
assert video[0].n_colours == 3 

給我:AttributeError的: 'numpy.ndarray' 對象有沒有屬性 'n_colours'

我怎樣才能使這項工作?

事情已經試過:

  • 設置subok =構建視頻時真實的 - 從子類對象的單個實例,而不是一個列表構建一個數組時,這只是工作。
  • 設置D型=對象或D型= ImageWrapper不起作用

我認識到,我可以只讓視頻列表,但它是最好保持它作爲其他原因numpy的陣列。

+0

的問題是,當你調用'3D陣列的列表上array',你會得到一個四維陣列,而不是一維數組全的3D陣列。顯然,4D數組不能是'ImageWrapper',所以它是一個'ndarray',所以它的任何一部分都是一個'ndarray',無論數據來自哪裏。問題是,_why_你想要它是一個數組嗎?對象的一維數組並不會失去numpy對本地列表的好處,但它會失去它們的一個_lot_,如果你能在最後一句中告訴我們「其他原因」,它可能會有所幫助。 – abarnert

+0

另外,你的設計是否有一個原因要求4D陣列_不能成爲ImageWrapper?如果N> 3(或者只是引發一個異常),你的'n_colours'將不得不返回一個N-3維數組而不是標量數組,否則,會出現什麼問題?因爲這會使事情變得更簡單... – abarnert

+0

「其他原因」並不是一個很好的理由,它只是數組是預期數據類型的接口的一部分。在這種情況下,Jaime建議的對象數組將會執行。 – Peter

回答

2

numpy.array只是不夠複雜,無法處理這種情況。 subok=True告訴函數要通過子類,但是你沒有將它傳遞給ndarray的子​​類,而是將它傳遞給一個列表(它恰好填充了ndarray子類的實例)。你可以像你期望通過這樣的:

import numpy as np 


class ImageWrapper(np.ndarray): 

    def __new__(cls, image_data): 
     assert 2 <= image_data.ndim <= 4 
     return image_data.view(cls) 

    @property 
    def n_colours(self): 
     return 1 if self.ndim==2 else self.shape[-1] 


n_frames = 10 
frame_shape = (20, 15, 3) 
video = ImageWrapper(np.empty((n_frames,) + frame_shape, dtype='uint8')) 
for i in xrange(n_frames): 
    video[i] = np.random.randint(255, size=(20, 15, 3)) 
assert video[0].n_colours == 3 

通知我不得不更新ImageWrapper允許4D數組作爲輸入。

3

無論你想要達到什麼目的,這可能比子類化ndarray更好。但是考慮到這一點,你可以讓你的陣列的類型爲object,儘管在創建時你必須小心。這工作:

>>> video = np.empty((len(frames),), dtype=object) 
>>> video[:] = frames 
>>> video[0].n_colours 
3 

但這並不:

>>> video = np.array(frames, dtype=object) 
>>> video[0].n_colours 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'numpy.ndarray' object has no attribute 'n_colours' 
+0

這對我很有用,謝謝。真正的原因是我們有一個奇怪的圖像格式(YUV),我們希望有辦法綁定它來做裁剪和縮減採樣等事情。繼承而不是包裝的原因更有問題 - 主要是因爲我們在使用python,但是想假裝我們使用Java,並且我們的接口要求在模塊之間傳遞的數據是數組類型的。 – Peter

+0

@彼得:YUV並不是那麼奇怪或不尋常。另外,如果'ImageWrapper'可以保存> 3D的數組,那麼對其調用方法似乎是_better_,在這種情況下,調用方法將有效地在每個3D子數組上傳播調用,而不是讓您手動遍歷每個3D子數組。 (這正是我在我的評論中提出的建議,我很確定Bi Rico在他的答案中的想法。)相反,如果你真的想強制自己迭代陣列,那麼最好用列表他們比一個數組。 – abarnert