Nội dung bài viết

KNN
1. Bài toán: Phân loại đánh giá phim
1.1. Câu FNE1KNN01
1.2. Câu FNE1KNN02
1.3. Câu FNE1KNN03
2. Bài toán: Breast Cancer Wisconsin Diagnostic - Tập Dữ Liệu Chẩn Đoán Ung Thư Vú
2.1. Câu FNE1KNN05
2.2. Câu FNE1KNN06
2.3. Câu FNE1KNN07
2.4. Câu FNE1KNN09
KMean
3. Phân cụm đánh giá phim
3.1. Bộ dữ liệu text ban đầu - corpus
3.2. Vectorization
3.3. Khởi tạo tâm cụm
3.4. Câu FNE1KM01
3.5. Câu FNE1KM02
3.6. Câu FNE1KM03
3.7. Câu FNE1KM04
3.8. Câu FNE1KM05
4. Tập Dữ Liệu Chẩn Đoán Ung Thư Vú
4.1. Mô Tả Dữ Liệu
4.2. Chọn hai tâm cụm
4.3. Câu FNE1KM06
4.4. Câu FNE1KM07
4.5. Câu FNE1KM08
4.6. Câu FNE1KM09
4.7. Câu FNE1KM10
Decision Tree
5. Tập Dữ Liệu Dự Đoán Quyết Định Chơi Tennis
5.1. Bộ dữ liệu để xây dựng cây quyết định:
5.2. Bộ dữ liệu kiểm tra:
5.3. Tách dữ liệu thành 2 phần
5.4. Các bước xây dựng cây quyết định (sử dụng Entropy)
5.5. Câu FNE1DT01
5.6. Câu FNE1DT02
5.7. Câu FNE1DT03
5.8. Câu FNE1DT04
5.9. Câu FNE1DT05
5.10. Câu FNE1DT06
5.11. Câu FNE1DT07
5.12. Câu FNE1DT08
5.13. Câu FNE1DT09
5.14. Câu FNE1DT10
Random Forest
6. Dự đoán chất lượng rượu
6.1. Câu FNE1RF04
6.2. Câu FNE1RF05
6.3. Câu FNE1RF06
6.4. Câu FNE1RF07
Adaboost Boost và Gradient Boost
Dự đoán chất lượng rượu
7. Các yêu cầu cần thực hiện:
7.1. Câu FNE1XAG01
7.2. Câu FNE1XAG02
7.3. Câu FNE1XAG03
7.4. Câu FNE1XAG04
7.4.1. Important Features AdaBoost
7.4.2. Important Features Gradient Boosting
7.5. Câu FNE1XAG05
7.6. Câu FNE1XAG06
7.7. Câu FNE1XAG07
7.8. Câu FNE1XAG08

© 2025 AI VIET NAM. All rights reserved.

Bài thi cuối khóa AIO2024 - Phần 1 (Machine Learning)

Tác giả: Nhóm ra đề (AIO2024)

Keywords: kiểm tra năng lực machine learning, học machine learning online, khóa học ai

KNN

Bài toán: Phân loại đánh giá phim

Trong phần này, chúng ta sẽ xử lý một tập hợp các câu đánh giá phim và chuyển đổi nó thành định dạng vector bằng CountVectorizer. Sự chuyển đổi này rất cần thiết để chuẩn bị dữ liệu văn bản cho các mô hình Machine Learning. Sau đây là quy trình từng bước chuyển đổi:

Bộ dữ liệu text-corpus
Chúng ta bắt đầu với một bộ data nhỏ các câu đánh giá phim, mà chúng ta gọi là corpus. Corpus chứa 6 câu đánh giá khác nhau:

import sklearn
from sklearn.neighbors import KNeighborsClassifier
from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
import pandas as pd

corpus = ["ai is powerful and useful",
          "smart and adaptive system",
          "very smart and useful",
          "learning AI is very hard",
          "ai can be biased",
          "biased and flawed"]
Các văn bảnNhãn
ai is powerful and useful1
smart and adaptive system1
very smart and useful1
learning AI is very hard0
ai can be biased0
biased and flawed0
Bảng 1: Danh sách văn bản và nhãn của chúng

Tạo đặc trưng

corpus = ["ai is powerful and useful",
          "smart and adaptive system",
          "very smart and useful",
          "learning AI is very hard",
          "ai can be biased",
          "biased and flawed"]

Vectorization

Chúng ta sử dụng CountVectorizer để chuyển đổi dữ liệu văn bản thành một ma trận, trong đó mỗi cột tương ứng với một từ trong bộ từ vựng và mỗi hàng đại diện cho một văn bản. Mỗi giá trị trong ma trận thể hiện số lần từ đó xuất hiện trong văn bản tương ứng.

Ví dụ: Câu đầu tiên là: "ai is powerful and useful" được thể hiện bằng vector [0 1 1 0 0 0 0 0 1 0 1 0 0 1 0] tức là đối với câu thứ nhất, có 1 từ ở index 1, 2, 8, 10, 13 trong bộ từ vựng vocab.

vectorizer = CountVectorizer()
X = vectorizer.fit_transform(corpus)
y_data = np.array([1, 1, 1, 0, 0, 0])

Câu FNE1KNN01

Biết bộ từ điển được sắp xếp theo thứ tự như sau:

adaptiveaiandbebiasedcanflawedhardislearningpowerfulsmartsystemusefulvery

Vector đặc trưng khi nhận đầu vào là "ai is a smart system" là?

  • A. [0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0]
  • B. [0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
  • C. [0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0]
  • D. [0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0]
new_sentence = ["ai is a smart system"]
new_sentence_vector = vectorizer.transform(new_sentence).toarray()
print(new_sentence_vector)

Câu FNE1KNN02

Hãy tính khoảng cách Euclid giữa câu "ai is a smart system" (bạn vừa thực hiện ở câu trước) và câu "learning AI is very hard" trong tập văn bản đã được biến đổi thành ma trận đặc trưng. Khoảng cách Euclid giữa hai câu này bằng ? (kết quả làm tròn đến 2 chữ số sau dấu phẩy).

  • A. 2.65
  • B. 2.45
  • C. 2.24
  • D. 2
def euclid_distance(x1, x2):
    return np.sqrt(np.sum((x1 - x2) ** 2))

distance = euclid_distance(X[3].toarray(), new_sentence_vector)
print(distance)

Câu FNE1KNN03

Top 3 câu có khoảng cách gần nhất với câu "ai is a smart system" là ?

  • A. "ai is powerful and useful", "smart and adaptive system", "ai can be biased"
  • B. "biased and flawed", "ai can be biased", "very smart and useful"
  • C. "smart and adaptive system", "ai is powerful and useful", "learning AI is very hard"
  • D. "biased and flawed", "smart and adaptive system", "ai is powerful and useful"
distances = []
for i in range(X.shape[0]):
    distance = euclid_distance(new_sentence_vector, X[i].toarray())
    distances.append((distance, i))

distances.sort()
top_3 = distances[:3]
for dist, idx in top_3:
    print(f"Index: {idx} - {corpus[idx]}; Distance: {dist}")

Bài toán: Breast Cancer Wisconsin Diagnostic - Tập Dữ Liệu Chẩn Đoán Ung Thư Vú

Tập dữ liệu này chứa thông tin về các đặc trưng liên quan đến khối u ung thư vú, cùng với chẩn đoán của chúng. (Đây là dữ liệu đã được cắt vớt và chuẩn hóa)

Mô Tả Dữ Liệu

Chỉ sốperimeter_meanarea_meancompactness_meandiagnosis
00.290.180.12B
10.110.060.17B
20.340.210.20B
30.260.150.09B
40.220.090.20B
50.580.420.47M
60.560.370.77M
70.480.380.28M
80.630.490.39M
90.540.420.43M

Các Đặc Trưng

  • perimeter_mean: Trung bình chu vi của các khối u.
  • area_mean: Trung bình diện tích của các khối u.
  • compactness_mean: Trung bình tính chất đặc của các khối u, được tính bằng (chu vi² / diện tích - 1.0).
  • diagnosis: Nhãn lớp cho biết chẩn đoán của khối u, trong đó ‘B’ đại diện cho lành tính và ‘M’ đại diện cho ác tính.
!gdown 1dLF8lffQLgBO5Thu__Lk5Pbw57fTkncc
df = pd.read_csv('/content/final_dataset.csv')
X_train = df[["perimeter_mean", "area_mean", "compactness_mean"]].values.tolist()
labels = df['diagnosis'].values.tolist()

Câu FNE1KNN05

Đoạn mã bên dưới chuyển đổi lớp 'B' và lớp 'M' lần lượt thành?

y_train = []

for label in labels:
    if label == 'B':
        y_train.append(0)
    else:
        y_train.append(1)

print(type(y_train))
y_train
  • A. Lớp ‘B’ = 1 và Lớp ‘M’ = 0
  • B. Lớp ‘B’ = 0 và Lớp ‘M’ = 1
  • C. Lớp ‘B’ = [0, 0, 0, 0, 0] và Lớp ‘M’ = [1, 1, 1, 1, 1]
  • D. Lớp ‘B’ = [1, 1, 1, 1, 1] và Lớp ‘M’ = [0, 0, 0, 0, 0]

Câu FNE1KNN06

Kết quả của mã nguồn bên dưới được hiểu như thế nào?

train_data = zip(X_train, y_train)
train_data = list(train_data)
train_data
================ Output ================
[
 ([0.29, 0.18, 0.12], 0),
 ([0.11, 0.06, 0.17], 0),
 ([0.34, 0.21, 0.2], 0),
 ([0.26, 0.15, 0.09], 0),
 ([0.22, 0.09, 0.2], 0),
 ([0.58, 0.42, 0.47], 1),
 ([0.56, 0.37, 0.77], 1),
 ([0.48, 0.38, 0.28], 1),
 ([0.63, 0.49, 0.39], 1),
 ([0.54, 0.42, 0.43], 1)
]
====================================
  • A. (Khoảng cách, Lớp)
  • B. (Lớp, Khoảng cách)
  • C. ([perimeter_mean, area_mean, compactness_mean], Lớp)
  • D. (Lớp, [perimeter_mean, area_mean, compactness_mean])

Câu FNE1KNN07

Cho input x = [0.25, 0.25, 0.25]. Tính khoảng cách Manhattan từ x tới 3 điểm dữ liệu đầu tiên (3 dòng đầu trong bộ dữ liệu train) là?

  • A. 0.1, 0.1, 0.1
  • B. 0.24, 0.41, 0.18
  • C. 0.18, 0.24, 0.33
  • D. 0.24, 0.18, 0.56
def manhattan_distance(x1, x2):
    return np.sum(np.abs(x1 - x2))

x = np.array([0.25, 0.25, 0.25])
manhattan_distances = []
for i in range(3):
    manhattan_distances.append(manhattan_distance(x, np.array(train_data[i][0])))

for d in manhattan_distances:
    print(np.round(d, 2), end=' ')

Câu FNE1KNN09

Sắp xếp theo thứ tự tăng dần khoảng cách, nếu K=7, có tổng cộng bao nhiêu Class 0 và 1?

  • A. Class 0: 2 và Class 1: 5
  • B. Class 0: 3 và Class 1: 4
  • C. Class 0: 4 và Class 1: 3
  • D. Class 0: 5 và Class 1: 2
x = np.array([0.25, 0.25, 0.25])

manhattan_distances = []
for i in range(len(train_data)):
    manhattan_distances.append((manhattan_distance(x, np.array(train_data[i][0])), i))

manhattan_distances.sort()
top_7 = manhattan_distances[:7]

for dist, idx in sorted(top_7):
    print(f"Index: {idx} - {train_data[idx][0]}; Distance: {np.round(dist, 2)}; label: {train_data[idx][1]}")

KMean

Phân cụm đánh giá phim

Trong phần này, chúng ta sẽ xử lý một tập hợp các câu đánh giá phim và chuyển đổi nó thành định dạng vector bằng CountVectorizer. Sự chuyển đổi này rất cần thiết để chuẩn bị dữ liệu văn bản cho các mô hình Machine Learning. Sau đây là quy trình từng bước chuyển đổi:

Bộ dữ liệu text ban đầu - corpus

Chúng ta bắt đầu với một bộ data nhỏ các câu đánh giá phim, mà chúng ta gọi là corpus. Corpus chứa 6 câu đánh giá khác nhau:

from sklearn.feature_extraction.text import CountVectorizer
import numpy as np

corpus = ["ai is powerful and useful",
          "smart and adaptive system",
          "very smart and useful",
          "learning AI is very hard",
          "ai can be biased",
          "biased and flawed"]

vectorizer = CountVectorizer()

Vectorization

Chúng ta sử dụng CountVectorizer để chuyển đổi dữ liệu văn bản thành một ma trận, trong đó mỗi cột tương ứng với một từ trong bộ từ vựng và mỗi hàng đại diện cho một văn bản. Mỗi giá trị trong ma trận thể hiện số lần từ đó xuất hiện trong văn bản tương ứng. Ví dụ: Câu đầu tiên là: "ai is powerful and useful" được thể hiện bằng vector [0 1 1 0 0 0 0 0 1 0 1 0 0 1 0], tức là đối với câu thứ nhất, có 1 từ ở index 1, 2, 8, 10, 13 trong bộ từ vựng (vocab).

X = vectorizer.fit_transform(corpus)
print("================== Output =================")
display(f"Bộ từ vựng xây dựng từ corpus: {dict(sorted(vectorizer.vocabulary_.items()))}")
print("===========================================")
WordIndex
adaptive0
ai1
and2
be3
biased4
can5
flawed6
hard7
is8
learning9
powerful10
smart11
system12
useful13
very14
X = X.toarray()
print("================== Output =================")
print("Vector đại diện cho bộ corpus sau khi vectorization:")
print(X)
print("===========================================")
[ [0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0], [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1], [0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1], [0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0] ]

Khởi tạo tâm cụm

Cho tâm cụm là 2 tâm cụm ngẫu nhiên:

  • C1: [0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0] — ai is powerful and useful
  • C2: [0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0] — ai can be biased

Câu FNE1KM01

Khoảng cách Euclidean của C1 tới các sample 1, 2, 3, 5 (làm tròn tới 3 chữ số thập phân) lần lượt là?

  • A. 2.646, 2.449, 1.712, 1.447
  • B. 2.646, 2.236, 2.449, 2.449
  • C. 2.828, 2.828, 2.646, 2.236
  • D. 2.828, 2.646, 2.236, 2.257
def euclidean_distance(x1, x2):
    return np.sqrt(np.sum(np.power(x1 - x2, 2)))

indices = [1, 2, 3, 5]
distances_C1 = [(euclidean_distance(C1, X[i]), i) for i in indices]

for dist, idx in distances_C1:
    print(f'Distance: {np.round(dist, 3)}; index: {idx}')

Câu FNE1KM02

Khoảng cách Euclidean của C2 tới các sample 1, 2, 3, 5 (làm tròn tới 3 chữ số thập phân) lần lượt là?

  • A. 2.646, 2.449, 1.712, 1.447
  • B. 2.646, 2.236, 2.449, 2.449
  • C. 2.828, 2.828, 2.646, 2.236
  • D. 2.828, 2.646, 2.236, 2.257
distances_C2 = [(euclidean_distance(C2, X[i]), i) for i in indices]

for dist, idx in distances_C2:
    print(f'Distance: {np.round(dist, 3)}; index: {idx}')

Câu FNE1KM03

Xác định các điểm dữ liệu thuộc cụm 1 và cụm 2: Vector biểu diễn phân cụm của bộ data X là?

  • A. [C1, C1, C1, C1, C2, C2]
  • B. [C1, C1, C1, C2, C1, C2]
  • C. [C1, C2, C1, C1, C1, C1]
  • D. [C1, C2, C1, C2, C2, C2]
C1 = X[0]
C2 = X[4]

indices = [1, 2, 3, 5]
distances_C1 = [euclidean_distance(C1, X[i]) for i in indices]
distances_C2 = [euclidean_distance(C2, X[i]) for i in indices]

labels = []
for d1, d2 in zip(distances_C1, distances_C2):
    labels.append('C1' if d1 < d2 else 'C2')

labels.insert(0, 'C1')
labels.insert(4, 'C2')

print(labels)

Câu FNE1KM04

Cập nhật tâm cụm: Cập nhật tọa độ của tâm cụm thứ 1 và thứ 2 dựa trên các câu được gán cho mỗi tâm cụm (Chọn đáp án gần bằng, làm tròn 1 chữ số thập phân):

  • A.

    • Cụm C1: [0.25, 0.5, 0.5, 0.0, 0.0, 0.0, 0.0, 0.75, 0.5, 0.25, 0.25, 0.5, 0.25, 0.5, 0.5]
    • Cụm C2: [0.25, 0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.25, 0.0]
  • B.

    • Cụm C1: [0.5, 0.75, 0.75, 0.0, 1.0, 0.0, 0.0, 0.5, 0.5, 0.25, 0.25, 0.5, 0.25, 0.5, 0.5]
    • Cụm C2: [0.0, 0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0]
  • C.

    • Cụm C1: [0.0, 0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    • Cụm C2: [0.25, 0.5, 0.75, 0.0, 0.0, 0.0, 0.0, 0.25, 0.5, 0.25, 0.25, 0.5, 0.25, 0.5, 0.5]
  • D.

    • Cụm C1: [0.25, 0.5, 0.75, 0.0, 0.0, 0.0, 0.0, 0.25, 0.5, 0.25, 0.25, 0.5, 0.25, 0.5, 0.5]
    • Cụm C2: [0.0, 0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
new_centroids_C1 = np.mean(X[0:4], axis=0)
new_centroids_C2 = np.mean(X[4:7], axis=0)

print(new_centroids_C1)
print(new_centroids_C2)

Câu FNE1KM05

Xác định các điểm dữ liệu thuộc cụm 1 và cụm 2 sau khi cập nhật tâm cụm (Theo vector biểu diễn)

  • A. [C1, C2, C1, C1, C2, C1]
  • B. [C2, C1, C2, C1, C1, C2]
  • C. [C1, C1, C1, C1, C1, C2]
  • D. [C1, C1, C1, C1, C2, C2]
labels = []
for d1, d2 in zip(distances_C1, distances_C2):
    labels.append('C1' if d1 < d2 else 'C2')

labels.insert(0, 'C1')
labels.insert(4, 'C2')

print(labels)

Tập Dữ Liệu Chẩn Đoán Ung Thư Vú

Tập dữ liệu này chứa thông tin về các đặc trưng liên quan đến khối u ung thư vú, cùng với chẩn đoán của chúng. (Đây là dữ liệu đã được cắt vớt và chuẩn hóa)

Mô Tả Dữ Liệu

Chỉ sốperimeter_meanarea_meancompactness_meandiagnosis
00.290.180.12B
10.110.060.17B
20.340.210.20B
30.260.150.09B
40.220.090.20B
50.580.420.47M
60.560.370.77M
70.480.380.28M
80.630.490.39M
90.540.420.43M

Chọn hai tâm cụm

C1: [0.34, 0.21, 0.2] (Index 2)
C2: [0.63, 0.49, 0.39] (Index 8)


Câu FNE1KM06

Tính tổng khoảng cách của các điểm dữ liệu tới tâm cụm thứ nhất C1: [0.34, 0.21, 0.2]

(Đáp án làm tròn tới 2 chữ số thập phân)

  • A. 2.79
  • B. 2.80
  • C. 3.74
  • D. 3.20
sum_dist = 0
for x in train_data:
    sum_dist += euclidean_distance(np.array(x), centroid_values[0])
print(np.round(sum_dist, 2))

Câu FNE1KM07

Tính tổng khoảng cách của các điểm dữ liệu tới tâm cụm thứ hai C2: [0.63, 0.49, 0.39]

(Đáp án làm tròn tới 2 chữ số thập phân)

  • A. 2.79
  • B. 2.80
  • C. 3.74
  • D. 3.20
sum_dist = 0
for x in train_data:
    sum_dist += euclidean_distance(np.array(x), centroid_values[1])
print(np.round(sum_dist, 2))

Câu FNE1KM08

Xác định các điểm dữ liệu thuộc cụm 1 và cụm 2: Vector biểu diễn phân cụm của bộ data_train là?

  • A. [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
  • B. [0, 1, 1, 0, 0, 1, 1, 0, 0, 1]
  • C. [0, 1, 1, 0, 0, 0, 1, 0, 1, 0]
  • D. [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
labels = []
distances_C1 = []
distances_C2 = []

for x in train_data:
    distances_C1.append(euclidean_distance(np.array(x), centroid_values[0]))
    distances_C2.append(euclidean_distance(np.array(x), centroid_values[1]))

for i in range(len(distances_C1)):
    labels.append('0' if distances_C1[i] < distances_C2[i] else '1')

print(labels)

Câu FNE1KM09

Cập nhật tọa độ của tâm cụm thứ 1 và thứ 2 dựa trên các điểm dữ liệu được gán cho mỗi tâm cụm trước đó

(Chọn đáp án gần bằng, làm tròn 2 chữ số thập phân)

  • A. C1: [0.56, 0.42, 0.47], C2: [0.24, 0.14, 0.16]

  • B. C1: [0.24, 0.18, 0.17], C2: [0.56, 0.44, 0.37]

  • C. C1: [0.56, 0.42, 0.27], C2: [0.28, 0.19, 0.16]

  • D. C1: [0.24, 0.14, 0.16] C2: [0.56, 0.42, 0.47]

new_centroids_C1 = np.mean(train_data[0:5], axis=0)
new_centroids_C2 = np.mean(train_data[5:10], axis=0)

print(np.round(new_centroids_C1, 2))
print(np.round(new_centroids_C2, 2))

Câu FNE1KM10

Xác định các điểm dữ liệu thuộc cụm 1 và cụm 2 sau khi cập nhật tâm cụm (Theo vector biểu diễn)

  • A. [0, 0, 0, 1, 0, 1, 0, 1, 1, 1]
  • B. [0, 1, 1, 0, 0, 1, 1, 1, 0, 1]
  • C. [0, 0, 0, 0, 0, 1, 1, 1, 1, 1]
  • D. [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
labels = []
distances_C1 = []
distances_C2 = []

for x in train_data:
    distances_C1.append(euclidean_distance(np.array(x), new_centroids_C1))
    distances_C2.append(euclidean_distance(np.array(x), new_centroids_C2))

for i in range(len(distances_C1)):
    labels.append('0' if distances_C1[i] < distances_C2[i] else '1')

print(labels)

Decision Tree

Tập Dữ Liệu Dự Đoán Quyết Định Chơi Tennis

Tập dữ liệu này chứa thông tin về các đặc trưng thời tiết liên quan đến quyết định chơi tennis (PlayTennis).
Bộ dữ liệu gồm 4 thuộc tính:

  • Outlook: trạng thái thời tiết (Sunny, Overcast, Rain)
  • Temperature: nhiệt độ (Hot, Mild, Cool)
  • Humidity: độ ẩm (High, Normal)
  • Wind: gió (Weak, Strong)
  • PlayTennis: quyết định chơi tennis (Yes, No)

Bộ dữ liệu để xây dựng cây quyết định:

OutlookTemperatureHumidityWindPlayTennis
SunnyCoolHighWeakYes
SunnyCoolHighStrongNo
OvercastMildHighWeakYes
RainHotNormalWeakYes
RainHotNormalStrongNo
OvercastHotNormalStrongYes
SunnyMildHighWeakNo
SunnyCoolNormalWeakYes
SunnyHotHighWeakNo
RainCoolNormalWeakYes

Bộ dữ liệu kiểm tra:

OutlookTemperatureHumidityWindPlayTennis
SunnyCoolNormalStrongYes
OvercastHotHighStrongYes
OvercastMildNormalWeakYes
RainCoolHighStrongNo

Tách dữ liệu thành 2 phần

  • Huấn luyện: 10 dòng đầu tiên
  • Kiểm tra: 4 dòng còn lại

Các bước xây dựng cây quyết định (sử dụng Entropy)

  1. Bắt đầu với toàn bộ tập dữ liệu
  2. Chọn thuộc tính chia nhánh tốt nhất dựa trên Entropy và Information Gain
  3. Chia dữ liệu thành các nhánh con theo giá trị thuộc tính
  4. Lặp lại đến khi:
    • Tất cả mẫu cùng lớp
    • Hết thuộc tính
    • Đạt điều kiện dừng

Câu FNE1DT01

Entropy của tập dữ liệu ban đầu là bao nhiêu (làm tròn đến 4 chữ số thập phân)?

  • A. 0.7910
  • B. 0.9710
  • C. 0.9120
  • D. 1.0000

Tập dữ liệu có 6 nhãn Yes, 4 nhãn No → Cross Entropy: H(S)=610log2610410log2410=0.9710H(S) = - \frac{6}{10} \log_2 \frac{6}{10} - \frac{4}{10} \log_2 \frac{4}{10} = 0.9710


Câu FNE1DT02

Với tập huấn luyện ban đầu, Information Gain của thuộc tính Temperature là bao nhiêu (làm tròn đến 4 chữ số thập phân)?

  • A. 0.0465
  • B. 0.0455
  • C. 0.9113
  • D. 0.9245

Các nhóm:

  • Cool (3 Yes, 1 No) → (H=0.8113)
  • Hot (2 Yes, 2 No) → (H=1.0000)
  • Mild (1 Yes, 1 No) → (H=1.0000)
IG(Temp)=0.9710[0.4×0.8113+0.4×1+0.2×1]=0.0465IG(Temp) = 0.9710 - [0.4\times0.8113 + 0.4\times1 + 0.2\times1] = 0.0465

Câu FNE1DT03

Thuộc tính nào được chọn chia nhánh đầu tiên?

  • A. Outlook
  • B. Temperature
  • C. Humidity
  • D. Wind

Tính IG:

  • (IG(Outlook)=0.2100)
  • (IG(Temperature)=0.0465)
  • (IG(Humidity)=0.1245)
  • (IG(Wind)=0.0913)

Outlook là root.


Câu FNE1DT04

Cây quyết định hoàn chỉnh sẽ có bao nhiêu lá?

  • A. 4
  • B. 5
  • C. 6
  • D. 7

Outlook là nhánh root.

  • Sunny: 2 Yes + 3 No → H(Sunny) = 0.9710
  • Overcast: 2 Yes → H(Overcast) = 0
  • Rain: 2 Yes + 1 No → H(Rain) = 0.9183

Tìm các nhánh tiếp theo của cây:

  • Temp | Sunny:
    • Mild: 1 No → H(Mild) = 0
    • Hot: 1 No → H(Hot) = 0
    • Cool: 2 Yes + 1 No → H(Cool) = 0.9183

IG(Temp)=H(Sunny)35×0.9183=0.4200IG(Temp) = H(Sunny) - \frac{3}{5} \times 0.9183 = 0.4200

  • Humidity | Sunny:
    • High: 1 Yes + 3 No → H(High) = 0.8113
    • Normal: 1 Yes → H(Normal) = 0

IG(Humidity)=H(Sunny)45×0.8113=0.3220IG(Humidity) = H(Sunny) - \frac{4}{5} \times 0.8113 = 0.3220

  • Wind | Sunny:
    • Weak: 2 Yes + 2 No → H(Weak) = 1
    • Strong: 1 Yes → H(Strong) = 0

IG(Wind)=H(Sunny)45×1=0.1710IG(Wind) = H(Sunny) - \frac{4}{5} \times 1 = 0.1710

Kết luận: Temp có IG lớn nhất → Temp là nhánh tiếp theo với thuộc tính Sunny.

H(Rain)=0.9183H(Rain) = 0.9183

  • Humidity | Rain:
    • Normal: 2 Yes + 1 No → H(Normal) = 0.9183

IG(Humidity)=H(Rain)1×0.9183=0IG(Humidity) = H(Rain) - 1 \times 0.9183 = 0

  • Wind | Rain:
    • Weak: 2 Yes → H(Weak) = 0
    • Strong: 1 No → H(Strong) = 0

IG(Wind)=H(Rain)00=0.9183IG(Wind) = H(Rain) - 0 - 0 = 0.9183

Kết luận: Wind có IG lớn nhất → Wind là nhánh tiếp theo với thuộc tính Rain.

Humidity | Cool:

  • High: → 1 Yes, 1 No → H(High) = 1.0
  • Normal: → 1 Yes, 0 No → H(Normal) = 0

IG(Humidity)=0.9183(231.0+130)=0.91830.6667=0.2516IG(Humidity) = 0.9183 - \left( \frac{2}{3} \cdot 1.0 + \frac{1}{3} \cdot 0 \right) = 0.9183 - 0.6667 = 0.2516

Wind | Cool

  • Weak: → 2 Yes, 0 No → H(Weak) = 0
  • Strong: → 0 Yes, 1 No → H(Strong) = 0

IG(Wind)=0.9183(230+130)=0.91830=0.9183IG(\text{Wind}) = 0.9183 - \left( \frac{2}{3} \cdot 0 + \frac{1}{3} \cdot 0 \right) = 0.9183 - 0 = 0.9183

Kết luận: Wind có IG lớn nhất → Wind là nhánh tiếp theo với thuộc tính Cool của Temperature.

Chi tiết các nhánh lá:

  • Outlook → Overcast → Yes
  • Outlook → Rain → Wind → Weak → Yes
  • Outlook → Rain → Wind → Strong → No
  • Outlook → Sunny → Temp → Mild → No
  • Outlook → Sunny → Temp → Hot → No
  • Outlook → Sunny → Temp → Cool → Wind → Weak → Yes
  • Outlook → Sunny → Temp → Cool → Wind → Strong → No

Câu FNE1DT05

Dùng cây quyết định đã xây dựng, dự đoán kết quả của dòng cuối cùng trong tập kiểm tra.

  • A. Strong
  • B. Cool
  • C. Yes
  • D. No

Câu FNE1DT06

Dùng cây quyết định đã xây dựng, dự đoán kết quả cho mẫu dữ liệu sau: Outlook = Overcast, Wind = Weak.

A. Yes

B. No

C. Thiếu giá trị của thuộc tính Temperature nên không dự đoán được

D. Thiếu giá trị của thuộc tính Humidity nên không dự đoán được


Câu FNE1DT07

Dùng cây quyết định đã xây dựng, dự đoán kết quả cho mẫu dữ liệu sau: Temperature = Hot, Outlook = Rain.

A. Yes

B. No

C. Thiếu giá trị của thuộc tính Wind nên không dự đoán được

D. Thiếu giá trị của thuộc tính Humidity nên không dự đoán được


Câu FNE1DT08

Độ chính xác của mô hình cây trên tập kiểm tra là bao nhiêu?**

A. 50%

B. 75%

C. 100%

D. 25%

Dựa vào cây đã được xây dựng, ta thấy 3 mẫu được dự đoán đúng nhãn và 1 mẫu sai nhãn → Độ chính xác của cây là 75%.


Câu FNE1DT09

Nếu một thuộc tính liên tục được chọn làm thuộc tính phân chia, bước tiếp theo sẽ là gì?

A. Chuyển đổi thuộc tính liên tục thành thuộc tính phân loại

B. Chọn điểm cắt để chia thuộc tính thành hai miền

C. Bỏ qua thuộc tính liên tục đó

D. Chia thuộc tính thành nhiều phân khúc dựa trên các giá trị trung bình

Thuộc tính liên tục là các thuộc tính có thể nhận giá trị trong một khoảng số thực, ví dụ như chiều cao, cân nặng, nhiệt độ,...
Khi xây dựng cây quyết định, để phân chia dữ liệu dựa trên thuộc tính liên tục, ta cần chuyển thuộc tính này thành dạng phân đoạn để tạo nhánh cây. Cách làm phổ biến là chọn một điểm cắt (threshold) để chia thuộc tính thành hai miền.
Ví dụ: Nếu thuộc tính là "tuổi", điểm cắt có thể là 30. Dữ liệu sẽ được chia thành hai nhóm: tuổi ≤ 30 và tuổi > 30. Việc chọn điểm cắt dựa trên tiêu chí tối ưu tùy theo thuật toán.


Câu FNE1DT10

Một thuộc tính có giá trị Information Gain bằng 0 cho thấy điều gì?

A. Thuộc tính không mang lại thông tin để phân biệt các lớp

B. Thuộc tính là quan trọng nhất

C. Thuộc tính này có thể loại bỏ trong quá trình huấn luyện

D. Thuộc tính gây overfitting

Information Gain đo lượng thông tin mà một thuộc tính cung cấp để phân biệt các lớp trong dữ liệu. Nếu IG = 0 nghĩa là phân chia theo thuộc tính đó không làm giảm entropy (độ hỗn loạn) của tập dữ liệu. Nói cách khác, thuộc tính đó không giúp phân biệt các lớp và không hữu ích cho mô hình phân loại.

Random Forest

Dự đoán chất lượng rượu

Trong bài toán này, chúng ta được cho dataset về các batch rượu đỏ ở Bồ Đào Nha, gồm 11 features (acidity, sugar, pH,…) và 1 label là quality (0–10).

Nhiệm vụ:

  1. Đọc dữ liệu với pandas và hiển thị DataFrame.
  2. Tách X (11 features) và y (quality).
  3. Chia train/test (80:20) với random_state=42.
  4. Sử dụng các mô hình regressor từ sklearn.

Code mẫu: Random Forest Hands-on


Câu FNE1RF04

Khi so sánh với các kỹ thuật ensemble như Gradient Boosting, một lợi thế nổi bật của Random Forest, đặc biệt khi làm việc với tập dữ liệu lớn, là gì?

A. Thời gian huấn luyện của Random Forest luôn ngắn hơn đáng kể so với Gradient Boosting.

B. Việc huấn luyện các cây trong Random Forest có thể được thực hiện song song một cách hiệu quả do tính độc lập của chúng.

C. Random Forest có độ chính xác cao hơn so với Gradient Boosting.

D. Random Forest thường ít nhạy cảm với hiện tượng overfitting hơn Gradient Boosting trong mọi trường hợp.


Câu FNE1RF05

Với n_estimators=50, random_state=42, MSE & R² trên tập test (làm tròn 4 chữ số) là?

  • A. MSE: 0.3062, R²: 0.9075
  • B. MSE: 0.0604, R²: 0.9075
  • C. MSE: 0.3062, R²: 0.5314
  • D. MSE: 0.0604, R²: 0.5314
# Đánh giá mô hình với MSE và R2
predictions = forest.predict(X_test)
print("MSE:", round(mean_squared_error(y_test, predictions), 4))
print("R2: ", round(r2_score(y_test, predictions), 4))

Câu FNE1RF06

Thử các n_estimators [10,20,50,100], cây nào cho MSE nhỏ nhất?

  • A. 10 cây
  • B. 20 cây
  • C. 50 cây
  • D. 100 cây
best_mse, best_trees = float('inf'), None
for n in [10,20,50,100]:
    model = RandomForestRegressor(n_estimators=n, random_state=42)
    model.fit(X_train, y_train)
    mse = mean_squared_error(y_test, model.predict(X_test))
    print(f"{n} trees → MSE: {mse:.4f}")
    if mse < best_mse:
        best_mse, best_trees = mse, n
print(f"Optimal: {best_trees} trees with MSE {best_mse:.4f}")

Câu FNE1RF07

Thử max_depth từ 1 đến 10 (random_state=100), độ sâu nào cho MSE nhỏ nhất?

  • A. 7
  • B. 8
  • C. 9
  • D. 10
best_mse, best_depth = float('inf'), None
for depth in range(1,11):
    model = RandomForestRegressor(n_estimators=100, max_depth=depth, random_state=100)
    model.fit(X_train, y_train)
    mse = mean_squared_error(y_test, model.predict(X_test))
    print(f"Depth {depth} → MSE: {mse:.4f}")
    if mse < best_mse:
        best_mse, best_depth = mse, depth
print(f"Optimal depth: {best_depth} with MSE {best_mse:.4f}")

Adaboost Boost và Gradient Boost

Dự đoán chất lượng rượu

Trong bài toán này, chúng ta sẽ được cho một bộ dataset mô tả thông tin về các batch của một loại rượu đỏ ở Bồ Đào Nha, bao gồm các features liên quan đến tính chất của rượu như: nồng độ acid, độ đường, độ pH,... Nhiệm vụ của chúng ta là phân tích, xử lý bộ data và trả lời các câu hỏi yêu cầu thực hiện coding. Đây là bài toán phân loại với 11 features đầu vào và 1 feature đầu ra là chất lượng của rượu (từ 0 đến 10).

Dataset: winequality-red.csv

Các yêu cầu cần thực hiện:

  1. Đọc dữ liệu

    • Sử dụng pandas để đọc file CSV và hiển thị DataFrame.
  2. Tách bộ feature (X) và label (y)

    • X: các cột "fixed acidity", "volatile acidity", "citric acid", …
    • y: cột "quality".
  3. Tách train/test

    • Tỷ lệ 80:20, random_state=42 để reproducibility.

Lưu ý: Sử dụng các mô hình regressor trong sklearn.

Code mẫu: XG Ada Gra Boost Hands-on


Câu FNE1XAG01

Yếu tố nào mô tả sự khác biệt cốt lõi trong cơ chế cải thiện mô hình giữa AdaBoost và Gradient Boosting?

A) Cả AdaBoost và Gradient Boosting đều áp dụng một phương pháp tương tự nhau để tinh chỉnh mô hình qua từng vòng lặp.
B) AdaBoost ưu tiên sử dụng các mô hình con mạnh, trong khi Gradient Boosting lại tập trung vào các mô hình con yếu.
C) AdaBoost tập trung vào việc sửa lỗi của các mẫu dữ liệu có lỗi cao nhất, còn Gradient Boosting tập trung vào giảm thiểu giá trị lỗi toàn bộ bằng cách sử dụng đạo hàm.
D) AdaBoost có khả năng chống overfitting tốt, còn Gradient Boosting thì ngược lại, rất dễ gặp phải tình trạng overfitting.


Câu FNE1XAG02

Việc gia tăng số lượng mô hình con (estimators) trong AdaBoost hoặc Gradient Boosting sẽ dẫn đến hiện tượng gì? (Gợi ý: hãy thử nghiệm bằng cách thay đổi tham số n_estimators trong code.)

A) Chất lượng của mô hình luôn được cải thiện một cách tuyến tính khi tăng số lượng mô hình con.
B) Chất lượng mô hình thường giảm khi số lượng mô hình con tăng lên.
C) Chất lượng mô hình không có sự thay đổi đáng kể nào khi điều chỉnh số lượng mô hình con.
D) Chất lượng mô hình có thể được cải thiện, tuy nhiên, việc tăng quá nhiều mô hình con có nguy cơ dẫn đến overfitting.


Câu FNE1XAG03

Trong những tình huống nào, hiện tượng overfitting có khả năng xuất hiện đối với các thuật toán AdaBoost và Gradient Boosting? (Gợi ý: hãy thử nghiệm với các kịch bản được mô tả dưới đây bằng code và đưa ra nhận định.)

A) Khi mô hình không được cung cấp đủ lượng dữ liệu cần thiết cho quá trình huấn luyện.
B) Khi số lượng mô hình con (estimators) được sử dụng là quá ít.
C) Hiện tượng overfitting không phải là một vấn đề đối với Gradient Boosting.
D) Khi sử dụng một tỷ lệ học (learning rate) quá lớn kết hợp với một số lượng mô hình con (estimators) quá nhiều.


Câu FNE1XAG04

Trong dự đoán chất lượng rượu, đặc trưng nào có importance cao nhất?

  • A) sulphates
  • B) alcohol
  • C) volatile acidity
  • D) chlorides
Important Features AdaBoost
importances = ada_regressor.feature_importances_
feature_names = X.columns
feature_importance_df = pd.DataFrame({
    'Feature': feature_names,
    'Importance': importances
}).sort_values(by='Importance', ascending=False)
print(feature_importance_df)
Important Features Gradient Boosting
importances = gb_regressor.feature_importances_
feature_names = X.columns
feature_importance_df = pd.DataFrame({
    'Feature': feature_names,
    'Importance': importances
}).sort_values(by='Importance', ascending=False)
print(feature_importance_df)

Câu FNE1XAG05

Với n_estimators=50, random_state=42, giá trị MSE & R² của AdaBoost và GB là?

  • A) R^2 thấp (0.1–0.2), MSE rất lớn.
  • B) R^2 ~0.4–0.5, MSE cao, hiệu suất kém.
  • C) R^2 ~0.7–0.8, MSE chấp nhận được.
  • D) R^2 ~0.6–0.7, MSE tương đối cao.
print("AdaBoost → MSE:", mean_squared_error(y_test, y_pred_ada))
print("AdaBoost → R2: ", r2_score(y_test, y_pred_ada))
print("GradientBoost → MSE:", mean_squared_error(y_test, y_pred_gb))
print("GradientBoost → R2: ", r2_score(y_test, y_pred_gb))

Câu FNE1XAG06

So sánh hiệu suất bốn model (n_estimators=50, random_state=42). Model nào tốt nhất?

  • A) Random Forest
  • B) XGBoost
  • C) AdaBoost
  • D) Gradient Boosting
import pandas as pd
from sklearn.ensemble import AdaBoostRegressor, GradientBoostingRegressor, RandomForestRegressor
from xgboost import XGBRegressor
from sklearn.metrics import mean_squared_error, r2_score

models = {
    'Random Forest': RandomForestRegressor(n_estimators=50, random_state=42),
    'XGBoost': XGBRegressor(n_estimators=50, random_state=42),
    'AdaBoost': AdaBoostRegressor(n_estimators=50, random_state=42),
    'Gradient Boosting': GradientBoostingRegressor(n_estimators=50, random_state=42)
}
results = {}
for name, model in models.items():
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    results[name] = {
        'R^2': r2_score(y_test, y_pred),
        'MSE': mean_squared_error(y_test, y_pred)
    }
print(pd.DataFrame(results).T)

Câu FNE1XAG07

Dùng RandomizedSearchCV tìm hyperparameters tốt nhất cho XGBoost. Kết quả nào đúng?

  • A) learning_rate=0.1, n_estimators=100, max_depth=3, subsample=0.6
  • B) learning_rate=0.1, n_estimators=100, max_depth=5, subsample=0.8
  • C) learning_rate=0.2, n_estimators=200, max_depth=7, subsample=1.0
  • D) learning_rate=0.01, n_estimators=50, max_depth=5, subsample=0.8
from sklearn.model_selection import RandomizedSearchCV
from xgboost import XGBRegressor

param_grid = {
    'n_estimators': [50, 100, 200],
    'max_depth': [3, 5, 7],
    'learning_rate': [0.01, 0.1, 0.2],
    'subsample': [0.6, 0.8, 1.0]
}
rs = RandomizedSearchCV(
    XGBRegressor(objective='reg:squarederror', random_state=42),
    param_distributions=param_grid,
    n_iter=10, cv=3, scoring='neg_mean_squared_error', random_state=42
)
rs.fit(X_train, y_train)
best_xgb = rs.best_estimator_
print('Best params:', rs.best_params_)
print('MSE:', mean_squared_error(y_test, best_xgb.predict(X_test)))
print('R2: ', r2_score(y_test, best_xgb.predict(X_test)))

Câu FNE1XAG08

Xét biến mục tiêu 'quality' (nhận các giá trị nguyên như 3, 4, 5, 6, 7, 8). Yếu tố nào sau đây giải thích chính xác nhất lý do tại sao các mô hình hồi quy (regression) cho kết quả tốt hơn so với việc sử dụng mô hình phân loại (classification) đa lớp cho đặc trưng 'quality'?

A) Các mô hình hồi quy có khả năng xử lý các đặc trưng đầu vào dạng số tốt hơn, trong khi mô hình phân loại phù hợp hơn với các đặc trưng dạng categorical đã được mã hóa.
B) Mô hình phân loại yêu cầu biến mục tiêu phải được chuẩn hóa bằng LabelEncoder về dạng 0, 1, 2,... trong khi mô hình hồi quy có thể làm việc trực tiếp với các giá trị gốc của 'quality', giúp giữ nguyên thông tin.
C) Biến 'quality' về bản chất thể hiện một thang đo có thứ tự, nơi độ lớn và khoảng cách giữa các giá trị (ví dụ, sự khác biệt giữa chất lượng 6 và 7) là thông tin quan trọng. Mô hình hồi quy có khả năng học và tận dụng mối quan hệ thứ tự này để dự đoán một giá trị liên tục (hoặc gần liên tục), trong khi mô hình phân loại thường coi mỗi mức chất lượng là một lớp riêng biệt, không có mối liên hệ về thứ tự, dẫn đến mất mát thông tin.
D) Các thuật toán hồi quy thường có ít siêu tham số cần tinh chỉnh hơn so với các thuật toán phân loại, giúp việc tìm kiếm mô hình tối ưu trở nên dễ dàng hơn.

from sklearn.preprocessing import LabelEncoder
from sklearn.ensemble import AdaBoostClassifier, GradientBoostingClassifier, RandomForestClassifier
from xgboost import XGBClassifier
from sklearn.metrics import mean_squared_error, r2_score

le = LabelEncoder()
y_enc = le.fit_transform(y)
X_tr, X_te, y_tr, y_te = train_test_split(X, y_enc, test_size=0.2, random_state=42)

models = {
    'Random Forest': RandomForestClassifier(n_estimators=50, random_state=42),
    'XGBoost': XGBClassifier(n_estimators=50, random_state=42),
    'AdaBoost': AdaBoostClassifier(n_estimators=50, random_state=42),
    'Gradient Boosting': GradientBoostingClassifier(n_estimators=50, random_state=42)
}
results = {}
for name, model in models.items():
    model.fit(X_tr, y_tr)
    y_p = model.predict(X_te)
    results[name] = {'R^2': r2_score(y_te, y_p), 'MSE': mean_squared_error(y_te, y_p)}
print(pd.DataFrame(results).T)

--- hết ----