ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ Python ] 선형대수학 X 파이썬 | 행렬
    Study/Python 2025. 5. 5. 23:54

    군 내에서 아이패드, 사지방 컴퓨터를 이용하여 작성함. 본 내용은 자기개발 목적으로 책 '개발자를 위한 실전 선형대수학-한빛미디어', 유튜브 등을 참고하였음
     
     

    행렬(Matrix)

     
     행렬은 벡터를 한 차원 더 올린 것이다. 과학과 수학의 수많은 분야에서 다채로운 수학적 객체로 쓰인다. 이는 일련의 방정식, 컴퓨터 그래픽, 기록 등 다양한 것들을 저장할 수 있다.
     작은 행렬은 간단하게 전체를 적을 수 있으나, 대규모 행렬은 간단하게 표기하는 게 어려우므로 파이썬 라이브러리 matplot-lib를 사용하여 이미지로 시각화하곤 한다.
     
    행렬은 A, M으로 표현하며 크기는 (행, 열) 순으로 나타낸다. 예시로 아래와 같이 행렬을 표기한다.
     
    $$\begin{bmatrix}1 & 2 & 3 & 4 \\2 & 6 &7&5 \\ 3 &1&0&4\end{bmatrix}$$


     위 행렬의 행이 3개이고 열이 4개이므로 3$\times$4이다.
     
     
     행과 열의 위치를 인덱싱해서 행렬의 특정 원소를 참조할 수도 있다. 행렬 A의 두 번째 행, 네 번 째 열에 있는 원소를 $a_{24}$로 나타낸다. 파이썬에서는 0 기반 인덱싱을 사용하므로 원소 $a_{24}$는 파이썬에서 A[1,3]으로 인덱싱된다.
     
     슬라이싱을 통해서도 행렬의 행 또는 열의 부분 집합을 추출할 수 있다.(일부 구간을 추출할 수 있다.) 행렬에서 슬라이싱을 사용하려면 시작 행과 마지막 행, 시작 열과 마지막 열을 지정하고 1칸씩 슬라이싱을 하도록 지정한다.(슬라이싱과 관련한 파트는 이전 발행글에서 확인할 수 있다.)
     
     다음 코드는 원래 행렬에서 행 2~3과 열 1~4의 부분 행렬을 추출하는 예제이다. 파이썬은 배타적 상한을 사용하므로 코드는 다음과 같다.

    import numpy as np
    
    A = np.arange(60).reshape(6,10)
    sub = A[1:3:1,0:4:1]

     
    기존의 행렬과 추출된 부분 행렬은 다음과 같다.

    기존의 행렬 :
     [[ 0  1  2  3  4  5  6  7  8  9]
     [10 11 12 13 14 15 16 17 18 19]
     [20 21 22 23 24 25 26 27 28 29]
     [30 31 32 33 34 35 36 37 38 39]
     [40 41 42 43 44 45 46 47 48 49]
     [50 51 52 53 54 55 56 57 58 59]]
    부분 행렬 :
     [[10 11 12 13]
     [20 21 22 23]]

     


     
     
     행렬의 숫자를 구성하는 방법이 무한하기에 행렬의 수는 무한하다. 하지만 행렬을 적은 특성만으로 설명할 수 있으며 이에 행렬은 어떠한 군 범주에 속하게 된다. 다음은 자주 사용되는 특수 행렬과 파이썬 코드이다.
     

    난수 행렬(Random Numbers Matrix)

     난수 행렬은 일반적으로 가우스(정규)와 같은 분포로부터 무작위로 추출된 숫자를 가진 행렬이다. 이 행렬은 이름 대로 임의의 크기와 행렬 계수(rank)로 빠르게 생성할 수 있기에 선형대수학을 코드로 공부할 때 유용하게 쓰인다. 파이썬 NumPy 라이브러리를 통해 난수 행렬을 생성할 수 있는데, 자주 쓰이는 메소드 3가지는 rand, randn, randint이다. 각각의 차이는 아래와 같다.

    • rand : 0 이상 1 미만의 실수 구간에서 균일한 분포를 가지는 난수 배열을 생성한다.
    • randn : 표준정규분포로부터 생성된 난수 배열을 반환한다.
    • randint : 설정된 최솟값 이상, 최댓값 미만의 구간에서 임의의 정수 배열을 생성한다.

    위 세 메소드는 공통적으로 행렬의 크기를 설정할 수 있다. 다음은 위 함수를 이용한 난수 행렬의 예시이다.

    np.random.rand

    import numpy as np
    
    Mrows = 3     # 행
    Ncols = 4     # 열
    A = np.random.rand(Mrows, Ncols)
    
    print(A)
    [[0.08878393 0.34298866 0.57211911 0.08331464]
     [0.00637008 0.99675959 0.8202452  0.70948844]
     [0.49824632 0.83885397 0.74375866 0.53795656]]

     
    random.rand 함수의 인자로 숫자 하나를 입력하면 그 숫자만큼의 요소를 가진 행벡터를 출력한다. 숫자 2개를 입력하면 그 크기에 맞는 행렬을 출력한다.
     

    np.random.randn

    import numpy as np
    
    Mrows = 3     # 행
    Ncols = 4     # 열
    A = np.random.randn(Mrows, Ncols)
    
    print(A)
    [[-1.00916421 -0.33031084  0.25154407  1.68458451]
     [-1.06987327 -1.58696524  0.01897073  1.00416368]
     [-1.29570174  0.09551931  0.45525513  0.75924997]]

     
    rand 함수와 형식적인 측면에서는 유사하나, 출력 과정에서 표준정규분포(평균이 0이고 표준편차가 1인 정규분포)로부터 난수를 얻어낸다는 점에서 차이가 있다.
     

    np.random.randint

    import numpy as np
    
    A = np.random.randint(3, size=4)
    B = np.random.randint(1, 5, size=4)
    C = np.random.randint(2, 6, size=(3, 4))
    
    print(A)
    print(B)
    print(C)
    [0 2 2 1]
    [2 2 3 4]
    [[3 5 3 3]
     [4 3 3 3]
     [3 3 2 2]]

     
    A에서 [0, 3) 구간에서 임의의 정수를 샘플링하여 4요소 행벡터를 반환한다.(0과 2 중에서 랜덤으로 4번 뽑는 것이다.)
    B에서 [1, 5) 구간에서 임의의 정수를 샘플링하여 4요소 행벡터를 반환한다.(1과 4 중에서 랜덤으로 4번 뽑는 것이다.)
    C에서 [2, 6) 구간에서 임의의 정수를 샘플링하여 3$\times\$4 행렬을 반환한다.
    위 세 가지의 공통점으로 구간의 최솟값이 0일 때 생략할 수 있다. 따라서 randint 함수에서는 입력할 수 있는 인자의 형태가 다양함을 알 수 있다.
     
     

    정방 행렬(Square Matrix)과 비정방 행렬(Nonsquare Matrix)

     정방 행렬은 행 수와 열 수가 같다. 즉 $\mathbb{R}^{N\times N}$ 행렬이다. 비정방 행렬은 그 반대로 행 수와 열 수가 다른 것을 가리킨다. 난수 행렬에서 행렬의 크기를 설정하여 난수의 정방과 비정방 행렬을 만들 수 있다. 비정방 행렬의 행 수가 열 수보다 많으면 높다고 하고 열 수가 행 수보다 많으면 넓다고 한다.
     
     

    대각 행렬(Diagonal Matrix)

     행렬의 대각은 왼쪽 위에서 시작하여 오른쪽 아래로 내려가는 원소들을 뜻한다. 대각 행렬은 모든 비대각 원소가 0이며 대각 원소는 0이거나 0이 아닌 값을 가질 수 있는 유일한 원소이다.
     함수 np.diag()는 입력에 따라 두 가지로 동작하는데, 먼저 행렬을 입력하면 대각 원소를 벡터로 반환하고 벡터를 입력하면 대각선에 해당 벡터 원소가 있는 행렬을 반환한다.(행렬의 대각 요소를 추출하는 것을 '행렬의 대각화'라고 하지 않는다.)
    다음은 np.diag() 함수를 이용한 대각 행렬 예시이다.

    import numpy as np
    
    diagonal_matrix = np.diag([10, 20, 30])
    print(diagonal_matrix)
    [[10  0  0]
     [ 0 20  0]
     [ 0  0 30]]

     
    위 행렬은 대각선 요소가 [10, 20, 30]인 대각 행렬이다.
     
     

    삼각 행렬(Triangular Matrix)

     삼각 행렬은 주 대각선의 위 또는 아래가 모두 0이다. 0이 아닌 원소가 대각선 위에 있으면 상삼각 행렬이라고 하며, 0이 아닌 원소가 대각선 아래에 있으면 하삼각 행렬이라고 한다.
     NumPy에는 행렬의 위(np.triu()) 또는 아래(np.tril()) 삼각형을 추출하는 전용 함수가 있다.
     

    상삼각행렬

    import numpy as np
    
    upper_triangular = np.triu(np.ones((4, 4)))
    print(upper_triangular)
    [[1. 1. 1. 1.]
     [0. 1. 1. 1.]
     [0. 0. 1. 1.]
     [0. 0. 0. 1.]]

     

    하삼각행렬

    import numpy as np
    
    lower_triangular = np.tril(np.ones((4, 4)))
    print(lower_triangular)
    [[1. 0. 0. 0.]
     [1. 1. 0. 0.]
     [1. 1. 1. 0.]
     [1. 1. 1. 1.]]

     
     
     
     

    단위 행렬(Identity Matrix)

     특수 행렬 중 가장 중요한 행렬은 단위 행렬이다. 행렬 또는 벡터에 단위 행렬을 곱하면 동일한 행렬 또는 벡터가 된다는 점에서 숫자 1과 동등하다. 따라서 단위 행렬은 모든 대각 원소가 1인 정방 대각 행렬이다. 단위 행렬은 문자 I로 나타내며 행렬의 크기는 아래 첨자로 표시한다.(예시로 $I_4$는 4$\times$4 단위 행렬이다.) 숫자가 표기되어 있지 않으면 방정식이 성립하도록 하는 것처럼 문맥상 크기를 추론할 수 있다.
     단위 행렬은 np.eye()를 사용해서 만들 수 있다. 다음 코드는 이 함수를 이용한 예시이다.

    import numpy as np
    
    identity_matrix = np.eye(3)
    print(identity_matrix)
    [[1. 0. 0.]
     [0. 1. 0.]
     [0. 0. 1.]]

     
    대각선 요소가 1이고 나머지는 0인 행렬이다.
     
     

    영 행렬(zeros matrix)

     영 행렬은 모든 원소가 0인 행렬로 영벡터와 유사하다. 0처럼 굵은 체로 나타내며 np.zeros() 함수를 사용해서 영 행렬을 만들 수 있다. 다음 코드는 영 행렬의 예시이다.

    import numpy as np
    
    zero_matrix = np.zeros((2, 3))
    print(zero_matrix)
    [[0. 0. 0.]
     [0. 0. 0.]]

     
    2$\times$2 영행렬을 나타냈다.

제목 없는 코딩 블로그