Coding Test/Machine Learning (NeetCode)
Linear Regression (Forward): 선형 회귀 (모델 구현)
hyunkookim
2025. 4. 24. 13:25
Linear Regression (Forward)
📘 문제 설명: 선형 회귀 (Linear Regression) 모델 구현
🎯 목표
- 선형 회귀 모델을 통해 입력 데이터 에 대해 예측값을 구하고,
- 예측값과 실제 정답 간의 오차(error) 를 계산하는 함수를 구현하는 것입니다.
🔢 주어진 입력
1. get_model_prediction(X, weights) 함수의 입력:
- X: 입력 데이터셋.
는 n×3 행렬 형태이며, 각 행은 3개의 특성(피처)을 가집니다. 예:
X = [
[x1_1, x1_2, x1_3], # 첫 번째 샘플
[x2_1, x2_2, x2_3], # 두 번째 샘플
...
]
- weights: 모델의 가중치 벡터, 길이 3인 리스트로 구성됨.
예: [w1, w2, w3]
2. get_error(model_prediction, ground_truth) 함수의 입력:
- model_prediction: 위 함수에서 예측한 결과값 리스트
- ground_truth: 정답값 리스트
🔍 요약
함수 이름 | 기능 설명 |
get_model_prediction(X, weights) | 각 샘플에 대해 선형식을 적용해 예측값을 계산 |
get_error(model_prediction, ground_truth) | 예측값과 실제값 간 평균 제곱 오차(MSE)를 계산 |
class Solution:
def get_minimizer(self, iterations: int, learning_rate: float, init: int) -> float:
# 초기값 x 설정 (초기 추정값)
x = init
# 설정한 반복 횟수만큼 경사 하강법을 수행
for _ in range(iterations):
# 함수 f(x) = x^2의 도함수는 f'(x) = 2x 이므로, 현재 x에서의 기울기(gradient)는 2x
gradient = 2 * x
# 경사 하강법 공식: x = x - learning_rate * gradient
# 기울기 방향의 반대 방향으로 learning_rate 만큼 이동
x -= learning_rate * gradient
# 최종적으로 얻어진 x 값을 소수점 5자리까지 반올림하여 반환
return round(x, 5)
def get_model_prediction(self, X, weights):
# 예측 결과를 저장할 리스트 초기화
predictions = []
# 각 샘플에 대해 계산
for sample in X:
# sample = [x1, x2, x3], weights = [w1, w2, w3] 일 때
# 예측값 = w1*x1 + w2*x2 + w3*x3 (내적 계산)
prediction = sum(x * w for x, w in zip(sample, weights))
predictions.append(prediction)
# 모든 샘플에 대한 예측값 리스트 반환
return predictions
def get_error(self, model_prediction, ground_truth):
# 샘플 수
n = len(model_prediction)
# 오차의 제곱을 모두 더함
total_squared_error = 0
for pred, actual in zip(model_prediction, ground_truth):
total_squared_error += (pred - actual) ** 2
# 평균 제곱 오차 (Mean Squared Error)를 반환
return total_squared_error / n
코드에 상세한 한글 주석을 추가했습니다. 주요 포인트는 다음과 같습니다:
- get_model_prediction: 각 샘플에 대해 가중치와 입력의 내적(dot product)을 계산하여 예측값 리스트를 반환합니다.
- get_error: 예측값과 실제값 사이의 평균 제곱 오차(Mean Squared Error, MSE)를 계산합니다.
import numpy as np
from numpy.typing import NDArray
# Helpful functions:
# https://numpy.org/doc/stable/reference/generated/numpy.matmul.html
# https://numpy.org/doc/stable/reference/generated/numpy.mean.html
# https://numpy.org/doc/stable/reference/generated/numpy.square.html
class Solution:
def get_model_prediction(self, X: NDArray[np.float64], weights: NDArray[np.float64]) -> NDArray[np.float64]:
# X is an Nx3 NumPy array [[x1_1, x1_2, x1_3], [x2_1, x2_2, x2_3], ... [xN_1, xN_2, xN_3] ]
# weights is a 3x1 NumPy array [w1, w2, w4]T
# HINT: np.matmul() will be useful
# return np.round(your_answer, 5)
def get_error(self, model_prediction: NDArray[np.float64], ground_truth: NDArray[np.float64]) -> float:
# model_prediction is an Nx1 NumPy array
# ground_truth is an Nx1 NumPy array
# HINT: np.mean(), np.square() will be useful
# return round(your_answer, 5)
import numpy as np
from numpy.typing import NDArray
class Solution:
def get_model_prediction(self, X: NDArray[np.float64], weights: NDArray[np.float64]) -> NDArray[np.float64]:
# X는 (N, 3) 형태의 2차원 배열, 각 행은 하나의 샘플이고 3개의 특성값을 가짐
# weights는 (3,) 또는 (3,1) 형태의 1차원 또는 2차원 가중치 벡터
# np.matmul(X, weights): X와 weights의 행렬 곱 => (N,) 또는 (N,1) 벡터로 예측값 생성
prediction = np.matmul(X, weights)
# 결과를 소수점 다섯째 자리까지 반올림하여 반환
return np.round(prediction, 5)
def get_error(self, model_prediction: NDArray[np.float64], ground_truth: NDArray[np.float64]) -> float:
# 평균 제곱 오차(MSE): mean((예측값 - 실제값)^2)
squared_error = np.square(model_prediction - ground_truth) # 제곱 오차 계산
mean_squared_error = np.mean(squared_error) # 평균 계산
# 결과를 소수점 다섯째 자리까지 반올림하여 반환
return round(mean_squared_error, 5)
import numpy as np
from numpy.typing import NDArray
# Helpful functions:
# https://numpy.org/doc/stable/reference/generated/numpy.matmul.html
# https://numpy.org/doc/stable/reference/generated/numpy.mean.html
# https://numpy.org/doc/stable/reference/generated/numpy.square.html
class Solution:
def get_model_prediction(self, X: NDArray[np.float64], weights: NDArray[np.float64]) -> NDArray[np.float64]:
# X is an Nx3 NumPy array [[x1_1, x1_2, x1_3], [x2_1, x2_2, x2_3], ... [xN_1, xN_2, xN_3] ]
# weights is a 3x1 NumPy array [w1, w2, w4]T
# HINT: np.matmul() will be useful
# return np.round(your_answer, 5)
preds = []
for sample in X:
# 각 sample (1x3 벡터)와 weights (3x1 벡터)의 내적을 수동으로 계산
# zip을 통해 (x1, w1), (x2, w2), (x3, w3) 식으로 묶어서 곱한 후 모두 더함
preds.append(sum([x * w for x, w in zip(sample, weights)]))
# 예측값 리스트를 넘파이 배열로 변환 후, 소수점 다섯째 자리까지 반올림하여 반환
return np.round(np.array(preds), 5)
def get_error(self, model_prediction: NDArray[np.float64], ground_truth: NDArray[np.float64]) -> float:
# model_prediction is an Nx1 NumPy array
# ground_truth is an Nx1 NumPy array
# HINT: np.mean(), np.square() will be useful
# return round(your_answer, 5)
n = len(model_prediction)
mse = 0
# flatten: (n, 1) → (n,)로 평탄화하여 각 값이 float이 되도록 처리
# 그렇지 않으면 zip에서 각 원소가 배열로 묶여 연산 시 오류 발생 가능
for gt, pred in zip(ground_truth.flatten(), model_prediction.flatten()):
# 정답값(gt)과 예측값(pred)의 차이를 제곱하여 누적합
mse += (gt - pred) ** 2
# 평균 제곱 오차(MSE)를 계산하고, 소수점 다섯째 자리까지 반올림하여 반환
return round(mse / n, 5)