From 195db0985b839235cdd685ca20d9ffb97f07afeb Mon Sep 17 00:00:00 2001 From: Hakula Chen Date: Tue, 30 Mar 2021 00:50:18 +0800 Subject: [PATCH 1/8] feat: _get_k_nearest_neighbors --- assignment-1/submission/18307130003/source.py | 67 +++++++++++++++++++ .../submission/18307130003/tester_demo.py | 24 +++++++ 2 files changed, 91 insertions(+) create mode 100644 assignment-1/submission/18307130003/source.py create mode 100644 assignment-1/submission/18307130003/tester_demo.py diff --git a/assignment-1/submission/18307130003/source.py b/assignment-1/submission/18307130003/source.py new file mode 100644 index 0000000..5345f68 --- /dev/null +++ b/assignment-1/submission/18307130003/source.py @@ -0,0 +1,67 @@ +from typing import List, Tuple +import numpy as np +import matplotlib.pyplot as plt +import heapq + + +class KNN: + ''' + k-Nearest Neighbors algorithm, which predicts the class of a data point + according to the most common class among its `k` nearest neighbors. + ''' + + def __init__(self) -> None: + ''' + Initialize parameters for our KNN model. + ''' + + self.k: int = 0 + self.train_data: np.ndarray = None + self.train_label: np.ndarray = None + + def _get_k_nearest_neighbors( + self, base_p: np.ndarray, data: np.ndarray + ) -> np.ndarray: + ''' + Get k nearest neighbors of `base_p` from `data`. + + :param `base_p`: the base data point + :param `data`: which dataset to use + ''' + + def _distance(p1: np.ndarray, p2: np.ndarray, mode: int = 2) -> float: + ''' + Get the distance between `p1` and `p2`. + + :param `p1`: the first data point + :param `p2`: the second data point + :param `mode`: which exponent to use when calculating distance, \ + using `2` by default for Euclidean distance + ''' + + assert p1.size == p2.size, ( + f'_distance: dimension not match for {p1.size} and {p2.size}' + ) + return np.linalg.norm(p1 - p2, ord=mode) + + heap: List[Tuple[float, np.ndarray]] = [] + p: np.ndarray + for p in data: + dist: float = _distance(base_p, p) + if (len(heap) < self.k): + heapq.heappush(heap, (-dist, p)) + else: + heapq.heappushpop(heap, (-dist, p)) + return np.array([item[1] for item in heap]) + + def fit(self, train_data: np.ndarray, train_label: np.ndarray) -> None: + self.train_data = train_data + self.train_label = train_label + self.k = 3 + + def predict(self, test_data: np.ndarray) -> np.ndarray: + result: np.ndarray = np.array([]) + p: np.ndarray + for p in test_data: + k_nearest: np.ndarray = self._get_k_nearest_neighbors(p, test_data) + print(k_nearest) diff --git a/assignment-1/submission/18307130003/tester_demo.py b/assignment-1/submission/18307130003/tester_demo.py new file mode 100644 index 0000000..6fe1511 --- /dev/null +++ b/assignment-1/submission/18307130003/tester_demo.py @@ -0,0 +1,24 @@ +import numpy as np + +from source import KNN + +train_data = np.array([ + [1, 2, 3, 4], + [4, 2, 3, 1], + [12, 12, 13, 14], + [14, 12, 13, 11], + [12, 14, 15, 16], +]) +train_label = np.array([0, 0, 1, 1, 1]) + +test_data = np.array([ + [3, 4, 4, 2], + [18, 14, 15, 16], +]) +test_label = np.array([0, 1]) + +model = KNN() +model.fit(train_data, train_label) +res = model.predict(test_data) + +print("acc =", np.mean(np.equal(res, test_label))) -- Gitee From 58f24013f951fd2d53f0f6bec669c3dc7738b567 Mon Sep 17 00:00:00 2001 From: Hakula Chen Date: Thu, 1 Apr 2021 16:10:17 +0800 Subject: [PATCH 2/8] feat: _get_most_common_label chore: fix comments and modify parameter names --- assignment-1/submission/18307130003/source.py | 71 ++++++++++++++----- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/assignment-1/submission/18307130003/source.py b/assignment-1/submission/18307130003/source.py index 5345f68..c2a6783 100644 --- a/assignment-1/submission/18307130003/source.py +++ b/assignment-1/submission/18307130003/source.py @@ -2,6 +2,12 @@ from typing import List, Tuple import numpy as np import matplotlib.pyplot as plt import heapq +from enum import Enum + + +class Dataset(Enum): + TRAIN_SET = 0 + TEST_SET = 1 class KNN: @@ -12,52 +18,81 @@ class KNN: def __init__(self) -> None: ''' - Initialize parameters for our KNN model. + Initialize our KNN model. ''' self.k: int = 0 self.train_data: np.ndarray = None self.train_label: np.ndarray = None + self.test_data: np.ndarray = None + self.test_label: np.ndarray = None def _get_k_nearest_neighbors( - self, base_p: np.ndarray, data: np.ndarray - ) -> np.ndarray: + self, base_p_i: int, dataset: Dataset = Dataset.TRAIN_SET + ) -> List[int]: ''' - Get k nearest neighbors of `base_p` from `data`. + Get k nearest neighbors of a point from dataset. Each point is + denoted by its index in dataset. - :param `base_p`: the base data point - :param `data`: which dataset to use + :param `base_p_i`: the index of base data point + :param `dataset`: which dataset to use ''' - def _distance(p1: np.ndarray, p2: np.ndarray, mode: int = 2) -> float: + if dataset == Dataset.TRAIN_SET: + data = self.train_data + else: + data = self.test_data + + def _distance(p1_i: int, p2_i: int, mode: int = 2) -> float: ''' - Get the distance between `p1` and `p2`. + Get the distance between two points. Each point is denoted by its + index in dataset. - :param `p1`: the first data point - :param `p2`: the second data point + :param `p1_i`: the index of first data point + :param `p2_i`: the index of second data point :param `mode`: which exponent to use when calculating distance, \ using `2` by default for Euclidean distance ''' + p1: np.ndarray = data[p1_i] + p2: np.ndarray = data[p2_i] assert p1.size == p2.size, ( - f'_distance: dimension not match for {p1.size} and {p2.size}' + '_distance: dimension not match for' + f'{p1.size} and {p2.size}' ) return np.linalg.norm(p1 - p2, ord=mode) heap: List[Tuple[float, np.ndarray]] = [] - p: np.ndarray - for p in data: - dist: float = _distance(base_p, p) + for p_i in range(data.size): + dist: float = _distance(base_p_i, p_i) if (len(heap) < self.k): - heapq.heappush(heap, (-dist, p)) + heapq.heappush(heap, (-dist, p_i)) else: - heapq.heappushpop(heap, (-dist, p)) - return np.array([item[1] for item in heap]) + heapq.heappushpop(heap, (-dist, p_i)) + return [item[1] for item in heap] + + def _get_most_common_label( + self, labels_i: List[int], dataset: int = Dataset.TRAIN_SET + ) -> int: + ''' + Get the most common label in given labels. Each label is denoted by + its data point's index in dataset. + + :param `labels_i`: the indices of given labels + :param `dataset`: which dataset to use + ''' + + if dataset == Dataset.TRAIN_SET: + all_labels = self.train_label + else: + all_labels = self.test_label + + labels: List[int] = [all_labels[i] for i in labels_i] + return max(set(labels), key=labels.count) def fit(self, train_data: np.ndarray, train_label: np.ndarray) -> None: self.train_data = train_data self.train_label = train_label - self.k = 3 def predict(self, test_data: np.ndarray) -> np.ndarray: result: np.ndarray = np.array([]) -- Gitee From a95ec92f09f03a2c07c0d46b5203a87263a24362 Mon Sep 17 00:00:00 2001 From: Hakula Chen Date: Thu, 1 Apr 2021 21:57:28 +0800 Subject: [PATCH 3/8] feat: fit, predict fix: change .size to .shape[0] --- assignment-1/submission/18307130003/source.py | 96 ++++++++++++++++--- 1 file changed, 81 insertions(+), 15 deletions(-) diff --git a/assignment-1/submission/18307130003/source.py b/assignment-1/submission/18307130003/source.py index c2a6783..a5e92e3 100644 --- a/assignment-1/submission/18307130003/source.py +++ b/assignment-1/submission/18307130003/source.py @@ -3,11 +3,13 @@ import numpy as np import matplotlib.pyplot as plt import heapq from enum import Enum +from math import floor class Dataset(Enum): TRAIN_SET = 0 - TEST_SET = 1 + DEV_SET = 1 + TEST_SET = 2 class KNN: @@ -24,11 +26,12 @@ class KNN: self.k: int = 0 self.train_data: np.ndarray = None self.train_label: np.ndarray = None + self.dev_data: np.ndarray = None + self.dev_label: np.ndarray = None self.test_data: np.ndarray = None - self.test_label: np.ndarray = None def _get_k_nearest_neighbors( - self, base_p_i: int, dataset: Dataset = Dataset.TRAIN_SET + self, base_p_i: int, dataset: int = Dataset.TRAIN_SET ) -> List[int]: ''' Get k nearest neighbors of a point from dataset. Each point is @@ -40,6 +43,8 @@ class KNN: if dataset == Dataset.TRAIN_SET: data = self.train_data + elif dataset == Dataset.DEV_SET: + data = self.dev_data else: data = self.test_data @@ -56,14 +61,14 @@ class KNN: p1: np.ndarray = data[p1_i] p2: np.ndarray = data[p2_i] - assert p1.size == p2.size, ( - '_distance: dimension not match for' - f'{p1.size} and {p2.size}' + assert p1.shape == p2.shape, ( + '_distance: dimensions not match for ' + f'{p1.shape} and {p2.shape}' ) return np.linalg.norm(p1 - p2, ord=mode) heap: List[Tuple[float, np.ndarray]] = [] - for p_i in range(data.size): + for p_i in range(data.shape[0]): dist: float = _distance(base_p_i, p_i) if (len(heap) < self.k): heapq.heappush(heap, (-dist, p_i)) @@ -85,18 +90,79 @@ class KNN: if dataset == Dataset.TRAIN_SET: all_labels = self.train_label else: - all_labels = self.test_label + all_labels = self.dev_label labels: List[int] = [all_labels[i] for i in labels_i] return max(set(labels), key=labels.count) def fit(self, train_data: np.ndarray, train_label: np.ndarray) -> None: - self.train_data = train_data - self.train_label = train_label + ''' + Train the model using a training set with labels. + + :param `train_data`: training set + :param `train_label`: provided labels for data in training set + ''' + + # Shuffle the dataset with labels + assert train_data.shape[0] == train_label.shape[0], ( + 'fit: data size not match for ' + f'{train_data.shape[0]} and {train_label.shape[0]}' + ) + shuffled_i = np.random.permutation(train_data.shape[0]) + shuffled_data: np.ndarray = train_data[shuffled_i] + shuffled_label: np.ndarray = train_label[shuffled_i] + + # Separate training set and development set + train_ratio: float = 0.75 + train_size: int = floor(shuffled_data.shape[0] * train_ratio) + self.train_data = shuffled_data[:train_size] + self.train_label = shuffled_label[:train_size] + self.dev_data = shuffled_data[train_size:] + self.dev_label = shuffled_label[train_size:] + + # Compare the predicted and expected results, calculate the accuracy + # for each parameter k, and find out the best k for prediction. + k_threshold: int = train_size if train_size > 20 else 20 + accuracy_table: List[float] = [0.0] + max_accuracy: float = 0.0 + + for k in range(1, k_threshold): + predicted_labels: List[int] = [] + + for p_i in range(self.dev_data.shape[0]): + k_nearest_neighbors: List[int] = self._get_k_nearest_neighbors( + p_i, Dataset.TRAIN_SET + ) + predicted_label: int = self._get_most_common_label( + k_nearest_neighbors, Dataset.TRAIN_SET + ) + predicted_labels.append(predicted_label) + + accuracy: float = np.mean( + np.equal(np.array(predicted_labels), self.dev_label) + ) + accuracy_table.append(accuracy) + print(f"k = {k}, train_acc = {accuracy * 100} %") + if accuracy > max_accuracy: + max_accuracy = accuracy + self.k = k def predict(self, test_data: np.ndarray) -> np.ndarray: - result: np.ndarray = np.array([]) - p: np.ndarray - for p in test_data: - k_nearest: np.ndarray = self._get_k_nearest_neighbors(p, test_data) - print(k_nearest) + self.test_data = test_data + + predicted_labels: List[int] = [] + + for p_i in range(self.test_data.shape[0]): + k_nearest_neighbors: List[int] = self._get_k_nearest_neighbors( + p_i, Dataset.TRAIN_SET + ) + predicted_label: int = self._get_most_common_label( + k_nearest_neighbors, Dataset.TRAIN_SET + ) + predicted_labels.append(predicted_label) + + accuracy: float = np.mean( + np.equal(np.array(predicted_labels), self.dev_label) + ) + print(f"k = {self.k}, test_acc = {accuracy * 100} %") + return predicted_labels -- Gitee From 44511c5bd5ac57acffdafd939bd4882237f22d2c Mon Sep 17 00:00:00 2001 From: Hakula Chen Date: Thu, 1 Apr 2021 22:25:11 +0800 Subject: [PATCH 4/8] fix: fixed all issues to get the program worked --- assignment-1/submission/18307130003/source.py | 77 +++++++++---------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/assignment-1/submission/18307130003/source.py b/assignment-1/submission/18307130003/source.py index a5e92e3..6f2a473 100644 --- a/assignment-1/submission/18307130003/source.py +++ b/assignment-1/submission/18307130003/source.py @@ -1,7 +1,7 @@ from typing import List, Tuple import numpy as np import matplotlib.pyplot as plt -import heapq +from heapq import heappush, heappushpop from enum import Enum from math import floor @@ -23,7 +23,7 @@ class KNN: Initialize our KNN model. ''' - self.k: int = 0 + self.k: int = 1 self.train_data: np.ndarray = None self.train_label: np.ndarray = None self.dev_data: np.ndarray = None @@ -31,49 +31,49 @@ class KNN: self.test_data: np.ndarray = None def _get_k_nearest_neighbors( - self, base_p_i: int, dataset: int = Dataset.TRAIN_SET + self, k: int, base_p: np.ndarray, dataset: int = Dataset.TRAIN_SET ) -> List[int]: ''' - Get k nearest neighbors of a point from dataset. Each point is - denoted by its index in dataset. + Get k nearest neighbors of a point from dataset. Each point (except the + base point) is denoted by its index in dataset. - :param `base_p_i`: the index of base data point + :param `base_p`: the base point :param `dataset`: which dataset to use ''' - if dataset == Dataset.TRAIN_SET: - data = self.train_data - elif dataset == Dataset.DEV_SET: - data = self.dev_data - else: - data = self.test_data - - def _distance(p1_i: int, p2_i: int, mode: int = 2) -> float: + def _distance(p1: np.ndarray, p2: np.ndarray, mode: int = 2) -> float: ''' - Get the distance between two points. Each point is denoted by its - index in dataset. + Get the distance between two points. - :param `p1_i`: the index of first data point - :param `p2_i`: the index of second data point + :param `p1`: the first point + :param `p2`: the second point :param `mode`: which exponent to use when calculating distance, \ using `2` by default for Euclidean distance ''' - p1: np.ndarray = data[p1_i] - p2: np.ndarray = data[p2_i] assert p1.shape == p2.shape, ( '_distance: dimensions not match for ' f'{p1.shape} and {p2.shape}' ) return np.linalg.norm(p1 - p2, ord=mode) + if dataset == Dataset.TRAIN_SET: + data = self.train_data + elif dataset == Dataset.DEV_SET: + data = self.dev_data + else: + data = self.test_data + + # Use a min heap of size k to get the k nearest neighbors heap: List[Tuple[float, np.ndarray]] = [] for p_i in range(data.shape[0]): - dist: float = _distance(base_p_i, p_i) - if (len(heap) < self.k): - heapq.heappush(heap, (-dist, p_i)) + dist: float = _distance(base_p, data[p_i]) + if (len(heap) < k): + heappush(heap, (-dist, p_i)) else: - heapq.heappushpop(heap, (-dist, p_i)) + heappushpop(heap, (-dist, p_i)) + + # Return the indices of the k points in dataset return [item[1] for item in heap] def _get_most_common_label( @@ -120,6 +120,8 @@ class KNN: self.dev_data = shuffled_data[train_size:] self.dev_label = shuffled_label[train_size:] + print("=== Training ===") + # Compare the predicted and expected results, calculate the accuracy # for each parameter k, and find out the best k for prediction. k_threshold: int = train_size if train_size > 20 else 20 @@ -128,41 +130,38 @@ class KNN: for k in range(1, k_threshold): predicted_labels: List[int] = [] - - for p_i in range(self.dev_data.shape[0]): + for p in self.dev_data: k_nearest_neighbors: List[int] = self._get_k_nearest_neighbors( - p_i, Dataset.TRAIN_SET + k, p, Dataset.TRAIN_SET ) predicted_label: int = self._get_most_common_label( k_nearest_neighbors, Dataset.TRAIN_SET ) predicted_labels.append(predicted_label) + prediction: np.ndarray = np.array(predicted_labels) - accuracy: float = np.mean( - np.equal(np.array(predicted_labels), self.dev_label) - ) + accuracy: float = np.mean(np.equal(prediction, self.dev_label)) accuracy_table.append(accuracy) print(f"k = {k}, train_acc = {accuracy * 100} %") if accuracy > max_accuracy: max_accuracy = accuracy self.k = k + print("\n") + def predict(self, test_data: np.ndarray) -> np.ndarray: self.test_data = test_data - predicted_labels: List[int] = [] + print("=== Predicting ===") - for p_i in range(self.test_data.shape[0]): + predicted_labels: List[int] = [] + for p in self.test_data: k_nearest_neighbors: List[int] = self._get_k_nearest_neighbors( - p_i, Dataset.TRAIN_SET + self.k, p, Dataset.TRAIN_SET ) predicted_label: int = self._get_most_common_label( k_nearest_neighbors, Dataset.TRAIN_SET ) predicted_labels.append(predicted_label) - - accuracy: float = np.mean( - np.equal(np.array(predicted_labels), self.dev_label) - ) - print(f"k = {self.k}, test_acc = {accuracy * 100} %") - return predicted_labels + prediction: np.ndarray = np.array(predicted_labels) + return prediction -- Gitee From 22da379c26380701b777e8ad1dc4b0c4779a8789 Mon Sep 17 00:00:00 2001 From: Hakula Chen Date: Fri, 2 Apr 2021 00:01:37 +0800 Subject: [PATCH 5/8] feat: done doc: done --- assignment-1/submission/18307130003/README.md | 332 ++++++++++++++++++ .../submission/18307130003/img/test.png | Bin 0 -> 25961 bytes .../submission/18307130003/img/train.png | Bin 0 -> 38778 bytes assignment-1/submission/18307130003/source.py | 143 +++++++- 4 files changed, 462 insertions(+), 13 deletions(-) create mode 100644 assignment-1/submission/18307130003/README.md create mode 100644 assignment-1/submission/18307130003/img/test.png create mode 100644 assignment-1/submission/18307130003/img/train.png diff --git a/assignment-1/submission/18307130003/README.md b/assignment-1/submission/18307130003/README.md new file mode 100644 index 0000000..9e5140a --- /dev/null +++ b/assignment-1/submission/18307130003/README.md @@ -0,0 +1,332 @@ +# 实验报告 + +## KNN 模型实现 + +```python {.line-numbers} +class KNN: + ''' + k-Nearest Neighbors algorithm, which predicts the class of a data point + according to the most common class among its `k` nearest neighbors. + ''' + + def __init__(self) -> None: + ''' + Initialize our KNN model. + ''' + + self.k: int = 1 + self.train_data: np.ndarray = None + self.train_label: np.ndarray = None + self.dev_data: np.ndarray = None + self.dev_label: np.ndarray = None + self.test_data: np.ndarray = None + + def _get_k_nearest_neighbors( + self, k: int, base_p: np.ndarray, dataset: int = Dataset.TRAIN_SET + ) -> List[int]: + ''' + Get k nearest neighbors of a point from dataset. Each point (except the + base point) is denoted by its index in the dataset. + + :param `base_p`: the base point + :param `dataset`: which dataset to use + ''' + + def _distance(p1: np.ndarray, p2: np.ndarray, mode: int = 2) -> float: + ''' + Get the distance between two points. + + :param `p1`: the first point + :param `p2`: the second point + :param `mode`: which exponent to use when calculating distance, \ + using `2` by default for Euclidean distance + ''' + + assert p1.shape == p2.shape, ( + '_distance: dimensions not match for ' + f'{p1.shape} and {p2.shape}' + ) + return np.linalg.norm(p1 - p2, ord=mode) + + if dataset == Dataset.TRAIN_SET: + data = self.train_data + elif dataset == Dataset.DEV_SET: + data = self.dev_data + else: + data = self.test_data + + # Use a min heap of size k to get the k nearest neighbors + heap: List[Tuple[float, np.ndarray]] = [] + for p_i in range(data.shape[0]): + dist: float = _distance(base_p, data[p_i]) + if (len(heap) < k): + heappush(heap, (-dist, p_i)) + else: + heappushpop(heap, (-dist, p_i)) + + # Return the indices of the k points in the dataset + return [item[1] for item in heap] + + def _get_most_common_label( + self, labels_i: List[int], dataset: int = Dataset.TRAIN_SET + ) -> int: + ''' + Get the most common label in given labels. Each label is denoted by + its data point's index in the dataset. + + :param `labels_i`: the indices of given labels + :param `dataset`: which dataset to use + ''' + + if dataset == Dataset.TRAIN_SET: + all_labels = self.train_label + else: + all_labels = self.dev_label + + labels: List[int] = [all_labels[i] for i in labels_i] + return max(set(labels), key=labels.count) + + def fit(self, train_data: np.ndarray, train_label: np.ndarray) -> None: + ''' + Train the model using a training set with labels. + + :param `train_data`: training set + :param `train_label`: provided labels for data in training set + ''' + + # Shuffle the dataset with labels + assert train_data.shape[0] == train_label.shape[0], ( + 'fit: data size not match for ' + f'{train_data.shape[0]} and {train_label.shape[0]}' + ) + shuffled_i = np.random.permutation(train_data.shape[0]) + shuffled_data: np.ndarray = train_data[shuffled_i] + shuffled_label: np.ndarray = train_label[shuffled_i] + + # Separate training set and development set (for validation) + train_ratio: float = 0.75 + train_size: int = floor(shuffled_data.shape[0] * train_ratio) + self.train_data = shuffled_data[:train_size] + self.train_label = shuffled_label[:train_size] + self.dev_data = shuffled_data[train_size:] + self.dev_label = shuffled_label[train_size:] + + print('=== Training ===') + + # Compare the predicted and expected results, calculate the accuracy + # for each parameter k, and find out the best k for prediction. + k_threshold: int = train_size if train_size < 20 else 20 + accuracy_table: List[float] = [0.0] + max_accuracy: float = 0.0 + + for k in range(1, k_threshold): + predicted_labels: List[int] = [] + for p in self.dev_data: + k_nearest_neighbors: List[int] = self._get_k_nearest_neighbors( + k, p, Dataset.TRAIN_SET + ) + predicted_label: int = self._get_most_common_label( + k_nearest_neighbors, Dataset.TRAIN_SET + ) + predicted_labels.append(predicted_label) + prediction: np.ndarray = np.array(predicted_labels) + + accuracy: float = np.mean(np.equal(prediction, self.dev_label)) + accuracy_table.append(accuracy) + print(f'k = {k}, train_acc = {accuracy * 100} %') + if accuracy > max_accuracy: + max_accuracy, self.k = accuracy, k + + print(f'best k = {self.k}\n') + + def predict(self, test_data: np.ndarray) -> np.ndarray: + ''' + Predict the label of a point using our model. + + :param `test_data`: testing set + ''' + + self.test_data = test_data + + predicted_labels: List[int] = [] + for p in self.test_data: + k_nearest_neighbors: List[int] = self._get_k_nearest_neighbors( + self.k, p, Dataset.TRAIN_SET + ) + predicted_label: int = self._get_most_common_label( + k_nearest_neighbors, Dataset.TRAIN_SET + ) + predicted_labels.append(predicted_label) + prediction: np.ndarray = np.array(predicted_labels) + return prediction +``` + +## 实验探究部分 + +生成数据集,并保存到文件: + +```python {.line-numbers} +def generate() -> None: + ''' + Generate datasets using different parameters, and save to a file for + further use. + ''' + + class Parameter(NamedTuple): + mean: Tuple[int, int] + cov: List[List[float]] + size: int + label: int + + def _generate_with_parameters(param: Parameter) -> np.ndarray: + ''' + Generate a dataset using given parameters + + :param `param`: a tuple of `mean`, `cov`, `size` + `mean`: the mean of the dataset + `cov`: the coefficient of variation (COV) of the dataset + `size`: the number of points in the dataset + ''' + + return np.random.multivariate_normal( + param.mean, + param.cov, + param.size, + ) + + parameters: List[Parameter] = [ + Parameter( + mean=(1, 2), + cov=[[73, 0], [0, 22]], + size=800, + label=0, + ), + Parameter( + mean=(16, -5), + cov=[[21.2, 0], [0, 32.1]], + size=200, + label=1, + ), + Parameter( + mean=(10, 22), + cov=[[10, 5], [5, 10]], + size=1000, + label=2, + ), + ] + + data: List[np.ndarray] = [ + _generate_with_parameters(param) for param in parameters + ] + + indices: np.ndarray = np.arange(2000) + np.random.shuffle(indices) + all_data: np.ndarray = np.concatenate(data) + all_label = np.concatenate([ + np.ones(param.size, int) * param.label for param in parameters + ]) + shuffled_data: np.ndarray = all_data[indices] + shuffled_label: np.ndarray = all_label[indices] + + train_data: np.ndarray = shuffled_data[:1600] + train_label: np.ndarray = shuffled_label[:1600] + test_data: np.ndarray = shuffled_data[1600:] + test_label: np.ndarray = shuffled_label[1600:] + np.save('data.npy', ( + (train_data, train_label), + (test_data, test_label), + )) +``` + +作图: + +```python {.line-numbers} +def display(data, label, name): + ''' + Visualize data and labels using `matplotlib.pyplot`. + ''' + + datas = [[], [], []] + for i in range(len(data)): + datas[label[i]].append(data[i]) + + for each in datas: + each = np.array(each) + plt.scatter(each[:, 0], each[:, 1]) + plt.savefig(f'img/{name}') + plt.show() +``` + +## 运行代码 + +```bash +# 训练模型及预测 +python ./source.py g + +# 展示数据集 +python ./source.py d +``` + +## 数据集 + +数据生成使用的参数: + +```python {.line-numbers} +mean = (1, 2) +cov = [[73, 0], [0, 22]] +size = 800 +``` + +```python {.line-numbers} +mean = (16, -5) +cov = [[21.2, 0], [0, 32.1]] +size = 200 +``` + +```python {.line-numbers} +mean = (10, 22) +cov = [[10, 5], [5, 10]] +size = 1000 +``` + +其中,`mean` 表示数据集的均值、`cov` 表示数据集的协方差、`size` 表示数据集的大小。 + +### 训练集 + +![训练集](./img/train.png) + +在训练时,我们随机选取 80% 作为训练集、20% 作为验证集。 + +### 测试集 + +![测试集](./img/test.png) + +## 参数 + +训练时使用的参数 `k` 及相应的准确率: + +```text +k = 1, train_acc = 95.75 % +k = 2, train_acc = 95.75 % +k = 3, train_acc = 97.25 % +k = 4, train_acc = 96.25 % +k = 5, train_acc = 96.5 % +k = 6, train_acc = 96.5 % +k = 7, train_acc = 96.75 % +k = 8, train_acc = 96.75 % +k = 9, train_acc = 96.75 % +k = 10, train_acc = 96.5 % +k = 11, train_acc = 96.5 % +k = 12, train_acc = 96.5 % +k = 13, train_acc = 96.75 % +k = 14, train_acc = 97.0 % +k = 15, train_acc = 96.75 % +k = 16, train_acc = 96.75 % +k = 17, train_acc = 96.75 % +k = 18, train_acc = 96.75 % +k = 19, train_acc = 97.0 % +``` + +可见,对于此数据集,最优的参数 `k` 为 `3`。 + +相应的准确率为 96%。 diff --git a/assignment-1/submission/18307130003/img/test.png b/assignment-1/submission/18307130003/img/test.png new file mode 100644 index 0000000000000000000000000000000000000000..77b898ff8a239b7338b029c2b7e1f76c0fd149f2 GIT binary patch literal 25961 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 literal 0 HcmV?d00001 diff --git a/assignment-1/submission/18307130003/img/train.png b/assignment-1/submission/18307130003/img/train.png new file mode 100644 index 0000000000000000000000000000000000000000..12c56b0d5885a7f2c0a1658dbdf18e0911783088 GIT binary patch literal 38778 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 z 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 GWc>rO%;R$a literal 0 HcmV?d00001 diff --git a/assignment-1/submission/18307130003/source.py b/assignment-1/submission/18307130003/source.py index 6f2a473..36c28e2 100644 --- a/assignment-1/submission/18307130003/source.py +++ b/assignment-1/submission/18307130003/source.py @@ -1,4 +1,6 @@ -from typing import List, Tuple +from typing import List, NamedTuple, Tuple +from collections import namedtuple +import sys import numpy as np import matplotlib.pyplot as plt from heapq import heappush, heappushpop @@ -35,7 +37,7 @@ class KNN: ) -> List[int]: ''' Get k nearest neighbors of a point from dataset. Each point (except the - base point) is denoted by its index in dataset. + base point) is denoted by its index in the dataset. :param `base_p`: the base point :param `dataset`: which dataset to use @@ -73,7 +75,7 @@ class KNN: else: heappushpop(heap, (-dist, p_i)) - # Return the indices of the k points in dataset + # Return the indices of the k points in the dataset return [item[1] for item in heap] def _get_most_common_label( @@ -81,7 +83,7 @@ class KNN: ) -> int: ''' Get the most common label in given labels. Each label is denoted by - its data point's index in dataset. + its data point's index in the dataset. :param `labels_i`: the indices of given labels :param `dataset`: which dataset to use @@ -112,7 +114,7 @@ class KNN: shuffled_data: np.ndarray = train_data[shuffled_i] shuffled_label: np.ndarray = train_label[shuffled_i] - # Separate training set and development set + # Separate training set and development set (for validation) train_ratio: float = 0.75 train_size: int = floor(shuffled_data.shape[0] * train_ratio) self.train_data = shuffled_data[:train_size] @@ -120,11 +122,11 @@ class KNN: self.dev_data = shuffled_data[train_size:] self.dev_label = shuffled_label[train_size:] - print("=== Training ===") + print('=== Training ===') # Compare the predicted and expected results, calculate the accuracy # for each parameter k, and find out the best k for prediction. - k_threshold: int = train_size if train_size > 20 else 20 + k_threshold: int = train_size if train_size < 20 else 20 accuracy_table: List[float] = [0.0] max_accuracy: float = 0.0 @@ -142,17 +144,20 @@ class KNN: accuracy: float = np.mean(np.equal(prediction, self.dev_label)) accuracy_table.append(accuracy) - print(f"k = {k}, train_acc = {accuracy * 100} %") + print(f'k = {k}, train_acc = {accuracy * 100} %') if accuracy > max_accuracy: - max_accuracy = accuracy - self.k = k + max_accuracy, self.k = accuracy, k - print("\n") + print(f'best k = {self.k}\n') def predict(self, test_data: np.ndarray) -> np.ndarray: - self.test_data = test_data + ''' + Predict the label of a point using our model. - print("=== Predicting ===") + :param `test_data`: testing set + ''' + + self.test_data = test_data predicted_labels: List[int] = [] for p in self.test_data: @@ -165,3 +170,115 @@ class KNN: predicted_labels.append(predicted_label) prediction: np.ndarray = np.array(predicted_labels) return prediction + + +def generate() -> None: + ''' + Generate datasets using different parameters, and save to a file for + further use. + ''' + + class Parameter(NamedTuple): + mean: Tuple[int, int] + cov: List[List[float]] + size: int + label: int + + def _generate_with_parameters(param: Parameter) -> np.ndarray: + ''' + Generate a dataset using given parameters + + :param `param`: a tuple of `mean`, `cov`, `size` + `mean`: the mean of the dataset + `cov`: the coefficient of variation (COV) of the dataset + `size`: the number of points in the dataset + ''' + + return np.random.multivariate_normal( + param.mean, + param.cov, + param.size, + ) + + parameters: List[Parameter] = [ + Parameter( + mean=(1, 2), + cov=[[73, 0], [0, 22]], + size=800, + label=0, + ), + Parameter( + mean=(16, -5), + cov=[[21.2, 0], [0, 32.1]], + size=200, + label=1, + ), + Parameter( + mean=(10, 22), + cov=[[10, 5], [5, 10]], + size=1000, + label=2, + ), + ] + + data: List[np.ndarray] = [ + _generate_with_parameters(param) for param in parameters + ] + + indices: np.ndarray = np.arange(2000) + np.random.shuffle(indices) + all_data: np.ndarray = np.concatenate(data) + all_label = np.concatenate([ + np.ones(param.size, int) * param.label for param in parameters + ]) + shuffled_data: np.ndarray = all_data[indices] + shuffled_label: np.ndarray = all_label[indices] + + train_data: np.ndarray = shuffled_data[:1600] + train_label: np.ndarray = shuffled_label[:1600] + test_data: np.ndarray = shuffled_data[1600:] + test_label: np.ndarray = shuffled_label[1600:] + np.save('data.npy', ( + (train_data, train_label), + (test_data, test_label), + )) + + +def read() -> None: + ''' + Read data from file. + ''' + + return np.load('data.npy', allow_pickle=True) + + +def display(data, label, name): + ''' + Visualize data and labels using `matplotlib.pyplot`. + ''' + + datas = [[], [], []] + for i in range(len(data)): + datas[label[i]].append(data[i]) + + for each in datas: + each = np.array(each) + plt.scatter(each[:, 0], each[:, 1]) + plt.savefig(f'img/{name}') + plt.show() + + +if __name__ == '__main__': + if len(sys.argv) > 1 and sys.argv[1] == 'g': + generate() + if len(sys.argv) > 1 and sys.argv[1] == 'd': + (train_data, train_label), (test_data, test_label) = read() + display(train_data, train_label, 'train') + display(test_data, test_label, 'test') + else: + (train_data, train_label), (test_data, test_label) = read() + + model = KNN() + model.fit(train_data, train_label) + res = model.predict(test_data) + print('acc =', np.mean(np.equal(res, test_label))) -- Gitee From 6d3b9d0b4d1b70f90d3699bb8f7264695323c9ab Mon Sep 17 00:00:00 2001 From: Hakula Chen Date: Fri, 2 Apr 2021 01:04:01 +0800 Subject: [PATCH 6/8] doc: improve report --- assignment-1/submission/18307130003/README.md | 437 ++++++++++++------ .../18307130003/img/{test.png => test_1.png} | Bin .../submission/18307130003/img/test_2.png | Bin 0 -> 23953 bytes .../submission/18307130003/img/test_3.png | Bin 0 -> 32971 bytes .../img/{train.png => train_1.png} | Bin .../submission/18307130003/img/train_2.png | Bin 0 -> 29011 bytes .../submission/18307130003/img/train_3.png | Bin 0 -> 47033 bytes assignment-1/submission/18307130003/source.py | 6 +- .../submission/18307130003/tester_demo.py | 24 - 9 files changed, 295 insertions(+), 172 deletions(-) rename assignment-1/submission/18307130003/img/{test.png => test_1.png} (100%) create mode 100644 assignment-1/submission/18307130003/img/test_2.png create mode 100644 assignment-1/submission/18307130003/img/test_3.png rename assignment-1/submission/18307130003/img/{train.png => train_1.png} (100%) create mode 100644 assignment-1/submission/18307130003/img/train_2.png create mode 100644 assignment-1/submission/18307130003/img/train_3.png delete mode 100644 assignment-1/submission/18307130003/tester_demo.py diff --git a/assignment-1/submission/18307130003/README.md b/assignment-1/submission/18307130003/README.md index 9e5140a..21cd813 100644 --- a/assignment-1/submission/18307130003/README.md +++ b/assignment-1/submission/18307130003/README.md @@ -1,169 +1,177 @@ # 实验报告 +## 目录 + +[TOC] + ## KNN 模型实现 +KNN 算法的主要思路是,根据当前点 `base_p` 最近的 `k` 个邻居 `p` 的标签,选择其中出现频率最高的标签,作为 `base_p` 标签的预测结果。 + +具体来说,我们使用函数 `_distance` 获取两点间的距离。 + ```python {.line-numbers} -class KNN: +def _distance(p1: np.ndarray, p2: np.ndarray, mode: int = 2) -> float: ''' - k-Nearest Neighbors algorithm, which predicts the class of a data point - according to the most common class among its `k` nearest neighbors. - ''' - - def __init__(self) -> None: - ''' - Initialize our KNN model. - ''' + Get the distance between two points. - self.k: int = 1 - self.train_data: np.ndarray = None - self.train_label: np.ndarray = None - self.dev_data: np.ndarray = None - self.dev_label: np.ndarray = None - self.test_data: np.ndarray = None + :param `p1`: the first point + :param `p2`: the second point + :param `mode`: which exponent to use when calculating distance, \ + using `2` by default for Euclidean distance + ''' - def _get_k_nearest_neighbors( - self, k: int, base_p: np.ndarray, dataset: int = Dataset.TRAIN_SET - ) -> List[int]: - ''' - Get k nearest neighbors of a point from dataset. Each point (except the - base point) is denoted by its index in the dataset. + assert p1.shape == p2.shape, ( + '_distance: dimensions not match for ' + f'{p1.shape} and {p2.shape}' + ) + return np.linalg.norm(p1 - p2, ord=mode) +``` - :param `base_p`: the base point - :param `dataset`: which dataset to use - ''' +这里我们使用了 `numpy` 库提供的 `np.linalg.norm` 方法来获取两点间的距离。特别地,当参数 `ord` 为 `2` 时,即采用 Euclidean 距离。我们这里使用 `2` 作为默认参数。 - def _distance(p1: np.ndarray, p2: np.ndarray, mode: int = 2) -> float: - ''' - Get the distance between two points. +接下来,我们维护一个大小为 `k` 的最小堆,来得到最近的 `k` 个邻居。思想就是 top k 问题的经典算法。 - :param `p1`: the first point - :param `p2`: the second point - :param `mode`: which exponent to use when calculating distance, \ - using `2` by default for Euclidean distance - ''' +```python {.line-numbers} +def _get_k_nearest_neighbors( + self, k: int, base_p: np.ndarray, dataset: int = Dataset.TRAIN_SET +) -> List[int]: + ''' + Get k nearest neighbors of a point from dataset. Each point (except the + base point) is denoted by its index in the dataset. - assert p1.shape == p2.shape, ( - '_distance: dimensions not match for ' - f'{p1.shape} and {p2.shape}' - ) - return np.linalg.norm(p1 - p2, ord=mode) + :param `base_p`: the base point + :param `dataset`: which dataset to use + ''' - if dataset == Dataset.TRAIN_SET: - data = self.train_data - elif dataset == Dataset.DEV_SET: - data = self.dev_data + if dataset == Dataset.TRAIN_SET: + data = self.train_data + elif dataset == Dataset.DEV_SET: + data = self.dev_data + else: + data = self.test_data + + # Use a min heap of size k to get the k nearest neighbors + heap: List[Tuple[float, np.ndarray]] = [] + for p_i in range(data.shape[0]): + dist: float = _distance(base_p, data[p_i]) + if (len(heap) < k): + heappush(heap, (-dist, p_i)) else: - data = self.test_data - - # Use a min heap of size k to get the k nearest neighbors - heap: List[Tuple[float, np.ndarray]] = [] - for p_i in range(data.shape[0]): - dist: float = _distance(base_p, data[p_i]) - if (len(heap) < k): - heappush(heap, (-dist, p_i)) - else: - heappushpop(heap, (-dist, p_i)) - - # Return the indices of the k points in the dataset - return [item[1] for item in heap] - - def _get_most_common_label( - self, labels_i: List[int], dataset: int = Dataset.TRAIN_SET - ) -> int: - ''' - Get the most common label in given labels. Each label is denoted by - its data point's index in the dataset. + heappushpop(heap, (-dist, p_i)) - :param `labels_i`: the indices of given labels - :param `dataset`: which dataset to use - ''' + # Return the indices of the k points in the dataset + return [item[1] for item in heap] +``` - if dataset == Dataset.TRAIN_SET: - all_labels = self.train_label - else: - all_labels = self.dev_label +最后我们对这 k 个邻居的标签分别进行计数,选择其中出现次数最多的标签作为预测结果。 - labels: List[int] = [all_labels[i] for i in labels_i] - return max(set(labels), key=labels.count) +```python {.line-numbers} +def _get_most_common_label( + self, labels_i: List[int], dataset: int = Dataset.TRAIN_SET +) -> int: + ''' + Get the most common label in given labels. Each label is denoted by + its data point's index in the dataset. - def fit(self, train_data: np.ndarray, train_label: np.ndarray) -> None: - ''' - Train the model using a training set with labels. + :param `labels_i`: the indices of given labels + :param `dataset`: which dataset to use + ''' - :param `train_data`: training set - :param `train_label`: provided labels for data in training set - ''' + if dataset == Dataset.TRAIN_SET: + all_labels = self.train_label + else: + all_labels = self.dev_label - # Shuffle the dataset with labels - assert train_data.shape[0] == train_label.shape[0], ( - 'fit: data size not match for ' - f'{train_data.shape[0]} and {train_label.shape[0]}' - ) - shuffled_i = np.random.permutation(train_data.shape[0]) - shuffled_data: np.ndarray = train_data[shuffled_i] - shuffled_label: np.ndarray = train_label[shuffled_i] - - # Separate training set and development set (for validation) - train_ratio: float = 0.75 - train_size: int = floor(shuffled_data.shape[0] * train_ratio) - self.train_data = shuffled_data[:train_size] - self.train_label = shuffled_label[:train_size] - self.dev_data = shuffled_data[train_size:] - self.dev_label = shuffled_label[train_size:] - - print('=== Training ===') - - # Compare the predicted and expected results, calculate the accuracy - # for each parameter k, and find out the best k for prediction. - k_threshold: int = train_size if train_size < 20 else 20 - accuracy_table: List[float] = [0.0] - max_accuracy: float = 0.0 - - for k in range(1, k_threshold): - predicted_labels: List[int] = [] - for p in self.dev_data: - k_nearest_neighbors: List[int] = self._get_k_nearest_neighbors( - k, p, Dataset.TRAIN_SET - ) - predicted_label: int = self._get_most_common_label( - k_nearest_neighbors, Dataset.TRAIN_SET - ) - predicted_labels.append(predicted_label) - prediction: np.ndarray = np.array(predicted_labels) - - accuracy: float = np.mean(np.equal(prediction, self.dev_label)) - accuracy_table.append(accuracy) - print(f'k = {k}, train_acc = {accuracy * 100} %') - if accuracy > max_accuracy: - max_accuracy, self.k = accuracy, k - - print(f'best k = {self.k}\n') - - def predict(self, test_data: np.ndarray) -> np.ndarray: - ''' - Predict the label of a point using our model. + labels: List[int] = [all_labels[i] for i in labels_i] + return max(set(labels), key=labels.count) +``` - :param `test_data`: testing set - ''' +训练模型时,我们先将数据集打乱,然后将其中的 75% 作为训练集 `train_data`,剩下 25% 作为验证集 `dev_data`,然后使用 KNN 算法进行训练。我们选择不同的 `k` 值,通过比较验证集 `dev_data` 的预测结果和其实际标签 `dev_label`,得到每个 `k` 值所对应的预测准确率 `accuracy`。最终,我们选择准确率最高的 `k` 值作为我们将在测试集 `test_data` 上使用的参数 `k`。 - self.test_data = test_data +```python {.line-numbers} +def fit(self, train_data: np.ndarray, train_label: np.ndarray) -> None: + ''' + Train the model using a training set with labels. + :param `train_data`: training set + :param `train_label`: provided labels for data in training set + ''' + + # Shuffle the dataset with labels + assert train_data.shape[0] == train_label.shape[0], ( + 'fit: data size not match for ' + f'{train_data.shape[0]} and {train_label.shape[0]}' + ) + shuffled_i = np.random.permutation(train_data.shape[0]) + shuffled_data: np.ndarray = train_data[shuffled_i] + shuffled_label: np.ndarray = train_label[shuffled_i] + + # Separate training set and development set (for validation) + train_ratio: float = 0.75 + train_size: int = floor(shuffled_data.shape[0] * train_ratio) + self.train_data = shuffled_data[:train_size] + self.train_label = shuffled_label[:train_size] + self.dev_data = shuffled_data[train_size:] + self.dev_label = shuffled_label[train_size:] + + print('=== Training ===') + + # Compare the predicted and expected results, calculate the accuracy + # for each parameter k, and find out the best k for prediction. + k_threshold: int = train_size if train_size < 20 else 20 + accuracy_table: List[float] = [0.0] + max_accuracy: float = 0.0 + + for k in range(1, k_threshold): predicted_labels: List[int] = [] - for p in self.test_data: + for p in self.dev_data: k_nearest_neighbors: List[int] = self._get_k_nearest_neighbors( - self.k, p, Dataset.TRAIN_SET + k, p, Dataset.TRAIN_SET ) predicted_label: int = self._get_most_common_label( k_nearest_neighbors, Dataset.TRAIN_SET ) predicted_labels.append(predicted_label) prediction: np.ndarray = np.array(predicted_labels) - return prediction + + accuracy: float = np.mean(np.equal(prediction, self.dev_label)) + accuracy_table.append(accuracy) + print(f'k = {k}, train_acc = {accuracy * 100} %') + if accuracy > max_accuracy: + max_accuracy, self.k = accuracy, k + + print(f'best k = {self.k}\n') ``` -## 实验探究部分 +对测试集进行预测时,我们就使用之前得到的最优的参数 `k` 进行预测,同样使用 KNN 算法。 -生成数据集,并保存到文件: +```python {.line-numbers} +def predict(self, test_data: np.ndarray) -> np.ndarray: + ''' + Predict the label of a point using our model. + + :param `test_data`: testing set + ''' + + self.test_data = test_data + + predicted_labels: List[int] = [] + for p in self.test_data: + k_nearest_neighbors: List[int] = self._get_k_nearest_neighbors( + self.k, p, Dataset.TRAIN_SET + ) + predicted_label: int = self._get_most_common_label( + k_nearest_neighbors, Dataset.TRAIN_SET + ) + predicted_labels.append(predicted_label) + prediction: np.ndarray = np.array(predicted_labels) + return prediction +``` + +## 生成数据 + +我们使用不同的参数生成数据集,并保存到文件 `data.npy`。这里由于时间有限,为了方便起见,我们直接在函数 `generate` 的 `parameters` 变量中对相应参数进行修改。 ```python {.line-numbers} def generate() -> None: @@ -238,7 +246,7 @@ def generate() -> None: )) ``` -作图: +为了直观起见,我们提供了函数 `display` 用于将当前使用的数据集可视化,并将图片保存到 `./img` 目录下。 ```python {.line-numbers} def display(data, label, name): @@ -259,6 +267,8 @@ def display(data, label, name): ## 运行代码 +在当前目录下,我们可以使用以下参数执行代码 `source.py`,具体功能参见注释。 + ```bash # 训练模型及预测 python ./source.py g @@ -267,9 +277,11 @@ python ./source.py g python ./source.py d ``` -## 数据集 +## 实验探究 + +### 1. 实验 1 -数据生成使用的参数: +#### 1.1 参数 ```python {.line-numbers} mean = (1, 2) @@ -289,21 +301,27 @@ cov = [[10, 5], [5, 10]] size = 1000 ``` -其中,`mean` 表示数据集的均值、`cov` 表示数据集的协方差、`size` 表示数据集的大小。 +其中: -### 训练集 +- `mean` 表示数据集的均值 +- `cov` 表示数据集的协方差 +- `size` 表示数据集的大小 -![训练集](./img/train.png) +下同。 -在训练时,我们随机选取 80% 作为训练集、20% 作为验证集。 +#### 1.2 数据集 -### 测试集 +训练集: -![测试集](./img/test.png) +![训练集](./img/train_1.png) -## 参数 +测试集: -训练时使用的参数 `k` 及相应的准确率: +![测试集](./img/test_1.png) + +#### 1.3 预测准确率 + +训练时使用的参数 `k` 及相应的准确率如下所示: ```text k = 1, train_acc = 95.75 % @@ -325,8 +343,137 @@ k = 16, train_acc = 96.75 % k = 17, train_acc = 96.75 % k = 18, train_acc = 96.75 % k = 19, train_acc = 97.0 % +best k = 3 + +acc = 0.96 +``` + +可见,对于此数据集,最优的参数 `k` 为 `3`,其对测试集的预测准确率为 96%。 + +### 2. 实验 2 + +这次,我们调大数据之间的距离,观察预测准确率的变化。 + +#### 2.1 参数 + +```python {.line-numbers} +mean = (-5, 2) +cov = [[73, 0], [0, 22]] +size = 800 +``` + +```python {.line-numbers} +mean = (30, -10) +cov = [[21.2, 0], [0, 32.1]] +size = 200 +``` + +```python {.line-numbers} +mean = (20, 40) +cov = [[10, 5], [5, 10]] +size = 1000 +``` + +#### 2.2 数据集 + +训练集: + +![训练集](./img/train_2.png) + +测试集: + +![测试集](./img/test_2.png) + +#### 2.3 预测准确率 + +训练时使用的参数 `k` 及相应的准确率如下所示: + +```text +k = 1, train_acc = 100.0 % +k = 2, train_acc = 100.0 % +k = 3, train_acc = 100.0 % +k = 4, train_acc = 100.0 % +k = 5, train_acc = 100.0 % +k = 6, train_acc = 100.0 % +k = 7, train_acc = 100.0 % +k = 8, train_acc = 100.0 % +k = 9, train_acc = 100.0 % +k = 10, train_acc = 100.0 % +k = 11, train_acc = 100.0 % +k = 12, train_acc = 100.0 % +k = 13, train_acc = 100.0 % +k = 14, train_acc = 100.0 % +k = 15, train_acc = 100.0 % +k = 16, train_acc = 100.0 % +k = 17, train_acc = 100.0 % +k = 18, train_acc = 100.0 % +k = 19, train_acc = 100.0 % +best k = 1 + +acc = 1.0 +``` + +可见,对于不同标签区分度较大(即彼此间距离较远)的数据集,所有 `k` 的预测准确率均为 100%。这说明 KNN 算法对于较分散的数据有着很高的准确率。 + +### 3. 实验 3 + +#### 3.1 参数 + +```python {.line-numbers} +mean = (1, 2) +cov = [[73, 0], [0, 22]] +size = 800 ``` -可见,对于此数据集,最优的参数 `k` 为 `3`。 +```python {.line-numbers} +mean = (3, -2) +cov = [[21.2, 0], [0, 32.1]] +size = 200 +``` + +```python {.line-numbers} +mean = (-5, 4) +cov = [[10, 5], [5, 10]] +size = 1000 +``` + +#### 3.2 数据集 + +训练集: + +![训练集](./img/train_3.png) + +测试集: + +![测试集](./img/test_3.png) + +#### 3.3 预测准确率 + +训练时使用的参数 `k` 及相应的准确率如下所示: + +```text +k = 1, train_acc = 65.0 % +k = 2, train_acc = 65.75 % +k = 3, train_acc = 69.25 % +k = 4, train_acc = 68.25 % +k = 5, train_acc = 72.5 % +k = 6, train_acc = 71.5 % +k = 7, train_acc = 73.75 % +k = 8, train_acc = 75.0 % +k = 9, train_acc = 76.0 % +k = 10, train_acc = 75.75 % +k = 11, train_acc = 76.0 % +k = 12, train_acc = 74.5 % +k = 13, train_acc = 75.25 % +k = 14, train_acc = 75.0 % +k = 15, train_acc = 74.75 % +k = 16, train_acc = 75.5 % +k = 17, train_acc = 75.0 % +k = 18, train_acc = 75.0 % +k = 19, train_acc = 74.5 % +best k = 9 + +acc = 0.76 +``` -相应的准确率为 96%。 +此时,最优的参数 `k` 为 `9`,其对测试集的预测准确率为 76%。可见,当数据集间的区分度较低时,较高的 `k` 值有着相对较高的准确率。这是可以理解的,因为这样可以尽可能地减少噪声的影响。 diff --git a/assignment-1/submission/18307130003/img/test.png b/assignment-1/submission/18307130003/img/test_1.png similarity index 100% rename from assignment-1/submission/18307130003/img/test.png rename to assignment-1/submission/18307130003/img/test_1.png diff --git a/assignment-1/submission/18307130003/img/test_2.png b/assignment-1/submission/18307130003/img/test_2.png new file mode 100644 index 0000000000000000000000000000000000000000..7e659711bc803be2d274a9c625717216d2daf75f GIT binary patch literal 23953 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 QXbnnN``n4FV;1-R2joZbGXMYp literal 0 HcmV?d00001 diff --git a/assignment-1/submission/18307130003/img/test_3.png b/assignment-1/submission/18307130003/img/test_3.png new file mode 100644 index 0000000000000000000000000000000000000000..b873479bf905f64c9aa4a9546c60cd7558248fe3 GIT binary patch literal 32971 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 literal 0 HcmV?d00001 diff --git a/assignment-1/submission/18307130003/img/train.png b/assignment-1/submission/18307130003/img/train_1.png similarity index 100% rename from assignment-1/submission/18307130003/img/train.png rename to assignment-1/submission/18307130003/img/train_1.png diff --git a/assignment-1/submission/18307130003/img/train_2.png b/assignment-1/submission/18307130003/img/train_2.png new file mode 100644 index 0000000000000000000000000000000000000000..cc5dc200bd579fdaca4286f6f6cc6d74837ee354 GIT binary patch literal 29011 zcmeFYWl&vF(=~YU;O-jSHMl0YyF+jY?(P;mgg|gYaCdhI9^BpC-EGdz^UnKyQzJFM zW`4|2MO}(>&py5P?(Vhr>OK)l3X;eO1PCAy2w7T6Oa%mj3;=;3*5APb|KXfi-UdE+ zUBtCqRPD`O+>M;fK=MW|4mS2KHkQU@Ze~u-miBfW%pA<@jAUP2TpXPFSXgZT`wPtW zP8KXIk?4rPAn*=S+Rh*lsuB1XqENWN5(IMSlotD_=8=A~;^~9w`YL>`sk3HRQlidWI;hkRVByt`>%S~+TsErea+`$tR5Ks3#}D>S3yHT4Ks1=#T|?$ z7T&{%JT=QA5ldN1RjJ)ONxt{}a_sTL+o^L`7yD4DazDm$Ew4tOt{z&~s6V1XqoJdt z#~D$Id4a@$AFR(vposABaHOvgWZ(;3tRPBqa&mS&*Z}Zl*ly5w;Oc-O9tZ=tjE@8* z0$e2zHUdcjS4~;}|C|4xSTIY>1Bf2>u`wC^;oTF-D_?ILzxMnBEMKvxc#Cw4n7U5Ln3e2GS}Bp$CY5vHW3 zlnzL=#r-L8E`EJeY$M&_DaZPuqB3wSH8wRW*XzvIc7?4UXWq2M+%-=1kk`OgH1 zc%7gXg&rusBH;(UJl*9qHxqyitF#2{Osce$l$GCmXL6+>bES>k`1<;`2?f)Tldt^L zNHE@AOhF^_(EIFM49hV$+LMhQw0xp5BKj36t_`(jA$oXNE|!Iy93f-HsK5Tu_Wn9dv8v1~?eyb# zs;D&<@!eHXCa3qX6m*7|)218pIuxovKuJYAfqt{gM|pYVUp|-8fcKjGO`u~$kYUfCR3` zMZZ{C{i(H_Qqt9p0yf)trdWMoU?BW_AR;_k)Q&=;tPJO_qJ^}9qz#+HpG~!5 zMqS_}PyWf0)vfiRaV-XYl~77&w06LbR++DjuX;$TV-Bt*$K7RaLhFMuI$yr)b>s36 z^NF%kvbcmseJB74CgewSxSI@>tq{1n5=<2o2QxyRNZ9|}2}JW|Z18LN)7%4UzLSd6ICn#ZA|`F@?5oIHD+ zX|erX#fksO8JqT?b^v@~&CCH8iep0+;G-qp2EDpw_F3gS$6MNyj9-MNjvZ5oiiq2s zsO)=&Dds?5QP(^axX?8VgSX&GSrAOe*a!>W4Lh5LD%!SowTo1dvWPUUQv-MZfi81% zm3&36Sle~lMON^-8%;Rn!@ND-8WfgRi0uuJ-rsn3NI0dL&fOT0yr^(N;mPK*d)Pop zPW(f6%f8b}lc%_od7V0JRtP9YDArCs(AbF&ihV-cMwO^LU|eJAlv%RM2e79`rLFIU zoIsnGXB@=Am;x)#1qOR5%slM8!Xv~OMk}c``<=} z_MBGcc*s^!-{sY|e=c>%oHYlYO`Q%&O`iQ7oXS)4Q>9QT=shbAOn?hGV54X$FRDF7 ztpN|Z9yvL3_B8&Kt>|xUdq7~a~_XTYkZOpY&xDS}*WPb;H9kD7u ztk8IXmBNf6kam$E=??#M4e%@D(N5kt5(za7?mEW#W{_K$;GdlLd{JO<47C9VgMcwx z^^Y2I!GuDJncWd!ZFO(Bd>*?C<~7=4y55Hpa|faU(*}}n^{{rb@1Tv1P%AzIYI(>A zdgE(mTzHxpup(^!M?SHuorxb1%?;So@(gKhz)VY7Di@OA@@M>y;K@jpVLkq-g4L`> zjqf)gIz71{vL4Nu5!T|03P}wOoWsMz?@y@B!*}*?n3$gu_(Nf1KRmDikan>SuRrz%t=mMs@`KV-@`9xG3*V z_rh1S)u&s*SY}edFcN}uv})Drs)uuPg{Q-S&^kJze{2wBX8rIjoiFHVZiTc@86OqV zT9pU9c#$7p^UZ_1>U<`;ewcsk`1V3Bh{O&8^GP;|BX)AVAzZ=Ku@5Fd0G>iquT-IZ zKvzaW=Wtz}s?Dk;TGFnGw|@B31C6;z)ez5=tiPr*HtUG>Z<~!nI^^_enfexrjk;Pk?_^(J3?!;wFV{uZ*|7`wbnXe!( zQBj+XwIxgxtD|dM+09d9|io1=Zz*B2Yl|~MQ z57^SaKhgJJy(woG)OjO{2r>!>RW>%_QOCn`m=8PXQ@?}U9nFY(e)h@D&o}M~N1yNT z_uqz<7Q+%T{zMM=1Yy8gAJo50t)hndJUUDgCa}*4Ae<4SM4hg$|na(4YmLj%z%&<0KtU z>gFIps~%g(T8ucYSEKxmTi^J}IZes41AujliOZ1uIt?E}i1eo$I^M<|mC5g$SXbl` z()x<~S`0iUwc+)bF-4V~ot?t+^1k^h6aA!=5pyI`AtFLw@Kt`LQwv5QOq`kh~av*-(W&UPFDLy1h?--!7ueV^Pij{vF$0m6yu-ExZR4T_9J zSa_;ku&G?IDL*?pI^rZ?LRa>PAVdcO+=2M_x6@N^?gD2z`d%~G%Ia#2yH#(NRlg_O z+}wdVOZF52+%<%tb?20p%}rxdGqa|4KKIkoh2)6vKZCv$kOu{_=1HA!=;9)JumSvT z$07g;dAvJ|1^DQ1`7|!A20P-{%cKtQ-{r%Z$?#Y+)6@5+Fe@V|9B=@#mskA#E2BRa z94@7p)AFq^e3Swp<&AwsZjl;}yf8iwJ4q&It8FAnD_%!s`!glD<|C=0&SQeO8YS3N zR8)=kn^6!TCMG8EV{jO?$hqJhy0X>+v712C z!(bKqhRpvt;kh0U4|i#(F{fGTIG_Zg%sFg$XBRcn>MJ~Gu3Z1}j34k#&Q24--IjPqYk|DCCM*B-g_>P=XF zzmAZgks#s4BlZKFX7Hm|jKWroB)!tErBJELXVQzihU+-+p;gq_hr#I`0*psME_(vO zz2{`Zp38I>WRK^#SZz4V$}j3W1CS}%@J~<~B5U=PlmeWpnh}7m17zUL>wF>y>;KWJ zntP+HV)aw(F^QJz3;pv}r2qOI?(6EAE%duWA@!IHPX6u>GUR6eYzY8Zz;oHv!mT_M zVm;qcFG?kf$er5?_R7~ZI{=b_r7x72qzRcwkOo*PQhQe1skV%@P^+qcTO{ zxA_r20eLYHe$sbap0z90+)NTJk`J7`HuZqR#p?6n2mo*8;rMMmA!5Vrrd*(V=)ldp z<9DAX!U5<}CaU2-_ORJ90g!3=```VTQ$7N4e(SIOM$)e{$p~g>{6R`;#`t*T**x_x z18&m|(~@3zj$H;4_5f&sNrv0(anD$RpF~(K%KlsxDThB+9e8%VXf564^aB7p;Ec|R zB0aF3oS@D^KGZqXO9I$Vvg;t@LiA@KDFIO#VjV8_9;^XiQRGJQ=mJ*(czdvvIB0{X zG;-OS;NgDKL#jk_fN>h$S8ip859-WT`uM*?EM+3hC?4;*3(Nwlo!L}d0392WmPr!X z`igCwxn4iqE9#Y4kommrQlpV)7w%Pr*LW-d8)@i1?^{l4NF2cEoOo&yZHCCK+qoW# z6b4?L1Vpu-1%s9<@X`?rX!cL^wlD53N}&eQ9)o8n&YNf3v;7UsKXGEUkbq1*WYml7 zc0fk434R7`fp`ns9Xk~joNVQFTAmIvi+PG+5Y@;ZW@1w*Fx?dAEnAFz5(yprNx>VFkQ8+3@lmWYcc! z0A@izL^zV2=192|>iaLN{F!y>^fZwc;Hlti{U)F4x*Y91aC~#3(p#2Yt&C-f`(O_E zA(EVBoaMy1^Vg>~Kdo0*f$=wp?fmUxlA+{slkdM0NX~hvrkXZu&+nc4O#)m&!NTM$ z|3*xnB%k7?kO8!brbuGV05F=Rs^Q6y#exK{A1w7ObSbYo1;1IE?Wn|{E0vU8JW{7~r0Yl)rw4Fu z+dw0FAG@=sDlBW~)YLk(lRio{`A?&O0>j6B(1nNXn{{=++$kr1UYLx27cNM1;isbC zy;x1vfEh*I@`Ie10yyT7N&#H2IP=%PeXQlO^w=1})myVjsR2Qx&Y_qpe$GAzOh1As9Hu`%sAMZ`m$NY*yQYj6&xq`3X*B4UR8EPM^mHOdy+*W#6*oda zYhnZANGc~H$gpMskTWU`yC9bx`-vk@E85#hw6(PhOG-q|&GUbW(vVNas9D6i4W2k; z?}&{H`t}A)3U&esjB#I1Iq+-^mJZ6KVd-Mk`z))f3OyJORpNh=UfBMJ^nwisxWq+g zTTPg^Lw&wejJ@F(JGhT%0*9b_Sv$BcN{@u_IIFq7pi!|2igKvVHt##*^YyMTc6Jf~ z3A)$_Bh9X?L<0y0Gzj1}Erz-fvaJADx5D+o)! z@0djS8Y~b!Uyb#juCzFA_Q3m`cflpIn<31W>FzbJnqKN%k-rNXGdqopin_Spiap}` zOrHIPBB@T*3m;v)pm7Bn5;QnCxId8t=XVih@EhQKzE8Kk0HVW{%piaO`g6~RI{%cDWh+i+oFVRc&7W#{Jhxa!NwA_9*OdoTKR zV0G1otL5+Ca09SRTSaYG5J2j8Z=~nB^K*Z>i35<#Ds2|nOZ8iD7&Oa604N6bn-u{3 z>*EDX0RMYhJ+HneCVm}^r;+s92M^I4xdb{Nh@)tH*iBPbR}U>MWd!>qaCZ+tAp!AP z@ER>OHI>zN@x%1&tnqqhpjMp~Haj~zxquVcVqg4Xl;5-9#1>9_d;YRyXbprH@B=Z36B*7aIpRPDvI)^T>_u05pI(HcmGFKHy7GsG`$O8$rJPQ`+U0x1(|)>;!%~RgBUhT^~eA*H0g`}C@LxnEvW$PU@l8M z*}G4m-HSP+6L3HRRc86{q zdwlc)*lt#NISP=0yfPty4YLe5TXRf@xYp3rgaZu>4nlwul9IssrAhxcS7H;cG&Y}m z2b<+aHgXg2z9NKi#gT~c0Fz7MurQvlGy;exBuGtD6AHwL6V+dZ69t2fjs4@!1V|V) z3wmpFb8|-@jDZ`;U+~DGczhpSju&d+WRsY0nnq38J$+cfk(K>Fv+yAgus2;}-9fCA zzMjJ|8nhEx&z5!p32&=;*{TkbC+&ab+v3iJO8 zInPgPZ+(X|CCW-l>yEx3KSGphFv!Tr=q1(F)*7xfyW+8%hHv|(j+mR8n|t{H_oDZv z0veYGpoeaOmF0d?|7bu&*UV=D^g2M){=bwS-^Km{jFu91Bm}izPs)M<&?zK5^j;UO zD~t}Oi$DQkBwp|2<>iyPYzeHat=SybMM`z*5CESsB4GlatbC7`kMf)3zhjF38(2sI zqUi$|BL810&Lji-3_?eTF?WAAuj5C=i9E8O92X>u;PgG&F!H)GoL1sLe2C#redFRS zA*;B2!BzXS1_DV-Gul?f}d89g6%ZW4wf2F*^%?sKeq@+I=-LkqE@$;#e`~&a} zGcYt~C#<|*2gdmLy-}g{82F>>^gCZrxD*LMYRIFlTdr|S#x7to6T*Q zguivIEQQ${ieX*hfmG(j9_4u^V_8D2TWUAXEC`3j9OZ+3&T)qw#l*;A1F&%7{4l>= zZw@wQ|zu@{~JoSiXR$Dw{r39`ZF+Ru3>^a??iS2j-1u)pw3mF{nbe?JR>A%*3Rq)&xbc~)(yg9&h5Z* zr=1=cnt;2l8UK!XDJJdnO0*H8hUCnsN|S!2y6eb&iP$+DkAFQR8R2t8f5;Xuinwvm z;LpKpl(U{Q(w64$U8LwmeW33ydFJTe0z&QShhApZ^$8@n(OR@Dn=AoyGPM<%gqjIq zNq$SHvy5YwpRF}yrWK7am9IAmL?+d9ajPUBFLsE8EvK$|>LAS|c<`muB{cSING~TmmviPU<;is%q*tKo(E)Q7wrF<2k*gPDoKGxX#(y92P^K}n7+z)%uC-; zlXzw0poqNB;ZhucSLg%(4Q?&P%Dj;!$4s|R&}oI2+}awdGS9Q}O4pf4#lOLkF|>pH zo{_ly*m36?z;(1|Y(x*p`-D*cZK1eZSb#j-w~eh8VWX))ll?VLLQn12U_wEtDJgS_ zwoF8SLI+5gbMmH4+lxBfO*7)TG4Ug63i50b9vC@@(B^t+y`ED+adTu<;&v(F_C*Zp z0FD5_W^AYuksa|*@FFKD5NW7H-T9>7ARQD8W;6I=Xf$Xu>9L{i`PUZdo_O5#Gy--E zG#*|S4(t4wHS#AT!dt=uACb;q90W)`1}r|OSTa~Ey@IHolS`8kixHd zkCo)n5LIFE7$Ww@Pv9(5)z$JNtju)oKfqbi4uPsj6BQ0nUH_vhWHjw76NjbI)L)HHZLd+uQW7jy%qBV2Il zjn*&P!yiK21Y$?)y?Mu}p9PJ=hX)q1*3+)Id1Yn7xK6Fu5yali#EpuhA@vmrA7+w_ zaYDt?`@bdv@YEu9u$+^j-?@o-z5?D@x<4=F{_A~q&F0ICZbV}Sq@9h8*jl@<<55|| zX7f?`RnzN#;n(@&QNQ~3kY$qA|LURwgLbwNXvm&Yo zr^b0NMCkaUKz;FFt*rG@X7C95V`t5nP?RKzC-mHBZzj-s4EJgPfP(yIt-<`KjTGsk zF)}*kwvl~8tzL0MsgIZk8TH1VaX>~o?|d?#f8>>Zkt<6v7guff3ZHhSEmv+mD$8Jn z@bf>NP&0@NANbx9Ff=rztgjzaWzyfw%#k*NC*;G!Ww%W0%@0(=0EmsP@W@k7`RF*IB>t2SY< z@H37LzXwr`@O+82H5cb{X14B5{M;54&Xl z813$GN-%)q&0u0I3Dk342@NPMm8mK9sMxpj^?#N&A?(zz79XWz#qy?ezJpT6Xw;bD z%vr;vYBs%xl+So{XQW4&q2h~;(@cTB%?i7mr!5{L2vS&(!&^%W zoBJk=^2HSmxe2=|NJ~ixR5BC!;|GSG&qXgN;J+%9h&YVl=lj``g)j--6Sm|Dj5)LT ze~Ci1Gg>6w`sIWT(0frUUSdmoOC96g>Qzw9_K~q4vncS)@uv$xZIZZd3#wXO1`{wI$mufAsf)c_^OtN5KfZ|&8cmp?b6~C zL$+$-rD9u ztacDeJZw%|9SrDB3I^&M^9Q{HcP+g~+s=NpwL;+)XS}JT z)61o7xoKujc-1hM?rPgGwKDXm5W}IW9*i@gSshc*n7I~9UpMJV{K%%vpz1_F4}q66 z#}l5&g46nn?)p>O^dr&BVI~q}4)j{bmIpE!e$<`$&tOTys>W$|K2(0ko3WgiUg61^E3(xG~F z8IrBlg-u0PDKZM92dEH0mx@E(d+lQzkhjEIV#$v3F6-?36C1+W70Mj;Ho4++pT) zZO4W?n)r>a#5iZKwgMHR@NLkONEyoz_WS0y#YexF7IO+3LFrrMS!gl_CiuJd7JkFB zW)J1@_rxr+(*eUnGF>^CUOC0(_yDBRufOOmRbZ|zI!TRX!OAb=3zXBM=6Jbw9#;6H zc%=E;@`t?Y*SwT3qzM(%B-)i-w+OMZFu=IS><0pLrzv06n$Q-UkRrKmq4{W-=;)GP z2g07lr;Won8D<)%{?K5TTc~>x#f<{Ycv)F>O)-7;68G7&g5pEak7^1n_NGi5WT_U> z&NZ$CxO6^s%x8H*M`jE;Y7n)Jz&VE-NipJs!1JK3bzeSIzmoo1v@M)9_R4O~N?6tN zPBvPzPrg}PrD~xyMufu@wSzLyBF4t#%184mI>mi_nj;V_7{#F z!nM!+||)R z5Zk3we;u0gB)VqW)#QM+p>zFYx|HvPv5!s8zlH~l&6p=5bl6j!_v+lx%TWUJ8(B8B#1xu z`bfU~99u>ZO@C{aN4-&>1(PgP9L9jAri#d>M}0FW3gr6J9XB~pwaSu5!pOy_pXXWX z$r`7w@-9nq)jqZZOpWTI!OKYF?jj75)UIC>B9GNMxc(X`DoI#J*WgrI1*7YtqedEa zn5tmnc+lW+5=H88G!E%9Brge^H%i<6p?7_CzH)O*_Um-S-i26*27&IU=D;6b)lpO`d#s3QN>}XYLut{6Ym<$MPNyk!ff%W|13fkki&nf%^Uf{%| z-+rZnc?-V1QJC@;0y4)QxCzuA39pW02v%*uqG&@_pi8~ zPr$&$zz7VI4MePPe;rzn%|?R~iR3r#3!)`xocneBkB!qQwa}OA>-^}yn=QqfOBF6! z3=D9Q?^23p`0G3)qW63h^*#OeP=MK33E#+1W?BI=u+G?XIEsqs=PK6SJJ&Do@! z+){$zmWKY^C_W>HyW8@0#bSO*b$yQ4=Jw^iOHBEKs>W;nYhNGi*E8WK(O2Rme$>0; zT%7sP5GhhdD9j*_MG2Cj%*s51X{gSC0vYU?pWaXIP(ZuhCwWnhcK*o#Dr*$z)|e)F zNE-`4)6R%CJ2(l}!>>)`Kxu6{AVVRs?vZRk&B=O*-nPw^DV`^W{K}+7eEH3o$*+IK z|IKM?BmkbrYjU>+if{hu*8SI4CT`L9Q3ZErhK>lydYP4N!tfzAzf0863bs+3_13+% z0!AaF5J+un!JGiZGvq=G4+6>(IwzAq^hgz^rxg?Ei!ciL!&KA>p1(y+{Q)1-1MfPf zuSIhg>%WQR5BrR~ecW^r2D8?~evXkGw%MVy29X+qf0N@u0N0 zlpJfGal zVASB7%Z|;SqnJ?-X8cu&Jl{{%p@bY8h)7hH3U&0QVLNcGNpevSs|4iY%G;RkbAEMq!A-DYHcVSXh z%h7jyM%K}4bO5ng8_tCL2V#0%c}9dd=un-sSjXSy4eyVxitcD^IPKp7LW7pxCDYg2 zfnF*Y-o{)qxD%ClEVJX>AmO;gE>ci*2P-OrPC+R?96`7Lt=g8bcd=`eeHbVqVdh?s z*{(d9t=VEA_B|+ho|~m`&9Ox^Kosryl^GU+_2+XNSbYG*gUT2E>FGg=MH0ze^jQd` zKoZvwa`jjij95Y&CJslvHMPv><{Pgle_wQ!cnqwhdoqMX_yDRYq|OkEn@fBj*?fG& zinAzjsx@QH9r%SOl@?V^X*xnSf%uj)t#aXFt%to)WYR#nhY*G~qh$ax@pEfpPZ>@gyBK87cz2%JD{?M8m#KVUC6 z+{vYZau7-q^>ztA|1$8dc_)9c-t_6k493IE*RyjS)q%N2tD4Utf`F>!ZYhsy<75rF z=c{%OWpLw{dv9DW_=wI%n6kA28#8=vgSX%G$?P8(^)cu0KoSvBb6Zil7rvKO+xdRQ zb`(OS6@Gq7x5%D`TpbVGA-s?17ux(cr!6TdlTC%i2zJjhx=+&~>l;86yCD3}{_*Trfd(&_wCROs zJVA7#-IJV-v1uaNV$15SnwCD90TsRAL?j? zQ%ZU03=a#uUFqh|AgDx&8PxuoKNnJC0>8_Jk=BZGvk2yBB;7X!$E zLodR`)b2Zsw;k~eN_Up_>m|SBm$QAH5RsO$O8w8CVLY6=mK$Lv7x>w{cZo%2G$E{`GPFA!Z13OYBO%Mq;XwkSg+A!zGeODL z6|#&}V}7?+0UbRnfy-Cm-pV}{eQ5SkChf(D5H6G%CrB8i^=gJqLNG@N@T*=zj)e0h zPt~Ue`UJ-ruCFxSXWX4o+rdrl_7@p{V(O2z0jJVx?nC>xv$I=KTvf?CSOuH8?8JZu z#{(RupYU1@xUt@PY*v5}PQC8Kd3YjLyK11H{59qhAN0LuAu)ylPmo zG3#>&K@ZQ;ZIgf}C&wsyb;@*}LGztX6m!^?c9#_t{b|##{mX_ugu8+l#;5FkR# z>`CPUEt_65WpZn!MXplL?b*UjfB#))d33c(3R?P#v%cH4@_o6_`BMD!=Cq=r_DP4I zsm63uM}rFTrEJoeH>_OtQ|;eBO>oY}w~R^~dk*Gf2sC_i^fKkn=`3w=RLM(9a%?^z zpxKATc;ioKVR7*v7+k#oi%egfq|bl#<+DW)8)LbD_0_t&ZG0nDG#tJEG`Iw}bSOQ{ zY9r);l;+11Id-eD)j81@VA5{;1wv@~MYXeYV!01`DMf35MMdBXpKbqi7ECp%UoN{< zT?|v>6R|}Bk-zmxg3YkfB$vWbjCo++j-nP>l1;oNncI(X^ ziQ7PgQAiPKZB7!8H(5q)XA$LdIFP9KuCei2=MmLUSpS2;XA{XR{#6fxDB1R2;EZ9) zujk>ug})}bpu_LD08O@J4e3ntIiLyig*4|zf`e)cVb8;dR{JP1b;_$Pl9>cp v` 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 literal 0 HcmV?d00001 diff --git a/assignment-1/submission/18307130003/img/train_3.png b/assignment-1/submission/18307130003/img/train_3.png new file mode 100644 index 0000000000000000000000000000000000000000..e3a72721e45d0df59e666a8ce075432f8eba2944 GIT binary patch literal 47033 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�Aq@?7j$fDqmYa2t~qva=O$-hL3GvAFGSN6%Ou5^ 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 M8CB^TNz>5(1He*mx&QzG literal 0 HcmV?d00001 diff --git a/assignment-1/submission/18307130003/source.py b/assignment-1/submission/18307130003/source.py index 36c28e2..0125a54 100644 --- a/assignment-1/submission/18307130003/source.py +++ b/assignment-1/submission/18307130003/source.py @@ -200,7 +200,7 @@ def generate() -> None: param.size, ) - parameters: List[Parameter] = [ + parameters: List[List[Parameter]] = [ Parameter( mean=(1, 2), cov=[[73, 0], [0, 22]], @@ -208,13 +208,13 @@ def generate() -> None: label=0, ), Parameter( - mean=(16, -5), + mean=(3, -2), cov=[[21.2, 0], [0, 32.1]], size=200, label=1, ), Parameter( - mean=(10, 22), + mean=(-5, 4), cov=[[10, 5], [5, 10]], size=1000, label=2, diff --git a/assignment-1/submission/18307130003/tester_demo.py b/assignment-1/submission/18307130003/tester_demo.py deleted file mode 100644 index 6fe1511..0000000 --- a/assignment-1/submission/18307130003/tester_demo.py +++ /dev/null @@ -1,24 +0,0 @@ -import numpy as np - -from source import KNN - -train_data = np.array([ - [1, 2, 3, 4], - [4, 2, 3, 1], - [12, 12, 13, 14], - [14, 12, 13, 11], - [12, 14, 15, 16], -]) -train_label = np.array([0, 0, 1, 1, 1]) - -test_data = np.array([ - [3, 4, 4, 2], - [18, 14, 15, 16], -]) -test_label = np.array([0, 1]) - -model = KNN() -model.fit(train_data, train_label) -res = model.predict(test_data) - -print("acc =", np.mean(np.equal(res, test_label))) -- Gitee From 1061dc60a92cf010075fe7e95884d72f0a4a6146 Mon Sep 17 00:00:00 2001 From: Hakula Chen Date: Fri, 2 Apr 2021 01:09:56 +0800 Subject: [PATCH 7/8] doc: minor fix --- assignment-1/submission/18307130003/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/assignment-1/submission/18307130003/README.md b/assignment-1/submission/18307130003/README.md index 21cd813..511563b 100644 --- a/assignment-1/submission/18307130003/README.md +++ b/assignment-1/submission/18307130003/README.md @@ -64,7 +64,7 @@ def _get_k_nearest_neighbors( return [item[1] for item in heap] ``` -最后我们对这 k 个邻居的标签分别进行计数,选择其中出现次数最多的标签作为预测结果。 +最后我们对这 `k` 个邻居的标签分别进行计数,选择其中出现次数最多的标签作为预测结果。 ```python {.line-numbers} def _get_most_common_label( @@ -352,7 +352,7 @@ acc = 0.96 ### 2. 实验 2 -这次,我们调大数据之间的距离,观察预测准确率的变化。 +这次,我们调大数据集之间的距离,观察预测准确率的变化。 #### 2.1 参数 @@ -417,6 +417,8 @@ acc = 1.0 ### 3. 实验 3 +我们再试试减小数据集间的距离,观察预测准确率的变化。 + #### 3.1 参数 ```python {.line-numbers} -- Gitee From b28837868fd1616c27f6cd60e98824034c6ae28e Mon Sep 17 00:00:00 2001 From: Hakula Chen Date: Fri, 2 Apr 2021 01:50:03 +0800 Subject: [PATCH 8/8] style: type annotations --- assignment-1/submission/18307130003/README.md | 81 ++++++++++++++----- assignment-1/submission/18307130003/source.py | 36 +++++---- 2 files changed, 85 insertions(+), 32 deletions(-) diff --git a/assignment-1/submission/18307130003/README.md b/assignment-1/submission/18307130003/README.md index 511563b..2bd04be 100644 --- a/assignment-1/submission/18307130003/README.md +++ b/assignment-1/submission/18307130003/README.md @@ -156,6 +156,8 @@ def predict(self, test_data: np.ndarray) -> np.ndarray: self.test_data = test_data + print('=== Predicting ===') + predicted_labels: List[int] = [] for p in self.test_data: k_nearest_neighbors: List[int] = self._get_k_nearest_neighbors( @@ -188,7 +190,7 @@ def generate() -> None: def _generate_with_parameters(param: Parameter) -> np.ndarray: ''' - Generate a dataset using given parameters + Generate a dataset using given parameters. :param `param`: a tuple of `mean`, `cov`, `size` `mean`: the mean of the dataset @@ -249,18 +251,23 @@ def generate() -> None: 为了直观起见,我们提供了函数 `display` 用于将当前使用的数据集可视化,并将图片保存到 `./img` 目录下。 ```python {.line-numbers} -def display(data, label, name): +def display(data: np.ndarray, label: np.ndarray, name: str) -> None: ''' - Visualize data and labels using `matplotlib.pyplot`. + Visualize dataset with labels using `matplotlib.pyplot`. + + :param `data`: dataset + :param `label`: labels for data in the dataset + :param `name`: file name when saving to file ''' - datas = [[], [], []] - for i in range(len(data)): - datas[label[i]].append(data[i]) + datasets_with_label: List[List[np.ndarray]] = [[], [], []] + for i in range(data.shape[0]): + datasets_with_label[label[i]].append(data[i]) + + for dataset_with_label in datasets_with_label: + dataset_with_label_: np.ndarray = np.array(dataset_with_label) + plt.scatter(dataset_with_label_[:, 0], dataset_with_label_[:, 1]) - for each in datas: - each = np.array(each) - plt.scatter(each[:, 0], each[:, 1]) plt.savefig(f'img/{name}') plt.show() ``` @@ -277,6 +284,35 @@ python ./source.py g python ./source.py d ``` +### 输出样例 + +```text +=== Training === +k = 1, train_acc = 67.5 % +k = 2, train_acc = 67.75 % +k = 3, train_acc = 70.5 % +k = 4, train_acc = 72.5 % +k = 5, train_acc = 72.75 % +k = 6, train_acc = 73.25 % +k = 7, train_acc = 74.25 % +k = 8, train_acc = 74.0 % +k = 9, train_acc = 75.75 % +k = 10, train_acc = 75.5 % +k = 11, train_acc = 75.75 % +k = 12, train_acc = 75.5 % +k = 13, train_acc = 75.75 % +k = 14, train_acc = 75.5 % +k = 15, train_acc = 75.5 % +k = 16, train_acc = 74.5 % +k = 17, train_acc = 75.0 % +k = 18, train_acc = 75.0 % +k = 19, train_acc = 75.25 % +best k = 9 + +=== Predicting === +k = 9, predict_acc = 71.5 % +``` + ## 实验探究 ### 1. 实验 1 @@ -343,12 +379,15 @@ k = 16, train_acc = 96.75 % k = 17, train_acc = 96.75 % k = 18, train_acc = 96.75 % k = 19, train_acc = 97.0 % -best k = 3 +``` + +预测时使用的参数 `k` 及相应的准确率如下所示: -acc = 0.96 +```text +k = 3, predict_acc = 96.0 % ``` -可见,对于此数据集,最优的参数 `k` 为 `3`,其对测试集的预测准确率为 96%。 +可见,对于此数据集,最优的参数 `k` 为 `3`,其对测试集的预测准确率为 96.0 %。 ### 2. 实验 2 @@ -408,12 +447,15 @@ k = 16, train_acc = 100.0 % k = 17, train_acc = 100.0 % k = 18, train_acc = 100.0 % k = 19, train_acc = 100.0 % -best k = 1 +``` + +预测时使用的参数 `k` 及相应的准确率如下所示: -acc = 1.0 +```text +k = 1, predict_acc = 100.0 % ``` -可见,对于不同标签区分度较大(即彼此间距离较远)的数据集,所有 `k` 的预测准确率均为 100%。这说明 KNN 算法对于较分散的数据有着很高的准确率。 +可见,对于不同标签区分度较大(即彼此间距离较远)的数据集,所有 `k` 的预测准确率均为 100.0 %。这说明 KNN 算法对于较分散的数据有着很高的准确率。 ### 3. 实验 3 @@ -473,9 +515,12 @@ k = 16, train_acc = 75.5 % k = 17, train_acc = 75.0 % k = 18, train_acc = 75.0 % k = 19, train_acc = 74.5 % -best k = 9 +``` -acc = 0.76 +预测时使用的参数 `k` 及相应的准确率如下所示: + +```text +k = 9, predict_acc = 76.0 % ``` -此时,最优的参数 `k` 为 `9`,其对测试集的预测准确率为 76%。可见,当数据集间的区分度较低时,较高的 `k` 值有着相对较高的准确率。这是可以理解的,因为这样可以尽可能地减少噪声的影响。 +此时,最优的参数 `k` 为 `9`,其对测试集的预测准确率为 76.0 %。可见,当数据集间的区分度较低时,较高的 `k` 值有着相对较高的准确率。这是可以理解的,因为提高可参考的邻居数量可以尽可能地减少噪声的影响。 diff --git a/assignment-1/submission/18307130003/source.py b/assignment-1/submission/18307130003/source.py index 0125a54..3676e4e 100644 --- a/assignment-1/submission/18307130003/source.py +++ b/assignment-1/submission/18307130003/source.py @@ -1,5 +1,4 @@ from typing import List, NamedTuple, Tuple -from collections import namedtuple import sys import numpy as np import matplotlib.pyplot as plt @@ -159,6 +158,8 @@ class KNN: self.test_data = test_data + print('=== Predicting ===') + predicted_labels: List[int] = [] for p in self.test_data: k_nearest_neighbors: List[int] = self._get_k_nearest_neighbors( @@ -186,7 +187,7 @@ def generate() -> None: def _generate_with_parameters(param: Parameter) -> np.ndarray: ''' - Generate a dataset using given parameters + Generate a dataset using given parameters. :param `param`: a tuple of `mean`, `cov`, `size` `mean`: the mean of the dataset @@ -244,26 +245,32 @@ def generate() -> None: )) -def read() -> None: +def read() -> Tuple[Tuple[np.ndarray, np.ndarray], Tuple[np.ndarray, np.ndarray]]: ''' - Read data from file. + Read data from file. Return `train_data`, `train_label` and `test_data`, + `test_label`. ''' return np.load('data.npy', allow_pickle=True) -def display(data, label, name): +def display(data: np.ndarray, label: np.ndarray, name: str) -> None: ''' - Visualize data and labels using `matplotlib.pyplot`. + Visualize dataset with labels using `matplotlib.pyplot`. + + :param `data`: dataset + :param `label`: labels for data in the dataset + :param `name`: file name when saving to file ''' - datas = [[], [], []] - for i in range(len(data)): - datas[label[i]].append(data[i]) + datasets_with_label: List[List[np.ndarray]] = [[], [], []] + for i in range(data.shape[0]): + datasets_with_label[label[i]].append(data[i]) + + for dataset_with_label in datasets_with_label: + dataset_with_label_: np.ndarray = np.array(dataset_with_label) + plt.scatter(dataset_with_label_[:, 0], dataset_with_label_[:, 1]) - for each in datas: - each = np.array(each) - plt.scatter(each[:, 0], each[:, 1]) plt.savefig(f'img/{name}') plt.show() @@ -280,5 +287,6 @@ if __name__ == '__main__': model = KNN() model.fit(train_data, train_label) - res = model.predict(test_data) - print('acc =', np.mean(np.equal(res, test_label))) + prediction: np.ndarray = model.predict(test_data) + accuracy: float = np.mean(np.equal(prediction, test_label)) + print(f'k = {model.k}, predict_acc = {accuracy * 100} %') -- Gitee