Bài viết này sẽ giới thiệu một số ví dụ ứng dụng hồi quy tuyến tính và hồi quy hậu cần. Trong hồi quy tuyến tính, chúng ta sẽ phỏng đoán giá nhà dựa vào số lượng phòng, và chỉ số truy cập đường cao tốc. Trong hồi quy hậu cần, chúng ta sẽ phân loại 3 loài hoa Iris dựa vào kích thước của cánh hoa và lá đài.

Chúng ta sẽ sử dụng thư viện scikit-learn trong bài viết này.

Nguồn dữ liệu

Nguồn dữ liệu chúng ta sử dụng dựa trên hai nguồn dữ liệu phổ biến:

  1. Dữ liệu giá nhà Boston từ http://archive.ics.uci.edu/ml/datasets/Housing.
  2. Dữ liệu hóa Iris từ http://archive.ics.uci.edu/ml/datasets/Iris.

Hai nguồn dữ liệu này đã được xử lý trước để phù hợp với mục đích bài viết. Sau đây là mã nguồn đã được dùng để xử lý dữ liệu.

# encoding: utf-8
import csv
from sklearn import datasets

# Boston
xs, ys = datasets.load_boston(return_X_y=True)
rooms_highway = [(1.0, x[5], x[8]) for x in xs]
with open('boston.csv', 'wb') as f:
    writer = csv.writer(f)
    writer.writerow(('bias', 'rooms', 'road', 'price'))
    for i, row in enumerate(rooms_highway):
        writer.writerow(row + (ys[i], ))

# Iris
xs, ys = datasets.load_iris(return_X_y=True)
with open('iris.csv', 'wb') as f:
    writer = csv.writer(f)
    writer.writerow(('sepal_length', 'sepal_width',
                     'petal_length', 'petal_width', 'bias', 'type'))
    for i, row in enumerate(xs):
        writer.writerow([x for x in row] + [1, ys[i]])

Giá nhà ở Boston

Tập dữ liệu giá nhà Boston bao gồm hai biến độc lập là số phòng, và chỉ số gần đường cao tốc, và một biến phụ thuộc là giá nhà. Tập dữ liệu này có tổng cộng 506 dòng.

Mục tiêu của ví dụ này là dự đoán (predict) giá nhà. Do đó, chúng ta sẽ xử dụng mô hình hồi quy tuyến tính.

Mô hình đầu tiên

Mô hình đầu tiên giả sử rằng

\begin{equation*} \text{Giá nhà} = \theta_1 \times \text{số phòng} + \theta_0 \end{equation*}

Với giả sử mô hình như vậy, trước hết chúng ta sẽ cần tìm các hệ số của véc-tơ \(\vec{\theta}\) qua quá trình đào tạo (train). Chúng ta sẽ làm việc này với một phần của tập dữ liệu. Lý do chúng ta chỉ sử dụng một phần, thay vì toàn bộ tập dữ liệu là vì chúng ta muốn giữ lại (hold out) một phần khác để kiểm tra (test) mô hình sau đó.

# encoding: utf-8
from sklearn import datasets, linear_model, model_selection

# Nạp bộ dữ liệu giá nhà Boston.
xs, ys = datasets.load_boston(return_X_y=True)
# Và lấy ra cột số phòng.
rooms_highway = xs[:, (5, )]
# Chia bộ dữ liệu ra làm hai phần, 80% dùng để dạy mô hình.
xs_train, xs_test, ys_train, ys_test = model_selection.train_test_split(
    rooms_highway, ys, test_size=0.2, random_state=42)
# Xác định mô hình là hồi quy tuyến tính.
model = linear_model.LinearRegression()
# Khớp mô hình với dữ liệu dạy.
model.fit(xs_train, ys_train)
print('Train R^2 score: {}'.format(model.score(xs_train, ys_train)))
print('Test R^2 score: {}'.format(model.score(xs_test, ys_test)))
# In ra 10 dòng giá trị kiểm tra.
predicted = model.predict(xs_test)
for i in range(10):
    print('Real: {}, predicted: {}'.format(ys_test[i], predicted[i]))

Kết quả nhận được khi thực thi chương trình này sẽ giống như sau:

Train R^2 score: 0.505065835278
Test R^2 score: 0.370756923225
Real: 23.6, predicted: 23.732382926
Real: 32.4, predicted: 26.929502007
Real: 13.6, predicted: 19.6845684169
Real: 22.8, predicted: 20.4511291323
Real: 16.1, predicted: 22.6199350586
Real: 20.0, predicted: 22.4516656333
Real: 17.8, predicted: 19.0395356199
Real: 14.0, predicted: 21.4700939856
Real: 19.6, predicted: 21.9842505629
Real: 16.8, predicted: 20.0958936788

Điểm \(R^2\) (R square score) có giá trị tốt nhất là \(1.0\).

Chúng ta thấy rằng điểm của mô hình với bộ dữ liệu dạy là \(0.505\), và với dữ liệu kiểm tra là \(0.371\). Nhìn lướt qua 10 giá trị trong bộ dữ liệu kiểm tra, ta thấy rằng độ sai lệch của giá trị dự đoán và giá trị thực không quá cao.

Mô hình thứ hai

Mô hình thứ hai giả sử rằng

\begin{equation*} \text{Giá nhà} = \theta_2 \times \text{số phòng} + \theta_1 \times \text{chỉ số gần đường} + \theta_0 \end{equation*}

Tương tự như mã nguồn ở phần trên, chúng ta chỉ thay đổi một chi tiết nhỏ.

# encoding: utf-8
from sklearn import datasets, linear_model, model_selection

# Nạp bộ dữ liệu giá nhà Boston.
xs, ys = datasets.load_boston(return_X_y=True)
# Và lấy ra hai cột số phòng, và chỉ số gần đường.
rooms_highway = xs[:, (5, 8)]
# Chia bộ dữ liệu ra làm hai phần, 80% dùng để dạy mô hình.
xs_train, xs_test, ys_train, ys_test = model_selection.train_test_split(
    rooms_highway, ys, test_size=0.2, random_state=42)
# Xác định mô hình là hồi quy tuyến tính.
model = linear_model.LinearRegression()
# Khớp mô hình với dữ liệu dạy.
model.fit(xs_train, ys_train)
print('Train R^2 score: {}'.format(model.score(xs_train, ys_train)))
print('Test R^2 score: {}'.format(model.score(xs_test, ys_test)))
# In ra 10 dòng giá trị kiểm tra.
predicted = model.predict(xs_test)
for i in range(10):
    print('Real: {}, predicted: {}'.format(ys_test[i], predicted[i]))

Kết quả nhận được khi thực thi chương trình này sẽ giống như sau:

Train R^2 score: 0.567849124316
Test R^2 score: 0.405470603973
Real: 23.6, predicted: 24.8754329851
Real: 32.4, predicted: 28.1205948465
Real: 13.6, predicted: 21.3963578154
Real: 22.8, predicted: 22.1078254754
Real: 16.1, predicted: 18.5643357112
Real: 20.0, predicted: 23.6867614067
Real: 17.8, predicted: 20.7976838087
Real: 14.0, predicted: 23.0535568772
Real: 19.6, predicted: 17.9743381395
Real: 16.8, predicted: 21.2224786844

Chúng ta thấy rằng điểm của mô hình thứ hai so với điểm của mô hình đầu tiên là cao hơn (\(0.568\) so với \(0.505\)\(0.405\) so với \(0.371\)). Điều này dễ hiểu vì mô hình thứ hai sử dụng thêm biến độc lập chỉ số truy cập đường cao tốc. Dĩ nhiên nhà gần đường cao tốc thì sẽ có giá tốt hơn nhà xa đường cao tốc vì việc đi lại sẽ dễ dàng hơn. So sánh 10 giá trị dự đoán và giá trị thực ta cũng thấy rằng sai số nhìn chung là thấp hơn so với mô hình đầu tiên.

Nhận xét

Chúng ta có hai nhận xét chính sau:

  1. Cả hai mô hình đều có điểm \(R^2\) kha khá. Điều này cho thấy cả hai mô hình đều đem lại giá trị phỏng đoán tương đối gần với giá trị thực.
  2. Mô hình thứ hai, vì có thêm thông tin có ảnh hưởng trực tiếp đến giá nhà, đem lại giá trị phỏng đoán tốt hơn mô hình đầu tiên.

Điều quan trọng nhất mà chúng ta cần ghi nhớ là không có một mô hình đúng. Việc tạo lập mô hình là một quá trình thử, và thử lại, rất dài, rất lâu, đòi hỏi nhiều kinh nghiệm, sự sáng tạo tinh tế, và một chút may mắn.

Phân loại 3 loài hoa Iris

Tập dữ liệu Iris bao gồm 4 biến độc lập là chiều dài và độ rộng lá đài, chiều dài và độ rộng cánh hoa, và 1 biến phụ thuộc là loài hoa (giá trị nguyên từ 0 đến 2). Tập dữ liệu này có 150 dòng, mỗi loài có 50 dòng.

Mục tiêu của ví dụ này là phân loại (classify) cho nên chúng ta sẽ áp dụng hồi quy hậu cần. Hơn thế nữa, chúng ta sẽ phải phân loại hai lần vì hồi quy hậu cần chỉ là một phương pháp phân loại nhị phân (binary classification). Trước tiên ta sẽ phân loại loài 0 với loài 1 và 2, sau đó chúng ta sẽ phân loại loài 1 và loài 2.

Phân loại loài 0 với loài 1 và loài 2

# encoding: utf-8
import numpy as np
from sklearn import datasets, linear_model, model_selection

# Nạp bộ dữ liệu Iris.
xs, ys = datasets.load_iris(return_X_y=True)
# Chép ys...
ys_zeros = np.copy(ys)
# ... và đặt loài 1 và loài 2 vào chung nhóm.
ys_zeros[50:] = 1
# Chia bộ dữ liệu làm hai phần để dạy và kiểm tra.
xs_train, xs_test, ys_train, ys_test = model_selection.train_test_split(
        xs, ys_zeros, test_size=0.2, random_state=42)
# Tạo một mô hình hồi quy hậu cần.
zero_model = linear_model.LogisticRegression()
# Dạy mô hình này phân loại loài 0 với loài 1 và 2.
zero_model.fit(xs_train, ys_train)
print('Accuracy: {}'.format(zero_model.score(xs_test, ys_test)))
# In ra 10 phân loại đầu tiên.
predicted = zero_model.predict(xs_test)
for i, p in enumerate(predicted[:10]):
    print('Real {}, predicted {}'.format(ys_test[i], p))

Khi thực thi đoạn mã này, chúng ta nhận được kết quả:

Accuracy: 1.0
Real 1, predicted 1
Real 0, predicted 0
Real 1, predicted 1
Real 1, predicted 1
Real 1, predicted 1
Real 0, predicted 0
Real 1, predicted 1
Real 1, predicted 1
Real 1, predicted 1
Real 1, predicted 1

Độ chính xác có giá trị tốt nhất là \(1.0\).

Nhìn qua kết quả (giá trị 0 là loài 0, giá trị 1 là loài 1 và loài 2), ta thấy rằng mô hình của chúng ta hoàn toàn có thể phân loại loài 0 trong ba loài hoa!

Phân loại loài 1 với loài 2

# encoding: utf-8
import numpy as np
from sklearn import datasets, linear_model, model_selection

# Nạp bộ dữ liệu Iris.
xs, ys = datasets.load_iris(return_X_y=True)
# Chép loại 1 và 2.
xs_one_two = xs[50:, :]
ys_one_two = ys[50:]
# Phân ra làm bộ dạy và bộ kiểm tra.
xs_train, xs_test, ys_train, ys_test = model_selection.train_test_split(
        xs_one_two, ys_one_two, test_size=0.2, random_state=42)
# Tạo mô hình hậu cần thứ hai.
one_two_model = linear_model.LogisticRegression()
# Dạy mô hình này phân biệt loài 1 và loài 2.
one_two_model.fit(xs_train, ys_train)
print('Accuracy: {}'.format(one_two_model.score(xs_test, ys_test)))
# In ra 10 phân loại đầu tiên.
predicted = one_two_model.predict(xs_test)
for i, p in enumerate(predicted[:10]):
    print('Real {}, predicted {}'.format(ys_test[i], p))

Kết quả thực thi sẽ là:

Accuracy: 0.85
Real 2, predicted 2
Real 2, predicted 2
Real 2, predicted 2
Real 1, predicted 1
Real 1, predicted 1
Real 1, predicted 1
Real 1, predicted 2  <--- kết quả phân loại khác với giá trị thực
Real 2, predicted 2
Real 1, predicted 1
Real 1, predicted 1

Dựa vào kết quả được in ra, ta thấy rằng mô hình này vẫn có độ chính xác cao, với giá trị \(0.85\), nhưng không tuyệt đối. Độ chính xác này nói rằng mô hình máy học mà chúng ta đã xây dựng có thể phân loại loài 1 và loài 2 đúng 85%.

Nhận xét

Chúng ta thấy rằng có một số dữ liệu có thể được phân loại hoàn toàn chính xác với mô hình hồi quy hậu cần, và cũng có những dữ liệu mà ta không thể tách biệt một cách dễ dàng được.

Tóm tắt

Bài viết này giới thiệu với các bạn hai bộ dữ liệu phổ biến là bộ dữ liệu giá nhà ở Boston, và bộ dữ liệu hoa Iris. Từ đó, chúng ta đưa ra một số mô hình máy học để phỏng đoán giá trị nhà dựa trên hồi quy tuyến tính, hoặc phân loại loài hoa dựa trên hồi quy hậu cần. Để kiểm tra tính đúng đắn, bài viết cũng giới thiệu sơ qua về kỹ thuật phân bộ dữ liệu ra làm hai phần để dạy và để kiểm tra lại.

Một điểm khác mà tác giả hy vọng bạn đọc nhận ra qua các ví dụ này là việc áp dụng máy học thật ra rất đơn giản. Hai dòng lệnh chủ đạo trong các ví dụ trên bao gồm 1) tạo mô hình, và 2) khớp mô hình với dữ liệu đã chuẩn bị. Ngay sau hai dòng lệnh đó là ta đã có thể phỏng đoán giá nhà, hoặc phân loại loài hoa rồi!

Tài liệu đọc thêm

  1. Bộ thư viện scikit-learn tại http://scikit-learn.org/.
  2. Trang Example for Principal Component Analysis (PCA): Iris data trong môn AMSC/CMSC 666 Numerical Analysis I do Tobias von Petersdorff dạy ở đại học Maryland, Hoa Kỳ.