Total Least Squares (TLS) Regression
Total Least Squares (TLS) 회귀는 데이터의 모든 방향에서의 오차를 최소화하는 회귀 방법임.
- 이는 특히 독립 변수와 종속 변수 모두에 오차가 포함되어 있는 경우에 유용함.
- TLS는 주로 행렬 분해 기법 (SVD or EVD)을 사용하여 문제를 해결함.
- Fitting에서 사용되어 데이터의 모든 방향에서의 오차를 최소화시키는 regression coefficients를 찾음.
2024.06.13 - [Programming/DIP] - [CV] Fitting
TLS의 주요 개념
일반적으로 Regression 문제는 다음과 같이 주어짐:
$$\mathbf{y} = \mathbf{X} \boldsymbol{\beta} + \boldsymbol{\epsilon}$$
여기서
- $\mathbf{X}$는 독립 변수 행렬,
- $\mathbf{y}$는 종속 변수 벡터,
- $\boldsymbol{\beta}$는 회귀 계수 벡터, 그리고
- $\boldsymbol{\epsilon}$은 오차 벡터임.
TLS는 오차가 $\mathbf{X}$와 $\mathbf{y}$ 모두에 포함될 수 있다고 가정함.
즉, 측정된 $\mathbf{X}$와 $\mathbf{y}$ 모두가 참 값에서 벗어날 수 있음.
Mean Centering
TLS를 수행하기 전, 데이터를 중앙 정렬(mean centering)하여 각 데이터에서 평균을 빼줌.
- 이를 통해 데이터의 중심이 원점으로 이동함.
- Mean Centering의 주요 이유는 다음과 같음:
- 분산을 원점으로 정렬:
- 데이터를 평균이 0이 되도록 변환하면, 데이터의 중심이 원점으로 이동함.
- 이렇게 하면 공분산 행렬이 더 간단하게 계산될 수 있음.
- 분석의 단순화:
- 평균이 0이 되면 회귀 분석의 수식이 단순해짐.
- 회귀 방정식에서 절편(intercept)이 0이 되므로, 기울기(slope)만을 고려하면 됨.
- 이는 해석을 더 쉽게 만듦.
- 수치 안정성:
- 평균을 빼주지 않으면 큰 값들 때문에 수치적으로 불안정한 계산이 발생할 수 있음.
- 평균을 빼서 데이터를 정규화하면 수치적인 안정성을 높일 수 있음.
- 잔차 최소화:
- 평균을 빼준 데이터로 TLS를 수행하면 데이터의 중심으로부터의 오차를 최소화하는 것이므로,
- 더 정확한 회귀 모델을 만들 수 있음.
TLS 수행절차 (EVD 기반)
- Mean Centering:
데이터를 중앙 정렬(mean centering)하여 각 데이터에서 평균을 빼줌.
$$\mathbf{X}_{\text{centered}} = \mathbf{X} - \bar{\mathbf{X}} \\ \mathbf{y}_{\text{centered}} = \mathbf{y} - \bar{\mathbf{y}}$$ - 데이터 행렬 생성:
$$\mathbf{A} = [\mathbf{X}_{\text{centered}} | \mathbf{y}_{\text{centered}}]$$ - 공분산 행렬 계산:
$$\mathbf{C} = \mathbf{A}^T \mathbf{A}$$ - Eigenvalue Decomposition (EVD):
$$
\mathbf{C} = \mathbf{V} \boldsymbol{\Lambda} \mathbf{V}^T
$$- 여기서 $\boldsymbol{\Lambda}$는 eigenvalue로 구성된 대각 행렬이고,
- $\mathbf{V}$는 eigenvector로 구성된 행렬임.
- 작은 eigenvalue에 해당하는 eigenvector 선택:
- 작은 eigenvalue에 해당하는 eigenvector $\mathbf{v}$를 선택함.
- 이 벡터는 $\boldsymbol{\beta}$의 방향을 정의함.
- 회귀 계수 계산:
eigenvector $\mathbf{v}$를 사용하여 TLS 회귀 계수 $\boldsymbol{\beta}$를 계산함:
$$\boldsymbol{\beta} = -\frac{\mathbf{v}_{1:d}}{\mathbf{v}_{d+1}}$$- 여기서 $\mathbf{v}_{1:d}$는 $\mathbf{v}$의 첫 $d$개의 요소 (독립 변수 $\mathbf{X}$의 차원),
- $\mathbf{v}_{d+1}$는 $\mathbf{v}$의 마지막 요소임.
$$
\text{intercept} = \bar{\mathbf{y}} - \boldsymbol{\beta} \cdot \bar{\mathbf{X}}
$$
OLS와의 비교
- OLS (Ordinary Least Squares)는 종속 변수 $\mathbf{y}$에 대한 오차만을 최소화하는 회귀 방법임. OLS는 독립 변수 $\mathbf{X}$에 오차가 없다고 가정함.
- TLS (Total Least Squares)는 독립 변수 $\mathbf{X}$와 종속 변수 $\mathbf{y}$ 모두에 오차가 포함되어 있다고 가정하며, 이 모든 오차를 최소화함.
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
# OLS를 사용한 회귀
def ols_regression(X, y):
ols = LinearRegression()
ols.fit(X, y)
return ols.coef_[0], ols.intercept_
# TLS를 사용한 회귀 (EVD 이용)
def tls_regression(X, y):
# 평균을 원점으로 맞추기 (Mean Centering)
X_mean = np.mean(X)
y_mean = np.mean(y)
X_centered = X - X_mean
y_centered = y - y_mean
# 데이터 행렬 생성
A = np.hstack((X_centered, y_centered))
# 공분산 행렬 계산
cov_matrix = np.cov(A.T)
# Eigen Value Decomposition
eigenvalues, eigenvectors = np.linalg.eig(cov_matrix)
# Eigen values에 따라 정렬
idx = np.argsort(eigenvalues)
eigenvectors = eigenvectors[:, idx]
# TLS 회귀 계수 계산 (작은 eigenvalue에 대응하는 eigenvector 사용)
tls_direction = eigenvectors[:, 0]
a_tls = -tls_direction[0] / tls_direction[1]
b_tls = y_mean - a_tls * X_mean
return a_tls, b_tls, tls_direction
# 데이터 생성
np.random.seed(0)
X = np.linspace(0, 10, 20)
y = 2 * X + 1 + np.random.normal(scale=2, size=X.shape)
X = X.reshape(-1, 1) # X를 2차원 배열로 변환
y = y.reshape(-1, 1) # y를 2차원 배열로 변환
# OLS 회귀
a_ols, b_ols = ols_regression(X, y)
y_pred_ols = a_ols * X + b_ols
# TLS 회귀
a_tls, b_tls, tls_direction = tls_regression(X, y)
y_pred_tls = a_tls * X + b_tls
# 그래프 그리기
plt.scatter(X, y, label='Data')
plt.plot(X, y_pred_ols, color='red', label='OLS fit')
plt.plot(X, y_pred_tls, color='blue', label='TLS fit')
# OLS residuals
for i in range(len(X)):
plt.plot([X[i], X[i]], [y[i], y_pred_ols[i]], color='red', linestyle='dotted')
# TLS residuals in the direction of the eigen vector
tls_direction = tls_direction / np.linalg.norm(tls_direction) # Normalize the direction vector
for i in range(len(X)):
point = np.array([X[i], y[i]]).flatten()
proj_length = np.dot(point - np.array([X[i], a_tls * X[i] + b_tls]).flatten(), tls_direction)
proj_point = point - proj_length * tls_direction
plt.plot([point[0], proj_point[0]], [point[1], proj_point[1]], color='blue', linestyle='dotted')
plt.xlabel('X')
plt.ylabel('y')
plt.legend()
plt.title('Comparison of OLS and TLS with Residuals')
plt.show()
print(f'OLS 회귀 계수: 기울기={a_ols}, 절편={b_ols}')
print(f'TLS 회귀 계수: 기울기={a_tls}, 절편={b_tls}')
2022.04.28 - [.../Math] - Ordinary Least Squares : OLS, 최소자승법
EVD와 SVD를 통한 TLS의 장단점 비교
EVD 기반 TLS
장점:
- 공분산 행렬을 사용하는 방법은 이해하기 쉽고, 구현이 간단함.
- 작은 데이터 세트에서 적절하게 작동할 수 있음.
단점:
- 공분산 행렬의 계산에서 수치적 불안정성이 발생할 수 있음.
- 큰 데이터 세트에서 성능이 떨어질 수 있음.
- 메모리 사용량이 증가할 수 있음.
2022.05.01 - [.../Math] - [Statistics] Covariance vs. Correlation
SVD 기반 TLS
장점:
- 수치적으로 더 안정적이며, 데이터의 크기와 관계없이 잘 작동함.
- 데이터 행렬 자체를 사용하여 계산하므로, 더 많은 정보를 제공함.
- 큰 데이터 세트에서도 효율적임.
단점:
- 이론적으로 더 복잡(?)하며, 이해와 구현이 상대적으로 어려울 수 있음:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
# OLS를 사용한 회귀
def ols_regression(X, y):
ols = LinearRegression()
ols.fit(X, y)
return ols.coef_[0], ols.intercept_
# TLS를 사용한 회귀 (SVD 이용)
def tls_regression_svd(X, y):
# 평균을 원점으로 맞추기 (Mean Centering)
X_mean = np.mean(X)
y_mean = np.mean(y)
X_centered = X - X_mean
y_centered = y - y_mean
# 데이터 행렬 생성
A = np.hstack((X_centered, y_centered))
# SVD 분해
U, S, Vt = np.linalg.svd(A, full_matrices=False)
# TLS 회귀 계수 계산 (작은 singular value에 대응하는 singular vector 사용)
tls_direction = Vt[-1]
a_tls = -tls_direction[0] / tls_direction[1]
b_tls = y_mean - a_tls * X_mean
return a_tls, b_tls, tls_direction
# 데이터 생성
np.random.seed(0)
X = np.linspace(0, 10, 20)
y = 2 * X + 1 + np.random.normal(scale=2, size=X.shape)
X = X.reshape(-1, 1) # X를 2차원 배열로 변환
y = y.reshape(-1, 1) # y를 2차원 배열로 변환
# OLS 회귀
a_ols, b_ols = ols_regression(X, y)
y_pred_ols = a_ols * X + b_ols
# TLS 회귀 (SVD)
a_tls, b_tls, tls_direction = tls_regression_svd(X, y)
y_pred_tls = a_tls * X + b_tls
# 그래프 그리기
plt.scatter(X, y, label='Data')
plt.plot(X, y_pred_ols, color='red', label='OLS fit')
plt.plot(X, y_pred_tls, color='green', label='TLS fit (SVD)')
# OLS residuals
for i in range(len(X)):
plt.plot([X[i], X[i]], [y[i], y_pred_ols[i]], color='red', linestyle='dotted')
# TLS residuals in the direction of the singular vector
tls_direction = tls_direction / np.linalg.norm(tls_direction) # Normalize the direction vector
for i in range(len(X)):
point = np.array([X[i], y[i]]).flatten()
proj_length = np.dot(point - np.array([X[i], a_tls * X[i] + b_tls]).flatten(), tls_direction)
proj_point = point - proj_length * tls_direction
plt.plot([point[0], proj_point[0]], [point[1], proj_point[1]], color='green', linestyle='dotted')
plt.xlabel('X')
plt.ylabel('y')
plt.legend()
plt.title('Comparison of OLS and TLS (SVD) with Residuals')
plt.show()
print(f'OLS 회귀 계수: 기울기={a_ols}, 절편={b_ols}')
print(f'TLS 회귀 계수 (SVD): 기울기={a_tls}, 절편={b_tls}')
결론
TLS를 사용할 때는 데이터의 특성과 크기를 고려하여 적절한 방법을 선택하는 것이 중요함.
작은 데이터 세트에서는 EVD 기반 방법이 충분히 효과적일 수 있지만,
큰 데이터 세트에서는 SVD 기반 방법이 더 나은 성능과 안정성을 제공할 수 있음.
같이 보면 좋은 자료들
https://gist.github.com/dsaint31x/9215404d5f84c063942c9c48666b4794
'Programming > ML' 카테고리의 다른 글
[ML] Radial Basis Function Kernel (RBF Kernel) (1) | 2024.09.26 |
---|---|
[ML] Ensemble 기법 (0) | 2024.09.08 |
[ML] RANdom SAmple Consensus (RANSAC) (0) | 2024.06.13 |
[ML] Feature Scaling (0) | 2024.05.04 |
[ML] Underfit (0) | 2023.09.21 |