Подклассы Python NumPy ndarray для изменения смещения - PullRequest
0 голосов
/ 22 мая 2018

Я работаю над платформой для обработки входящих данных.

Данные получены из сокета и добавлены в массив n (для использования в качестве буфера) с использованием сдвига, например:

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 и добавляю новое значение в конце.Однако для автономного тестирования я хочу загрузить все данные в начале фреймворка и запустить все остальное, как раньше (то есть те же классы, реализующие обработку данных).Конечно, я могу снова создать буфер A, используя массив нулей, и переместить его с новыми значениями.Однако это включает в себя копирование данных между двумя массивами, что абсолютно не нужно - требует времени и памяти.

Я думал о том, чтобы предоставить способ изменить границы массива numpy или изменить A.data.указатель.Тем не менее, все решения не разрешены или приводят к появлению предупреждающего сообщения.

Наконец, я пытаюсь изменить внутреннее смещение массива A, чтобы я мог его увеличить и, таким образом, сделать больше данных доступным для алгоритмов.Что важно, self.data[-1] должен всегда указывать на вновь появившийся образец, и должен использоваться стандартный API для массива numpy.

У меня есть подкласс 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 не принесли никаких результатов.

1 Ответ

0 голосов
/ 23 мая 2018

Я восхищаюсь вашей храбростью, но я вполне уверен, что подклассификация массивов numpy для вашей проблемы излишня и может причинить вам огромную головную боль.В конце концов это может привести к снижению производительности где-то, что намного превосходит копирование массива, которого вы пытаетесь избежать.

Почему бы не сделать срез (т.е. [-4:] или slice(-4, None)) параметром для вашего * 1005?* Функция или атрибут класса и переопределить это в вашем тесте?

def __init__(self, lastfour=slice(-4, None)):
    self.myData = self.data[lastfour]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...