ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

diabetes数据集线性回归拆解:单特征斜率与R²深度解读

diabetes数据集线性回归拆解:单特征斜率与R²深度解读 拿到sklearn里的diabetes数据集很多人第一件事就是LinearRegression().fit(X, y)看两眼R²然后就没有然后了。波士顿房价数据集被讲烂了之后diabetes成了另一个练手标配但说实话我见过不少人在这个数据集上把回归跑完却连s1到s6代表什么都不清楚更别提回答单个特征值到底和病情是什么关系这种最基础的问题。这篇就围绕这个缺口展开用线性回归把diabetes数据集完整拆一遍重点落在单特征分析上每个特征单独建模时斜率怎么读、R²怎么理解、系数在多元模型里为什么会变脸以及分析过程中那些文档里不会写但实际很容易踩的坑。1. 建模前先搞明白diabetes数据集的10个特征到底在测什么1.1 字段含义s1到s6不是神秘代号是血清指标load_diabetes()返回的数据集来自一项糖尿病疾病进展研究共442个样本每人有10个基线特征。很多人以为s1到s6是某种脱敏后的隐藏变量其实它们对应的是具体的血清检测指标这是理解后续回归系数的前提。特征名缩写生理含义ageage年龄sexsex性别经过编码处理不是直观的0/1bmibmi体质指数bpbp平均血压s1tc总血清胆固醇s2ldl低密度脂蛋白s3hdl高密度脂蛋白s4tch总胆固醇 / HDL 比值s5ltg甘油三酯水平的对数s6glu血糖水平这里有个特别容易被忽略的细节sklearn返回的数据已经做过中心化和标准化处理每一列的均值都接近0标准差接近1。也就是说你拿到的不是原始的生理测量值而是偏离平均水平多少个标准差的数值。这个特点直接影响系数的解读方式——后面我会专门展开。1.2 目标变量y不是有没有糖尿病而是疾病进展的定量指标目标变量target是一年后疾病进展的量化分数范围大约在25到346之间均值约152标准差约77。分数越高代表进展程度越严重。搞清楚这一点很重要因为很多人把它当成是否患病的分类标签但实际上这是一个连续型回归任务。我遇到过有人问这个数据里为什么没有得病/没得病的标签这就是典型的没看数据描述就开始建模。diabetes数据集的定位是回归不是分类。你用它做线性回归预测的是病情进展的严重程度而不是患病概率。2. 建单特征模型之前先花三分钟看图2.1 散点图能告诉你线性假设靠不靠谱线性回归有个隐含前提特征和目标之间大致是线性关系。很多人跳过验证直接拟合结果R²低得可怜还找不出原因。我的习惯是先把关键特征和目标变量画出来看一眼。import matplotlib.pyplot as plt import seaborn as sns fig, axes plt.subplots(2, 2, figsize(12, 8)) for ax, col in zip(axes.ravel(), [bmi, bp, s5, s3]): ax.scatter(df[col], df[target], alpha0.6) ax.set_xlabel(col) ax.set_ylabel(target) plt.tight_layout() plt.show()实际画出来的结果里bmi和s5与病情的正向趋势最明显bp次之s3与病情呈负向趋势。这些都是肉眼可见的关系。如果你画完图发现散点完全是一坨圆形那这个特征单独做线性回归基本不会有好的表现。2.2 相关系数排序先知道谁强谁弱散点图是定性判断相关系数给出定量依据。用.corr()算一下每个特征与target的皮尔逊相关系数特征与target的相关系数单特征R²参考值bmi约0.59约0.34s5约0.57约0.32bp约0.44约0.19s4约0.43约0.18s3约-0.39约0.15s6约0.38约0.15s1约0.21约0.04s2约0.17约0.03age约0.17约0.03sex约0.04约0.00从这张表能看出来bmi和s5是单特征里和病情相关性最高的两个变量而age、sex、s2单独拿出来基本没什么解释力。这为后面的单特征回归画好了重点。3. 逐个特征跑线性回归斜率、截距、R²一起读3.1 用bmi跑通第一个单特征模型先拿相关性最高的bmi演示完整的单特征回归流程from sklearn.linear_model import LinearRegression model LinearRegression() X_bmi df[[bmi]] y df[target] model.fit(X_bmi, y) print(截距:, model.intercept_) print(斜率:, model.coef_[0]) print(R²:, model.score(X_bmi, y))我本地跑出来的结果大致是截距约152斜率约45R²约0.34这里的读法非常关键因为特征经过了标准化所以斜率的含义是bmi每增加1个标准差病情进展分数平均增加约45分。截距152对应的是bmi处于平均水平时标准化后为0的预测值其实就等于target的均值。这解释了为什么截距约等于152——它不是一个有实际意义的当bmi为0时病情152分而是特征取均值时预测的病情基线。3.2 10个特征的单特征回归汇总把10个特征各自单独跑一遍线性回归结果就是一张梳理单个特征值与病情关系的核心参考表特征斜率约方向R²约显著性bmi45正相关0.34极显著s544正相关0.32极显著bp34正相关0.19极显著s433正相关0.18极显著s3-30负相关0.15极显著s629正相关0.15极显著s116正相关0.04显著s213正相关0.03显著age13正相关0.03显著sex3弱正相关0.00不显著这张表就是单个特征值与病情关系这个问题最直白的答案。bmi和s5是单特征模型的王者sex基本没有解释力。3.3 注意标准化数据的斜率可以直接横向比较这里有一个大多数教程不会强调的点因为所有特征都标准化了所以单特征回归的斜率可以直接横向比较。bmi斜率45和s5斜率44可以理解为这两个特征对病情的影响强度接近。如果数据没标准化bmi和s5的单位不同斜率完全没法对比。这也是为什么把数据标准化后做线性回归系数大小本身就携带重要性信息。4. 单特征模型暴露出的三个盲区4.1 线性假设不一定站得住脚跑完单特征回归很多人直接看R²但很少检查残差图。每个单特征模型拟合完都应该画一下残差y_pred model.predict(X_bmi) residuals y - y_pred plt.scatter(y_pred, residuals, alpha0.6) plt.axhline(0, colorred, linestyle--) plt.xlabel(predicted) plt.ylabel(residuals) plt.show()这个散点图如果呈现扇形分布——预测值越大残差越分散——说明可能存在异方差性。糖尿病数据集里这种情况不算严重但我在其他医学数据上经常遇到。扇形残差图意味着线性模型的预测不确定性在病情严重的人群里更大这时考虑加权最小二乘或者对target做变换是更稳妥的做法。4.2 单特征预测的精度上限很低bmi单特征模型R²约0.34意味着它只能解释病情进展约34%的变异。剩下66%的变异来自其他特征和噪声。一个实用的判断标准是R²低于0.1的特征单独建模型基本没有实用价值比如age、sex、s2。这不代表它们和病情无关只是在单变量视角下贡献太小。4.3 相关不是因果医学数据尤其要克制s5甘油三酯对数和病情进展高度正相关s3高密度脂蛋白负相关这些结论只能表述为存在统计关联绝不能写成降低s5就能延缓病情。糖尿病患者血脂指标本身就和疾病严重程度互相缠绕可能存在反向因果病情更重的人代谢更差导致s5升高也可能存在混杂因素bmi同时影响s5和病情。线性回归在这里是描述关联的工具不是证明因果的工具。写结论时用与……相关与……呈正相关而不是导致使得。5. 从单特征到全特征系数变脸背后的共线性5.1 全特征模型的表现用10个特征一起做多元线性回归from sklearn.model_selection import train_test_split X df.drop(target, axis1) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) model_full LinearRegression() model_full.fit(X_train, y_train) print(Test R²:, model_full.score(X_test, y_test))本地复现的Test R²大约在0.48到0.52之间比最好的单特征模型bmi的0.34提升有限。这说明病情进展是个多因素问题但10个特征加起来也没法完全解释它。5.2 同一个特征单模型和全模型的系数为什么不一样单特征回归时bmi的斜率约45在多元回归里它的系数不再等于45。这是因为多元回归的系数是控制其他特征不变时该特征变化一个单位带来的病情变化。如果bmi和其他特征相关——比如bmi高的人往往血压更高、血糖更差——那么单特征回归会把它们的影响也混进bmi的斜率里多元回归则尝试把它们分离开。下面是我本地复现时对比单特征系数和全模型系数的方向变化特征单特征斜率方向全模型系数方向近似bmi显著正正幅度略变s5显著正正仍是最大贡献者之一s3显著负负贡献被其他特征分担s2弱正方向可能变为负s1显著正方向可能变弱甚至反转sex几乎为零保持很弱s2从单特征的弱正相关变成全模型里的负系数这种符号翻转是多重共线性的典型信号。s1和s2都是胆固醇相关指标它们之间高度相关回归算法很难稳定地分配各自的影响。5.3 用相关矩阵的特征值分解诊断共线性这里就用到矩阵特征值分解了。注意机器学习里说的特征值通常指某个样本的某个特征取值而线性代数里的特征值是矩阵的固有属性两个词指的东西不一样。但要诊断特征之间的共线性后者正好派上用场。import numpy as np corr_matrix df.drop(target, axis1).corr().values eigvals np.linalg.eigvalsh(corr_matrix) print(特征值排序后:, np.sort(eigvals)) print(条件数:, np.max(eigvals) / np.min(eigvals))对diabetes数据集10个特征的相关矩阵做特征值分解后最小特征值离0不远条件数最大特征值与最小特征值的比值明显偏高。条件的含义是最小特征值接近0说明特征矩阵在某个方向上几乎是线性相关的也就是特征之间存在近似冗余。具体到diabetes数据集s1、s2、s4都来源于胆固醇代谢彼此高度纠缠这就是共线性的源头。提示如果条件数超过30一般就认为存在较严重的多重共线性。这时线性回归系数虽然还是无偏估计但方差会被放大系数的小幅数据扰动就会剧烈变化解释单个系数要格外小心。6. 实操经验数据划分、复现和结果解释的几个细节6.1 训练集/测试集划分要固定随机种子做多元回归评估时train_test_split的random_state一定要固定。diabetes数据集只有442条样本量不大换一个随机种子R²可能上下浮动好几分。我习惯用random_state42这样别人复现我的结果时能看到完全一样的数字。对于小样本更稳妥的做法是用交叉验证from sklearn.model_selection import cross_val_score scores cross_val_score(LinearRegression(), X, y, cv5, scoringr2) print(交叉验证R²:, scores.mean(), ±, scores.std())做交叉验证能避免运气好划分了一个特别合适的测试集的假象。6.2 评估回归模型别只盯R²R²很直观但它对异常值敏感而且不反映预测误差的实际大小。回归任务至少还要看两个指标指标含义在diabetes数据集上的参考值全特征RMSE均方根误差单位与target一致约55~60MAE平均绝对误差约45左右target标准差约77RMSE约55意味着模型的预测误差幅度大约等于目标标准差的70%。说实话这个精度不算高用它做临床预测远远不够但作为理解线性回归和特征关系的教学案例足够说明问题。6.3 单特征分析结果的呈现技巧我自己的习惯是跑完所有单特征回归后把斜率和R²的汇总表存下来再画一张带误差条的条形图。这样哪个特征和病情关系强、哪个方向、解释力多少一眼就能看清楚。还有一个个人经验一定要对比单特征系数和全特征系数。只给单个特征系数会忽略特征间的相互影响只给全特征系数读者无法直观感受某个特征单独的表现。两个放在一起看能自然看出共线性在中间扮演了什么角色——这也是这篇文章的核心线索。
返回列表