Как я могу масштабировать набор 2D-массивов (3D-массив) по 2D-массиву векторизованным способом, используя NumPy? - PullRequest
1 голос
/ 19 апреля 2020

У меня есть 3D-матрица, содержащая N x N ковариационных матриц для M каналов [M x N x N]. У меня также есть двумерная матрица коэффициентов масштабирования для каждого канала в серии моментов времени [M x T]. Я хочу создать матрицу 4D, содержащую масштабированную версию ковариации соответствующего канала в каждый момент времени. Чтобы было ясно, [M x T] * [M x N x N] -> [M x T x N x N]

Текущая версия, используемая для циклов:

m, t, n = 4, 10, 7
channel_timeseries = np.zeros((m, t))
covariances = np.random.rand(m, n, n)

result_array = np.zeros((m, t, n, n))

# Each channel
for i, (channel_cov, channel_timeseries) in enumerate(zip(covariances, channel_timeseries)):
    # Each time point
    for j, time_point in enumerate(channel_timeseries):
        result_array[i, j] = time_point * channel_cov

Это должно привести к тому, что массив результатов будет иметь все нули. Заменив инициализацию channel_timeseries на np.ones, мы должны увидеть ковариацию для каждого реплицированного канала без изменений на каждом шаге временного ряда.

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

Как вы можете видеть выше, я могу сделать это с помощью a для l oop и он работает совершенно нормально, но я работаю с некоторыми огромными наборами данных, и было бы лучше иметь векторизованное решение.

Большое спасибо за ваше время.

Ответы [ 2 ]

1 голос
/ 19 апреля 2020

Вы можете использовать np.einsum, , как сказал б-фг

np.einsum('mt,mno->mtno', channel_timeseries, covariances)

или Вещание:

channel_timeseries[:, :, None, None] * covariances[:, None, :, :]
1 голос
/ 19 апреля 2020

numpy.einsum пригодится здесь. Я изменил ваш код со случайным массивом channel_timeseries, увеличил размер массивов и переименовал переменные l oop (в противном случае вы перезаписываете исходные!)

import numpy as np
import time

m, t, n = 40, 100, 70
channel_timeseries = np.random.rand(m, t)
covariances = np.random.rand(m, n, n)

t0 = time.time()
result_array_1 = np.zeros((m, t, n, n))
# Each channel
for i, (c_cov, c_ts) in enumerate(zip(covariances, channel_timeseries)):
    # Each time point
    for j, time_point in enumerate(c_ts):
        result_array_1[i, j] = time_point * c_cov
t1 = time.time()
result_array_2 = np.einsum('ij,ikl->ijkl', channel_timeseries, covariances)
t2 = time.time()

print(np.array_equal(result_array_1, result_array_2)) # True
print('Time for result_array_1: ', t1-t0) # 0.07601261138916016
print('Time for result_array_2: ', t2-t1) # 0.02957916259765625

Это приводит к увеличению скорости более 50% с numpy.einsum в моей машине.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...