ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

红酒数据集数据分析大作业:相关性、回归与KNN分类全流程

红酒数据集数据分析大作业:相关性、回归与KNN分类全流程

简介:围绕红酒数据集展开的数据分析大作业文档,面向统计学、数据科学课程学习者及需要完成课程设计的本科生,聚焦红酒评分影响因素与分类标准的建模分析。压缩包内共1个docx文件,约202KB,以实验报告形式组织,便于查阅、摘录和二次修改。文档从11项物理属性与0~10分感官评分的关联入手,串联相关性分析、多元线性回归、主成分回归及KNN简单分类的完整分析链条,并讨论变量降维、模型拟合优度与预测检验等关键环节。已有4271人学习或下载,适合作为课程作业参考、回归与分类方法对照,以及报告写作框架借鉴。需注意资源为单一文档,不含原始数据与代码附件,读者可据此理解分析思路与结论呈现方式。

1. 从一份评分表开始:这个红酒数据集凭什么撑起一份数据分析大作业

数据分析大作业最容易卡在选题:数据要能公开拿到,要有连续变量撑起回归,要有一个类别标签撑起分类,最后最好还能落到一句能被追问的结论上。红酒理化指标数据集三样都占——11 项理化指标加一个 0 到 10 的感觉评分,够做相关性分析、多元线性回归、主成分回归,还能用 KNN 做一次评分档位的分类。这份方案的定位很直接:给要交数据分析大作业、课程设计的人一条从读表到验收的完整路径,每一步都有可复现的代码和判断标准,而不是跑完summary()就交差。整套流程用 Python 做数据搬运和 KNN,用 R 做统计建模,两个工具各干各擅长的事,最后落在「怎么验收、答辩会被问什么」上。

2. 数据准备与字段体检:11 个理化指标的口径、量纲与分布

2.1 变量字典:x1 到 x11 先落成有物理含义的字段

拿到一张宽表就急着跑模型,是这类作业最常见的起手式错误。原始数据集的列名是英文长名,空格、大小写、缩写混在一起,R 里写公式时全是反引号,主成分还原系数时顺序还容易对错。我一般先做一张变量字典,把每个字段压成 x1 到 x11 的短代号,同时把物理含义、量纲和典型范围写清楚,后面所有代码、表格、答辩 PPT 都统一用这一套代号,不会出现「第 9 列到底是 pH 还是密度」这种扯皮。

代号含义均值标准差
x1非挥发性酸度8.36231.7415
x2挥发性酸度0.52730.1791
x3柠檬酸0.27190.1947
x4残糖2.53711.4103
x5氯化物0.08780.0471
x6游离二氧化硫15.705410.4627
x7总二氧化硫46.403732.9041
x8密度0.99680.00189
x9pH 值3.3090.154
x10硫酸盐0.65830.1695
x11酒精10.41141.0657
q感觉评分3 到 8 分,集中在 5、6—

这张表不只是给人看的。后面做方差、做标准化、做主成分系数还原,处处要用到均值和标准差,与其到 R 里现敲mean()和sd(),不如现在就算好固定下来,写进脚本常量。这样别人复现你的结果时,不会因为princomp的cor参数改了一位就整个还原公式错位。

量纲差异是我在体检阶段最关心的一件事。x7 总二氧化硫的标准差是 32.9,x8 密度的标准差是 0.00189,两者差四个数量级。任何基于欧氏距离的方法(KNN 就是)如果直接拿原始值算,距离几乎完全由 x7 这一列决定,其余十项等于没参与。这一点在第 5 章的排查里还会再出现一次,是 KNN 准确率上不去的第一嫌疑人。

2.2 从 csv 到 xlsx:一次格式转换解决 R 读表的坑

原始文件是 csv,分隔符不是逗号而是分号,R 里直接read.csv不显式指定sep = ";"就会把整行读成一列。R 的readxl读 xlsx 不依赖外部 Java 环境,字段类型判断也稳,所以我在 Python 侧先把 csv 转成 xlsx,顺便把列名换成短代号,一次解决分隔符、编码、列名三件事。

import pandas as pd # 原始文件用分号分隔,必须显式指定,否则整行被读成一列 raw = pd.read_csv("winequality-red.csv", sep=";") # 长列名统一压成 x1..x11 和 q,后续 R 公式和系数还原都按这套代号走 raw = raw.rename(columns={ "fixed acidity": "x1", "volatile acidity": "x2", "citric acid": "x3", "residual sugar": "x4", "chlorides": "x5", "free sulfur dioxide": "x6", "total sulfur dioxide": "x7", "density": "x8", "pH": "x9", "sulphates": "x10", "alcohol": "x11", "quality": "q", }) # 只保留约定的 12 列,多余列一律不带进模型 raw = raw[["x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "q"]] raw.to_excel("redwine.xlsx", sheet_name="Sheet1", index=False) print(raw.shape, raw.dtypes.value_counts())

这段脚本有两个地方值得说。sep=";"不是可选项,是必须项,判错的直接表现是df.shape变成(行数, 1),一眼能看出来;raw[...]那次显式选列的作用是锁定列顺序,后面主成分的均值向量、特征向量都按这个顺序排,一旦中间有人插了一列,还原出来的系数就全对不上号了。打印shape和dtypes是给自己留一个读数手感:行数对不对、有没有整列变成 object 类型(说明混进了脏字符),五秒钟的事,能省掉后面半小时的排查。

转出来的文件用Sheet1作表名,是因为 R 的read_excel默认读第一个 sheet,起个明确名字比事后 debug 强。

2.3 评分分布体检:集中在 5 分和 6 分意味着什么

q是这篇作业里唯一的有监督标签,它的分布决定了后面所有评价指标该怎么读。先看一眼分布,再决定用什么指标。

library(readxl) df <- read_excel("redwine.xlsx", sheet = 1, col_names = TRUE) table(df$q) # 每个评分档位的样本数 prop.table(table(df$q)) # 换算成占比,更直观 mean(df$q); sd(df$q) # 均值和标准差,写进报告第一段

跑出来的结论很明确:评分落在 3 到 8 分之间,5 分和 6 分占掉绝大多数,高分档(7、8)和低分档(3、4)都是少数。这个分布特征会引出两个后果,必须在报告里主动交代,而不是等老师问。

第一,分类任务的准确率不能只看绝对值。如果 5 分和 6 分合计占到六成以上,那么一个什么都不学、把所有样本都猜成 6 分的「模型」也能拿到六成左右的准确率。所以任何 KNN 的准确率都必须和一个基准对比,基准就叫多数类基线(majority baseline),算法跑出来只比基线高几个百分点,那这几个百分点才是它真正的贡献。

第二,回归任务里极端评分样本太少,模型会向中间收缩,预测值天然集中在 5 到 6 之间,这是评分数据的常见现象,不是模型写错了。理解这一点,后面看到 R² 只有 0.6589 时才不会慌。

提示:分布体检这一步的产出要写进报告,一句「样本在评分档位上分布不均,多数类占比约六成」比一堆模型参数更能体现你懂数据。

3. 相关性分析:用 Spearman 矩阵决定砍掉哪三个变量

3.1 为什么用 Spearman 而不是 Pearson

相关性分析的目的是筛变量,筛完要降维,所以这一步的方法选择必须站得住脚。数据集里的自变量大致是连续型的理化指标,但因变量q是 3 到 8 的整数评分,本质上是一个有序等级,不是连续正态变量;自变量里残糖、总二氧化硫、游离二氧化硫的分布也明显右偏,长尾很重。

Pearson 相关系数度量的是线性关系,对离群点敏感,两列变量要是单调但非线性(比如先快后慢),Pearson 会低估。Spearman 先把每列转成秩再算相关,只看单调趋势不看具体数值,正好匹配「评分等级 + 偏态指标」这个组合。这一条在答辩时被问到的概率很高,答案就一句话:因变量是有序等级,自变量有偏态,用秩相关更稳。

3.2 相关矩阵的代码与读法

整张相关矩阵的计算在 R 里只有一行,难点全在读法。

# 全部 12 列一起算秩相关矩阵 cor_mat <- cor(df, method = "spearman") # 只取与评分 q 相关的那一列,按绝对值从大到小排序 q_cor <- cor_mat[, "q"] q_cor <- q_cor[order(abs(q_cor), decreasing = TRUE)] round(q_cor, 3)

输出是一列长度 12 的数值(含 q 与自己的相关,恒为 1)。读数的时候我按三档处理,而不是盯着一两个小数纠结:

与 q 的秩相关处置说明
接近 0(绝对值很小)优先剔除对评分几乎没有单调影响,留着只会增加维度
中等保留进全变量模型观察单独看弱,但可能和其他变量组合后有用
明显偏高单独建模的核心变量与评分关系最直接

按这个规则落到这份数据上:x4 残糖、x6 游离二氧化硫、x9 pH 值与评分的相关性都不高,可以先剔除,达到降维目的;x2 挥发性酸度、x10 硫酸盐、x11 酒精三项与评分的相关性明显更高,是后面精简模型的主力。其余变量的相关性居中,不急着在相关性阶段就砍掉,留到回归阶段靠 t 检验来裁决,这比在相关性阶段凭感觉砍要严谨得多。

这里有个容易被忽略的细节:cor(df, method = "spearman")要求每一列都是数值型。如果read_excel把某一列读成了字符(比如某行混进了「N/A」),cor会直接报错而不是给你一个 NA,报错信息还不一定指向那一列。稳妥的做法是先跑一遍str(df)确认全列数值,再算相关。

3.3 变量之间的共线先兆:pH 与非挥发性酸

自变量的相关矩阵比自变量与因变量的那一列更有信息量,因为它提前告诉你会不会踩共线性这个坑。

# 只看几组在酿酒常识上就有关系的变量 round(cor_mat[c("x1", "x9", "x8", "x11"), c("x1", "x9", "x8", "x11")], 3)

结果里有两个现象值得写进报告:pH 与 x1 非挥发性酸度的相关性很高,因为非挥发性酸本身就是决定酸度水平的主体成分,数据里这一项的含量也偏高;酒精 x11 与密度 x8 存在明显相关,酒精浓度上去,液体密度自然下来,这是物理常识,不是数据错误。

这两组高相关意味着什么?意味着后面做多元线性回归时,x1 和 x9 同时进模型,会互相「抢」解释权:两个变量说的是同一件事,模型给出的系数会一个正一个负、数值忽大忽小,标准误被撑大,t 检验跟着不显著。这就是第 4 章全变量模型里部分参数通不过检验的直接原因,也是主成分回归这条路线存在的理由。相关性分析阶段先把这层关系讲清楚,比在回归结果里看到一堆不显著再回头找原因要舒服得多。

4. 回归建模:从 8 变量全模型到 3 变量精简模型

4.1 全变量回归:8 个变量里谁没通过检验

剔除与评分相关性低的三项后,剩下的 8 个变量先全部塞进模型,看一遍整体情况。

# 剔除 x4、x6、x9 后的全变量模型 lm.sol <- lm(q ~ x1 + x2 + x3 + x5 + x7 + x8 + x10 + x11, data = df) summary(lm.sol)

summary()里有三块要看:Coefficients 表的Pr(>|t|)列告诉你每个变量单独是否显著;Multiple R-squared告诉你整体解释了多少方差;F-statistic的 p 值告诉你模型整体是否成立。这份数据跑出来,部分变量的系数没通过 t 检验,p 值偏大。

没通过检验不等于「这个变量没用」,更常见的原因是它和别的变量挤在一起了。x1 与 x9 高度相关,放进同一个模型里,两个都变得不显著是很典型的表现;x3 柠檬酸均值只有 0.27、标准差 0.19,本身波动小,解释力自然弱。处理办法不是一口气全删,而是一次剔一个:删掉 p 值最大的那个,重跑,看 R² 掉了多少、其余变量的显著性有没有改善,如此往复。一次性删五个变量,最后说不清是哪个变量在起作用。

4.2 三变量精简模型:R²=0.6589 该怎么读

按相关性排序挑出最直接的三项重跑,模型会干净很多。

# 只用相关性最高的三个变量 lm.sol2 <- lm(q ~ x2 + x10 + x11, data = df) summary(lm.sol2)

三个参数全部通过 t 检验,得到的方程是:

q = 2.61104 - 1.22130 * x2 + 0.67898 * x10 + 0.30920 * x11

R² 为 0.6589。这个数字怎么讲,决定了答辩时是被追问还是被认可。

先说它意味着什么:三个理化指标解释了评分方差的约 66%,剩下 34% 没有被解释。再说为什么不该追求更高:评分是人的感觉评分,品鉴者的个体差异、当天的状态、酒的储存和醒酒条件,这些信息压根没进这张表,模型再复杂也补不上。同时前面已经看到评分集中在 5、6 两档,因变量本身方差有限,R² 天然上不去。把这两条讲清楚,0.6589 就不是「拟合不好」,而是「在只用客观理化指标的前提下,达到了合理水平」。

比 R² 更值得讲的是三个系数的符号。x2 挥发性酸度的系数是负的:挥发酸含量高的时候,酒闻起来会像醋或者洗甲水,口感失衡,评分自然被拉低;x10 硫酸盐的系数是正的:它在酿酒里承担抗氧化、护色、帮助提取风味的角色;x11 酒精的系数也是正的,酒精度适中偏高时口感更饱满。三个符号全部能和酿酒常识对上,这是模型可信度的第一道验证。反过来说,如果哪个系数符号跟常识拧着来,八成是共线性或者量纲出了问题,先别急着解释,先去查数据。

4.3 单点预测:置信区间和预测区间的差别

把一组没参与建模的样本代进去,验证模型能不能用。

# 一组留出来的样本:x2=0.31, x10=0.66, x11=11,实际评分为 6 new <- data.frame(x2 = 0.31, x10 = 0.66, x11 = 11) # 均值的置信区间:这个 x 上所有样本的平均评分落在哪 predict(lm.sol2, new, interval = "confidence") # 单个样本的预测区间:下一个酒样会打几分 predict(lm.sol2, new, interval = "prediction")

两个区间给出的点估计完全一样,宽度差很多。confidence回答的是「在这个理化指标组合下,平均评分是多少」,区间窄;prediction回答的是「再拿一瓶同样指标的酒去评,可能打几分」,要把个体波动也算进去,区间明显宽。这份方案里预测值和实际评分 6 分比较接近,属于合理范围内。

报告里两个区间都写,只给点估计是典型的丢分点。老师问一句「你这个 6.2 分有多大把握」,没有区间就没法回答。另外new这个 data.frame 的列名必须和模型里的变量名完全一致,写成x2 = 0.31而不是volatile.acidity = 0.31,否则predict会报「变量长度不一致」这种让人摸不着头脑的错。

4.4 主成分回归:princomp 提取与系数还原

全变量模型里那几个不显著的系数,根子在共线性。主成分回归的思路是把 11 个自变量先转成互不相关的几个主成分,用主成分去回归评分,再把系数换算回原始变量。

library(readxl) # range 锁定数据区域,避免把表头或空行读进来 wine <- read_excel("redwine.xlsx", sheet = 1, col_names = TRUE, range = "A1:K1559") # cor = TRUE:用相关阵做主成分,等价于先把 11 个变量标准化 wine.pr <- princomp(wine, cor = TRUE) summary(wine.pr, loadings = TRUE)

summary输出的 Cumulative Proportion 那一行是关键,它告诉你前几个主成分累计解释了多少原始方差。这份数据取前五个主成分,累计贡献已经能覆盖绝大部分波动,后面就用 z1 到 z5 五列来建模。取几个主成分没有绝对标准,常规做法是取到累计贡献七成到八成的位置,取得太少信息不够,取得太多又把噪声带回来了。

# 计算每个样本在主成分上的得分 pre <- predict(wine.pr) z1 <- pre[, 1]; z2 <- pre[, 2]; z3 <- pre[, 3]; z4 <- pre[, 4]; z5 <- pre[, 5] # 注意用 df$q 而不是 df[12],按列号取一旦列序变了就悄悄出错 redd <- data.frame(q = df$q, z1, z2, z3, z4, z5) lm.solp <- lm(q ~ z1 + z2 + z3 + z4 + z5, data = redd) summary(lm.solp)

这一步的参数基本都能通过检验,因为五个主成分彼此正交,不存在共线性问题,系数估计非常稳定。代价是主成分没有物理含义,z1 大不代表某个具体指标高,所以结论不能直接讲给做酒的人听,必须还原回原始变量。

XX <- cor(wine) # 原始变量的相关阵,与 princomp(cor = TRUE) 对应 A <- eigen(XX)$vectors # 特征向量,列序对应 z1、z2、... beta <- coef(lm.solp) # beta[1] 是截距,beta[2]..beta[6] 对应 z1..z5 # 均值与标准差,与第 2 章变量字典里的数值保持一致 X.bar <- c(8.3623, 0.5273, 0.2719, 2.5371, 0.0878, 15.7054, 46.4037, 0.9968, 3.309, 0.6583, 10.4114) X.sd <- c(1.7415, 0.1791, 0.1947, 1.4103, 0.0471, 10.4627, 32.9041, 0.00189, 0.154, 0.1695, 1.0657) # 五个主成分对应 A 的前五列,少写一列是最常见的还原错误 coef_z <- (beta[2] * A[, 1] + beta[3] * A[, 2] + beta[4] * A[, 3] + beta[5] * A[, 4] + beta[6] * A[, 5]) / X.sd # 截距也要跟着换算:beta0 = beta[1] - sum(mean * coef) beta0 <- beta[1] - sum(X.bar * coef_z) round(c(beta0, coef_z), 4)

输出第一个数是常数项,后面依次是 x1 到 x11 的系数。这套换算看着绕,逻辑其实就一层:princomp(cor = TRUE)内部先把每个 x 标准化成 (x - 均值) / 标准差,主成分是标准化变量的线性组合,所以还原时系数要除以标准差,截距要减去系数与均值的内积。

两个必须自己校验的点。第一,beta的长度是 6(截距加五个主成分),如果只写到A[, 4],等于漏掉第五个主成分,还原出来的系数全部偏移,而代码不会报任何错,这是我看过的最隐蔽的翻车方式。第二,eigen()给出的特征向量与princomp的载荷在正负号上可能相反,还原前跑一句all.equal(abs(A[, 1:5]), abs(wine.pr$loadings[, 1:5]))确认绝对值一致,符号相反时对结果取负即可,否则系数符号会集体反掉。

还原之后的系数,方向和 4.2 节三变量模型应该大致一致:挥发性酸度为负,硫酸盐和酒精为正。两个模型互相印证,比单个模型的结论更有说服力,这也是主成分回归这条路线在报告里的价值所在——它不一定让预测更准,但它给了共线性一个交代。

5. KNN 分类与常见问题排查:五个特征的距离度量与投票陷阱

5.1 三要素:五个特征、欧氏距离、20 票多数表决

KNN 做的是「给一瓶新酒估个评分档位」这件事,思路是把新样本丢进已有样本里,看离它最近的 k 个邻居都是什么评分,取出现次数最多的那个。三要素定下来,算法的行为就唯一确定了。

特征是 x2 挥发性酸度、x5 氯化物、x7 总二氧化硫、x10 硫酸盐、x11 酒精五项,选这五项是因为它们和评分的关系相对直接,维度也不至于太高。距离用欧氏距离,五个维度做差的平方和再开方。决策规则是 k = 20 的多数表决。

import openpyxl from collections import Counter # 0-based 列索引:x2、x5、x7、x10、x11、q COLS = [1, 4, 6, 9, 10, 11] def load(path, sheet="Sheet1"): """从 xlsx 读数据,返回 [[x2, x5, x7, x10, x11, q], ...]""" ws = openpyxl.load_workbook(path, data_only=True)[sheet] data = [] for r in range(2, ws.max_row + 1): # 第 1 行是表头,从第 2 行开始 rec = [ws.cell(row=r, column=c + 1).value for c in COLS] if any(v is None for v in rec): # 空行、脏行直接跳过 continue data.append([float(v) for v in rec]) return data def knn_predict(train, target, k=20): """target 是长度 5 的特征列表,返回 (评分, 票数)""" d = [] for rec in train: dist = sum((rec[j] - target[j]) ** 2 for j in range(5)) ** 0.5 d.append((dist, rec[5])) d.sort(key=lambda t: t[0]) votes = Counter(label for _, label in d[:k]) return votes.most_common(1)[0]

load里有两个刻意的写法:列索引用 0-based,取值时统一加 1 转成 openpyxl 的 1-based,免得两套下标混着用;遇到None直接跳过而不是填 0,因为填 0 会让这条样本在距离计算中被当成「氯化物为零」的极端值,悄悄污染邻居选择。knn_predict里用Counter.most_common(1)取票王,比自己维护字典再遍历取第一个键要可靠——字典的遍历顺序是插入顺序,不排序直接取第一个,拿到的是「最先被遍历到的评分」,不是「票数最多的评分」。

评估时按行切分训练集和测试集,并且只切一次:

data = load("redwine.xlsx") train, test = data[:1200], data[1200:] hit = sum(1 for rec in test if knn_predict(train, rec[:5])[0] == rec[5]) print("accuracy:", hit / len(test))

跑出来的准确率不算高,这个结果是意料之中的,原因后面几条会逐一说清楚。值得单独记一笔的是「只看距离最近的一个点」的命中率:把 k 改成 1 再跑一遍,如果明显高于 k = 20 的结果,说明邻居圈子拉太大,把远处的噪声也拉进来投票了。这个对比是解释 KNN 表现最简单有力的证据。

5.2 常见问题排查:五条最容易翻车的点

第一条:准确率还不如「全猜 6 分」。现象是 KNN 跑出来 55%,而直接猜多数类能到 60%,看起来算法白写了。原因是评分分布本身就不均匀,5 分和 6 分占绝大多数,多数表决机制天然倾向于把边界样本判给多数类。解决办法是先算出多数类基线写进报告,再补一张混淆矩阵,看模型到底在哪些档位上出错;通常 5、6 之间互错很多,而 7、8 这种少数档几乎全错,这个结论比一个孤零零的准确率有价值得多。把 k 从 1 试到 20,画出准确率随 k 变化的曲线,也能体现你在做实验而不是碰运气。

第二条:距离完全被总二氧化硫一个维度主导。现象是无论怎么调 k,结果几乎不变,像是模型没在学东西。原因是五个特征量纲差异太大:x7 总二氧化硫均值 46.4、标准差 32.9,x5 氯化物均值 0.088、标准差 0.047,两者相差三个数量级,欧氏距离里 x7 的贡献压倒性的大。解决办法是算距离之前先标准化,减均值除标准差,用第 2 章表里的 X.bar 和 X.sd 就行;如果还想更严谨,可以换成马氏距离把特征间的相关性也考虑进去。

# 标准化:减均值、除标准差,让五个特征在距离里等权 MEAN = [0.5273, 0.0878, 46.4037, 0.6583, 10.4114] STD = [0.1791, 0.0471, 32.9041, 0.1695, 1.0657] def norm(rec): return [(rec[j] - MEAN[j]) / STD[j] for j in range(5)]

标准化之后knn_predict收到的 train 和 target 都要是标准化后的值,两边漏一边是最常见的低级错误,表现出来是准确率直接跌到随机水平。

第三条:换一次划分,准确率上下浮动十几个点。现象是今天跑 58%、明天跑 47%,自己都说不清模型到底什么水平。原因是只做了一次留出划分,测试集样本量本来就不大,抽到哪一批全看运气。解决办法是固定随机种子,并且改成 5 折交叉验证取均值,报告里写「5 折交叉验证准确率 52.3% ± 3.1%」,比写一个单次结果可信得多。

第四条:训练集里混进了测试样本。现象是准确率异常地高,高到不像话。原因通常是数据没打乱就按行切,而原始文件恰好按评分排过序,导致训练集和测试集的分布完全不同;或者标准化时用了全量数据的均值和标准差(这叫数据泄漏),把测试集的信息提前泄露给了训练过程。解决办法是划分只做一次并保存索引,标准化的均值方差只用训练集算,测试集套用训练集的参数。

第五条:读表错位,整张表偏了一行。现象是读进来的第一行数据明显不对,或者特征值全是表头文字。原因是 openpyxl 的行列都从 1 开始,如果用for row in range(1, rows)配cell(row + 1, col + 1),实际取到的是第 2 行到第 rows+1 行,整体上移一行,表头被当成数据。解决办法是统一口径:数据行从 2 开始(跳过表头),列索引写 0-based 再统一加 1。写完之后打印前三条记录肉眼看一眼,比什么断言都管用。

注意:排查的顺序建议固定为「先看数据、再看量纲、再看划分、最后才怀疑算法」。这个顺序能覆盖九成以上的问题,反过来先调 k 值基本是白费时间。

6. 验收与答辩:把三个模型讲成一条完整的证据链

验收这件事,我一般按「能不能被别人一条命令复现」来卡。脚本从 csv 读到结果全程无人工干预,中间不出现「这里手动改了一下数值」,才算过关。具体到这份方案,验收清单大致是这样:

验收项合格标准常见不合格表现
数据可复现一条命令从原始 csv 跑到全部图表中间某步手工改了 xlsx
相关性分析给出方法理由 + 变量取舍依据只贴一张热力图,不说为什么用 Spearman
回归模型系数、R²、t 检验、区间预测齐全只报 R²,没有区间
主成分回归系数已还原回原始变量并校验符号停在主成分系数,没还原
分类模型有基线对比、有混淆矩阵、有 k 值实验只报一个准确率数字
结论每条结论都能对应到具体系数结论和模型结果对不上

答辩被问到的题目其实高度集中,提前准备好这四问基本就稳了。为什么用 Spearman 不用 Pearson——因变量是有序等级、自变量有偏态,秩相关更稳。R² 只有 0.66 为什么还说模型可用——评分是主观感觉评分,客观理化指标只能解释一部分,剩下的方差来自品鉴者差异和工艺外因素,同时三个系数的符号全部符合酿酒常识。主成分回归比普通回归强在哪——它不追求更高的 R²,它解决的是共线性导致的系数不稳定,让每个变量的方向能被解释。KNN 的 k 怎么定的——从 1 试到 20,看准确率曲线和基线对比,取稳定区间的中段。

还有一个特别容易被追问的点:你的模型说挥发酸越低、硫酸盐和酒精越高评分越高,那是不是酒厂照着调就能拿高分?答案是不能。模型给的是相关关系,不是因果,而且三个变量都在合理区间内才有意义,酒精无限高只会毁掉平衡感。能主动说出这句边界,比多跑两个模型更能体现你懂自己在做什么。

从那以后我每次带这类作业,都会强制走一遍「结论回指」:报告里每写一条结论,必须在前面找到一个具体的系数或者一个具体的检验结果去

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

返回列表