资讯详情

资讯详情

红酒品质预测:相关性分析、回归建模与KNN分类实战

简介面向高校数据分析课程作业与入门实践者这份资料以经典红酒数据集为分析对象完整呈现从数据整理到统计建模再到分类预测的作业流程。文档从11项理化属性入手逐项分析其与评分的关系借助相关性矩阵完成特征筛选随后开展多元线性回归、主成分回归并通过KNN对红酒品质进行简单分类全程附有R语言与Python的关键代码思路、输出结果解读及模型改进说明可迁移至其他回归与分类任务。资源为docx格式压缩包内共1个文件大小202KB内容紧凑、章节完整适合作为课程设计参考或自学案例。目前已有4265人学习下载对正在完成数据分析大作业或想系统掌握回归、主成分与KNN应用的学习者尤为实用。1. 引言一份红酒数据怎样拆出影响评分的核心因素第一次拿到这份红酒数据集做数据分析时我心里有点犯嘀咕1599条记录、11个物理属性、3到8分的口感评分看起来就是一个标准的课程大作业素材但真正跑完相关性分析和回归之后我发现结论跟大多数人的直觉是相反的——消费者常以为pH值和残糖决定红酒好坏可相关性矩阵告诉我们挥发性酸度、硫酸盐和酒精才是与评分最相关的三个变量。这份资源把“数据分析”从数据清洗到统计建模再到KNN分类的完整链路都走了一遍适合正在做课程大作业、或者想快速上手统计建模与机器学习入门的人照着跑就能复现全套图表和结论。2. 数据预处理与相关性分析11个物理属性与评分的关联初探拿到一份新数据我习惯先搞清楚变量含义再做格式转换最后才谈建模。这个顺序在红酒数据集上同样适用而且能帮你避开后面回归时的不少坑。2.1 数据读取与格式转换原始数据是以csv格式存放的列分别是非挥发性酸度、挥发性酸度、柠檬酸、残糖、氯化物、游离二氧化硫、总二氧化硫、密度、pH值、硫酸盐、酒精和评分。项目里用Python的openpyxl库把csv转成了xlsx主要原因是后面R语言读取Excel更直观而且课程环境里用Excel打开查看数据也更方便。import openpyxl import csv def csv_to_xlsx(csv_file, xlsx_file): workbook openpyxl.Workbook() sheet workbook.active sheet.title Sheet1 with open(csv_file, encodingutf-8) as f: reader csv.reader(f) for row in reader: sheet.append(row) workbook.save(xlsx_file) csv_to_xlsx(winequality-red.csv, redwine.xlsx)这段代码做的事情很简单新建一个工作簿把csv逐行读进来再逐行写入工作表最后保存为xlsx。这里的encoding参数要留意如果csv里没有中文用utf-8没问题如果是从老系统导出的文件可能需要换成gbk或latin1否则读出来就是乱码。sheet.title指定工作表名后面R语言读取时默认找的也是这个Sheet1名字对不上时会直接报错这是第一个容易翻车的细节。转完之后遍历整个数据集能看到评分的分布区间是3到8分绝大多数数据落在5分和6分之间这意味着后面无论做回归还是分类都会遇到样本分布不平衡的问题——这个坑先记着第4章会专门展开。2.2 相关性分析实操数据准备好之后用R读取xlsx并计算变量间的相关性。这里选择的是Spearman秩相关系数而不是默认的Pearson原因是评分本质上是品酒师的主观打分分布并不严格正态Spearman对离散数据更稳健。install.packages(readxl) library(readxl) df - read_excel(redwine.xlsx, sheet 1, col_names TRUE) cor(df, method spearman)read_excel的第一个参数是文件路径sheet指定工作表序号或名称col_names TRUE表示第一行是列名而不是数据。cor函数计算整个数据框的相关系数矩阵method参数决定用哪种相关系数。输出的是一个12乘12的矩阵对角线全是1其余位置的值代表两个变量之间的关联强度和方向。从矩阵里能看到几组关键信息x4残糖、x6游离二氧化硫、x9 pH值与评分的相关性都很低接近0可以暂时忽略达到降维的目的而x2挥发性酸度、x10硫酸盐、x11酒精与评分的相关性较高是后续建模的主力变量。同时变量之间也存在联动比如pH与非挥发性酸的相关性很高因为数据里非挥发性酸的含量本身较大酒精和密度也有一定相关性这符合酿酒常识——糖分发酵越彻底酒精越高密度越低。2.3 相关性结果解读与变量筛选看到相关矩阵之后很容易直接拍脑袋把x4、x6、x9删掉但其实相关系数低只说明“单独看这一个变量它与评分的线性关系弱”并不等于它对模型没有贡献。项目里先基于相关性把变量从11个降到8个再做回归这属于业务导向的特征筛选更严谨的做法是同时跑一遍全变量回归对比一下删掉低相关变量后R方和检验p值的变化再决定保留谁。我习惯把这一步的产出整理成一张变量关系清单强正相关是x10硫酸盐、x11酒精强负相关是x2挥发性酸度弱相关是x4残糖、x6游离二氧化硫、x9 pH。这张表后面回归选变量的时候会反复用也是你改这个项目时最快能落地的部分——换数据集时只需要重新跑一遍cor函数清单就自动更新了。3. 回归分析实战从八变量回归到主成分回归相关性分析告诉你哪些变量值得用回归分析则告诉你它们以什么权重组合在一起。这一章的重点不是单纯跑一个lm函数而是搞清楚为什么一开始八变量回归会出现一堆不显著的参数以及主成分回归是怎样绕过共线性问题的。3.1 多元线性回归建模八变量还是三变量按第2章的筛选结果先对去除低相关变量后的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)lm函数的第一个参数是回归公式波浪号左边是因变量评分q右边是自变量列表data参数指定数据来源为df。summary返回的是系数估计、标准误、t值和p值重点关注Pr(|t|)这一列。用summary查看回归结果时会看到好几个参数的p值大于0.05说明它们没有通过显著性检验。这不是模型写错了而是变量之间存在共线性比如pH和非挥发性酸高度相关两个变量同时放进方程时系数估计的标准误会被拉大t值变小看起来就好像它们都不显著。既然这样干脆只保留相关性最高的三个变量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但summary里显示的R方只有0.6589说明这三个变量只能解释评分变异的六成多剩下的部分来自品酒师的主观差异、其他未纳入的化学指标以及随机误差。项目里留了一组数据没参与建模x20.31、x100.66、x1111对应评分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)predict函数的第一个参数是拟合好的回归模型第二个参数new是要预测的新数据框interval参数决定输出类型confidence给出的是回归均值的置信区间prediction给出的是单个新样本的预测区间后者的宽度通常比前者大不少因为它额外包含了残差标准差。从结果看模型预测值比较接近6说明在样本覆盖范围内方程还是能用的。这里的操作属于留一验证的简化版只留一组数据实际工程中建议用随机留出法留20%的数据避免单次验证的偶然性。3.2 主成分回归建模从z空间回到x空间三变量回归的R方并不高于是项目改用主成分回归试图捕捉更多信息。先对全部11个变量做主成分分析wine - read_xlsx(redwine.xlsx, sheet 1, col_names TRUE, range A1:K1559) wine.pr - princomp(wine, cor TRUE) summary(wine.pr, loadings TRUE)range A1:K1559把数据限制在前11列把评分列排除在主成分分析之外。princomp的cor TRUE表示用相关阵而不是协方差阵做分析因为各属性的量纲差异很大比如总二氧化硫是几十的量级密度是0.99左右的量级不标准化的话密度和二氧化硫会主导主成分方向这显然是错的。summary输出里的loadings TRUE会显示载荷矩阵给出每个主成分是原始变量的哪种线性组合同时累计方差贡献率会告诉你前几个主成分覆盖了多少信息。实际取了前五个主成分z1到z5对评分q做回归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)这里df[12]取的是评分列注意df是第2章用read_excel读进来的数据框列顺序和原始csv一致所以第12列就是评分。predict(wine.pr)会返回每个样本在各主成分方向上的投影值取前五列就得到z1到z5。主成分回归的参数基本都通过了检验说明五个主成分比三变量抓住了更多信息但输出的主成分表达式没法直接用来做业务解释——z1 0.49x1 - 0.239x2 0.466*x3 ...这种组合看起来有点不知所云。所以项目最后一步是把主成分回归系数还原成原始变量的系数。这一步用到的关键素材是特征向量、各列均值和标准差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 - (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)eigen(XX)$vectors取出相关阵的特征向量矩阵每一列对应一个主成分的载荷系数。X.bar和X.sd分别是各变量的均值和标准差用excel函数就能算出来注意顺序要和原始数据列一一对应。还原原理是主成分回归的预测等于各主成分的线性组合而主成分又是原始变量标准化后的线性组合把这两层组合展开、合并同类项就能得到对原始变量x的系数。coef的公式里用到的是beta[2]到beta[5]对应z1到z4的回归系数第五个主成分z5的系数没有被纳入还原这是脚本里一个值得注意的细节需要根据你实际保留的主成分个数同步调整。跑完后输出一个常数项beta0和11个变量的系数这样就能像普通回归方程一样直接使用对业务解释也更友好。3.3 模型对比与选型两个模型放到一起比结论很清晰模型变量数检验情况R方预测偏差三元线性回归x2、x10、x11全部通过0.6589预测接近实际五主成分回归z1到z5基本通过略高存在一定偏差如果目标是把回归方程用在生产环境预测评分我更倾向于三元回归系数可直接解释输入变量只有三个采集成本低预测偏差也小。如果目标是用尽可能多的化学信息做精细建模主成分回归更合适但代价是解释性差、系数还原步骤繁琐而且主成分个数需要根据累计方差贡献率反复试。改这个项目时你可以把主成分个数从5改成7或8看R方提升多少再决定要不要为这一点精度牺牲可解释性。4. 数据分析避坑记录相关性、回归与KNN的踩坑复盘这次红酒分析里遇到的典型问题我都按“现象、原因、解决”拆开记录换一个数据集也能照用属于做数据分析绕不开的血泪经验。4.1 坑一相关性不高不代表这个变量没用现象cor函数跑完看到x4残糖、x6游离二氧化硫、x9 pH和评分的相关系数接近0果断把它们从特征里删掉。后来发现某些被删掉的变量组合进模型后反而能微弱改善预测结果。原因Spearman相关系数衡量的是单一变量与评分之间的单调关联它不捕捉交互效应。比如残糖对评分的影响可能只有在酒精含量高时才体现出来单独看就是一条平平的线。相关性筛选适合用来快速砍掉明显无关的列但不适合作为唯一特征选择手段。解决把相关性筛选当作第一步而不是最后一步。删掉弱相关变量后至少保留一个全变量回归的结果做对比如果全变量模型里这些变量依旧不显著再删也不迟。省事的方法是直接上LASSO回归让惩罚项替你做选择这比手撕相关系数矩阵更靠谱。4.2 坑二八变量回归一堆参数没通过检验现象lm函数运行正常但summary输出里x1、x3等参数的p值都在0.05以上Pr(|t|)这一列看起来非常不理想。原因变量间存在多重共线性。pH和非挥发性酸相关系数很高密度与酒精也明显相关两个高度相关的变量同时进方程后各自的系数估计被拉扯标准误变大t值自然就掉下去了。这不是数据的问题而是回归模型对冗余特征的惩罚。解决先看相关矩阵里两两变量的相关系数大于0.7的配对只选其中一个进模型。项目里最终保留x2、x10、x11三个变量正是因为这三个变量彼此相关性不高而各自与评分相关性都较强。如果你不想手动选可以用R的car包里的vif函数计算方差膨胀因子vif大于10的变量逐次剔除效果一样流程还更工程化。4.3 坑三主成分回归的预测值跟实际对不上现象代入一组主成分值z1到z5后预测结果跟实际评分6有一定偏差置信区间也比较宽看起来不如三变量回归那么稳。原因取前五个主成分对应五个投影方向前五个主成分的累计方差贡献率大约是七成意味着仍然有大约三成的变异没有进入模型而这部分信息恰好可能包含与评分相关的细节预测自然会有偏差。另外主成分是对全变量方差最大方向的分解它对响应变量的解释能力并不做任何保证方差贡献率大不代表与评分相关性强。解决把主成分个数从5增加到8或9观察累计方差贡献率跳到多少同时比较回归R方。另一种做法是偏最小二乘回归它在找投影方向时直接把响应变量纳入目标函数相比之下更贴合预测任务。做预测验证时不要只留一组数据用交叉验证或留出20%的测试集看误差分布会更靠谱。4.4 坑四KNN分类准确度不到六成现象选好五个特征列、设置k为20之后测试集上的分类准确度一直不高多数样本被分到5分和6分两类整体效果不太理想。原因两个因素叠加。第一数据集中评分本来就集中在5分和6分训练样本间类别不平衡少数类别很难被正确识别第二原始特征数值跨度大比如总二氧化硫在几十的量级密度在0.99左右直接算欧氏距离时量纲大的特征实际上主导了距离等于变相降权了其他属性。解决先用z-score标准化再算距离让每个属性在距离计算里公平发言把k值换成近邻数量的网格搜索找最优别拍脑袋定20更实际的做法是把评分从离散的3到8分合并成三个档次比如“高、中、低”避免10分类变成少数类别之间的近身肉搏。标准化和分档这两步做完通常准确率会有肉眼可见的提升。5. KNN分类实现给新红酒打分的距离度量实战回归分析告诉我们哪些化学属性影响评分KNN则是从另一个角度切入不学函数关系直接拿已知样本的评分给新样本投票。这一章把KNN的Python实现拆开逐段讲重点看特征选择、距离计算和投票逻辑里的门道。5.1 KNN原理与特征选择K近邻算法的核心是三个要素k值、距离度量、分类决策规则。对一个新数据点算法在训练集中找到与它距离最近的k个点再用多数表决决定它的类别。三要素一旦确定新样本的预测类别也是唯一确定的所以调参的功夫全在这三件事上。项目里没有把全部11个属性都用来算距离而是选了x2挥发性酸度、x5氯化物、x7总二氧化硫、x10硫酸盐、x11酒精五项。这个选择说明作者在特征上做了取舍既保留了跟评分相关性强的挥发性酸度、硫酸盐、酒精也加入了氯化物和总二氧化硫做补充避开了与pH强相关的酸度变量尽量避免距离被相近特征带偏。新样本的这五项属性与已知样本对应属性做差的平方和再开方得到的就是欧氏距离距离最近的前k个样本里出现次数最多的评分就是新样本的预测评分。5.2 Python代码逐段拆解数据读取用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): object [] for col in range(cols): if col in (1, 4, 6, 9, 10, 11): data table1.cell(row 1, col 1).value object.append(data) objects.append(object) return objects这里col从0开始计数所以col等于1、4、6、9、10、11时对应Excel列就是B、E、G、J、K、L也就是挥发性酸度、氯化物、总二氧化硫、硫酸盐、酒精和评分。cell(row 1, col 1)是因为openpyxl的行列都从1开始循环里row从1开始时实际读取从第二行开始正好跳过表头。objects里的每个元素是一个6维列表前5个是特征最后1个是对应评分整体返回一个二维列表供后续计算使用。距离计算函数把每个训练样本与新样本的5个特征逐一相减、平方、累加再开方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 distancesobjects[i][j]取编号为i的样本的第j个特征nowa是待预测样本的特征列表。这段代码只计算距离不做排序复杂度是O(n*m)n为样本数m为特征数数据量小的时候完全够用。距离算完后返回一个与样本数等长的列表再交给classify做投票。投票函数里明确了近邻数量的处理逻辑def classify(distances, objects): value [] d {} for i in range(30): item objects[distances.index(min(distances))][5] if item in d: d[item] d[item] 1 else: d[item] 1 distances[distances.index(min(distances))] 100 i 0 for k, v in d.items(): i i 1 print(value is , k) if i 1: break这里的实际逻辑是循环30次每次找到当前距离最小值对应的样本取出它的评分在字典d里累计票数然后把距离列表里这个位置的值改成100相当于标记为已使用避免下次重复取同一个点。循环结束后字典d里存的就是每个评分被近邻投了多少票。原稿文字写的是取距离最近20个点但代码循环是30次属于“文档描述与实现不一致”的典型情况改项目时要么把range(30)改成20要么把文档改成30否则验证结果和设计目标对不上。另外输出部分只打印了d的第一个键值对方便快速预览并不代表它是得票最多的类别想要真正多数表决应该在循环结束后用max(d, keyd.get)取出票数最高的评分。5.3 结果分析与改进方向从测试结果看这个KNN版本的准确度并不高原因可以归结为三点数据集里评分5和6占绝大多数样本分布自带偏倚化学属性与评分之间的相关性偏弱距离相近的样本评分却可能差两分特征量纲差异导致距离被总二氧化硫这类大数值列主导。改进的优先级我建议这样排第一步对特征做标准化把每个属性变成均值为0、方差为1的数值这一步几乎稳赚第二步把k设为候选人名单用交叉验证挑出误差最小的k而不是拍脑袋定20第三步如果想保留分档语义把评分合并成三个档位再分类准确率数字会好看很多也更贴近实际业务里“推荐还是不推荐”的二分类问题。6. 二次开发从R脚本分析到Python预测接口如果只照着原项目跑一遍得到的是回归方程和一组KNN脚本真正把它变成能反复使用的东西我建议做一次“从R分析到Python预测接口”的迁移让回归和分类的结论通过一个统一入口对外输出。6.1 改造思路与目录结构改造不复杂核心是把第3章R语言拟合出的三变量回归系数固定下来同时用sklearn重写KNN并把数据读取、训练、预测拆成独立模块。建议目录结构模块职责对应原稿data_loader.py读取xlsx/csv完成标准化第2章read_excelregression.py载入固定回归系数输出预测区间第3章lm.sol2knn_model.py用sklearn训练KNN分类器第5章手写KNNapp.py命令行或接口入口汇总6.2 用sklearn重写回归与KNN回归部分可以直接把系数写死成一个字典用numpy做向量点积也可以保留sklearn的LinearRegression便于下次重新训练。KNN我一般换成sklearn版本省去手写距离和投票的麻烦from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler X df[[x2, x5, x7, x10, x11]].values y df[q].values X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42) scaler StandardScaler() X_train scaler.fit_transform(X_train) X_test scaler.transform(X_test) knn KNeighborsClassifier(n_neighbors20, weightsdistance) knn.fit(X_train, y_train) print(knn.score(X_test, y_test))weightsdistance是加权KNN距离越近的近邻投票权重越大比原稿的等权投票更适合评分密集的数据集。n_neighbors不要写死改成for循环遍历5到50的候选取交叉验证分数最高的值这一步能直接改善分类效果。6.3 验证方法与落地习惯改造完成后的验证方式是回归部分用MSE和预测区间覆盖率检查KNN部分用留出法和交叉验证对比几个k值的F1分数。还要把第4章踩过的坑固化到代码里比如数据读取后先检查列名和缺失值再算标准化均值方差特征标准化参数只从训练集fit测试集只transform避免信息泄漏。从那以后我每次拿到一份新的数据集都会强制走一遍“变量字典、缺失值检查、相关矩阵、建模、留出验证”的流程KNN的k值也必定先画一个错误率曲线再拍板不再凭感觉定参数。这套红酒数据集项目被我拿来当模板改一改列名就能套用到其他评分预测场景希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

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

立即咨询 →