数据挖掘入门系列博客:https://www.cnblogs.com/xiaohuiduan/category/1661541.htmlhtml
项目地址:GitHubpython
在上一篇博客中,咱们经过分析亲和性来寻找数据集中数据与数据之间的相关关系。这篇博客咱们会讨论简单的分类问题。git
分类问题,顾名思义我么就是去关注类别(也就是目标)这个变量。分类应用的目的是根据已知类别的数据集获得一个分类模型,而后经过这个分类模型去对类别未知的数据进行分类。这里有一个很典型的应用,那就是垃圾邮件过滤器。github
在这片博客中,咱们使用著名Iris(鸢尾属)植物做为数据集。这个数据集共有150条植物数据,每条数据都给出了四个特征:sepal length、sepal width、petal length、petal width(分别表示萼片和花瓣的长与宽),单位均为cm。一共有三种类别:Iris Setosa(山鸢尾)、Iris Versicolour(变色鸢尾)和Iris Virginica(维吉尼亚鸢尾)算法
在scikit-learn库中内置了该数据集,咱们首先pip安装scikit-learn库数组
下面的代码表示从sklearn中的数据集中加载iris数据集,并打印数据集中的说明(Description)。app
from sklearn.datasets import load_iris
dataset = load_iris()
print(dataset.DESCR)
# data 为特征值
data = dataset.data
# target为分类类别
target = dataset.target
截一个数据集中的说明图:dom
在数据集中,数据的特征值通常是连续值
,好比说花瓣的长度可能有无数个值,而当两个值相近时,则表示类似度很大。(这个是由天然界决定的)svg
与之相反,数据的类别为离散值。由于一种植物就确定是一种植物,一般使用数字表示类别,可是在这里,数字的相近不可以表明这两个类别类似(由于这个类别是人为定义的)函数
数据集的特征为连续数据,而类别是离散值,所以咱们须要将连续值转成类别值,这个称之为离散化
。
而将连续数据进行离散化有个很简单的方法,就是设定一个阈值,高于这个阈值为1,低于这个阈值为0。具体怎么实现咱们在下面再说。
OneR(one rule)算法很简单,当时挺有效的。on rule,一条规则,以上面的iris植物为例,就是咱们选择四个特种中分类效果最好的一个
做为分类依据。这里值得注意的是,选择一个,选择一个,选择一个。
下面是算法的具体步骤,为《Python数据挖掘入门与实践》的原文。
算法首先遍历每一个特征的每个取值,对于每个特征值,统计它在各个类别中的出现次数,找到它出现次数最多的类别,并统计它在其余类别中的出现次数。
举例来讲,假如数据集的某一个特征能够取0或1两个值。数据集共有三个类别。特征值为0的状况下,A类有20个这样的个体,B类有60个,C类也有20个。那么特征值为0的个体最可能属于B类,固然还有40个个体确实是特征值为0,可是它们不属于B类。将特征值为0的个体分到B类的错误率就是40%,由于有40个这样的个体分别属于A类和C类。特征值为1时,计算方法相似,再也不赘述;其余各特征值最可能属于的类别及错误率的计算方法也同样。
统计完全部的特征值及其在每一个类别的出现次数后,咱们再来计算每一个特征的错误率。计算方法为把它的各个取值的错误率相加,选取错误率最低的特征做为惟一的分类准则(OneR),用于接下来的分类。
若是你们对OneR算法为何可以对花卉进行分类感到迷惑的话,能够继续往下看,后面有说明。
在前面的前面咱们介绍了特征值的离散化,经过设定一个阈值,咱们能够将特征值变成简单的0和1。具体怎么作呢?能够看下面的图片:
假如一共有三个类别,120条数据造成一个(120 × 3的矩阵),而后咱们进行压缩行,计算每一列的平均值,而后获得阈值矩阵(1 × 3的矩阵)。这个时候,咱们就能够原先的数据进行离散化,变成0和1了。(这一步能够看示意图)
在python的numpy中有一个方法,numpy.mean,里面常常操做的参数为axis,以m*n的矩阵为例:
average_num = data.mean(axis = 0)
import numpy as np
data = np.array(data > average_num,dtype = "int")
print(data)
经过np.array去构建一个新的数组,当data 大于average_num的时候(为矩阵比较),就为True,不然为False,而后指定类型为int,则True变成了1,False变成了0。结果以下图:
既然是去构建一个分类模型,那么咱们既须要去构建这个模型,也须要去测试这个模型。so,咱们既须要训练集,也须要测试集。根据二八法则,一共150条数据,那么就有120个训练集,30个测试集。
幸运的是sklearn提供了这个划分训练集的库给咱们,train_test_split中0.2 表明的是测试集所占的比例(在我上传到GitHub的源代码中,没有设置这个值,默认是0.25),14表明的是随机种子。
from sklearn.model_selection import train_test_split
# 随机得到训练和测试集
def get_train_and_predict_set():
data_train,data_predict,target_train,target_predict = train_test_split(data,target,test_size=0.2, random_state=14)
return data_train,data_predict,target_train,target_predict
data_train,data_predict,target_train,target_predict = get_train_and_predict_set()
这里有一点须要注意,同时也是困扰了我一段时间的问题。那就是在OneR算法中,只凭借1
个特征,2
种特征值,凭什么可以对3种花卉进行识别??实际上,不能,除非有3个特征值。在《Python数据挖掘入门与实践》,用花卉这个例子举OneR算法不是很恰当,由于当算法实现的时候,只可以识别出两种花卉。以下图:
若是想看一个合适的例子,你们能够去看:https://www.saedsayad.com/oner.htm,在里面最后识别的结果只有yes和no。
具体的训练步骤是怎么样的呢?
首先咱们假设有x,y,z三个特征,每一个特征的特征值为0和1,同时有A,B两个类。所以咱们能够获得下面的统计。
对于每个特征值,统计它在各个类别中的出现次数:
既然咱们获得了统计,这时候,咱们就开始来计算错误率。首先咱们找到某个特征值(如 $X = 0$)出现次数最多的类别。在下图中,被框框圈住的部分就是出现次数最多的特征值(若是有三个类别,任然是选择次数最多的类别)。
再而后咱们就是计算出每个特征的错误率了,下面以$X$为例
同理,咱们能够获得$Y$,$Z$的错误错误率,而后选择最小的错误率做为分类标准便可。
说了这么多,如今来写代码了。
下面是train_feature函数,目的是获得指定特征
,特征值
获得错误率最小的类别。也就是上面图中的$b_{x0},a_{x1}$等等。
from collections import defaultdict
from operator import itemgetter
def train_feature(data_train,target_train,index,value):
""" data_train:训练集特征 target_train:训练集类别 index:特征值的索引 value :特征值 """
count = defaultdict(int)
for sample,class_name in zip(data_train,target_train):
if(sample[index] ==value):
count[class_name] += 1
# 进行排序
sort_class = sorted(count.items(),key=itemgetter(1),reverse = True)
# 拥有该特征最多的类别
max_class = sort_class[0][0]
max_num = sort_class[0][1]
all_num = 0
for class_name,class_num in sort_class:
all_num += class_num
# print("{}特征,值为{},错误数量为{}".format(index,value,all_num-max_num))
# 错误率
error = 1 - (max_num / all_num)
return max_class,error
在train函数中,咱们对全部的特征和特征值进行计算,获得最小的特征错误率。
def train():
errors = defaultdict(int)
class_names = defaultdict(list)
# 遍历特征
for i in range(data_train.shape[1]):
# 遍历特征值
for j in range(0,2):
class_name,error = train_feature(data_train,target_train,i,j)
errors[i] += error
class_names[i].append(class_name)
return errors,class_names
errors,class_names = train()
# 进行排序
sort_errors = sorted(errors.items(),key=itemgetter(1))
best_error = sort_errors[0]
# 获得最小错误率对应的特征
best_feature = best_error[0]
# 当特征值取 0 ,1对应的类别。
best_class = class_names[best_feature]
print("最好的特征是{}".format(best_error[0]))
print(best_class)
训练完成后,咱们就能够进行predict了。predict就是那测试集中数据进行测试,使用本身的模型进行预测,在与正确的做比较获得准确度。看下图predict的流程:
下面是预测代码以及准确度检测代码:
# 进行预测
def predict(data_test,feature,best_class):
return np.array([best_class[int(data[feature])] for data in data_test])
result_predict = predict(data_predict,best_feature,best_class)
print("预测准确度{}".format(np.mean(result_predict == target_predict) * 100))
print("预测结果{}".format(result_predict))
在如下条件下:
最后的结果以下如所示:
在如下条件下:
结果以下图所示
OneR算法很简单,可是在某些状况下却颇有效,没有完美的算法,只有最适用的算法。
GitHub地址:GitHub
参考书籍:Python数据挖掘入门与实践
感谢蒋少华老师为我解惑。