데이터를 활용해 머신 러닝 모델을 학스하고 평가하는 과정에 대해 살펴보기
머신 러닝 모델링을 하는 전반적인 과정 알아보기
모델로 해결하고 싶은 문제가 무엇인지 확실하게 정의
문제에 대한 나의 접근 방식 설정
→ 지난 시간 '머니볼' 예시에서 새로운 변수를 만든 것도(OPS(출루율+장타율), WHIP(이닝당 안타와 볼넷 허용률) 등의 지표를 생성
) 피쳐 엔지니어링이라 할 수 있습니다.
→ 데이터가 한정적인 경우(데이터 확보가 어려운 경우) 데이터를 세분화해서(Train/Validation/Test 데이터로 구분) 활용하는 경우가 많습니다.
→ 시계열 데이터의 경우 미래 데이터로 학습해서 과거를 예측하면 당연히 잘 맞추게 되고 bias도 커지겠죠? 그래서 시점을 잘 정해줘야 합니다.
학습 데이터를 이용해 모델을 학습시키기
테스트 데이터를 이용해 모델을 이용한 예측을 진행
성능 지표를 활용해 모델의 성능을 평가
모델 성능을 끌어올리기 위해 모델의 하이퍼 파라미터 값을 변경하며 위 과정을 반복
종류 | Grid Search | Random Search |
---|---|---|
탐색 방식 | 모든 조합 시도 | 랜덤 샘플링 |
장점 | 체계적, 모든 가능성 고려 | 효율적, 적은 계산량 |
단점 | 계산량 많음, 고차원 공간에서 비효율적 | 최적값을 찾지 못할 가능성 |
적용 시기 | 하이퍼파라미터 개수가 작고, 정확한 최적값을 찾아야 할 때 | 하이퍼파라미터 개수가 많고, 빠르게 좋은 결과를 얻고 싶을 때 |
보통 처음 머신 러닝 모델을 돌릴 때는 하이퍼 파라미터를 어떻게 설정해야 할지 모르는 상태이므로 기본 설정값으로 돌리거나 휴리스틱(heuristic)한 값을 넣음
- 휴리스틱(heuristic): '대충 어림짐작하기'입니다. (눈대중으로 맞추기, 즉흥적으로 맞추기, 주먹구구식으로 맞추기 등)
- 사람의 심리에 기반을 두고 무엇인가가 대충 이럴 것이다 라고 빠르게 판단을 내리는 것
→ 원인, 상관관계, 어떤 변수에 집중해야 하는지를 알 수 있음
(머신러닝, 딥러닝의 경우 아웃풋은 인간과 유사하게 원하는 대로 도출할 수 있지만 어떻게&무엇을 근거로 그러한 결과가 나왔는지는 알 수 없음 → BLACK BOX)
딥러닝이 학습하면서 하는 일은 절대적인 정답 또는 해답을 찾는 것이 아닙니다. 인풋이 있을 때 '어떻게' 원하는 아웃풋을 도출하는지를 찾는 것입니다. 일반적으로는 많은 데이터와 지도 학습(supervised learning)을 이용하여 학습시키는데, 어떤 데이터가 주어지느냐에 따라 그 기준도 '상대적'으로 달라질 것입니다.
이 때 내부적으로 원하는 아웃풋을 도출해내기 위한 여러가지 기준을 정하게 되는데 우리는 그 내부를 들여다볼 수 없습니다. 최근의 딥러닝 모델들은 레이어가 최소 수십개로 '딥'하게 학습하기 떄문에 그 계산이 굉장히 복잡하기 때문입니다.
99%의 정확도로 암을 진단하는, 딥러닝으로 학습시킨 AI 가 있다고 해보죠. 이 AI가 어떤 환자를 암으로 진단했는데 현대의 의료기술로는 암이라는 증거를 찾을 수 없었습니다. 그렇다면 이 AI는 학습하는 과정에서 자신만의 기준을 찾았다는 것인데 그것은 굉장히 중요한 발견일 수 있습니다. 하지만 그 기준은 설계한 사람이라도 알 수 없습니다.
🡆 어떤 task를 수행하는지에 따라 평가 지표를 다르게 적용해야 함!
위에서 배운 내용을 바탕으로 머신 러닝 모델링 과정 예제 코드 살펴보기
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import math
from sklearn import datasets
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
import warnings
warnings.filterwarnings('ignore')
dataset_housing = datasets.fetch_california_housing()
df_housing = pd.DataFrame(dataset_housing.data, columns=dataset_housing.feature_names)
df_housing['target'] = dataset_housing.target
print(df_housing.shape) # 사이즈 확인
df_housing.head()
## 1. 위치 데이터를 활용한 새로운 피처 생성 -> 공항까지의 거리
## 캘리포니아 주의 5대 공항의 위치 정보를 이용해서 가장 가까운 공항까지의 거리를 새로운 변수로 생성
def calculate_distance(lat, lon):
# 공항 위도, 경도 리스트
airport_lat_lon_list = [(33.9425, -118.4085), (37.6189, -122.3749), (32.7333, -117.1894), (33.6747, -117.8533), (37.3625, -121.929)]
dist_airport_list = []
for airport_lat_lon in airport_lat_lon_list:
airport_lat, airport_lon = airport_lat_lon
# 위도, 경도를 radian 값으로 변환
lat1, lon1, lat2, lon2 = map(math.radians, [lat, lon, airport_lat, airport_lon])
# Haversine formula
dlat = lat2 - lat1
dlon = lon2 - lon1
a = math.sin(dlat/2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon/2)**2
c = 2 * math.asin(math.sqrt(a))
# Radius of earth in kilometers
r = 6371
# Calculate the distance
distance = c * r
dist_airport_list.append(distance)
res = min(dist_airport_list)
return res
df_housing['dist_airport'] = df_housing.apply(lambda row: calculate_distance(row['Latitude'], row['Longitude']), axis=1)
df_housing.head()
# 데이터 분리
X = df_housing.drop(['target', 'Latitude', 'Longitude'], axis=1)
y = df_housing['target']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 데이터 스케일링
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# Scikit-Learn 의 선형회귀 모델 사용
linear_reg = LinearRegression()
linear_reg.fit(X_train_scaled, y_train)
# 학습 데이터를 입력했을 떄의 모델 성능
y_insample_linear = linear_reg.predict(X_train_scaled)
insample_rmse_linear = mean_squared_error(y_train, y_insample_linear)**0.5
insample_r2_linear = r2_score(y_train, y_insample_linear)
print(f"In-Sample RMSE: {insample_rmse_linear:.4f}")
print(f"In-Sample R²: {insample_r2_linear:.4f}")
[실행 결과]
In-Sample RMSE: 0.7468
In-Sample R²: 0.5828
# 예측 및 평가
y_pred_linear = linear_reg.predict(X_test_scaled)
rmse_linear = mean_squared_error(y_test, y_pred_linear)**0.5
r2_linear = r2_score(y_test, y_pred_linear)
print(f"RMSE: {rmse_linear:.4f}")
print(f"R²: {r2_linear:.4f}")
[실행 결과]
RMSE: 0.7659
R²: 0.5524
# 결과 그래프
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred_linear)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
plt.title('Price Prediction - Linear Regression')
plt.xlabel('Actual ($100K)')
plt.ylabel('Predict ($100K)')
plt.tight_layout()
plt.show()
print("\n특징별 계수:")
for name, coef in zip(X.columns, linear_reg.coef_):
print(f"{name}: {coef:.4f}")
[실행 결과]
특징별 계수:
MedInc: 0.8845
HouseAge: 0.1440
AveRooms: -0.3327
AveBedrms: 0.3408
Population: -0.0091
AveOccup: -0.0420
dist_airport: -0.2590
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
import seaborn as sns
data_iris = load_iris()
df_iris = pd.DataFrame(data_iris.data, columns=data_iris.feature_names)
df_iris['target'] = data_iris.target
df_iris.head()
# 데이터 스케일링
X = df_iris.drop('target', axis=1)
y = df_iris['target']
scaler = StandardScaler()
X_iris_scaled = scaler.fit_transform(X)
kmeans = KMeans(n_clusters=3, random_state=1)
kmeans_labels = kmeans.fit_predict(X_iris_scaled)
print(kmeans_labels)
[실행 결과]
특징별 계수:
[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 0 1 1 1 1 1 1 1 1 2 2 2 0 2 0 2 0 2 0 0 0 0 0 0 2 0 0 0 0 2 0 0 0
0 2 2 2 0 0 0 0 0 0 0 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 2 2 2 2 0 2 2 2 2
2 2 0 2 2 2 2 2 0 2 0 2 2 2 2 2 2 2 2 2 2 2 2 0 2 2 2 2 2 2 2 0 2 2 2 0 2
2 2]
# 결과를 시각화하여 실제 값과 비교
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_iris_scaled)
plt.figure(figsize=(15, 5))
# K-means 클러스터링 결과
plt.subplot(121)
scatter = plt.scatter(X_pca[:, 0], X_pca[:, 1], c=kmeans_labels, cmap='viridis')
plt.title('K-means Result')
plt.colorbar(scatter)
# 실제 타겟값
plt.subplot(122)
scatter = plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y, cmap='viridis')
plt.title('Actual Iris')
plt.colorbar(scatter)
# 실제 값과 새롭게 분류된 라벨을 기준으로 했을 떄의 피처 평균값
feature_summary = df_iris.groupby('target').mean()
print(feature_summary.sort_values(by='sepal length (cm)', ascending=False))
[실행 결과]
sepal length (cm) sepal width (cm) petal length (cm) \
target
2 6.588 2.974 5.552
1 5.936 2.770 4.260
0 5.006 3.428 1.462
petal width (cm) cluster
target
2 2.026 1.68
1 1.326 0.52
0 0.246 0.98
df_iris['cluster'] = kmeans_labels
feature_summary_cluster = df_iris.groupby('cluster').mean().drop('target', axis=1)
print(feature_summary_cluster.sort_values(by='sepal length (cm)', ascending=False))
[실행 결과]
sepal length (cm) sepal width (cm) petal length (cm) \
cluster
2 6.696364 3.060000 5.418182
0 5.704348 2.634783 4.215217
1 5.016327 3.451020 1.465306
petal width (cm)
cluster
2 1.938182
0 1.332609
1 0.244898