파이썬에서 행렬을 곱하는 3가지 방법

이 자습서에서는 Python에서 두 행렬을 곱하는 방법을 배웁니다.

유효한 행렬 곱셈에 대한 조건을 학습하고 행렬을 곱하는 사용자 지정 Python 함수를 작성하는 것으로 시작합니다. 다음으로 중첩 목록 이해를 사용하여 동일한 결과를 얻는 방법을 살펴보겠습니다.

마지막으로 NumPy 및 내장 함수를 사용하여 행렬 곱셈을 보다 효율적으로 수행합니다.

행렬 곱셈이 유효한지 확인하는 방법

행렬 곱셈을 위한 Python 코드를 작성하기 전에 행렬 곱셈의 기본 사항을 다시 살펴보겠습니다.

두 행렬 A와 B 사이의 행렬 곱셈은 행렬 A의 열 수가 행렬 B의 행 개수와 같은 경우에만 유효합니다.

이전에 행렬 곱셈에 대해 이 조건을 보았을 것입니다. 그러나 왜 이것이 사실인지 궁금해 한 적이 있습니까?

음, 그것은 행렬 곱셈이 작동하는 방식 때문입니다. 아래 이미지를 살펴보십시오.

일반적인 예에서 행렬 A에는 m개의 행과 n개의 열이 있습니다. 그리고 행렬 B에는 n개의 행과 p개의 열이 있습니다.

제품 매트릭스의 모양은 무엇입니까?

결과 행렬 C의 인덱스 (i, j)에 있는 요소는 행렬 A의 행 i와 행렬 B의 열 j의 내적입니다.

따라서 결과 행렬 C의 특정 인덱스에 있는 요소를 얻으려면 행렬 A와 B에 있는 해당 행과 열의 내적을 각각 계산해야 합니다.

위의 과정을 반복하면 아래와 같이 m개의 행과 p개의 열이 있는 mxp 모양의 곱 행렬 C를 얻을 수 있습니다.

그리고 두 벡터 a와 b 사이의 내적 또는 내적은 다음 방정식으로 주어집니다.

이제 요약해 보겠습니다.

  • 내적은 길이가 같은 벡터 사이에서만 정의된다는 것이 분명합니다.
  • 따라서 행과 열 사이의 내적이 유효하려면(두 행렬을 곱할 때) 두 행렬에 동일한 수의 요소가 있어야 합니다.
  • 위의 일반적인 예에서 행렬 A의 모든 행에는 n개의 요소가 있습니다. 그리고 행렬 B의 모든 열에도 n개의 요소가 있습니다.

자세히 살펴보면 n은 행렬 A의 열 개수이고 행렬 B의 행 개수이기도 합니다. 이것이 바로 행렬 A의 열 개수가 숫자와 같아야 하는 이유입니다. 행렬 B의 행 수

행렬 곱셈이 유효한 조건과 곱 행렬의 각 요소를 얻는 방법을 이해하시기 바랍니다.

두 행렬을 곱하는 Python 코드를 작성해 보겠습니다.

  Google 문서에 Google 드로잉을 포함하는 방법

행렬을 곱하기 위한 사용자 지정 Python 함수 작성

첫 번째 단계로 행렬을 곱하는 사용자 정의 함수를 작성해 보겠습니다.

이 함수는 다음을 수행해야 합니다.

  • 두 개의 행렬 A와 B를 입력값으로 받습니다.
  • A와 B 사이의 행렬 곱셈이 유효한지 확인합니다.
  • 유효한 경우 두 행렬 A와 B를 곱하고 곱 행렬 C를 반환합니다.
  • 그렇지 않으면 행렬 A와 B를 곱할 수 없다는 오류 메시지를 반환합니다.

1단계: NumPy의 random.randint() 함수를 사용하여 두 개의 정수 행렬을 생성합니다. 행렬을 중첩된 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단계: 계속해서 곱하기_매트릭스(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.shape[0] 및 arr.shape[1] 행과 열의 수를 각각 지정하십시오. 그래서 만약 A.shape[1] == B.모양[0] 행렬 곱셈이 유효한지 확인합니다. 이 조건이 True인 경우에만 제품 행렬이 계산됩니다. 그렇지 않으면 함수는 오류 메시지를 반환합니다.

중첩 루프를 사용하여 값 계산: 결과 행렬의 요소를 계산하려면 행렬 A의 행을 반복해야 하며 외부 for 루프가 이 작업을 수행합니다. 내부 for 루프는 행렬 B의 열을 순환하는 데 도움이 됩니다. 그리고 가장 안쪽에 있는 for 루프는 선택한 열의 각 요소에 액세스하는 데 도움이 됩니다.

▶️ 이제 행렬을 곱하는 파이썬 함수가 어떻게 작동하는지 배웠으니 앞에서 생성한 행렬 A와 B로 함수를 호출해 봅시다.

multiply_matrix(A,B)

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

A와 B 사이의 행렬 곱셈이 유효하기 때문에 multi_matrix() 함수는 곱 행렬 C를 반환합니다.

  macOS에서 호스트 파일을 편집하는 방법(Mac OS X)

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의 List Comprehension – with Examples를 확인하여 심층적인 이해를 얻으십시오.

계속 진행하기 전에 결과 행렬 C를 한 번에 한 행씩 작성하고 싶습니다.

중첩 목록 이해 설명

1단계: 행렬 C에서 단일 값 계산

행렬 A의 행 i와 행렬 B의 열 j가 주어지면 아래 식은 행렬 C의 인덱스 (i, j)에 있는 항목을 제공합니다.

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의 항목 c_11을 반환합니다. 따라서 이 방법으로 한 행에서 하나의 요소를 얻을 수 있습니다.

2단계: 행렬 C에서 하나의 행 만들기

다음 목표는 전체 행을 만드는 것입니다.

행렬 A의 행 1에 대해 행렬 C의 완전한 행 하나를 얻으려면 행렬 B의 모든 열을 반복해야 합니다.

목록 이해 템플릿으로 돌아갑니다.

  • 를 1단계의 표현식으로 바꾸십시오. 이것이 바로 여러분이 원하는 것이기 때문입니다.
  • 다음으로, 을 B_col(행렬 B의 각 열)로 바꿉니다.
  • 마지막으로 을 행렬 B의 모든 열을 포함하는 목록인 zip(*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의 모든 행인 A_row로 바꿉니다.
  • 그리고 은 행렬 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://koreantech.org.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)도 예상 곱 행렬을 반환한다는 것을 알 수 있습니다.

그러나 넘파이 문서행렬 곱셈이 아니라 두 1차원 벡터의 내적을 계산할 때만 np.dot()를 사용해야 합니다.

이전 섹션에서, 곱 행렬 C의 인덱스 (i, j)에 있는 요소는 행렬 A의 행 i와 행렬 B의 열 j의 내적입니다.

NumPy는 이 내적 연산을 모든 행과 모든 열에 암시적으로 브로드캐스트하므로 결과 곱 행렬을 얻습니다. 그러나 코드를 읽기 쉽게 유지하고 모호성을 피하려면 대신 np.matmul() 또는 @ 연산자를 사용하십시오.

결론

🎯 이 튜토리얼에서는 다음을 배웠습니다.

  • 행렬 곱셈이 유효하기 위한 조건: 행렬 A의 열 수 = 행렬 B의 행 수.
  • 행렬 곱셈이 유효한지 확인하고 곱 행렬을 반환하는 사용자 지정 Python 함수를 작성하는 방법입니다. 함수의 본문은 중첩 for 루프를 사용합니다.
  • 다음으로 중첩 목록 이해를 사용하여 행렬을 곱하는 방법을 배웠습니다. for 루프보다 간결하지만 가독성 문제가 발생하기 쉽습니다.
  • 마지막으로 NumPy 내장 함수 np.matmul()을 사용하여 행렬을 곱하는 방법과 이것이 속도 면에서 가장 효율적인 방법을 배웠습니다.
  • 또한 Python에서 두 행렬을 곱하는 @ 연산자에 대해서도 배웠습니다.

이것으로 파이썬의 행렬 곱셈에 대한 논의를 마치겠습니다. 다음 단계로 파이썬에서 숫자가 소수인지 확인하는 방법을 배웁니다. 또는 Python 문자열에 대한 흥미로운 문제를 해결하십시오.

즐거운 배움!🎉