资讯详情

资讯详情

红酒评分数据分析实战:相关性分析、回归与KNN分类

简介这份数据分析大作业资料面向统计学、数据科学相关课程的学生与自学者围绕红酒数据集展开完整的建模实践帮助读者理解如何从物理属性出发探究评分的影响因素并完成分类。压缩包内为1个docx文档约202KB集中呈现分析摘要、变量说明、代码片段与结果图表便于对照复现。资料依次覆盖单一属性与评分的关联性分析、11项物理属性的变量梳理、Spearman相关性分析降维、多元线性回归拟合与预测区间验证以及主成分回归的系数还原过程并延伸至KNN简单分类。读者可从中获得一套可复用的分析框架包括变量筛选思路、R方偏低的诊断视角、主成分表达式的推导与还原方法以及回归与分类衔接的完整流程。目前已有4270人学习下载适合作为课程大作业参考或数据分析入门练手素材。1. 从一份红酒评分表说起这个数据分析大作业到底在做什么拿到一份 1599 行的红酒数据11 个理化指标外加一列 0 到 10 的感官评分你会怎么下手这个数据分析大作业干的就是这件事用统计方法把“什么因素在影响红酒评分”这个问题拆开揉碎先用相关性分析筛变量再用多元线性回归拟合接着上主成分回归处理共线性最后用 KNN 做一次简单分类。整套流程横跨 Python 和 R 两个工具链数据从 csv 转 xlsx分析在 R 里跑KNN 部分回到 Python 手写。适合正在找数据分析课程设计参考、想看清“相关性→回归→降维→分类”完整链路怎么落地的人。它不是工业级建模项目但胜在流程完整、代码可复现拿来改改就能交作业或者当练手模板。2. 数据准备与相关性分析11 个变量怎么筛到 3 个2.1 数据格式转换与变量含义原始数据是 csv项目里先用 Python 转成 xlsx方便 R 的 readxl 直接读。这一步看着多余但实际做作业时挺实用——xlsx 能保留列名和 sheet 结构R 里读进来不用再处理编码问题。11 个变量对应关系如下编号变量名含义x1非挥发性酸度fixed acidityx2挥发性酸度volatile acidityx3柠檬酸citric acidx4残糖residual sugarx5氯化物chloridesx6游离二氧化硫free sulfur dioxidex7总二氧化硫total sulfur dioxidex8密度densityx9pH 值pHx10硫酸盐sulphatesx11酒精alcohol评分列 q 范围 3 到 8绝大多数集中在 5 和 6。这个分布特征后面会反复提到——它直接导致 KNN 分类准确度上不去也是回归 R 方偏低的隐性原因之一。转换代码不复杂用 pandas 读 csv 再 to_excel 就行import pandas as pd # 读取原始 csv注意分隔符UCI 红酒数据通常是分号 df pd.read_csv(winequality-red.csv, sep;) # 列名重命名为 x1~x11 q方便后续 R 代码里直接用 x2、x10 这种写法 df.columns [x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,q] # 写出 xlsxsheet 名保持默认R 端 read_excel 按 sheet1 读 df.to_excel(redwine.xlsx, indexFalse)这里有个细节列顺序必须和后面 R 代码里的 x1 到 x11 严格对应否则相关性分析出来的结论会整体错位。我一般会在转换后打印df.head()和df.columns.tolist()各看一遍确认列名和顺序没跑偏再往下走。2.2 用 Spearman 相关系数做初筛R 端读数据用 readxl相关性分析用cor()方法选 spearman。为什么不用 pearson红酒的理化指标分布未必正态评分又是离散的 3 到 8spearman 基于秩对异常值和非线性单调关系更稳。代码很短install.packages(readxl) library(readxl) # 读第一个 sheetcol_names T 表示首行是列名 df - read_excel(redwine.xlsx, sheet 1, col_names TRUE) # spearman 相关系数矩阵得到 12x12 的矩阵 cor_matrix - cor(df, method spearman)跑完看 q 那一列或那一行结论是x4 残糖、x6 游离二氧化硫、x9 pH 值与评分相关性不高可以先剔除降维x2 挥发性酸度、x10 硫酸盐、x11 酒精与评分相关性较高。同时变量之间也有明显关联——pH 和非挥发性酸高度相关酸多 pH 低符合化学常识酒精和密度也有一定负相关。这两条变量间相关性是后面主成分回归的伏笔直接拿全部变量做多元回归共线性会把系数估计搅乱。提示cor()返回的是矩阵别只看 q 那一列就下结论。变量之间的高相关对后面选模型很关键建议把矩阵存下来用which(abs(cor_matrix) 0.5, arr.ind TRUE)快速定位强相关对。3. 回归建模从全变量到三变量再到主成分3.1 多元线性回归与变量筛选第一版回归把剔除低相关变量后的 8 个变量全塞进去# q 为评分x1 x2 x3 x5 x7 x8 x10 x11 为保留变量 lm_sol - lm(q ~ x1 x2 x3 x5 x7 x8 x10 x11, data df) summary(lm_sol)summary出来会发现部分系数没通过 t 检验p 值大于 0.05说明变量太多、彼此干扰。于是收缩到相关性最高的三个x2、x10、x11。# 三变量回归参数全部通过检验 lm_sol2 - lm(q ~ x2 x10 x11, data df) summary(lm_sol2)得到的方程是q -1.22130*x2 0.67898*x10 0.30920*x11 2.61104。系数符号值得注意挥发性酸度系数为负硫酸盐和酒精为正。这跟常识对得上——挥发酸高会让酒闻起来像醋评分自然低硫酸盐和酒精适度提升则对口感有正面作用。但 R 方只有 0.6589拟合程度不算高说明这三个变量解释不了全部评分波动还有别的因素在起作用。预测部分留了一组数据做验证x20.31、x100.66、x1111实际评分 6new - 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)两个区间要分清confidence 回答“这个条件下平均评分大概多少”prediction 回答“这一瓶酒评分可能落在哪”。做作业时两个都输出答辩时能讲出区别是加分项。3.2 主成分回归处理共线性三变量模型虽然干净但丢掉了其他变量的信息。主成分回归的思路是先把 11 个变量压成几个互不相关的主成分再拿主成分对评分回归最后把系数换算回原始变量。# 读全部 11 列corTRUE 表示用相关阵而非协方差阵消除量纲影响 wine - read_xlsx(redwine.xlsx, sheet 1, col_names TRUE, range A1:K1559) wine_pr - princomp(wine, cor TRUE) summary(wine_pr, loadings TRUE)取前五个主成分累计贡献率通常能到 80% 以上。然后求每个样本的主成分得分再对评分回归pre - predict(wine_pr) z1 - pre[,1]; z2 - pre[,2]; z3 - pre[,3]; z4 - pre[,4]; z5 - pre[,5] redd - data.frame(q df[[12]], z1, z2, z3, z4, z5) lm_solp - lm(q ~ z1 z2 z3 z4 z5, data redd) summary(lm_solp)主成分回归的参数基本通过检验。但主成分系数没法直接解释业务含义得换算回原始变量。换算公式是原始变量系数 特征向量矩阵对应列 × 主成分回归系数 / 原始变量标准差截距再根据均值调整。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_raw - (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_raw) c(beta0, coef_raw)输出第一个数是常数项后面依次是 x1 到 x11 的系数。这一步是整份作业里最容易翻车的地方——均值、标准差必须和原始数据严格对应特征向量列顺序也要和主成分编号对齐错一位结果就全乱。我一般会把X_bar和X_sd用colMeans(wine)、apply(wine, 2, sd)现算一遍跟手填的值对一下再往下跑。4. KNN 分类手写距离计算与投票逻辑4.1 数据读取与距离度量KNN 部分切回 Python没用 sklearn而是手写作业里这么写能体现对算法三要素k 值、距离度量、决策规则的理解。选 x2、x5、x7、x10、x11 五个属性做距离度量k 取 20。import openpyxl def read_excel(input_file_name, objects): 从 xlsx 读取数据只保留参与距离计算的列 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): # 列索引 1,4,6,9,10,11 对应 x2,x5,x7,x10,x11 和评分 q 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注意cell(row 1, col 1)的偏移openpyxl 行列从 1 开始而循环从 0 开始所以都要加 1。列索引的判断用的是 0 基对应到实际列要再 1这个双重偏移是手写读取时最常见的 bug 来源。距离计算就是欧氏距离五个维度def knndis(nowa, objects): 计算测试点到每个训练样本的欧氏距离 distances [] for i in range(len(objects)): distance 0 for j in range(5): # 前 5 列是属性第 6 列是评分 distance (objects[i][j] - nowa[j]) ** 2 distances.append(distance ** 0.5) return distances4.2 投票逻辑与准确度问题分类函数取距离最近的 20 个点统计评分出现次数取最多的作为预测结果def classify(distances, objects): 取最近 20 个邻居多数表决 d {} for i in range(20): idx distances.index(min(distances)) label objects[idx][5] # 第 6 列是评分 d[label] d.get(label, 0) 1 distances[idx] 100 # 已选点置大值避免重复选中 # 返回出现次数最多的评分 return max(d, keyd.get)distances[idx] 100这行是“已访问标记”的土办法把选过的距离改成一个大数下一轮min就不会再选它。比维护一个 visited 集合省事但前提是数据里没有距离超过 100 的点红酒数据归一化后不会出现这种情况所以能用。实际测试准确度不高原因有两个一是评分 5 和 6 占了绝大多数模型倾向于预测这两个类少数类3、4、7、8基本预测不出来二是选用的五个属性和评分的相关性本身就不算高距离近不代表评分接近。如果只看最近的那个点k1准确度反而更高——这说明数据里局部结构比全局投票更可靠。做作业时把这个现象写进分析比单纯报一个准确率数字更有说服力。注意KNN 对量纲敏感x7 总二氧化硫的数值范围远大于其他变量不归一化的话距离会被它主导。项目里没做标准化严格来说是个缺陷二次开发时建议先(x - mean) / std再算距离。5. 避坑与排查这份作业跑不通时先看这几条5.1 列索引错位导致相关性结论全反现象R 里跑出来的相关性矩阵q 和 x4 的相关性很高跟预期完全相反。原因Python 转 xlsx 时列顺序和 R 代码里的 x1 到 x11 没对齐或者 csv 分隔符不是分号导致整行读成一列。解决转换后立刻print(df.columns.tolist())R 端读进来先str(df)看列名和类型两边对上了再跑cor()。5.2 主成分系数换算结果对不上现象换算回原始变量的系数代入一组数据预测值和实际差很远。原因X_bar和X_sd是手填的和当前数据版本不一致或者特征向量矩阵A的列顺序和主成分编号没对齐。解决不要手填均值和标准差用colMeans(wine)和apply(wine, 2, sd)现算A[,1]对应第一主成分确认princomp的loadings输出顺序后再取列。5.3 KNN 读取时行列偏移多算一位现象read_excel读出来的第一行数据是列名或者空值距离计算报类型错误。原因cell(row 1, col 1)的偏移和循环起点没配合好表头行被当成数据读了。解决循环从range(2, rows 1)开始跳过表头或者读之前先确认table1.cell(1, 1).value是不是列名。5.4 回归预测区间和置信区间混用现象答辩时被问“这个区间能不能说明单瓶酒的评分范围”答成置信区间。原因两个函数参数一样输出都是三列fit、lwr、upr容易混。解决记住 confidence 是均值区间、prediction 是单样本区间后者一定更宽代码里变量名分别叫lm_conf和lm_pred别都叫pred。5.5 评分分布不均导致 KNN 准确率虚高现象KNN 准确率看着有 60% 多但混淆矩阵里 7 分、8 分一个都没预测对。原因5 和 6 样本占绝对多数模型全猜 5 或 6 就能拿到不低的准确率。解决别只看总体准确率按类别看召回率或者对少数类做过采样再跑对比前后结果写进分析。6. 二次开发把这份作业改成能讲出故事的模板这份代码最大的价值不是结论而是流程骨架。想拿它做二次开发我建议从三个方向动手。第一把 R 和 Python 拆开的部分合并到一条 Python 流水线里用 pandas 做相关性、statsmodels 做回归、sklearn 做 PCA 和 KNN这样别人拿到手一条命令就能跑完不用装两个环境。第二补上标准化和交叉验证——KNN 前先StandardScaler回归用cross_val_score看泛化误差比单次 R 方更有说服力。第三把“评分预测”改成“评分分档分类”3 到 5 归为低档、6 归为中档、7 到 8 归为高档三分类比直接回归 3 到 8 的连续值更稳也更容易解释。改造时有个验证习惯我一直保持每换一个模型先把同一组留出数据跑一遍记录预测值和实际值的偏差再决定要不要调参。下面这个对比表是我一般会填的改完代码对着填一遍哪个环节退步了一眼就能看出来环节改造前改造后验证方式相关性筛选spearman 手看阈值自动筛对比保留变量数回归三变量 OLS加交叉验证R 方 RMSE降维princomp 前五主成分PCA 方差解释率累计贡献率分类手写 KNN k20标准化 k 调参分类报告还有个小技巧主成分回归换算回原始系数那一步写个函数封装起来输入特征向量矩阵、主成分系数、均值和标准差输出原始系数以后换数据集直接调用不用每次重抄公式。我当时第一次做换算时手抄均值抄错一位跑出来的系数符号全反排查了半天才发现是数据录入问题。从那以后我每次做系数换算都强制用colMeans现算一遍再和手填值对账对不上就不往下走。希望这个习惯能帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →