ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

红酒数据集分析指南:从pandas清洗到sklearn建模验证

红酒数据集分析指南:从pandas清洗到sklearn建模验证 简介这份《数据分析大作业-红酒数据集的分析》文档资源面向正在进行数据分析课程设计或统计建模练习的大学生完整呈现从数据清洗到建模分析的全过程。内容以11项红酒理化属性与感官评分为研究对象依次开展相关性分析、多元线性回归、主成分回归并采用KNN算法实现简单分类结论对红酒品质影响因素挖掘具有参考价值。资源包共1个文件为docx格式大小202KB打开即可查看含图表、代码及结果输出的完整报告。该资源已有4265人学习适合作为数据分析、机器学习入门及R语言应用的参照范例。读者可从中获取红酒数据集分析的标准流程、特征降维思路、回归模型构建与检验方法以及主成分回归与原始变量转换的具体实现细节。1. 红酒数据集该怎么分析先想清楚大作业到底在考什么期末数据分析大作业发下来很多人第一反应是直接把红酒数据集塞进模型跑出一个准确率截图交差这种做法在答辩现场往往撑不过三分钟。原因很简单老师想看的是分析路径不是模型的黑匣子输出。这里说的红酒数据集是 UCI 上那套 178 个样本、13 个化学特征、分成 3 个品种类别的经典数据它体积小、标签干净、规律明显非常适合完整走一遍数据清洗、描述统计、可视化和建模验证的小样本数据分析案例。这篇笔记只讲一件事如何把这套数据分析案例做出“能交作业、能答辩、能讲清楚每个选择”的程度。适合正在做课程设计的学生也适合刚接触 pandas 和 scikit-learn 的从业者照着复现。2. 数据获取与基础清洗先拿到一份能分析的 DataFrame拿到任何数据集第一步都不是写模型而是把它读进来整理成结构清晰的表格。红酒数据集虽然内置在 sklearn 里但很多大作业要求你自己从 UCI 下载原始文件两种来源的读取方式不一样处理细节也不同。这一章把读取、体检、清洗、标签分离一次说清楚。2.1 红酒数据集的常见来源与读取方式常见做法有两种一是直接用 sklearn 的内置接口适合快速验证流程二是从 UCI 网站下载.data文件适合写在报告里展示“数据获取”环节。我一般会优先用load_wine()作为主流程因为列名是现成的省去手工命名的麻烦如果导师指定要解析原始文件则用pd.read_csv()加headerNone处理。import pandas as pd from sklearn.datasets import load_wine # sklearn 内置读取返回 Bunch 对象类似字典 wine load_wine() print(wine.keys()) print(wine[DESCR].split(\n)[0])# 转成 DataFrame列名直接用 sklearn 给好的 feature_names df pd.DataFrame(wine[data], columnswine[feature_names]) df[target] wine[target] print(df.head())load_wine()返回的 Bunch 对象里有data、target、feature_names、target_names和DESCR五个部分。data是 178 行 13 列的二维数组target是长度 178 的一维标签feature_names存着 13 个化学指标的名称包括 alcohol酒精、malic_acid苹果酸、color_intensity颜色强度、proline脯氨酸等。把标签直接并进 DataFrame 是为了后面做分组统计和可视化时方便但建模前必须再拆开。如果你从 UCI 下载原始文件文件里第一列是类别标签后面 13 列是特征没有表头读取方式略有不同df_raw pd.read_csv(wine.data, headerNone, names[target] wine[feature_names])参数headerNone告诉 pandas 第一行不是列名names手动指定列名。这两处不写对后面所有分析都会串列这是新手最常见的翻车点。2.2 用 Pandas 完成首轮体检缺失、重复、类型数据读完先别急着算统计量花一分钟确认三个基础问题有没有缺失值、有没有完全重复的行、每一列的数据类型是否符合预期。红酒数据集本身很干净但“干净”这个结论不能靠猜要写在报告里。print(数据维度:, df.shape) print(数据类型:\n, df.dtypes) print(缺失值总数:, df.isnull().sum().sum()) print(重复行数量:, df.duplicated().sum())shape输出(178, 14)表示 178 个样本、13 个特征加 1 个目标列。dtypes应该全部是float64或int64如果出现object说明某列被读成了字符串常见原因是原始文件里混入了缺失占位符。isnull().sum().sum()先按列统计缺失数再全部相加得到全局缺失值总数。duplicated().sum()统计完全重复的行数。对这份数据来说缺失值和重复行都是 0但这步不能跳过。报告里写“已完成数据清洗确认无缺失无重复”的前提是你真的跑过这些命令而不是凭感觉说“数据集是干净的”。2.3 大作业最容易忽略的一步标签和特征分离很多同学建模前直接把整个df扔进fit()等于把target列也当成特征输入模型训练时模型已经“看到”了答案测试集准确率直接逼近 100%。这种事一旦在答辩时被追问基本没有还手余地。# 特征矩阵 X 只保留 13 个化学指标 X df.drop(target, axis1) # 目标变量 y 单独存放 y df[target] print(特征矩阵:, X.shape) print(目标变量:, y.shape)drop(target, axis1)按列名删掉目标列返回新的 DataFrame原df不受影响。y是 pandas Series长度与X行数一致都是 178。后面做标准化、PCA、交叉验证时始终只传X和y不再碰带标签的完整表。3. 描述统计与特征筛查三个类别差异到底藏在哪里大作业的得分点从这一章开始真正拉开差距。很多人只贴一个df.describe()就完事但描述统计不是凑字数而是用来回答一个具体问题三类红酒在哪些化学指标上分得开这一章用分组对比、量纲分析、相关性筛查三组操作把“该建模时优先选哪些特征”这个结论一步步推出来。3.1 类别是否平衡统计前先看 target做任何统计分析前先回答“三个类别各有多少样本”。类别不平衡会直接影响后续指标选择如果某一类样本特别少准确率就不可信。# 统计三个类别的样本量 print(df[target].value_counts().sort_index())输出结果中类别 0 有 59 个样本类别 1 有 71 个类别 2 有 48 个比例接近 1:1.2:0.8属于基本平衡。这意味着后面用准确率作为主要指标是安全的不需要额外做重采样或加权。如果你拿到的是其他数据集且类别比例悬殊就要考虑StratifiedKFold或者给模型加class_weight参数不能照搬这套流程。类别平衡确认后接下来按类别分组看特征均值和标准差。这是描述统计里最有信息量的一步。# 按类别分组统计每个特征的均值和标准差 group_stats df.groupby(target).agg([mean, std]) print(group_stats.T.round(2))转置后行是特征名列是三个类别可以逐行比较。用color_intensity颜色强度举例类别 0 均值约 4.97类别 1 约 3.02类别 2 约 1.69三个箱体几乎错开说明这个特征对区分三类酒的贡献很大。再看alcohol类别 0 约 13.7类别 1 约 12.3类别 2 约 13.1虽然也有差异但类别 1 和类别 2 之间的差距很小单独用它分类会有重叠。这一步的价值在于读完这个表你已经知道哪些特征“一眼就能分开”哪些特征“基本分不开”后续建模选特征和解释模型都有据可依。3.2 描述统计里有价值的信息量纲差异预告标准化全局describe()看起来平平无奇但把最大值减最小值算出一个跨度列就能立刻发现数据的一个关键问题量纲差异巨大。# 计算每列的最大最小值跨度 desc df.describe().T[[mean, std, min, max]] desc[range] desc[max] - desc[min] print(desc.round(2))describe()返回的是按特征排列的 DataFrame取转置后只看均值、标准差、最小值、最大值再手动增加range列。这时你会看到proline脯氨酸的跨度接近 1400从 278 到 1680而alcohol的跨度只有 3.8从 11.0 到 14.8。magnesium的跨度也有 92从 70 到 162。如果后续做 PCA 或逻辑回归这类对尺度敏感的模型不标准化的话主成分会被脯氨酸这种量纲大的变量带着走模型学到的不是真实规律而是尺度假象。所以这个跨度列的存在就是后面第 5 章“标准化前就做 PCA 会翻车”的实证依据。报告里把这张表放上去比空写一句“需要标准化”可信得多。3.3 相关性矩阵从冗余特征里挑出建模主力相关性分析解决的是另一个问题13 个特征之间有没有信息重复如果有建模时就不必全部塞进去既省训练时间又降低过拟合风险。# 计算特征间的相关性矩阵并查看与 target 的相关性排名 corr_matrix df.corr(numeric_onlyTrue) corr_with_y corr_matrix[target].drop(target).abs().sort_values(ascendingFalse) print(与target相关性最高的3个特征:) print(corr_with_y.head(3))df.corr()默认计算 Pearson 相关系数numeric_onlyTrue确保只对数值列计算。取corr_matrix[target]得到所有特征与目标列的相关性drop(target)把 target 和自身的相关性 1.0 去掉abs()取绝对值只看相关强度不看方向。排序后可以看到与类别相关性最高的特征大概在 0.63 到 0.73 这个区间具体排序因随机扰动略有浮动但color_intensity、flavanoids黄酮类化合物、proline这几项稳定靠前。再看特征之间的横向相关性flavanoids和total_phenols总酚的相关系数接近 0.86flavanoids与od280/od315_of_diluted_wines稀释葡萄酒的 OD 值也接近 0.79。这说明这三者描述的是同一类化学信息建模时保留一个代表即可。到这里建模方向基本清晰优先关注color_intensity、flavanoids、proline这三个判别力强的特征同时注意特征间的冗余不必追求“全都要”。这一章的三个小节加在一起就是数据分析方法里最实用的一条链路分组对比看判别力量纲分析看预处理必要性相关性分析看信息冗余。4. 可视化给你的大作业配上能讲出道理的图大作业报告里最容易被挑刺的就是图。不是因为图丑而是因为很多图根本解释不了“为什么要画它”。可视化实践的核心原则是每一张图都要回答前面提出的一个问题要么展示类别分布要么展示特征判别力要么展示特征冗余关系。这一章给出三张必做图以及每张图对应的解读思路。4.1 类别分布图和箱线图先用图验证分组统计的结论箱线图是你在答辩时最有力的一张图因为它直接呈现“三个类别在一个特征上的分离程度”看箱体错开多少比背数字直观得多。import matplotlib.pyplot as plt import seaborn as sns # 拼接特征便于 seaborn 按 target 分组绘图 df_plot df.copy() df_plot[target] df_plot[target].astype(str) # 画类别分布柱状图 plt.figure(figsize(6, 4)) sns.countplot(datadf_plot, xtarget) plt.title(三个类别的样本量分布) plt.show()countplot按target分组统计样本量x 轴是三个类别y 轴是数量对应第 3 章的value_counts()用来在报告里可视化“类别平衡”这个结论。接下来是核心图箱线图。# 选择判别力最强的特征画箱线图 fig, axes plt.subplots(2, 2, figsize(12, 8)) cols [alcohol, color_intensity, flavanoids, proline] for idx, col in enumerate(cols): ax plt.subplot(2, 2, idx 1) sns.boxplot(datadf_plot, xtarget, ycol, axax) ax.set_title(f{col} by target) plt.tight_layout() plt.show()subplots(2, 2)创建 2x2 的画布figsize(12, 8)控制画布大小保证每个子图不会被压扁。sns.boxplot的xtarget按类别分组ycol指定特征箱体的高度表示四分位距箱子里的横线是中位数箱子外的须子是数据范围。从箱线图里能直接读出上一章的统计结论color_intensity的三个箱子几乎完全不重叠判别力最强flavanoids的类别 0 和类别 2 间距明显alcohol三个箱子重叠较多判读时要谨慎。答辩时指着这张图说“我据此选择 color_intensity 和 flavanoids 作为主要特征”比说“模型给我的准确率很高”专业得多。4.2 散点图矩阵和相关性热力图把特征冗余画出来箱线图回答的是“单特征能不能分类”散点图矩阵回答的是“两个特征放在一起能不能分得更好”。这是从统计到建模之间的最后一块拼图。# 用 seaborn 的 pairplot 画散点图矩阵 sns.pairplot(df_plot, vars[alcohol, color_intensity, flavanoids, proline], huetarget, diag_kindkde) plt.show()vars指定参与绘制的特征列表huetarget让三个类别的点显示不同颜色diag_kindkde把对角线上的直方图换成核密度曲线曲线重叠度越低说明该特征区分度越高。非对角线上的散点图如果颜色聚成三坨说明这两个特征组合的判别效果好。相关性热力图则是把第 3 章算出来的相关系数矩阵可视化让冗余特征一目了然。plt.figure(figsize(12, 10)) sns.heatmap(df_plot.corr(numeric_onlyTrue), annotTrue, cmapcoolwarm, fmt.2f, linewidths0.5) plt.show()annotTrue在每个格子里显示相关系数数值cmapcoolwarm用冷暖色区分正负相关fmt.2f控制数字格式linewidths0.5给格子加边线防止视觉粘连。红色格子代表正相关蓝色格子代表负相关颜色越深相关越强。这张图的价值在于你能一眼指出“flavanoids 和 total_phenols 是强相关建模时只需要其中一个”这种观察在报告里写出来比单纯的数表更有说服力。4.3 可视化指导建模两张图定下特征清单可视化做完需要把观察结论收敛成具体的建模决策。以这份红酒数据集为例四张图看下来能得出三条可以写进报告的判断第一color_intensity和flavanoids在箱线图和散点图中都表现出一类与两类清晰分离的趋势是建模时必须保留的特征。第二alcohol单独判别力弱但和color_intensity组合后能看到三个类别的分布呈现三个方向说明它适合作为辅助特征保留。第三proline的动态范围大、判别力也强但使用 PCA 或距离模型前必须标准化否则它会喧宾夺主。如果报告篇幅允许可以在这张图上叠加 PCA 之后的主成分散点图把 13 维压缩到 2 维观察类别分布。可视化这条链路走完建模的方向已经被图给“规定”好了后面训练模型只是验证这些图的判断是否成立。5. 红酒数据集的避坑与常见问题四条血泪经验这份数据集体积小、规律明显按理说翻车概率不高但恰恰因为它看起来简单很多人会跳过基本功在四个固定位置上踩坑。每条都是实际跑数据时反复遇到的状况按“现象 → 原因 → 解决”写方便对照排查。5.1 把三分类当成二分类做模型准确率虚高现象模型输出的准确率达到 96%但查看分类报告发现类别 2 的 precision 和 recall 明显低甚至某一类完全没被识别出来。原因红酒数据集的目标变量是 0、1、2 三个类别对应三种不同栽培品种的红酒不是二分类问题。新手容易在建模时用逻辑回归默认的二分类模式或者只看整体准确率忽略了多分类的本质。解决建模前用一行命令确认类别数量和标签含义不要凭感觉猜。print(wine[target_names]) # 输出三个类别的原始名称 print(df[target].value_counts().sort_index()) # 确认每个类别的样本量如果这一步发现样本量严重不平衡后续建模要用StratifiedKFold保持每折类别比例或者给模型加class_weightbalanced。5.2 标准化前就做主成分分析第一主成分被脯氨酸绑架现象PCA 降维后画出的散点图第一主成分方向上三个类别的分布没有明显区分而且主成分权重几乎全部集中在proline上。原因PCA 是方差驱动算法哪个变量量纲大、方差大哪个就对主成分贡献大。前面第 3 章算过proline的跨度接近 1400alcohol只有 3.8两者不在一个尺度上PCA 找到的方向被proline主导其他 12 个特征的信息被稀释。解决先标准化再 PCA两步必须分开写清楚。from sklearn.preprocessing import StandardScaler from sklearn.decomposition import PCA # 先标准化再降维 X_scaled StandardScaler().fit_transform(X) pca PCA(n_components2) X_pca pca.fit_transform(X_scaled) print(主成分方差解释比:, pca.explained_variance_ratio_)StandardScaler()把每个特征变成均值为 0、标准差为 1 的分布fit_transform先计算均值和标准差再套用到数据上。PCA(n_components2)降到两维explained_variance_ratio_查看两个主成分各自解释了多少方差合理区间一般在 50% 到 65% 之间。如果这里不标准化第一主成分的解释率容易虚高但实际可视化效果很差。5.3 随机种子不同测试集准确率在 80% 到 100% 之间跳动现象同一套代码只改random_state的取值训练集和测试集划分变了模型在测试集上的准确率从 0.82 跳到 1.0。原因数据一共只有 178 条测试集通常留出 30 到 40 条。样本量这么小随机划分的偶然性很大划分到简单样本则准确率高划分到难样本则准确率低模型真实水平被单次划分的运气掩盖。解决用交叉验证代替单次 hold-out 划分报告均值而不是单次结果。from sklearn.model_selection import StratifiedKFold, cross_val_score from sklearn.linear_model import LogisticRegression cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) scores cross_val_score(LogisticRegression(max_iter2000), X, y, cvcv) print(f交叉验证准确率: {scores.mean():.3f} ± {scores.std():.3f})StratifiedKFold保证每一折里三个类别的比例跟整体一致n_splits5把数据切成 5 份轮流转训练和验证shuffleTrue打乱顺序避免原始数据按类别排好导致的分割偏差。最后输出的均值比单次准确率可信得多。5.4 只盯着准确率忽略混淆矩阵里的细节现象准确率 96%看起来模型很好但把混淆矩阵打出来发现类别 2 有 20% 的样本被错分到类别 1只是在整体准确率里被稀释了。原因准确率把三个类别的结果汇总成一个数字掩盖了单个类别上的失败。红酒数据集类别基本平衡所以问题不大但如果换成类别不平衡的数据准确率会完全失真。解决每次训练完至少跑一次分类报告和混淆矩阵。from sklearn.metrics import classification_report, confusion_matrix from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) model LogisticRegression(max_iter2000).fit(X_train, y_train) y_pred model.predict(X_test) print(classification_report(y_test, y_pred)) print(confusion_matrix(y_test, y_pred))classification_report输出每个类别的 precision、recall、f1-score能直接看出哪一类被模型冷落。confusion_matrix的行是真实类别列是预测类别矩阵里的非对角线元素就是错分样本的位置。一条额外提醒报告里不要只贴代码和输出每个数字下面加一句判断比如“类别 0 的召回率为 1.00说明这一类基本全部识别正确类别 2 有 3 条被错分到类别 1主要集中在 proline 值偏高的样本”。带分析的输出才是老师想看到的东西。6. 建模验证技巧把结果从“跑通”提升到“能答辩”模型本身在这种小数据集上很难翻车真正区分作业质量的是验证方式是否严谨、解释是否闭环。这一章给出一个直接能用的 Pipeline 对比实验以及一套把模型结果与前面 EDA 结论串起来的技巧。6.1 用 Pipeline 把标准化和模型绑定防止数据泄漏单次StandardScaler().fit(X_train)之后再transform(X_test)是正确写法但手写容易乱。更稳的做法是把标准化放进 Pipeline让交叉验证的每一折自动在训练子集上计算均值方差。from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.model_selection import StratifiedKFold, cross_val_score X df.drop(target, axis1) y df[target] cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) log_pipe make_pipeline( StandardScaler(), LogisticRegression(max_iter2000) ) scores cross_val_score(log_pipe, X, y, cvcv) print(f逻辑回归: {scores.mean():.3f} ± {scores.std():.3f})make_pipeline把标准化和模型串成一条流水线cross_val_score在每一折里自动执行“先 fit 标准化器再 fit 模型再预测验证集”。max_iter2000是给逻辑回归的优化器一个更宽上限避免在低样本量下出现收敛警告。6.2 随机森林对比不标准化的基线模型随机森林不受量纲影响可以直接拿原始特征跑正好可以当对照模型验证逻辑回归的表现。from sklearn.ensemble import RandomForestClassifier rf_pipe make_pipeline( RandomForestClassifier(n_estimators200, random_state42) ) rf_scores cross_val_score(rf_pipe, X, y, cvcv) print(f随机森林: {rf_scores.mean():.3f} ± {rf_scores.std():.3f})n_estimators200是随机森林里常用的中度规模树太少方差大树太多在小数据集上收益递减200 在这个场景足够稳定。两个模型跑完报告里写下“逻辑回归与随机森林的交叉验证均值都在 0.95 附近模型差异不大但逻辑回归在标准化后对特征重要性解释更清晰”这句话已经把模型对比的结论说透了。6.3 用特征重要性回扣 EDA 结论随机森林训练后可以直接读取特征重要性用它来验证前面可视化的判断。rf RandomForestClassifier(n_estimators200, random_state42) rf.fit(X, y) for name, imp in zip(X.columns, rf.feature_importances_): print(f{name}: {imp:.3f})训练完成后打印 13 个特征的重要性分数排名靠前的通常是color_intensity、flavanoids、proline这几项与前面箱线图、散点图里观察到的强判别特征高度重合。这个重合就是一份大作业最完整的证据链先用描述统计和可视化挑出候选特征再用模型验证这些特征确实重要最后在报告里写一句“EDA 阶段发现 color_intensity 与 flavanoids 区分度最高模型特征重要性排序与这一观察一致”。我每次做这类小样本分析都会刻意保留这条证据链因为它能把报告从“我跑了个模型”变成“我理解这份数据”。希望帮到你。本文还有配套的精品资源点击获取
返回列表