[Python 지도학습 실습 RETURN 2]

2024. 12. 27. 18:09·Machine learning

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
'Machine learning' 카테고리의 다른 글
  • [Machine Learing 타이타닉 데이터]
  • [Python 지도학습 실습 RETURN 1]
  • [머신러닝: 비지도학습 실습]
  • [머신러닝: 지도학습 실습 2]
100.nam
100.nam
100.nam님의 블로그 입니다.
  • 100.nam
    100.nam님의 블로그
    100.nam
  • 전체
    오늘
    어제
    • 분류 전체보기
      • Python 정리
      • Python 문제 풀기
      • Machine learning
      • SQL 정리
      • SQL 문제풀기
      • Django 정리
      • LangChain,Graph
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    스파르타코딩클럽
    SQL
    pandas
    내일배움캠프
    스파르타코딩크럽
    인공지능을위한파이썬
    머신러닝
    vscode
    Python
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
100.nam
[Python 지도학습 실습 RETURN 2]
상단으로

티스토리툴바