字体大小
第一编 机器学习的数学起点 · 01_第一编_机器学习的数学起点/section_end.md

第一编 Section End

从零搭建一个二手房价格评估器:机器学习基础如何真正落地

第一编到这里,读者已经见过了学习问题的数学表述、监督学习的基本框架、线性回归、Logistic 回归以及泛化问题。若只停留在这些理论对象本身,当然已经能够理解机器学习为什么能够成为一个严肃的数学问题;但接下来的自然疑问往往是:在真实工程里,这些对象究竟以什么顺序出现?工程师到底是怎样把“输入空间、损失函数、经验风险、最小二乘、分类概率、泛化误差”这些看起来很抽象的概念,一步步转成一个真正可用的系统?

这一节的目的,就是回答这个问题。这里选择的案例,是为一个城市的二手房交易平台搭建房价评估系统。这个任务非常适合作为第一编结尾的工程案例,因为它既足够具体,又不会过早依赖后面几编中的复杂模型。更重要的是,它几乎会自然调用第一编已经建立起来的全部核心数学对象。

我们不妨把场景直接放到一个真实团队里。业务方提出的需求是:当平台拿到一套房子的基础信息时,希望系统给出一个合理的价格估计,并最好还能给出“高价风险”或“价格分层”这样的辅助判断,以便帮助平台定价、推荐、风控和交易撮合。于是,一个很典型的机器学习项目就开始了。

1. 先不要急着建模,而要先把需求写清楚

一个好的工程起点,应先回答“业务方究竟要什么”,模型选择通常要放在后面。对于房价评估系统,表面需求似乎很简单,就是“预测价格”;但稍微深入一点就会发现,这里其实至少包含三个层次的问题。

第一个层次是中心估计。也就是说,给定一套房子的属性,系统需要输出一个中心价格,例如“预计成交价为 520 万”。第二个层次是区间估计。工程上往往不会满足于一个单点数字,因为房价本身有波动,所以平台更希望知道一个合理区间,例如“更可信的成交区间在 500 万到 540 万之间”。第三个层次是风险分层。业务方可能还希望知道,这套房子是否属于高价房、是否存在明显高估或低估风险、是否值得人工复核。

一旦把这三个层次拆开,数学对象就出现了。中心估计是一个回归问题,风险分层则是一个分类问题。工程上最常见的错误之一,就是业务需求没有拆清楚,结果把本来应该分开处理的目标混在一起。这里最值得注意的是:所谓“需求定义”,本质上就是在确定随机变量、输入输出空间和目标函数。换句话说,工程的第一步,实际上已经在做数学建模。

因此,在项目最开始,团队通常会先和业务方确认几件事:第一,到底预测的是挂牌价、成交价,还是某种平台内部定义的“参考价”;第二,误差多大才算可接受;第三,模型输出是给用户直接看,还是给内部运营和风控团队看;第四,是否需要额外输出价格分层或风险标签。只有这些问题先确定,后面的数据准备和模型设计才不会发生方向性偏差。

2. 数据准备:数学对象开始进入现实

需求明确之后,下一步就是准备数据。对于房价评估系统,最基本的数据往往包括:房屋面积、户型、楼层、总楼层、朝向、建成年份、小区名称、行政区、是否临近地铁、历史成交价、挂牌时长、装修情况、物业类型等。若平台掌握更多信息,还可以加入周边学校、商圈、公共交通、过去若干月的小区均价走势等特征。

从数学上看,这一步其实是在构造样本对

$$ (x_i,y_i), $$

其中 $x_i$ 表示第 $i$ 套房子的特征向量,$y_i$ 表示它对应的目标价格。这里的“特征向量”并不意味着一开始所有变量都已经天然是向量。相反,真实工程中很多原始字段是类别、文本、时间或缺失混合体。工程团队要做的第一件事,就是把这些原始信息整理成能够进入模型的结构化表示。

这一步尤其重要,因为它能非常直观地展示:抽象的输入空间 $\mathcal X$ 需要由工程过程逐步构造出来。比如,“朝向”这种离散属性需要做类别编码;“建成年份”可能要转成“房龄”;“小区名称”如果类别太多,可能需要先映射成更稳定的地理或统计特征;“历史成交价”如果存在时间差异,可能需要做时间校正。也就是说,输入空间本身是建模选择的结果,并非天然现成的对象。

与此同时,数据准备还必须处理三个非常现实的问题。第一是缺失值。有些房子没有明确的装修信息,有些没有完整交易记录,这时必须决定是删除、填补,还是单独增加“缺失”标记。第二是异常值。极端豪宅、法拍房、特殊产权房等样本,很可能并不遵守与普通住房相同的统计规律。第三是重复与泄漏。如果同一套房子以不同记录形式重复出现,或测试集中泄漏了训练阶段才应知道的信息,那么模型效果会被高估。

这一步看起来很“工程”,但背后的数学意义非常清楚。数据清洗其实是在决定经验分布

$$ \hat P_n=\frac{1}{n}\sum_{i=1}^{n}\delta_{(x_i,y_i)} $$

究竟长什么样。这里,$\hat P_n$ 表示由样本形成的经验分布,$n$ 表示样本数,$\delta_{(x_i,y_i)}$ 表示集中在样本点 $(x_i,y_i)$ 上的单位质量。第一编里我们已经看到,工程上真正能优化的总是经验风险,而经验风险又是建立在经验分布之上的。因此,数据准备不是建模之前的琐碎劳动,它实际上决定了后续优化问题是建立在什么“近似世界”之上的。

3. 把任务正式写成监督学习问题

当数据准备到一定程度后,工程团队才会真正进入“定义学习问题”的阶段。对房价评估而言,可以把输入空间记为 $\mathcal X$,其中每个元素都是一套房子的结构化特征;把输出空间记为 $\mathcal Y\subseteq \mathbb R$,因为价格是一个实数。于是,一个预测函数就是

$$ f:\mathcal X\to\mathcal Y. $$

这里,$f(x)$ 表示模型对样本 $x$ 给出的价格预测。

接下来必须定义损失函数。若当前目标是价格回归,最自然的起点通常是平方损失

$$ L(y,f(x))=(y-f(x))^2. $$

这里,$y$ 是真实价格,$f(x)$ 是预测价格,平方损失衡量的是预测误差的平方。为什么工程里常从这个损失开始?原因并不神秘。第一,它对大误差更敏感,便于惩罚严重偏差;第二,它对应了第一编已经讲过的最小二乘框架;第三,它在解析和优化上都比较方便。

于是,总体风险可以写成

$$ R(f)=\mathbb E_{(X,Y)\sim P}[L(Y,f(X))], $$

其中 $P$ 表示真实但未知的数据分布,$\mathbb E$ 表示在该分布下取期望。这个式子在工程语境里的意思很直接:如果我们能够看到整个城市未来所有可能成交房屋的分布,那么一个好模型应当让平均预测误差尽可能小。

但工程上看不到真实分布 $P$,只能看到样本。因此,团队真正会优化的是经验风险

$$ \hat R_n(f)=\frac{1}{n}\sum_{i=1}^{n}L(y_i,f(x_i)). $$

这就是第一编中“为什么工程上只能优化经验风险”的最直接体现。从这里也能更清楚地看到,监督学习在工程里会落实为一条明确的工作链:先定义输入、输出、模型类,再定义损失,最后在样本上优化经验目标。

4. 第一个可用模型为什么常常是线性回归

在现代机器学习时代,人们很容易本能地想到更复杂的模型,但一个成熟工程团队在第一轮尝试时,往往还是会先建立一个线性回归基线。原因非常现实。

第一,线性回归足够快,能够帮助团队迅速判断数据是否基本可学。第二,它有良好的可解释性,能让团队快速识别哪些特征方向是合理的,哪些可能是脏数据或编码错误。第三,它和第一编的数学对象严丝合缝:输入特征、参数向量、最小二乘、正规方程、残差分析都会完整出现。

假设我们把每套房子的特征表示成向量 $x_i\in\mathbb R^p$,其中 $p$ 表示特征维度;把参数写成 $\theta\in\mathbb R^p$;并引入截距项 $b\in\mathbb R$。那么线性回归模型写成

$$ f_{\theta,b}(x)=\theta^\top x+b. $$

这里,$\theta^\top x$ 表示参数与特征的内积,反映每个特征对价格的线性贡献。

训练时,工程团队要做的是最小化残差平方和:

$$ \min_{\theta,b}\sum_{i=1}^{n}\big(y_i-(\theta^\top x_i+b)\big)^2. $$

这一步在业务语言里其实很容易解释:我们在找一个线性定价公式,使所有训练样本上的预测价格尽量接近真实成交价格。

这里更重要的是理解工程意义,不必把重点放在死记公式上。参数 $\theta$ 的每个分量都在回答一个问题:当其他条件大致不变时,某个特征变化一个单位,会怎样影响预测价格。残差

$$ r_i=y_i-f_{\theta,b}(x_i) $$

则对应第 $i$ 个样本上的定价偏差。若某些区域、小区或房型的残差持续偏大,就说明线性模型在这些子空间里可能不够用,或者特征还不够充分。

如果从程序员的视角来看,这里的“训练”不能停留在一句抽象的“最小化目标函数”上,它对应的是一条非常具体的工程流程。团队通常会先把全部样本整理成特征矩阵

$$ X\in\mathbb R^{n\times p}, $$

其中 $n$ 是样本数,$p$ 是特征维度,第 $i$ 行对应第 $i$ 套房子的特征;再把目标价格整理成向量

$$ y\in\mathbb R^n. $$

然后,程序员会先做一轮最基础的预处理,例如统一数值尺度、检查某些类别编码是否异常、确认训练集和验证集的字段处理完全一致。之所以要先做这些事情,是因为哪怕目标函数写得很漂亮,只要输入矩阵组织得不稳定,训练过程就会在很早阶段出现偏差。

接下来才是真正意义上的“拟合参数”。如果特征规模不大、模型形式简单,团队有时会直接使用最小二乘的解析求解或数值线性代数库来求参数;如果样本规模更大、特征处理链更复杂,团队则往往会把这件事看成一个优化过程,用迭代方法逐步更新参数。对工程师而言,这里的核心在于训练误差是否随着参数更新稳定下降,而不在于是否背出了正规方程。也就是说,程序员真正盯着看的,是每次训练后目标函数值有没有下降,残差分布有没有改善,验证集误差有没有同步变好。

在这一步里,第一编中的数学对象会以非常直接的方式出现。比如,若某次训练后发现训练误差下降很快,但验证误差几乎不动,那么工程师通常就会立刻意识到:程序虽然已经跑通,经验风险下降和泛化风险下降却可能开始脱节。又比如,如果某些特征的系数大得不合理,或者模型对极少数样本异常敏感,那么程序员通常会回头检查特征尺度、异常值和正则化设置,而不会只把它当成“优化结果”照单全收。

换句话说,从程序员的工作流来看,训练是一轮轮围绕“数据表示是否稳定”“目标函数是否真的在下降”“验证集表现是否可信”“参数是否具有基本解释性”的来回检查。第一编中的最小二乘、经验风险和泛化问题,也会在一轮轮训练和验证中同时发生,而不会被分成彼此孤立的三段理论。

因此,线性回归在工程中的价值,不只是“先跑一个简单模型”,更是帮助团队形成对任务结构的第一轮认识。它让数学模型第一次和业务对象绑定起来。

5. 价格预测之外,为什么还要做风险分层

真实业务往往不会满足于一个连续价格预测。平台很可能还会提出另一个问题:哪些房子属于高价风险样本,需要人工复核?或者,哪些样本更适合进入高端房源池?这时,问题就从回归自然延伸到了分类。

设我们定义一个阈值 $c$,例如把价格高于某个分位数的房子记为 1,其他记为 0。于是,新的标签变量写成

$$ z_i=\mathbf 1\{y_i>c\}, $$

其中 $\mathbf 1\{\cdot\}$ 是示性函数,条件成立时取值 1,否则取值 0。这样一来,原来的连续价格问题就扩展成了一个二分类问题。

此时,一个自然的模型就是 Logistic 回归。它不再直接输出价格,而是输出“属于高价风险类”的概率:

$$ P_\theta(z=1\mid x)=\sigma(\theta^\top x+b), $$

其中

$$ \sigma(t)=\frac{1}{1+e^{-t}} $$

表示 sigmoid 函数,$t$ 是线性打分。这个概率输出在工程上非常有用,因为业务方通常并不只关心“分到哪一类”,还关心系统对该判断有多大把握。

训练时,团队通常最小化对数损失或交叉熵损失:

$$ \min_{\theta,b}-\sum_{i=1}^{n}\Big[z_i\log p_i+(1-z_i)\log(1-p_i)\Big], $$

其中 $p_i=P_\theta(z_i=1\mid x_i)$。这里的数学意义非常清楚:模型希望让真实类别出现的概率尽可能大。

对工程师而言,这一步意味着模型输出已经不再只是一个“标签”,而是一个可以参与业务决策的概率量。例如,当某套房子的高价概率是 0.52 和 0.95 时,虽然都可能被判为高价房,但它们在人工复核优先级上的意义完全不同。于是,数学上的条件概率建模就直接进入了业务策略。

若继续从程序员视角看,这里的训练过程和前面的回归训练非常相似,但工程关注点已经发生了细微变化。回归模型主要关注预测值和真实价格之间的偏差,而 Logistic 回归训练时,程序员更关心的是:模型给真实类别分配的概率是否在持续提高,分类边界是否稳定,以及不同阈值下业务代价会怎样变化。

具体来说,程序员通常会先在训练集上拟合参数,再在验证集上看几类东西。第一类是损失值本身是否下降,也就是交叉熵是否在逐步减小。第二类是概率输出是否有区分度,例如高风险样本的预测概率是否整体高于普通样本。第三类则是阈值敏感性,也就是当判定阈值从 0.5 改到 0.7 时,人工复核量、漏报率和误报率会怎样变化。

这一步非常能体现“数学知识如何进入工程判断”。因为对程序员来说,训练好一个分类模型,不只是看到损失函数收敛,更是要把概率分布、阈值、业务代价和人工流程一起连起来看。也就是说,sigmoid 函数、对数损失和条件概率在书里是数学对象,在工程里则直接变成了排序优先级、告警强弱和人工审核队列的组织方式。

6. 泛化问题:为什么训练效果好不代表系统能上线

到这里,工程上常常会出现一个非常典型的误区:团队看到训练集上的误差已经很低,就误以为模型已经可以上线。但第一编最重要的提醒恰恰是,训练误差低并不自动意味着真实风险低。

在房价评估任务中,这一点尤其明显。因为训练数据往往来自过去一段时间的成交记录,而系统上线后面对的是未来的待评估房源。如果市场环境变化、小区分布变化或数据采样机制变化,那么训练集上的低误差并不能保证未来也表现稳定。

因此,工程团队必须把数据划分为训练集、验证集和测试集。训练集用于拟合参数,验证集用于调参和选择模型,测试集用于最后评估。这种划分在工程上看似只是流程规范,但换个角度看,它正是在用操作层面的方式逼近第一编中的泛化问题:我们能否从有限样本上的经验表现,推断未知样本上的真实表现?

这时,正则化也会自然出现。若线性模型包含很多特征,而样本规模又不够大,那么参数可能变得极不稳定。于是,团队会考虑加入岭正则化:

$$ \min_{\theta,b}\sum_{i=1}^{n}\big(y_i-(\theta^\top x_i+b)\big)^2+\lambda\|\theta\|_2^2, $$

其中 $\lambda>0$ 是正则化系数,$\|\theta\|_2^2$ 表示参数向量的平方范数。这个额外项在工程上的含义是:不仅要拟合数据,还要避免参数过大、模型过于敏感。

从这里也很容易看到,所谓“正则化”在工程中对应的是防止过拟合、提升稳定性的直接操作。它正是“模型复杂度控制”在现实系统里的体现。

如果把这一节再说得更像程序员日常一点,那么“训练一个模型”通常至少会有这样一条循环:先在训练集上拟合参数,再到验证集上看效果,再调整特征、正则化强度或阈值,然后重新训练。这个过程会不断重复,直到团队认为模型已经在“拟合能力”和“稳定性”之间达到了一个可接受平衡。这里面真正重要的,是程序员逐渐确认模型没有只记住训练集,而是在新的样本上也保持了相近表现。

因此,在真实工程中,训练往往不是单次动作,而更像一个反复迭代的实验过程。程序员每跑完一轮训练,都会重新检查三个问题:第一,目标函数有没有按预期下降;第二,验证集是否同步改善;第三,当前模型的错误究竟来自优化没做好,还是来自模型形式本身太弱。正是在这个意义上,第一编中的优化、统计推断和泛化理论,才会在工程里真正连成一体。

7. 工程上如何判断这个系统够不够好

一个机器学习系统上线前,团队不会只看一个指标。对于回归任务,常见会同时看平均绝对误差、均方误差、相对误差或分段误差;对于分类辅助任务,则会看准确率、召回率、精确率、AUC 或不同阈值下的业务代价。

但从数学上说,这些指标本质上都在回答同一个问题:我们究竟用什么方式近似衡量总体风险?例如,平方损失会更惩罚大偏差,而绝对误差对异常值更稳健;分类中的召回率和精确率则体现不同类型错误的代价差异。也就是说,评价指标是在重新选择“风险”的刻画方式,不能被当成上线前随手挑出的几个数字。

工程团队通常还会做几类额外检查。第一类是分组误差分析,例如分行政区、分户型、分价格段看误差是否明显不均匀。第二类是时间稳定性检查,例如看最近一个月和过去半年数据上的误差是否明显偏离。第三类是解释性检查,例如某些特征的方向是否符合常识。如果模型给出的“房龄越老价格越高”的线性趋势在大多数区域都成立,那么团队就必须回头检查特征工程和样本分布,而不能只看整体指标漂亮。

这一步的启发在于:工程上的“验收”并不是与理论无关的附加程序,它恰恰是在不断检查模型假设、经验风险、样本代表性与泛化能力之间是否一致。

8. 从这个案例回头看第一编,数学知识究竟是怎样落地的

如果把整个项目重新回看一遍,就会发现第一编中的几乎每一个核心对象都已经进入了工程过程。

首先,所谓“人工智能学习与数学建模”,在这个案例里表现为:业务需求被转成输入空间 $\mathcal X$、输出空间 $\mathcal Y$、样本集和预测函数。没有这一步,工程根本不知道自己在学什么。

其次,监督学习框架在这里表现为:团队以样本对 $(x_i,y_i)$ 为基础,定义损失函数,最小化经验风险,并在训练集、验证集和测试集之间区分拟合、调参与评估。

再次,线性回归与最小二乘在这里构成第一个可用系统。采用它们的目的,是先让任务进入一个可解释、可诊断、可比较的数学框架。

然后,分类模型与概率判别在这里表现为风险分层任务。Logistic 回归让系统不仅能给出“是否高价”的判断,还能给出该判断的概率,从而进入实际决策流程。

最后,统计学习理论与泛化问题则体现在模型选择、正则化、留出测试和分布稳定性检查上。它提醒团队,工程追求的是一个在未来样本上也能稳定工作的系统,而不只是把训练误差压到最低。

因此,这个案例最值得带走的,是一种认识:工程流程并不是数学之外的杂务,它本身就是数学对象在现实中的展开方式。所谓数据准备、训练、评估、上线检查,其实都可以被看作是在一步步逼近第一编已经给出的理论结构。

9. 这个系统还不够好,而这正是第二编出现的原因

尽管到这里为止,我们已经搭出了一个可以工作的房价评估系统,但它仍然很可能不够好。最根本的原因是,真实房价规律往往不是线性的。面积、地段、学区、交通、楼层、房龄和周边配套之间常常存在复杂交互,而这些交互很难被第一编中的线性模型完全表达。

这就意味着,工程团队很快会遇到新的问题:如果线性特征和线性边界不够,我们是否需要做更复杂的特征映射?是否需要进入核方法、非线性表示和无监督结构发现?换句话说,当第一编的工程链真正跑通后,读者自然会感受到第二编为什么必然出现。第二编对应的,正是工程实践顺着第一编继续往前走时必然遇到的下一层问题。

因此,第一编的 section_end 最重要的作用,在于帮助读者建立一种更稳固的直觉:机器学习工程的每一步,都是数学结构在现实世界中的具体化;而当这些结构开始不够用时,后续各编的理论发展也就有了非常自然的工程动因。