зацикливание на numpy массиве v / s отображающие функции? - PullRequest
2 голосов
/ 09 июня 2019

У меня есть вопрос улучшения скорости / читабельности.У меня есть N временных рядов длины T в матрице Y (dim = TxN).У меня также есть 3D Matrix X, который является TxNxK.

Данные имеют некоторые случайные значения NaN.

Учитывая заданное окно регрессии (W), цель состоит в том, чтобы создать прогноз Y, используя данные от X.с учетом того, что для любого отдельного временного ряда Y регрессия должна превышать последние доступные W значений переменных.Это означает, что вам нужны все переменные X и соответствующие переменные серии Y, но вам не нужны другие переменные Y.

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

import random
import numpy as np
from numpy.linalg import inv

# Parameters
N = 500  #Number of time series
T = 1000 #Length of each time series
W = 72   #Regression window
K = 3    #Numer of independent variables

Y = np.random.randn(T, N)
X = np.random.randn(T, N, K)

# Add the constants
X = np.concatenate((X, np.ones((T, N, 1))), axis=2)

def get_rand_arr(arr, frac_rand=0.0001):
    ix = [(row, col) for row in range(arr.shape[0]) for col in range(arr.shape[1])]
    for row, col in random.sample(ix, int(round(frac_rand*len(ix)))):
        arr[row, col] = np.nan
    return arr

# Insert some NaN values - like the real world - I dont care about this loop
Y = get_rand_arr(Y)
for i in range(X.shape[2]):
    X[:, :, i] = get_rand_arr(X[:, :, i])

X_mask = np.apply_along_axis(np.any, 1, np.apply_along_axis(np.any, 2, np.isnan(X)))
Y_mask = np.concatenate([np.logical_or(np.isnan(Y)[:, i],X_mask).reshape(-1,1) for i in range(N)],axis=1)

Y_hat = np.NaN*np.zeros((T, N))
for j in range(N):
    y = Y[~Y_mask[:, j], j]
    x = X[~Y_mask[:, j], j, :]
    y_hat = np.NaN*np.zeros(y.shape[0])
    for i in range(y_hat.shape[0]-W):
        y_hat[i+W] = x[i+W, :].dot(inv(x[i:i+W, :].T.dot(x[i:i+W, :])).dot(x[i:i+W, :].T.dot(y[i:i+W])))
    Y_hat[~Y_mask[:, j], j] =  y_hat

Я получаю следующие результаты времени

%%timeit
Y_hat = np.NaN*np.zeros((T, N))
for j in range(N):
    y = Y[~Y_mask[:, j], j]
    x = X[~Y_mask[:, j], j, :]
    y_hat = np.NaN*np.zeros(y.shape[0])
    for i in range(y_hat.shape[0]-W):
        y_hat[i+W] = x[i+W, :].dot(inv(x[i:i+W, :].T.dot(x[i:i+W, :])).dot(x[i:i+W, :].T.dot(y[i:i+W])))
    Y_hat[~Y_mask[:, j], j] =  y_hat
9.5 s ± 373 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Временной ряд достаточно длинный, и окно регрессиидостаточно мала, поэтому мне не нужно беспокоиться о том, чтобы у меня было достаточно значений для выполнения хотя бы одной регрессии.

...