Поместить вектор внутри матрицы + преобразование - PullRequest
0 голосов
/ 06 ноября 2018

Итак, у меня есть вектор, созданный с помощью Numpy, который называется

V = [10 20 30 40  0  1]

И я хочу матрицу М вот так:

 [10.  0.  0.  0.  0.  0.]
 [20. 10.  0.  0.  0.  0.]
 [30. 20. 10.  0.  0.  0.]
 [40. 30. 20. 10.  0.  0.]
 [ 0. 40. 30. 20. 10.  0.]
 [ 1.  0. 40. 30. 20. 10.]
 [ 0.  1.  0. 40. 30. 20.]
 [ 0.  0.  1.  0. 40. 30.]
 [ 0.  0.  0.  1.  0. 40.]
 [ 0.  0.  0.  0.  1.  0.]
 [ 0.  0.  0.  0.  0.  1.]

Для этого я использую петли и извлечение вектора, но это слишком долго, потому что мой вектор V имеет 500 столбцов, а матрица M имеет 500*2 -1 строк и 500 столбцов.

Более того, я должен повторить это, по крайней мере, 100 000 раз для другого вектора V

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

Спасибо!

(я использую Python 3.6 на Spyder)

РЕДАКТИРОВАТЬ: Мое решение:

т = 480 п = 10000

t1 = time.time()
for p in range(n):
    for j in range(M.shape[1]):
        M[j:j+t,j] = np.transpose(V[:])
print(time.time()-t1)   

14 секунд всего 10 000 раз ... слишком долго

РЕДАКТИРОВАТЬ 2: тест решения в комментарии:

(Здесь Prate is V)

t1 = time.time()
for p in range(n):
    for j in range(M.shape[1]):
        M[j:j+t,j] = np.transpose(Prate[:])
print(time.time()-t1) 


t1 = time.time()
for p in range(n):
    n = len(Prate)
    m = np.tile(np.concatenate((np.array(Prate), np.zeros(t))), t)[:2*t*t-t]
    result = m.reshape(t, -1).T
print(time.time()-t1)  

t1 = time.time()
for p in range(n):
    ind = np.arange(t)
    indices = ((ind[:,None] + ind).ravel() , np.repeat(ind, t))
    base = np.zeros((n1, t))
    base[indices] = np.tile(Prate, t)
print(time.time()-t1) 

Выход:

16.737313747406006
29.46031618118286 
3.6843104362487793

РЕДАКТИРОВАТЬ 3 : Чтобы не проходить массив в два раза больше требуемого размера, я задаю свой вопрос по-другому:

У меня есть вектор (1x6):

V = [1 20 5 0  0  9]

И я хочу матрицу M (6x6), например:

 [1.  20.  5.  0.  0.  9.]
 [0.  1.  20.  5.  0.  0.]
 [0.  0.  1.  20.  5.  0.]
 [0.  0.  0.  1.  20.  5.]
 [0.  0.  0.  0.  1.  20.]
 [0.  0.  0.  0.   0.  1.]

в каждой строке это один и тот же вектор V (его часть), но со смещением для получения треугольной матрицы.

Как я могу сделать это без петель?

(это простой пример, но реальный вектор V намного больше)

Спасибо: D

Ответы [ 4 ]

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

Используйте следующее:

from scipy.linalg import toeplitz
res=np.tril(toeplitz(V).T

выход:

res
>>array([[10, 20, 30, 40,  0,  1],
         [ 0, 10, 20, 30, 40,  0],
         [ 0,  0, 10, 20, 30, 40],
         [ 0,  0,  0, 10, 20, 30],
         [ 0,  0,  0,  0, 10, 20],
         [ 0,  0,  0,  0,  0, 10]])
0 голосов
/ 06 ноября 2018

Вот векторизованный подход:

In [74]: ind = np.arange(6)

In [75]: indices = ((ind[:,None] + ind).ravel() , np.repeat(ind, 6))

In [76]: base = np.zeros((11, 6))

In [77]: base[indices] = np.tile(V, 6)

In [78]: base
Out[78]: 
array([[10.,  0.,  0.,  0.,  0.,  0.],
       [20., 10.,  0.,  0.,  0.,  0.],
       [30., 20., 10.,  0.,  0.,  0.],
       [40., 30., 20., 10.,  0.,  0.],
       [ 0., 40., 30., 20., 10.,  0.],
       [ 1.,  0., 40., 30., 20., 10.],
       [ 0.,  1.,  0., 40., 30., 20.],
       [ 0.,  0.,  1.,  0., 40., 30.],
       [ 0.,  0.,  0.,  1.,  0., 40.],
       [ 0.,  0.,  0.,  0.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  1.]])
0 голосов
/ 06 ноября 2018

Если вам нужно только быстрое решение, а не решение, которое избегает циклов, вы можете просто использовать Numba или Cython.

Пример

import numpy as np
import numba as nb

@nb.njit()
def create_mat(V):
  arr=np.zeros((V.shape[0],V.shape[0]),dtype=V.dtype)
  for i in range(V.shape[0]):
    for j in range(i,V.shape[0]):
      arr[i,j]=V[j-i]
  return arr

Задержка

V=np.random.rand(10000)
#The first call has an constant compilation overhead of about 0.2s, 
#which is neglected here.
create_mat: 0.35s
0 голосов
/ 06 ноября 2018

Да, для массива v, мы можем сначала создать массив numpy с помощью len (v) extra 0:

n = len(V)
m = np.tile(np.concatenate((V, np.zeros(n))), n)[:2*n*n-n]
result = m.reshape(n, 1).T

Для данного списка V это дает нам:

>>> np.tile(np.concatenate((V, np.zeros(n))), n)[:2*n*n-n].reshape(n,-1).T
array([[10.,  0.,  0.,  0.,  0.,  0.],
       [20., 10.,  0.,  0.,  0.,  0.],
       [30., 20., 10.,  0.,  0.,  0.],
       [40., 30., 20., 10.,  0.,  0.],
       [ 0., 40., 30., 20., 10.,  0.],
       [ 1.,  0., 40., 30., 20., 10.],
       [ 0.,  1.,  0., 40., 30., 20.],
       [ 0.,  0.,  1.,  0., 40., 30.],
       [ 0.,  0.,  0.,  1.,  0., 40.],
       [ 0.,  0.,  0.,  0.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.,  1.]])

Для массива numpy, содержащего 500 элементов и 10 000 запусков, мы получаем:

>>> timeit(f, number=10000)
5.285840999999891

Таким образом, преобразование одного массива из 500 элементов занимает на моей машине 0,5 миллисекунды. Построение всех этих массивов, таким образом, займет примерно 52,86 секунды.

РЕДАКТИРОВАТЬ : Я реализовал три попытки следующим образом:

def wil():
    n = len(V)
    return np.tile(np.concatenate((V, np.zeros(n))), n)[:2*n*n-n].reshape(n,-1).T


def mii():
    n = len(V)
    M = np.zeros((2*n-1, n))
    for j in range(n):
        M[j:j+n,j] = np.transpose(V[:])
    return M


def kas():
    n = len(V)
    ind = np.arange(n)
    indices = ((ind[:,None] + ind).ravel() , np.repeat(ind, n))
    base = np.zeros((2*n-1, n))
    base[indices] = np.tile(V, n)
    return base

и сгенерировал случайный массив из 500 элементов:

V = np.random.randn(500)

затем мы запустили тесты с:

>>> timeit(wil, number=10000)
3.461620999999923
>>> timeit(mii, number=10000)
13.704932000000099
>>> timeit(kas, number=10000)
159.63497699999994 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...