본문 바로가기
AI/참고자료

[AI] 선형대수와 머신러닝

by SeungyubLee 2025. 10. 23.

※ 머신러닝은 세상을 숫자로 표현하는 일

머신러닝은 세상을 숫자로 바꾸는 과정이다.

예를 들어,

고양이 사진을 생각해보자, 사진은 수천 개의 픽셀로 이루어져 있고, 각 픽셀에는 색상(밝기, 빨강, 초록, 파랑 값)이 들어 있다.

즉, 고양이 한 장의 이미지는 사실 "숫자가 아주 많이 들어 있는 표(행렬)"이다.

 

머신러닝은 이 숫자표(행렬)를 다루는 일이기 때문에, 숫자표를 계산하고 변형하는 기술이 꼭 필요하다.
그게 바로 선형대수(Linear Algebra)이다.

※ 선형대수는 숫자표(행렬)를 다루는 기술

선형대수는 벡터(vector)와 행렬(matrix)을 다루는 수학이다.

개념 의미 예시
벡터 방향과 크기를 가진 숫자들의 모임 [1, 2, 3]
행렬 여러 벡터를 모아놓은 표 [[1,2,3],[4,5,6],[7,8,9]]

 

이 벡터와 행렬을 이용해

입력 데이터(예 : 이미지, 텍스트, 수치)를 표현하고,

가중치(weight)를 곱해서 예측을 계산하고,

여러 층(layer)을 연결하여 딥러닝 모델을 구성한다.
즉, 모든 계산이 벡터와 행렬의 연산으로 이뤄진다.

※ 예시로 보는 행렬 연산의 의미

예를 들어,

"광고비, 제품 가격, 날씨로 매출을 예측하고 싶다." 이런 문제를 컴퓨터가 계산하려면,

매출 = (광고비 × a) + (제품가격 × b) + (날씨 × c)

이걸 수백, 수천 개의 데이터로 처리해야 한다. 이걸 하나하나 계산하면 너무 느리기 때문에,

한 번에 계산할 수 있게 만든 것이 행렬 곱셈이다.

즉, 여러 개의 숫자 관계를 한꺼번에 계산하는 도구 = 선형대수

※ 선형대수는 공간에서의 변화를 표현하는 언어

조금 더 감각적으로 보면, 선형대수는 공간을 변형시키는 언어이다.

벡터 → 한 점의 위치
행렬 곱셈 → 그 공간을 회전, 이동, 확대, 축소시키는 동작

딥러닝에서는 이런 변형이 "특징을 추출하고 패턴을 찾는 과정"과 같다.

예를 들어,

"고양이 귀 방향이 바뀌어도 인식할 수 있게 하려면?" 이미지를 회전, 이동, 확대시켜도 본질을 파악해야 한다.

이때 필요한 것이 선형대수 기반의 변환(행렬 연산)이다.

※ 요약

선형대수는 머신러닝이 "데이터를 이해하고 변형할 수 있게" 만드는 언어이다.
벡터와 행렬이 바로 머신러닝의 '문법'이다.


1) 선형대수 기본 개념


2) 선형대수 기본 수식


3) 기본 수식 활용 파이썬 코드

import numpy as np

# 벡터, 행렬 생성
a = np.array([2, 3])
b = np.array([4, 1])
A = np.array([[2, 1],
              [1, 3]])

# 1) 내적
dot = np.dot(a, b)
print("a·b =", dot)

# 2) 행렬-벡터 곱
Av = A @ a
print("A·a =", Av)

# 3) 노름
norm_a = np.linalg.norm(a)
print("||a|| =", norm_a)

# 4) 역행렬
A_inv = np.linalg.inv(A)
print("A^-1 =\n", A_inv)

# 5) 고유값 / 고유벡터
eigvals, eigvecs = np.linalg.eig(A)
print("고유값 =", eigvals)
print("고유벡터 =\n", eigvecs)

# 6) SVD
U, S, Vt = np.linalg.svd(A)
print("U=\n", U)
print("S=", S)
print("V^T=\n", Vt)

4) 머신러닝에 필요한 수식


5) 머신러닝에 필요한 수식 활용 파이썬 코드

▶ 선형회귀 해석해 구하기 (정규방정식)

import numpy as np

# 데이터 생성
rng = np.random.default_rng(0)
X = rng.normal(size=(100, 2))
true_w = np.array([3.0, -2.0])
y = X @ true_w + rng.normal(scale=0.5, size=100)

# 닫힌 해 (Normal Equation)
w_hat = np.linalg.inv(X.T @ X) @ X.T @ y

print("추정된 가중치 =", w_hat)
print("실제 가중치 =", true_w)

 

PCA 구현 (고유값 분해 기반)

import numpy as np

# 데이터 (2D -> 1D로 축소)
X = np.random.randn(200, 2)
X[:, 1] = 0.8 * X[:, 0] + 0.1 * np.random.randn(200)

# 1) 평균 중심화
X_centered = X - X.mean(axis=0)

# 2) 공분산 행렬
cov = np.cov(X_centered, rowvar=False)

# 3) 고유값 분해
eigvals, eigvecs = np.linalg.eig(cov)

# 4) 최대 고유값의 고유벡터 선택 (주성분)
idx = np.argmax(eigvals)
pc1 = eigvecs[:, idx]

# 5) 투영
X_reduced = X_centered @ pc1

print("주성분 벡터:", pc1)
print("축소된 차원 shape:", X_reduced.shape)

 

SVD를 이용한 차원 축소

import numpy as np

# 3x3 행렬을 SVD로 분해 후, 상위 2개만 사용해 근사
X = np.array([[5, 4, 3],
              [4, 3, 2],
              [3, 2, 1]], dtype=float)

U, S, Vt = np.linalg.svd(X, full_matrices=False)

# 상위 2개 특이값만 사용
k = 2
S_k = np.diag(S[:k])
X_approx = U[:, :k] @ S_k @ Vt[:k, :]

print("원본 행렬:\n", X)
print("근사 행렬(2차원):\n", np.round(X_approx, 2))

 

벡터 정규화 & 투영

import numpy as np

a = np.array([3, 4])
b = np.array([2, 1])

# 정규화
a_norm = a / np.linalg.norm(a)
b_norm = b / np.linalg.norm(b)
print("정규화된 a:", a_norm)

# a를 b에 투영
proj_a_on_b = (np.dot(a, b) / np.dot(b, b)) * b
print("a를 b에 투영한 벡터:", proj_a_on_b)