카테고리 없음

[ML]멜버른 주택가격 예측-회귀분석

DEDS 2025. 4. 21. 13:46
728x90

Kaggle의 멜버른 주택가격 데이터셋을 사용하여 예측을 하도록 하겠습니다.

데이터는 아래 주소에서 다운로드 받으셔서 사용하시면 됩니다.

Melbourne Housing Dataset

 

Melbourne Housing Dataset

Discover Insights and Trends from Housing Market

www.kaggle.com

데이터 로드

import pandas as pd
df = pd.read_csv('/content/Melbourne_housing.csv') 
#pd.set_option('display.max_column', 100)
df.head().T

컬럼이 많은 경우 df.head().T 로 전치(transpose)해서 보시면 편합니다.

set_option을 사용해서 모든 컬럼이 보이게 하셔도 됩니다.

 

EDA(데이터 탐색)

dfSummary(df)

 

라이브러리가 설치되어 있지 않으신분은 dfSummary자료  참고하시기 바랍니다.

간단히 보시려면 기존 코드로 단계별로 보시면 됩니다.

df.shape 
#(34857, 22)
df.isnull().sum()[df.isnull().sum()>0]
#Distance	1
#Postcode	1
#Bedroom	8217
#Bathroom	8226
#Car	8728
#Landsize	11810
#BuildingArea	21097
#YearBuilt	19306
#CouncilArea	3
#Latitude	7976
#Longtitude	7976
#Propertycount	3
#Price	7610
df.describe().T

 

df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 34857 entries, 0 to 34856
Data columns (total 22 columns):
 #   Column         Non-Null Count  Dtype  
 0   Suburb         34857 non-null  object 
 1   Address        34857 non-null  object 
 2   Rooms          34857 non-null  int64  
 3   Type           34857 non-null  object 
 4   Method         34857 non-null  object 
 5   SellerG        34857 non-null  object 
 6   Date           34857 non-null  object 
 7   Distance       34856 non-null  float64
 8   Postcode       34856 non-null  float64
 9   Bedroom        26640 non-null  float64
 10  Bathroom       26631 non-null  float64
 11  Car            26129 non-null  float64
 12  Landsize       23047 non-null  float64
 13  BuildingArea   13760 non-null  object 
 14  YearBuilt      15551 non-null  float64
 15  CouncilArea    34854 non-null  object 
 16  Latitude       26881 non-null  float64
 17  Longtitude     26881 non-null  float64
 18  Regionname     34857 non-null  object 
 19  Propertycount  34854 non-null  float64
 20  ParkingArea    34857 non-null  object 
 21  Price          27247 non-null  float64
dtypes: float64(11), int64(1), object(10)
memory usage: 5.9+ MB

df.nuique()
#Suburb	351
#Address	34009
#Rooms	12
#Type	3
#Method	9
#SellerG	388
#Date	78
#Distance	215
#Postcode	211
#Bedroom	15
#Bathroom	11
#Car	15
#Landsize	1684
#BuildingArea	994
#YearBuilt	160
#CouncilArea	33
#Latitude	13402
#Longtitude	14524
#Regionname	8
#Propertycount	342
#ParkingArea	8
#Price	2871
#dtype: int64

데이터 전처리

#컬럼선택 
Columns1 = ['Suburb', 'Rooms', 'Type', 'Method', 'SellerG', 'Regionname', 'Propertycount', 'Distance', 'CouncilArea', 'Bedroom', 'Bathroom', 'Car', 'Landsize', 'BuildingArea', 'Price']
df1 = df[Columns1]
#값 채우기 Fillna 0으로 채우기
Columns2 = ['Car', 'Bathroom', 'Bedroom', 'Distance', 'Propertycount']
df1[Columns2] = df[Columns2].fillna(0)
df1['Landsize'] = pd.to_numeric(df1['Landsize'], errors='coerce')
df1['BuildingArea'] = pd.to_numeric(df1['BuildingArea'], errors='coerce')
df1['Landsize'] = df1['Landsize'].fillna(df1['Landsize'].mean())
df1['BuildingArea'] = df1['BuildingArea'].fillna(df1['BuildingArea'].mean())
df1 = df1.replace([np.inf, -np.inf], np.nan).dropna()

 

결측치에 대해서 0 채우기, mean, mode, 보간법 등 다양한 방안이 있으나 컬럼 속성에 맞게 처리가 필요한다.

Category 컬럼에 대하여 숫자로 인코딩이 필요하며 다양한 방안이 있지만 가장 일반적인 One-Hot 인코딩을

사용하도록 한다.

#one-hot 인코딩 
df1 = pd.get_dummies(df1, drop_first=True)
#컬럼이 많아 옵션 변경이 필요함 
pd.set_option('display.max_columns', 1000)
df1.head()

 

모델 훈련 및 평가

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
X = df1.drop('Price', axis='columns')
y = df1.Price
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, random_state=2)
model = LinearRegression()
model.fit(X_train, y_train)
print('test accuracy',model.score(X_test, y_test))
print('train accuracy',model.score(X_train, y_train))

test accuracy 0.7007745077719215

train accuracy 0.7272548867643198

 

추가적으로 L2, L1 규제를 적용한 Lasso/Ridge 모델 결과도 보도록 하겠습니다.

from sklearn.linear_model import Lasso    # Sklearn's Lass regression is the L1 regularization.
from sklearn.linear_model import Ridge
from sklearn.linear_model import ElasticNet

lasso_model = Lasso()
lasso_model.fit(X_train, y_train)
print('l2 test accuracy',lasso_model.score(X_test, y_test))
print('l2 train accuracy',lasso_model.score(X_train, y_train))

l1_model = Ridge()
l1_model.fit(X_train, y_train)
print('l1 test accuracy',l1_model.score(X_test, y_test))
print('l1 train accuracy',l1_model.score(X_train, y_train))


el_model = ElasticNet(alpha=0.1, l1_ratio=0.5)
el_model.fit(X_train, y_train)
print('Elastic Net test accuracy',el_model.score(X_test, y_test))
print('Elastic Net train accuracy',el_model.score(X_train, y_train))

l2 test accuracy 0.7009527568387347

l2 train accuracy 0.7272489742782413

l1 test accuracy 0.7043454519542658

l1 train accuracy 0.7253954749500959

Elastic Net test accuracy 0.6371874976568843

Elastic Net train accuracy 0.6323263194777249

 

L2 규제를 적용한 Lasso 모델이 정확도가 가장 높았습니다.  과적합이 높으면 L2/L1 Regulation을 적용을

검토해 보시기 바랍니다. 

위코드에 값의 차이가 큰 Feature에 의해 영향을 받을 수 있어 Scaler를 적용이 필요합니다.

MinMaxScaler나 StandardScaler를 사용하시면됩니다. 아래코드는 MinMaxScaler 적용코드입니다.

from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, train_size=0.8, random_state=2)

 

회귀모델에서는 metric을 MAE를 사용함으로 MAE를 통하여 값이 가장 낮은 모델을 선택하시면됩니다.

RandomForestRegressor가 성능이 좋아 코드를 비교해 보도록 하겠습니다.

from sklearn.ensemble import RandomForestRegressor
rfr = RandomForestRegressor() 
rfr.fit(X_train, y_train) 
prediction = rfr.predict(X_test) 
rfr_mae = mean_absolute_error(y_test, prediction) 
rfr_mae

 

167547.84318792998

 

랜덤포레스터는 스케일링이 불필요하니 참고하시기 바랍니다.(간단히 코드 구현 가능)

MAE도 linerRegression의 MAE 242425에 비해 성능이 더 좋아 보입니다.

 

728x90