데이터 값이 평균과 같은 일정한 값으로 돌아가려는 경향을 이용한 통계학 기법
여러 개의 독립변수와 한 개의 종속변수 간의 상관관계를 모델링하는 기법을 통칭
머신러닝 관점에서 보면 독립변수는 피처에 해당되며 종속변수는 결정값이다.
머신러닝 회귀 예측의 핵심은 주어진 피처와 결정값 데이터 기반에서 학습을 통해 최적의 회귀계수를 찾아내는 것이다.
회귀는 회귀 계수의 선형/비선형 여부, 독립변수의 개수, 종속변수의 개수에 따라 여러 가지 유형으로 나눌 수 있다.
독립변수 개수
회귀 계수의 결합
지도학습은 분류와 회귀로 나뉘며, 이 두 가지 기법의 가장 큰 차이는 분류는 예측값이 카테고리와 같은 이산형 클래스 값이고 회귀는 연속형 숫자 값이라는 것이다.
여러 가지 회귀 중에서 선형 회귀가 가장 많이 사용된다.
선형 회귀 모델은 규제 방법에 따라 다시 별도의 유형으로 나뉠 수 있다.
(1) 일반 선형 회귀
(2) 릿지(Ridge)
선형 회귀에 L2 규제를 추가한 회귀 모델
L2 규제는 상대적으로 큰 회귀 계수 값의 예측 영향도를 감소시키기 위해서 회귀 계수값을 더 작게 만드는 규제 모델
(3) 라쏘(Lasso)
선형 회귀에 L1 규제를 적용한 방식
L2 규제가 회귀 계수 값의 크기를 줄이는 데 반해, L1 규제는 예측 영향력이 작은 피처의 회귀 계수를 0으로 만들어 회귀 예측 시 피처가 선택되지 않게 하는 것으로 L1 규제는 피처 선택 기능으로도 불린다.
(4) 엘라스틱넷(ElasticNet)
L2, L1 규제를 함께 결합한 모델
주로 피처가 많은 데이터 세트에서 적용되며, L1 규제로 피처의 개수를 줄임과 동시에 L2 규제로 계수 값의 크기를 조정
(5) 로지스틱 회귀(Logistic Regression)
분류에 사용되는 선형 모델
일반적으로 이진 분류뿐만 아니라 희소 영역의 분류, 예를 들어 텍스트 분류와 같은 영역에서 뛰어난 예측 성능을 보인다.
- : 예측값
- : 절편
- : 기울기
잔차: 실제 값과 회귀 모델의 예측값의 차이에 따른 오류 값
최적의 회귀 모델을 만든다는 것은 바로 전체 데이터의 잔차(오류 값) 합이 최소가 되는 모델을 만든다는 의미이다. 즉, 오류 값 합이 최소가 될 수 있는 최적의 회귀 계수를 찾는다는 의미도 된다.
오류 값은 +나 -가 될 수 있다. 그래서 전체 데이터의 오류 합을 구하기 위해 단순히 더했다가는 뜻하지 않게 오류 합이 크게 줄어들 수 있다. 따라서 보통 오류 합을 계산할 때는 절댓값을 취해서 더하거나(Mean Absolute Error), 오류 값의 제곱을 구해서 더하는 방식(RSS, Residual Sum of Squares)을 취한다.
일반적으로 미분 등의 계산을 편리하게 하기 위해서 RSS 방식으로 오류 합을 구한다.
- 비용(Cost): RSS
- 비용 함수(손실 함수, loss function): w 변수(회귀 계수)로 구성되는 RSS
( 는 1부터 학습 데이터의 총 건수 N까지 )
- 머신러닝 회귀 알고리즘은 데이터를 계속 학습하면서 이 비용 함수가 반환하는 값을 지속해서 감소시키고 최종적으로는 더 이상 감소하지 않는 최소의 오류 값을 구하는 것이다.
점진적으로 반복적인 계산을 통해 W 파라미터 값을 업데이트하면서 오류 값이 최소가 되는 W 파라미터를 구하는 방식
반복적으로 비용 함수의 반환 값, 즉 예측값과 실제 값의 차이가 작아지는 방향성을 가지고 W 파라미터를 지속해서 보정해 나간다. 그리고 오류 값이 더 이상 작아지지 않으면 그 오류 값을 최소 비용으로 판단하고 그때의 W 값을 최적 파라미터로 반환한다.
비용 함수가 포물선 형태의 2차 함수라면 경사 하강법은 최초 w에서부터 미분을 적용한 뒤 이 미분 값이 계속 감소하는 방향으로 순차적으로 w를 업데이트하고, 마침내 더 이상 미분된 1차 함수의 기울기가 감소하지 않는 지점을 비용 함수가 최소인 지점으로 간주하고 그때의 w를 반환한다.
def get_cost(y, y_pred): N = len(y) cost = np.sum(np.square(y - y_pred))/N return cost
새로운 w 업데이트는 이전 w에서 편미분 결괏값을 마이너스(-)하면서 적용한다.
# w1과 w0를 업데이트 할 w1_update, w0_update를 반환 def get_weight_updates(w1, w0, X, y, learning_rate=0.01): N = len(y) # 먼저 w1_update, w0_update를 각각 w1, w0의 shape와 동일한 크기를 가진 0 값으로 초기화 w1_update = np.zeros_like(w1) w0_update = np.zeros_like(w0) # 예측 배열 계산하고 예측과 실제 값의 차이 계산 y_pred = np.dot(X, w1.T) + w0 diff = y-y_pred # w0_update를 dot 행렬 연산으로 구하기 위해 모두 1값을 가진 행렬 생성 w0_factors = np.ones((N,1)) # w1과 w0을 업데이트할 w1_update와 w0_update 계산 w1_update = -(2/N)*learning_rate*(np.dot(X.T, diff)) w0_update = -(2/N)*learning_rate*(np.dot(w0_factors.T, diff)) return w1_update, w0_update # 입력 인자 iters로 주어진 횟수만큼 반복적으로 w1과 w0를 업데이트 적용 def gradient_descent_steps(X, y, iters=10000): # w0와 w1을 모두 0으로 초기화. w0 = np.zeros((1,1)) w1 = np.zeros((1,1)) # 인자로 주어진 iters 만큼 반복적으로 get_weight_updates() 호출하여 w1, w0 업데이트 수행 for ind in range(iters): w1_update, w0_update = get_weight_updates(w1, w0, X, y, learning_rate=0.01) w1 = w1 - w1_update w0 = w0 - w0_update return w1, w0 # 최종 w1, w0 값 w1, w0 = gradient_descent_steps(X, y, iters=1000) print("w1:{0:.3f} w0:{1:.3f}".format(w1[0,0], w0[0,0])) # RSS 계산 y_pred = w1[0,0] * X + w0 print('Gradient Descent Total Cost:{0:.4f}'.format(get_cost(y, y_pred))) # 0.9935
📝 경사 하강법의 일반적인 프로세스 정리
STEP1
를 임의의 값으로 설정하고 첫 비용 함수의 값을 계산한다.
STEP2
을 ,
를
업데이트한 후 다시 비용 함수의 값을 계산한다.
STEP3
비용 함수의 값이 감소했으면 다시 STEP2를 반복한다.
더 이상 비용 함수의 값이 감소하지 않으면 그때의 를 구하고 반복을 중지한다.
일반적으로 경사 하강법은 모든 학습 데이터에 대해 반복적으로 비용 함수 최소화를 위한 값을 업데이트하기 때문에 수행 시간이 매우 오래 걸린다는 단점이 있다.
따라서 실전에서는 대부분 확률적 경사 하강법을 이용한다.
확률적 경사 하강법 (Stochastic Gradient Descent)
전체 데이터가 아닌 일부 데이터만 이용해 w가 업데이트되는 값을 계산하므로 경사 하강법에 비해서 빠른 속도를 보장한다.
대용량 데이터의 경우 대부분 확률적 경사 하강법(batch_size=1)이나 미니 배치 확률적 경사 하강법(batch_size=지정)을 이용해 최적 비용 함수를 도출한다.
def stochastic_gradient_descent_steps(X, y, batch_size=10, iters=1000): w0 = np.zeros((1,1)) w1 = np.zeros((1,1)) for ind in range(iters): np.random.seed(ind) # 전체 X, y 데이터에서 랜덤하게 batch_size만큼 데이터 추출하여 sample_X, sample_y로 저장 stochastic_random_index = np.random.permutation(X.shape[0]) sample_X = X[stochastic_random_index[0:batch_size]] sample_y = y[stochastic_random_index[0:batch_size]] # 랜덤하게 batch_size만큼 추출된 데이터 기반으로 w1_update, w0_update 계산 후 업데이트 w1_update, w0_update = get_weight_updates(w1, w0, sample_X, sample_y, learning_rate=0.01) w1 = w1 - w1_update w0 = w0 - w0_update # 최종 w1, w0 값 w1, w0 = stochastic_gradient_descent_steps(X, y, iters=1000) print("w1:",round(w1[0,0],3),"w0:",round(w0[0,0],3)) # RSS 계산 y_pred = w1[0,0] * X + w0 print('Stochastic Gradient Descent Total Cost:{0:.4f}'.format(get_cost(y, y_pred))) # 0.9937
- 경사 하강법과 예측 성능상의 차이가 크게 없다.
MAE
: Mean Absolute Error, 실제 값과 예측값의 차이를 절댓값으로 변환해 평균한 것
MSE
: Mean Squared Error, 실제 값과 예측값의 차이를 제곱해 평균한 것
RMSE
: Root Mean Squared Error, MSE에 루트를 씌운 것
R²
: 분산 기반으로 예측 성능을 평가한다. 실제 값의 분산 대비 예측값들의 분산 비율을 지표로 하며, 1에 가까울수록 예측 정확도가 높다.
이 밖에 MSE나 RMSE에 로그를 적용한 MSLE
(Mean Squared Log Error), RMSLE
(Root Mean Squared Log Error)도 사용한다.