大家好 这个部分我们将基于UCI葡萄酒数据集 完成一个从 数据获取、预处理和探索、机器学习建模,调参 及模型评估等较为完整的过程 希望给大家一个较为完整的 利用机器学习模型实现分类任务的认识 先来看UCI葡萄酒数据集 我们直接看一下它的官网 大家可以先通过网站上数据集的摘要 了解数据集的基本情况 可以发现UCI葡萄酒数据集包括两份 分别是关于葡萄牙北部的红色 和白色vinho verde葡萄酒样本 它是经典的机器学习标准数据集 常用于数据分析和机器学习分类等任务 我们选择红葡萄酒数据集进行分析 点击这里就可以进行数据的下载 再来看一下数据的基本信息 这是数据集中各属性的说明 可以看到有11个输入变量也就是特征属性 它们基于物理化学测试 包括如残糖residual sugar PH值PH 酒精度alcohol 输出变量也就是目标属性quality 是葡萄酒的质量评分 基于专家感官获得 值从0到10 我们直接来看一下数据 可以发现数据有表头 数据间用分号;分隔 那么很简单 只要利用pandas模块的read_csv()函数 并将其参数sep的值设为';'就可以读取数据了 来读取数据 读取数据 将数据保存到变量wine中 wine是一个DataFrame对象 下面先来探索数据并进行必要的预处理 执行程序 先看一下数据的基本情况 共有1599条非空记录 12个属性 像这种采集的数据常含有重复记录 来检查一下 duplicated()方法可以检查Series 或DataFrame对象是否有重复记录 如果有则返回True 没有则返回Fasle 返回结果用sum()方法计算总和就能获得重复的行数 可以看到有240条重复记录 来删除重复记录 用drop_duplicates()方法 将结果仍然赋值给wine 处理后还剩1359条记录 来看一下数据的基本统计信息 简单看一下目标属性quality 可以看到均值是5.6 最小值是3 最大值是8 中位数和上四分位数都是6 显而易见质量为6的记录至少含所有记录的1/4 看一下quality属性具体每一类有多少个值 使用value_counts()方法 可以看到中间的数字5和6对应的记录都比较多 头尾的8和3对应记录比较少 符合正态分布 再来绘制饼图 可以看到quality是5和6的记录 合计超过了总记录数的80% 再来看一看quality 与其他属性之间的皮尔逊相关系数 数据一般满足正态分布这里就不单独测试了 可以看到volatile acidity和alcohol属性 与quality的相关性相对比较大 一个是负线性相关 一个是正线性相关 我们继续通过绘图来看一下每一个quality值 对应的volatile acidity和alcohol属性的均值的分布情况 更直观地来看一下它们之间的相关性 用seaborn模块的barplot()函数来处理 分别把要观察的属性列出来 看一下这两张图 图怎么看呢 例如看alcohol 看这一条 这是quality为8对应的所有记录中alcohol值的均值 接近12 其他也会看了吧 是不是可以比较明显地看到alcohol值越高 quality就越高 而volatile acidity正好相反 与刚才的相关系数的判断一致 不过用条形图更加细节 更加直观 属性和记录都较少 我们就不做数据规约了 数据探索和预处理工作我们就谈到这里 下面来谈一下我们的核心任务 假设现在有一批新的红葡萄酒数据 通过物理化学测试知道了它们的如PH值 和alcohol酒精度等11个属性 是不是不需要专家的品鉴 就可能获知这些酒的quality值呢 从上面的数据探索我们知道了quality的值有6个 从3-8 类别比较多 分类难度有点大 如果我们把多分类问题改成二分类问题 例如将quality的值[3,8]划分为两部分 [3,6]的属于质量一般 [7,8]属于质量很好 进行二值化处理 问题是不是就变得容易一些了 只要判断新的酒是属于质量一般还是很好就可以了 当然我们也可以将原始数据处理成3个分类 例如我们马上要看到的程序 就是将quality处理成了3类 先来看程序 看这个部分 我们可以使用之前介绍过的 pandas模块中的cut()函数将数据分箱 先设置待划分数据的bins 大家想一想这个bins值的写法是如何划分数据的 注意bins划分数据的方式是构成左开右闭区间 那么这里是不是就是(2,4],(4,6]和(6,8] 因为quality的值从3到8 那就是3和4一组 5和6一组 7和8一组 组名由这里的group_names确定 包括low、medium和high 执行后wine中将会多一个属性quality_lb 它的值就是low、medium和high中的一个 运行一下 确实是这样 多了一个属性 每个值是刚才说的三个中的一个 字符串不便运算 我们接着用preprocessing模块中的LabelEncoder()函数 为quality_lb属性分配标签0、1和2 执行后label属性中即为具体的标签 继续运行 看到了吧 增加了一个新列 成功了 挺方便的吧 用value_counts()方法再来统计一下新类别的分布 可以看到medium类别对应的记录数最多 这是high对应的类别数 这是low对应的类别数 接着对数据做一些必要处理 这样处理以后wine中就是11个特征属性 和新产生的label这样总的12个属性 下面再通过数据选择的方式 将特征属性和目标属性分开 分别存入X和y中 看一下X和y的值 因为是分类任务 通常接下来的工作是将数据划分成训练集和测试集 常规且简单的划分方法是 使用train_test_split()这样的一个函数 这个函数可以随机地从样本中 按比例选取训练数据和测试数据 test_size这个参数用来设置测试集的比例 这里我们设为0.2 也就是20% 计算后知道是272条记录 那另外1359条记录的80% 即1087条记录就作为了训练集 用于训练模型 在真正使用机器学习模型前 我们还需要把数据进行规范化处理 这里将特征属性训练集 和测试集用scale()函数进行了标准化处理 接着我们用随机森林模型来解决这个分类问题 随机森林(Random Forest)是比较新的一种机器学习模型 它是一种集成学习(Ensemble Learning)算法 所谓集成学习 就是构建并结合多个学习器来完成学习任务 随机森林模型属于并行式集成学习代表Bagging类型 具体做法为对原始数据集进行多次随机采样 得到多个不同的采样集 然后基于每个采样集训练一个决策树基学习器 再将这些基学习器进行结合 最终通过投票或取均值等方式 使得模型获得较高的精准度和泛化性能 具体模型的细节 大家可以根据各自的基础和需求去学习 我们这个案例的主要目的是基于数据 提出一个实际的问题 构建一个较为完整的解决方案 重点在过程 后续大家可以基于自己的需求 补充各种算法模型的知识后 就可以真正进行数据挖掘了 用sklearn模块可以非常方便地完成建模和测试工作 看一下这几行代码 首先通过RandomForestClassifier()函数构建一个分类器 n_estimators参数非常常用 它是指在利用最大投票数 或均值来预测前想要建立子树的数量 因为基学习器是决策树 通常比较多的子树可以让模型有更好的性能 但代码会变慢 这里将参数值设为200 接着用模型的fit()方法基于训练集进行学习 然后利用predict()方法 基于测试集的X部分数据(X_test)进行预测 预测的结果就保存在这个变量中 如果换成其他的分类模型 程序的写法也基本一致 通常只要把用于建模的函数换掉就可以了 那么预测效果怎么样呢 我们需要用预测结果与实际的y值比较 这是实际的y值 这是预测结果 预测结果我们用最常规的混淆矩阵来观察 混淆矩阵是一种特定的矩阵 它是一种算法性能的可视化呈现 每一列代表预测值 每一行代表的是实际的类别 来运行看一下 这就是分类结果的混淆矩阵 混淆矩阵怎么看呢 最简单的理解就是对角线上的个数 是正确判断出类别的数据记录条数 其他位置的是类别误判的条数 对角线上的值占总数越大表示分类效果越好 再具体来看 例如15这个值 它是类别0判断正确的个数 类别0也就是质量为high这一类 那总的类别0个数有多少呢 是15加上17共32个 刚才已经说过了 混淆矩阵当中行代表实际的类别 列代表预测值 再来看这个值 想一想怎么看 其实刚才已经说过了 表示本来应该是类别0的记录 被误判成了类别2的数目 其他的数字是不是也会看了 大家应该会看吧 哪一个类别的分类精度是最高 是不是类别2 也就是medium类 只有6个被误判成了类别0 也就是本来的medium类别被误判成了high类别 大致明白了吧 另外我们之前说过 除了根据经验设计参数外还可以人工调参 GridSearchCV()函数的作用就是调参 在机器学习模型中 需要人工选择的参数称为超参数 例如随机森林中决策树的个数 就是之前n_estimators参数对应的值 GridSearchCV()函数其实就是暴力搜索 只要把参数输进去 就能给出最优化的结果和参数 但是这个方法适合于小数据集 我们简单示意一下 正在进行暴力搜索 比较慢 结束了 我们看一下这里有一个参数best_params 它保存的是已取得最佳结果的参数的组合 我们这里选择了要调参的这两个参数 可以看一下best_params的结果 这个值只有30 然后基于最佳参数组合重新训练模型 预测结果 具体的细节大家可以根据需要自行去探索 时间关系我们只是提出一种常规的调参做法 这个例子我们就介绍完毕了 希望这个例子可以让大家对利用机器学习算法 进行数据挖掘完成分类任务有一个基本的认识 随着大家的知识储备越来越多 就可以真正把这些算法用来解决自己的实际问题了