มาทำนายผลราคาบ้านด้วยขั้นตอนการทำ machine learning จาก house-price-india dataset ด้วย R กันเถอะ

Image placeholder
แวะมาทักทายกันได้


บทความนี้เป็นการใช้ภาษา R ในการทำ Machine Learning เพื่อทำนายผลราคาบ้านของ Dataset house price india ด้วยการใช้ Linear Regression และ KNN ทำมาเพื่อเปรียบเทียบประสิทธิภาพในการทำนายผล ซึ่งเป็นการฝึกทำขั้นตอนการทำ machine learning ที่เรียนมาจาก data rockie bootcamp โดยข้อสรุปของผลที่ได้นั้น อ่านต่อด้านล่างนี้ได้เลย


ก่อนจะเริ่มทำ Machine Learning จริงๆแล้ว เราควรจะทำการ EDA หรือใช้ความรู้ทางสถิติเพื่อ สำรวจข้อมูลก่อนเพื่อที่จะจัดการข้อมูลหรือที่เรียกว่า Preparation Data เสียก่อน

โดยเริ่มจากการตั้งคำถามก่อน โดยตั้งเอาไว้ 2 ข้อดังนี้

  • อยากรู้ว่าราคาทั้งหมดของ Data set มีการกระจายตัวอย่างไรบ้าง
  • model ระหว่าง linear regression กับ knn แบบไหนดีกว่ากัน


จากนั้นก็ load library ที่จำเป็นแล้วเริ่มทำการ explore data

library("tidyverse")

## EDA
library("readxl")
library("tidyverse")
library("caret")
library("httr")
GET("<https://query.data.world/s/abvtdvuruklmcomk4h7y2hbjtru63m>", write_disk(tf <- tempfile(fileext = ".xlsx")))
df_hp_india <- read_excel(tf)

View(df_hp_india)

mean(df_hp_india$Price)
median(df_hp_india$Price)
max(df_hp_india$Price)
min(df_hp_india$Price)

จากนั้นก็ทำการ sampling data

## Split Data
set.seed(50)
n <- nrow(df_hp_india)
id <- sample(1:n, size=0.7*n)
train_data <- df_hp_india[id, ]
test_data <- df_hp_india[-id, ]

## Visualization
hist(df_hp_india$Price)
boxplot(df_hp_india$Price)

จะพบว่ามีค่าที่สูงจนไม่สามารถดูได้ และ เบ้ขวา


ข้อมูลมีลักษณะของเบ้ขวา จะต้องทำการ sampling เพื่อ ทำ normal distribution ก่อนที่จะเข้า machine learning

ซึ่งถ้าสังเกต histogram จะมีค่าที่สูงมากๆ แม้ว่าจะ sampling ค่ามา จะต้องทำการใส่ค่า log เพื่อเปลี่ยนค่าให้เล็กลง

log_price <- log(train_data$Price)
log_price
hist(log_price)


แล้วทำการ Explore ดูอีกครั้งหลังจากใส่ค่า Log


> mean(log_price)
[1] 13.04824
> median(log_price)
[1] 13.01701
> max(log_price)
[1] 15.85673
> min(log_price)
[1] 11.26448


หลังจากที่ใส่ค่า log แล้ว สามารถที่จะ exp() เพื่อคืนค่าเดิมได้ จะมีตัวอย่างให้ดูด้านล่างนี้


ถ้ามาลองคิดดูแล้ว น่าจะต้องเอาค่า feature ทุกตัวที่ต้องการเป็น input มา predict จะต้องทำการ log ค่าเช่นเดียวกัน

ซึ่งจะมีค่าดังนี้

number of bedrooms

number of bathrooms

living area

number of views

lot area


ทำการแปลงค่าโดยสร้าง dataframe ขึ้นมาใหม่ โดยใช้ความรู้ data transform หรือ library ชื่อ dplyr


ทำการ select data มาทำเป็น dataframe

## select data feature

df_prepare_data <- df_hp_india %>% select(Price, 
                       `number of bedrooms`, 
                       `number of bathrooms`,
                       `living area`,
                       `number of views`,
                       `lot area`)


ทำการเพิ่ม column

df_prepare_data %>% mutate(log_Price = log(Price + 1),
log_num_bedroom = (log(`number of bedrooms`) + 1),
log_num_bathrooms = (log(`number of bathrooms`) + 1),
log_living_area = (log(`living area`) + 1),
log_num_views = (log(`number of views`) + 1),
log_lot_area = (log(`lot area`) + 1)
)

View(df_prepare_data)


เดี๋ยวจะใส่กลับเข้าไปใน object เดิม คราวนี้เราก็จะได้ column ที่เป็นค่า log ของแต่ละ feature


ทำการ split ใหม่อีกครั้ง จาก new dataset

## Split Data Again with new dataset

set.seed(42)
n <- nrow(df_prepare_data)
id <- sample(1:n, size=0.7*n)
new_train_data <- df_prepare_data[id, ]
new_test_data <- df_prepare_data[-id, ]


จากนั้นก็เอามาเข้า ml เพื่อ train model เริ่มจาก linear regression ก่อน

## Train Model
ctrl <- trainControl(method = 'cv', number=10)

linear_regression_model <- train(log_Price ~  
      log_num_bedroom + 
      log_num_bathrooms + 
      log_living_area + 
      log_num_views +
      log_lot_area,
      data = new_train_data, 
      method = 'lm',
      trControl = ctrl)


เมื่อลอง run พบว่า เกิด error บางอย่าง ก็คือ เจอค่า null ใน column log_num_view อาจจะเป็นเพราะ บวก 1 ไม่ถูก ในที่นี้ขอตัดค่า log_num_view ออกไปก่อน

## Train Model
ctrl <- trainControl(method = 'cv', number=10)

linear_regression_model <- train(log_Price ~  
      log_num_bedroom + 
      log_num_bathrooms + 
      log_living_area + 
      log_lot_area,
      data = new_train_data, 
      method = 'lm',
      trControl = ctrl)

###### Result ######

> linear_regression_model
Linear Regression 

10234 samples
    4 predictor

No pre-processing
Resampling: Cross-Validated (10 fold) 
Summary of sample sizes: 9210, 9210, 9211, 9211, 9211, 9210, ... 
Resampling results:

  RMSE       Rsquared   MAE      
  0.3751279  0.4943142  0.3012616

Tuning parameter 'intercept' was held constant at a value of TRUE


จากนั้นลอง เอามา model มา predict กับ new data หรือ test dataset

## Score Model
log_price_pred <- predict(linear_regression_model, newdata = new_test_data)
log_price_pred


ลองหาค่า error ที่ได้จากการ ทดสอบ โดยใช้ function Root Mean Square Error ตาม code ด้านล่าง

## Evaluate Model
rmse_metric <- function(actual, prediction){
    sq_error <- (actual - prediction)**2
    sqrt(mean(sq_error))
}


ทำการประเมิน

rmse_metric(newtest_data$log_Price, log_price_pred)
[1] 0.3705133


เอาค่าที่ได้จาก predict และ test มาเทียบกัน

train : 0.3751279
test :  0.3705133


มีค่าใกล้เคียงกัน

ลองสร้าง data ใหม่ที่สมมติขึ้นมา

(new_data <- data.frame(
  log_price_pred = c(13.25164), 
  log_num_bedroom = c(2.586294), 
    log_num_bathrooms =c(1.910930), 
    log_living_area = c(8.918685),
    log_lot_area = c(11.937969)
  ))


ทดสอบอีกครั้ง ได้ผลว่า price เดิม ใกล้เคียงกับ price ที่ลองสมมติขึ้นมา

log_price_pred <- predict(linear_regression_model, newdata = new_data)
log_price_pred

## price
13.17152

ลอง convert ค่า 13.17152 ด้วย exponential

exp(13.17152)
###
525192.4

คราวนี้มาลองทดสอบ ด้วย knn model เพื่อเปรียบเทียบ model

ctrl <- trainControl(method = 'cv', number=10)

knn_model <- train(log_Price ~  
log_num_bedroom + 
log_num_bathrooms + 
log_living_area + 
log_lot_area,
data = new_train_data, 
method = 'knn',
trControl = ctrl)

knn_model

##### Result #####

k-Nearest Neighbors 

10234 samples
    4 predictor

No pre-processing
Resampling: Cross-Validated (10 fold) 
Summary of sample sizes: 9209, 9210, 9210, 9211, 9211, 9211, ... 
Resampling results across tuning parameters:

  k  RMSE       Rsquared   MAE      
  5  0.3780176  0.4942525  0.2994490
  7  0.3689344  0.5137424  0.2926094
  9  0.3650446  0.5224657  0.2900262

RMSE was used to select the optimal model using the smallest value.
The final value used for the model was k = 9.
## Score Model
log_price_pred <- predict(linear_regression_model, newdata = new_test_data)
log_price_pred
## Evaluate Model
rmse_metric <- function(actual, prediction){
    sq_error <- (actual - prediction)**2
    sqrt(mean(sq_error))
}

###
> rmse_metric(new_test_data$log_Price, log_price_pred)
[1] 0.3372817

เปรียบเทียบ  Model

Linear Regression

train : 0.3751279
test :  0.3705133

Knn

train :  
k  RMSE      
5  0.3780176  
7  0.3689344 
9  0.3650446
test : 0.3372817

ได้ข้อสรุปว่า เมื่อเปรียบเทียบระหว่าง model linear regression กับ knn

knn มีค่า error ที่ต่ำกว่า


code ทั้งหมด

library("readxl")
library("tidyverse")
library("caret")
library("httr")
GET("<https://query.data.world/s/abvtdvuruklmcomk4h7y2hbjtru63m>", write_disk(tf <- tempfile(fileext = ".xlsx")))
df_hp_india <- read_excel(tf)

View(df_hp_india)

mean(df_hp_india$Price)
median(df_hp_india$Price)
max(df_hp_india$Price)
min(df_hp_india$Price)

hist(df_hp_india$Price)
boxplot(df_hp_india$Price)

## Split Data
set.seed(50)
n <- nrow(df_hp_india)
id <- sample(1:n, size=0.7*n)
train_data <- df_hp_india[id, ]
test_data <- df_hp_india[-id, ]

hist(train_data$Price)
boxplot(train_data$Price)

log_price <- log(train_data$Price + 1)
log_price
hist(log_price)
boxplot(log_price)

mean(log_price)
median(log_price)
max(log_price)
min(log_price)

## select data feature

df_prepare_data <- df_hp_india %>% select(Price, 
`number of bedrooms`, 
`number of bathrooms`,
`living area`,
`number of views`,
`lot area`) %>% mutate(log_Price = log(Price + 1),
log_num_bedroom = (log(`number of bedrooms`) + 1),
log_num_bathrooms = (log(`number of bathrooms`) + 1),
log_living_area = (log(`living area`) + 1),
log_num_views = (log(`number of views`) + 1),
log_lot_area = (log(`lot area`) + 1))

View(df_prepare_data)

## Split Data Again with new dataset

set.seed(42)
n <- nrow(df_prepare_data)
id <- sample(1:n, size=0.7*n)
new_train_data <- df_prepare_data[id, ]
new_test_data <- df_prepare_data[-id, ]

new_train_data

## Train Model
ctrl <- trainControl(method = 'cv', number=10)

linear_regression_model <- train(log_Price ~  
      log_num_bedroom + 
      log_num_bathrooms + 
      log_living_area + 
      log_lot_area,
      data = new_train_data, 
      method = 'lm',
      trControl = ctrl)

linear_regression_model

## Score Model
log_price_pred <- predict(linear_regression_model, newdata = new_test_data)
log_price_pred

## Evaluate Model
rmse_metric <- function(actual, prediction){
    sq_error <- (actual - prediction)**2
    sqrt(mean(sq_error))
}

rmse_metric(new_test_data$log_Price, log_price_pred)

(new_data <- data.frame(
  log_price_pred = c(13.25164), 
  log_num_bedroom = c(2.586294), 
    log_num_bathrooms =c(1.910930), 
    log_living_area = c(8.918685),
    log_lot_area = c(11.937969)
  ))

log_price_pred <- predict(linear_regression_model, newdata = new_data)
log_price_pred

exp(13.17152)

knn_model <- train(log_Price ~  
log_num_bedroom + 
log_num_bathrooms + 
log_living_area + 
log_lot_area,
data = new_train_data, 
method = 'knn',
trControl = ctrl)

knn_model

## Score Model
log_price_pred <- predict(knn_model, newdata = new_test_data)
log_price_pred

## Evaluate Model
rmse_metric <- function(actual, prediction){
  sq_error <- (actual - prediction)**2
  sqrt(mean(sq_error))
}

rmse_metric(new_test_data$log_Price, log_price_pred)



เป็นอย่างไรบ้างครับ หวังว่าจะมีประโยชน์ ฝากกดแชร์บทความนี้ให้กับเพื่อนๆที่สนใจ ขั้นตอนการทำ machine learning กันด้วยนะครับ





แวะมาทักทายกันได้
donate

Categories: Research Tags: #Machine Learning , 1016