https://qoraudska.tistory.com/23
[Python 지도학습 실습 RETURN]
더보기💡 주제주택 가격 예측 모델 구축 🎯 목표 주어진 주택 데이터셋을 사용하여 주택 가격을 예측하는 회귀 모델을 구축합니다. 📖 학습 내용 - 지도 학습의 기본 개념과 회귀 분석을
qoraudska.tistory.com
- 저번 시간 우리는 이상치 처리까지 했다.
- 하나 간과한게 있는데 이상치 처리를 한번만 했어야 했는데 계속해서 이상치가 사라진 것이었다.
- 이것은 데이터에 좋을 수도 있고 나쁠수도 있다고 한다. 대부분 한 두번 정도만 이상치 처리를 한다고 한다.
- 그래서 나는 이상치 처리가 데이터에 얼마나 영향을 주는 지 한번 해보겠다.
더보기
- 선형회귀 코드 돌린 것이다.!!
- R2 값을 다 비교하면서 제일 좋은 상위 10개를 가져오는 건데 선형회귀라 2분정도면 된다.
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
import itertools
# 결측값을 처리할 열
columns_to_check = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'AGE', 'LSTAT']
# 결측값을 처리할 방법들
methods = ['dropna', 'fillna_zero', 'fillna_mean', 'fillna_median', 'fillna_mode']
# 모델 평가 함수
def evaluate_model(X, y):
# 훈련 세트와 테스트 세트 분리 (80% 훈련, 20% 테스트)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 선형 회귀 모델 훈련
model = LinearRegression()
model.fit(X_train, y_train)
# 예측값
y_pred = model.predict(X_test)
# R^2 점수 계산
r2 = r2_score(y_test, y_pred)
# MAE, MSE 계산
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
return r2, mae, mse
# 결과 저장할 변수
results = {}
# 모든 가능한 결측값 처리 방법의 조합 생성
all_combinations = itertools.product(methods, repeat=len(columns_to_check))
# 결측값 처리 및 평가
X_all = df.drop(columns='MEDV') # MEDV 열 제외하고 X값 생성
for combination in all_combinations:
df_temp = df.copy() # 원본 데이터를 복사
# 각 열에 대해 결측값 처리 방법 적용
for idx, column in enumerate(columns_to_check):
method = combination[idx] # 해당 열에 대한 결측값 처리 방법
if method == 'dropna':
df_temp = df_temp.dropna(subset=[column]) # 결측값이 포함된 행 제거
elif method == 'fillna_zero':
df_temp[column] = df_temp[column].fillna(0) # 결측값을 0으로 채우기
elif method == 'fillna_mean':
df_temp[column] = df_temp[column].fillna(df_temp[column].mean()) # 결측값을 평균으로 채우기
elif method == 'fillna_median':
df_temp[column] = df_temp[column].fillna(df_temp[column].median()) # 결측값을 중앙값으로 채우기
elif method == 'fillna_mode':
df_temp[column] = df_temp[column].fillna(df_temp[column].mode().iloc[0]) # 결측값을 최빈값으로 채우기
# X_temp와 y_temp 생성 (필요한 경우 결측값이 처리된 후 X_temp가 비지 않는지 확인)
X_temp = df_temp.drop(columns='MEDV')
y_temp = df_temp['MEDV']
# 결측값 처리 후 X_temp가 비지 않으면 모델 평가
if X_temp.shape[0] > 0 and not X_temp.isnull().values.any(): # X_temp가 비지 않고 결측값이 없는지 확인
r2, mae, mse = evaluate_model(X_temp, y_temp)
# 결과 저장 (결측값 처리 방법의 조합을 키로 사용)
results[combination] = {'R²': r2, 'MAE': mae, 'MSE': mse}
# 결과를 R² 기준으로 내림차순 정렬하여 상위 10개 출력
sorted_results = sorted(results.items(), key=lambda x: x[1]['R²'], reverse=True)[:10]
# 상위 10개 결과 출력
for idx, (combination, scores) in enumerate(sorted_results, 1):
print(f"Top {idx} Combination: {combination}, R²: {scores['R²']:.4f}, MAE: {scores['MAE']:.4f}, MSE: {scores['MSE']:.4f}")
- 이상치 처리를 할 때마다 결과가 안 좋아졌다.
- 따른 이상치 처리를 해도 반복이다. 선형 회귀는 이상치에 민감해서 이상치 처리를 안하고 할 수 있는 랜덤포레스트가 좋아보인다.
더보기
- 의사결정나무 코드 돌린 것이다.
- 선형회귀랑 똑같이 만들었다. 근데 성능이 좀 안 좋아졌다.
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
import itertools
# 결측값을 처리할 열
columns_to_check = ['CRIM', 'ZN', 'INDUS', 'CHAS', 'AGE', 'LSTAT']
# 결측값을 처리할 방법들
methods = ['dropna', 'fillna_zero', 'fillna_mean', 'fillna_median', 'fillna_mode']
# 모델 평가 함수
def evaluate_model(X, y):
# 훈련 세트와 테스트 세트 분리 (80% 훈련, 20% 테스트)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 의사결정 모델 훈련
model = DecisionTreeRegressor(random_state=42)
model.fit(X_train, y_train)
# 예측값
y_pred = model.predict(X_test)
# R^2 점수 계산
r2 = r2_score(y_test, y_pred)
# MAE, MSE 계산
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
return r2, mae, mse
# 결과 저장할 변수
results = {}
# 모든 가능한 결측값 처리 방법의 조합 생성
all_combinations = itertools.product(methods, repeat=len(columns_to_check))
# 결측값 처리 및 평가
X_all = df.drop(columns='MEDV') # MEDV 열 제외하고 X값 생성
for combination in all_combinations:
df_temp = df.copy() # 원본 데이터를 복사
# 각 열에 대해 결측값 처리 방법 적용
for idx, column in enumerate(columns_to_check):
method = combination[idx] # 해당 열에 대한 결측값 처리 방법
if method == 'dropna':
df_temp = df_temp.dropna(subset=[column]) # 결측값이 포함된 행 제거
elif method == 'fillna_zero':
df_temp[column] = df_temp[column].fillna(0) # 결측값을 0으로 채우기
elif method == 'fillna_mean':
df_temp[column] = df_temp[column].fillna(df_temp[column].mean()) # 결측값을 평균으로 채우기
elif method == 'fillna_median':
df_temp[column] = df_temp[column].fillna(df_temp[column].median()) # 결측값을 중앙값으로 채우기
elif method == 'fillna_mode':
df_temp[column] = df_temp[column].fillna(df_temp[column].mode().iloc[0]) # 결측값을 최빈값으로 채우기
# X_temp와 y_temp 생성 (필요한 경우 결측값이 처리된 후 X_temp가 비지 않는지 확인)
X_temp = df_temp.drop(columns='MEDV')
y_temp = df_temp['MEDV']
# 결측값 처리 후 X_temp가 비지 않으면 모델 평가
if X_temp.shape[0] > 0 and not X_temp.isnull().values.any(): # X_temp가 비지 않고 결측값이 없는지 확인
r2, mae, mse = evaluate_model(X_temp, y_temp)
# 결과 저장 (결측값 처리 방법의 조합을 키로 사용)
results[combination] = {'R²': r2, 'MAE': mae, 'MSE': mse}
# 결과를 R² 기준으로 내림차순 정렬하여 상위 10개 출력
sorted_results = sorted(results.items(), key=lambda x: x[1]['R²'], reverse=True)[:10]
# 상위 10개 결과 출력
for idx, (combination, scores) in enumerate(sorted_results, 1):
print(f"Top {idx} Combination: {combination}, R²: {scores['R²']:.4f}, MAE: {scores['MAE']:.4f}, MSE: {scores['MSE']:.4f}")
- 의사결정 나무도 똑같이 이상치 처리를 하면 성능이 안좋아진다... 랜덤포레스트 가보자
더보기
- 랜덤포레스트는 다 비교하려면 이틀정도 걸린다고 해서 적당한 값을 넣어줬다.
- 랜덤포레스트에 넣은 것들도 다른 모델에 넣으면 어떻게 될 지 궁금해서 값들을 보여주기로 했다.
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
# 결측값 처리 방법 지정
fill_methods = {
'CRIM': 'mean',
'ZN': 'median',
'INDUS': 'mean',
'CHAS': 'mode',
'AGE': 'median',
'LSTAT': 'mean'
}
# 결측값 처리 함수
def handle_missing_values(df, fill_methods):
df_temp = df.copy()
for column, method in fill_methods.items():
if method == 'mean':
df_temp[column] = df_temp[column].fillna(df_temp[column].mean())
elif method == 'median':
df_temp[column] = df_temp[column].fillna(df_temp[column].median())
elif method == 'mode':
df_temp[column] = df_temp[column].fillna(df_temp[column].mode().iloc[0])
return df_temp
# 모델 평가 함수
def evaluate_model(X, y, model):
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
r2 = r2_score(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
return r2, mae, mse
# 결측값 처리
df_cleaned = handle_missing_values(df, fill_methods)
# X, y 분리
X = df_cleaned.drop(columns='MEDV')
y = df_cleaned['MEDV']
# 모델 평가
print("LinearRegression:")
lr_model = LinearRegression()
lr_r2, lr_mae, lr_mse = evaluate_model(df_cleaned.drop(columns='MEDV'), df_cleaned['MEDV'], lr_model)
print(f"R²: {lr_r2:.4f}, MAE: {lr_mae:.4f}, MSE: {lr_mse:.4f}")
print("\nDecision Tree Results:")
dt_model = DecisionTreeRegressor(random_state=42)
dt_r2, dt_mae, dt_mse = evaluate_model(df_cleaned.drop(columns='MEDV'), df_cleaned['MEDV'], dt_model)
print(f"R²: {dt_r2:.4f}, MAE: {dt_mae:.4f}, MSE: {dt_mse:.4f}")
print("\nRandom Forest Results:")
rf_model = RandomForestRegressor(random_state=42, n_estimators=100)
rf_r2, rf_mae, rf_mse = evaluate_model(X, y, rf_model)
print(f"R²: {rf_r2:.4f}, MAE: {rf_mae:.4f}, MSE: {rf_mse:.4f}")
- 이상치를 총 두번까지 제거하면 랜덤포레스트에 성능은 올라간다. 그러나 3번부터는 더 이상 올라가지 않고 떨어진다. 결국 R2값은 0.9에서 멈춘다.
- 신기한 것은 따른 선형회귀랑 의사결정 나무는 1번 제거했을때 성능이 떨어졌다가 2번 제거 했을 때 올라갔다.
- 나중에는 한번 모델 학습을 시키면 금액부터 시간이 많이 필요하다고 한다.
- 그러니 그냥 처음부터 괜찮은 모델을 바로 사용하는 게 좋아보인다.
- 이 데이터에서는 랜덤포레스트가 제일 좋다
- 제일 괜찮았던 것들로 모델을 비교해보자
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
# 각 모델에 맞는 결측값 처리 방법
fill_methods_rf = { # 랜덤 포레스트에 적용
'CRIM': 'mean',
'ZN': 'median',
'INDUS': 'mean',
'CHAS': 'mode',
'AGE': 'median',
'LSTAT': 'mean'
}
fill_methods_lr = { # 선형 회귀에 적용
'CRIM': 'dropna',
'ZN': 'mean',
'INDUS': 'mode',
'CHAS': 'dropna',
'AGE': 'fillna_zero',
'LSTAT': 'mode'
}
fill_methods_dt = { # 의사결정 나무에 적용
'CRIM': 'dropna',
'ZN': 'fillna_zero',
'INDUS': 'fillna_zero',
'CHAS': 'dropna',
'AGE': 'dropna',
'LSTAT': 'dropna'
}
# 결측값 처리 함수
def handle_missing_values(df, fill_methods):
df_temp = df.copy()
for column, method in fill_methods.items():
if method == 'dropna':
df_temp = df_temp.dropna(subset=[column]) # 결측값이 포함된 행 제거
elif method == 'mean':
df_temp[column] = df_temp[column].fillna(df_temp[column].mean())
elif method == 'median':
df_temp[column] = df_temp[column].fillna(df_temp[column].median())
elif method == 'mode':
df_temp[column] = df_temp[column].fillna(df_temp[column].mode().iloc[0])
elif method == 'fillna_zero':
df_temp[column] = df_temp[column].fillna(0) # 추가: 0으로 채우는 방법
return df_temp
# 모델 평가 함수
def evaluate_model(X, y, model):
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
r2 = r2_score(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
return r2, mae, mse
# df_cleaned 데이터 준비
df_cleaned_rf = handle_missing_values(df, fill_methods_rf)
df_cleaned_lr = handle_missing_values(df, fill_methods_lr)
df_cleaned_dt = handle_missing_values(df, fill_methods_dt)
# X, y 분리
X_rf = df_cleaned_rf.drop(columns='MEDV')
y_rf = df_cleaned_rf['MEDV']
X_lr = df_cleaned_lr.drop(columns='MEDV')
y_lr = df_cleaned_lr['MEDV']
X_dt = df_cleaned_dt.drop(columns='MEDV')
y_dt = df_cleaned_dt['MEDV']
# 선형 회귀 모델 평가
print("Linear Regression Results:")
lr_model = LinearRegression()
lr_r2, lr_mae, lr_mse = evaluate_model(X_lr, y_lr, lr_model)
print(f"R²: {lr_r2:.4f}, MAE: {lr_mae:.4f}, MSE: {lr_mse:.4f}")
# 의사결정 나무 모델 평가
print("\nDecision Tree Results:")
dt_model = DecisionTreeRegressor(random_state=42)
dt_r2, dt_mae, dt_mse = evaluate_model(X_dt, y_dt, dt_model)
print(f"R²: {dt_r2:.4f}, MAE: {dt_mae:.4f}, MSE: {dt_mse:.4f}")
# 랜덤 포레스트 모델 평가
print("\nRandom Forest Results:")
rf_model = RandomForestRegressor(random_state=42, n_estimators=100)
rf_r2, rf_mae, rf_mse = evaluate_model(X_rf, y_rf, rf_model)
print(f"R²: {rf_r2:.4f}, MAE: {rf_mae:.4f}, MSE: {rf_mse:.4f}")
- 그래프로도 보자!!
# 결과를 저장할 리스트
models = ['Linear Regression', 'Decision Tree', 'Random Forest']
r2_scores = [lr_r2, dt_r2, rf_r2]
mae_scores = [lr_mae, dt_mae, rf_mae]
mse_scores = [lr_mse, dt_mse, rf_mse]
# 그래프 그리기
x = np.arange(len(models)) # 모델의 인덱스
# 그래프 크기 설정
plt.figure(figsize=(12, 6))
# R², MAE, MSE의 바 그래프 생성
plt.subplot(1, 3, 1)
plt.bar(x, r2_scores, color='skyblue')
plt.xticks(x, models)
plt.title('R² Score')
plt.ylim(0, 1)
plt.subplot(1, 3, 2)
plt.bar(x, mae_scores, color='lightgreen')
plt.xticks(x, models)
plt.title('Mean Absolute Error (MAE)')
plt.ylim(0, max(mae_scores) * 1.1)
plt.subplot(1, 3, 3)
plt.bar(x, mse_scores, color='salmon')
plt.xticks(x, models)
plt.title('Mean Squared Error (MSE)')
plt.ylim(0, max(mse_scores) * 1.1)
# 그래프 레이아웃 조정
plt.tight_layout()
# 그래프 출력
plt.show()
끝 진짜 끝..눈 빠진다..
'Machine learning' 카테고리의 다른 글
[Machine Learing 타이타닉 데이터] (2) | 2025.01.02 |
---|---|
[Python 지도학습 실습 RETURN 1] (1) | 2024.12.26 |
[머신러닝: 비지도학습 실습] (2) | 2024.12.19 |
[머신러닝: 지도학습 실습 2] (6) | 2024.12.19 |
[머신 러닝: 지도학습 실습 1] (4) | 2024.12.18 |