简介:这是一份红酒数据集分析完整大作业资源,面向数据分析初学者和需要完成统计建模作业的高校学生,以单个docx文档呈现从数据预处理、相关分析到回归建模与分类的完整流程。文档先介绍红酒物理属性(非挥发性酸度、挥发性酸度、柠檬酸、残糖、氯化物、二氧化硫、密度、pH、硫酸盐、酒精共11项)与评分(0~10分)之间的关系,通过相关性矩阵识别出挥发性酸度、硫酸盐、酒精是影响评分的关键因素,而残糖、游离二氧化硫和pH值可作降维剔除。接着对比多元线性回归与主成分回归,前者给出p=-1.22130x2+0.67898x10+0.30920x11+2.61104的预测式,后者提取五个主成分并还原为原变量系数,同时展示置信区间和预测区间结果。压缩包内仅含1个docx文件,大小202KB,代码截图与R/Python关键步骤均在文档中标注,方便按步骤复现。已有4265人浏览学习,适合作为红酒品质影响因素分析或数据统计课程设计的直接参考。
1. 红酒数据集分析:这份作业要解决评分预测、属性筛选与分类三个问题
红酒数据集分析是数据分析课程作业里出现频率最高的题目之一,数据公开、变量连续、结论好写,但它真正考验人的地方不在跑代码,而在“怎么从十一个物理属性里找出跟评分真正相关的因素,再用合适的模型把关系表达出来”。我拿到这份《数据分析大作业-红酒数据集的分析》时,完整做了一遍下来的体感是:这个过程天然分成三段——先做相关性分析判断哪些变量值得留下,再做多元线性回归和主成分回归来解释评分,最后用 KNN 做分类作为方法对比。适合正在做课设、需要一份能直接套用完整分析流程的人参考,也适合想看看回归和分类在同一个数据集上怎么衔接的从业者。整套流程从数据读取到模型预测都有可复现的代码。
2. 数据预处理与相关性分析:先看数据分布再谈建模
2.1 从 csv 到 xlsx:数据读取的第一道坎
原始数据集以 csv 格式存储,共 1559 条样本,评分范围为 3 到 8 分,其中绝大多数集中在 5 到 6 分之间。这个分布信息非常重要,后面分析 KNN 准确率偏低时还要回过头来看它。csv 文件可以直接用 read.csv 读取,但原文的处理方式是先用 Python 把 csv 转成 xlsx,再用 R 的 readxl 包读取。这个转换不是多此一举,xlsx 格式在列名识别和调试查看时更直观,尤其在 RStudio 里用 View() 查看数据框时不容易出现中文乱码或列类型识别错误。
import pandas as pd df = pd.read_csv("winequality-red.csv", header=0) df.columns = ["x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "q"] df.to_excel("redwine.xlsx", index=False, sheet_name="Sheet1")这里把列名直接重命名为 x1 到 x11 加上评分 q,是为了后续在 R 里写公式时更简洁。如果你打算保留原始英文列名也可以,但中文列名在 R 的 formula 里会遇到编码问题,我一般会提前重命名。转换完成后用 df.shape 确认行列数,再检查有没有空值和重复行,数据集本身比较干净,这一步通常不会卡住。
2.2 用 spearman 计算相关性:为什么不用 pearson
数据读取进来之后,下一步就是相关性分析。原文用的是 cor() 函数加 method = "spearman",这个选择是有讲究的:pearson 相关系数假设变量之间是线性关系且近似正态分布,而评分 q 是离散的 3 到 8 分整数值,分布明显偏斜,pearson 容易低估变量间的关联强度。spearman 基于秩次计算,对非线性但单调的关系更敏感,在评分这类离散变量上更稳妥。
library(readxl) df <- read_excel("redwine.xlsx", sheet = 1, col_names = TRUE) cor_matrix <- cor(df, method = "spearman") write.csv(cor_matrix, "cor_matrix.csv")cor() 一次计算所有变量两两之间的相关系数,得到一个 12×12 的相关矩阵。建议把矩阵导出成 csv 后,在 Excel 里用条件格式给相关系数上色,高相关变量一眼就能看出来,比盯着 R 控制台里的数字直观得多。相关矩阵中,评分为目标的列是重点观察对象。
2.3 相关性结论如何指导变量取舍
从相关矩阵能得到两组关键结论。第一组是针对评分 q 的相关性:x4(残糖)、x6(游离二氧化硫)、x9(pH)与评分的 spearman 相关系数绝对值较低,可以暂时剔除,达到降维目的;x2(挥发性酸度)与评分呈明显负相关,x10(硫酸盐)、x11(酒精)与评分正相关,这三个变量是后续回归分析的主力。
第二组结论是变量之间的相关性,这同样会影响建模质量。pH 与非挥发性酸度相关性很高,这一点符合化学直觉,非挥发性酸含量高会拉低 pH;酒精含量与密度也有相关性,因为酒精密度低于水,酒精含量越高整体密度越低。变量之间存在相关性意味着后续全变量回归可能出现共线性问题,这也是为什么不能把十一个属性一股脑全部丢进回归模型。
3. 多元线性回归:从全变量回归到三变量模型
3.1 全变量回归为什么不可靠
在完成相关性筛选之后,我先把剩余八个变量做了一次多元线性回归。选择 x1、x2、x3、x5、x7、x8、x10、x11 进入模型,也就是剔除了残糖、游离二氧化硫和 pH。用 lm() 拟合后看 summary() 输出,第一反应是有些变量的系数并没有通过显著性检验,p 值大于 0.05 的变量在模型中属于“留着没帮助、去掉也不影响”的状态。
lm.sol <- lm(q ~ x1 + x2 + x3 + x5 + x7 + x8 + x10 + x11, data = df) summary(lm.sol)问题出在变量之间的共线性上。柠檬酸和非挥发性酸度都跟 pH 强相关,把它们同时放进模型,系数估计会互相拉扯,标准误变大,显著性检验自然不过。这不是模型写错了,而是数据集本身的结构决定的。这时候不要强行解释每个系数的含义,而是退一步做变量筛选。
3.2 三变量回归:显著性通过但决定系数不高
根据相关性分析的结论,筛选出与评分关联最强的三个变量:x2(挥发性酸度)、x10(硫酸盐)、x11(酒精),重新拟合模型。
lm.sol2 <- lm(q ~ x2 + x10 + x11, data = df) summary(lm.sol2)这一次所有参数都通过了 t 检验,模型的拟合方程为:
p = -1.22130 × x2 + 0.67898 × x10 + 0.30920 × x11 + 2.61104
三个变量的方向和业务常识一致:挥发性酸度系数为负,说明挥发酸含量高会让酒闻起来像醋,评分下降;硫酸盐和酒精系数为正,适量亚硫酸盐起到抗氧化、保持风味的作用,酒精则直接关联酒体和口感强度。但模型的 Multiple R-squared 只有 0.6589,意味着评分中约 34% 的变异仍然无法由这三个属性解释。红酒的感官评分还受单宁、香气复杂度、个人偏好等因素影响,而这些没有包含在数据集的物理属性中。
R² 0.6589 这个水平,在红酒评分预测这类偏主观的回归任务里属于中等可用水平。用它判断相对趋势没问题,用它做精确到小数点后一位的评分预测就会露怯。
3.3 用模型预测新样本:置信区间与预测区间的区别
拟合完模型还有个重要动作:用留出的样本做预测验证。原数据读取时专门留下一组数据不参与拟合,这组真实评分为 6 的样本,属性为 x2=0.31、x10=0.66、x11=11。
new <- data.frame(x2 = 0.31, x10 = 0.66, x11 = 11) lm.conf <- predict(lm.sol2, new, interval = "confidence") lm.pred <- predict(lm.sol2, new, interval = "prediction")predict() 函数里 interval 参数取 confidence 和 prediction 会得到两种不同的区间。置信区间描述的是“在 x2、x10、x11 取这组值时,评分条件均值的可能范围”,它的区间较窄;预测区间描述的是“单个新样本评分值的可能范围”,因为叠加了残差波动,区间明显更宽。课程报告里经常有人只贴一行点预测值,我一般建议把两种区间都输出,区分清楚能体现对统计概念的理解。实际预测值与真实值 6 比较接近,说明模型在这组数据上有一定可靠性。
4. 主成分回归:解决共线性并还原原始变量系数
4.1 主成分提取:为什么一定要用相关阵
多元线性回归虽然筛到只剩三个变量,但最初十一个物理属性之间明显存在相关性,直接把所有变量放进回归必然出问题。主成分回归的思路是先把十一个变量压缩成少数几个互不相关的综合变量,再用这几个综合变量对评分做回归。
library(readxl) wine <- read_excel("redwine.xlsx", sheet = 1, col_names = TRUE, range = "A1:K1559") wine.pr <- princomp(wine, cor = TRUE) summary(wine.pr, loadings = TRUE)princomp() 的 cor 参数是决定结果差异的关键点。cor = TRUE 表示基于相关矩阵做主成分分析,先把每个变量标准化成均值为 0、方差为 1 再计算主成分;如果用 cor = FALSE,则基于协方差矩阵,量纲大的变量会主导主成分方向,比如二氧化硫的数值范围远大于酒精,结果会被它带偏。这里必须用 cor = TRUE。summary() 输出的标准差和累计方差贡献率表明,前五个主成分已经能解释数据的大部分变异,因此取前五个主成分进入回归。
4.2 从主成分得分到回归建模:全部通过显著性检验
得到主成分之后,需要先 predict() 求每个样本在各个主成分上的得分,再取前五列作为新的自变量。
pre <- predict(wine.pr) z1 <- pre[, 1] z2 <- pre[, 2] z3 <- pre[, 3] z4 <- pre[, 4] z5 <- pre[, 5] 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)这次回归的结果里参数基本都通过了显著性检验,整体拟合优度比直接回归更稳定。主成分之间相互正交,解决了原变量间的共线性问题,这是主成分回归的内在优势。不过这里有个细节容易翻车:主成分变量的取值是原始变量标准化后的线性组合,数据范围差异很大,直接用 summary 里输出的系数去解释“某个主成分增加一个单位评分变化多少”没有实际业务含义,主成分本身只是数学构造,不直接对应某个物理属性。
4.3 系数还原:把主成分空间拉回原变量空间
主成分回归最大的坑在于:模型最终要能对原始属性做解释,但拟合出来的系数是在主成分空间里的。如果只报告“z1 到 z5 的系数”,导师一定会追问“那原变量的系数是多少”。还原方法是用主成分系数的加权组合,结合每个变量的均值和标准差。
XX <- cor(wine) A <- eigen(XX)$vectors beta <- coef(lm.solp) 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) coef_value <- (beta[2] * A[, 1] + beta[3] * A[, 2] + beta[4] * A[, 3] + beta[5] * A[, 4]) / X.sd beta0 <- beta[1] - sum(X.bar * coef_value) c(beta0, coef_value)还原逻辑是这样的:主成分 Z 等于原始变量 X 标准化后的线性组合,即 Z = A' × (X - X.bar) / X.sd,其中 A 是相关矩阵的特征向量矩阵。回归模型是 q = β0 + β1 × z1 + β2 × z2 + ...,把 Z 的表达式代进去展开,就能得到 q 关于原始 x 的线性表达式。A[, 1] 到 A[, 4] 对应前四个特征向量,beta[2] 到 beta[5] 是回归系数。展开后常数项合并为 beta0,每个变量的系数是特征向量和回归系数的加权和再除以标准差。最终结果会给出一个带常数项的输出,这就是主成分回归在原始变量空间的等价表达式。
很多资料到这一步就停了,只告诉你“主成分回归结果不错”,不告诉你系数怎么换算回去,导致报告里留下一块黑匣子。
5. KNN 分类实现与避坑:准确率不高时先排查这几点
5.1 KNN 实现:特征选择、距离度量与多数表决
KNN 用在新样本分类上的逻辑直观:找到训练集中与测试样本距离最近的 K 个已知样本,让这 K 个样本通过多数表决决定新样本的类别。原文把评分当作类别标签,选择 x2(挥发性酸度)、x5(氯化物)、x7(总二氧化硫)、x10(硫酸盐)、x11(酒精)五项属性计算欧氏距离,取距离最近的 20 个点,以这 20 个点中出现次数最多的评分作为预测结果。
import openpyxl def read_excel(input_file_name): workbook = openpyxl.load_workbook(input_file_name) table = workbook["Sheet1"] objects = [] for row in range(1, table.max_row): obj = [] for col in range(table.max_column): if col in (1, 4, 6, 9, 10, 11): obj.append(table.cell(row + 1, col + 1).value) objects.append(obj) return objects def knndis(nowa, objects): distances = [] for item in objects: dist = sum((item[j] - nowa[j]) ** 2 for j in range(5)) ** 0.5 distances.append(dist) return distances def classify(nowa, objects, k=20): distances = knndis(nowa, objects) sorted_idx = sorted(range(len(distances)), key=lambda i: distances[i]) votes = {} for i in sorted_idx[:k]: label = objects[i][5] votes[label] = votes.get(label, 0) + 1 return max(votes, key=votes.get)read_excel 里 col in (1, 4, 6, 9, 10, 11) 对应 x2、x5、x7、x10、x11 这五个特征在原始表里的位置,objects[i][5] 是这条样本的评分标签。knndis 计算欧氏距离时注意五点同时相减再求和开方,每一个维度的量纲差异都直接影响距离。原始代码里手动把最小距离改成 100 来模拟“移除已选点”,sort 加切片更干净,效果相同。
5.2 避坑一:评分分布不均衡让“准确率”失去意义
现象:KNN 总体准确率很低,看起来像是分类器完全失效。
原因:这个数据集的评分大量集中在 5 和 6 分,3 分和 8 分的样本极少。模型在多数表决时天然偏向频率高的类别,即使距离最近的一批样本里有几个 7 分,也会被更多的 5 分和 6 分“淹没”。准确率被少数类别的稀疏分布拉低,不代表模型完全没有区分能力。
解决:先画评分分布直方图,确认类别均衡情况。对不均衡数据,报告里不建议只报整体准确率,改成按评分值分别计算召回率,或报告“最近邻评分分布”。原文在测试中也发现:如果只看距离测试点最近的那个点的评分,准确度明显更高,这个观察正好说明问题不在算法实现,而在类别分布。
5.3 避坑二:特征和评分相关性强弱直接影响距离度量
现象:无论怎么调 K,预测结果都和真实评分对不上,距离计算看起来像是在“随机找邻居”。
原因:KNN 的距离是五个特征维度上的综合距离,如果某些特征与评分几乎不相关,它们贡献的距离反而成为噪音。比如氯化物和总二氧化硫跟评分的相关性很弱,这两个维度在距离中的存在相当于把样本在无关方向上拉开,真正与评分相关的挥发性酸度、硫酸盐、酒精的信号被稀释了。
解决:结合第 2 章的相关性分析结果选择特征。既然相关性分析已经告诉我们 x2、x10、x11 和评分关联最强,可以先只用这三个特征做距离度量,再看准确率变化。如果结果变好,说明降维对 KNN 同样有效。这个实验对比写进课设里很有说服力:线性回归里的变量筛选结论,在 KNN 里被再次验证。
5.4 避坑三:K 值取太大反而比 1 近邻差
现象:K=20 时准确率平平,尝试 K=1 只看最近邻反而和真实评分吻合得更好。
原因:评分数据本身是 3 到 8 的离散整数,相邻评分之间的差异只有 1 分,K 越大引入的“远亲”越多,多数表决结果容易向众数类别收敛,等于把分类退化成了“猜 5 分 6 分”。K 值过大的本质是偏差和方差的权衡,对类别密集的评分数据来说,K=20 过于平滑。
解决:把 K 作为超参数扫一遍,从 1 到 30 逐个测试,记录每个 K 值的准确率曲线。你会发现 K 从 5 到 10 之间通常会有一个相对更好的平台,再往上走准确率反而下降。这段调参过程应当截图放进报告,它展示了 KNN 三要素中 k 值选择的实际影响,比单纯给结论更有说服力。距离度量方式也一样,尝试曼哈顿距离或加权距离(距离越近权重越大),对比结果后选一个解释最顺的。
6. 验收与答辩:如何把分析流程讲清楚并扛住追问
课程设计或大作业交上去之后,最怕的不是代码跑不出来,而是被问到“为什么这么做”时答不上来。验收前建议把整个分析过程压缩成一条故事线:从 1559 条样本、11 个属性、评分 3 到 8 分的数据现状出发,先通过 spearman 相关性分析筛掉与评分弱相关的残糖、游离二氧化硫和 pH,再用筛选后的三变量做多元回归得到方程 p = -1.22130x2 + 0.67898x10 + 0.30920x11 + 2.61104,接着用主成分回归解决变量共线性并还原原始系数,最后用 KNN 做分类对比。这条线每一环都在回答上一个结论遗留的问题,讲的时候按这条线走,导师跟着你的逻辑走就不会跑偏。
答辩时有三个问题基本必问。第一个是“为什么相关性分析用 spearman 不用 pearson”,回答要点是评分是离散整数且分布偏斜,spearman 基于秩次更稳健。第二个是“R 方只有 0.6589 你怎么解释”,不要回避,直接说评分是主观感受,现有物理属性无法覆盖全部影响因素,这个模型反映的是主要趋势而非精确预测。第三个是“主成分回归得到的系数和普通回归有什么不同”,回答主成分回归消除了共线性对系数估计的干扰,并通过特征向量还原成了原始变量空间的可解释系数。
演示环节建议只展示三张核心输出:相关性矩阵的热力图、三变量回归的 summary 输出、主成分系数还原后的最终表达式。这三张图能支撑起 80% 的讲解内容。有一个实战技巧是提前准备一张真实的预测对比表,把留出样本的真实评分、多元回归预测值、主成分回归预测值、KNN 预测结果四列放在一起,现场演示时直接指出每个方法的偏差大小,比空讲理论有力得多。数据来源如果不是作业指定的,记得在参考文献里标注数据集出处,简单一行说明来源名称和下载日期就可以。
从那以后,我每次交数据分析作业都强制走一遍“数据分布观察 → 相关性分析 → 回归建模 → 降维对比 → 分类验证”的完整流程,哪怕某个环节结论不理想,比如 R 方不高或者 KNN 准确率偏低,也要把原因讲清楚再往下走。别人交的是结果,你交的是思路。希望帮到你。
本文还有配套的精品资源,点击获取