실습_1. 선형대수학(Numpy)
Updated:
NumPy 행렬
NumPy는 파이썬에서 행렬 계산을 쉽게 할 수 있도록 도와줍니다. NumPy의 다양한 함수를 이용하면 기계학습에서 사용되는 수식을 쉽게 구현할 수 있습니다.
NumPy를 사용하기 위해서는 먼저 import를 통해 라이브러리를 불러와야 합니다.
import numpy as np
- np.array()
array()를 이용하면 n차원 행렬을 쉽게 생성할 수 있습니다. 우리가 접하는 데이터는 보통 1~3차원 행렬에 속하지만 복잡한 데이터를 다룰 때에는 고차원 행렬이 필요합니다. 2 \times 22×2 차원 행렬을 생성하는 방법은 다음과 같습니다.
A = np.array([[1, 2],
[3, 4]])
대괄호의 짝과 수, 쉼표의 위치에 주의하세요. 고차원 행렬을 작성할 때 각 행을 다른 줄에 작성하면 코드의 가독성을 높일 수 있습니다.
- 실습
matrix_tutorial() 함수 안에 배열 3 \times 43×4 의 크기를 가진 행렬 A를 선언하세요.
import numpy as np
def main():
print(matrix_tutorial())
def matrix_tutorial():
# Create the matrix A here...
A=np.array([[1,4,5,8],[2,1,7,3],[5,4,5,9]])
return A
if __name__ == "__main__":
main()
NumPy 산술연산자
- np.sum()
sum()을 이용하면 행렬 안의 모든 값의 합을 빠르게 구할 수 있습니다.
>>> A = np.array([[1, 2], [3, 4]])
>>> print(np.sum(A))
10
+, -, /, *
NumPy 행렬에는 사칙연산을 적용할 수 있습니다. 수학에서는 이와 같은 연산을 허용하지 않지만 큰 데이터를 다룰 때 편의를 위해 만들어진 기능입니다. A 행렬에 사칙연산을 A의 모든 원소에 해당 연산이 적용됩니다.
>>> A = np.array([[1, 2], [3, 4]])
>>> print(A + 2)
[[3 4]
[5 6]]
>>> print(A / 5)
[[0.2 0.4]
[0.6 0.8]]
- np.mean, np.median, np.std, np.var
mean(), median(), std(), var()를 이용하면 행렬의 평균값, 중간값, 표준 편차값, 분산값을 코드 한 줄로 구할 수 있습니다. 이 외에도 NumPy는 통계 처리를 위한 다양한 함수를 제공합니다: Numpy - Statistics.
>>> A = np.array([1, 2, 4, 5, 5, 7, 10, 13, 18, 21])
>>> print(np.mean(A))
8.6
>>> print(np.median(A))
6.0
>>> print(np.std(A))
6.437390775772433
>>> print(np.var(A))
41.44
- 실습
A 원소의 합이 1이 되도록 표준화(Normalization)를 적용하고 결과값을 A에 다시 저장하세요. ([42, 58][42,58] 에 표준화를 적용하면 [0.42, 0.58][0.42,0.58] 이 됩니다.
matrix_tutorial() 함수가 A의 분산(Variance)값을 리턴하도록 리턴값을 변경하세요.
import numpy as np
def main():
print(matrix_tutorial())
def matrix_tutorial():
A = np.array([[1,4,5,8], [2,1,7,3], [5,4,5,9]])
# 아래 코드를 작성하세요.
Sum = np.sum(A)
A = A/Sum
A = np.var(A)
return A
if __name__ == "__main__":
main()
행렬에 논리연산자 적용하기
앞으로 보다 쉽게 행렬을 입력할 수 있도록 다음과 같은 방법으로 배열을 입력받겠습니다.
먼저 행렬의 크기를 입력받습니다. 행의 수와 열의 수를 의미하는 두 정수를 받습니다. 두 개의 숫자는 공백으로 나누어집니다. 그 다음 한 줄에 열의 수 만큼의 숫자가 입력됩니다. [행의 수] 만큼의 줄이 입력되고 총 [행의 수] \times× [열의 수] 만큼의 숫자를 입력받게 됩니다.
3 5
1 2 6 3 8
11 0 -1 3 1
9 0 7 -3 4
- np.transpose()
transpose() 또는 T를 이용하면 전치행렬을 구할 수 있습니다. 배열의 (i, j)(i,j) 번째 원소를 (j, i)(j,i)번째 원소로 변환합니다.
>>> A = np.array([[1, 2, 3], [4, 5, 6]])
>>> print(A.T)
[[1 4]
[2 5]
[3 6]]
- np.linalg.inv
inv()는 행렬의 역행렬(inverse)를 구할 때 사용됩니다. NumPy의 선형대수학 관련 세부 패키지 linalg를 사용하기 때문에, 조금 더 긴 명령어를 사용합니다.
>>> A = np.array([[1, 2], [3, 4]])
>>> print(np.linalg.inv(A))
- np.dot
dot()은 두 행렬의 곱셈, 혹은 두 벡터의 내적(dot product)을 구할 때 사용됩니다. 이때 두 행렬의 크기 또는 shape이 맞지 않으면 오류가 발생합니다.
>>> A = np.array([[1, 2, 3], [1, 2, 1]])
>>> B = np.array([[2, 1, 3], [-1, 0, 5]])
>>> C = np.dot(A, B)
'ValueError: shapes (2,3) and (2,3) not aligned'
>>> B = B.transpose()
>>> C = np.dot(A, B)
>>> print(C)
[[13 14]
[ 7 4]]
- 실습
지금까지 배운 행렬 사용 방법을 모두 응용해보겠습니다.
앞으로 자주 사용될 get_matrix() 함수를 살펴보고 동작 방법을 숙지하세요.
A의 전치행렬(transpose) B를 생성하세요.
B의 역행렬을 구하여 C에 저장하세요. 역행렬을 구하는 것이 불가능하면 문자열 “not invertible”을 리턴합니다.
matrix_tutorial() 함수의 리턴값으로 0보다 큰 C의 원소를 모두 세어 개수를 리턴하세요. sum()의 인자로 해당 조건 C > 0을 입력하면 0보다 큰 원소를 쉽게 셀 수 있습니다.
import numpy as np
def main():
A = get_matrix()
print(matrix_tutorial(A))
def get_matrix():
mat = []
[n, m] = [int(x) for x in input().strip().split(" ")]
for i in range(n):
row = [int(x) for x in input().strip().split(" ")]
mat.append(row)
return np.array(mat)
def matrix_tutorial(A):
# 아래 코드를 완성하세요.
B = np.transpose(A)
print(B)
try:
C = np.linalg.inv(B)
except:
return 'not invertible'
return np.sum(C > 0)
if __name__ == "__main__":
main()
벡터 연산과 Numpy로 그림 그리기
이번 프로젝트에서는 Numpy를 이용한 벡터 연산으로 그림을 그려보겠습니다.
캔버스
그림을 그리기 위해서는 그림을 그릴 공간이 필요합니다. 이 프로젝트에서는 이 공간을 xrange, yrange 라는 변수로 지정하겠습니다. 만약,
xrange = [1, 3]
yrange = [2, 4]
라면, 그림을 그릴 캔버스는 (1, 2)(1,2), (3, 4)(3,4) 로 지정된 공간을 사용하게 됩니다.
그림 그리기
그림을 그리기 위해서, 다음 방식을 사용하겠습니다. 어떤 함수 f와 매우 작은 숫자 threshold에 대해,
캔버스 내에 점 P = (x, y)을 임의로 생성한다.
f(P) < threshold 라면 점을 찍는다. 만약 그렇지 않다면, 점을 찍지 않는다.
이것을 100,000 회 반복한다.
왜 f(P) == 0 일때 점을 찍지 않고, 아주 작은 값 threshold 보다 작을 때 점을 찍는지, 한번 생각해 보세요!
예제: 원 그리기
이 예제는 circle 함수에 정의되어 있습니다.
(0, 0)(0,0) 이 중심이고 반지름 1인 원을 그리는 방정식은 다음과 같습니다.
x^2 + y^2 = 1
위의 그림을 그리는 방식을 생각하면, 정확히 원 위에 있는 점들에 대해서 circle(P) 은 0을 가져야 합니다. 그러므로, circle(P) 는 다음과 같이 정의할 수 있습니다.
x = P[0]
y = P[1]
return sqrt(x ** 2 + y ** 2) - 1
return sqrt(np.sum(P * P)) - 1
- 프로젝트
예제로 주어진 원 circle 과 다이아몬드 diamond 함수를 이용해 원과 다이아몬드 그림을 그려봅니다. 그리고, 이것들을 조합해 새로운 그림을 만듭니다. 조합하는 방법은 smile 함수를 참고합니다.
import matplotlib as mpl
mpl.use("Agg")
import matplotlib.pyplot as plt
import elice_utils
import numpy as np
elice = elice_utils.EliceUtils()
def circle(P):
return np.linalg.norm(P) - 1 # 밑의 코드와 동일하게 동작합니다.
# return np.sqrt(np.sum(P * P)) - 1
def diamond(P):
return np.abs(P[0]) + np.abs(P[1]) - 1
def smile(P):
def left_eye(P):
eye_pos = P - np.array([-0.5, 0.5])
return np.sqrt(np.sum(eye_pos * eye_pos)) - 0.1
def right_eye(P):
eye_pos = P - np.array([0.5, 0.5])
return np.sqrt(np.sum(eye_pos * eye_pos)) - 0.1
def mouth(P):
if P[1] < 0:
return np.sqrt(np.sum(P * P)) - 0.7
else:
return 1
return circle(P) * left_eye(P) * right_eye(P) * mouth(P)
def checker(P, shape, tolerance):
return abs(shape(P)) < tolerance
def sample(num_points, xrange, yrange, shape, tolerance):
accepted_points = []
rejected_points = []
for i in range(num_points):
x = np.random.random() * (xrange[1] - xrange[0]) + xrange[0]
y = np.random.random() * (yrange[1] - yrange[0]) + yrange[0]
P = np.array([x, y])
if (checker(P, shape, tolerance)):
accepted_points.append(P)
else:
rejected_points.append(P)
return np.array(accepted_points), np.array(rejected_points)
xrange = [-1.5, 1.5] # X축 범위입니다.
yrange = [-1.5, 1.5] # Y축 범위입니다.
accepted_points, rejected_points = sample(
100000, # 점의 개수를 줄이거나 늘려서 실행해 보세요. 너무 많이 늘리면 시간이 오래 걸리는 것에 주의합니다.
xrange,
yrange,
smile, # smile을 circle 이나 diamond 로 바꿔서 실행해 보세요.
0.005) # Threshold를 0.01이나 0.0001 같은 다른 값으로 변경해 보세요.
plt.figure(figsize=(xrange[1] - xrange[0], yrange[1] - yrange[0]),
dpi=150) # 그림이 제대로 로드되지 않는다면 DPI를 줄여보세요.
plt.scatter(rejected_points[:, 0], rejected_points[:, 1], c='lightgray', s=0.1)
plt.scatter(accepted_points[:, 0], accepted_points[:, 1], c='black', s=1)
plt.savefig("graph.png")
elice.send_image("graph.png")
Leave a comment