3 sposoby mnożenia macierzy w Pythonie

W tym samouczku dowiesz się, jak mnożyć dwie macierze w Pythonie.

Zaczniesz od poznania warunku prawidłowego mnożenia macierzy i napisania niestandardowej funkcji Pythona do mnożenia macierzy. Następnie zobaczysz, jak możesz osiągnąć ten sam wynik, używając zagnieżdżonych list składanych.

Na koniec przejdziesz do korzystania z NumPy i jego wbudowanych funkcji, aby wydajniej wykonywać mnożenie macierzy.

Jak sprawdzić, czy mnożenie macierzy jest prawidłowe?

Zanim napiszemy kod Pythona do mnożenia macierzy, przyjrzyjmy się podstawom mnożenia macierzy.

Mnożenie macierzy między dwiema macierzami A i B jest poprawne tylko wtedy, gdy liczba kolumn w macierzy A jest równa liczbie wierszy w macierzy B.

Prawdopodobnie spotkałbyś się już wcześniej z tym warunkiem mnożenia macierzy. Jednak czy kiedykolwiek zastanawiałeś się, dlaczego tak jest?

Cóż, to ze względu na sposób, w jaki działa mnożenie macierzy. Spójrz na poniższy obrazek.

W naszym ogólnym przykładzie macierz A ma m wierszy i n kolumn. A macierz B ma n wierszy ip kolumn.

Jaki jest kształt matrycy produktów?

Element o indeksie (i, j) w wynikowej macierzy C jest iloczynem skalarnym wiersza i macierzy A i kolumny j macierzy B.

Tak więc, aby uzyskać element o określonym indeksie w wynikowej macierzy C, musisz obliczyć iloczyn skalarny odpowiedniego wiersza i kolumny w macierzach A i B, odpowiednio.

Powtarzając powyższy proces, otrzymasz macierz produktu C o kształcie mxp — z m wierszami i p kolumnami, jak pokazano poniżej.

Iloczyn skalarny lub iloczyn skalarny między dwoma wektorami a i b jest podany przez następujące równanie.

Podsumujmy teraz:

  • Jest oczywiste, że iloczyn skalarny jest zdefiniowany tylko pomiędzy wektorami o jednakowej długości.
  • Tak więc, aby iloczyn skalarny między wierszem a kolumną był poprawny — przy mnożeniu dwóch macierzy — trzeba by obie miały taką samą liczbę elementów.
  • W powyższym ogólnym przykładzie każdy wiersz w macierzy A ma n elementów. A każda kolumna w macierzy B też ma n elementów.

Jeśli przyjrzysz się bliżej, n to liczba kolumn w macierzy A, a także liczba wierszy w macierzy B. I właśnie dlatego potrzebujesz, aby liczba kolumn w macierzy A była równa liczbie wierszy w macierzy B.

Mam nadzieję, że rozumiesz warunek, aby mnożenie macierzy było prawidłowe i jak uzyskać każdy element w macierzy produktu.

Przejdźmy do napisania kodu w Pythonie, który pomnoży dwie macierze.

Napisz niestandardową funkcję Pythona do mnożenia macierzy

Jako pierwszy krok, napiszmy niestandardową funkcję mnożącą macierze.

Ta funkcja powinna wykonywać następujące czynności:

  • Zaakceptuj dwie macierze, A i B, jako dane wejściowe.
  • Sprawdź, czy mnożenie macierzy między A i B jest prawidłowe.
  • Jeśli jest poprawna, pomnóż dwie macierze A i B i zwróć macierz iloczynów C.
  • W przeciwnym razie zwróć komunikat o błędzie, że macierze A i B nie mogą być pomnożone.

Krok 1: Wygeneruj dwie macierze liczb całkowitych za pomocą funkcji random.randint() NumPy. Możesz także deklarować macierze jako zagnieżdżone listy Pythona.

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]]

Krok 2: Śmiało i zdefiniuj funkcję multiply_matrix(A,B). Ta funkcja pobiera dwie macierze A i B jako dane wejściowe i zwraca macierz iloczynu C, jeśli mnożenie macierzy jest prawidłowe.

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."

Analiza definicji funkcji

Przejdźmy do parsowania definicji funkcji.

Zadeklaruj C jako zmienną globalną: Domyślnie wszystkie zmienne wewnątrz funkcji Pythona mają zasięg lokalny. I nie możesz uzyskać do nich dostępu spoza funkcji. Aby macierz iloczynu C była dostępna z zewnątrz, będziemy musieli zadeklarować ją jako zmienną globalną. Wystarczy dodać kwalifikator globalny przed nazwą zmiennej.

Sprawdź, czy mnożenie macierzy jest prawidłowe: Użyj atrybutu kształtu, aby sprawdzić, czy można mnożyć A i B. Dla dowolnej tablicy arr, arr.shape[0] i arr.kształt[1] podaj odpowiednio liczbę wierszy i kolumn. Więc jeśli A.kształt[1] == B.kształt[0] sprawdza, czy mnożenie macierzy jest prawidłowe. Tylko jeśli ten warunek ma wartość Prawda, zostanie obliczona macierz iloczynu. W przeciwnym razie funkcja zwraca komunikat o błędzie.

Użyj zagnieżdżonych pętli do obliczenia wartości: Aby obliczyć elementy macierzy wynikowej, musimy przejść przez rzędy macierzy A, a robi to zewnętrzna pętla for. Wewnętrzna pętla for pomaga nam przechodzić przez kolumnę macierzy B. A najbardziej wewnętrzna pętla for pomaga uzyskać dostęp do każdego elementu w wybranej kolumnie.

▶️ Teraz, gdy dowiedzieliśmy się, jak działa funkcja mnożenia macierzy w Pythonie, wywołajmy funkcję z macierzami A i B, które wygenerowaliśmy wcześniej.

multiply_matrix(A,B)

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

Ponieważ mnożenie macierzy między A i B jest prawidłowe, funkcja multiply_matrix() zwraca macierz iloczynu C.

Użyj zagnieżdżonej listy składanej w Pythonie do pomnożenia macierzy

W poprzedniej sekcji napisałeś funkcję Pythona do mnożenia macierzy. Teraz zobaczysz, jak możesz użyć zagnieżdżonych list składanych, aby zrobić to samo.

Oto zagnieżdżona lista składana do mnożenia macierzy.

Na początku może się to wydawać skomplikowane. Ale krok po kroku przeanalizujemy zagnieżdżoną listę.

Skoncentrujmy się na jednym zrozumieniu listy na raz i określmy, co ona robi.

Do zrozumienia listy użyjemy następującego ogólnego szablonu:

[<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

▶️ Sprawdź nasz przewodnik List Comprehension in Python – z przykładami, aby uzyskać dogłębne zrozumienie.

Zanim przejdziemy dalej, zwróć uwagę, że chcielibyśmy zbudować wynikową macierz C po jednym wierszu.

Wyjaśnienie zagnieżdżonej listy ze zrozumieniem

Krok 1: Oblicz pojedynczą wartość w macierzy C

Biorąc pod uwagę wiersz i macierzy A i kolumnę j macierzy B, poniższe wyrażenie daje wpis o indeksie (i, j) w macierzy 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

Jeśli i = j = 1, wyrażenie zwróci wpis c_11 macierzy C. W ten sposób możesz uzyskać jeden element w jednym wierszu.

Krok 2: Zbuduj jeden wiersz w macierzy C

Naszym kolejnym celem jest zbudowanie całego rzędu.

W przypadku wiersza 1 w macierzy A musisz przejść pętlą przez wszystkie kolumny w macierzy B, aby uzyskać jeden pełny wiersz w macierzy C.

Wróć do szablonu listy ze zrozumieniem.

  • Zastąp wyrażeniem z kroku 1, ponieważ właśnie to chcesz zrobić.
  • Następnie zamień na B_col — każda kolumna w macierzy B.
  • Na koniec zamień na zip(*B) — listę zawierającą wszystkie kolumny w macierzy B.

A oto pierwsze rozumienie listy.

[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

Krok 3: Zbuduj wszystkie wiersze i uzyskaj macierz C

Następnie będziesz musiał wypełnić macierz iloczynów C, obliczając pozostałe wiersze.

W tym celu musisz wykonać pętlę przez wszystkie wiersze w macierzy A.

Wróć jeszcze raz do zrozumienia listy i wykonaj następujące czynności.

  • Zastąp wyrażeniem listy z kroku 2. Przypomnij sobie, że w poprzednim kroku obliczyliśmy cały wiersz.
  • Teraz zamień na A_row — każdy wiersz w macierzy A.
  • A twoją jest sama macierz A, gdy przeglądasz jej wiersze.

A oto nasze ostateczne zrozumienie zagnieżdżonej listy.🎊

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

Czas zweryfikować wynik! ✔

# cast into <a href="https://newsblog.pl.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]]

Jeśli przyjrzysz się bliżej, jest to odpowiednik zagnieżdżonych pętli for, które mieliśmy wcześniej — tylko, że jest bardziej zwięzły.

Możesz to zrobić jeszcze wydajniej, korzystając z niektórych wbudowanych funkcji. Dowiedzmy się o nich w następnej sekcji.

Użyj NumPy matmul() do pomnożenia macierzy w Pythonie

Funkcja np. matmul() przyjmuje dwie macierze jako dane wejściowe i zwraca iloczyn, jeśli mnożenie macierzy między macierzami wejściowymi jest prawidłowe.

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

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

Zauważ, że ta metoda jest prostsza niż dwie metody, których nauczyliśmy się wcześniej. W rzeczywistości zamiast np.matmul() możesz użyć równoważnego operatora @ i zobaczymy to od razu.

Jak używać operatora @ w Pythonie do mnożenia macierzy?

W Pythonie @ jest operatorem binarnym używanym do mnożenia macierzy.

Działa na dwóch macierzach i ogólnie na N-wymiarowych tablicach NumPy i zwraca macierz iloczynu.

Uwaga: Aby używać operatora @, musisz mieć Pythona 3.5 lub nowszego.

Oto jak możesz z niego korzystać.

C = [email protected]
print(C)

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

Zauważ, że macierz iloczynu C jest taka sama jak ta, którą otrzymaliśmy wcześniej.

Czy możesz użyć np.dot() do pomnożenia macierzy?

Jeśli kiedykolwiek natknąłeś się na kod, który używa np.dot() do mnożenia dwóch macierzy, oto jak to działa.

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

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

Zobaczysz, że np.dot(A, B) również zwraca oczekiwaną macierz produktu.

Jednak, jak na Dokumenty NumPynależy używać np.dot() tylko do obliczania iloczynu skalarnego dwóch jednowymiarowych wektorów, a nie do mnożenia macierzy.

Przypomnijmy sobie z poprzedniej sekcji, element o indeksie (i, j) macierzy iloczynu C jest iloczynem skalarnym wiersza i macierzy A i kolumny j macierzy B.

Ponieważ NumPy niejawnie rozgłasza tę operację iloczynu skalarnego do wszystkich wierszy i wszystkich kolumn, otrzymujesz wynikową macierz iloczynów. Aby jednak zachować czytelność kodu i uniknąć niejednoznaczności, zamiast tego użyj np.matmul() lub operatora @.

Wniosek

🎯 W tym samouczku nauczyłeś się następujących rzeczy.

  • Warunek poprawności mnożenia macierzy: liczba kolumn w macierzy A = liczba wierszy w macierzy B.
  • Jak napisać niestandardową funkcję Pythona, która sprawdza, czy mnożenie macierzy jest poprawne i zwraca macierz iloczynu. Treść funkcji wykorzystuje zagnieżdżone pętle for.
  • Następnie nauczyłeś się używać zagnieżdżonych list składanych do mnożenia macierzy. Są bardziej zwięzłe niż pętle for, ale są podatne na problemy z czytelnością.
  • Wreszcie nauczyłeś się używać wbudowanej funkcji NumPy np.matmul() do mnożenia macierzy i jak jest to najbardziej wydajne pod względem szybkości.
  • Nauczyłeś się również o operatorze @ do mnożenia dwóch macierzy w Pythonie.

I to kończy naszą dyskusję na temat mnożenia macierzy w Pythonie. W następnym kroku dowiedz się, jak sprawdzić, czy liczba jest liczbą pierwszą w Pythonie. Lub rozwiązywać interesujące problemy na łańcuchach Pythona.

Miłej nauki!🎉