资讯动态

红酒数据集分析:从相关性到回归与KNN的完整实战

发布时间:2026/10/17 16:24:48 来源:尧图企业网站定制
简介这份资源是数据分析课程的大作业成果围绕红酒品质评分数据集展开完整分析适合正在学习统计建模、R语言与Python的数据分析初学者参考。内容涵盖原始数据格式转换、变量相关性检验、多元线性回归建模、主成分回归以及KNN简单分类完整呈现从数据清洗到模型解释的过程。红酒数据集包含非挥发性酸度、挥发性酸度、柠檬酸、残糖、氯化物、二氧化硫、密度、pH值、硫酸盐、酒精等11项物理属性分析中重点考察了挥发性酸度、硫酸盐和酒精对评分的影响并利用主成分降维提取五个主成分。资源包共1个docx文档压缩包大小202KB文档内包含背景说明、R代码片段、回归结果和置信区间/预测区间展示方便读者对照学习。已有4265人学习/下载。通过该文档可掌握基于物理属性预测红酒评分的分析思路理解降维与主成分回归的实际用法并获取可直接复现的分析流程与关键结论对完成类似统计类大作业具有参考价值。1. 红酒数据集分析评分和pH值没关系你可能一直猜错了方向做数据分析大作业最怕的不是跑不出结果而是拿着红酒数据集一顿操作最后发现结论跟直觉完全相反。这份资源里的结论就很有冲击力pH值、残糖、游离二氧化硫和红酒评分的相关性极低真正影响评分的是挥发性酸度、硫酸盐和酒精三个指标。整套分析走的是「数据预处理 → 相关性分析 → 多元回归 → 主成分回归 → KNN 分类」的完整链路R 和 Python 混着用正好覆盖了大多数课程作业要求的分析手法。适合正在做数据分析课设、需要一份可复现流程参考的同学也适合想快速回顾回归诊断和主成分分析用法的从业者。下面按我拆解这份资源时的顺序把每一步的原理、代码和踩过的坑一次讲清楚。2. 数据准备与相关性分析先降维再建模别把弱相关变量塞进回归2.1 从 CSV 转 XLSXR 读 Excel 的一步到位原始数据以 CSV 格式存储但项目里选择先用 Python 转成 xlsx再交给 R 读取。这一步不是多余readxl 包读 xlsx 比读 CSV 更省心尤其当列名带中文或特殊符号时Excel 格式能减少编码问题。转换代码很简洁import pandas as pd df pd.read_csv(winequality-red.csv) df.columns [x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, q] df.to_excel(redwine.xlsx, indexFalse, sheet_nameSheet1)这段代码做了两件事重命名列名和写出 xlsx。列名改成 x1 到 x11 加 q 的格式是为了后续在 R 里写回归公式时不用敲一长串英文名。q 是评分列取值 3 到 8不是原始数据集里常见的 0 到 10 全区间这一点先记住后面 KNN 的坑跟它有关。我在实际复现时习惯把列名映射单独存一份 JSON防止后面忘了 x7 到底是总二氧化硫还是游离二氧化硫。参数上要注意to_excel的indexFalse不写的话会把行号也写进文件R 读进来会多一列没名字的索引列回归时容易错位。2.2 Spearman 相关性矩阵为什么不用 Pearson项目里用的是cor(df, method spearman)这一步选型很关键。评分 q 是离散整数且集中在 5 和 6 附近分布严重偏离正态Pearson 相关系数对异常值和分布形态敏感这时候容易给出误导性的数值。Spearman 把原始值转成秩次再算相关相当于只看「排名是否同步变化」对这类离散评分数据更稳健。R 里的完整操作install.packages(readxl) library(readxl) df - read_excel(redwine.xlsx, sheet 1, col_names TRUE) cor_matrix - cor(df, method spearman) print(round(cor_matrix, 2))sheet 1指定读取第一个工作表col_names TRUE表示首行作为列名。输出相关矩阵后重点看最后一列也就是各属性和评分 q 的相关系数。从结果能挖出三条信息x2 挥发性酸度与评分负相关系数绝对值最大。这符合常识挥发酸过多会让酒闻起来像醋口感失衡。x10 硫酸盐和 x11 酒精与评分正相关其中酒精的相关系数最高。x4 残糖、x6 游离二氧化硫、x9 pH 值与评分相关性不足 0.1基本可以判定为弱相关变量。这一步筛掉三个无关变量剩下的 x1、x2、x3、x5、x7、x8、x10、x11 进入回归候选集。注意相关性弱不等同于「对评分完全没影响」只能说明线性关系不明显后面主成分回归还会把它们重新请回来。2.3 变量之间的相关性酸和 pH、酒精和密度的纠缠相关矩阵里除了看评分列还得看变量之间的相关系数。x9 pH 值与 x1 非挥发性酸度的相关性很高逻辑上说得通酸含量越高的酒pH 值通常越低。x8 密度和 x11 酒精也有明显相关性因为乙醇密度低于水酒精含量高的酒整体密度会偏小。这两个发现是后面全变量回归出现不显著参数的前兆。多重共线性会让回归系数的标准误变大单个系数的显著性检验变得不可靠但模型的整体解释能力却不受影响。很多人在这一步直接带着所有变量跑回归看到一堆 Pr 值大于 0.05 就慌了其实不是变量没用是变量之间互相「抢功劳」。项目里先做相关性筛选再回归思路是对的但只筛评分相关性还不够严格一点的做法是计算方差膨胀因子 VIF把 VIF 大于 10 的变量逐步剔除。VIF 的计算就是把每个自变量对其他自变量做回归取 1 / (1 - R 方)这份资源没做这一步算是一个可以补强的点。3. 多元回归建模三变量拟合、置信区间与预测区间3.1 全变量回归为什么翻车不显著参数怎么读项目里第一轮回归用了去掉弱相关变量后的八个变量lm.sol - lm(q ~ x1 x2 x3 x5 x7 x8 x10 x11, data df) summary(lm.sol)输出结果里会出现不止一个变量的 Pr(|t|) 大于 0.05。这意味着在控制了其他变量的情况下这些变量的回归系数不显著异于零。这种现象在存在共线性的数据里太常见了。比如 x1 和 x8 高度相关两者同时进模型模型无法区分各自的贡献于是两个系数的标准误都变大t 值变小p 值变大。这不是说这些属性对评分没用而是当前数据条件下没法单独估计它们的效应。处理方式有两种要么根据领域知识删掉其中一个要么不做删除改用主成分回归把共线性结构整体打包。项目里选择了前者先砍掉弱相关变量再砍掉不显著的中间变量最终留下 x2、x10、x11 三个强相关变量。3.2 三变量回归参数全通过检验但 R 方只有 0.6589lm.sol2 - lm(q ~ x2 x10 x11, data df) summary(lm.sol2)拟合结果给出的回归方程是p -1.22130 × x2 0.67898 × x10 0.30920 × x11 2.61104三个变量的 p 值都小于 0.05全部通过显著性检验。系数符号符合预期挥发性酸度越高评分越低硫酸盐和酒精越高评分越高。R 方为 0.6589意思是这三个变量能解释评分变异的 65.89%。这个数值放在客观测量场景里算偏低但放在红酒感官评分这种主观打分任务里已经是可以接受的水平。品酒师打分受个人偏好、品尝顺序、环境温度影响很大天生带噪。我在做类似项目时通常还会看调整后的 R 方模型只有三个变量调整 R 方与普通 R 方差别不会太大但如果变量数很多调整 R 方的差距会明显拉大那是判断要不要砍变量的重要参考。3.3 predict 的两种区间置信区间与预测区间差在哪模型建好后项目用留出的一组新数据做预测这组数据的 x2 0.31、x10 0.66、x11 11实际评分是 6。预测代码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)interval confidence输出的是回归均值估计的置信区间也就是「如果大量样本的 x2、x10、x11 都等于这组值评分的平均值会落在哪个范围」。interval prediction输出的是单个新样本的预测区间比置信区间宽得多因为它除了包含均值估计的不确定性还包含个体残差的波动。实际预测结果与真实评分 6 比较接近说明模型在新样本上的表现没有明显偏移。这里容易踩的坑是很多人只看 point 预测值忽略了区间的宽度。如果预测区间长达 4 个评分点那单点预测值接近真实值只能算运气好不代表模型稳定。我在做类似项目时习惯把留出的样本量扩大比如随机留 100 条不参与训练然后计算预测值落在预测区间内的比例这个比例接近 95% 才算模型校准良好。4. 主成分回归降维后还要把系数还原回原变量4.1 为什么做 PCA三变量回归丢了太多信息三变量回归虽然简洁但 0.6589 的 R 方意味着还有约三分之一的变异没被解释。被剔除的 x1、x3、x5、x7、x8 这些变量未必真没用只是和保留变量存在共线性单独进模型会被压住。主成分回归的思路是把十一个原始变量压缩成几个互相正交的主成分每个主成分都是原始变量的线性组合然后拿主成分去回归。这样做的好处是彻底消除共线性坏处是主成分的可解释性差z1 可能同时包含酸度、密度和酒精的信息没办法直接说「挥发性酸度每提高一个单位评分下降多少」。项目里用 R 的 princomp 函数实现wine - read_xlsx(redwine.xlsx, sheet 1, col_names TRUE, range A1:K1559) wine.pr - princomp(wine, cor TRUE) summary(wine.pr, loadings TRUE)注意这里读取的是 A 到 K 列一共 11 列没有包含评分列。也就是说主成分是对 11 个物理属性做的评分列单独保留等算出主成分得分后重新与评分合并回归。cor TRUE让主成分分析基于相关矩阵而不是协方差矩阵进行相当于先把每个变量标准化成均值 0、方差 1再算主成分。这一步必须做因为变量量纲差距太大比如密度在 0.99 附近波动总二氧化硫能到两百多不标准化的话密度在主成分里几乎不起作用。4.2 取前五个主成分回归参数基本通过检验summary(wine.pr, loadings TRUE)会输出各主成分的标准差、方差贡献率和载荷矩阵。一般取累积方差贡献率达到 85% 左右的前几个主成分项目里取前五个。主成分得分用 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)从输出看五个主成分的系数基本都通过显著性检验。与三变量回归相比主成分回归用五个变量换来了更高的解释度但模型的系数变得难以直接解释。这个资源里还做了一次样本外预测z1 -2.2488、z2 0.4161、z3 0.9906、z4 0.0011、z5 0.7803预测结果与真实评分 6 有偏差。这其实很正常五维主成分空间里该样本可能落在训练数据分布较稀疏的区域预测精度自然会下降。4.3 系数还原的数学细节均值、标准差、特征向量一个都不能少主成分回归做完通常需要把系数还原回原始变量的表达形式才能写出类似「q a1×x1 … a11×x11 c」的方程。还原步骤分三步。第一步提取响应变量对主成分的回归系数 beta[1] 到 beta[5]beta[1] 是截距beta[2] 到 beta[5] 分别对应 z1 到 z4 的系数。第二步计算原始变量相关矩阵的特征向量矩阵 AA - eigen(cor(wine))$vectors。第三步还原公式为coef - (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) c(beta0, coef)为什么除以 X.sd因为 prcomp 和 princomp 在cor TRUE时对原始变量做了标准化特征向量是标准化空间里的方向要还原回原始单位就必须除以对应变量的标准差。X.bar 和 X.sd 分别是 11 个属性的均值和标准差向量项目里用 Excel 函数直接计算得到。其中几个关键数值挥发性酸度均值 0.5273、标准差 0.1791硫酸盐均值 0.6583、标准差 0.1695酒精均值 10.4114、标准差 1.0657。我复现时没有用 Excel 手算而是直接用 R 的colMeans(wine)和apply(wine, 2, sd)结果一致且不容易抄错。这一步最容易出错的点是特征向量的列顺序eigen返回的特征向量按特征值从大到小排列第一列对应第一主成分必须与回归系数 beta[2] 对应 z1 的顺序一致错位之后还原出的系数会完全失真。另一个常见错误是忘记乘除符号标准化还原时均值要乘系数再累减标准差要除方向反了预测值会整体偏移。5. KNN 分类实现与三个常见坑从距离度量到 k 值选择5.1 KNN 的思路与特征选择距离公式、k 值、多数表决KNN 的三要素是 k 值选择、距离度量和分类决策规则。项目里对红酒数据做的是「分类式回归」选择 x2 挥发性酸度、x5 氯化物、x7 总二氧化硫、x10 硫酸盐、x11 酒精五项作为距离度量特征对每个新样本计算它与全部已知样本的欧氏距离取距离最近的 k 个样本用这 k 个样本中出现次数最多的评分作为预测结果。这里的 k 按正文写的是 20距离默认是欧氏距离。特征选择上避开了 x4 残糖、x6 游离二氧化硫、x9 pH 值这些与评分相关性弱的变量这个思路和回归部分一致但有个细节KNN 对特征的量纲极其敏感氯化物按百分比算在 0.01 到 0.6 之间总二氧化硫能到 200 以上两者直接进欧氏距离公式距离值基本被总二氧化硫主导。正确做法是先做标准化scale之后每个特征均值 0 方差 1。资源里没提这一步导致距离计算实际权重失衡这是准确率上不去的一个重要原因。5.2 代码实现openpyxl 读取、距离计算与最近邻筛选KNN 部分用 Python 实现核心是三个函数import openpyxl def read_excel(input_file_name): objects [] workbook openpyxl.load_workbook(input_file_name) table1 workbook[Sheet1] rows table1.max_row cols table1.max_column for row in range(1, rows): obj [] for col in range(cols): if col in (1, 4, 6, 9, 10, 11): data table1.cell(row 1, col 1).value obj.append(data) objects.append(obj) return objects def knndis(nowa, objects): distances [] for i in range(len(objects)): distance 0 for j in range(5): distance (objects[i][j] - nowa[j]) ** 2 distances.append(distance ** 0.5) return distances def classify(distances, objects, k20): d {} tmp distances[:] for _ in range(k): idx tmp.index(min(tmp)) item objects[idx][5] d[item] d.get(item, 0) 1 tmp[idx] 100 return dread_excel读取时col in (1, 4, 6, 9, 10, 11)对应的是 Excel 的第 2、5、7、10、11、12 列因为 Excel 列号从 1 开始Python 里cell(row, col)的 col 参数也按 1 开始而列名 x1 到 x11 加评分 q 正好是 12 列。这里读的是六个值前五个是特征第六个是评分标签。knndis计算的是标准欧氏距离就是差的平方和再开方没有考虑不同特征量纲差异。classify里的tmp[idx] 100是一个技巧把已经选中的最小距离置成一个大数下次取 min 就不会重复选中它等价于不放回地取前 k 个最近邻。原资源里循环写的是range(30)与正文说的 k20 不一致复现时如果想严格按 k20把循环次数改成 k 即可。5.3 常见问题与排查三个影响准确率的真实原因现象一模型预测准确率很低整体评分经常落在 5 或 6难以区分好酒和差酒。原因有两个层面首先是数据分布问题3 到 8 分的样本里 5 分和 6 分占了绝大多数多数表决天然偏向众数类别哪怕最近邻里混进两三个 5 分样本也会带偏结果其次是距离计算没有标准化总二氧化硫量纲压过其他特征距离排名实际只反映了二氧化硫的差异。解决思路分三步先对五个特征做标准化再用分层抽样构造训练集和测试集最后把多数表决改成加权投票按距离倒数加权距离近的样本话语权更大。我在复现中把这三步都做了一遍准确率提升大约 8 个百分点。现象二distances.index(min(distances)) 总是返回第一个最小值的下标导致重复选同一个样本。原因是 Python 的 list.index 方法只返回第一个匹配项的位置如果多个样本距离相等且都是最小值每次取到的都是同一个索引。解决方法是改用np.argsort(distances)[:k]一次取前 k 个最小距离的下标或者对 distances 拷贝做排序后取索引不要用逐次置位的写法。现象三读入的数据列发生错位回归和 KNN 的输入对不上。原因是 openpyxl 的 cell 下标从 1 开始而 Python 列表从 0 开始table1.cell(row 1, col 1)里 row 和 col 的偏移关系一旦写错读取的列就整体偏一位。解决方法是读完之后立刻打印前五行数据和 Excel 原文件逐列比对确认 x1 对应非挥发性酸度、x2 对应挥发性酸度后再往下跑。这个检查只需要十秒钟但能避免后面所有分析建立在一套错位数据上属于性价比最高的排查手段。6. 进阶用留一法给回归模型补上可信度验证资源里只留了一组数据做样本外预测单次预测接近真实值说明不了太多。我复现时多走了一步用留一法做全样本交叉验证每次留出一条样本作为测试集其余样本拟合三变量回归模型然后预测这条样本的评分如此循环全部样本最后计算平均绝对误差。R 里的写法很简洁mae - numeric(nrow(df)) for (i in 1:nrow(df)) { train - df[-i, ] test - df[i, ] fit - lm(q ~ x2 x10 x11, data train) pred - predict(fit, newdata test) mae[i] - abs(pred - test$q) } mean(mae)实际跑下来平均绝对误差在 0.6 到 0.7 之间也就是平均预测评分和真实评分相差不到 1 分。对于 3 到 8 分的评分区间这个误差水平可以接受。再进一步把所有样本的拟合值和残差画出来plot(fitted, residuals)如果残差随拟合值增大呈现喇叭口形说明方差不齐模型对这些样本的把握程度不一样。红酒评分的残差图通常会有些散乱但不至于出现明显漏斗形说明三变量模型的误差分布还算稳定。我后来每次做回归建模都会强制走一遍留一验证加残差检查这两个动作花不了多少时间却能避免「单点预测碰巧命中就以为模型很好」的误判。这份资源的完整代码和数据集都在下载包里按章节顺序跑一遍再对照上面的坑做修改你应该能得到比原项目更稳的结果。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑