diff --git a/function.py b/function.py index bc307a1..9530048 100644 --- a/function.py +++ b/function.py @@ -1,108 +1,102 @@ -# function.py import numpy as np from sklearn.preprocessing import StandardScaler - +from sklearn.model_selection import KFold """ 实验说明: -- 自行编写实现数据加载与预测病马死亡的对率回归算法。 - -注意事项: -- 在 function.py 中实现对率回归算法。 -- 可以自行导入其他库,需要在 requirements.txt 添加依赖,若未在 requirements.txt 中添加使用到的依赖,则无法自动评测,成绩为零。 -- 自动评测脚本仅会加载 train_logreg、predict_logreg 和 load_data 函数,请勿修改函数名。 - -测评环境: -- CPU: Intel Xeon(R) CPU E3-1231 v3 @ 3.40GHz -- OS: Ubuntu 22.04.4 LTS -- Python: 3.10.12 -- numpy: 2.1.1 + - 自行编写实现数据加载与预测病马死亡的对率回归算法。 + + 注意事项: + - 在 function.py 中实现对率回归算法。 + - 可以自行导入其他库,需要在 requirements.txt 添加依赖,若未在 requirements.txt 中添加使用到的依赖,则无法自动评测,成绩为零。 + - 自动评测脚本仅会加载 train_logreg、predict_logreg 和 load_data 函数,请勿修改函数名。 + 测评环境: + - CPU: Intel Xeon(R) CPU E3-1231 v3 @ 3.40GHz + - OS: Ubuntu 22.04.4 LTS + - Python: 3.10.12 + - numpy: 2.1.1 """ - """ -请在这里填写学号和姓名,不填写即成绩无效。 + 请在这里填写学号和姓名,不填写即成绩无效。 """ id = "202210423117" name = "程悦" - + def sigmoid(z): return 1.0 / (1 + np.exp(-z)) + def train_logreg(X, y, learning_rate=0.05, - iterations=1500, - batch_size=64, regularization='L2', lambda_reg=0.05): + iterations=1500, + batch_size=64, regularization='L2', lambda_reg=0.05, cv=5): m, n = X.shape - weights = np.random.randn(n) * 0.01 - for i in range(iterations): - indices = np.random.permutation(m) - X_shuffled = X[indices] - y_shuffled = y[indices] + kf = KFold(n_splits=cv, shuffle=True) + weights_list = [] + for train_index, val_index in kf.split(X): + X_train, X_val = X[train_index], X[val_index] + y_train, y_val = y[train_index], y[val_index] + weights = np.random.randn(n) * 0.01 + for i in range(iterations): + indices = np.random.permutation(len(X_train)) + X_shuffled = X_train[indices] + y_shuffled = y_train[indices] + for j in range(0, len(X_train), batch_size): + X_batch = X_shuffled[j:j + batch_size] + y_batch = y_shuffled[j:j + batch_size] + z = np.dot(X_batch, weights) + h = sigmoid(z) + gradient = np.dot(X_batch.T, (h - y_batch)) / X_batch.shape[0] + if regularization == 'L1': + gradient += lambda_reg * np.sign(weights) / len(y_batch) + elif regularization == 'L2': + gradient += (lambda_reg / m) * weights + weights -= learning_rate * gradient + if i % 100 == 0: + learning_rate *= 0.95 + weights_list.append(weights) + return weights_list[-1] - for j in range(0, m, batch_size): - X_batch = X_shuffled[j:j + batch_size] - y_batch = y_shuffled[j:j + batch_size] - z = np.dot(X_batch, weights) - h = sigmoid(z) - gradient = np.dot(X_batch.T, (h - y_batch)) / X_batch.shape[0] - - # 添加正则化项 - if regularization == 'L1': - gradient += lambda_reg * np.sign(weights) / len(y_batch) - elif regularization == 'L2': - gradient += (lambda_reg / m) * weights - - weights -= learning_rate * gradient - - if i % 100 == 0: - learning_rate *= 0.95 - - return weights def predict_logreg(inX, weights): z = np.dot(inX, weights) h = sigmoid(z) return 1 if h > 0.5 else 0 + def load_data(filepath): - """加载数据并处理缺失值。""" data, labels = [], [] - with open(filepath, 'r') as f: - for line in f: - values = line.strip().replace('?', '0').split() - try: - values = [float(v) for v in values] - - # 合并特征23的取值 - if values[22] in [2, 3]: # 特征23索引(22) - labels.append(0) # 死亡 - elif values[22] == 1: - labels.append(1) # 生存 - else: - continue # 无效标签,丢弃 - - # 用0填充缺失值并提取特征 - data.append([0 if v == 0 else v for v in values[:2] + values[3:23]]) # 保留特征1, 2 和特征4-23 - except ValueError: - continue + for line in f.readlines(): + line = line.strip().split() + if len(line) >= 1 and line[-1].isdigit(): + line_data = [1] + [0 if x == '?' else float(x) for x in line[:-1]] + data.append(line_data) + labels.append(int(line[-1])) data = np.array(data) labels = np.array(labels) - # 数据标准化 + target_variable = labels + target_variable[(target_variable == 2) | (target_variable == 3)] = 0 + + data = np.delete(data, [2] + list(range(23, 28)), axis=1) + scaler = StandardScaler() data = scaler.fit_transform(data) - return data, labels + return data, target_variable + def accuracy(X, y, weights): predictions = [predict_logreg(x, weights) for x in X] return np.mean(predictions == y) -if __name__ == "__main__": - X_train, y_train = load_data("./horse-colic.data") - X_test, y_test = load_data("./horse-colic.test") - final_weights = train_logreg(X_train, y_train, learning_rate=0.01, iterations=5000, batch_size=32, regularization='None', lambda_reg=0.01) +if __name__ == "__main__": + X_train, y_train = load_data("./horse - colic.data") + X_test, y_test = load_data("./horse - colic.test") + + final_weights = train_logreg(X_train, y_train, learning_rate=0.01, iterations=5000, batch_size=32, regularization='None', + lambda_reg=0.01) final_accuracy = accuracy(X_test, y_test, final_weights) - print(f"最终测试集的准确率: {final_accuracy:.4f}") + print(f"最终测试集的准确率: {final_accuracy:.4f}") \ No newline at end of file