什么是机器学习
说明
传统编程:规则 + 数据 → 程序 → 输出
机器学习:数据 + 期望输出 → 学习算法 → 模型(= 被学出来的规则)
你给计算机几千封标注好的邮件(“垃圾”/“正常”),让它自己找出规则。训出来的“模型”本质上就是规则——只不过编码成了数字(权重、参数)。规则改变时,你用新数据重新训练,而不是重写代码。
三大类型
监督学习:有输入 + 正确答案(标签), 如1万张猫狗图片; 房子->房价
无监督学习:之友输入,没有正确答案(标签),如1万份用户购买记录
强化学习:环境+奖励/惩罚信号,如游戏胜负 +/-1分,让智能体自己悟出策略。
现实中做的产品大多是监督学习;无监督常用于预处理和探索;强化学习支撑游戏 AI、机器人,以及大模型的 RLHF 对齐。此外还有两个重要的“混合体”:半监督(少量标签 +
大量无标签)和自监督(让数据自己生成标签——BERT 的遮词预测、GPT 的下一词预测都是自监督)。
重点概念
分类 vs 回归: 分类回答“是哪类”?(如垃圾/正常邮件),回归回答“是多少”(如某套房的房价是342万),同一问题可以是两种框架:预测股票涨跌是分类;预测股票的精准价格是回归。
2、数据划分——测试集是神圣的:
- 训练集(~70%):模型学习用。
- 验证集(~15%):调超参数用、
- 测试集(~15%):只看一次,最终汇报使用。
3、过拟合:训练准确率98%,测试准确率55%->典型过拟合(死记硬背了训练数据的噪声)。欠拟合则相反:两边都差。总误差 = 偏差² + 方差 + 不可约噪声。
从零写最简单的 ML 算法
现在实现最近质心分类器(Nearest Centroid)——整个算法只有 10 行:
classNearestCentroid:deffit(self,X,y):self.classes=np.unique(y)self.centroids=np.array([X[y==c].mean(axis=0)forcinself.classes# 每个类算一个"中心点"])defpredict(self,X):distances=np.array([np.sqrt(((X-c)**2).sum(axis=1))# 新点到每个中心的距离forcinself.centroids])returnself.classes[distances.argmin(axis=0)]# 离谁近就是谁入代码片生产环境:直接用 sklearn
fromsklearn.neighborsimportNearestCentroidfromsklearn.datasetsimportmake_classificationfromsklearn.model_selectionimporttrain_test_split X,y=make_classification(n_samples=500,n_features=2,n_redundant=0,n_clusters_per_class=1,random_state=42)X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.3)clf=NearestCentroid()clf.fit(X_train,y_train)print(f"Accuracy:{clf.score(X_test,y_test):.3f}")规则写得出来且稳定 → 用规则;规则写不出或总在变 → 用数据学。
线性回归
真正“训练”
你有数据:房子面积和成交价。现在来了套 123㎡ 的房子,要预测它能卖多少钱。
完整的训练循环:定义模型 → 定义损失函数 → 优化参数
模型:一条直线
y=wx+b
- w(权重/斜率):面For each additional square meter加 1㎡,价格变多少
- b(偏置/截距):面积为 0 时的基准价格(土地价值…好吧,数学意义上)
损失函数:怎么衡量“拟合得好”
模型预测 ŷ,真实值 y,误差就是它们的差。把所有样本的误差汇总成一个数字——均方误差(MSE)
MSE=(1/n)· Σ(ŷᵢ-yᵢ)²为什么是平方?两个理由:
- 大错重罚:误差 10 的代价是误差 1 的 100 倍(不是 10 倍)——逼着模型优先消灭大错误
- 处处可导且光滑:这让后面的优化有路可走
关键图像:每个 (w, b) 取值都对应一个 MSE 值。把它们画成曲面,就是一个碗。碗底 = MSE 最小 = 最好的 w 和 b。所谓“训练”,就是找碗底。
问题:你站在碗壁上的某个 (w, b) 位置,四下漆黑看不见碗底。怎么决定下一步往哪走
答案:算当前位置的斜率,沿下坡方向迈一小步。
——梯度下降(Gradient Descent)
梯度下降:一步一步走下山
第一步:算斜率
对 MSE 分别求 w 和 b 的偏导数(链式法则展开后得到):
∂MSE/∂w=(2/n)· Σ(ŷᵢ-yᵢ)·xᵢ ← 斜率对 x 的敏感度 ∂MSE/∂b=(2/n)· Σ(ŷᵢ-yᵢ)← 斜率对偏置的敏感度注意核心结构:两个梯度都由误差项 (ŷ - y) 驱动。预测越离谱,坡越陡,步子越大。
第二步:往反方向走
导数指向上坡方向,所以走下坡就要减去它
w ← w-lr · ∂MSE/∂w b ← b-lr · ∂MSE/∂blr就是学习率——表示每一步迈多大:
太大:一步跨过碗底
太小:蚂蚁挪步,一万年走不到底
第三步:重复
更新->重算预测->重算梯度->再更新… 重算几百上千次,直到cost不再下降。
逻辑回归
直线回答不了“是/否”
回到开头的垃圾分类器,使用线性回归的输出是-0.5,1.7之类的数字,这些数字不是概率,也没有特殊的意义:1.7是垃圾邮件? 是正常邮件?
分类真正需要的是概率,输出压在0~1之间的概率。
直线+S压弯器
逻辑回归 = 直线 + 一个sigmoid函数
z=wx+b ← 还是那条直线(打分) p=sigmoid(z)=1/(1+e^(-z))← 把任意分数压进(0,1)p ≥0.5→ 判1;p<0.5→ 判0← 阈值决策sigmoid 的含义:
z sigmoid(z) 含义
很大正数 => 1 => “非常确定是"
很大负数 => 0 => “非常确定不是"
0 => 0.5 => “五五开” 决策的边界就在这
损失函数:为什么必须换掉 MSE
sigmoid 相比直线的最大优势在于MSE拟合的直线被大幅拖拽变形,sigmoid 模型几乎不受影响。
MSE 对误差平方,离群点离线 50 单位就贡献 2500 的代价,硬生生把线拖过去。而交叉熵的逻辑是“对了就闭嘴”——模型对 50 小时的样本给出 p≈1,loss≈0,没有任何梯度再去拟合它。sigmoid 模型只关心边界附近的模糊地带,边界外的世界它爱谁谁。
MSE 不仅要不得,而且用不了。数学事实是:MSE 套 sigmoid 会把碗形曲面敲出坑坑洼洼(非凸)——梯度下降走两步就卡在半山腰的小坑里(局部最优),训练报废。
替代品:二元交叉熵(binary cross-entropy / log loss):Loss = -(1/n) · Σ[ y·log(p) + (1-y)·log(1-p) ]