From c2d85fb3bed8707a9c9e2b2832c943a94328e746 Mon Sep 17 00:00:00 2001 From: wk <1270232716@qq.com> Date: Wed, 16 Oct 2024 22:19:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20function.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function.py | 142 +++++++++------------------------------------------- 1 file changed, 25 insertions(+), 117 deletions(-) diff --git a/function.py b/function.py index 6bd78c4..7ace34c 100644 --- a/function.py +++ b/function.py @@ -1,96 +1,48 @@ import numpy as np -from sklearn.decomposition import PCA -from sklearn.model_selection import cross_val_score, KFold -from sklearn.metrics import accuracy_score -from sklearn.preprocessing import StandardScaler +import os +""" +请在这里填写学号和姓名,不填写即成绩无效。 +""" id = "202210423103" name = "王坤" -def classify0(input_vector, dataSet, labels, k=3, weighted=False, distance_metric='euclidean'): +def classify0(input_vector, dataSet, labels, k=3): """ - KNN 分类算法(支持加权KNN、不同距离度量以及降维处理)。 - + KNN 分类算法。 + Args: - input_vector (numpy array): 输入待分类的样本。 - dataSet (numpy array): 训练数据集。 - labels (list or numpy array): 训练集对应的标签。 - - k (int): kNN 算法参数。 - - weighted (bool): 是否使用加权KNN。 - - distance_metric (str): 距离度量方法,支持 'euclidean', 'manhattan', 'minkowski'。 - + - k (int): kNN 算法参数,请**自行设置默认值**。 + Returns: - int: 预测的分类标签。 """ - # 根据选择的距离度量计算距离 - if distance_metric == 'euclidean': - distances = np.linalg.norm(dataSet - input_vector, axis=1) - elif distance_metric == 'manhattan': - distances = np.sum(np.abs(dataSet - input_vector), axis=1) - elif distance_metric == 'minkowski': - p = 3 # 可以调整为合适的 p 值 - distances = np.sum(np.abs(dataSet - input_vector) ** p, axis=1) ** (1 / p) - else: - raise ValueError("Unsupported distance metric") + # 计算输入向量与训练集中每个样本的欧氏距离 + distances = np.linalg.norm(dataSet - input_vector, axis=1) - # 按距离从小到大排序并获取前k个距离最小的索引 + # 按照距离从小到大排序并获取前k个距离最小的索引 sorted_indices = distances.argsort()[:k] - # 如果加权,使用距离的倒数作为权重 - if weighted: - weights = 1 / (distances[sorted_indices] + 1e-5) # 防止除零 - weighted_labels = {} - for i, index in enumerate(sorted_indices): - label = labels[index] - weighted_labels[label] = weighted_labels.get(label, 0) + weights[i] - predicted_label = max(weighted_labels, key=weighted_labels.get) - else: - # 统计前k个最近邻的标签 - nearest_labels = [labels[i] for i in sorted_indices] - predicted_label = max(set(nearest_labels), key=nearest_labels.count) + # 统计前k个最近邻的标签 + nearest_labels = [labels[i] for i in sorted_indices] + + # 返回出现次数最多的标签 + predicted_label = max(set(nearest_labels), key=nearest_labels.count) return predicted_label -def pca_reduction(data, n_components=2): - """ - 使用PCA对数据进行降维。 - - Args: - - data (numpy array): 原始特征数据。 - - n_components (int): 保留的主成分数量。 - - Returns: - - numpy array: 降维后的特征数据。 - """ - pca = PCA(n_components=n_components) - reduced_data = pca.fit_transform(data) - return reduced_data - -def normalize_data(data): - """ - 归一化特征数据,将每个特征值缩放到 [0, 1] 之间。 - - Args: - - data (numpy array): 原始特征数据。 - - Returns: - - numpy array: 归一化后的特征数据。 - """ - min_vals = data.min(0) - max_vals = data.max(0) - ranges = max_vals - min_vals - norm_data = (data - min_vals) / ranges - return norm_data, ranges, min_vals - def load_data(file_path): """ - 从 TSV 文件中加载数据集,并进行归一化处理。 - + 从 TSV 文件中加载数据集。 + Args: - file_path (str): TSV 文件路径。 - + Returns: - - np.array: 归一化后的特征数据。 + - np.array: 特征数据。 - np.array: 标签数据。 """ data = np.loadtxt(file_path, delimiter='\t') @@ -98,56 +50,12 @@ def load_data(file_path): labels = data[:, -1].astype(int) return data_set, labels -def cross_validate_knn(data_set, labels, k_range, weighted=False, distance_metric='euclidean'): - """ - 使用交叉验证来选择最佳的K值。 - - Args: - - data_set (numpy array): 训练数据集。 - - labels (numpy array): 训练集标签。 - - k_range (list): K值的候选范围。 - - weighted (bool): 是否使用加权KNN。 - - distance_metric (str): 距离度量方法。 - - Returns: - - tuple: 最佳K值和对应的最高准确率。 - """ - best_k = k_range[0] - best_accuracy = 0 - for k in k_range: - kf = KFold(n_splits=5) - accuracies = [] - for train_index, test_index in kf.split(data_set): - train_data, test_data = data_set[train_index], data_set[test_index] - train_labels, test_labels = labels[train_index], labels[test_index] - predictions = [classify0(test_sample, train_data, train_labels, k, weighted, distance_metric) - for test_sample in test_data] - accuracy = accuracy_score(test_labels, predictions) - accuracies.append(accuracy) - mean_accuracy = np.mean(accuracies) - if mean_accuracy > best_accuracy: - best_accuracy = mean_accuracy - best_k = k - return best_k, best_accuracy - if __name__ == "__main__": - # 加载数据集 + # 以下代码可用于测试,可自行随意修改 train_file = "datingTrainSet2.tsv" train_data, train_labels = load_data(train_file) - # 归一化和PCA降维处理 - scaler = StandardScaler() - scaled_train_data = scaler.fit_transform(train_data) - pca_train_data = pca_reduction(scaled_train_data, n_components=3) - - # 使用交叉验证选择最佳K值 - k_range = range(1, 21) - best_k, best_accuracy = cross_validate_knn(pca_train_data, train_labels, k_range, weighted=True, distance_metric='euclidean') - print(f"最佳K值: {best_k}, 交叉验证准确率: {best_accuracy}") - - # 使用最佳K值进行预测 + # 示例测试样本,确保维度与训练数据一致 test_sample = np.array([65915, 3.868359, 0.128078]) - norm_test_sample = scaler.transform([test_sample]) - pca_test_sample = pca_reduction(norm_test_sample, n_components=3) - prediction = classify0(pca_test_sample[0], pca_train_data, train_labels, k=best_k, weighted=True) - print(f"预测的分类标签: {prediction}") + prediction = classify0(test_sample, train_data, train_labels) + print(f"预测的分类标签: {prediction}") \ No newline at end of file