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 не можна перемножити.
  Як виправити збій гри Steam під час запуску (повний посібник)

Крок 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 доступною ззовні, нам доведеться оголосити її як глобальну змінну. Просто додайте глобальний кваліфікатор перед назвою змінної.

Перевірте, чи дійсне множення матриці: використовуйте атрибут форми, щоб перевірити, чи можна помножити 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.

Використовуйте Python Nested List Comprehension для множення матриць

У попередньому розділі ви написали функцію Python для множення матриць. Тепер ви побачите, як ви можете використовувати розуміння вкладених списків, щоб зробити те саме.

Ось розуміння вкладеного списку для множення матриць.

Спочатку це може здатися складним. Але ми розберемо розуміння вкладеного списку крок за кроком.

Давайте зосередимося на одному розумінні списку за раз і визначимо, що він робить.

  Що означає «IDK» і як ви його використовуєте?

Ми будемо використовувати такий загальний шаблон для розуміння списку:

[<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://techukraine.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.

Гарного навчання!🎉

  Як додати умовне форматування до комірок у таблицях Google