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

Trong phần 1, tôi đã giới thiệu tổng quan về phương pháp học có giám sát và thực hành với mô hình k-Nearest Neighbors, trong phần này chúng ta sẽ đi tiếp với các mô hình Linear, Naive BayesDecision Tree.

1. Mô hình Linear

Là mô hình phổ biến nhất, cổ xưa nhất trong học thuật cũng như thực hành trong vài thập kỷ trở lại đây. Biểu diễn mô hình bởi công thức như sau:

ŷ = w[0] * x[0] + w[1] * x[1] + ... + w[p] * x[p] + b

Trong đó:

ŷ: Giá trị dự đoán (predictor)

x[]: Các biến số đầu vào, quy định các tính năng (features). Với single feature thì ta có mô hình: ŷ = w[0] * x[0] + b

w[]: Các hệ số, khi vẽ thành biểu đồ thì ta thấy hệ số này quy định độ dốc của đường tuyến tính

b: Giá trị bù thêm (intercept offset)

Mục tiêu của mô hình Linear là học để tìm ra giá trị các hệ số w[] và b. Ví dụ về single feature linear dưới đây:

Input:

mglearn.plots.plot_linear_regression_wave()

Output:

w[0]: 0.393906 b: -0.031804

Biểu đồ như sau:

So sánh với mô hình kNN thì có vẻ single feature linear khá đơn giản, thuần túy, không khớp với training data, còn bỏ sót khá nhiều data point. Tuy nhiên khi số features tăng lên thì sức mạnh, độ chính xác của mô hình tuyến tính Linear sẽ được thể hiện rõ nét. Cũng tương tự như mô hình kNN, chúng ta có Linear Regression và Linear Classification.

a. Linear Regression

Có khá nhiều mô hình hồi quy tuyến tính, các mô hình khác nhau ở chỗ các trọng số w và b được dạy học như thế nào và làm thế nào để kiểm soát độ phức tạp của mô hình. Chúng ta sẽ chỉ đi các mô hình phổ biến.

Linear Regression OLS:

Mô hình cổ điển, tìm các trọng số w và b bằng cách tối thiểu hóa hàm mất mát (loss function) – mean squared error của hiệu số giữa giá trị predictor ŷ và giá trị thực tế trong training set.

Dưới đây là đoạn code demo viết trên python:

Input:

import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
X, y = mglearn.datasets.make_wave(n_samples=60)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
lr = LinearRegression().fit(X_train, y_train)
mglearn.plots.plot_linear_regression_wave()
print("X.shape {}".format(X.shape))
print("lr.coef_: {}".format(lr.coef_))
print("lr.intercept_: {}".format(lr.intercept_))
print("Training set score: {:.2f}".format(lr.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lr.score(X_test, y_test)))print("Test set score: {:.2f}".format(lr.score(X_test, y_test)))print("Test set score: {:.2f}".format(lr.score(X_test, y_test)))

Output:

w[0]: 0.393906

b: -0.031804

X.shape (60, 1)

lr.coef_: [0.39390555]

lr.intercept_: -0.031804343026759746

Training set score: 0.67

Test set score: 0.66

Chú ý: coef_ chính là giá trị w, intercept chính là giá trị b.

Kết quả training và test đều xấp xỉ 0.67 là rất thấp, chứng tỏ mô hình single feature này bị underfitting. Tiếp theo chúng ta thử với lượng dữ liệu lớn hơn.

Input:

import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
X, y = mglearn.datasets.load_extended_boston()
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
lr = LinearRegression().fit(X_train, y_train)
print("X.shape {}".format(X.shape))
print("lr.coef_: {}".format(lr.coef_))
print("lr.intercept_: {}".format(lr.intercept_))
print("Training set score: {:.2f}".format(lr.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lr.score(X_test, y_test)))

Output:

w[0]: 0.393906

b: -0.031804

X.shape (506, 104)

lr.coef_: [-5.11126504e+02 4.02559787e+00 -9.45778613e+01 1.34720251e+01 3.48176257e+01 6.03611391e+01 3.49707471e+01 2.94114542e+00 3.14525465e+00 8.20792132e+01 1.24254396e+01 3.86676075e+01 -9.38409521e-01 1.32936334e+01 7.60317098e+02 1.42274855e+03 2.29220565e+02 -7.79405429e+01 8.79429261e+01 1.39813973e+01 1.02565346e+02 7.52178879e+02 -1.82071934e+03 5.34143172e+02 -2.41122305e+01 1.11848898e+02 -4.38177813e+00 -1.23079894e+01 -3.63360790e+00 -5.64878037e+01 4.60395879e-01 8.18005986e+00 -2.06294404e+01 -3.49659791e+01 4.31717988e+01 -2.92220843e+00 1.45250942e+01 -3.24346333e+01 3.66984591e+01 -2.75859278e+00 6.27805740e+00 4.98379104e+01 6.55060318e+00 3.91047481e+01 -1.14826290e+01 -8.00990322e-01 -3.68662287e+00 3.36483260e+01 -1.49103502e+01 1.34720251e+01 -1.80244019e+01 -2.90956806e+01 -2.78115796e+00 -1.10315060e+01 1.15584830e+00 -8.37313259e-01 -7.89905136e+00 6.27950290e+00 -1.09538327e+01 -2.48389637e+01 -1.16316264e+01 -3.00228631e+00 6.83518378e+01 -1.76428626e+01 6.10371772e+01 -6.12936496e+01 -1.14748321e+01 2.09075528e+01 3.32421356e+01 -4.11743268e+01 -2.19312422e+01 -2.08881337e+01 -5.05858326e+01 -2.14714962e+01 -1.11593182e+01 -6.16458839e-01 -1.12569338e+00 -1.40290786e-01 3.17622544e+01 -2.57159897e+01 5.51837314e-01 -1.33768644e+01 -3.25170630e+01 5.20806824e+01 1.08614313e-01 -3.62670514e+01 -2.68217433e+01 -3.42720513e+01 1.41341012e+01 -6.56371258e+01 8.64151127e+01 -3.08281756e+01 3.61562583e+01 -2.56736318e+01 -1.69118913e+01 3.35683331e+01 -7.48792540e+01 -2.02885460e+01 3.35543349e+00 1.07705825e+01 3.50306579e+00 -5.10021527e+00 2.46929457e+00 2.55749022e+01] lr.intercept_: -34.707522103873316

Training set score: 0.94

Test set score: 0.78

Chúng ta thấy có sự khác nhau giữa training score và test score, dấu hiệu của overfitting khi mô hình quá phức tạp, có quá nhiều hệ số. Một trong những giải pháp thay thế Linear Regression truyền thống là Ridge Regression.

Ridge Regression

Ridge Regression về cơ bản cũng giống với Linear Regression truyền thống, vẫn sử dụng đến hàm mean square error nhưng có điểm khác là công thức tìm giá trị hệ số w thì bổ sung thêm ràng buộc để sao cho các hệ số w nhỏ nhất có thể đến mức gần bằng 0, nghĩa là các feature (x) ít có ảnh hưởng tới giá trị đầu ra. Ràng buộc này sử dụng công thức chuẩn hóa L2.

Input:

import matplotlib.pyplot as plt
from sklearn.linear_model import Ridge
from sklearn.model_selection import train_test_split
X, y = mglearn.datasets.load_extended_boston()
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
lr = Ridge().fit(X_train, y_train)
print("X.shape {}".format(X.shape))
print("lr.coef_: {}".format(lr.coef_))
print("lr.intercept_: {}".format(lr.intercept_))
print("Training set score: {:.2f}".format(lr.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lr.score(X_test, y_test)))

Output:

X.shape (506, 104)

lr.coef_: [-1.66018119e+00 -1.41929759e+00 -5.37684614e-01 7.96954640e-01 7.74009379e-01 9.00801690e+00 -8.92776134e-02 -4.91574523e+00 4.70214703e+00 -5.75434742e-01 -1.03433773e+00 1.77375286e+00 -4.16912180e+00 -2.13431099e-01 3.34424596e-03 -1.04210767e+00 1.56638846e+00 -1.20451306e+00 -1.42821926e+00 -1.61322770e+00 -2.42136076e-01 -1.94292142e+00 -1.67700882e+00 -1.48142670e+00 -1.04731871e+00 -1.11313713e+00 1.49485608e+00 -1.32119098e+00 2.31624450e+00 5.36928772e-01 3.45017547e+00 -1.23455386e+00 -2.35995304e-01 -4.33677055e-01 5.38893908e-01 1.73276291e+00 -1.12104286e+00 -1.80935022e+00 2.88495662e+00 1.82746265e+00 6.32937278e-01 -3.47131888e+00 1.89615705e+00 -3.09731568e+00 1.29031258e+00 3.20064563e+00 -2.05596659e+00 8.12855686e-01 -3.32761682e+00 7.96954640e-01 -5.86013095e+00 -3.57189492e+00 1.58982272e+00 -1.86216410e+00 3.61069409e+00 3.83871054e+00 2.09210783e-01 1.45641163e+00 -3.71898439e+00 -2.43728264e+00 -2.82695659e+00 -1.89357431e+00 -1.00515836e+00 -1.36445946e+00 -1.05970963e+00 -2.79742388e+00 -5.76463641e-01 -8.21276002e-01 1.80618447e+01 -7.76371306e-01 2.51323314e+00 -8.74200296e+00 -9.28927450e+00 -6.35833636e+00 9.81331630e+00 -8.34429422e+00 2.04363934e+00 -2.70371191e+00 3.56231644e+00 4.88560092e-01 -3.63645437e+00 -9.62975567e-01 -5.15644035e+00 9.99195084e-01 -1.06904595e+00 -3.30865649e+00 2.01128756e-01 -4.78203750e+00 -1.26479048e-01 8.78662293e-03 5.62854157e-01 2.54344334e+00 2.60329865e+00 -8.37207151e+00 9.28661900e-01 2.01937829e+00 -7.97643825e-01 -7.26085189e+00 1.76650958e+00 -1.81787063e+00 -6.69991765e-01 2.79044443e-01 -4.99596454e+00 1.12372028e+01] lr.intercept_: 19.772508539375153

Training set score: 0.87

Test set score: 0.81

Ridge Regression cho training score thấp hơn Linear Regression truyền thống nhưng điểm test thực tế lại cao hơn. Bởi vì Ridge đã loại bớt được số lượng các hệ số w, giảm bớt độ phức tạp của mô hình, qua đó tránh được tình trạng overfitting, đạt được genelization với dữ liệu test.

Chúng ta nhận thấy có 01 mối quan hệ nghịch giữa việc giảm số lượng các hệ số w và điểm training score, càng tìm cách để giảm số lượng hệ số w để mô hình đơn giản hơn thì điểm training score càng tồi và ngược lại.  Do đó, trong mô hình Ridge có thêm một hệ số alpha để điều chỉnh. Tăng alpha sẽ làm giảm số lượng các hệ số w (hầu hết các hệ số w quy về giá trị 0) thì điểm training score càng thấp. Ví dụ:

Input: alpha = 10

ridge10 = Ridge(alpha=10).fit(X_train, y_train)
print("Training set score: {:.2f}".format(ridge10.score(X_train, y_train)))
print("Test set score: {:.2f}".format(ridge10.score(X_test, y_test)))

Output: alpha = 10

Training set score: 0.77

Test set score: 0.73

Input: alpha = 0.1

ridge10 = Ridge(alpha=0.1).fit(X_train, y_train)
print("Training set score: {:.2f}".format(ridge10.score(X_train, y_train)))
print("Test set score: {:.2f}".format(ridge10.score(X_test, y_test)))

Ouput: alpha = 0.1

Training set score: 0.92

Test set score: 0.82

Hình vẽ sau biểu diễn mối quan hệ giữa việc điều chỉnh hệ số alpha và số lượng các trọng số w.

Input:

plt.plot(lr.coef_, 's', label="Ridge alpha=1")
plt.plot(ridge10.coef_, '^', label="Ridge alpha=10")
plt.plot(ridge01.coef_, 'v', label="Ridge alpha=0.1")
plt.plot(lr.coef_, 'o', label="LinearRegression")
plt.xlabel("Coefficient index")
plt.ylabel("Coefficient magnitude")
plt.hlines(0, 0, len(lr.coef_))
plt.ylim(-25, 25)
plt.legend()

Output:

Một điểm cần chú ý nữa là số lượng training data càng nhiều thì độ chính xác của các mô hình sẽ càng cao. Hình vẽ sau so sánh kết quả giữa Ridge và Linear sau khi tăng số lượng training và testing data:

Input:

mglearn.plots.plot_ridge_n_samples()

Output:

Hình vẽ này cho thấy training score của Ridge là thấp hơn so với Linear bởi vì Ridge sử dụng chuẩn hóa nhưng testing score của Ridge lại cao hơn Linear, không xảy ra hiện tượng Overfitting như Linear. Với dữ liệu nhỏ hơn 400 thì mô hình Linear gần như là rất tồi. Tuy nhiên khi lượng dữ liệu ngày càng nhiều thì mô hình Linear ngày càng tiệm cận Ridge, lúc đó có vẻ công thức chuẩn hóa của Ridge không còn quan trọng nữa. Một điểm chú ý nữa là khi dữ liệu càng nhiều thì training score của Linear sẽ giảm vì rất khó để có một mô hình có thể Overfitting cho đống dữ liệu nhiều như này.

LASO REGRESSION

Một mô hình anh em với Ridge là Laso, thay vì Ridge sử dụng công thức chuẩn hóa L2 khi tìm hệ số w thì Laso sử dụng công thức chuẩn hóa L1. Sử dụng công thức chuẩn hóa L1 nhằm mục đích loại bớt feature ít ảnh hưởng tới đầu ra nghĩa là làm cho phần lớn các trọng số w = 0.

Công thức chuẩn hóa L1:

Thay vì sử dụng bình phương các trọng số w (chính là bj trong công thức) thì L1 sử dụng hàm abs, để giảm tối đa giá trị trọng số w.

Input:

import numpy as np
from sklearn.linear_model import Lasso
lasso = Lasso().fit(X_train, y_train)
print("X.shape {}".format(X.shape))
print("Training set score: {:.2f}".format(lasso.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lasso.score(X_test, y_test)))
print("lasso.coef_: {}".format(lasso.coef_))
print("Number of features used: {}".format(np.sum(lasso.coef_ != 0)))

print("Number of features used: {}".format(np.sum(lasso.coef_ != 0)))

print("Number of features used: {}".format(np.sum(lasso.coef_ != 0)))

Output:

X.shape (506, 104) Training set score: 0.27 Test set score: 0.26

lasso.coef_: [-0. 0. -0. 0. -0. 0.
-0. 0. -0. -0. -0. 0.
-8.26069561 -0. 0. -0. 0. -0.
-0. -0. -0. -0. -0. -0.
-0. -0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. 0. -0. 0. -0. -0.
-0. -0. -0. -0. -0. -0.
-0. 0. 0. 0. 0. 0.
0. 0. 0. 0. -0. -0.
-0. -0. -0. -0. -0. -0.
-0. -0. 0. 0. 0. -0.
-0. -0. 0. -0. -0. -0.
-0. -0. -0.50971544 -0. -0. 0.
-0. -0. -0. 0. -0. -1.13009513
-0. -0. -0. -0. -0. -0.
-0. -0. -0. -0. -0. 0.
-0. -0. ]

Number of features used: 3

Chúng ta thấy một kết quả tồi tệ, xảy ra hiện tượng underfitting bởi Laso đã loại bỏ gần hết các feature, cho ra một mô hình quá đơn giản. Cúng giống như Ridge, Laso có một hệ số alpha để điều chỉnh, mặc định alpha = 1.0, để tránh hiện tượng underfitting, chúng ta sẽ điều chỉnh giảm alpha và tăng tham số mặc định max_iter.

Input:

lasso001 = Lasso(alpha=0.01, max_iter=100000).fit(X_train, y_train)
print("Training set score: {:.2f}".format(lasso001.score(X_train, y_train)))
print("Test set score: {:.2f}".format(lasso001.score(X_test, y_test)))
print("Number of features used: {}".format(np.sum(lasso001.coef_ != 0)))

Output:

Training set score: 0.89

Test set score: 0.80

Number of features used: 34

Kết luận: Trong thực tế, Ridge Regression sẽ là lựa chọn đầu tiên khi xét đến việc sử dụng Ridge hay Lasso. Tuy nhiên với bài toán có số lượng lớn dữ liệu và muốn giảm bớt các nhân tố thuộc tính ảnh hưởng đến kết quả đầu ra cho dễ hiểu thì chúng ta hay sử dụng Lasso hơn. Ngoài ra scikit-learn có lớp ElasticNet cho phép chúng ta sử dụng kết hợp cùng lúc 02 phương pháp Ridge và Lasso bằng cách cho phép điều chỉnh các trọng số sử dụng của chuẩn hóa L1 và L2.

Mô hình Linear cho bài toán phân loại (Linear model for classification)

Mô hình Linear Classification cũng được sử dụng trong bài toán phân loại. Biểu diễn công thức của mô hình cũng tương tự Linear Regression:

ŷ = w[0] * x[0] + w[1] * x[1] + … + w[p] * x[p] + b > 0

Tuy nhiên thay vì trả về con số tổng giá trị của các feature thì đầu ra sẽ được phân loại class là -1 nếu giá trị < 0, phân loại classs là +1 nếu giá trị > 0. Nếu như biểu đồ của Linear Regression thường được vẽ dưới dạng đường thẳng tuyến tính với single feature, dạng mặt phẳng hoặc nhiều mặt phẳng với nhiều thuộc tính multi features thì biểu đồ của Linear Classification biểu diễn dưới dạng các vùng biên ranh giới quyết định và các đường, mặt phẳng chia cắt các ranh giới đó chính là các đường mặt phẳng của Regression.

Có 02 mô hình Linear Classification chính:

  • Logistic Regression: sử dụng class linear_model.LogisticRegression
  • Linear Support Vector Machines: sử dụng class svm.LinearSVC

Ví dụ:

Input:

from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC
import matplotlib.pyplot as plt
import mglearn

X,y = mglearn.datasets.make_forge()

fig, axes = plt.subplots(1,2, figsize=(10,3))

for model, ax in zip([LinearSVC(), LogisticRegression()], axes):
    clf = model.fit(X, y)
    mglearn.plots.plot_2d_separator(clf, X, fill=False, eps=0.5, ax=ax, alpha=.7)
    mglearn.discrete_scatter(X[:, 0], X[:, 1], y, ax=ax)
    ax.set_title("{}".format(clf.__class__.__name__))
    ax.set_xlabel("Feature 0")
    ax.set_ylabel("Feature 1")
axes[0].legend()

Output:

Cả 02 biểu đồ thể hiện đường kẻ chia ranh giới giữa 02 class 0 và 1. Ở dưới đường ranh giới là class 0, trên đường ranh giới là class 1. Cả 02 mô hình chúng ta thấy có đường biên ranh giới khá giống nhau do đều sử dụng chuẩn L2 regularization tương tự như thuật toán Ridge Regression.

Logistic và SVC có một tham số cho phép điều chỉnh điểm trade-off tối ưu hóa nhất bằng cách điều chỉnh hệ số của chuẩn L2 gọi là C, hệ số C càng cao thì càng tối thiểu hóa giá trị chuẩn hóa, càng dễ khớp với training data, khớp quá thì thành Overfitting, trong khi hệ số C càng thấp thì càng dễ triệt tiêu các trọng số C gây ra hiện tượng Underfitting. Ví dụ:

Input:

mglearn.plots.plot_linear_svc_regularization()

Output:

Chúng ta thấy khi C = 1000 có vẻ mô hình là khớp nhất so với training data, tuy nhiên vẫn bị sai mất 01 điểm. Nhìn chung mô hình Logistic và SVM đều bị hạn chế nếu lượng training data ít. Khi lượng training data nhiều lên thì sức mạnh của cả 02 thuật toán này mới được thể hiện. Sau đây, chúng ta sẽ thử với tập dữ liệu chẩn đoán ung thư của bệnh viện Boston, Mỹ:

Input:

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
cancer.data, cancer.target, stratify=cancer.target, random_state=42)
logreg = LogisticRegression().fit(X_train, y_train)
print("Training set score: {:.3f}".format(logreg.score(X_train, y_train)))
print("Test set score: {:.3f}".format(logreg.score(X_test, y_test)))

Output:

Training set score: 0.955

Test set score: 0.958

Chúng ta nhận thấy kết quả khá tốt với cả Training và Test data, tuy nhiên kết quả Training và Test khá giống nhau, có thể xảy ra hiện tượng underfitting. Chúng ta thử điều chỉnh tham số C để phân tích thêm:

Input:

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

cancer = load_breast_cancer()
X_train, X_test, y_train, y_test = train_test_split(
cancer.data, cancer.target, stratify=cancer.target, random_state=42)

logreg = LogisticRegression().fit(X_train, y_train)

print("C=1.Training set score: {:.3f}".format(logreg.score(X_train, y_train)))
print("C=1.Test set score: {:.3f}".format(logreg.score(X_test, y_test)))

logreg100 = LogisticRegression(C=100).fit(X_train, y_train)
print("C=100.Training set score: {:.3f}".format(logreg100.score(X_train, y_train)))
print("C=100.Test set score: {:.3f}".format(logreg100.score(X_test, y_test)))

logreg001 = LogisticRegression(C=0.01).fit(X_train, y_train)
print("C=0.01.Training set score: {:.3f}".format(logreg001.score(X_train, y_train)))
print("C=0.01.Test set score: {:.3f}".format(logreg001.score(X_test, y_test)))

plt.plot(logreg.coef_.T, 'o', label="C=1")
plt.plot(logreg100.coef_.T, '^', label="C=100")
plt.plot(logreg001.coef_.T, 'v', label="C=0.001")
plt.xticks(range(cancer.data.shape[1]), cancer.feature_names, rotation=90)
plt.hlines(0, 0, cancer.data.shape[1])
plt.ylim(-5, 5)
plt.xlabel("Feature")
plt.ylabel("Coefficient magnitude")
plt.legend()

Output:

C=1.Training set score: 0.955

C=1.Test set score: 0.958

C=100.Training set score: 0.972

C=100.Test set score: 0.965

C=0.01.Training set score: 0.934

C=0.01.Test set score: 0.930

Hình vẽ trên cho thấy mối quan hệ giữa các feature với trọng số. Phần lớn các feature có giá trị bằng 0, bị triệt tiêu mức độ ảnh hưởng tới kết quả đầu ra. Các feature có giá trị khác 0 chứng tỏ là những thuộc tính ảnh hưởng lớn tới kết quả đầu ra, ví dụ như “texture error”, “mean radius”. Đồng thời thay đổi trọng số điều chỉnh C cũng cho kết quả khác nhau. Với trọng số C = 100 cho kết quả cao nhất chúng ta thấy khá nhiều feature có giá trị khác 0, mô hình có vẻ phức tạp vì có quá nhiều thuộc tính ảnh hưởng tới kết quả đầu ra. Trường hợp chúng ta muốn tiếp tục loại bớt sự ảnh hưởng của các thuộc tính thì có thể cấu hình sử dụng công thức chuẩn hóa L1.

Input:

for C, marker in zip([0.001, 1, 100], ['o', '^', 'v']):
lr_l1 = LogisticRegression(C=C, penalty="l1").fit(X_train, y_train)
print("Training accuracy of l1 logreg with C={:.3f}: {:.2f}".format(
C, lr_l1.score(X_train, y_train)))
print("Test accuracy of l1 logreg with C={:.3f}: {:.2f}".format(
C, lr_l1.score(X_test, y_test)))
plt.plot(lr_l1.coef_.T, marker, label="C={:.3f}".format(C))
plt.xticks(range(cancer.data.shape[1]), cancer.feature_names, rotation=90)
plt.hlines(0, 0, cancer.data.shape[1])
plt.xlabel("Feature")
plt.ylabel("Coefficient magnitude")
plt.ylim(-5, 5)
plt.legend(loc=3)

Output:

Training accuracy of l1 logreg with C=0.001: 0.91

Test accuracy of l1 logreg with C=0.001: 0.92

Training accuracy of l1 logreg with C=1.000: 0.96

Test accuracy of l1 logreg with C=1.000: 0.96

Training accuracy of l1 logreg with C=100.000: 0.99

Test accuracy of l1 logreg with C=100.000: 0.98

 

 

Các khái niệm Generalization, Overfitting, Underfitting và Trade-Off trong Machine Learning

Trong Supervised Machine Learning, chúng ta cố gắng đi tìm mô hình dự đoán chính xác nhất có thể dựa trên dữ liệu thu thập được trong quá khứ để có thể đoán được chính xác kết quả của dữ liệu mới, chưa từng gặp trong tương lai.

1.Generalization

Nếu một mô hình dự đoán được chính xác phần lớn các trường hợp của dữ liệu mới thì ta gọi đó là mô hình đạt được độ khái quát hóa (generalization).

2. Overfitting

Trong thực tế có rất nhiều biến số trong cuộc sống, việc đi tìm các mô hình không đơn giản, không phải lúc nào cũng tìm được generalization. Ví dụ: 01 công ty kinh doanh du thuyền muốn dự đoán một khách hàng nào có khả năng mua du thuyền cao nhất dựa trên dữ liệu về khách hàng đã mua du thuyền được thu thập và phân tích đặc tính trước đó.

Tuổi Số ô tô sở hữu Có nhà riêng Số người con Tình trạng hôn nhân Có nuôi chó Có mua du thuyền
66 1 2 Góa chồng Không
52 2 3 Đã cưới Không
22 0 Không 0 Đã cưới Không
25 1 Không 1 Độc thân Không Không
44 0 Không 2 Li dị Không
39 1 2 Đã cưới Không
26 1 Không 2 Độc thân Không Không
40 3 1 Đã cưới Không
53 2 2 Li dị Không
64 2 3 Li dị Không Không
58 2 2 Đã cưới
33 1 Không 1 Độc thân Không Không

Sau khi phân tích dữ liệu, một số nhà phân tích ít kinh nghiệm đưa ra quy tắc: “Nếu khách hàng trên 45, có nhỏ hơn 03 con hoặc chưa từng li dị thì có khả năng mua du thuyền”. Họ cho rằng quy tắc này đúng 100%. Quy tắc trên là khá phức tạp nhiều biến số dựa trên lượng dữ liệu quá ít làm cho các nhà phân tích trẻ chủ quan rằng quy tắc quá hoàn hảo. Khi đó, chúng ta gọi mô hình này xảy ra là overfitting. Overfitting xảy ra khi xây dựng một mô hình quá phức tạp để khớp với một lượng dữ liệu training không đủ, dẫn tới mô hình này lại không thể khớp với dữ liệu mới trong thực tế.

3. Underfitting

Ngược lại với Overfitting là khi cảm thấy quá phức tạp, chúng ta bỏ bớt các biến số, đơn giản hóa mô hình nhưng đơn giản quá đến mức không bao quát được hết các biến số trong thực tế. Khi đó ta gọi mô hình này xảy ra underfitting. Ví dụ: “Những ai mua nhà thì sẽ mua du thuyền”.

4. Trade-Off

Có một điểm vàng (sweet spot) ở giữa Overfitting và Underfitting, ở đó chúng ta đạt mức độ generalization cao nhất. Điểm này gọi là điểm thỏa thuận, chấp nhận được (Trade – Off). Điểm này nhắc cho chúng ta nhân sinh quan trong cuộc sống, cái gì nhiều quá cũng không tốt mà ít quá cũng không được, cần nỗ lực không ngừng nhưng cần biết điểm dừng vừa đủ mới là tốt. Đó cũng là triết lý của tự nhiên.

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ế.

 

 

Tổng quan về Data Science

Bất kỳ phần mềm nào cũng đều có dữ liệu (dữ liệu đầu vào, dữ liệu đầu ra), các phần mềm quản lý thì đều có CSDL quản lý, quản trị; các trang web đều có dữ liệu nội dung trang web, bài viết; các mạng xã hội đều lưu trữ hàng tỷ petabytes nội dung mỗi ngày…v.v. Nói như vậy cho thấy tầm quan trọng của dữ liệu, tuy nhiên không dừng lại ở đó, khi con người không ngừng lưu trữ thu thập dữ liệu đến một ngày họ nhận ra rằng đó không chỉ là những con số nội dung thô sơ mà nó là những con số biết nói, chỉ cần tập trung một chút vào phân tích, biểu diễn dữ liệu sẽ có cái nhìn chiều sâu, phát hiện ra rất nhiều điều như vấn đề nội tại của một doanh nghiệp, quan hệ khách hàng ra sao, biết được điểm yếu, điểm mạnh thế nào từ đó có thể dự đoán khách quan được tình hình và đưa ra các chiến lược quyết sách trong tương lai…v.v. Có thể nói ngày nay có dữ liệu là có tất cả, hầu hết các phần mềm, phần cứng trên thế giới hiện nay đều thiết kế theo hướng dịch vụ và dữ liệu. Và dữ liệu nói chung, dữ liệu lớn (Big Data nói riêng) là một trong những trụ cột quan trọng của cuộc cách mạng công nghiệp 4.0 bên cạnh AI, Internet of Things, băng thông rộng. Chính vì vậy, những nghề liên quan đến dữ liệu là một trong những nghề IT hot nhất hiện nay và trong tương lai.

Chắc hẳn phần lớn trong chúng ta cảm thấy khá lạ lẫm, to tát khi nghe tới Data Science (khoa học về dữ liệu). Rốt cuộc nó có hoành tráng, phức tạp như cái từ nghĩa đen “khoa học dữ liệu” của nó không? Chúng ta từng nghe tới xác suất (Probability), thống kê (Statistic), Business Intelligence (BI), Data Warehouse rồi Big Data, Machine Learning, Deep Learning…v.v. Tất cả những lĩnh vực đó đều là phạm trù liên quan đến Data Science, điều này có nghĩa là để trở thành 01 data scientist thì bạn sẽ cần nắm được các lĩnh vực đó. Đến đây bạn đã thấy Data Science to tát và hấp dẫn chưa? Chúng ta bắt đầu khám phá về Data Science.

Hãy xem bức tranh toàn cảnh Infographic của Data Science:

Có tất cả 05 cột, trong đó 02 cột liên quan đến dữ liệu, 03 cột liên quan đến Data Science. Với mỗi cột ta sẽ đi trả lời các câu hỏi WHEN, WHAT, WHY, HOW, WHERE, WHO.

Đầu tiên, đối tượng chính của Data Science chính là dữ liệu, do đó ta cần hiểu data trong thế giới hiện nay là như thế nào. Dữ liệu hiện nay chia làm 02 loại: dữ liệu truyền thống và dữ liệu lớn.

  • Dữ liệu truyền thống: bao gồm dữ liệu các con số, văn bản biểu diễn dưới dạng các bảng trong CSDL quan hệ như CSDL người dùng – khách hàng, CSDL kho vật tư, CSDL lịch sử giá…v.v. Các phần mềm quản trị CSDL điển hình như SQL (Oracle, SQL Server, MySQL, DB2), Excel, IBM SPSS, ngôn ngữ lập trình: .NET, Java, C++, Python, Matlab…v.v. Những nghề nghiệp liên quan như: Data Engineer, Data Architect, Database Administration.
  • Dữ liệu lớn (Big Data): dữ liệu lớn lưu trữ và xử lý trong mạng xã hội, trong giao dịch tài chính bao gồm dữ liệu dạng số, dạng văn bản, dạng ảnh, dạng audio, dạng video. Dữ liệu lớn ở cả 03 cấp độ: dung lượng lớn (volume), tốc độ (velocity), sự đa dạng (varieties) . Các phần mềm quản lý và xử lý Big Data: Apache Hadoop, Escala, HBase, Python, R…v.v. Nghề nghiệp liên quan như Big Data Engineer, Big Data Architect.

Dữ liệu sau khi được tiền xử lý sẽ được đưa vào để phân tích. Đến đây bắt đầu là lĩnh vực của Data Science. Mục đích của Data Science là để phân tích dữ liệu trong quá khứ và nâng cao hơn 01 mức, dựa trên các phân tích đó để dự đoán được các kịch bản trong tương lai, dự đoán được hành vi bằng cách sử dụng các công nghệ của trí tuệ nhân tạo.

  • Business Intelligence: tập hợp các công cụ để phân tích dữ liệu trong quá khứ, biểu diễn dữ liệu dưới dạng biểu đồ, bảng điều khiển để thu được cái nhìn sâu sắc về những điều ẩn chứa bên trong dữ liệu (các chiều dữ liệu, thước đo về chỉ số hiệu năng KPI). BI thường được áp dụng trong phân tích tối ưu giá sản phẩm trong quan hệ khách hàng, quản lý kho vật tư, phân tích các dữ liệu về kinh tế. Các công cụ, phần mềm sử dụng trong BI: Datawarehouse (Oracle BI, Power BI), Tableau,  Excel, Python, R …v.v. Những nghề nghiệp liên quan bao gồm BI Analyst, BI Consultant, BI Developer.
  • Các công cụ, phương pháp dự đoán phân tích (ví dụ: phân tích thói quen người dùng để tự động gửi các quảng cáo, sản phẩm tương ứng; dự báo các mô hình kinh tế): bao gồm mô hình hóa dữ liệu đã phân tích theo hồi quy tuyến tính, phân loại chùm dữ liệu hay phân tích nhân tố. Các công cụ sử dụng như Python, R, Matlab, Eview, Escala, Stata. Những nghề nghiệp liên quan bao gồm Data Analyst, Data Scientist.
  • Sử dụng AI để đoán trước hành vi chưa từng xảy ra(ví dụ: tự động phát hiện gian lận trong các giao dịch tài chính, spam mail hay đưa ra các chiến lược giữ chân người dùng). Sử dụng các phương pháp của Machine Learning (học có giám sát, học không giám sát, học củng cố). Các công cụ sử dụng như Python, R, Matlab, …v.v. Những nghề nghiệp liên quan bao gồm: Data Scientist, Machine Learning Engineer.

Như vậy, bạn đã có cái nhìn tổng quan về ngành khoa học dữ liệu Data Science. Trong các phần tiếp theo, tôi sẽ đi sâu chi tiết vào từng lĩnh vực.