학교 다닐 때 행렬로 연립방정식 풀었던 기억이 날 듯 합니다. 선형대수(Linear Algebra)는 통계, 기계학습, 공학, 영상/이미지 처리 등 여러 분야에서 활용이 됩니다. 선형대수를 전부 다루려면 너무나 방대하므로, 이번 포스팅에서는 Python의 NumPy에 있는 선형대수(Linear Algebra) 함수들 중에서 자주 사용하는 함수에 대해서만 선별적으로 소개하겠습니다. 그리고 선형대수의 이론적인 부분은 별도로 참고할 수 있는 링크를 달도록 하겠습니다.
- 단위행렬 (Unit matrix): np.eye(n)
- 대각행렬 (Diagonal matrix): np.diag(x)
- 내적 (Dot product, Inner product): np.dot(a, b)
- 대각합 (Trace): np.trace(x)
- 행렬식 (Matrix Determinant): np.linalg.det(x)
- 역행렬 (Inverse of a matrix): np.linalg.inv(x)
- 고유값 (Eigenvalue), 고유벡터 (Eigenvector): w, v = np.linalg.eig(x)
- 특이값 분해 (Singular Value Decomposition): u, s, vh = np.linalg.svd(A)
- 연립방정식 해 풀기 (Solve a linear matrix equation): np.linalg.solve(a, b)
- 최소자승 해 풀기 (Compute the Least-squares solution): m, c = np.linalg.lstsq(A, y, rcond=None)[0]
1. 단위행렬 혹은 항등행렬 (Unit matrix, Identity matrix): np.eye(n) |
단위행렬은 대각원소가 1이고, 나머지는 모두 0인 n차 정방행렬을 말하며, numpy의 eye() 함수를 사용해서 만들 수 있습니다.
* 참고 링크 : https://rfriend.tistory.com/141
import numpy as np unit_mat_4 = np.eye(4) print(unit_mat_4) [[1. 0. 0. 0.]
[0. 1. 0. 0.]
[0. 0. 1. 0.]
[0. 0. 0. 1.]]
|
1. 대각행렬 (Diagonal matrix): np.diag(x) |
대각행렬은 대각성분 이외의 모든 성분이 모두 '0'인 n차 정방행렬을 말합니다. 아래 예시의 행렬에서 빨간색으로 표시한 원소를 '0'으로 바꾼 행렬이 대각행렬입니다.
* 참고 링크 : http://rfriend.tistory.com/141
In [1]: import numpy as np In [2]: x = np.arange(9).reshape(3, 3) In [3]: print(x) [[0 1 2] [3 4 5] [6 7 8]] In [4]: np.diag(x) Out[4]: array([0, 4, 8]) In [5]: np.diag(np.diag(x)) Out[5]: array([[0, 0, 0], [0, 4, 0],
[0, 0, 8]]) |
2. 내적 (Dot product, Inner product): np.dot(a, b), a.dot(b) |
원소 간 곱 (element-wise product) : a*b |
내적 (dot product, inner product) : np.dot(a, b) |
In [6]: a = np.arange(4).reshape(2, 2) In [7]: print(a) [[0 1] [2 3]] In [8]: a*a Out[8]: array([[0, 1],
[4, 9]]) |
In [6]: a = np.arange(4).reshape(2, 2) In [7]: print(a) [[0 1] [2 3]] In [9]: np.dot(a, a) Out[9]: array([[ 2, 3], [ 6, 11]]) |
np.dot(a, b) NumPy 함수와 a.dot(b)의 배열 메소드의 결과는 동일합니다.
In [10]: a.dot(a) Out[10]: array([[ 2, 3],
[ 6, 11]])
|
3. 대각합 (Trace): np.trace(x) |
정방행렬의 대각에 위치한 원소를 전부 더해줍니다.
아래의 2차 정방행렬 예의 대각합은 0+5+10+15 = 30 이 됩니다. (파란색으로 표시함)
In [12]: b = np.arange(16).reshape(4, 4) In [13]: print(b) [[ 0 1 2 3] [ 4 5 6 7] [ 8 9 10 11] [12 13 14 15]] In [14]: np.trace(b)
Out[14]: 30
|
3차원 행렬에 대해서도 대각합을 구할 수 있습니다. 2차원은 대각선 부분의 원소 값을 전부 더하면 되지만 3차원 행렬에서는 대각(diagonal)이 어떻게 되나 좀 헷갈릴 수 있겠습니다. 아래의 3차원 행렬의 대각합을 구하는 예를 살펴보면, [0+12+24, 1+13+25, 2+14+26] = [36, 39, 42] 가 됩니다.
In [15]: c = np.arange(27).reshape(3, 3, 3) In [16]: print(c) [[[ 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]]] In [17]: np.trace(c)
Out[17]: array([36, 39, 42])
|
4. 행렬식 (Matrix Determinant): np.linalg.det(x) |
역행렬이 존재하는지 여부를 확인하는 방법으로 행렬식(determinant, 줄여서 det)이라는 지표를 사용합니다. 이 행렬식이 '0'이 아니면 역행렬이 존재하고, 이 행렬식이 '0'이면 역행렬이 존재하지 않습니다.
* 참고 링크 : http://rfriend.tistory.com/142
아래의 예에서 array([[1, 2], [3, 4]]) 의 행렬식이 '-2.0'으로서, '0'이 아니므로 역행렬이 존재한다고 판단할 수 있습니다.
In [18]: d = np.array([[1, 2], [3, 4]]) In [19]: np.linalg.det(a)
Out[19]: -2.0
|
5. 역행렬 (Inverse of a matrix): np.linalg.inv(x) |
In [20]: a = np.array(range(4)).reshape(2, 2) In [21]: print(a) [[0 1] [2 3]] In [22]: a_inv = np.linalg.inv(a) In [23]: a_inv Out[23]: array([[-1.5, 0.5], [ 1. , 0. ]]) |
위의 예제에서 np.linalg.inv() 함수를 사용하여 푼 역행렬이 제대로 푼 것인지 확인을 해보겠습니다. 역행렬의 정의에 따라서 원래의 행렬에 역행렬을 곱하면, 즉, a.dot(a_inv) 또는 np.dot(a, a_inv) 를 하면 단위행렬(unit matrix)가 되는지 확인해보겠습니다.
In [24]: a.dot(a_inv) Out[24]: array([[1., 0.], [0., 1.]])
|
6. 고유값 (Eigenvalue), 고유벡터 (Eigenvector): w, v = np.linalg.eig(x) |
In [25]: e = np.array([[4, 2],[3, 5]]) In [26]: print(e) [[4 2] [3 5]] In [27]: w, v = np.linalg.eig(e) # w: the eigenvalues lambda In [28]: print(w) [2. 7.] # v: the corresponding eigenvectors, one eigenvector per column In [29]: print(v) [[-0.70710678 -0.5547002 ] [ 0.70710678 -0.83205029]]
|
고유벡터는 배열 인덱싱하는 방법을 사용해서 각 고유값에 대응하는 고유벡터를 선택할 수 있습니다.
# eigenvector of eigenvalue lambda 2 In [30]: print(v[:, 0]) [-0.70710678 0.70710678] # eigenvector of eigenvalue labmda 7 In [31]: print(v[:, 1]) [-0.5547002 -0.83205029]
|
7. 특이값 분해 (Singular Value Decomposition): u, s, vh = np.linalg.svd(A) |
특이값 분해는 고유값 분해(eigen decomposition)처럼 행렬을 대각화하는 한 방법으로서, 정방행렬뿐만 아니라 모든 m x n 행렬에 대해 적용 가능합니다. 특이값 분해는 차원축소, 데이터 압축 등에 사용할 수 있습니다. 이론적인 부분은 설명하자면 너무 길기 때문에 이 포스팅에서는 설명하지 않겠으며, 아래의 링크를 참고하시기 바랍니다.
* 참고 링크 : http://rfriend.tistory.com/185
In [32]: A = np.array([[3,6], [2,3], [0,0], [0,0]]) In [33]: print(A) [[3 6] [2 3] [0 0] [0 0]] In [34]: u, s, vh = np.linalg.svd(A) In [35]: print(u) [[-0.8816746 -0.47185793 0. 0. ] [-0.47185793 0.8816746 0. 0. ] [ 0. 0. 1. 0. ] [ 0. 0. 0. 1. ]] In [36]: print(s) [7.60555128 0.39444872] In [37]: print(vh) [[-0.47185793 -0.8816746 ]
[ 0.8816746 -0.47185793]]
|
8. 연립방정식 해 풀기 (Solve a linear matrix equation): np.linalg.solve(a, b) |
아래의 두 개 연립방정식의 해(x0, x1)를 np.linalg.solve(a, b) 함수를 사용하여 풀어보겠습니다.
위의 연립방정식을 어떻게 행렬로 입력하고, np.linalg.solve(a, b)에 입력하는지 유심히 살펴보시기 바랍니다.
In [38]: a = np.array([[4, 3], [3, 2]]) In [39]: b = np.array([23, 16]) In [40]: x = np.linalg.solve(a, b) In [41]: print(x)
[2. 5.]
|
NumPy 가 제대로 x0, x1의 해를 풀었는지 확인해보겠습니다. x0=2, x1=5 가 해 맞네요!
In [42]: np.allclose(np.dot(a, x), b)
Out[42]: True
|
9. 최소자승 해 풀기 (Compute the Least-squares solution) : m, c = np.linalg.lstsq(A, y, rcond=None)[0] |
회귀모형 적합할 때 최소자승법(Least-squares method)으로 잔차 제곱합을 최소화하는 회귀계수를 추정합니다.
* 참고 링크 : https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.lstsq.html
아래의 예에서는 회귀계수 m, y절편 c를 최소자승법을 사용해서 구해보겠습니다.
In [43]: x = np.array([0, 1, 2, 3]) In [44]: y = np.array([-1, 0.2, 0.9, 2.1]) In [45]: A = np.vstack([x, np.ones(len(x))]).T In [46]: A Out[46]: array([[0., 1.], [1., 1.], [2., 1.], [3., 1.]]) In [47]: m, c = np.linalg.lstsq(A, y, rcond=None)[0] In [48]: print(m, c)
0.9999999999999999 -0.9499999999999997
|
아래의 그래프에서 점은 원래의 데이터이며, 빨간색 선은 최소자승법으로 추정한 회귀식의 적합선이 되겠습니다.
In [49]: import matplotlib.pyplot as plt ...: plt.plot(x, y, 'o', label='Original data', markersize=10) ...: plt.plot(x, m*x + c, 'r', label='Fitted line') ...: plt.legend()
...: plt.show() |
많은 도움이 되었기를 바랍니다.
'Python 분석과 프로그래밍 > Python 데이터 전처리' 카테고리의 다른 글
[Python pandas] groupby() 로 그룹별 집계하기 (data aggregation by groups) (8) | 2018.08.26 |
---|---|
[Python pandas] 다수개의 범주형자료로 가변수 만들기 (dummy variable) (2) | 2018.08.21 |
[Python] numpy 배열을 여러개의 하위 배열로 분할하기 (split an array into sub-arrays) (0) | 2018.05.22 |
[Python] numpy 배열 외부 파일로 저장하기(save), 외부 파일을 배열로 불러오기(load) (4) | 2018.05.21 |
[Python] numpy array 정렬, 거꾸로 정렬, 다차원 배열 정렬 (2) | 2018.05.18 |