knn 모델 마지막
여러기법 적용해보기
from joblib import Parallel, delayed
train_df = train_no_duplicates
test_df = test
# 특성 선택
features = ['latitude', 'longitude', 'area_m2', 'floor', 'built_year', 'contract_year_month']
# Train 데이터를 train과 validation으로 분리
train_df, val_df = train_test_split(train_df, test_size=0.2, random_state=42)
# 스케일링
scaler = StandardScaler()
train_scaled = scaler.fit_transform(train_df[features])
val_scaled = scaler.transform(val_df[features])
test_scaled = scaler.transform(test_df[features])
# 특성 가중치 조정
weights = np.array([1, 1, 5, 0.5, 0.5, 0.5]) # latitude, longitude, area_m2, floor, built_year, contract_year_month 순서
train_scaled = train_scaled * weights
val_scaled = val_scaled * weights
test_scaled = test_scaled * weights
# BallTree 구축
tree = BallTree(train_scaled, leaf_size=40)
# 예측 함수
def predict_deposit(neighbors, distances):
weights = 1 / (distances + 1e-5)
weighted_deposits = neighbors['deposit'] * weights
return np.sum(weighted_deposits) / np.sum(weights)
# 단일 예측 함수
def predict_single(data_point, min_k, max_k):
distances, indices = tree.query([data_point], k=max_k)
k = min(max_k, max(min_k, int(np.sum(distances < np.median(distances)))))
neighbor_indices = indices[0][:k]
neighbor_distances = distances[0][:k]
neighbors = train_df.iloc[neighbor_indices]
return predict_deposit(neighbors, neighbor_distances)
# 병렬 예측 수행 함수
def make_predictions_parallel(data_scaled, min_k, max_k):
return Parallel(n_jobs=-1)(delayed(predict_single)(data_point, min_k, max_k) for data_point in data_scaled)
# Validation 예측
min_k = 3
max_k = 10
val_predictions = make_predictions_parallel(val_scaled, min_k, max_k)
# Validation MAE 계산
val_mae = mean_absolute_error(val_df['deposit'], val_predictions)
print(f"Validation MAE: {val_mae}")
# Test 예측
test_predictions = make_predictions_parallel(test_scaled, min_k, max_k)
여기부터였나?
이상치 처리
def handle_outliers(predictions, threshold=3):
median = np.median(predictions)
mad = np.median(np.abs(predictions - median))
lower_bound = median - threshold * mad
upper_bound = median + threshold * mad
return np.clip(predictions, lower_bound, upper_bound)
predictions = make_predictions(test_scaled, k)
predictions = handle_outliers(predictions)
Validation MAE: 8552.217652688742
앙상블
def ensemble_predictions(data_scaled, k_values):
all_predictions = []
for k in k_values:
predictions = make_predictions(data_scaled, k)
all_predictions.append(predictions)
return np.mean(all_predictions, axis=0)
test_predictions = ensemble_predictions(test_scaled, [3, 5, 7, 9])
Validation MAE: 8405.48183286097
거리에 따른 가중치 함수 조정
def predict_deposit(neighbors, distances):
weights = np.exp(-distances) # 지수 함수 사용
weighted_deposits = neighbors['deposit'] * weights
return np.sum(weighted_deposits) / np.sum(weights)
StandardScaler, RobustScaler, MinMaxScaler / 로그변환 비교
기존의 StandardScaler방식을 다른 방식으로도 적용해보았다.
StandardScaler without Log Transform - Validation MAE: 8405.48183286097
StandardScaler with Log Transform - Validation MAE: 8468.876950218077
RobustScaler without Log Transform - Validation MAE: 8584.839449059366
RobustScaler with Log Transform - Validation MAE: 8540.002242918164
MinMaxScaler without Log Transform - Validation MAE: 8566.245673670523
MinMaxScaler with Log Transform - Validation MAE: 8771.50220388082
Results sorted by MAE:
StandardScaler without Log: 8405.48183286097
StandardScaler with Log: 8468.876950218077
RobustScaler with Log: 8540.002242918164
MinMaxScaler without Log: 8566.245673670523
RobustScaler without Log: 8584.839449059366
MinMaxScaler with Log: 8771.50220388082
Best method: StandardScaler without Log with MAE: 8405.48183286097
기존의 정규화 방법이 가장 성능이 좋았고, 아마 이때까지도 1/100 sampleing 한 걸로 해서 확실한 그건진 모르겠지만 사실 이때까지도 무슨 한번 돌리는데 20분넘어가는 코드들이 너무 많아서 살짝 어지러웠다. 입력 하면 딱 출력 바로바로 나오고 판단하고 싶은데 공부의 속도에 진전이 너무 느렸다. 스트레스 받을 뻔.
거리 계산 방식을 변경
기존의 유클리드 거리 방식을 3가지로 나누어 비교해보았다. 맨해튼 방식이 가장 성능이 좋게 나오긴 했다.
Euclidean Validation MAE: 8486.101253090092
Manhattan Validation MAE: 8031.291888515132
Minkowski (p=3) Validation MAE: 8742.976038886232
Best performing distance metric: Manhattan with MAE: 8031.291888515132
Test predictions using Manhattan distance metric have been generated
맨해튼 방식의 베이스코드 - 아마 앙상블할때 이거 아니면 밑에 코드 쓸듯?
# 데이터 로드
train_df = pd.read_csv('merged_data.csv')
test_df = pd.read_csv
# 특성 선택
features = train_df.columns.drop(['deposit', 'index']).tolist()
# Train 데이터를 train과 validation으로 분리
train_df, val_df = train_test_split(train_df, test_size=0.2, random_state=42)
# 스케일링
scaler = StandardScaler()
train_scaled = scaler.fit_transform(train_df[features])
val_scaled = scaler.transform(val_df[features])
test_scaled = scaler.transform(test_df[features])
# 특성 가중치 조정
weights = np.array([1, 1, 5, 0.5, 0.5, 0.5]) # latitude, longitude, area_m2, floor, built_year, contract_year_month 순서
train_scaled = train_scaled * weights
val_scaled = val_scaled * weights
test_scaled = test_scaled * weights
# BallTree 구축 (맨해튼 거리 사용)
tree = BallTree(train_scaled, leaf_size=40, metric='manhattan')
# 예측 함수 (거리에 따른 가중치 함수 조정)
def predict_deposit(neighbors, distances):
weights = np.exp(-distances) # 지수 함수 사용
weighted_deposits = neighbors['deposit'] * weights
return np.sum(weighted_deposits) / np.sum(weights)
# 단일 예측 함수
def predict_single(data_point, k):
distances, indices = tree.query([data_point], k=k)
neighbors = train_df.iloc[indices[0]]
return predict_deposit(neighbors, distances[0])
# 병렬 예측 수행 함수
def make_predictions_parallel(data_scaled, k):
return Parallel(n_jobs=-1)(delayed(predict_single)(data_point, k) for data_point in data_scaled)
# 앙상블 예측 함수
def ensemble_predictions(data_scaled, k_values):
all_predictions = Parallel(n_jobs=-1)(
delayed(make_predictions_parallel)(data_scaled, k) for k in k_values
)
return np.mean(all_predictions, axis=0)
# k 값 리스트 정의
k_values = [3, 5, 7, 9]
# Validation 예측
val_predictions = ensemble_predictions(val_scaled, k_values)
# Validation MAE 계산
val_mae = mean_absolute_error(val_df['deposit'], val_predictions)
print(f"Validation MAE: {val_mae}")
# Test 예측
test_predictions = ensemble_predictions(test_scaled, k_values)
# 결과 저장
submission_df = pd.DataFrame({
'index': test_df['index'],
'deposit': test_predictions
})
submission_df.to_csv('submission.csv', index=False)
print("예측이 완료되었습니다. 'submission.csv' 파일을 확인하세요.")
이제 여기서 엥간한 건 다 해봤으니 위 코드로 파생변수 추가한 데이터로 돌려보려고 했다.
1867783 rows × 35 columns
1시간 돌렸는데 안돌아가지더라.. 그래서 피처 10개만 설정해서 돌렸다.
Validation MAE: 5591.6022472139475
화나서 XGBoost로 gpt한테 바꿔달라고 했다.
XGBoost 예제
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import mean_absolute_error
import xgboost as xgb
# 데이터 로드
merged_data = pd.read_csv('merged_data_cleaned.csv')
# Train과 Test 데이터 분리
train_df = merged_data[merged_data['deposit'] != 0].copy()
test_df = merged_data[merged_data['deposit'] == 0].copy()
# 타겟 변수 분리
y_train = train_df['deposit']
X_train = train_df.drop('deposit', axis=1)
# test_df에서 deposit 열 제거
X_test = test_df.drop('deposit', axis=1)
# 범주형 변수 인코딩
le = LabelEncoder()
for col in X_train.select_dtypes(include=['object']).columns:
X_train[col] = le.fit_transform(X_train[col].astype(str))
X_test[col] = le.transform(X_test[col].astype(str))
# Train 데이터를 train과 validation으로 분리
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.2, random_state=42)
# XGBoost 모델 생성 및 학습
model = xgb.XGBRegressor(
n_estimators=500,
learning_rate=0.1,
max_depth=6,
subsample=0.8,
colsample_bytree=0.8,
random_state=42,
tree_method='hist',
n_jobs=-1
)
model.fit(
X_train, y_train,
eval_set=[(X_val, y_val)],
verbose=100
)
# Validation 예측 및 MAE 계산
val_predictions = model.predict(X_val)
val_mae = mean_absolute_error(y_val, val_predictions)
print(f"Validation MAE: {val_mae}")
# Test 예측
test_predictions = model.predict(X_test)
# 결과 저장
submission_df = pd.DataFrame({
'index': test_df.index,
'deposit': test_predictions
})
submission_df.to_csv('submission.csv', index=False)
print("예측이 완료되었습니다. 'submission.csv' 파일을 확인하세요.")
# 특성 중요도 출력
feature_importance = model.feature_importances_
feature_names = X_train.columns
feature_importance_df = pd.DataFrame({'feature': feature_names, 'importance': feature_importance})
feature_importance_df = feature_importance_df.sort_values('importance', ascending=False)
print("\n상위 10개 중요 특성:")
print(feature_importance_df.head(10))
Validation MAE: 4714.424762007194
1분만에 실행되었는데 지금까지 못 넘은 4000의 벽을 가뿐히 깨버렸다.
허허.. 암울하다. 며칠동안 쟤만 삽질했는데. 그래서 걍 그리드서치해서 최적 가중치 찾고 나중에 앙상블할때 쓰는 용도로 써야겠다. 이게 특히 모델링이 너무 오래걸리니까 하루 동안 스트레스가 너무 심했다. 중간에 공부하기도 뭐하고 집중도 잘 안되고 종종 확인하기도 귀찮고 아오 그냥.
끝