实验四、数据挖掘之KNN,Naive Bayes
实验四、数据挖掘之KNN,Naive Bayes一、实验目的1. 掌握KNN的原理2. 掌握Naive Bayes的原理3. 学会利用KNN与Navie Bayes解决分类问题二、实验工具1. Anaconda2. sklearn三、实验简介1. KNNKNN(K-Nearest Neighbor)工作原理:存在一个样本数据集合,也称为训练样本集,并且样本集中每个数据都存在标签,即我们知道样本集中
实验四、数据挖掘之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
朴素贝叶斯分类器中最核心的便是贝叶斯准则,他用如下的公式表示:
p ( c ∣ x ) = p ( x ∣ c ) p ( c ) p ( x ) p(c|x)= \frac{p(x|c)p(c)}{p(x)} p(c∣x)=p(x)p(x∣c)p(c)
在机器学习中,朴素贝叶斯分类器是一个基于贝叶斯定理的比较简单的概率分类器,其中 naive(朴素)是指的对于模型中各个 feature(特征) 有强独立性的假设,并未将 feature 间的相关性纳入考虑中。
朴素贝叶斯分类器一个比较著名的应用是用于对垃圾邮件分类,通常用文字特征来识别垃圾邮件,是文本分类中比较常用的一种方法。朴素贝叶斯分类通过选择 token(通常是邮件中的单词)来得到垃圾邮件和非垃圾邮件间的关联,再通过贝叶斯定理来计算概率从而对邮件进行分类。
四、实验内容
1. 利用KNN对鸢尾花数据进行分类。
(1) 调用数据的方法如下:
from sklearn.datasets import load_iris
iris = load_iris()# 从sklearn 数据集中获取鸢尾花数据。
(2)数据进行KNN分类
from sklearn import datasets
iris = datasets.load_iris()
#第一步:首先读取Iris数据集资料
#查看数据的规模
print(iris.data.shape)
#查看数据说明,要养成看数据说明的好习惯
print(iris.DESCR)
#由数据描述可知,iris数据集中共有150多鸢尾花,
#每朵花都有四个特征值,并均匀分布在3个不同的亚种。
#第二步:对原始数据进行数据分割
from sklearn.model_selection 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)
Xtest=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('knc的准确率:',knc.score(X_test,y_test))
print(classification_report(y_predict,y_test,target_names=iris.target_names))
运行结果截图
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))
运行结果截图
3.不使用sklearn中的分类方法,自己编写KNN程序(建议用python语言),并对鸢尾花数据进行分类。
# -*- coding: utf-8 -*-
"""
Created on Fri Apr 22 08:32:23 2022
@author: zhenkai
"""
import numpy as np
import pandas as pd
from sklearn import datasets
iris = datasets.load_iris()
# 从sklearn 数据集中获取鸢尾花数据。
#读取数据集,header参数来指定参数标题的行,默认为0,
#第一行,如果没有标题使用None
#data = iris.data
data = pd.read_csv('iris.csv',header=0)
#对文本进行处理,将Species列的文本映射成数值类型
data['species'] = data['species'].map({'virginica':0,'setosa':1,'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类
"""使用python实现K近邻算法"""
class KNN:
def __init__(self,k):
self.k = k
"""
训练方法
Parameters
----
X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]
y:类似数组类型,形状为[样本数量] 每个样本的目标值,也是就是标签
"""
#将X转换成ndarray类型,如果X已经是ndarray则不进行转换
def fit(self, X, y):
self.X = np.asarray(X)
self.y = np.asarray(y)
"""
根据参数传递的样本,对样本数据进行预测,返回预测之后的结果
Parameters
----
X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]
Return
---- result:数类型,预测的结果。
"""
#将测试的X转换为ndarray结构
def predict(self, X):
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)
"""
根据参数传递的样本,对样本数据进行预测
(考虑权重,使用距离的倒数作为权重),返回预测之后的结果
Parameters
----
X:类似数组类型,list,ndarray……形状:[样本的数量,特征的数量]
Return
----
result:数类型,预测的结果。
"""
def predict2(self, X):
X = np.asarray(X)#将测试的X转换为ndarray结构
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['sepal_length'][:40],y=t0['petal_length']
[:40],color='r',label='virginica')
plt.scatter(x=t1['sepal_length'][:40],y=t1['petal_length']
[:40],color='g',label='setosa')
plt.scatter(x=t2['sepal_length'][:40],y=t2['petal_length']
[:40],color='b',label='versicolor')
#绘制测试集数据,使用不同的图案显示预测正确和错误的结果
right = test_X[result == test_Y]
wrong = test_X[result != test_Y]
plt.scatter(x=right['sepal_length'],y=right['petal_length'],color='c',marker='x',label='right')
plt.scatter(x=wrong['sepal_length'],y=wrong['petal_length'],color='m',marker='>',label='wrong')
#显示额外信息
plt.xlabel("花萼长度")
plt.ylabel("花瓣长度")
plt.title("KNN分类显示结果")
plt.legend(loc="best")
plt.show()
运行截图如下:
4.(选做) 不使用sklearn中的分类方法,自己编写Navie Bayes程序(建议用python语言),并对鸢尾花数据进行分类。
# -*- coding: utf-8 -*-
"""
Created on Fri Apr 22 09:31:10 2022
@author: zhenkai
"""
from sklearn import datasets
from sklearn.model_selection import GridSearchCV,train_test_split,cross_val_score
iris = datasets.load_iris()#下载鸢尾花数据集
data_x = iris["data"]#特征x
# print(data_x)
data_y = iris["target"]#类别y
#将每一列特征划分成几份区间,标准化
num_1=5#每个特征分成五份,我这里是每个特征都分成5个区间,也可以分开。不过代码自己改
def standard_feature(feature_col,num):
max_0 = max(data_x[:,feature_col])
min_0 = min(data_x[:,feature_col])
width_0 = (max_0-min_0)/num
for j in range(len(data_x[:,feature_col])):
for i in range(1, num + 1):
if min_0+(i-1)*width_0<=data_x[j,feature_col]<=min_0+i*width_0:
data_x[j,feature_col] =i
# print(data_x[j,feature])
break
x_col_num = len(data_x[0])#获取列数及特征数目
def get_pb(one_feature,col,x_train):
'''
one_feature在该x_train数据集的col列的概率
:param one_feature:查找的特征是啥
:param col: 列
:param x_train:
:return: 返回该特征的概率
'''
fea_sum = 0
for i in x_train[:,col]:
if i == one_feature:
fea_sum+=1
col_all = len(x_train)
p_b1 =fea_sum/col_all
# if p_b1 == 0:
# print("第几列第几个特征个数为0",col,one_feature,len(x_train))#如果当你把x特征分的太细会出现有些特征测试集有但训练集没有。看len(x_train)当这个等于训练集总数第78行会除数为0
return p_b1
for i in range(x_col_num):#data_x将所有特征标准化
standard_feature(i,num_1)
x_train,x_test,y_train,y_test = train_test_split(data_x,data_y,test_size=0.3)#拆分成测试集,训练集
print("训练集样本数量",len(x_train))
print("测试集样本数量",len(x_test))
test_PB_list =[]#
for row_i in range(len(x_test)):
P_B = 1
for col_i in range(x_col_num):
one_pb = get_pb(x_test[row_i,col_i],col_i,x_train)
P_B *= one_pb
#经过for循环得到每个测试集样本的P(B)
test_PB_list.append(P_B)
print("test_PB_list元素个数",len(test_PB_list))
y =3
y_index_list = []#分别存放对应y的全部训练集的全部列索引,该列表元素的列表索引对应y
for y_num in range(y):
one_y_index_list =[]
for y_index in range(len(y_train)):
if y_train[y_index] == y_num:
one_y_index_list.append(y_index)
y_index_list.append(one_y_index_list)
print("训练集中每类拥有索引个数",*[len(a) for a in y_index_list])
y_num_list = []
for y_num in range(y):
one_y_num = 0
for y_index in range(len(y_train)):
if y_train[y_index] == y_num:
one_y_num+=1
y_num_list.append(one_y_num)
print("训练集每类拥有个数",y_num_list)
test_y_predict =[]#测试集预测Y
for test_row in range(len(x_test)):#test_row为测试集每行样本,每行样本都需要计算分类为各个y的概率,哪个概率最大,说明就是哪一类
final_y_P = []
for y_index in range(y):
x_train_yindex = x_train[y_index_list[y_index],:]
P_BinA = 1
for col_i in range(x_col_num):
one_pb = get_pb(x_test[test_row, col_i], col_i, x_train_yindex)
P_BinA *= one_pb
PAinB=(y_num_list[y_index]/len(y_train))*P_BinA/test_PB_list[test_row]
final_y_P.append(PAinB)
belong_class = final_y_P.index(max(final_y_P))
test_y_predict.append(belong_class)
print(test_y_predict)
print(list(y_test))
predict_right_num = 0
for i in range(len(test_y_predict)):
if test_y_predict[i] == y_test[i]:
predict_right_num+=1
probability = predict_right_num/len(test_y_predict)
print("预测正确概率",probability)
运行结果截图
五、实验总结(写出本次实验的收获,遇到的问题等)
KNN计算步骤
1)算距离:给定测试对象,计算它与训练集中的每个对象的距离
2)找邻居:圈定距离最近的k个训练对象,作为测试对象的近邻
3)做分类:根据这k个近邻归属的主要类别,来对测试对象分类 在实验过程中发现knn样本不平衡容易导致结果错误,而且计算量较大
更多推荐
所有评论(0)