2015-03-04 2 views
0

У меня есть следующий код:Матричное умножение с использованием нарезки. Python

from numpy import * 
a = random.rand(3,4) 
b = random.rand(4,2) 
c = linspace(0,0,6) 
c.shape = (3,2) 
for i in range(a.shape[0]): 
    for j in range(b.shape[1]): 
     for k in range(b.shape[0]): 
     c[i][j] += a[i][k] * b[k][j] 
for r in c: 
    print "C = ", r 

Но мне нужно изменить последний (внутренний) цикл, и мне нужно использовать нарезку. Как я понял, я должен сделать что-то вроде этого:

for i in range(a.shape[0]): 
for j in range(b.shape[1]): 
    c[i][j] += a[i][0:l-1] * b[0:l-1][j] 

Но, к сожалению, это не работает. Может ли кто-нибудь помочь мне и дать подсказку, как это сделать?

+2

Просто из любопытства это для школы, или вы на самом деле пытаетесь сделать матричное умножение для какой-то реалистической цели? Если последний, используйте 'np.dot'. Не зацикливайте массивы Numpy по элементам в Python, если вы можете помочь. – Iguananaut

+0

@Iguananaut На самом деле мне нужно рассчитать и сравнить время вычисления этих двух методов и np.dot. – Sage

ответ

1

То, что вы пытаетесь сделать здесь скалярное произведение вектора-строки из a, и вектор-столбец из b:

c[i][j] += a[i][0:l-1] * b[0:l-1][j] 

который будет

c[i][j] = np.dot(a[i], b[:][j]) 

, который является то же, что и

sum([a_*b_ for a_,b_ in zip(a[i],b[:][j])]) 

или

sum(a[i]*b[:][j]) 

но быстрее.

Однако, если вы используете np.dot, в любом случае:

c = np.dot(a,b) 

, безусловно, быстрее.

0

Давайте начнем с вспомогательную функцию, которая создает ListOfLists (а LoL) из r строк, каждая из которых состоит из c колонн:

In [1]: def lol(r,c): return [[i*c+j for j in range(c)] for i in range(r)] 

и создать два списка списков

In [2]: a = lol(2,5) ; b = lol(5,4) 

Мы хотим чтобы убедиться, что наш код ниже, предназначенный для работы с матричным продуктом с использованием двух LOL, работает правильно, поэтому мы создаем два ndarray s от a и b и формируем их внутренний продукт

In [3]: from numpy import array 

In [4]: aa = array(a) ; ab = array(b) ; aa.dot(ab) 
Out[4]: 
array([[120, 130, 140, 150], 
     [320, 355, 390, 425]]) 

Теперь мы можем проверить наш код для внутренних или матриц, произведение два Lols

In [5]: [[sum(x*y for x, y in zip(ar,bc)) for bc in zip(*b)] for ar in a] 
Out[5]: [[120, 130, 140, 150], [320, 355, 390, 425]] 

Это нормально, не так ли? (Я должен сказать, что на первой итерации кода я вышел с транспонированием результата ...).

Теперь, когда у нас есть немного уверенности, давайте попробуем что-то более существенное

In [6]: a = lol(200,50) ; b = lol(50,400) 

In [7]: aa = array(a) ; ab = array(b) 

In [8]: %timeit c = aa.dot(ab) 
100 loops, best of 3: 4.53 ms per loop 

In [9]: %timeit c = [[sum(x*y for x, y in zip(ar,bc)) for bc in zip(*b)] for ar in a] 
1 loops, best of 3: 469 ms per loop 

Как вы можете видеть, numpy есть два порядка быстрее, чем работает в списках, но это более интересно, в контекст ОП вопрос, чтобы попробовать наш список код на ndarray с:

In [10]: %timeit c = [[sum(x*y for x, y in zip(ar,bc)) for bc in zip(*ab)] for ar in aa] 
1 loops, best of 3: 1.32 s per loop 

о, если у вас есть numpy массивов это лучше использовать методы массива, а не работать на отдельных элементах ... ноподождите, у нас есть более быстрая альтернатива внутренних zip:

In [11]: %timeit c = [[sum(x*y for x, y in zip(ar,bc)) for bc in ab.T] for ar in aa] 
1 loops, best of 3: 1.34 s per loop 

In [12]: 

нет, даже если мы используем транспонирование свойство ndarray мы имеем те же результаты.

Резюме: никогда не использовать по отдельности доступны numpy элементов массива, чтобы сделать тяжелую вычислительную лифтинг ...


Спасибо ipython и его %timeitмагия, что сделал это бессвязное легче и весело (для меня) ,

Смежные вопросы