实验四、数据挖掘之KNN,Naive Bayes
一、实验目的
1. 掌握KNN的原理
2. 掌握Naive Bayes的原理
3. 学会利用KNN与Navie Bayes解决分类问题
二、实验工具
1. Anaconda
2. sklearn
三、实验简介
1. KNN
KNN(K-Nearest Neighbor)工作原理:存在一个样本数据集合,也称为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中每一数据与所属分类对应的关系。输入没有标签的数据后,将新数据中的每个特征与样本集中数据对应的特征进行比较,提取出样本集中特征最相似数据(最近邻)的分类标签。一般来说,我们只选择样本数据集中前k个最相似的数据,这就是k近邻算法中k的出处,通常k是不大于20的整数。最后选择k个最相似数据中出现次数最多的分类作为新数据的分类。
说明:KNN没有显示的训练过程,它是“懒惰学习”的代表,它在训练阶段只是把数据保存下来,训练时间开销为0,等收到测试样本后进行处理。
2. Navie Bayes
朴素贝叶斯分类器中最核心的便是贝叶斯准则,他用如下的公式表示:
在机器学习中,朴素贝叶斯分类器是一个基于贝叶斯定理的比较简单的概率分类器,其中 naive(朴素)是指的对于模型中各个 feature(特征) 有强独立性的假设,并未将 feature 间的相关性纳入考虑中。
朴素贝叶斯分类器一个比较著名的应用是用于对垃圾邮件分类,通常用文字特征来识别垃圾邮件,是文本分类中比较常用的一种方法。朴素贝叶斯分类通过选择 token(通常是邮件中的单词)来得到垃圾邮件和非垃圾邮件间的关联,再通过贝叶斯定理来计算概率从而对邮件进行分类。
四、实验内容
1. 利用KNN对鸢尾花数据进行分类。
(1) 调用数据的方法如下:
from sklearn.datasets import load_iris
iris = load_iris()# 从sklearn 数据集中获取鸢尾花数据。
(2)数据进行KNN分类
from sklearn.datasets import load_iris
iris = load_iris()
#第一步:读取Iris数据集资料
#查看数据规模
print (iris.data.shape)
#查看数据说明,要养成看数据说明的好习惯
print (iris.DESCR)
#由数据描述可知,iris数据集中共有150多鸢尾花,每朵花都有四个特征值,并均匀分布在3个不同的亚种。
#第二步:对原始数据进行数据分割
from sklearn.cross_validation import train_test_split
X_train,X_test,y_train,y_test=train_test_split(iris.data,iris.target,test_size=0.25,random_state=33)
#第三步: 使用KNN分类器训练模型并预测
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
X_train = ss.fit_transform(X_train)
X_test = ss.transform(X_test)
#导入knn分类器
from sklearn.neighbors import KNeighborsClassifier
knc = KNeighborsClassifier()
knc.fit(X_train,y_train)
y_predict = knc.predict(X_test)
#第四步:对KNN分类器的预测性能进行评估
from sklearn.metrics import classification_report
print( 'Accuracy of knc:',knc.score(X_test,y_test))
print( classification_report(y_predict,y_test,target_names=iris.target_names))
image.png
2. 利用Navie Bayes对鸢尾花数据建模
# 通过朴素贝叶斯对鸢尾花数据进行分类
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB, GaussianNB
import matplotlib.pyplot as plt
import numpy as np
import matplotlib as mpl
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
iris = datasets.load_iris() # 加载鸢尾花数据
iris_x = iris.data # 获取数据
# print(iris_x)
iris_x = iris_x[:, :2] # 取前两个特征值
# print(iris_x)
iris_y = iris.target # 0, 1, 2
x_train, x_test, y_train, y_test = train_test_split(iris_x, iris_y, test_size=0.75, random_state=1) # 对数据进行分类 一部分最为训练一部分作为测试
# clf = GaussianNB()
# ir = clf.fit(x_train, y_train)
clf = Pipeline([
('sc', StandardScaler()),
('clf', GaussianNB())]) # 管道这个没深入理解 所以不知所以然
ir = clf.fit(x_train, y_train.ravel()) # 利用训练数据进行拟合
# 画图:
x1_max, x1_min = max(x_test[:, 0]), min(x_test[:, 0]) # 取0列特征得最大最小值
x2_max, x2_min = max(x_test[:, 1]), min(x_test[:, 1]) # 取1列特征得最大最小值
t1 = np.linspace(x1_min, x1_max, 500) # 生成500个测试点
t2 = np.linspace(x2_min, x2_max, 500)
x1, x2 = np.meshgrid(t1, t2) # 生成网格采样点
x_test1 = np.stack((x1.flat, x2.flat), axis=1)
y_hat = ir.predict(x_test1) # 预测
mpl.rcParams['font.sans-serif'] = [u'simHei'] # 识别中文保证不乱吗
mpl.rcParams['axes.unicode_minus'] = False
cm_light = mpl.colors.ListedColormap(['#77E0A0', '#FF8080', '#A0A0FF']) # 测试分类的颜色
cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b']) # 样本点的颜色
plt.figure(facecolor='w')
plt.pcolormesh(x1, x2, y_hat.reshape(x1.shape), cmap=cm_light) # y_hat 25000个样本点的画图,
plt.scatter(x_test[:, 0], x_test[:, 1], edgecolors='k', s=50, c=y_test, cmap=cm_dark) # 测试数据的真实的样本点(散点) 参数自行百度
plt.xlabel(u'花萼长度', fontsize=14)
plt.ylabel(u'花萼宽度', fontsize=14)
plt.title(u'GaussianNB对鸢尾花数据的分类结果', fontsize=18)
plt.grid(True)
plt.xlim(x1_min, x1_max)
plt.ylim(x2_min, x2_max)
plt.show()
y_hat1 = ir.predict(x_test)
result = y_hat1 == y_test
print(result)
acc = np.mean(result)
print('准确度: %.2f%%' % (100 * acc))
image.png
image.png
3. 不使用sklearn中的分类方法,自己编写KNN程序(建议用python语言),并对鸢尾花数据进行分类。
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
iris = load_iris()# 从sklearn 数据集中获取鸢尾花数据。
#读取数据集,header参数来指定参数标题的行,默认为0,第一行,如果没有标题使用None
data = iris.data
#data = pd.read_csv('iris.csv',header=0)
#对文本进行处理,将Species列的文本映射成数值类型
#data['Species'] = data['Species'].map({'Iris-virginica':0,'Iris-setosa':1,'Iris-versicolor':2})
#data.head(20)
#显示末尾行数
# data.tail(20)
#随机显示,默认为1条
data.sample(10)
#删除不需要的列
data.drop("id",axis=1,inplace=True)
#重复值检查,any(),一旦有重复值,就返回True
data.duplicated().any()
#删除重复的数据
data.drop_duplicates(inplace=True)
#查看各类别的数据条数
data['Species'].value_counts()
#编写KNN类
class KNN:
"""使用python实现K近邻算法"""
def __init__(self,k):
"""初始化方法
Parameters:
----
k:int
邻居的个数
"""
self.k = k
def fit(self, X, y):
"""训练方法
Parameters
----
X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]
y:类似数组类型,形状为[样本数量]
每个样本的目标值,也是就是标签
"""
#将X转换成ndarray类型,如果X已经是ndarray则不进行转换
self.X = np.asarray(X)
self.y = np.asarray(y)
def predict(self, X):
"""根据参数传递的样本,对样本数据进行预测,返回预测之后的结果
Parameters
----
X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]
Return
----
result:数类型,预测的结果。
"""
#将测试的X转换为ndarray结构
X = np.asarray(X)
result = []
for x in X:
#ndarray相减为对应元素相减,测试的X的每一行与self.X 相减
#求欧氏距离:每个元素都取平方值
dis = np.sqrt(np.sum((x - self.X) ** 2,axis = 1))
#求最近的k个点的距离,sort()排序不适用,因为排序后打乱了顺序
#argsort(),返回每个元素在排序之前原数组的索引
index = dis.argsort()
#取前k个元素,距离最近的k的元素
index = index[:self.k]
#返回数组中每个元素出现的次数,元素必须是非负整数
count = np.bincount(self.y[index])
#返回ndarray之最大的元素的索引,该索引就是我们判定的类别
result.append(count.argmax())
return np.asarray(result)
def predict2(self, X):
"""根据参数传递的样本,对样本数据进行预测(考虑权重,使用距离的倒数作为权重),返回预测之后的结果
Parameters
----
X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]
Return
----
result:数类型,预测的结果。
"""
#将测试的X转换为ndarray结构
X = np.asarray(X)
result = []
for x in X:
#ndarray相减为对应元素相减,测试的X的每一行与self.X 相减
#求欧氏距离:每个元素都取平方值
dis = np.sqrt(np.sum((x - self.X) ** 2,axis = 1))
#求最近的k个点的距离,sort()排序不适用,因为排序后打乱了顺序
#argsort(),返回每个元素在排序之前原数组的索引
index = dis.argsort()
#取前k个元素,距离最近的k的元素
index = index[:self.k]
#返回数组中每个元素出现的次数,元素必须是非负整数,【使用weight考虑权重,权重为距离的倒数】
count = np.bincount(self.y[index],weights=1/dis[index])
#返回ndarray之最大的元素的索引,该索引就是我们判定的类别
result.append(count.argmax())
return np.asarray(result)
#数据集拆分成训练集和测试集
#1、提取每个类别鸢尾花的数量
t0 = data[data['Species']==0]
t1 = data[data['Species']==1]
t2 = data[data['Species']==2]
#打乱顺序,random_state ,记住打乱的顺序
t0 = t0.sample(len(t0),random_state=0)
t1 = t1.sample(len(t1),random_state=0)
t2 = t2.sample(len(t2),random_state=0)
train_X = pd.concat([t0.iloc[:40,:-1],t1.iloc[:40,:-1],t2.iloc[:40,:-1]],axis=0)
train_Y = pd.concat([t0.iloc[:40,-1],t1.iloc[:40,-1],t2.iloc[:40,-1]],axis=0)
test_X = pd.concat([t0.iloc[40:,:-1],t1.iloc[40:,:-1],t2.iloc[40:,:-1]],axis=0)
test_Y = pd.concat([t0.iloc[40:,-1],t1.iloc[40:,-1],t2.iloc[40:,-1]],axis=0)
#进行训练与测试
knn = KNN(k=3)
#进行训练
knn.fit(train_X,train_Y)
#进行测试
result = knn.predict(test_X)
# display(result)
# display(test_Y)
#查看预测结果
display(np.sum(result == test_Y))
#对计算结果进行可视化展示
import matplotlib as mpl
import matplotlib.pyplot as plt
#设置matplotlib 支持中文显示
mpl.rcParams['font.family'] = 'SimHei' #设置字体为黑体
mpl.rcParams['axes.unicode_minus'] = False #设置在中文字体是能够正常显示负号(“-”)
#设置画布大小
plt.figure(figsize=(10,10))
#挑选维度进行散点图显示
#绘制训练集的散点图'Iris-virginica':0,'Iris-setosa':1,'Iris-versicolor':2
plt.scatter(x=t0['SepalLengthCm'][:40],y=t0['PetalLengthCm'][:40],color='r',label='Iris-virginica')
plt.scatter(x=t1['SepalLengthCm'][:40],y=t1['PetalLengthCm'][:40],color='g',label='Iris-setosa')
plt.scatter(x=t2['SepalLengthCm'][:40],y=t2['PetalLengthCm'][:40],color='b',label='Iris-versicolor')
#绘制测试集数据,使用不同的图案显示预测正确和错误的结果
right = test_X[result == test_Y]
wrong = test_X[result != test_Y]
plt.scatter(x=right['SepalLengthCm'],y=right['PetalLengthCm'],color='c',marker='x',label='right')
plt.scatter(x=wrong['SepalLengthCm'],y=wrong['PetalLengthCm'],color='m',marker='>',label='wrong')
#显示额外信息
plt.xlabel("花萼长度")
plt.ylabel("花瓣长度")
plt.title("KNN分类显示结果")
plt.legend(loc="best")
plt.show()
4. (选做) 不使用sklearn中的分类方法,自己编写Navie Bayes程序(建议用python语言),并对鸢尾花数据进行分类。
五、实验总结(写出本次实验的收获,遇到的问题等)
KNN计算步骤
1)算距离:给定测试对象,计算它与训练集中的每个对象的距离
2)找邻居:圈定距离最近的k个训练对象,作为测试对象的近邻
3)做分类:根据这k个近邻归属的主要类别,来对测试对象分类
在实验过程中发现knn样本不平衡容易导致结果错误,而且计算量较大
网友评论