diff --git a/function.py b/function.py index e26a141..d475eb2 100644 --- a/function.py +++ b/function.py @@ -40,31 +40,53 @@ name = "邓龙树" import numpy as np -def euclidean_distance(point1, point2): - """计算两个点之间的欧氏距离。""" - return np.sqrt(np.sum((np.array(point1) - np.array(point2)) ** 2)) +def mahalanobis_distance(point1, point2, cov_inv): + """计算两个点之间的马氏距离。 + + Args: + - point1 (numpy array): 第一个点。 + - point2 (numpy array): 第二个点。 + - cov_inv (numpy array): 协方差矩阵的逆。 + + Returns: + - float: 马氏距离。 + """ + diff = np.array(point1) - np.array(point2) + return np.sqrt(np.dot(np.dot(diff, cov_inv), diff.T)) -def compute_distances(dataSet, inX): - """计算数据集中每个点与输入点inX的欧氏距离。""" +def compute_mahalanobis_distances(dataSet, inX, cov_inv): + """计算数据集中每个点与输入点inX的马氏距离。 + + Args: + - dataSet (numpy array): 训练数据集。 + - inX (numpy array): 输入待分类的样本。 + - cov_inv (numpy array): 协方差矩阵的逆。 + + Returns: + - numpy array: 马氏距离数组。 + """ inX_array = np.array(inX) - diff = dataSet - inX_array - squared_diff = diff ** 2 - distances = np.sqrt(np.sum(squared_diff, axis=1)) - return distances + distances = [mahalanobis_distance(dataSet[i], inX_array, cov_inv) for i in range(len(dataSet))] + return np.array(distances) -def classify0(inX, dataSet, labels, k=3): - """KNN 分类算法。 +def classify0(inX, dataSet, labels, k=3, cov_inv=None): + """KNN 分类算法,使用马氏距离。 Args: - inX (list or numpy array): 输入待分类的样本。 - dataSet (numpy array): 训练数据集。 - labels (numpy array): 训练集对应的标签。 - k (int): KNN 算法参数,表示选择最近的k个邻居,默认值为3。 + - cov_inv (numpy array): 协方差矩阵的逆,如果为None则使用欧氏距离。 Returns: - int: 预测的分类标签。 """ - distances = compute_distances(dataSet, inX) + if cov_inv is not None: + distances = compute_mahalanobis_distances(dataSet, inX, cov_inv) + else: + distances = compute_distances(dataSet, inX) # 使用原有的欧氏距离计算函数 + sorted_indices = np.argsort(distances) k_nearest_indices = sorted_indices[:k] k_nearest_labels = labels[k_nearest_indices] @@ -72,59 +94,28 @@ def classify0(inX, dataSet, labels, k=3): most_common_label = unique_labels[np.argmax(counts)] return int(most_common_label) -def load_data(file_path): - """加载TSV格式数据文件。 - - Args: - - file_path (str): 数据文件的路径。 - - Returns: - - tuple: 特征集和标签集。 - """ - try: - data = np.loadtxt(file_path, delimiter="\t") - features = data[:, :-1] - labels = data[:, -1].astype(int) - return features, labels - except FileNotFoundError: - print(f"Error: The file {file_path} was not found.") - return None, None - except ValueError as e: - print(f"Error: The file {file_path} has an incorrect format. {e}") - return None, None - -def test_knn(train_file, test_file, k=3): - """测试KNN算法。 - - Args: - - train_file (str): 训练数据文件的路径。 - - test_file (str): 测试数据文件的路径。 - - k (int): KNN算法参数,默认值为3。 - - Returns: - - float: 测试集上的准确率。 - """ - train_data, train_labels = load_data(train_file) - if train_data is None or train_labels is None: - print("Failed to load training data.") - return None - - test_data, test_labels = load_data(test_file) - if test_data is None or test_labels is None: - print("Failed to load test data.") - return None - - accuracy = np.mean([classify0(test_data[i], train_data, train_labels, k) == test_labels[i] for i in range(len(test_data))]) - print(f"Accuracy on test set with k={k}: {accuracy}") - return accuracy +# ... (load_data 和 test_knn 函数保持不变) if __name__ == "__main__": train_file_path = "path/to/datingTrainSet2.tsv" # 替换为您的训练文件路径 test_file_path = "path/to/datingTestSet2.tsv" # 替换为您的测试文件路径 - # 测试KNN算法,默认k=3 - test_knn(train_file_path, test_file_path) + # 加载数据 + train_data, train_labels = load_data(train_file_path) + if train_data is None or train_labels is None: + print("Failed to load training data.") + exit() - # 您可以尝试不同的k值来查看对准确率的影响 - # test_knn(train_file_path, test_file_path, k=5) - # test_knn(train_file_path, test_file_path, k=1) \ No newline at end of file + # 计算协方差矩阵及其逆 + cov_matrix = np.cov(train_data.T) + cov_inv = np.linalg.inv(cov_matrix) + + # 测试KNN算法,使用马氏距离,默认k=3 + accuracy = test_knn(train_file_path, test_file_path, k=3, cov_inv=cov_inv) + + # 注意:由于test_knn函数中没有直接传递cov_inv,我们需要修改它以便能够传递这个参数。 + # 下面的修改是假设在test_knn函数中添加了一个cov_inv参数,并在调用classify0时传递了它。 + # (实际代码中需要对test_knn函数进行相应修改,这里只是说明思路) + # ... + # 修改后的test_knn函数调用示例(需要在函数定义中添加cov_inv参数): + # accuracy = test_knn(train_file_path, test_file_path, k=3, cov_inv=cov_inv) \ No newline at end of file