Перестановка матрицы рефакторинга в стиле numpy - PullRequest
0 голосов
/ 24 ноября 2018

Я написал следующий код для умножения перестановок матриц, и мне было интересно, можно ли его написать в стиле numpy, чтобы я мог избавиться от двух циклов for:

Z = np.empty([new_d, X.shape[1]])
Z = np.ndarray(shape=(new_d, X.shape[1]))
Z = np.concatenate((X, X**2))
res = []
for i in range(0, d):
    for j in range(i+1, d):
        res.append(np.array(X.T[:,i]* X.T[:,j]))

Z = np.concatenate((Z, res))

while: X shape is (7, 1000), d = 7, new_d=35

есть предложения?

1 Ответ

0 голосов
/ 24 ноября 2018

Подход № 1

Мы могли бы использовать np.triu_indices, чтобы получить эти попарные индексы перестановки, а затем просто выполнить поэлементное умножение массивов с индексированными строками-

r,c = np.triu_indices(d,1)
res = X[r]*X[c]

Подход № 2

Для эффективности памяти и, следовательно, производительности, особенно для больших массивов, нам лучше нарезать входной массив и запустить один цикл скаждая итерация работает с порциями данных, например:

n = d-1
idx = np.concatenate(( [0], np.arange(n,0,-1).cumsum() ))
start, stop = idx[:-1], idx[1:]
L = n*(n+1)//2
res_out = np.empty((L,X.shape[1]), dtype=X.dtype)
for i,(s0,s1) in enumerate(zip(start,stop)):
    res_out[s0:s1] = X[i] * X[i+1:]

Чтобы получить Z напрямую и, таким образом, избежать всех этих объединений, мы могли бы изменить ранее опубликованный подход, например так: *

n = d-1
N = len(X)
idx = 2*N + np.concatenate(( [0], np.arange(n,0,-1).cumsum() ))
start, stop = idx[:-1], idx[1:]
L = n*(n+1)//2
Z_out = np.empty((2*N + L,X.shape[1]), dtype=X.dtype)
Z_out[:N] = X
Z_out[N:2*N] = X**2
for i,(s0,s1) in enumerate(zip(start,stop)):
    Z_out[s0:s1] = X[i] * X[i+1:]
...