3 начина за умножение на матрици в Python

В този урок ще научите как да умножите две матрици в Python.

Ще започнете, като научите условието за валидно умножение на матрици и ще напишете персонализирана функция на Python за умножение на матрици. След това ще видите как можете да постигнете същия резултат с помощта на разбиране на вложени списъци.

И накрая, ще продължите да използвате NumPy и неговите вградени функции, за да извършвате по-ефективно умножение на матрици.

Как да проверите дали умножението на матрицата е валидно

Преди да напишем код на Python за матрично умножение, нека преразгледаме основите на матричното умножение.

Умножението на матрица между две матрици A и B е валидно само ако броят на колоните в матрица A е равен на броя на редовете в матрица B.

Вероятно бихте се натъкнали на това условие за умножение на матрица преди. Замисляли ли сте се обаче защо това е така?

Е, това е заради начина, по който работи умножението на матрицата. Разгледайте изображението по-долу.

В нашия общ пример матрица A има m реда и n колони. И матрица B има n реда и p колони.

Каква е формата на продуктовата матрица?

Елементът с индекс (i, j) в резултантната матрица C е точковият продукт на ред i на матрицата A и колона j на матрица B.

Така че, за да получите елемент с определен индекс в резултантната матрица C, ще трябва да изчислите точковия продукт на съответния ред и колона в матрици A и B, съответно.

Повтаряйки горния процес, ще получите продуктовата матрица C с форма mxp—с m реда и p колони, както е показано по-долу.

И скалярният продукт или вътрешният продукт между два вектора a и b се дава от следното уравнение.

Нека да обобщим сега:

  • Очевидно е, че точковият продукт се дефинира само между вектори с еднаква дължина.
  • Така че, за да бъде точковият продукт между ред и колона валиден – когато умножавате две матрици – трябва и двете да имат еднакъв брой елементи.
  • В горния общ пример всеки ред в матрица A има n елемента. И всяка колона в матрица B също има n елемента.

Ако погледнете по-отблизо, n е броят на колоните в матрица A, а също и броят на редовете в матрица B. И точно това е причината, поради която трябва броят на колоните в матрица A да бъде равен на числото от редове в матрица B.

Надявам се, че разбирате условието за валидност на умножението на матрицата и как да получите всеки елемент в матрицата на произведението.

  Какво представляват алгоритмите и защо правят хората неудобни?

Нека продължим да пишем код на Python за умножаване на две матрици.

Напишете персонализирана функция на Python за умножаване на матрици

Като първа стъпка нека напишем персонализирана функция за умножение на матрици.

Тази функция трябва да прави следното:

  • Приемете две матрици, A и B, като входни данни.
  • Проверете дали матричното умножение между A и B е валидно.
  • Ако е валидно, умножете двете матрици A и B и върнете матрицата на произведението C.
  • В противен случай връща съобщение за грешка, че матриците A и B не могат да бъдат умножени.

Стъпка 1: Генерирайте две матрици от цели числа, като използвате функцията random.randint() на NumPy. Можете също така да декларирате матрици като вложени списъци на Python.

import numpy as np
np.random.seed(27)
A = np.random.randint(1,10,size = (3,3))
B = np.random.randint(1,10,size = (3,2))
print(f"Matrix A:n {A}n")
print(f"Matrix B:n {B}n")

# Output
Matrix A:
 [[4 9 9]
 [9 1 6]
 [9 2 3]]

Matrix B:
 [[2 2]
 [5 7]
 [4 4]]

Стъпка 2: Продължете и дефинирайте функцията multiply_matrix(A,B). Тази функция приема две матрици A и B като входни данни и връща произведението матрица C, ако умножението на матрицата е валидно.

def multiply_matrix(A,B):
  global C
  if  A.shape[1] == B.shape[0]:
    C = np.zeros((A.shape[0],B.shape[1]),dtype = int)
    for row in range(rows): 
        for col in range(cols):
            for elt in range(len(B)):
              C[row, col] += A[row, elt] * B[elt, col]
    return C
  else:
    return "Sorry, cannot multiply A and B."

Разбор на дефиницията на функцията

Нека продължим да анализираме дефиницията на функцията.

Декларирайте C като глобална променлива: По подразбиране всички променливи във функция на Python имат локален обхват. И не можете да получите достъп до тях извън функцията. За да направим продуктовата матрица C достъпна отвън, ще трябва да я декларираме като глобална променлива. Просто добавете глобалния квалификатор преди името на променливата.

Проверете дали умножението на матрицата е валидно: Използвайте атрибута shape, за да проверите дали A и B могат да бъдат умножени. За всеки масив arr, arr.shape[0] и обр. форма[1] дайте съответно броя на редовете и колоните. Така че, ако A.shape[1] == B.форма[0] проверява дали умножението на матрицата е валидно. Само ако това условие е вярно, матрицата на продукта ще бъде изчислена. В противен случай функцията връща съобщение за грешка.

Използвайте вложени цикли за изчисляване на стойности: За да изчислим елементите на резултантната матрица, трябва да преминем през редовете на матрица A и външният for цикъл прави това. Вътрешният for цикъл ни помага да преминем през колоната на матрица B. А най-вътрешният for цикъл помага за достъп до всеки елемент в избраната колона.

▶️ Сега, след като научихме как работи функцията на Python за умножение на матрици, нека извикаме функцията с матриците A и B, които генерирахме по-рано.

multiply_matrix(A,B)

# Output
array([[ 89, 107],
       [ 47,  49],
       [ 40,  44]])

Тъй като умножението на матрица между A и B е валидно, функцията multiply_matrix() връща матрицата на продукта C.

  Как да поправите повредени WAV файлове

Използвайте Python разбиране на вложени списъци за умножаване на матрици

В предишния раздел написахте функция на Python за умножаване на матрици. Сега ще видите как можете да използвате разбирането на вложени списъци, за да направите същото.

Ето разбирането на вложен списък за умножаване на матрици.

На пръв поглед това може да изглежда сложно. Но ние ще анализираме разбирането на вложения списък стъпка по стъпка.

Нека се съсредоточим върху едно по едно разбиране на списък и да определим какво прави то.

Ще използваме следния общ шаблон за разбиране на списъка:

[<do-this> for <item> in <iterable>]

where,
<do-this>: what you'd like to do—expression or operation
<item>: each item you'd like to perform the operation on
<iterable>: the iterable (list, tuple, etc.) that you're looping through

▶️ Вижте нашето ръководство за разбиране на списък в Python – с примери, за да получите по-задълбочено разбиране.

Преди да продължим, имайте предвид, че бихме искали да изградим резултантната матрица C ред по ред.

Обяснено разбиране на вложен списък

Стъпка 1: Изчислете една стойност в матрицата C

Като се има предвид ред i на матрица A и колона j на матрица B, изразът по-долу дава запис при индекс (i, j) в матрица C.

sum(a*b for a,b in zip(A_row, B_col)

# zip(A_row, B_col) returns an iterator of tuples
# If A_row = [a1, a2, a3] & B_col = [b1, b2, b3]
# zip(A_row, B_col) returns (a1, b1), (a2, b2), and so on

Ако i = j = 1, изразът ще върне запис c_11 от матрицата C. Така че можете да получите един елемент в един ред по този начин.

Стъпка 2: Изградете един ред в матрицата C

Следващата ни цел е да изградим цял ред.

За ред 1 в матрица A, трябва да преминете през всички колони в матрица B, за да получите един пълен ред в матрица C.

Върнете се към шаблона за разбиране на списъка.

  • Заменете <направете това> с израза от стъпка 1, защото това е, което искате да направите.
  • След това заменете с B_col—всяка колона в матрица B.
  • Накрая заменете с zip(*B) – списъкът, съдържащ всички колони в матрица B.

И ето първото разбиране на списъка.

[sum(a*b for a,b in zip(A_row, B_col)) for B_col in zip(*B)] 

# zip(*B): * is the unzipping operator
# zip(*B) returns a list of columns in matrix B

Стъпка 3: Изграждане на всички редове и получаване на матрицата C

След това ще трябва да попълните продуктовата матрица C, като изчислите останалите редове.

И за това трябва да преминете през всички редове в матрица A.

Върнете се отново към разбирането на списъка и направете следното.

  • Заменете <направете това> с разбирането на списъка от стъпка 2. Припомнете си, че изчислихме цял ред в предишната стъпка.
  • Сега заменете с A_row—всеки ред в матрица A.
  • И вашият е самата матрица A, докато преминавате през нейните редове.

И ето нашето окончателно разбиране на вложен списък.🎊

[[sum(a*b for a,b in zip(A_row, B_col)) for B_col in zip(*B)] 
    for A_row in A]

Време е да проверим резултата! ✔

# cast into <a href="https://pctechbg.net.com/numpy-reshape-arrays-in-python/">NumPy array</a> using np.array()
C = np.array([[sum(a*b for a,b in zip(A_row, B_col)) for B_col in zip(*B)] 
    for A_row in A])

# Output:
[[ 89 107]
 [ 47  49]
 [ 40  44]]

Ако погледнете по-отблизо, това е еквивалентно на вложените цикли for, които имахме по-рано – само че е по-сбито.

Можете също така да направите това много по-ефективно, като използвате някои вградени функции. Нека научим за тях в следващия раздел.

Използвайте NumPy matmul() за умножаване на матрици в Python

np.matmul() приема две матрици като вход и връща продукта, ако умножението на матрици между входните матрици е валидно.

C = np.matmul(A,B)
print(C)

# Output:
[[ 89 107]
 [ 47  49]
 [ 40  44]]

Забележете как този метод е по-прост от двата метода, които научихме по-рано. Всъщност, вместо np.matmul(), можете да използвате еквивалентен оператор @ и ще видим това веднага.

Как да използвате @ оператор в Python за умножение на матрици

В Python @ е двоичен оператор, използван за умножение на матрици.

Той работи с две матрици и като цяло с N-мерни масиви NumPy и връща матрицата на продукта.

Забележка: Трябва да имате Python 3.5 или по-нова версия, за да използвате оператора @.

Ето как можете да го използвате.

C = [email protected]
print(C)

# Output
array([[ 89, 107],
       [ 47,  49],
       [ 40,  44]])

Забележете, че продуктовата матрица C е същата като тази, която получихме по-рано.

Можете ли да използвате np.dot() за умножение на матрици?

Ако някога сте попадали на код, който използва np.dot() за умножение на две матрици, ето как работи.

C = np.dot(A,B)
print(C)

# Output:
[[ 89 107]
 [ 47  49]
 [ 40  44]]

Ще видите, че np.dot(A, B) също връща очакваната продуктова матрица.

Въпреки това, съгласно NumPy документитрябва да използвате np.dot() само за изчисляване на точковия продукт на два едномерни вектора, а не за матрично умножение.

Спомнете си от предишния раздел, елементът с индекс (i, j) на продуктовата матрица C е точковият продукт на ред i на матрица A и колона j на матрица B.

Тъй като NumPy имплицитно излъчва тази операция с точков продукт към всички редове и всички колони, вие получавате резултантната матрица на продукта. Но за да запазите кода си четим и да избегнете двусмислие, използвайте вместо това np.matmul() или оператора @.

Заключение

🎯 В този урок научихте следното.

  • Условие за валидност на умножението на матрицата: брой колони в матрица A = брой редове в матрица B.
  • Как да напишем персонализирана функция на Python, която проверява дали умножението на матрицата е валидно и връща матрицата на продукта. Тялото на функцията използва вложени for цикли.
  • След това научихте как да използвате разбирания на вложени списъци за умножаване на матрици. Те са по-кратки от for циклите, но са склонни към проблеми с четливостта.
  • Най-накрая се научихте да използвате вградената функция на NumPy np.matmul() за умножаване на матрици и как това е най-ефективното по отношение на скоростта.
  • Освен това научихте за оператора @ за умножение на две матрици в Python.

И това приключва нашата дискусия относно умножението на матрици в Python. Като следваща стъпка научете как да проверите дали дадено число е просто в Python. Или решавайте интересни проблеми на низове на Python.

Приятно учене!🎉

  Как да експортирате и импортирате безопасните и блокирани податели на Outlook