Khóa học
Bạn sẽ triển khai KNN trên bộ dữ liệu Iris nổi tiếng.
Lưu ý: Bạn có thể cân nhắc tham gia khóa học Machine Learning với Python hoặc để có bối cảnh về cách ML phát triển cùng nhiều nội dung khác, hãy đọc bài viết này.
Giới thiệu
Machine Learning phát triển từ khoa học máy tính, chủ yếu nghiên cứu thiết kế các thuật toán có thể học từ kinh nghiệm. Để học, chúng cần dữ liệu có các thuộc tính nhất định dựa trên đó các thuật toán cố gắng tìm ra những mẫu dự đoán có ý nghĩa. Nhìn chung, các tác vụ ML có thể được phân loại như học khái niệm, phân cụm, mô hình dự đoán, v.v. Mục tiêu cuối cùng của các thuật toán ML là có thể đưa ra quyết định chính xác mà không cần can thiệp của con người. Dự đoán cổ phiếu hay thời tiết là một vài ứng dụng của các thuật toán machine learning.
Có nhiều thuật toán machine learning như Cây quyết định, Naive Bayes, Rừng ngẫu nhiên, Máy véc-tơ hỗ trợ, Láng giềng gần nhất k, Phân cụm K-means, v.v.
Trong lớp thuật toán machine learning, hôm nay bạn sẽ sử dụng k-láng giềng gần nhất.
Vậy chính xác thuật toán K-Nearest Neighbor là gì? Hãy cùng tìm hiểu!
K-Nearest Neighbor là gì?
KNN hay k-láng giềng gần nhất là một thuật toán học có giám sát; “có giám sát” nghĩa là nó sử dụng nhãn lớp của dữ liệu huấn luyện trong giai đoạn học. Đây là một thuật toán học dựa trên thể hiện (instance-based), trong đó các điểm dữ liệu mới được phân loại dựa trên các thể hiện (điểm dữ liệu) đã lưu trữ và gán nhãn. KNN có thể dùng cho cả phân loại và hồi quy; tuy vậy, nó được dùng rộng rãi hơn cho mục đích phân loại.
Biến k trong KNN là một biến quan trọng, còn gọi là siêu tham số, giúp phân loại chính xác một điểm dữ liệu. Cụ thể hơn, k là số lượng láng giềng gần nhất mà bạn muốn “lấy phiếu” khi phân loại một điểm dữ liệu mới.

Bạn có thể thấy khi giá trị k tăng từ 1 lên 7, ranh giới quyết định giữa hai lớp có một số điểm dữ liệu trở nên mượt hơn.
Giờ câu hỏi là: làm sao mọi thứ “kỳ diệu” này diễn ra, khi mỗi lần có một điểm dữ liệu mới xuất hiện, nó được phân loại dựa trên các điểm đã lưu trữ?
Hãy hiểu nhanh theo các bước sau:
- Đầu tiên, bạn nạp toàn bộ dữ liệu và khởi tạo giá trị k,
- Sau đó, tính khoảng cách giữa các điểm dữ liệu đã lưu và điểm dữ liệu mới mà bạn muốn phân loại bằng các độ đo tương đồng hay khoảng cách như khoảng cách Manhattan (L1), khoảng cách Euclid (L2), độ tương đồng Cosine, khoảng cách Bhattacharyya, khoảng cách Chebyshev, v.v.
- Tiếp theo, sắp xếp các giá trị khoảng cách theo thứ tự tăng hoặc giảm và xác định k láng giềng gần nhất ở đầu hoặc cuối danh sách.
- Thu thập nhãn của k láng giềng gần nhất, và dùng đa số phiếu hoặc phiếu có trọng số để phân loại điểm dữ liệu mới. Điểm dữ liệu mới được gán nhãn lớp dựa trên điểm có số phiếu cao nhất trong tất cả các điểm đã lưu.
- Cuối cùng, trả về lớp dự đoán cho thể hiện mới.
Dự đoán có thể thuộc hai loại: phân loại trong đó gán nhãn lớp cho điểm dữ liệu mới, hoặc hồi quy trong đó gán một giá trị cho điểm dữ liệu mới. Khác với phân loại, trong hồi quy, trung bình của k láng giềng gần nhất sẽ được gán cho điểm dữ liệu mới.
Nhược điểm của KNN: Thứ nhất, độ phức tạp khi tìm láng giềng gần nhất cho mỗi điểm dữ liệu mới. Thứ hai, việc xác định giá trị k đôi khi là một nhiệm vụ khó khăn. Cuối cùng, cũng không rõ nên dùng loại độ đo khoảng cách nào khi tính láng giềng gần nhất.
Lý thuyết thế là đủ rồi nhỉ? Giờ hãy nạp, phân tích và tìm hiểu dữ liệu bạn sẽ dùng trong hướng dẫn nhỏ hôm nay.
Nạp dữ liệu Iris
Bộ dữ liệu Iris gồm 150 mẫu với ba lớp là Iris-Setosa, Iris-Versicolor và Iris-Virginica. Bốn đặc trưng/thuộc tính giúp nhận dạng duy nhất một trong ba lớp gồm sepal-length, sepal-width, petal-length và petal-width.
Bạn có thể thoải mái dùng bộ dữ liệu công khai khác hoặc dữ liệu riêng của bạn.
Sklearn là thư viện machine learning cho Python được dùng rộng rãi trong các tác vụ khoa học dữ liệu. Nó cung cấp nhiều thuật toán phân loại, hồi quy và phân cụm bao gồm support vector machines, random forests, gradient boosting, k-means, KNN, v.v. Trong sklearn có thư viện datasets chứa nhiều bộ dữ liệu sẵn dùng cho các tác vụ khác nhau, bao gồm cả Iris; tất cả có thể nạp sẵn “out of the box”. Rất trực quan và đơn giản. Vậy hãy nhanh chóng nạp bộ dữ liệu iris.
from sklearn.datasets import load_iris
load_iris có cả dữ liệu và nhãn lớp cho mỗi mẫu. Hãy trích xuất nhanh tất cả.
data = load_iris().data
Biến data sẽ là một mảng numpy có dạng (150,4) gồm 150 mẫu, mỗi mẫu có bốn thuộc tính khác nhau. Mỗi lớp có 50 mẫu.
data.shape
(150, 4)
Hãy trích xuất nhãn lớp.
labels = load_iris().target
labels.shape
(150,)
Tiếp theo, bạn cần kết hợp dữ liệu và nhãn lớp; để làm vậy, bạn sẽ dùng thư viện Python tuyệt vời là NumPy. NumPy bổ sung hỗ trợ cho mảng và ma trận lớn, đa chiều, cùng một tập hợp phong phú các hàm toán học cấp cao để thao tác trên các mảng này. Hãy import nhanh nó!
import numpy as np
Vì data là mảng 2 chiều, bạn cũng sẽ phải reshape labels thành mảng 2 chiều.
labels = np.reshape(labels,(150,1))
Bây giờ, bạn sẽ dùng hàm concatenate trong thư viện numpy, và dùng axis=-1 để nối theo chiều thứ hai.
data = np.concatenate([data,labels],axis=-1)
data.shape
(150, 5)
Tiếp theo, bạn sẽ import thư viện phân tích dữ liệu của Python là pandas — hữu ích khi bạn muốn sắp xếp dữ liệu theo dạng bảng và thực hiện một số thao tác, biến đổi trên dữ liệu. Cụ thể, nó cung cấp các cấu trúc dữ liệu và thao tác cho bảng số và chuỗi thời gian.
Trong hướng dẫn hôm nay, bạn sẽ dùng pandas khá nhiều.
import pandas as pd
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'species']
dataset = pd.DataFrame(data,columns=names)
Bây giờ bạn đã có khung dữ liệu dataset gồm cả dữ liệu & nhãn lớp bạn cần!
Trước khi đi tiếp, hãy nhớ rằng biến labels có nhãn lớp dưới dạng số, nhưng bạn sẽ chuyển các giá trị số này thành tên hoa hay loài.
Để làm điều đó, bạn sẽ chỉ chọn cột class và thay thế mỗi trong ba giá trị số bằng loài tương ứng. Bạn sẽ dùng inplace=True để sửa đổi trực tiếp khung dữ liệu dataset.
dataset['species'].replace(0, 'Iris-setosa',inplace=True)
dataset['species'].replace(1, 'Iris-versicolor',inplace=True)
dataset['species'].replace(2, 'Iris-virginica',inplace=True)
Hãy in 5 hàng đầu của dataset để xem trông thế nào!
dataset.head(5)
| sepal-length | sepal-width | petal-length | petal-width | species | |
|---|---|---|---|---|---|
| 0 | 5.1 | 3.5 | 1.4 | 0.2 | Iris-setosa |
| 1 | 4.9 | 3.0 | 1.4 | 0.2 | Iris-setosa |
| 2 | 4.7 | 3.2 | 1.3 | 0.2 | Iris-setosa |
| 3 | 4.6 | 3.1 | 1.5 | 0.2 | Iris-setosa |
| 4 | 5.0 | 3.6 | 1.4 | 0.2 | Iris-setosa |
Phân tích dữ liệu của bạn
Hãy nhanh chóng xem ba loài hoa trông như thế nào khi trực quan hóa và chúng khác nhau ra sao — không chỉ về con số mà cả “ngoài đời”!
(Nguồn)Hãy trực quan hóa dữ liệu bạn đã nạp ở trên bằng scatterplot để xem một biến bị ảnh hưởng bởi biến kia như thế nào, hay nói cách khác là mức độ tương quan giữa hai biến.
Bạn sẽ dùng thư viện matplotlib để trực quan hóa dữ liệu bằng biểu đồ phân tán.
import matplotlib.pyplot as plt
Mẹo: Bạn muốn học các cách khác nhau để trực quan hóa dữ liệu trong Python? Hãy xem khóa Giới thiệu trực quan hóa dữ liệu với matplotlib.
plt.figure(4, figsize=(10, 8))
plt.scatter(data[:50, 0], data[:50, 1], c='r', label='Iris-setosa')
plt.scatter(data[50:100, 0], data[50:100, 1], c='g',label='Iris-versicolor')
plt.scatter(data[100:, 0], data[100:, 1], c='b',label='Iris-virginica')
plt.xlabel('Sepal length',fontsize=20)
plt.ylabel('Sepal width',fontsize=20)
plt.xticks(fontsize=20)
plt.yticks(fontsize=20)
plt.title('Sepal length vs. Sepal width',fontsize=20)
plt.legend(prop={'size': 18})
plt.show()

Từ biểu đồ trên, có thể thấy rõ có tương quan cao giữa các hoa Iris setosa xét theo chiều dài và chiều rộng đài hoa. Ngược lại, tương quan giữa Iris versicolor và Iris virginica thấp hơn. Các điểm dữ liệu của versicolor & virginica phân tán hơn so với setosa vốn dày đặc.
Hãy nhanh chóng vẽ thêm biểu đồ cho petal-length và petal-width.
plt.figure(4, figsize=(8, 8))
plt.scatter(data[:50, 2], data[:50, 3], c='r', label='Iris-setosa')
plt.scatter(data[50:100, 2], data[50:100, 3], c='g',label='Iris-versicolor')
plt.scatter(data[100:, 2], data[100:, 3], c='b',label='Iris-virginica')
plt.xlabel('Petal length',fontsize=15)
plt.ylabel('Petal width',fontsize=15)
plt.xticks(fontsize=15)
plt.yticks(fontsize=15)
plt.title('Petal length vs. Petal width',fontsize=15)
plt.legend(prop={'size': 20})
plt.show()

Ngay cả với petal-length và petal-width, biểu đồ trên cũng cho thấy tương quan mạnh đối với hoa setosa vốn cụm lại dày đặc.
Tiếp theo, để củng cố nhận định về mức độ tương quan giữa petal-length và petal-width, hãy vẽ ma trận tương quan cho cả ba loài.
dataset.iloc[:,2:].corr()
| petal-length | petal-width | |
|---|---|---|
| petal-length | 1.000000 | 0.962865 |
| petal-width | 0.962865 | 1.000000 |
Bảng trên cho thấy tương quan mạnh ở mức 0.96 giữa petal-length và petal-width khi gộp cả ba loài.
Hãy phân tích tương quan giữa ba loài riêng rẽ.
dataset.iloc[:50,:].corr() #setosa
| sepal-length | sepal-width | petal-length | petal-width | |
|---|---|---|---|---|
| sepal-length | 1.000000 | 0.742547 | 0.267176 | 0.278098 |
| sepal-width | 0.742547 | 1.000000 | 0.177700 | 0.232752 |
| petal-length | 0.267176 | 0.177700 | 1.000000 | 0.331630 |
| petal-width | 0.278098 | 0.232752 | 0.331630 | 1.000000 |
dataset.iloc[50:100,:].corr() #versicolor
| sepal-length | sepal-width | petal-length | petal-width | |
|---|---|---|---|---|
| sepal-length | 1.000000 | 0.525911 | 0.754049 | 0.546461 |
| sepal-width | 0.525911 | 1.000000 | 0.560522 | 0.663999 |
| petal-length | 0.754049 | 0.560522 | 1.000000 | 0.786668 |
| petal-width | 0.546461 | 0.663999 | 0.786668 | 1.000000 |
dataset.iloc[100:,:].corr() #virginica
| sepal-length | sepal-width | petal-length | petal-width | |
|---|---|---|---|---|
| sepal-length | 1.000000 | 0.457228 | 0.864225 | 0.281108 |
| sepal-width | 0.457228 | 1.000000 | 0.401045 | 0.537728 |
| petal-length | 0.864225 | 0.401045 | 1.000000 | 0.322108 |
| petal-width | 0.281108 | 0.537728 | 0.322108 | 1.000000 |
Từ ba bảng trên, có thể thấy rõ tương quan giữa petal-length và petal-width của setosa và virginica lần lượt là 0.33 và 0.32. Trong khi đó, với versicolor là 0.78.
Tiếp theo, hãy trực quan hóa phân phối đặc trưng bằng cách vẽ các biểu đồ histogram:
fig = plt.figure(figsize = (8,8))
ax = fig.gca()
dataset.hist(ax=ax)
plt.show()

petal-length, petal-width và sepal-length cho thấy phân phối đơn đỉnh, trong khi sepal-width có kiểu phân phối gần Gaussian. Tất cả phân tích này đều hữu ích vì từ đó bạn có thể cân nhắc dùng thuật toán phù hợp với loại phân phối này.
Tiếp theo, bạn sẽ phân tích xem bốn thuộc tính có cùng thang đo hay không; đây là khía cạnh quan trọng trong ML. Khung dữ liệu pandas có hàm dựng sẵn describe cung cấp count, mean, max, min của dữ liệu theo dạng bảng.
dataset.describe()
| sepal-length | sepal-width | petal-length | petal-width | |
|---|---|---|---|---|
| count | 150.000000 | 150.000000 | 150.000000 | 150.000000 |
| mean | 5.843333 | 3.057333 | 3.758000 | 1.199333 |
| std | 0.828066 | 0.435866 | 1.765298 | 0.762238 |
| min | 4.300000 | 2.000000 | 1.000000 | 0.100000 |
| 25% | 5.100000 | 2.800000 | 1.600000 | 0.300000 |
| 50% | 5.800000 | 3.000000 | 4.350000 | 1.300000 |
| 75% | 6.400000 | 3.300000 | 5.100000 | 1.800000 |
| max | 7.900000 | 4.400000 | 6.900000 | 2.500000 |
Bạn có thể thấy cả bốn thuộc tính đều có thang đo tương tự giữa 0 & 8 và tính theo đơn vị cm; nếu muốn bạn có thể chuẩn hóa thêm về khoảng 0 đến 1.
Mặc dù chúng ta biết mỗi lớp có 50 mẫu, tức ~33,3% của toàn bộ phân phối, nhưng hãy kiểm tra lại!
print(dataset.groupby('species').size())
species
Iris-setosa 50
Iris-versicolor 50
Iris-virginica 50
dtype: int64
Tiền xử lý dữ liệu
Sau khi nạp và phân tích dữ liệu kỹ lưỡng, đã đến lúc chuẩn bị dữ liệu để đưa vào mô hình ML. Trong phần này, bạn sẽ tiền xử lý dữ liệu theo hai cách: chuẩn hóa dữ liệu và chia dữ liệu thành tập huấn luyện và kiểm tra.
Chuẩn hóa dữ liệu
Có hai cách để bạn chuẩn hóa dữ liệu:
- Chuẩn hóa theo mẫu trong đó bạn chuẩn hóa từng mẫu riêng lẻ,
- Chuẩn hóa theo đặc trưng trong đó bạn chuẩn hóa mỗi đặc trưng theo cùng một cách trên tất cả các mẫu.
Vì sao hoặc khi nào bạn cần chuẩn hóa dữ liệu? Và bạn có cần chuẩn hóa dữ liệu Iris không?
Câu trả lời là hầu như luôn luôn. Chuẩn hóa dữ liệu là một thực hành tốt vì nó đưa tất cả mẫu về cùng thang đo và phạm vi. Chuẩn hóa đặc biệt quan trọng khi dữ liệu của bạn không nhất quán. Bạn có thể kiểm tra sự không nhất quán bằng hàm describe() như đã học ở trên — hàm này cho bạn giá trị max và min. Nếu giá trị max và min của một đặc trưng lớn hơn đáng kể so với đặc trưng khác thì việc đưa cả hai về cùng thang đo là rất quan trọng.
Giả sử X là một đặc trưng có phạm vi lớn và Y là đặc trưng thứ hai có phạm vi nhỏ. Khi đó, ảnh hưởng của Y có thể bị lấn át bởi ảnh hưởng của X. Trong trường hợp đó, việc chuẩn hóa cả X và Y trở nên quan trọng.
Với dữ liệu Iris, không cần chuẩn hóa.
Hãy in lại kết quả describe() để xem vì sao bạn không cần chuẩn hóa.
dataset.describe()
| sepal-length | sepal-width | petal-length | petal-width | |
|---|---|---|---|---|
| count | 150.000000 | 150.000000 | 150.000000 | 150.000000 |
| mean | 5.843333 | 3.057333 | 3.758000 | 1.199333 |
| std | 0.828066 | 0.435866 | 1.765298 | 0.762238 |
| min | 4.300000 | 2.000000 | 1.000000 | 0.100000 |
| 25% | 5.100000 | 2.800000 | 1.600000 | 0.300000 |
| 50% | 5.800000 | 3.000000 | 4.350000 | 1.300000 |
| 75% | 6.400000 | 3.300000 | 5.100000 | 1.800000 |
| max | 7.900000 | 4.400000 | 6.900000 | 2.500000 |
Thuộc tính sepal-length có giá trị từ 4,3 đến 7,9; sepal-width có giá trị từ 2 đến 4,4; petal-length từ 1 đến 6,9; và petal-width từ 0,1 đến 2,5. Giá trị của tất cả đặc trưng nằm trong khoảng 0,1 đến 7,9 — có thể coi là chấp nhận được. Do đó, bạn không cần áp dụng chuẩn hóa cho bộ dữ liệu Iris.
Chia dữ liệu
Đây là một khía cạnh quan trọng khác của machine learning vì mục tiêu của bạn là tạo ra một mô hình đủ khả năng đưa ra quyết định hoặc phân loại dữ liệu trong môi trường kiểm tra mà không cần can thiệp của con người. Do vậy, trước khi triển khai mô hình ML trong thực tế, bạn cần đảm bảo mô hình có thể khái quát hóa tốt trên dữ liệu kiểm tra.
Với dữ liệu Iris, bạn có 150 mẫu; bạn sẽ huấn luyện mô hình ML trên 80% dữ liệu và 20% còn lại dùng để kiểm tra.
Trong khoa học dữ liệu, bạn sẽ thường gặp thuật ngữ Overfitting (quá khớp), nghĩa là mô hình học rất tốt dữ liệu huấn luyện nhưng không hoạt động tốt trên dữ liệu kiểm tra. Vì vậy, việc chia dữ liệu thành tập huấn luyện và kiểm tra hay xác thực sẽ giúp bạn biết mô hình có bị quá khớp hay không.
Để chia tập huấn luyện và kiểm tra, bạn sẽ dùng thư viện sklearn với hàm tách dựng sẵn train_test_split. Hãy chia dữ liệu.
from sklearn.model_selection import train_test_split
train_data, test_data, train_label, test_label = train_test_split(dataset.iloc[:,:3], dataset.iloc[:,3], test_size=0.2, random_state=42)
Lưu ý random_state là hạt giống ngẫu nhiên; nếu bạn thay đổi số này thì cách chia dữ liệu cũng thay đổi. Tuy nhiên, nếu giữ nguyên random_state và chạy lại nhiều lần thì kết quả chia dữ liệu vẫn không đổi.
Hãy in nhanh kích thước dữ liệu huấn luyện và kiểm tra cùng với nhãn của chúng.
train_data.shape,train_label.shape,test_data.shape,test_label.shape
((120, 3), (120,), (30, 3), (30,))
Cuối cùng, đã đến lúc đưa dữ liệu vào thuật toán k-láng giềng gần nhất!
Mô hình KNN
Sau khi nạp, phân tích và tiền xử lý dữ liệu, giờ là lúc bạn đưa dữ liệu vào mô hình KNN. Để làm vậy, bạn sẽ dùng hàm dựng sẵn neighbors của sklearn với lớp KNeigborsClassifier.
Hãy bắt đầu bằng cách import bộ phân loại.
from sklearn.neighbors import KNeighborsClassifier
Lưu ý: tham số k (n_neighbors) thường là số lẻ để tránh hòa khi bỏ phiếu.
Để quyết định giá trị tốt nhất cho siêu tham số k, bạn sẽ thực hiện grid-search. Bạn sẽ huấn luyện và kiểm tra mô hình trên 10 giá trị k khác nhau và cuối cùng dùng giá trị cho kết quả tốt nhất.
Hãy khởi tạo biến neighbors(k) với các giá trị từ 1–9 và hai ma trận zero của numpy là train_accuracy và test_accuracy tương ứng cho độ chính xác huấn luyện và kiểm tra. Bạn sẽ cần chúng sau để vẽ đồ thị chọn giá trị neighbor tốt nhất.
neighbors = np.arange(1,9)
train_accuracy =np.zeros(len(neighbors))
test_accuracy = np.zeros(len(neighbors))
Đoạn mã tiếp theo là nơi “phép màu” diễn ra. Bạn sẽ enumerate qua cả chín giá trị láng giềng và với mỗi giá trị, bạn dự đoán trên cả dữ liệu huấn luyện và kiểm tra. Cuối cùng, lưu độ chính xác vào các mảng numpy train_accuracy và test_accuracy.
for i,k in enumerate(neighbors):
knn = KNeighborsClassifier(n_neighbors=k)
#Fit the model
knn.fit(train_data, train_label)
#Compute accuracy on the training set
train_accuracy[i] = knn.score(train_data, train_label)
#Compute accuracy on the test set
test_accuracy[i] = knn.score(test_data, test_label)
Tiếp theo, bạn sẽ vẽ độ chính xác huấn luyện và kiểm tra bằng matplotlib. Với đồ thị accuracy vs. varying number of neighbors, bạn sẽ chọn được giá trị k mà tại đó mô hình hoạt động tốt nhất.
plt.figure(figsize=(10,6))
plt.title('KNN accuracy with varying number of neighbors',fontsize=20)
plt.plot(neighbors, test_accuracy, label='Testing Accuracy')
plt.plot(neighbors, train_accuracy, label='Training accuracy')
plt.legend(prop={'size': 20})
plt.xlabel('Number of neighbors',fontsize=20)
plt.ylabel('Accuracy',fontsize=20)
plt.xticks(fontsize=20)
plt.yticks(fontsize=20)
plt.show()

Nhìn vào đồ thị trên, có vẻ khi n_neighbors=3, cả hai độ chính xác của mô hình đều tốt nhất. Hãy giữ n_neighbors=3 và huấn luyện lại một lần nữa.
knn = KNeighborsClassifier(n_neighbors=3)
#Fit the model
knn.fit(train_data, train_label)
#Compute accuracy on the training set
train_accuracy = knn.score(train_data, train_label)
#Compute accuracy on the test set
test_accuracy = knn.score(test_data, test_label)
Đánh giá mô hình
Ở phần cuối của hướng dẫn này, bạn sẽ đánh giá mô hình trên dữ liệu kiểm tra bằng một vài kỹ thuật như confusion_matrix và classification_report.
Trước tiên, hãy kiểm tra độ chính xác của mô hình trên dữ liệu kiểm tra.
test_accuracy
0.9666666666666667
Tuyệt vời! Có vẻ mô hình phân loại đúng 96,66% dữ liệu kiểm tra. Thật ấn tượng phải không? Chỉ với vài dòng mã, bạn đã huấn luyện được một mô hình ML có thể cho biết tên loài hoa chỉ bằng bốn đặc trưng với độ chính xác 96,66%. Biết đâu nó còn làm tốt hơn cả con người.
Ma trận nhầm lẫn
Ma trận nhầm lẫn chủ yếu dùng để mô tả hiệu năng mô hình trên dữ liệu kiểm tra mà ở đó các giá trị hoặc nhãn thực tế đã biết.
Scikit-learn cung cấp một hàm tính ma trận nhầm lẫn cho bạn.
prediction = knn.predict(test_data)
Hàm plot_confusion_matrix() dưới đây đã được chỉnh sửa và tham khảo từ nguồn này.
import itertools
def plot_confusion_matrix(cm, classes,
normalize=False,
title='Confusion matrix',
cmap=plt.cm.Blues):
plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title)
plt.colorbar()
tick_marks = np.arange(len(classes))
plt.xticks(tick_marks, classes, rotation=45)
plt.yticks(tick_marks, classes)
fmt = '.2f' if normalize else 'd'
thresh = cm.max() / 2.
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
plt.text(j, i, format(cm[i, j], fmt),
horizontalalignment="center",
color="white" if cm[i, j] > thresh else "black")
plt.ylabel('True label',fontsize=30)
plt.xlabel('Predicted label',fontsize=30)
plt.tight_layout()
plt.xticks(fontsize=18)
plt.yticks(fontsize=18)
class_names = load_iris().target_names
# Compute confusion matrix
cnf_matrix = confusion_matrix(test_label, prediction)
np.set_printoptions(precision=2)
# Plot non-normalized confusion matrix
plt.figure(figsize=(10,8))
plot_confusion_matrix(cnf_matrix, classes=class_names)
plt.title('Confusion Matrix',fontsize=30)
plt.show()

Từ biểu đồ confusion_matrix trên, bạn có thể thấy mô hình phân loại đúng tất cả các hoa ngoại trừ một bông virginica bị phân loại thành versicolor.
Báo cáo phân loại
Báo cáo phân loại giúp bạn xác định các lớp bị phân loại sai chi tiết hơn bằng cách cung cấp precision, recall và F1 score cho từng lớp. Bạn sẽ dùng thư viện sklearn để hiển thị báo cáo phân loại.
from sklearn.metrics import classification_report
print(classification_report(test_label, prediction))
precision recall f1-score support
Iris-setosa 1.00 1.00 1.00 10
Iris-versicolor 0.90 1.00 0.95 9
Iris-virginica 1.00 0.91 0.95 11
micro avg 0.97 0.97 0.97 30
macro avg 0.97 0.97 0.97 30
weighted avg 0.97 0.97 0.97 30
Đi xa hơn!
Trước hết, xin chúc mừng tất cả những ai đã đi đến cuối! Nhưng đây mới chỉ là khởi đầu. Vẫn còn chặng đường dài phía trước!
Hướng dẫn này chủ yếu đề cập đến những điều cơ bản của machine learning và triển khai một loại thuật toán ML gọi là KNN với Python. Bộ dữ liệu Iris mà bạn dùng khá nhỏ và tương đối đơn giản.
Nếu hướng dẫn này khơi gợi hứng thú muốn học thêm, bạn có thể thử dùng các bộ dữ liệu khác hoặc tìm hiểu thêm về một số thuật toán ML khác và có thể áp dụng lên bộ dữ liệu Iris để quan sát tác động đến độ chính xác. Cách này giúp bạn học được nhiều hơn là chỉ hiểu lý thuyết!
Nếu bạn đã thử nghiệm đủ với các kiến thức cơ bản trong hướng dẫn này và các thuật toán machine learning khác, bạn có thể muốn đi sâu hơn vào Python và phân tích dữ liệu.