Supervised Learning (Thực hành – Phần 1)

1. Supervised Learning là gì?

  • Phương pháp bao gồm các thuật toán đoán trước giá trị dựa trên kinh nghiệm học của tập giá trị input – output trong quá khứ;
  • Điểm cốt lõi của phương pháp này là xây dựng tập giá trị đào tạo (training set data), bước này đòi hỏi nhiều nguồn lực, tuy nhiên sau khi có được bộ dữ liệu ngon thì việc tìm ra mô hình, công thức cho độ chính xác cao là rất nhanh;
  • Khi xây dựng được bộ dữ liệu, thông thường ta sẽ chia thành 02 bộ training settesting set data. Trong đó, training set để phục vụ cho việc học các mô hình (như k-Nearest Neighbors, linear, …v.v) còn testing set để đối chiếu so với kết quả học để check độ chính xác của các mô hình (ví dụ: training set chiếm 75%, testing set chiếm 25%). Trong thư viên scikit-learn của python có hàm train_test_split để thực hiện tạo 02 bộ dữ liệu từ 01 bộ dữ liệu mà ta đã thu thập từ trước: X_train, X_test, y_train, y_test = train_test_split(array_data, array_target, random_state=0). Lưu ý: X viết hoa đại diện cho input.

2. Phân loại Supervised Learning

02 loại chính của Supervised Learning là classification (phân loại) và regression (hồi qui).

Classification: mục đích là đoán trước để gán nhãn phân loại kết quả thuộc nhóm định sẵn. Chia làm 02 loại: binary classification (chỉ có 02 nhóm) và multi class (nhiều nhóm). Ví dụ về binary classification: phân tích kết quả chụp x-quang khối u đoán là u lành hay u ác; phân loại mail là spam hay không. Ví dụ dưới đây là code trên python để vẽ biểu đồ scatter biểu diễn dữ liệu chia thành 02 lớp xanh, đỏ tách biệt nhau rõ rệt:

import mglearn
import matplotlib.pyplot as plt
X, y = mglearn.datasets.make_forge()
mglearn.discrete_scatter(X[:,0], X[:,1],y)
plt.legend(["Class 0", "Class 1"], loc=4)
plt.xlabel("First Feature")
plt.ylabel("Second Feature")
print("X.shape: {}".format(X.shape))

Regression: mục đích là đoán trước kết quả là một số nguyên (floating point). Ví dụ: đoán thu nhập của một người dựa trên bằng cấp, tuổi tác và số năm kinh nghiệm; đoán giá nhà dựa trên diện tích và vùng miền. Ví dụ: đoạn code dưới đây mô phỏng dữ liệu dạng tuyến tính:

import mglearn
import matplotlib.pyplot as plt
X, y = mglearn.datasets.make_wave(n_samples=40)
plt.plot(X, y, 'o')
plt.ylim(-3, 3)
plt.xlabel("Feature")
plt.ylabel("Target")

3. Mô hình k-Nearest Neighbors

kNN Là một trong những mô hình đơn giản nhất của Machine Learning. Trong mô hình này, chúng ta xây dựng trước tập (input, output) cho training set, kết quả đoán trước của 01 input mới dựa vào quy tắc tìm điểm gần nhất của training set với input mới này (gọi là anh hàng xóm gần nhất). Dân gian có câu muốn biết tính cách của 01 người như nào hãy xem tính cách của anh/cô bạn thân của người đó; thuật toán này tương tự như vậy.

3.1. k-Neighbors classification

Trường hợp đơn giản nhất là chỉ xét cô bạn chỉ có 1 người bạn gái thân duy nhất, việc đoán tính cách có vẻ dễ dàng. 

mglearn.plots.plot_knn_classification(n_neighbors=1)

Như trong hình vẽ trên thì chúng ta chú ý hình ngôi sao là input cần test, chúng ta thấy có 3 đường kẻ tới các ngôi sao này, đó chính là đường nối giữa input training gần nhất với input test.

Tuy nhiên trong thực tế, rất ít trường hợp chỉ có 01 cô hàng xóm mà sẽ có thể có nhiều cô hàng xóm, khi đó ta có k-neighbors, đó chính là tên gọi của thuật toán này.

mglearn.plots.plot_knn_classification(n_neighbors=3)

Giờ chúng ta bắt đầu thử training với k-Neighbors với tập dữ liệu chuẩn đoán u lành hay u ác khi xét nghiệm ung thư:

from sklearn.model_selection import train_test_split
from sklearn.datasets import load_breast_cancer
from sklearn.neighbors import KNeighborsClassifier
cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, stratify=cancer.target, random_state=66)
training_accuracy = []
test_accuracy = []
# try n_neighbors from 1 to 10
neighbors_settings = range(1, 11)
for n_neighbors in neighbors_settings:
   # build the model
   clf = KNeighborsClassifier(n_neighbors=n_neighbors)
   clf.fit(X_train, y_train)
   # record training set accuracy
   training_accuracy.append(clf.score(X_train, y_train))
   # record generalization accuracy
   test_accuracy.append(clf.score(X_test, y_test))
plt.plot(neighbors_settings, training_accuracy, label="training accuracy")
plt.plot(neighbors_settings, test_accuracy, label="test accuracy")
plt.ylabel("Accuracy")
plt.xlabel("n_neighbors")
plt.legend()

Với cùng tập dữ liệu training và testing có sẵn, chúng ta tiến hành đánh giá độ chính xác khi thử hệ số k-neighbors từ 1 đến 10. Dựa trên kết quả cho ta thấy, với tập dữ liệu training độ chính xác giảm xuống khi hệ số k tăng, còn với tập dữ liệu testing thì ngược lại, nghĩa là với chỉ 1 neighbors thì mô hình thực tế sẽ rất phức tạp (over fitting), độ chính xác thấp trong khi tăng số neighbors lên 10 (under fitting) thì mô hình quá đơn giản, kết quả cùng tồi không kém. Điểm kết quả khả quan nhất (generalization) rơi vào tầm 5-6, khoảng giữa 1 và 10. Trong thực tế khi triển khai các mô hình ML, chúng ta cần tìm ra điểm cho độ chính xác chấp nhận được.

3.2. k-Neighbors regression

Tương tự như classification, mô hình kNN regression rất đa dạng, phụ thuộc vào hệ k.

mglearn.plots.plot_knn_regression(n_neighbors=1)

mglearn.plots.plot_knn_regression(n_neighbors=3)

Triển khai thuật toán kNN regression sử dụng KNeighborsRegressor:

from sklearn.neighbors import KNeighborsRegressor
X, y = mglearn.datasets.make_wave(n_samples=40)
# split the wave dataset into a training and a test set
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# instantiate the model and set the number of neighbors to consider to 3
reg = KNeighborsRegressor(n_neighbors=3)
# fit the model using the training data and training targets
reg.fit(X_train, y_train)

print("Test set predictions:\n{}".format(reg.predict(X_test)))

print("Test set R^2: {:.2f}".format(reg.score(X_test, y_test)))

Kết quả:

Test set predictions: [-0.05396539 0.35686046 1.13671923 -1.89415682 -1.13881398 -1.63113382 0.35686046 0.91241374 -0.44680446 -1.13881398] Test set R^2: 0.83


Bây giờ, chúng ta thực hiện vẽ biểu đồ để có thêm chiều sâu phân tích kết quả, sử dụng tập dữ liệu từ hàm linspace của thư viện numpy, random 1000 điểm tuyến tính, chúng ta vẽ biểu đồ cho 03 hệ số k = 1, 3, 9.
import numpy as np
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# create 1,000 data points, evenly spaced between -3 and 3
line = np.linspace(-3, 3, 1000).reshape(-1, 1)
for n_neighbors, ax in zip([1, 3, 9], axes):
    # make predictions using 1, 3, or 9 neighbors
    reg = KNeighborsRegressor(n_neighbors=n_neighbors)
    reg.fit(X_train, y_train)
    ax.plot(line, reg.predict(line))
    ax.plot(X_train, y_train, '^', c=mglearn.cm2(0), markersize=8)
    ax.plot(X_test, y_test, 'v', c=mglearn.cm2(1), markersize=8)
    ax.set_title("{} neighbor(s)\n train score: {:.2f} test score: {:.2f}".format(n_neighbors, reg.score(X_train, y_train),
    reg.score(X_test, y_test)))
    ax.set_xlabel("Feature")
    ax.set_ylabel("Target")
axes[0].legend(["Model predictions", "Training data/target",
"Test data/target"], loc="best")

Kết quả:

Với k =  1 thì mô hình quá phức tạp, lên xuống liên tục, kết quả tồi;

Với k = 9 thì mô hình có vẻ đơn giản, đường nối rất trơn nhưng lại không khớp với training data.

Kết luận điểm mạnh, điểm yếu của kNN:

  • kNN phụ thuộc vào 02 yếu tố: hệ số k và hàm đo khoảng cách giữa các điểm để xác định khoảng cách nhỏ nhất, thực tế chúng ta sử dụng khoảng cách Euclidean để chuẩn hóa. Như trong training thì ta thấy điều chỉnh hệ số k sẽ cho ra kết quả độ chính xác khác nhau, k = 3 – 5 cho kết quả tốt nhưng trong thực tế chúng ta nên điều chỉnh nhiều hơn để tìm điểm tối ưu hóa nhất.
  • Điểm mạnh: dễ hiểu, dễ đạt được độ chính xác tốt mà ít phải điều chỉnh. 
  • Điểm yếu: phải xây dựng training set công phu và khi bộ dữ liệu lớn (hàng triệu) thì thuật toán sẽ chạy tương đối chậm. kNN không thể áp dụng được cho trường hợp mô hình có quá nhiều nhân tố biến số (lên đến hàng trăm). Chính vì vậy, kNN không được áp dụng nhiều trong thực tế.

 

 

0 Comments