From f2d11485bff443606ee626e3927c01ded271ee3f Mon Sep 17 00:00:00 2001 From: Xionghaoran <719929980@qq.com> Date: Thu, 31 Oct 2024 16:51:28 +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 | 204 ++++++++++++++++++++++++++++------------------------ 1 file changed, 109 insertions(+), 95 deletions(-) diff --git a/function.py b/function.py index 5031f05..0a74857 100644 --- a/function.py +++ b/function.py @@ -1,119 +1,133 @@ import numpy as np +from sklearn.impute import SimpleImputer +from sklearn.feature_selection import SelectKBest, f_classif - +# 填写学号和姓名 id = "202210423213" name = "熊浩燃" +def load_data(filepath, k_features=20): + """ + 从文件中加载数据并进行预处理,包括缺失值填充和特征选择。 -# 对率回归训练函数,包含加权损失、正则化、学习率调度和提前停止 -def train_logreg(X, y, learning_rate=0.01, iterations=1000, regularization=0.01, early_stopping_rounds=100, class_weights={0: 1, 1: 1}): - weights = np.zeros(X.shape[1]) - min_loss = float('inf') - stopping_step = 0 + Args: + - filepath (str): 数据文件路径。 + - k_features (int): 选择的特征数量。 - for i in range(iterations): - z = np.dot(X, weights) - predictions = 1 / (1 + np.exp(-z)) - - loss = -np.mean(class_weights[1] * y * np.log(predictions) + - class_weights[0] * (1 - y) * np.log(1 - predictions)) + regularization * np.sum(weights**2) - - if loss < min_loss: - min_loss = loss - stopping_step = 0 - else: - stopping_step += 1 - if stopping_step >= early_stopping_rounds: - print("提前停止于迭代:", i) - break - - gradient = (np.dot(X.T, (predictions - y)) + regularization * weights) / y.size - weights -= learning_rate * gradient - - if i % 100 == 0 and i != 0: - learning_rate *= 0.9 # 每100轮衰减学习率 - print(f"迭代 {i},损失: {loss},学习率: {learning_rate}") - - return weights - -# 对率回归预测函数,带有自定义阈值 -def predict_logreg(inX, weights, threshold=0.6): - probability = 1 / (1 + np.exp(-np.dot(inX, weights))) - return 1 if probability >= threshold else 0 - -# 数据加载函数,包含缺失值填充 -def load_data(filepath): + Returns: + - np.array: 特征数据。 + - np.array: 标签数据。 + """ data = [] labels = [] with open(filepath, 'r') as file: for line in file: - fields = line.strip().split() - features = [float(x) if x != '?' else None for x in fields[:-1]] - label = float(fields[-1]) - data.append(features) - labels.append(label) + line = line.strip().split() + if line: + features = [] + for feature in line[:-1]: # 最后一个元素是标签 + try: + features.append(float(feature)) + except ValueError: + features.append(np.nan) # 用 NaN 表示缺失值 + label = int(line[-1]) + data.append(features) + labels.append(label) - data = np.array(data, dtype=float) - labels = np.array(labels, dtype=float) + # 转换为 numpy 数组 + data = np.array(data) + labels = np.array(labels) - col_means = np.nanmean(data, axis=0) - indices = np.where(np.isnan(data)) - data[indices] = np.take(col_means, indices[1]) + # 使用SimpleImputer填充NaN + imputer = SimpleImputer(strategy='mean') + data = imputer.fit_transform(data) + + # 特征标准化,避免除零错误 + mean = data.mean(axis=0) + std_dev = data.std(axis=0) + std_dev[std_dev == 0] = 1 # 如果标准差为0,将其设为1,避免除以零 + data = (data - mean) / std_dev + + # 特征选择 + selector = SelectKBest(f_classif, k=k_features) + data = selector.fit_transform(data, labels) return data, labels -# 暴力搜索函数 -def brute_force_search(X, y, X_test, y_test, learning_rates, iterations_list, regularizations, class_weights_list, thresholds): - best_params = {} - best_weights = None - best_accuracy = 0 +def sigmoid(z): + """ + Sigmoid激活函数,用于对率回归模型。 - for lr in learning_rates: - for iters in iterations_list: - for reg in regularizations: - for cw in class_weights_list: - for threshold in thresholds: - print(f"参数组合: 学习率={lr}, 迭代次数={iters}, 正则化={reg}, 类别权重={cw}, 阈值={threshold}") - weights = train_logreg(X, y, learning_rate=lr, iterations=iters, regularization=reg, class_weights=cw) - y_pred = [predict_logreg(x, weights, threshold=threshold) for x in X_test] - accuracy = np.mean(y_pred == y_test) - print(f"当前组合的测试集准确率: {accuracy}") + Args: + - z (numpy array): 输入数据。 - if accuracy > best_accuracy: - best_accuracy = accuracy - best_weights = weights - best_params = {'learning_rate': lr, 'iterations': iters, 'regularization': reg, 'class_weights': cw, 'threshold': threshold} + Returns: + - numpy array: Sigmoid函数输出值。 + """ + return 1 / (1 + np.exp(-z)) - print("最佳参数组合:", best_params) - print("最佳准确率:", best_accuracy) - return best_weights, best_params +def train_logreg(X, y, initial_lr=0.005, iterations=5000, regularization=0.01, decay=0.0001): + """ + 对率回归训练函数,包含学习率衰减策略。 + Args: + - X (numpy array): 特征数据。 + - y (numpy array): 标签数据。 + - initial_lr (float): 初始学习率。 + - iterations (int): 迭代次数。 + - regularization (float): 正则化强度。 + - decay (float): 学习率衰减系数。 + + Returns: + - numpy array: 训练得到的权重。 + """ + m, n = X.shape + weights = np.zeros(n) + learning_rate = initial_lr + + for i in range(iterations): + z = np.dot(X, weights) + predictions = sigmoid(z) + errors = y - predictions + gradient = np.dot(X.T, errors) / m - regularization * weights / m + weights += learning_rate * gradient + + # 学习率衰减 + learning_rate = initial_lr / (1 + decay * i) + + return weights + +def predict_logreg(inX, weights, threshold=0.5): + """ + 对率回归预测函数,包含可调阈值。 + + Args: + - inX (numpy array): 输入待分类的样本。 + - weights (numpy array): 训练得到的权重。 + - threshold (float): 判定阈值,默认为0.5。 + + Returns: + - int: 预测的分类标签。 + """ + probability = sigmoid(np.dot(inX, weights)) + return 1 if probability >= threshold else 2 + +# 测试代码 if __name__ == "__main__": - # 加载训练集 - X_train, y_train = load_data("./data/horse-colic.data") - X_test, y_test = load_data("./data/horse-colic.test") + # 加载数据并选择前20个最重要的特征 + X_train, y_train = load_data("./data/horse-colic.data", k_features=20) + X_test, y_test = load_data("./data/horse-colic.test", k_features=20) - # 超参数组合列表 - learning_rates = [0.001, 0.01, 0.1] - iterations_list = [1000, 2000, 3000] - regularizations = [0.01, 0.1, 1.0] - class_weights_list = [{0: 1, 1: 1}, {0: 1, 1: 2}, {0: 1, 1: 3}] - thresholds = [0.5, 0.55, 0.6, 0.65] + # 训练模型 + weights = train_logreg(X_train, y_train, initial_lr=0.005, iterations=5000, regularization=0.01, decay=0.0001) - # 进行暴力搜索找到最佳参数组合 - best_weights, best_params = brute_force_search(X_train, y_train, X_test, y_test, learning_rates, iterations_list, regularizations, class_weights_list, thresholds) - print("最佳权重:", best_weights) + # 模型评估 + correct_predictions = 0 + for i in range(len(X_test)): + y_pred = predict_logreg(X_test[i], weights, threshold=0.5) + if y_pred == y_test[i]: + correct_predictions += 1 + print(f"预测结果: {y_pred}, 实际结果: {y_test[i]}") - # 使用最佳权重和阈值在测试集上评估 - y_pred = [predict_logreg(x, best_weights, threshold=best_params['threshold']) for x in X_test] - accuracy = np.mean(y_pred == y_test) - print(f"最终测试集准确率: {accuracy}") - # 进行网格搜索以找到最佳超参数组合 - best_weights, best_params = grid_search(X_train, y_train, learning_rates, iterations_list, regularizations, class_weights_list) - print("最佳权重:", best_weights) - - # 使用最佳权重进行预测 - X_test, y_test = load_data("./data/horse-colic.test") - y_pred = [predict_logreg(x, best_weights, threshold=0.6) for x in X_test] - accuracy = np.mean(y_pred == y_test) - print(f"测试集准确率: {accuracy}") + accuracy = correct_predictions / len(X_test) + print(f"测试集准确率: {accuracy:.2f}") \ No newline at end of file