حل مسئله قیمت خانه به روش رندوم فورست

موارد اولیه:

ابتدا موارد اولیه را فراخوانی میکنیم:

import numpy as np
import pandas as pd
import seaborn as sns 
import matplotlib.pyplot as plt 

در کد زیر کتابخانه پیش پردازش standardscaler و رگرسیون خطی و رندوم فورست وهمچنین XGBOOST و در نهایت کتابخانه انتخاب فیچر را فرامیخوانیم:

from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression 
from sklearn.ensemble import RandomForestRegressor 
from xgboost import XGBRFRegressor 
from sklearn.feature_selection import RFE

در دو مورد زیر هم موارد مرتبط با ارزیابی خطای مدل را بارگذاری میکنیم

from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score 

در نهایت سه مورد زیر را داریم:

trinn test split که برای جدا کردن نمونه آموزش و تست است

cross_val_score : که در زیر در مورد آن توضیح داده شده است . همچنین در این نوشته (بلاگ پست).

Cross_val_score is a method which runs cross validation on a dataset to test whether the model can generalise over the whole dataset. The function returns a list of one score per split, and the average of these scores can be calculated to provide a single metric value for the dataset

RandomizedSearchCV:

RandomizedSearchCV implements a “fit” and a “score” method. It also implements “score_samples”, “predict”, “predict_proba”, “decision_function”, “transform” and “inverse_transform” if they are implemented in the estimator used

from sklearn.model_selection import train_test_split, cross_val_score, RandomizedSearchCV 

سپس دیتا ها را میخوانیم. در خط سوم ID دیتا برای مرحله آخر (submission) ذخیره شده است

train=pd.read_csv("train.csv")
test=pd.read_csv("test.csv")
Id = test['Id'] 

در مرحله بعد به سراغ EDA میرویم:

EDA:

عمده توابع مورد استفاده در این مرحله head وinfo وdescribe و shape هستند که روی هر دو مورد test و train اجرا میکنیم.

Null values :

با توابع isnull و sum تعداد مقادیر گم شده از دیتا ست را مشاهده میکنیم:

با دستور زیر تعداد داده های گم شده در هر ستون را از زیاد به کم هم در train و هم در test مشاهده می کنیم:

pd.set_option('display.max_rows', train.shape[0])
pd.DataFrame(train.isnull().sum().sort_values(ascending = False))

سوال: خط اول کد بالا چه کاری انجام میدهد؟

با دستور زیر درصد مقادیری صفر را حساب میکنیم و اگر بیشتر از 50 درصد بود آن را شناسایی میکنیم:

null = train.isnull().sum() / train.shape[0] *100   
col_to_drop = null[null > 50 ].keys()  
col_to_drop

دستور زیر ستونهایی که دارای مقادیر صفر هستند را به ما نشان میدهد. که اگر از آن len بگیریم 19 تا خواهد بود

train.columns[train.isnull().any()]

با دستور زیر ردیف های شناسایی شده را drop میکنیم:

train.drop(columns=['Alley', 'PoolQC', 'Fence', 'MiscFeature'], inplace=True) 

حال اگر دستور زیر را اجرا کنیم 15 تا خواهد بود. زیرا 4 مورد را حذف کردیم.

len((train.columns[train.isnull().any()]))

جایگذاری مقادیر null

بدون هیچ دردسری برای 15 فیچر باقی مانده که یا عددی هستند و یا categorical مقادیر null را یا با mean (در حالت عددی) یا با mod (در حالت categorical)جایگذاری میکنیم. 4 مورد در زیر آورده شده است.

train['LotFrontage'] = train['LotFrontage'].fillna(train['LotFrontage'].mean())
train['MasVnrArea']  = train['MasVnrArea'].fillna(train['MasVnrArea'].mean())     
train['GarageYrBlt'] = train['GarageYrBlt'].fillna(train['GarageYrBlt'].mean())
train['MasVnrType']   = train['MasVnrType'].fillna(train['MasVnrType'].mode()[0]) 

plotting :

با کد زیر نمودار پراکندگی قیمت را ترسیم کرده و همچنین مقدار skewd را در کنار پلات نمایش میدهیم:

plt.figure(figsize=(20,10))
bar = sns.distplot(train['SalePrice'])
bar.legend(['Skewnes: {:.2f} '.format(train['SalePrice'].skew())])
plt.show()

در کد زیر متود corr برای ما این کار را انجام میدهد:

Compute pairwise correlation of columns, excluding NA/null values.

یعنی مقدار وابستگی جفت ستون ها را برای ما نمایش میدهد. در خط دوم میخواهیم که آن مقادیری که بزرگتر از نیم باشند را برای ما جدا کند. که یازده مورد از ستون ها correlation بیشتر از نیم دارند. (ا ز15 مورد موجود)

corr = train.corr()

high_corr_features = corr.index[abs(corr['SalePrice']) > 0.5] 
print(f'Highly Corrolated Features:\n', high_corr_features, '\n') 
print(f'No. of Highly Corrolated Features:', len(high_corr_features))

با دستور زیر هیت مپ این 11 مورد را رسم میکنیم:

plt.figure(figsize=(14,12))   
sns.heatmap(train[high_corr_features].corr(), annot=True, cmap='coolwarm', cbar=True, fmt='.2f', square=True, linewidths=2)

plt.title('Higly Correlatated Features Matrix', fontsize=16)
plt.xlabel('Features', fontsize=12)
plt.ylabel('Features', fontsize=12)

FEATURE ENGINEERING

ابتدا با get dummy مقادیر categorical را به numerical تبدیل میکنیم: (هم train و هم test )

Convert categorical variable into dummy/indicator variables.

train = pd.get_dummies(train, drop_first=True)  
test = pd.get_dummies(test, drop_first=True)  
train.shape   
test.shape

با دستور زیر میبینیم که هیچکدام از ستون ها دیگر از نوع object یا categorical نیستند:

len(train.select_dtypes(include='object').columns)

سوال: چرا نتیجه دستور زیر قبل و بعد از اجرای getdummy تفاوت دارد؟

جواب: به نظر میرسد، زمانی که به روش getDummy ستون های categorical به numerical تبدیل میشوند، این تغییر رخ میدهد.

SPLITTING DATASET

در این قسمت مجددا corr را حساب میکنیم و مشاهده میشود که مجددا 11 ستون واجد شرایط corr بزرگتر از 0.52 هستند: در دو مورد باهم تفاوت دارند در حالت اول مورد YearRemodAdd وجود دارد ولی در حالت دوم (بعد از دامی کردم) مورد ExterQual_TA وجود دارد.

corr = train.corr()

high_corr_features = corr.index[abs(corr['SalePrice']) > 0.52] 
print(f'Highly Corrolated Features:\n', high_corr_features, '\n') 
print(f'No. of Highly Corrolated Features:', len(high_corr_features))

نکته :

در اینجا 11 مورد از ستون ها را انتخاب کرده ایم و نام آن را high_corr_features گذارده ایم. این موارد را در حاتی امنتخاب کردیم که دیتای ما با روش get dummy مقادیر cat آن به num تبدیل شده است. در صورتی که 11 مورد قبلی از حالتی از data استخراج شد که مقادیر cat ما حضور داشتند.

با دستور زیر X و y را برای آموزش آماده میکنیم:

X = train[high_corr_features.drop('SalePrice')]      
y = train[['SalePrice']]  

اکنون x ما 10 ستون دارد که همان فیچرهای سلکت شده هستند. و y ما یک ستون دارد که قیمت ها هستند. بنابراین دیتایterst نیز باید از فیلتری عبور کند که 10 ستون آن باقی بماند:

1- وقتی دیتا ست تست را میخوانیم 80 فیچر دارد.
2- فیلتر اول: گت دامی –> که مقادیر cat آن به Num تبدیل میشود. که ستون های آن به 228 تا افزایش می یابد.
3- فیلتر دوم: که فیچر های با corr بزرگتر از 0.52 آن مشخص میشود. ستون ها به 10 مورد کاهش می یابد.

test = pd.get_dummies(test, drop_first=True)  
test = test[high_corr_features.drop('SalePrice')] 
len(test.columns)

فیلتر های train:

1- ابتدا 81 فیچر داشتیم
2- چهار مورد آن را حذف کردیم (مواردی که بیش از 50 درصد null داشتند.) 77 ستون باقی میماند. (در کل 19 ستون دارای null داشتیم که 15 مورد باقی ماند)
3- در 15 مورد باقی مانده با mod یا mean مقادیر null را از بین بردیم. (کاری که برای test نکردیم)
4- گت دامی میزنیم و ستون های آن به 238 مورد میرسد.
5- فیلتر دوم: که فیچر های با corr بزرگتر از 0.52 آن مشخص میشود. ستون ها به 10 مورد کاهش می یابد.

حال با دستور زیر ترین و تست را جدا میکنیم:

X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=0)

با دستور زیر مشخص میشود که ترین و تست در چه وضعیت سطر و ستونی قرار دارند:

print(f'X_train',X_train.shape)  #Printing the X_train Features Shape
print(f'y_train',y_train.shape)  #Printing the y_train Labels Shape
print(f'X_val',X_val.shape)    #Printing the X_test Features Shape
print(f'y_val',y_val.shape)    #Printing the y_test Labels  Shape

با دستور زیر مقادیر null دیتایtest را با مقدار میانگین بدست آمده از Mode ستون ها جایگذاری میکنیم

test.fillna(test.mode().iloc[0], inplace=True) 

با دستور زیر دیتا را نرمال سازی میکنیم:

# normalise data
ss = StandardScaler()
X_train = ss.fit_transform(X_train)
X_val = ss.transform(X_val)
test = ss.transform(test)

توضیح :

transform() method helps in transforming the data into a form that is suitable for the model.

fit() method helps in fitting the data into a model.

fit_transform() method, combines the functionalities of both fit() and transform() methods in one step.

BUILDNG MODEL

رندوم فورست:

با دستور زیر مدل را روی دیتای ترین و تست فیت میکنیم و اصطلاحا مدل را آموزش میدهیم:

clf_rfr = RandomForestRegressor(random_state=0)   
clf_rfr.fit(X_train, y_train)                    
pred = clf_rfr.predict(X_val) 

PREDICTION AND SUBMISSION

و در نهایت با دستورات زیر خروجی مورد نظر ذخیره میکنیم:

output = clf_rfr.predict(test)                   
df=pd.DataFrame({"Id":Id.values,"SalePrice":output})
df.to_csv('final_house_price.csv', index=False)

منابع:

1- گیت هاب

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد.