Как эффективно индексировать массивный массив на основе разных индексов запуска и остановки для каждой строки - PullRequest
1 голос
/ 24 октября 2019

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

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

import numpy as np
import matplotlib.pyplot as plt

# Amount of time series to consider
batchsize = 25

# Original length of the time series
timesteps = 150

# As an example, fill the 2D array with sine function time series
sinefunction = np.expand_dims(np.sin(np.arange(timesteps)), axis=0)
originalarray = np.repeat(sinefunction, batchsize, axis=0)

# Now the real thing, we want:
# - to start the time series at a random moment (between 0 and maxstart)
# - to end the time series at a random moment
# - however with a minimum length of the resulting subset time series (minlength)
maxstart = 50
minlength = 75

# get random starts
randomstarts = np.random.choice(np.arange(0, maxstart), size=batchsize)

# get random stops
randomstops = np.random.choice(np.arange(maxstart + minlength, timesteps), size=batchsize)

# determine the resulting random sizes of the subset time series
randomsizes = randomstops - randomstarts

# finally create a new 2D array with all the randomly subset time series, however pre-padded with zeros
# THIS IS THE FOR LOOP WE SHOULD TRY TO AVOID
cutarray = np.zeros_like(originalarray)
for i in range(batchsize):
    cutarray[i, -randomsizes[i]:] = originalarray[i, randomstarts[i]:randomstops[i]]

Чтобы показать, что входит и выходит из функции:

# Show that it worked
f, ax = plt.subplots(2, 1)
ax[0].imshow(originalarray)
ax[0].set_title('original array')
ax[1].imshow(cutarray)
ax[1].set_title('zero-padded subset array')

Example of the desired functionality

1 Ответ

1 голос
/ 24 октября 2019

Подход № 1: на основе просмотров

Мы можем использовать np.lib.stride_tricks.as_strided на основе scikit-image's view_as_windows, чтобы получить скользящие оконные видыверсия ввода с дополнением нулями и присвоение версии вывода с дополнением нулями. Все это дополнение необходимо для векторизованного решения из-за неровной природы. И наоборот, работа с представлениями будет эффективна с точки зрения памяти и производительности.

Реализация будет выглядеть примерно так -

from skimage.util.shape import view_as_windows

n = randomsizes.max()
max_extent = randomstarts.max()+n
padlen = max_extent - origalarray.shape[1]
p = np.zeros((origalarray.shape[0],padlen),dtype=origalarray.dtype)
a = np.hstack((origalarray,p))
w = view_as_windows(a,(1,n))[...,0,:]
out_vals = w[np.arange(len(randomstarts)),randomstarts]

out_starts = origalarray.shape[1]-randomsizes    
out_extensions_max = out_starts.max()+n

out = np.zeros((origalarray.shape[0],out_extensions_max),dtype=origalarray.dtype)
w2 = view_as_windows(out,(1,n))[...,0,:]
w2[np.arange(len(out_starts)),out_starts] = out_vals
cutarray_out = out[:,:origalarray.shape[1]]

Подход № 2. С masking

cutarray_out = np.zeros_like(origalarray)
r = np.arange(origalarray.shape[1])
m = (randomstarts[:,None]<=r) & (randomstops[:,None]>r)
s = origalarray.shape[1]-randomsizes
m2 = s[:,None]<=r
cutarray_out[m2] = origalarray[m]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...