news 2026/5/25 1:28:11

保姆级教程:用Python手写逻辑回归,从零搞定西瓜书3.0α数据集分类

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
保姆级教程:用Python手写逻辑回归,从零搞定西瓜书3.0α数据集分类

从零实现逻辑回归:用Python解析西瓜数据集分类任务

当翻开周志华教授的《机器学习》第三章,许多初学者会被"对率回归"(即逻辑回归)的数学推导劝退。本文将以纯手工代码实现的方式,带你用Python从零构建逻辑回归模型,并用经典的西瓜数据集3.0α验证模型效果。不同于直接调用sklearn,我们将深入算法核心,亲手实现:

  • 数据预处理与自定义DataLoader
  • Sigmoid函数与梯度下降的数学实现
  • 留一法交叉验证策略
  • 决策边界可视化

1. 理解逻辑回归与西瓜数据集

逻辑回归虽然名字带"回归",实则是解决二分类问题的利器。它通过Sigmoid函数将线性回归结果映射到(0,1)区间,表示样本属于正类的概率。西瓜数据集3.0α包含17个样本,每个样本有密度和含糖率两个特征,标签为"好瓜"(1)或"坏瓜"(0)。

数据集关键特征分析

统计量密度含糖率
均值0.5180.191
最大值0.7740.460
最小值0.2430.026

观察数据可发现,好瓜普遍具有较高含糖率(>0.2),但仅凭单一特征无法完美分类,这正是逻辑回归的用武之地。

2. 构建数据加载器

我们先实现一个轻量级DataLoader,模仿PyTorch的接口设计:

import numpy as np import pandas as pd class WatermelonLoader: def __init__(self, data_path, features, label): raw_data = pd.read_csv(data_path) self.features = raw_data[features].values self.labels = raw_data[label].values.reshape(-1, 1) self._n_samples = len(raw_data) def __len__(self): return self._n_samples def __getitem__(self, idx): return self.features[idx], self.labels[idx] def get_batch(self, batch_size): indices = np.random.choice(self._n_samples, batch_size) return self.features[indices], self.labels[indices]

使用示例:

loader = WatermelonLoader('watermelon3.0.csv', ['密度','含糖率'], '好瓜') for x, y in loader: print(f"特征:{x}, 标签:{y}")

3. 实现逻辑回归核心

逻辑回归的核心在于Sigmoid函数和梯度计算。我们创建一个LogisticRegression类:

class LogisticRegression: def __init__(self, lr=0.01, n_iter=1000): self.lr = lr # 学习率 self.n_iter = n_iter # 迭代次数 self.weights = None # 模型参数 self.bias = None # 偏置项 def _sigmoid(self, z): return 1 / (1 + np.exp(-z)) def fit(self, X, y): n_samples, n_features = X.shape self.weights = np.zeros(n_features) self.bias = 0 # 梯度下降 for _ in range(self.n_iter): linear = np.dot(X, self.weights) + self.bias predictions = self._sigmoid(linear) # 计算梯度 dw = (1/n_samples) * np.dot(X.T, (predictions - y).flatten()) db = (1/n_samples) * np.sum(predictions - y) # 参数更新 self.weights -= self.lr * dw self.bias -= self.lr * db def predict(self, X, threshold=0.5): linear = np.dot(X, self.weights) + self.bias y_pred = self._sigmoid(linear) return (y_pred >= threshold).astype(int)

关键点解析

  1. Sigmoid函数将线性输出压缩到(0,1)
  2. 使用交叉熵损失函数的梯度下降
  3. 预测时默认以0.5为分类阈值

4. 模型训练与评估

由于西瓜数据集样本较少,我们采用留一法交叉验证:

def leave_one_out_eval(data_path): raw_data = pd.read_csv(data_path) features = ['密度', '含糖率'] label = '好瓜' correct = 0 total = len(raw_data) for i in range(total): # 留一法分割 test_data = raw_data.iloc[i:i+1] train_data = raw_data.drop(i) # 数据准备 X_train = train_data[features].values y_train = train_data[label].values.reshape(-1, 1) X_test = test_data[features].values y_test = test_data[label].values # 训练模型 model = LogisticRegression(lr=0.1, n_iter=1000) model.fit(X_train, y_train) # 预测验证 pred = model.predict(X_test) if pred == y_test: correct += 1 print(f"留一法准确率: {correct/total:.2%}")

运行结果示例:

留一法准确率: 82.35%

5. 决策边界可视化

理解模型如何做出决策至关重要,我们绘制决策边界:

import matplotlib.pyplot as plt def plot_decision_boundary(model, loader): # 创建网格点 x_min, x_max = loader.features[:,0].min()-0.1, loader.features[:,0].max()+0.1 y_min, y_max = loader.features[:,1].min()-0.1, loader.features[:,1].max()+0.1 xx, yy = np.meshgrid(np.linspace(x_min, x_max, 100), np.linspace(y_min, y_max, 100)) # 预测网格点 Z = model.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) # 绘制 plt.contourf(xx, yy, Z, alpha=0.4) plt.scatter(loader.features[:,0], loader.features[:,1], c=loader.labels.flatten(), s=20, edgecolor='k') plt.xlabel('密度') plt.ylabel('含糖率') plt.title('逻辑回归决策边界')

可视化解读

  • 背景色表示模型预测的区域
  • 散点表示真实样本分布
  • 边界线即为决策边界(概率=0.5的位置)

6. 常见问题与调试技巧

在实际实现过程中,可能会遇到以下典型问题:

问题1:梯度爆炸/消失

  • 现象:损失值剧烈波动或长期不下降
  • 解决:调整学习率(通常尝试0.01, 0.1, 0.3等)

问题2:特征尺度不一致

  • 现象:密度值范围(0.2-0.7)与含糖率(0.02-0.4)差异大
  • 解决:添加特征标准化
from sklearn.preprocessing import StandardScaler scaler = StandardScaler() X_train = scaler.fit_transform(X_train) X_test = scaler.transform(X_test)

问题3:类别不平衡

  • 检查:查看正负样本比例
print(f"正样本比例: {np.mean(y_train):.1%}")

7. 进阶优化方向

基础实现后,可以考虑以下改进:

  1. 正则化:添加L1/L2正则项防止过拟合
# 在fit方法中添加 self.weights -= self.lr * (dw + lambda * np.sign(self.weights)) # L1 self.weights -= self.lr * (dw + 2 * lambda * self.weights) # L2
  1. 优化器升级:实现动量法或Adam
# 动量法示例 velocity = 0.9 * velocity + self.lr * dw self.weights -= velocity
  1. 多分类扩展:改造为softmax回归
def _softmax(self, z): exp = np.exp(z - np.max(z)) return exp / exp.sum(axis=1, keepdims=True)

完整项目代码已托管在GitHub,包含详细注释和Jupyter Notebook示例。在实际项目中,当数据量较大时建议使用scikit-learn的优化实现,但这次手写实践让我们真正理解了逻辑回归的每一个计算细节。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/25 1:27:39

Kaggle新冠X光数据集处理实战:用Python脚本搞定80/20划分与掩码文件整理

Kaggle新冠X光数据集处理实战:Python脚本实现高效数据划分与掩码管理医学影像分析项目的第一步往往不是模型构建,而是数据准备——这个看似简单的环节却能消耗开发者50%以上的时间。当面对Kaggle上COVID-19 Radiography Database这类包含多类别、带掩码的…

作者头像 李华
网站建设 2026/5/25 1:23:10

第四十八周学习周报

摘要 今日学习了模拟壁面导热的三种方法(实体网格、薄壁模型、壳导热),重点掌握了壳导热模型的原理、设置和限制条件,以及热量在多方向传递的特性。AbstractToday, I learned three methods for simulating wall heat conduction …

作者头像 李华
网站建设 2026/5/25 1:21:57

2026年杭州靠谱的GEO优化公司,杭州这里通网络科技值得选择吗?

在数字化时代,企业越来越重视线上推广,GEO优化服务能有效提升企业在AI平台上的曝光和流量,因此很多企业关注靠谱的GEO优化公司。杭州这里通网络科技就是一家值得了解的企业。 ### 选择标准 技术能力:靠谱的GEO优化公司应具备强大…

作者头像 李华
网站建设 2026/5/25 1:17:43

如何用Python快速接入Taotoken调用多个大模型

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 如何用Python快速接入Taotoken调用多个大模型 对于希望快速集成大模型能力的开发者而言,逐一对接不同厂商的API往往意味…

作者头像 李华
网站建设 2026/5/25 1:17:18

C51中断服务中的寄存器保护机制与优化实践

1. C51中断服务中的寄存器保护机制解析在8051单片机开发中,中断服务程序(ISR)的寄存器管理是个容易被忽视但极其关键的问题。我曾在多个工业控制项目中遇到过由于寄存器处理不当导致的随机性故障,后来通过深入研究Keil C51的编译机制才彻底解决了这些问题…

作者头像 李华