2011-03-01 100 views
9

我想要numpy ndarray的子​​类。但是,我无法更改该数组。为什么self = ...不更改数组?谢谢。subclassing numpy ndarray问题

import numpy as np 

class Data(np.ndarray): 

    def __new__(cls, inputarr): 
     obj = np.asarray(inputarr).view(cls) 
     return obj 

    def remove_some(self, t): 
     test_cols, test_vals = zip(*t) 
     test_cols = self[list(test_cols)] 
     test_vals = np.array(test_vals, test_cols.dtype) 

     self = self[test_cols != test_vals] # Is this part correct? 

     print len(self) # correct result 

z = np.array([(1,2,3), (4,5,6), (7,8,9)], 
    dtype=[('a', int), ('b', int), ('c', int)]) 
d = Data(z) 
d.remove_some([('a',4)]) 

print len(d) # output the same size as original. Why? 
+0

请提供您的预期输出,但不清楚您想要达到的效果。 – 2011-03-01 02:13:21

+0

我想从数据实例中删除行。 – riza 2011-03-01 04:12:55

+0

好的,你可以使用一个掩码,但如果你问另一个问题会更好,因为这跟子类化ndarray – 2011-03-01 06:54:44

回答

4

或许使这一功能,而不是一个方法:

import numpy as np 

def remove_row(arr,col,val): 
    return arr[arr[col]!=val] 

z = np.array([(1,2,3), (4,5,6), (7,8,9)], 
    dtype=[('a', int), ('b', int), ('c', int)]) 

z=remove_row(z,'a',4) 
print(repr(z)) 

# array([(1, 2, 3), (7, 8, 9)], 
#  dtype=[('a', '<i4'), ('b', '<i4'), ('c', '<i4')]) 

或者,如果你想让它作为一种方法,

import numpy as np 

class Data(np.ndarray): 

    def __new__(cls, inputarr): 
     obj = np.asarray(inputarr).view(cls) 
     return obj 

    def remove_some(self, col, val): 
     return self[self[col] != val] 

z = np.array([(1,2,3), (4,5,6), (7,8,9)], 
    dtype=[('a', int), ('b', int), ('c', int)]) 
d = Data(z) 
d = d.remove_some('a', 4) 
print(d) 

这里的关键区别在于remove_some不会尝试修改self,它只会返回一个新实例Data

+0

这可能对问题有帮助,但不是答案。为什么自我= ...不改变价值?也许答案在下面?否则我会转贴。 – mathtick 2012-10-03 21:21:08

+0

想象'd',你的'Data'实例。它指向一个包含底层数据的内存块。要移除一列* in-place *,您必须将其他列移动到一起,然后重新调整数组的大小。当你说'self = some_other_array'时,你正在将变量名'self'重定向到另一块内存。然而,在'remove_row'方法之外,变量名称'd'仍然指向原始内存块。所以它不能修改'd'。 – unutbu 2012-10-03 22:11:31

+0

我读过的有关numpy的所有建议都说不应该尝试调整numpy数组的大小。这是可能的,但所有的复制都会让它变慢。最好使用slice来创建视图,或者使用幻想索引来创建具有所需数据的新阵列。是的,创建一个新的阵列还涉及到复制,但至少可以省去就地转移数据的复杂性。 – unutbu 2012-10-03 22:19:57

6

你没有得到你所期望的结果的原因是因为你的方法remove_some内重新分配self。您只是创建一个新的本地变量self。如果你的阵列形状不改变,你可以简单地做self [:] = ...并且你可以保持对self的引用,并且一切都会好,但是你试图改变self的形状。这意味着我们需要重新分配一些新的内存,并改变我们指向self的位置。

我不知道该怎么做。我认为这可以通过__array_finalize____array____array_wrap__来实现。但是我所尝试过的一切都不尽如人意。

现在,还有另外一种方法可以解决这个问题,它不会继承ndarray。你可以做一个新的类,它可将是一个ndarray,然后覆盖所有常见__add____mul__,等等。事情是这样的一个属性:

Class Data(object): 
    def __init__(self, inarr): 
     self._array = np.array(inarr) 
    def remove_some(x): 
     self._array = self._array[x] 
    def __add__(self, other): 
     return np.add(self._array, other) 

那么,你得到的图片。覆盖所有运营商是一种痛苦,但从长远来看,我认为更灵活。

您必须仔细阅读this才能正确操作。像__array_finalize__这样的方法需要被称为是“清理”的正确时间。

+0

我认为'__array_finalize__'被用于新的实例启动时,例如添加额外的属性。 – riza 2011-03-01 01:06:44

+0

我以为只要你像OP那样重新分配数组,它就不得不被调用。但说实话,这是我的头。'__array_wrap__'似乎更接近想要的,但只有在被一个ufunc调用时才会返回。 – Paul 2011-03-01 01:44:25

3

我试图做同样的事情,但子类ndarray确实非常复杂。

如果你只需要添加一些功能,我会建议创建一个存储数组作为属性的类。

class Data(object): 

    def __init__(self, array): 
     self.array = array 

    def remove_some(self, t): 
     //operate on self.array 
     pass 

d = Data(z) 
print(d.array) 
+0

[关于如何创建子类别的文档](https://docs.scipy.org/doc/numpy/user/basics.subclassing.html)可能有助于简化它。 – Sardathrion 2017-07-18 10:10:07