# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# + [markdown] id="e8ea7aca"
# <a href="https://colab.research.google.com/github/SLCFLAB/Data-Science-Python/blob/main/Day%205/5_1.Matrix%20Computation.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>

# + [markdown] id="17kXJzbRkIjs"
# # 1장 Matrix Computation

# + [markdown] id="ujSPerl6kIjv"
# # 1절 벡터, 행렬

# + [markdown] id="-g2AmcRmkIjw"
# #### 코드 출처 
# [1] https://github.com/rickiepark/machine-learning-with-python-cookbook
# [2] https://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html https://colab.research.google.com/github/SLCFLAB/Math4DS/blob/main

# + [markdown] id="ky2nt0MCkIjw"
# ## 1.1 벡터 만들기

# + id="qAqH4-hAkIjw"
# 라이브러리를 임포트합니다.
import numpy as np

# + id="zvNfYBsJkIjx" outputId="b598a6f7-f9df-4003-869d-1e779f7e4fd5" colab={"base_uri": "https://localhost:8080/", "height": 35}
np.__version__

# + id="2PIfuDyZkIjy"
# 하나의 행으로 벡터를 만듭니다.
vector_row = np.array([1, 2, 3])

# + id="o6Lc8CD5kIjz" outputId="0ed4f296-056d-4ff8-c3e7-512edd9b1c2b" colab={"base_uri": "https://localhost:8080/"}
vector_row.shape

# + id="kjNkyEgBkIjz"
# 하나의 열로 벡터를 만듭니다.
vector_column = np.array([[1],
                          [2],
                          [3]])

# + id="DGAAJN0IkIj0" outputId="cfc4dc93-ee7e-406c-acbf-8cf88c20a608" colab={"base_uri": "https://localhost:8080/"}
vector_column

# + [markdown] id="nANPcg9ZkIj0"
# ### 불임

# + id="k9qx9B1rkIj1" outputId="719d5b73-8d7e-4665-cec2-63027a743b50" colab={"base_uri": "https://localhost:8080/"}
# 넘파이 배열의 클래스를 출력합니다.
print(type(vector_row))

# + id="PImy2SE_kIj1"
# ndarray를 사용하는 것은 권장되지 않습니다.
bad_way = np.ndarray((3,))

# + id="6rqdDT-4kIj1" outputId="1994dc59-7eba-480b-bdee-aecb32a1efc9" colab={"base_uri": "https://localhost:8080/"}
new_row = np.asarray([1, 2, 3])
# asarray()는 새로운 배열을 만들지 않습니다.
new_row = np.asarray(vector_row)
new_row is vector_row

# + [markdown] id="krLWuwEqkIj3"
# ## 1.2 행렬 만들기

# + id="CIUU8VX3kIj3" outputId="08278573-d11e-4004-824d-d9d62b2ddfdf" colab={"base_uri": "https://localhost:8080/"}
# numpy.matrix is matrix class that has a more convenient interface than numpy.ndarray for matrix operations. 
# This class supports, MATLAB-like creation syntax via the semicolon, has matrix multiplication as default for the * operator, 
# and contains I and T members that serve as shortcuts for inverse and transpose:
import numpy as np
A = np.mat('[1 2;3 4]')
A

# + id="Mr93lvUTkIj3" outputId="a74b8666-35d5-4c4c-a912-34c223797eac" colab={"base_uri": "https://localhost:8080/"}
A.I

# + id="5Z3OSxsZkIj4" outputId="30b8a83b-e516-4390-e039-442d0c0a4857" colab={"base_uri": "https://localhost:8080/"}
b = np.mat('[5 6]')
b

# + id="wI4v6ohykIj4" outputId="527c20c4-bfad-4883-9c66-81e344e32814" colab={"base_uri": "https://localhost:8080/"}
b.T

# + id="zHLJc8KlkIj4" outputId="98f54626-729d-40e3-92e1-2fbc72d31d45" colab={"base_uri": "https://localhost:8080/"}
A*b.T
# the matrix data structure is not recommended for two reasons. 
# First, arrays are the de facto standard data structure of NumPy. 
# Second, the vast majority of NumPy operations return arrays, not matrix objects.

# + [markdown] id="NpQw4v7ZkIj4"
# ### the above code can be rewritten as:

# + id="4d2ziZr6kIj5" outputId="100eac20-d091-4358-a322-affe06d18511" colab={"base_uri": "https://localhost:8080/"}
# scipy.linalg operations can be applied equally to numpy.matrix or to 2D numpy.ndarray objects.
import numpy as np
from scipy import linalg
A = np.array([[1,2],[3,4]])
A

# + id="Z_Uu6dMKkIj5" outputId="603a2643-35d0-4710-9daf-86e53688159c" colab={"base_uri": "https://localhost:8080/"}
linalg.inv(A)

# + id="na3qw86FkIj5" outputId="04963e80-7a8c-4c8b-d109-97884175dffe" colab={"base_uri": "https://localhost:8080/"}
b = np.array([[5,6]]) #2D array
b

# + id="Eg0mNvKTkIj5" outputId="8041c636-bc70-405d-c922-a8cf6b127332" colab={"base_uri": "https://localhost:8080/"}
b.T

# + id="jchuYQM8kIj6" outputId="1130c05e-5bdd-41e0-9165-8aa1f3fe7337" colab={"base_uri": "https://localhost:8080/"}
A*b #not matrix multiplication!

# + id="UEfqz_5jkIj6" outputId="702ae2ed-293c-4660-e8d3-a96faa5600dd" colab={"base_uri": "https://localhost:8080/"}
A.dot(b.T) #matrix multiplication

# + id="BL1h60zlkIj6" outputId="afe8e5ac-989b-4ae7-ca4b-1899d0d753ee" colab={"base_uri": "https://localhost:8080/"}
b = np.array([5,6]) #1D array
b

# + id="QlZTif1-kIj6" outputId="00808aad-236b-4576-d666-20bff23ebf5e" colab={"base_uri": "https://localhost:8080/"}
b.T  #not matrix transpose!

# + id="U3X7wG0VkIj6" outputId="ae010cf8-ae16-46ae-f681-0f3079b79b92" colab={"base_uri": "https://localhost:8080/"}
A.dot(b)  #does not matter for multiplication

# + [markdown] id="3OXc_QxykIj7"
# ### 붙임

# + id="zFe5fuAPkIj7" outputId="2654d77f-cf3f-403b-e095-c859328d6136" colab={"base_uri": "https://localhost:8080/"}
# 임의의 값이 채워진 배열을 만듭니다.
empty_matrix = np.empty((3, 2))
empty_matrix

# + id="pwLNY0wukIj7" outputId="e0c13c1b-dfb1-4754-e522-4674f93d8ca8" colab={"base_uri": "https://localhost:8080/"}
zero_matrix = np.zeros((3, 2))
zero_matrix

# + id="DB3H9YnQkIj7" outputId="10b67202-0110-4b28-ff1e-aab2a86733f6" colab={"base_uri": "https://localhost:8080/"}
one_matrix = np.ones((3, 2))
one_matrix

# + id="mndqTazVkIj7" outputId="f6b3a63f-1398-4eb0-fd28-808fcf5d8b30" colab={"base_uri": "https://localhost:8080/"}
# 0 행렬을 만든 후 7을 더합니다.
seven_matrix = np.zeros((3, 2)) + 7
# full() 함수를 사용하는 것이 효율적입니다.
seven_matrix = np.full((3, 2), 7)
seven_matrix

# + [markdown] id="kRA2ecYWkIj8"
# ## 1.3 희소 행렬 만들기

# + id="z8bAusrmkIj8"
# 라이브러리를 임포트합니다.
import numpy as np
from scipy import sparse

# 행렬을 만듭니다. 
matrix = np.array([[0, 0],
                   [0, 1],
                   [3, 0]])

# CSR (compressed sparse row) 행렬을 만듭니다.
matrix_sparse = sparse.csr_matrix(matrix)

# + id="YO4pAmLSkIj8" outputId="336e8789-306b-4a4d-ef28-fa73d0cdac09" colab={"base_uri": "https://localhost:8080/"}
# 희소 행렬을 출력합니다.
print(matrix_sparse)

# + id="x82iQ_3nkIj8" outputId="bb348efa-31f3-45b7-d174-41bc385e3d52" colab={"base_uri": "https://localhost:8080/"}
# 큰 행렬을 만듭니다.
matrix_large = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                         [0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
                         [3, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

# CSR 행렬을 만듭니다.
matrix_large_sparse = sparse.csr_matrix(matrix_large)

# 원래 희소 행렬을 출력합니다.
print(matrix_sparse)

# + id="Kl2AG7Z5kIj8" outputId="b70c68fb-f5e6-49cb-e0ef-e03d1c74b3ff" colab={"base_uri": "https://localhost:8080/"}
# 큰 희소 행렬을 출력합니다.
print(matrix_large_sparse)

# + [markdown] id="iPaVtBZAkIj9"
# ### 붙임

# + id="teg6u_ThkIj9" outputId="c8326e63-d399-42e4-e57b-96f117d04178" colab={"base_uri": "https://localhost:8080/"}
# (data, (row_index, col_index))로 구성된 튜플을 전달합니다.
# shape 매개변수에서 0을 포함한 행렬의 전체 크기를 지정합니다.  
matrix_sparse_2 = sparse.csr_matrix(([1, 3], ([1, 2], [1, 0])), shape=(3, 10))

print(matrix_sparse_2)

# + id="2wZibkQMkIj9" outputId="b7d18a2f-80b7-4f6b-fd03-c629afedba7d" colab={"base_uri": "https://localhost:8080/"}
print(matrix_sparse_2.toarray())

# + id="TerBo2-bkIj9" outputId="eae9c949-fd3c-48ec-97ca-e16543bd5a07" colab={"base_uri": "https://localhost:8080/"}
matrix_sparse_2.todense()

# + [markdown] id="XaVGDIk3kIj9"
# ## 1.4 원소 선택

# + id="Gtq6BEFekIj9" outputId="49b3e69e-852f-4c09-8361-2afe640d0062" colab={"base_uri": "https://localhost:8080/"}
# 라이브러리를 임포트합니다.
import numpy as np

# 행 벡터를 만듭니다.
vector = np.array([1, 2, 3, 4, 5, 6])

# 행렬을 만듭니다.
matrix = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

# vector의 세 번째 원소를 선택합니다.
vector[2]

# + id="Fzu_J5UakIj-" outputId="8cddd760-0b03-4554-8195-877d04899b8f" colab={"base_uri": "https://localhost:8080/"}
# matrix의 두 번째 행, 두 번째 열의 원소를 선택합니다.
matrix[1,1]

# + id="IdEZ4dX9kIj-" outputId="645c9a01-601d-40ed-963f-764802719cec" colab={"base_uri": "https://localhost:8080/"}
# 벡터에 있는 모든 원소를 선택합니다.
vector[:]

# + id="r5R1veFKkIj-" outputId="5d77e9d5-682a-47d2-cb90-d03651d76168" colab={"base_uri": "https://localhost:8080/"}
# 세 번째 원소를 포함하여 그 이전의 모든 원소를 선택합니다.
vector[:3]

# + id="EmmxEQkIkIj-" outputId="d2b49f1d-b70b-42af-8a65-fb0392e694df" colab={"base_uri": "https://localhost:8080/"}
# 세 번째 이후의 모든 원소를 선택합니다.
vector[3:]

# + id="SLktBU3JkIj_" outputId="43e45f37-8a74-4f25-c854-483182d4e05d" colab={"base_uri": "https://localhost:8080/"}
# 마지막 원소를 선택합니다.
vector[-1]

# + id="a087d759kIj_" outputId="992848a2-d5b4-44bb-d2cf-0d5139d7d6a4" colab={"base_uri": "https://localhost:8080/"}
# 행렬에서 첫 번째 두 개의 행과 모든 열을 선택합니다.
matrix[:2,:]

# + id="JOuElc4qkIj_" outputId="3214152f-f6dd-4235-ee4e-f5e372fddb32" colab={"base_uri": "https://localhost:8080/"}
# 모든 행과 두 번째 열을 선택합니다.
matrix[:,1:2]

# + [markdown] id="hISP1Q0gkIj_"
# ### 붙임

# + id="hdzPVR6_kIj_" outputId="8774aab3-e4aa-47c0-8942-3f5423d7b00a" colab={"base_uri": "https://localhost:8080/"}
# 첫 번째 행과 세 번째 행을 선택합니다.
matrix[[0,2]]

# + id="u1-4-TLakIkA" outputId="4064facb-2ef2-475f-a3fe-aa766f27289d" colab={"base_uri": "https://localhost:8080/"}
# (0, 1), (2, 0) 위치의 원소를 선택합니다.
matrix[[0,2], [1,0]]

# + id="qD6FVxjgkIkA" outputId="58a60b10-a44a-411b-c3c7-2f895504d1ed" colab={"base_uri": "https://localhost:8080/"}
# matrix의 각 원소에 비교 연산자가 적용됩니다.
mask = matrix > 5

mask

# + id="DFwRFA8IkIkA" outputId="2d552838-73d3-459e-d2a6-231a2f916222" colab={"base_uri": "https://localhost:8080/"}
# 불리언 마스크 배열을 사용하여 원소를 선택합니다.
matrix[mask]

# + [markdown] id="PHmRzahLkIkA"
# ## 1.5 행렬 정보 확인

# + id="1von0JtokIkB" outputId="7b9cc864-01d1-4444-98a3-86066f38e92c" colab={"base_uri": "https://localhost:8080/"}
# 라이브러리를 임포트합니다.
import numpy as np

# 행렬을 만듭니다.
matrix = np.array([[1, 2, 3, 4],
                   [5, 6, 7, 8],
                   [9, 10, 11, 12]])

# 행렬의 크기를 확인합니다.
matrix.shape

# + id="aRFDiOkOkIkB" outputId="115e576a-f4e4-4133-c269-106c4dcb9761" colab={"base_uri": "https://localhost:8080/"}
# 행렬의 원소 개수를 확인합니다(행 * 열).
matrix.size

# + id="umXvj3sSkIkB" outputId="58877e38-6383-4142-85d4-9b01713c43d6" colab={"base_uri": "https://localhost:8080/"}
# 차원 수를 확인합니다.
matrix.ndim

# + [markdown] id="s4Lpi5MIkIkB"
# ### 붙임

# + id="PcEyH00ckIkB" outputId="bc487599-d93b-4e7a-d9ed-82e01eec16fe" colab={"base_uri": "https://localhost:8080/"}
# 원소의 데이터 타입을 확인합니다.
print(matrix.dtype)

# + id="Uy-uKz50kIkB" outputId="f5ada8a4-e5bc-4d42-ba60-86a1e4a8c176" colab={"base_uri": "https://localhost:8080/"}
# 원소 하나가 차지하는 바이트 크기입니다. 
print(matrix.itemsize)

# + id="rwuTI5HMkIkC" outputId="ac579f4a-924e-45c8-f721-aea9eb60c9c1" colab={"base_uri": "https://localhost:8080/"}
# 배열 전체가 차지하는 바이트 크기입니다.
print(matrix.nbytes)

# + [markdown] id="7LHQLTgdkIkC"
# ## 1.6 벡터화 연산 적용하기

# + id="z7tqAXNnkIkC" outputId="5ac388ce-037e-4b4d-f852-fcadcc6e9e66" colab={"base_uri": "https://localhost:8080/"}
# 라이브러리를 임포트합니다.
import numpy as np

# 행렬을 만듭니다.
matrix = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

# 100을 더하는 함수를 만듭니다.
add_100 = lambda i: i + 100

# 벡터화된 함수를 만듭니다.
vectorized_add_100 = np.vectorize(add_100)

# 행렬의 모든 원소에 함수를 적용합니다.
vectorized_add_100(matrix)

# + id="99x0mo4PkIkC" outputId="ab86be73-01eb-4279-9f83-bfe2cbf28765" colab={"base_uri": "https://localhost:8080/"}
# 모든 원소에 100을 더합니다.
matrix + 100

# + [markdown] id="hiEZJhZ7kIkC"
# ### 붙임

# + id="X0jAkA0tkIkC" outputId="a8b486bc-f8ec-41b7-c78d-f943faf60034" colab={"base_uri": "https://localhost:8080/"}
# (3, 3) 크기 행렬에 (3, ) 벡터를 더하면 
# (1, 3) 크기가 된다음 행을 따라 반복됩니다.
matrix + [100, 200, 300]

# + id="f0RI8u5nkIkD" outputId="5286ba27-64f1-4dd6-ff8a-7b92a8d3e5c2" colab={"base_uri": "https://localhost:8080/"}
# (3, 3) 크기 행렬에 (3, 1) 벡터를 더하면 열을 따라 반복됩니다.
matrix + [[100], [200], [300]]

# + [markdown] id="32GPsFupkIkD"
# ## 1.7 최댓값, 최솟값 찾기

# + id="0aL5nC0LkIkD" outputId="fec6bbda-9846-41b4-a64a-cac01b4684f2" colab={"base_uri": "https://localhost:8080/"}
# 라이브러리를 임포트합니다.
import numpy as np

# 행렬을 만듭니다.
matrix = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

# 가장 큰 원소를 반환합니다.
np.max(matrix)

# + id="nHXZtlN3kIkD" outputId="11299648-ee38-4f25-d708-3eecf48ac28d" colab={"base_uri": "https://localhost:8080/"}
# 가장 작은 원소를 반환합니다.
np.min(matrix)

# + id="Dgd88trokIkD" outputId="27c8da3f-a37f-434c-c469-a9f871dc4120" colab={"base_uri": "https://localhost:8080/"}
# 각 열에서 최댓값을 찾습니다.
np.max(matrix, axis=0)

# + id="VM8x4mU6kIkD" outputId="e99b2bb1-29f9-47a4-c9fa-170d34d791de" colab={"base_uri": "https://localhost:8080/"}
# 각 행에서 최댓값을 찾습니다.
np.max(matrix, axis=1)

# + [markdown] id="N_rS7tGHkIkE"
# ### 붙임

# + id="YGdcRMcGkIkE" outputId="1ea3d8ee-ae8c-4620-8d2b-dfc92fcb4918" colab={"base_uri": "https://localhost:8080/"}
# 이전 예와 달리 (3, 1) 크기의 열 벡터가 만들어 집니다.
vector_column = np.max(matrix, axis=1, keepdims=True)

vector_column

# + id="pm1adhFMkIkE" outputId="a516f775-dac6-4994-b8b9-ef738d8eb858" colab={"base_uri": "https://localhost:8080/"}
# 열 벡터이므로 브로드캐스팅을 이용하여 각 행의 최댓값을 뺄 수 있습니다.
matrix - vector_column

# + [markdown] id="SnTKT8VOkIkE"
# ## 1.8 평균, 분산, 표준 편차 계산하기

# + id="om-hfaC2kIkE" outputId="143898c6-5522-4700-f5a4-7324785bd902" colab={"base_uri": "https://localhost:8080/"}
# 라이브러리를 임포트합니다.
import numpy as np

# 행렬을 만듭니다.
matrix = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

# 평균을 반환합니다.
np.mean(matrix)

# + id="eUiTo7ZBkIkE" outputId="79797740-5fa4-4fdc-aa16-59e0c8906e21" colab={"base_uri": "https://localhost:8080/"}
# 분산을 반환합니다.
np.var(matrix)

# + id="CvIP-sxTkIkF" outputId="f15f40a2-8f3b-470e-941a-e66d5c1d9335" colab={"base_uri": "https://localhost:8080/"}
# 표준 편차를 반환합니다.
np.std(matrix)

# + id="6qfnuIbOkIkF" outputId="f2153329-0443-42f7-f9fe-30dfaed5575f" colab={"base_uri": "https://localhost:8080/"}
# 각 열의 평균을 계산합니다.
np.mean(matrix, axis=0)

# + [markdown] id="L1twP7-UkIkF"
# ## 1.9 배열 크기 바꾸기

# + id="KHw1PkjEkIkF" outputId="98cd24d0-1449-485c-b60c-2c47c370751e" colab={"base_uri": "https://localhost:8080/"}
# 라이브러리를 임포트합니다.
import numpy as np

# 4x3 행렬을 만듭니다.
matrix = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9],
                   [10, 11, 12]])

# 2x6 행렬로 크기를 바꿉니다.
matrix.reshape(2, 6)

# + id="DWLRpNJ7kIkJ" outputId="36ff5077-5e93-4387-cc7f-1533028c30df" colab={"base_uri": "https://localhost:8080/"}
matrix.size

# + [markdown] id="W7zO9WMzkIkK"
# ## 1.10 벡터나 행렬을 전치하기

# + id="puCRlVBakIkK" outputId="9305b3d2-a0bb-4f29-e236-0c9d7aa9e2f4" colab={"base_uri": "https://localhost:8080/"}
# 라이브러리를 임포트합니다.
import numpy as np

# 행렬을 만듭니다.
matrix = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

# 행렬을 전치합니다.
matrix.T

# + id="B2Rxj5_XkIkK" outputId="32183a60-4f7b-4d1a-b1b0-92a1e9e91733" colab={"base_uri": "https://localhost:8080/"}
# 벡터를 전치합니다. -1D array
np.array([1, 2, 3, 4, 5, 6]).T

# + id="c4GKrps7kIkL" outputId="a56e1c14-28b8-4a3e-d22d-ed79233f4c17" colab={"base_uri": "https://localhost:8080/"}
# 행 벡터를 전치합니다.- 2D array
np.array([[1, 2, 3, 4, 5, 6]]).T

# + [markdown] id="ZhgxBk5lkIkL"
# ### 붙임

# + id="0smcVTsYkIkL" outputId="8a674d9e-a46c-4b50-e638-71b64cbb6291" colab={"base_uri": "https://localhost:8080/"}
matrix.transpose()

# + id="rJEoEpGYkIkL" outputId="6b5fffe2-eddc-4cb4-c79a-b640bd322ad0" colab={"base_uri": "https://localhost:8080/"}
# 2x3x2 행렬을 만듭니다.
matrix = np.array([[[ 1,  2],
                    [ 3,  4],
                    [ 5,  6]],

                   [[ 7,  8],
                    [ 9, 10],
                    [11, 12]]])

# 두 번째와 세 번째 차원을 바꾸어 2x2x3 행렬로 만듭니다.
matrix.transpose((0, 2, 1))

# + [markdown] id="gYcI3a1qkIkL"
# ## 1.11 행렬 펼치기

# + id="VdTrk4wmkIkM" outputId="4f19c04d-cd7c-439c-f63b-9bb42def5456" colab={"base_uri": "https://localhost:8080/"}
# 라이브러리를 임포트합니다.
import numpy as np

# 행렬을 만듭니다.
matrix = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])

# 행렬을 펼칩니다.
matrix.flatten()

StarcoderdataJupyterScriptsDedupFiltered