【问题标题】:python numpy ndarray subclassing for offset changingpython numpy ndarray 子类化以改变偏移量
【发布时间】:2018-05-22 17:10:43
【问题描述】:

我正在研究处理传入数据的框架。

从套接字接收数据并使用移位将数据添加到 numpy 数组 A(用作缓冲区),例如:

A[:-1] = A[1:]
A[-1] = value

框架允许将处理单元加载为可以使用指向 A 的数组视图访问传入数据的类。每次接收新数据并将其存储在 A 中时,都会调用方法 execute()

def execute(self,):
    newSample = self.data[-1]

重要的是新样本始终位于index = -1 下。 用户还可以在__init__ 函数中创建自己的数组视图:

def __init__(self,):
    self.myData = self.data[-4:]  # view that contains last 4 samples

当我移动数组 A 并在最后添加新值时,一切都很好。但是,对于离线测试,我想在框架开始时加载所有数据并像以前一样运行其他所有内容(即实现数据处理的相同类)。 当然,我可以再次使用 zeros 数组创建 A 缓冲区并使用新值对其进行移位。但是,这涉及到在两个数组之间复制数据,这是绝对没有必要的 - 需要时间和内存。

我在想的是提供一种方法来改变 numpy 数组的边界或改变 A.data 指针。但是,所有解决方案都不允许或导致警告消息。

最后,我正在尝试更改数组 A 的内部偏移量,以便我可以推进它,从而为算法提供更多数据。重要的是,self.data[-1] 必须始终指向新出现的样本,并且应该使用标准的 numpy 数组 API。

我对 np.ndarray 进行了子类化:

class MyArrayView(np.ndarray):
    def __new__(cls, input_array):
        obj = np.asarray(input_array).view(cls)
        # add the new attribute to the created instance
        obj._offset = 0
        # Finally, we must return the newly created object:
        return obj

    def __array_finalize__(self, obj):
        if obj is None:
            return
        self._offset = getattr(obj, '_offset', None)

    def advance_index(self):
        self._offset += 1

    def __str__(self):
        return super(MyArrayView, self[:]).__str__()

    def __repr__(self):
        return super(MyArrayView, self[:]).__repr__()

    def __getitem__(self, idx):
        if isinstance(idx, slice):
            start = 0
            stop = self._offset
            step = idx.step
            idx = slice(start, stop, step)
        else:
            idx = self._offset + idx
        return super(MyArrayView, self).__getitem__(idx)

这允许我执行以下操作:

a = np.array([1,2,3,4,5,6,7,8,9,10])
myA = MyArrayView(a)
b = myA
print("b :", b)
for i in range(1,5):
    myA.advance_index()
    print(b[:], b[-1])

print("b :", b)
print("b + 10 :", b + 10)
print("b[:] + 20 :", b[:] + 20)

并给出以下输出:

b : []
[1] 1
[1 2] 2
[1 2 3] 3
[1 2 3 4] 4
b : [1 2 3 4]
b + 10 : [11 12 13 14]
b[:] + 20 : [21 22 23 24]

到目前为止一切顺利。但是,如果我检查形状:

print("shape", b[:].shape)  # shape (4,)
print("shape", b.shape)     # shape (10,)

这两种情况是不同的。我尝试使用:shape=(self.internalIndex,) 对其进行更改,但它只会导致我出现错误消息。

我想问你是否认为这是我正在做的正确方式,它只需要在 np.ndarray 类中重载更多函数。或者我应该完全放弃这个解决方案并使用新样本回退到移动阵列?或者是否可以使用标准的 np.ndarray 实现来实现,因为我需要使用标准的 numpy API。

我也试过这个:

a = np.array([1,2,3,4,5,6,7,8,9,10])
b = a.view()[5:]

print(a.data)  # <memory at 0x7f09e01d8f48>
print(b.data)  # <memory at 0x7f09e01d8f48> They point to the same memory start!

print(np.byte_bounds(a)) # (50237824, 50237904)
print(np.byte_bounds(b)) # (50237864, 50237904) but the byte_bounds are different

因此,考虑到这一点,我想说我需要创建数组 a 的视图并扩展它(或者至少像窗口一样将它移动到 a 之上)。 但是,我所有更改 byte_bounds 的尝试都没有带来任何效果。

【问题讨论】:

    标签: python numpy subclass offset


    【解决方案1】:

    我很佩服你的勇气,但我很确定对 numpy 数组进行子分类对于你的问题来说太过分了,而且会让你非常头疼。最后,它可能会导致性能下降,远远超出您试图避免的数组复制。

    为什么不将切片(即[-4:]slice(-4, None))作为__init__ 函数或类属性的参数并在测试中覆盖它?

    def __init__(self, lastfour=slice(-4, None)):
        self.myData = self.data[lastfour]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-14
      • 2015-09-25
      • 1970-01-01
      • 2021-08-05
      • 2023-03-15
      • 2013-10-13
      • 2011-05-02
      • 2014-04-22
      相关资源
      最近更新 更多