机器学习线性回归身高预测:从原理到实战的完整指南
2026/9/23 16:28:38 网站建设 项目流程

简介:这份资源面向机器学习入门者与需要掌握回归建模的开发者,围绕线性回归在身高预测中的完整应用展开。包内共2个文件,包含1个xlsx数据表与1个py脚本,压缩包约80KB,体量轻便,适合快速上手练习。数据表用于记录身高、年龄、性别、体重等影响因素,脚本则借助scikit-learn的LinearRegression类完成数据预处理、模型训练、评估与预测全流程,并涉及MSE、RMSE、R²等指标的使用。读者可据此理解线性模型如何描述变量间依赖关系,掌握分类变量编码、训练测试集划分等关键环节,同时也能延伸思考多项式回归、岭回归及集成方法在复杂场景下的改进空间。目前已有114人学习,适合作为课程实验或自学练手素材。

1. 身高预测这件事,为什么线性回归是最先该跑通的模型

很多人第一次接触机器学习,都是从「用身高预测体重」或者「用父母身高预测孩子身高」这类题目入门的。机器学习线性回归身高预测这个组合之所以经典,是因为它把机器学习的完整流程压缩到了一个足够小、又能跑通的问题里:有连续型输入特征,有连续型输出目标,有明确的误差度量,还有可解释的参数含义。你不需要 GPU,不需要大数据集,一台普通笔记本就能把从数据构造到模型评估的全链路走一遍。

这篇文章面向两类人:一类是刚学完线性回归公式、但不知道代码怎么落地的新手;另一类是想拿身高预测当教学案例或项目原型的从业者。我会把数据构造、模型训练、多项式扩展、正则化、评估指标、常见翻车点全部拆开讲,每一步都给可复现的代码和参数说明。读完你应该能自己搭出一个预测误差在合理范围内的身高预测模型,并且知道什么时候该换更复杂的模型。

2. 从散点到模型:身高预测的数据构造与线性回归原理

2.1 身高预测问题到底在拟合什么

先把问题定义清楚。假设我们有一组样本,每个样本包含若干特征和一个目标值。身高预测最常见的设定有两种:一种是用父母身高预测子女身高,特征是两个连续变量;另一种是用年龄、性别、营养指标等预测儿童身高,特征更多。不管哪种,线性回归要做的就是找到一组权重 w 和偏置 b,使得预测值 ŷ = w·x + b 尽可能接近真实值 y。

这里的关键假设是:目标值和特征之间存在近似线性关系。如果真实关系是强非线性的,比如身高随年龄先快后慢地增长,直接用一条直线去拟合就会系统性偏差。所以第一步不是写代码,而是画散点图。我一般会先用 matplotlib 把特征和目标的关系画出来,肉眼判断线性假设是否成立。这一步花两分钟,能省掉后面半小时的调参。

从数学上看,线性回归的求解有两种主流方式:正规方程和梯度下降。正规方程直接解 w = (XᵀX)⁻¹Xᵀy,一步到位,但要求矩阵可逆且特征维度不能太高。梯度下降是迭代逼近,适合大样本和高维场景。身高预测这种小规模问题,两种都能用,但正规方程更容易验证结果对不对。

2.2 用 numpy 手写一版最小可跑通的线性回归

在调库之前,我建议先用 numpy 手写一遍。这样你对每个参数的形状、每次更新的方向都会有直觉。下面是一个用正规方程求解的最小实现:

import numpy as np # 构造模拟数据:父亲身高、母亲身高 -> 子女身高 np.random.seed(42) n = 200 father = np.random.normal(172, 6, n) mother = np.random.normal(160, 5, n) # 真实关系:子女身高约等于父母均值加一点噪声 child = 0.5 * father + 0.4 * mother + 20 + np.random.normal(0, 3, n) # 组装特征矩阵,加一列全1用于偏置 X = np.column_stack([father, mother, np.ones(n)]) y = child # 正规方程求解 w = np.linalg.inv(X.T @ X) @ X.T @ y print("权重:", w) # 预测并计算均方误差 y_pred = X @ w mse = np.mean((y - y_pred) ** 2) print("MSE:", mse)

这段代码的逻辑很直接:先把父母身高拼成特征矩阵,再补一列全 1 作为偏置项,然后用正规方程公式一次性解出权重。参数说明上,np.random.seed(42)保证每次运行数据一致,方便你对照结果;np.column_stack把三列拼在一起,顺序要和后面权重的解读对应;np.linalg.inv求逆,如果矩阵接近奇异会报错,这时候要么去掉冗余特征,要么改用np.linalg.pinv求伪逆。

跑完之后你会得到三个权重,前两个分别对应父亲和母亲身高的贡献,第三个是偏置。如果数据构造合理,权重应该接近 0.5、0.4、20 附近。这就是线性回归可解释性的体现:每个权重告诉你该特征每变化一个单位,预测值平均变化多少。

2.3 用 scikit-learn 落地标准流程

手写版帮你理解原理,实际项目里我一般直接用 scikit-learn,因为它的接口统一、评估工具齐全、后续换模型也方便。下面是一个完整的训练和评估流程:

from sklearn.linear_model import LinearRegression from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error, r2_score import numpy as np # 沿用上面的 father、mother、child 数据 X = np.column_stack([father, mother]) y = child # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) # 训练模型 model = LinearRegression() model.fit(X_train, y_train) # 预测与评估 y_pred = model.predict(X_test) print("系数:", model.coef_) print("截距:", model.intercept_) print("MSE:", mean_squared_error(y_test, y_pred)) print("R2:", r2_score(y_test, y_pred))

这里有几个参数值得注意。test_size=0.2表示留出 20% 做测试,身高预测这种小数据集一般用 8:2 或 7:3,不要用 9:1,否则测试集太小,评估结果波动大。random_state=42固定划分,保证你复现时结果一致。r2_score衡量模型解释了目标值多少方差,越接近 1 越好,但身高预测里能到 0.7 以上就算不错了,因为身高受遗传、营养、环境等多因素影响,父母身高只是其中一部分。

如果你发现 R2 很低,先别急着换模型,检查三件事:特征是否漏了关键变量、数据里有没有异常值、线性假设是否成立。这三件事比调模型参数重要得多。

3. 多项式回归与正则化:当直线不够用时怎么加料

3.1 身高和年龄的关系为什么需要多项式

用父母身高预测子女身高,线性假设基本够用。但如果你做的是儿童身高预测,特征里包含年龄,线性模型就会翻车。因为身高随年龄的增长是典型的 S 型曲线:婴儿期长得快,儿童期平稳,青春期又加速,成年后停止。用一条直线去拟合,低龄段会高估,青春期中段会低估。

这时候常见做法是加多项式特征。比如把年龄这一列扩展成年龄、年龄²、年龄³,让模型自己去拟合曲线的不同弯曲程度。scikit-learn 提供了PolynomialFeatures来做这件事:

from sklearn.preprocessing import PolynomialFeatures from sklearn.pipeline import make_pipeline from sklearn.linear_model import LinearRegression # 假设 age 是年龄特征,height 是身高目标 age = np.random.uniform(2, 18, 300) height = 75 + 12 * age - 0.4 * age ** 2 + np.random.normal(0, 2, 300) X = age.reshape(-1, 1) y = height # 构造二次多项式并训练 poly_model = make_pipeline( PolynomialFeatures(degree=2, include_bias=False), LinearRegression() ) poly_model.fit(X, y) print("R2:", poly_model.score(X, y))

degree=2表示扩展到二次项,include_bias=False是因为 LinearRegression 自己会处理截距,不需要多项式再生成一列全 1。用make_pipeline把两步串起来,预测时不用手动做特征转换,少一个出错环节。

但多项式次数不是越高越好。次数太高会过拟合:训练集 R2 很漂亮,测试集一塌糊涂。我一般会从 2 次开始试,画学习曲线看训练和验证误差的差距,差距大就降次数或者加正则化。

3.2 岭回归和 Lasso 在身高预测里的选择

正则化是解决过拟合的标准手段。岭回归在损失函数里加 L2 惩罚,让权重整体变小但不为零;Lasso 加 L1 惩罚,会把不重要的特征权重压到零,相当于自动做特征选择。身高预测里,如果你扩展了很多多项式项和交互项,Lasso 能帮你筛掉没用的项,岭回归则更适合所有特征都有点用、但需要控制幅度的情况。

from sklearn.linear_model import Ridge, Lasso from sklearn.preprocessing import StandardScaler # 多项式扩展后用岭回归 ridge_model = make_pipeline( PolynomialFeatures(degree=3, include_bias=False), StandardScaler(), Ridge(alpha=1.0) ) ridge_model.fit(X_train, y_train) print("Ridge R2:", ridge_model.score(X_test, y_test)) # Lasso 版本 lasso_model = make_pipeline( PolynomialFeatures(degree=3, include_bias=False), StandardScaler(), Lasso(alpha=0.1, max_iter=10000) ) lasso_model.fit(X_train, y_train) print("Lasso R2:", lasso_model.score(X_test, y_test))

alpha是正则化强度,越大惩罚越重。岭回归的 alpha 一般从 0.1 到 10 之间调,Lasso 的 alpha 更敏感,通常从 0.001 到 1 之间试。StandardScaler不能省,因为多项式项的数值范围差异很大,不标准化的话正则化会偏向惩罚数值大的项,结果不可信。Lasso 还要设max_iter,默认迭代次数在特征多时可能不够,会报收敛警告。

选岭回归还是 Lasso,我的经验是:如果你不确定哪些特征有用,先用 Lasso 看它把哪些权重压成零,再用岭回归做最终模型。两者都试一遍,对比测试集 R2,花不了多少时间。

3.3 特征标准化与交互项:别让量纲毁了模型

身高预测里如果特征只有父母身高,量纲一致,不标准化问题不大。但一旦加入年龄、体重、营养指数,量纲差异就出来了。体重可能是几十,年龄是个位数,不标准化的话梯度下降会震荡,正规方程虽然不受影响,但正则化会失真。

标准化的做法是减均值除标准差,scikit-learn 的StandardScaler默认就是这么干的。注意标准化要在训练集上 fit,然后 transform 测试集,不能拿全体数据一起 fit,否则测试集信息泄漏到训练过程,评估结果会偏乐观。

交互项是另一个容易被忽略的点。父母身高对子女身高的影响可能不是简单相加,而是有交互:父亲高且母亲高时,子女可能比单纯相加预测的更高。加交互项可以让模型捕捉这种协同效应。PolynomialFeaturesinteraction_only=True参数可以只生成交互项不生成平方项,适合你想控制特征数量的时候。

4. 评估与调参:身高预测模型到底准不准

4.1 MSE、MAE、R2 三个指标各看什么

训练完模型,第一个问题就是「准不准」。回归问题常用的三个指标是 MSE、MAE 和 R2。MSE 是均方误差,对大误差惩罚重,适合你特别在意大偏差的场景;MAE 是平均绝对误差,单位跟目标值一致,身高预测里 MAE 等于 3 就表示平均预测偏差 3 厘米,直观好懂;R2 是决定系数,衡量模型比「直接猜平均值」好多少。

我一般三个都看。MAE 用来跟业务方沟通,比如「平均误差 2.8 厘米」;MSE 用来对比不同模型,因为它对误差更敏感;R2 用来判断模型是否值得上线,低于 0.5 基本说明特征不够或关系非线性。注意 R2 在测试集上可能为负,表示模型比猜平均值还差,这时候别怀疑指标,直接回去检查数据和特征。

4.2 交叉验证怎么做才不白跑

单次划分训练测试集有个问题:划分方式不同,评估结果可能差很多。交叉验证能缓解这个问题。K 折交叉验证把数据分成 K 份,每次拿 K-1 份训练、1 份验证,循环 K 次取平均。身高预测这种小数据集,我一般用 5 折或 10 折。

from sklearn.model_selection import cross_val_score scores = cross_val_score( ridge_model, X, y, cv=5, scoring='neg_mean_absolute_error' ) print("MAE 各折:", -scores) print("平均 MAE:", -scores.mean())

scoring='neg_mean_absolute_error'是因为 scikit-learn 的交叉验证默认分数越大越好,而 MAE 越小越好,所以取负。打印时再取负还原。cv=5表示 5 折,数据量少于 200 时用 5 折,多于 1000 可以用 10 折。如果各折分数波动很大,说明数据分布不均匀或者样本太少,这时候要考虑增加数据或检查异常值。

4.3 学习曲线告诉你该加数据还是加特征

调参调到一定程度,你会遇到瓶颈:不管怎么调 alpha 或 degree,测试集 R2 就是上不去。这时候该判断是数据不够还是特征不够。学习曲线能帮你做这个判断:横轴是训练样本数,纵轴是误差,画两条线,一条训练误差,一条验证误差。

如果两条线都高且接近,说明欠拟合,模型太简单,该加特征或提高多项式次数。如果训练误差低、验证误差高且差距大,说明过拟合,该加数据或加正则化。如果验证误差还在下降但没到底,说明加数据还有用。这个判断比盲目调参有效得多,我一般会在项目初期就跑一次学习曲线,确定后续投入方向。

5. 避坑与排查:身高预测里最容易翻车的五个地方

5.1 现象:模型在训练集上 R2 0.95,测试集只有 0.3

原因:过拟合。多项式次数太高,或者特征太多而样本太少,模型把训练集的噪声也学进去了。

解决:先降多项式次数,从 3 降到 2 或 1;再加正则化,岭回归 alpha 从 1 开始往上调;最后检查样本量,特征数是样本数的十分之一以下比较安全,超了就减特征或加数据。

5.2 现象:预测出来的身高出现负数或者 250 以上

原因:特征量纲没统一,或者测试集里有训练集没见过的极端值,模型外推到了不合理区域。

解决:加StandardScaler做标准化;检查训练集和测试集的特征分布,用箱线图看有没有离群点;对预测结果做业务裁剪,比如身高限制在 100 到 220 之间,超出就标记为异常而不是直接输出。

5.3 现象:交叉验证各折分数差距很大,从 0.2 到 0.8

原因:数据划分不均匀,某些折里集中了特殊样本,或者样本量太小,随机波动大。

解决:改用分层划分,如果是分类问题用StratifiedKFold,回归问题可以按目标值分箱后再分层;增加样本量;检查是否有重复样本或数据泄漏,比如同一个人的多条记录被分到了不同折。

5.4 现象:Lasso 把所有权重都压成零了

原因:alpha 太大,惩罚过重,模型退化成只剩截距。

解决:减小 alpha,从 0.001 开始试;先做标准化,否则量纲大的特征会被优先惩罚;检查特征之间是否高度相关,共线性严重时 Lasso 会随机保留一个而压掉其他,这时候改用岭回归更稳。

5.5 现象:训练时没有报错,但预测结果和手算对不上

原因:特征顺序搞错了。训练时特征矩阵的列顺序是 [父亲, 母亲],预测时传成了 [母亲, 父亲],模型照常输出但结果是错的。

解决:用 DataFrame 而不是裸 numpy 数组来管理特征,列名跟着数据走;或者在预测前打印model.feature_names_in_确认顺序;把特征组装和预测封装成一个函数,避免手动拼列。

6. 把身高预测模型用起来:从脚本到可复用的预测函数

前面讲的都是训练和评估,但实际用的时候,你需要的是一个输入父母身高、输出预测身高的函数,而不是每次重新跑训练脚本。我一般会把训练好的模型和标准化器一起保存,然后写一个干净的预测接口。

import joblib # 保存模型和标准化器 joblib.dump(ridge_model, 'height_model.pkl') # 加载并预测 def predict_height(father_cm, mother_cm): model = joblib.load('height_model.pkl') X_new = np.array([[father_cm, mother_cm]]) return model.predict(X_new)[0] print(predict_height(178, 165))

joblib比 pickle 更适合保存 numpy 数组多的模型,速度快、文件小。预测函数里把加载模型放在函数内部是为了演示,实际服务里应该只加载一次,常驻内存。输入参数用厘米,输出也是厘米,单位统一,避免调用方混淆。

如果你想进一步提升精度,可以试三个方向:一是加特征,比如祖父母身高、出生体重、青春期启动年龄;二是换模型,梯度提升树或随机森林在表格数据上通常比线性回归强,但可解释性下降;三是做分性别建模,男女性身高增长曲线不同,分开训练往往比混在一起效果好。不过在做这些之前,先把线性回归的基线跑稳,知道基线在哪,才知道复杂模型带来的提升值不值得。

我自己在这个问题上踩过最深的坑,是早期拿到数据直接上模型,没画散点图,结果特征和目标明显是曲线关系,线性回归怎么调 R2 都上不去,白白花了一下午调参。后来养成习惯,任何回归任务先画图,两分钟的事,能省几小时。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询