Machine learning

[Python 지도학습 실습 RETURN 1]

100.nam 2024. 12. 26. 21:48
더보기

💡 주제

주택 가격 예측 모델 구축

 

🎯 목표 주어진 주택 데이터셋을 사용하여 주택 가격을 예측하는 회귀 모델을 구축합니다.

 

📖 학습 내용 - 지도 학습의 기본 개념과 회귀 분석을 이해하고, 실제 데이터에 적용하는 능력

  • 데이터 전처리 및 탐색: 데이터의 품질을 높이는 방법과 특징 선택의 중요성
  • 여러 회귀 모델의 이해: 다양한 회귀 기법의 원리와 적용 방법
  • 모델 성능 평가: 성능 지표의 이해 및 비교 분석을 통해 최적의 모델 선택
  • 과제한게 뭔가 마음에 안들기도 하고 놓친게 있어서 차근차근 다시 해보기로 했다.

1. 데이터 불러오기

# CSV 파일 불러오기
df = pd.read_csv('housingdata.csv')

# 데이터 로드 (5행만)
df.head()

 

2. 데이터 확인(결측치, 정규성 등)

1) 데이터 정보 확인

#데이터 정보 확인(타입, 결측값 등)
df.info()

import seaborn as sns
import matplotlib.pyplot as plt

# 결측치 시각화
sns.heatmap(df.isnull(), cbar=False, cmap='viridis')
plt.title('Missing Values Heatmap')
plt.show()
    • 데이터 정보를 확인해보니 506개의 열이 존재
    • CRIM, ZN, INDUS, CHAS, AGE, LSTAT 총 6개 행에 결측값 20개 존재

 

2) 이상치 확인

# Boxplot으로 이상치 시각화
for col in df.columns:
    plt.figure(figsize=(8, 4))
    sns.boxplot(data=df[col])
    plt.title(f'Boxplot of {col}')
    plt.show()

# IQR 기반 이상치 탐지
Q1 = df.quantile(0.25)  # 1사분위수
Q3 = df.quantile(0.75)  # 3사분위수
IQR = Q3 - Q1

# 이상치 경계
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 이상치 탐지
outliers = (df < lower_bound) | (df > upper_bound)
print(outliers.sum())  # 각 열에서 이상치 개수 출력

from scipy.stats import zscore

# Z-Score 계산
z_scores = df.apply(zscore)

# Z-Score 기준 이상치 탐지 (절댓값이 3을 초과하는 경우 이상치로 간주)
outliers_z = (z_scores.abs() > 3)
print(outliers_z.sum())  # 각 열에서 이상치 개수 출력
  • Boxplot으로 시각화하면 아래처럼 나온다
  • 왼쪽 CRIM에는 동그라미들이 이상치이다. INDUS처럼 나오면 이상치 없는 것이다

 

    • 왼쪽 IQR 기반 이상치 탐지하면 나오는 것이다. CRIM 이상치가 63개나 나온다
    • 오른쪽은 Z-Score로 계산한것이다. 3초과부터 이상치이다

 

3) 데이터 정규성 확인

import scipy.stats as stats
import matplotlib.pyplot as plt

# 모든 특성 변수에 대해
# 히스토그램은 정규성을 따르면 종 모양을 하고 있음
for column in df.columns:
    # 히스토그램
    plt.figure(figsize=(10, 5))
    plt.subplot(1, 2, 1)
    df[column].hist(bins=30)
    plt.title(f'{column} Histogram')

    # Q-Q 플롯
    # 정규분포를 따르면 데이터들이 직선 모양으로 분포
    plt.subplot(1, 2, 2)
    stats.probplot(df[column], dist="norm", plot=plt)
    plt.title(f'{column} Q-Q Plot')
    
    plt.show()
    
# RM, LSTAT, MEDV 열이 정규분포를 따름
# 의사결정나무, 랜덤 포레스트의 경우 분포에 민감하지 않으므로 데이터 변환이 없어도 괜찮다.
# 선형 회귀, 로지스틱 회귀는 데이터가 정규분포에 가까울 수록 예측 성능과 해석력이 좋아진다.

 

3. 데이터 전처리

1) 이상치 처리

  • 처리 방법에는 제거, 대체, 완화, 모델기반 처리가 있다
  • 이상치가 적은 경우( <5% 정도) = 제거
  • 이상치가 중간 정도 경우 (5~15%) = 대체
  • 이상치가 많거나 극단적인 경우 (>15%) = 완화
  • 약 500개의 데이터에서 각 열의 이상치 비율은 아래와 같다.
  • CRIM: 65개 (13%)
  • ZN: 63개 (12.6%)
  • CHAS: 34개 (6.8%)
  • RM: 30개 (6%)
  • DIS: 5개 (1%)
  • PTRATIO: 15개 (3%)
  • B: 77개 (15.4%)
  • LSTAT: 7개 (1.4%)
  • MEDV: 40개 (8%) -> 종속변수이기에 이상치는 처리하지 않음. 성능에 영향을 미치기 때문
# 이상치 비율 5% 이하: 제거
# IQR 기준 이상치 제거
for column in ['DIS', 'LSTAT', 'PTRATIO','NOX']:
    df = df[~((df[column] < lower_bound[column]) | (df[column] > upper_bound[column]))]
    
# 이상치 비율 5%~15%: 대체 
# 중앙값으로 이상치 대체
for column in ['CRIM', 'ZN', 'CHAS', 'RM']:
    median_value = df[column].median()
    df[column] = df[column].where((df[column] >= lower_bound[column]) & (df[column] <= upper_bound[column]), median_value)

# 0과 100 사이로 클리핑
# B는 아프리카계 미국인 비율을 나타내므로, 0~100% 범위 내에서 값이 유지되어야 한다. 그래서 0,100사이로 지정
df['B'] = df['B'].clip(0, 100)

# Boxplot으로 확인
print(outliers.sum())

  • 이상치는 어느정도 걸러진 것 같다.

 

결측치 처리랑 모델 선택은 다음 시간에 계속 해보자