Trong bài viết này, tôi sẽ giới thiệu một thuật toán cơ bản của Machine Learning - Linear Regression (Hồi quy Tuyến tính) thuộc nhóm học có giám sát (Supervised learning). Hồi quy Tuyến tính là một phương pháp đơn giản nhưng đã được chứng minh rằng nó rất hữu ích trong nhiều tình huống khác nhau. Trên thực tế, Hồi quy Tuyến tính làm việc như thế nào sẽ được trình bày chi tiết trong bài viết này.
Khi nghiên cứu về phân tích dữ liệu, chúng ta thường gặp thuật ngữ "Hồi quy" (Regression) thường xuyên. Trước khi đi sâu vào Hồi quy Tuyến tính, hãy hiểu khái niệm cơ bản của Hồi quy. Hồi quy là một phương pháp thống kê dùng để xác định mối quan hệ giữa một biến phụ thuộc và một nhóm các biến độc lập.
Đặt vấn đề
Mô hình dự báo giá xe hơi giúp chúng ta ước lượng giá trị của một chiếc xe hơi dựa trên các thông tin và đặc điểm quan trọng.
Trong quá trình xây dựng mô hình, chúng ta sẽ sử dụng các kỹ thuật và thuật toán để tìm mối quan hệ giữa các yếu tố như năm sản xuất, dung tích động cơ, số dặm đã đi, và nhiều yếu tố khác đến giá trị của xe hơi.
Việc xây dựng mô hình dự báo giá xe hơi không chỉ giúp chúng ta hiểu sâu hơn về quy luật và yếu tố ảnh hưởng đến giá trị xe, mà còn có thể hỗ trợ trong việc đưa ra quyết định mua bán, định giá và dự báo xu hướng thị trường xe hơi.
Thông tin dự án
Link github tham khảo: DiiyDiyy2002/car_price_prediction (github.com)
Sau đây là thông tin các file đã được đính kèm trong dự án xây dựng mô hình Marchine learning để dự báo giá xe có chứa trong github:
app.py: File Python chứa mã nguồn cho ứng dụng web. Nó sử dụng mô hình hồi quy để đưa ra dự báo giá xe hơi và hiển thị trên trang web giả lập chạy trên localhost.
build_model.ipynb: File Jupyter Notebook chứa quá trình xây dựng mô hình và phân tích dữ liệu.
index.html: File HTML để người dùng nhập các biến đầu vào.
result.html: File HTML để hiển thị kết quả dự báo khi người dùng đã nhập đầy đủ các thuộc tính.
/data: Thư mục chứa dữ liệu về xe hơi, bao gồm các trường như năm sản xuất, dung tích động cơ, số dặm đã đi và giá là biến phụ thuộc.
/templates: Thư mục chứa các file HTML templates.
/static/images: Thư mục chứa các hình ảnh sử dụng trong trang web.
report.pdf: File PDF chứa báo cáo chi tiết về dự án.
Sau đây, chúng ta sẽ tìm hiểu cụ thể cách xây dựng mô hình ML và đưa ra các kết quả dự báo.
Chuẩn bị dữ liệu
Import các thư viện cần thiết
Đọc dữ liệu
Khám phá dữ liệu (EDA)
Thêm các thư viện cần thiết
#Import thư viện
import pandas as pd
import numpy as np
import math
import os
from os import listdir
from datetime import date
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
import statsmodels.api as sm
from flask import Flask, render_template, request
Đọc dữ liệu
#Integration data
basic = 'data/'
df = pd.DataFrame(data = None)
for file in dirs:
url = basic + file
new_df = pd.read_csv(url) #đọc từng file trong folder
new_df['automaker'] = file.split(".")[0] #tạo cột hãng xe
if file == 'hyundi.csv':
new_df.rename(columns = {'tax(£)': 'tax'}, inplace =True) #đổi tên cột thuế
df = pd.concat([df,new_df]) #gộp file
Sau khi check các cột dữ liệu của các tệp, ta phát hiện có file csv của dòng xe Huyndi bị sai tên cột. Cụ thể, thay vì có tên là ‘tax’ như các file khác thì lại có tên là 'tax(£)'. Vì thế, tại phải đổi tên cột trong file này trước khi gộp các file dữ liệu lại với nhau.
Khám phá dữ liệu (EDA)
![](https://static.wixstatic.com/media/9cf01b_e676891bcc0448959e36661829c36f02~mv2.png/v1/fill/w_940,h_950,al_c,q_90,enc_auto/9cf01b_e676891bcc0448959e36661829c36f02~mv2.png)
Dữ liệu có 104641 dòng với 10 cột và tại cột tax, mpg có dữ liệu bị thiếu.
Mô tả các biến định lượng
![](https://static.wixstatic.com/media/9cf01b_e1afe4acd2354841bccdb623f770e016~mv2.png/v1/fill/w_940,h_346,al_c,q_85,enc_auto/9cf01b_e1afe4acd2354841bccdb623f770e016~mv2.png)
Phần trăm giá trị riêng biệt trong các cột định lượng
# Đếm số giá trị riêng biệt trong biến định lượng
distincts = []
percents = []
for numerical_col in numerical_cols:
distinct = df[numerical_col].nunique()
percent = distinct*100/df.shape[0]
print(numerical_col, 'column has',distinct,'distinct values')
print('It takes', format(percent,'.2f'),'%')
print('---')
distincts.append(distinct)
percents.append(format(percent,'.2f')+'%')
data = {'Count Distinct': distincts,'Take Percent':percents}
![](https://static.wixstatic.com/media/9cf01b_4e9ad5786f914a9a98320f6de1a19507~mv2.png/v1/fill/w_811,h_689,al_c,q_90,enc_auto/9cf01b_4e9ad5786f914a9a98320f6de1a19507~mv2.png)
Những cột định lượng có ít giá trị riêng biệt thì có thể nhóm các giá trị lại theo tứ phân vị. Chuyển đổi thành những cột mang tính định tính.
Độ tương quan giữa giá xe và tổng số dặm đã đi (mileage)
![](https://static.wixstatic.com/media/9cf01b_8ee330c3191744c2a60473cdd590177d~mv2.png/v1/fill/w_940,h_631,al_c,q_90,enc_auto/9cf01b_8ee330c3191744c2a60473cdd590177d~mv2.png)
Vì chưa thấy tương quan nhiền nên ta thử logarit biến mileage
![](https://static.wixstatic.com/media/9cf01b_f3e4f2e2a00d4432a6510007213a1648~mv2.png/v1/fill/w_940,h_631,al_c,q_90,enc_auto/9cf01b_f3e4f2e2a00d4432a6510007213a1648~mv2.png)
Tương quan trung bình giá với các biến category
![](https://static.wixstatic.com/media/9cf01b_faae0c0c23f54eb1a44fcff02e8beeed~mv2.png/v1/fill/w_940,h_940,al_c,q_90,enc_auto/9cf01b_faae0c0c23f54eb1a44fcff02e8beeed~mv2.png)
Tiền xử lý dữ liệu
Xử lý dữ liệu thiếu - Missing value
Kiểm tra
columns = df.columns
for i,column in enumerate(columns):
missing = df[column].isnull().sum()
percent = missing*100/(df.shape[0])
if missing > 0:
print('Column', column, 'contains', missing, 'missing value')
print('take', format(percent, ".2f"), "%")
print("--")
![](https://static.wixstatic.com/media/9cf01b_be03f98277a94d8899c53f6660e5377c~mv2.png/v1/fill/w_938,h_375,al_c,q_85,enc_auto/9cf01b_be03f98277a94d8899c53f6660e5377c~mv2.png)
Dữ liệu cột tax và mpg bị thiếu. Ta giải quyết bằng cách thay những giá trị bị null bằng giá trị trung bình của toàn dữ liệu.
Chuyển đổi dữ liệu
Nhóm cụm dữ liệu
Với hình ảnh trực quan về automaker với giá xe ta có thể gom cụm các automaker lại và chia thành ba mục chính (Luxury, Mid-range, Affordable).
def fill_class(x):
if x in ('merc','audi','bmw'):
return "Luxury"
if x in ('vw','skoda','focus'):
return "Mid-range"
else:
return "Affordable"
df['Class'] = df['automaker'].apply(lambda x: fill_class(x))
Vì cột year, engineSize có rất ít dữ liệu riêng biệt nên ta có thể xem nó như những dữ liệu định tính. Ta phân nhóm những trường dữ liệu này theo tứ phân vị.
df['year'] = pd.cut(df['year'],
bins = [0, 2015.9, 2016.9, 2018.9, 2061],
labels =['hơn 5 năm','4-5 năm','2-4 năm','dưới 2 năm'])
df['engineSize'] = pd.cut(df['engineSize'],
bins = [-1, df['engineSize'].quantile(0.25)-0.01, df['engineSize'].quantile(0.5)-0.01, df['engineSize'].quantile(0.75)-0.01, df['engineSize'].max()+0.01],
labels =['Small','Medium','Large','Very Large'])
Xử lý outlier
Những dữ liệu định lượng trong bộ dữ liệu có hiện tượng bị outlier khá nhiều, Hướng giải quyết cho điều này là thay thể các giá trị outlier về ngưỡng cho phép.
# Xử lý Outlier
cols = ['ln_mileage','tax','ln_mpg','price']
for col in cols:
# Tính IQR của biến
Q1 = df[col].quantile(0.25)
Q3 = df[col].quantile(0.75)
IQR = Q3 - Q1
# Xác định ngưỡng trên và ngưỡng dưới
upper_threshold = Q3 + (1.5 * IQR)
lower_threshold = Q1 - (1.5 * IQR)
# Thay thế các giá trị outlier
df[col] = df[col].apply(lambda x: upper_threshold if x >= upper_threshold else (lower_threshold if x <= lower_threshold else x))
Chia tập dữ liệu thành X và y
cat_features = ['year','transmission','fuelType','engineSize','Class']
num_features = ['ln_mileage','tax','ln_mpg']
features = cat_features + num_features
X = df[features].reset_index(drop=True)
y = df['price'].reset_index(drop=True)
Chuẩn hóa và đưa về dạng sẵn sàng để huấn luyện mô hình
Ở bước này, ta tiến hành mã hóa các biến category về dạng (0,1,..). Scale các biến định lượng. Cụ thể, tạo một Pipeline bằng thư viện sklearn và fit vào bộ dữ liệu X.
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
#Đường ống
num_transformer = Pipeline(steps = [
('scaler', StandardScaler())
])
cat_transformer = Pipeline([
('encoder',OneHotEncoder())
])
#Khai báo quá trình xử lý
preprocessor = ColumnTransformer([
('num',num_transformer,num_features),
('cat',cat_transformer,cat_features),
])
#Fit và transform vào bộ dữ liệu
X_transformed = preprocessor.fit_transform(X)
Chia training set và test set
Để tránh tình trạng bị bias khi huấn luyện mô hình, ta sẽ chia bộ dữ liệu thành 2 bộ nhỏ hơn với bộ trainning dùng để train mô hình máy học. Bộ test dùng để kiểm tra lại khi đã huấn luyện xong.
#Chia bộ dữ liệu
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X_transformed,y, train_size = 0.8)
Tỷ lệ chia là 8 - 2.
Chạy mô hình
from sklearn import linear_model
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score
#Khai báo mô hình
linear_regression = linear_model.LinearRegression()
#Huấn luyện mô hình
linear_regression.fit(X_train, y_train)
Kiểm tra các thông số kỹ thuật
y_pred = linear_regression.predict(X_test)
r2 = r2_score(y_test, y_pred)
print('R2 Score:',r2)
![](https://static.wixstatic.com/media/9cf01b_73df3a2d9b58480a833475dbf93243b7~mv2.png/v1/fill/w_669,h_125,al_c,q_85,enc_auto/9cf01b_73df3a2d9b58480a833475dbf93243b7~mv2.png)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
print('MSE:',mse)
print('RMSE:',rmse)
![](https://static.wixstatic.com/media/9cf01b_a97aff5f763d4565800ecc9b09888c17~mv2.png/v1/fill/w_581,h_156,al_c,q_85,enc_auto/9cf01b_a97aff5f763d4565800ecc9b09888c17~mv2.png)
Hệ số xác định (coefficient of determination) ký hiệu là R2, một con số thống kê tổng hợp khả năng giải thích của một phương trình. R2 = 82% thể hiện tổng mức biến thiên của các biến độc lập giải thích được 82% sự biến thiên của biến phụ thuộc. RMSE = 3325 là sai số bình quân khi dự đoán.
Tương quan giữa sai số và dự đoán
![](https://static.wixstatic.com/media/9cf01b_f6b0910f58db4908b7cc821919ccfaa0~mv2.png/v1/fill/w_940,h_665,al_c,q_90,enc_auto/9cf01b_f6b0910f58db4908b7cc821919ccfaa0~mv2.png)
Mô hình hồi quy OLS
Mô hình hồi quy OLS (Ordinary Least Squares) là một phương pháp ước lượng tham số trong mô hình hồi quy tuyến tính. Đây là phương pháp phổ biến và cơ bản nhất trong hồi quy tuyến tính.
Trong mô hình hồi quy OLS, chúng ta cố gắng tìm ra các tham số ước lượng sao cho tổng bình phương sai số (sum of squared residuals) là nhỏ nhất. Cụ thể, ta tính toán sai số giữa giá trị dự báo và giá trị thực tế cho từng điểm dữ liệu, sau đó bình phương và tổng hợp chúng lại.
Chuẩn bị dữ liệu
Mã hóa các cột category
#Mã hóa các cột category
# Thực hiện encode cho các cột categorical
X['price'] = y
cat_cols = ['year', 'transmission','fuelType','engineSize','Class']
for cat_col in cat_cols:
min_value = X.groupby(cat_col)['price'].sum().sort_values().index[0]
values = X[cat_col].unique()
for value in values:
X[value] = X[cat_col].apply(lambda x: 0 if x == min_value else (1 if x == value else 0))
del X['price']
remove_cols = cat_cols
X = X.drop(columns = remove_cols,axis =1)
Thay vì mã hóa bằng thư viện sklearn thì chúng ta mã hóa thủ công.
Scale các cột định lượng
# Thực hiện scaler cho các cột numerical
from sklearn.preprocessing import StandardScaler
num_cols = ['ln_mileage','tax','ln_mpg']
scaler = StandardScaler()
X[num_cols] = pd.DataFrame(data = scaler.fit_transform(X[num_cols]), columns= num_cols)
Chia bộ dữ liệu
#Chia bộ dữ liệu
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y, train_size = 0.8)
Huấn luyện mô hình
#Huấn luyện mô hình
model = sm.OLS(y_train, X_train)
X = sm.add_constant(X)
results = model.fit()
Thông số kỹ thuật
results.summary()
![](https://static.wixstatic.com/media/9cf01b_06ba9ab6659a4f17b4f0fb52e6f6e1bf~mv2.png/v1/fill/w_940,h_475,al_c,q_90,enc_auto/9cf01b_06ba9ab6659a4f17b4f0fb52e6f6e1bf~mv2.png)
R2 = 82.7%. F<0.05 ⇒ Mô hình có ý nghĩa thống kê.
![](https://static.wixstatic.com/media/9cf01b_0d538342f28c4f53877c66b0016e760c~mv2.png/v1/fill/w_856,h_1017,al_c,q_90,enc_auto/9cf01b_0d538342f28c4f53877c66b0016e760c~mv2.png)
p-value của những biến như Manual, Automatic, Semi-Auto, Hybrid cao hơn 0.05
⇒ Với mức ý nghĩa 5% thì những biến này không có ý nghĩa thống kê.
⇒ Có thể nói fuelType không ảnh hưởng đến giá của xe.
Dự báo
![](https://static.wixstatic.com/media/9cf01b_f6e5beb0107d43ad8e5f7b7e880dcf18~mv2.png/v1/fill/w_940,h_665,al_c,q_90,enc_auto/9cf01b_f6e5beb0107d43ad8e5f7b7e880dcf18~mv2.png)
Tương quan giữa sai số dự báo với giá dự báo. Sai số thấp hơn so với mô hình dùng trong sklearn.
Ứng dụng demo dự án dự báo giá xe hơn
Sau khi đã hoàn thành xong mô hình, chúng ta tạo một file python cho phép đọc dữ liệu và huấn luyện mô hình trong file. File python sẽ chạy một website với hosting là localhost. Cho phép chúng ta nhập dữ liệu trên web. Sau đó, từ dữ liệu người dùng nhập chúng ta sẽ dự báo giá xe theo mô hình đã huấn luyện từ đầu. Kết quả trả ra sẽ là giá xe được dự báo.
Comments