简体   繁体   English

子类numpy ndarray问题

[英]Subclassing numpy ndarray problem

I would like to subclass numpy ndarray. 我想继承numpy ndarray。 However, I cannot change the array. 但是,我无法更改阵列。 Why self = ... does not change the array? 为什么self = ...不会改变阵列? Thanks. 谢谢。

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?

The reason you are not getting the result you expect is because you are re-assigning self within the method remove_some . 您没有得到预期结果的原因是因为您在方法remove_some中重新分配self You are just creating a new local variable self . 您只是创建一个新的局部变量self If your array shape were not to change, you could simply do self[:] = ... and you could keep the reference to self and all would be well, but you are trying to change the shape of self . 如果你的数组形状没有改变,你可以简单地做自我[:] = ...你可以保持对self的引用,一切都会很好,但你正试图改变self的形状。 Which means we need to re-allocate some new memory and change where we point when we refer to self . 这意味着我们需要重新分配一些新的内存,并在我们引用self时改变我们所指向的位置。

I don't know how to do this. 我不知道该怎么做。 I thought it could be achieved by __array_finalize__ or __array__ or __array_wrap__ . 我认为可以通过__array_finalize____array____array_wrap__来实现。 But everything I've tried is falling short. 但我所尝试的一切都不尽如人意。

Now, there's another way to go about this that doesn't subclass ndarray . 现在,还有另一种方法可以解决这个问题,而不是ndarray子类。 You can make a new class that keeps an attribute that is an ndarray and then override all the usual __add__ , __mul__ , etc.. Something like this: 你可以创建一个新的类来保存一个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)

Well, you get the picture. 好吧,你明白了。 It's a pain to override all the operators, but in the long run, I think more flexible. 覆盖所有操作员是一种痛苦,但从长远来看,我认为更灵活。

You'll have to read this thoroughly to do it right. 你必须阅读彻底把事情做对。 There are methods like __array_finalize__ that need to be called a the right time to do "cleanup". __array_finalize__这样的方法需要被称为正确的“清理”时间。

Perhaps make this a function, rather than a method: 也许这是一个函数,而不是一个方法:

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')])

Or, if you want it as a method, 或者,如果你想要它作为一种方法,

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)

The key difference here is that remove_some does not try to modify self , it merely returns a new instance of Data . 这里的关键区别是remove_some不会尝试修改self ,它只返回一个新的Data实例。

I tried to do the same, but it is really very complex to subclass ndarray. 我尝试做同样的事情,但是将ndarray子类化为非常复杂。

If you only have to add some functionality, I would suggest to create a class which stores the array as attribute. 如果您只需要添加一些功能,我建议创建一个将数组存储为属性的类。

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM