python分类分析--K-近邻(KNN)算法及鸢尾花分类案例

1、分类分析--K近邻(KNN)算法原理

核心思想:根据离自己最近的邻居判断自己属于哪一类,如上图当圆的半径(距离)为1时,k个个体中有2/3个是三角形,则目标圆点(预测点)的分类和三角形为一类;当半径(距离)取值为2时,k个特征个体中有3/5个是正方形,则认为预测点和正方形为一类的思想。由此也说明了KNN算法的结果很大程度取决于K的选择。

我们设定要取的k个邻近点来看属于哪一类别的分类时,其实就找距离目标(预测)点最近的k个点就可以了,那么我们就要先求得各个样本点离预测点的距离d。

在KNN中,通过计算对象间距离来作为各个对象之间的非相似性指标,避免了对象之间的匹配问题,在这里距离一般使用欧氏距离或曼哈顿距离或名可夫斯基距离:

 

2、特征值进行标准化:

当特征变量之间差值非常大时,如果不进行标准化处理,则会导致预测错误。如下图,当k值取3时,非标准化计算的距离最近的电影是E、F、D,100%判断为动作片;标准化处理后最近距离的电影是C、B、D,则判断为爱情片,显然更准确。

3、KNN的优缺点

KNN算法的优势:KNN通过依据k个对象中占优的类别进行决策,而不是单一的对象类别决策。

KNN算法的缺势:

  • k值取得太小容易受到异常值影响,
  • K值取得过大容易受到样本不均衡的影响(如a类取10个样本,b类取30个样本,k取20显然分布不均)。
  • K值取奇数不取偶数(偶数会出现同票现象)
  • 懒情算法,对测试样本分类时的计算量大,内存开销大
  • 必须指定K值,K值选择不当则分类精度不能保证
  • 使用场景:小数据场景,几干~几万样本,具体场景具体业务去测试

4、python实现及案例

API:

sklearn.neighbors.KNeighborsClassifier(n_neighbors=5,algorithm='auto)

  •     sklearn.neighbors.KNeighborsClassifier(n_neighbors=5.algorithm='auto')

  •  n_neighbors:int.可选(默i认=5),k_.neighbors查询默认使用的邻居数
        algornthm:{'auto',‘ball_tree','kd_tree','brute'},可选用于计算最近邻居的算法:ball_tree'将会使用BallTree,'kd_tree将使用KDTree。‘auto将尝试根据传递给t方法的值来决定最合适的算法。(不同实现方式影响效率)

案例数据说明:

df = sklearn.datasets.load_iris() #iris:花的数据集

实例数量:150(三个类各有50个)

属性数量:4(数值型,数值型,帮助预测的属性和类)

Attribute Information:·sepal length 薯片长度(厘米)

·sepal width 薯片宽度(厘米)

·petal length花瓣长度(厘米)

·petal width花瓣宽度(厘米)

·target_names:Setosa山鸢尾、Versicolour 变色鸢尾、Virginica 维吉尼亚鸢尾

#1、获取数据

from sklearn import datasets      #机器学习数据集库
#sklearn.datasets.load_*()        # *:表示某个数据集的名称,load_:获取小规模数据集
df = datasets.load_iris()       #iris:花的数据集
#display(df.data)  #返回特征值(自变量)数组
#display(df.target) #返回目标值(因变量)数组
#print(df["DESCR"]) #返回描述信息
display(df["feature_names"]) #返回特征值的字段名称
display(df.target_names) #返回目标值数字对应解释

# 2、数据集划分

from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(df.data,df.target,test_size=0.2,random_state=11)
print(x_train.shape,x_test.shape,y_train.shape,y_test.shape)

# 3、特征工程:标准化

from sklearn.preprocessing import StandardScaler
import pandas as pd
transfer = StandardScaler() #实例化一个转换器类
#标准化训练集
x_train = transfer.fit_transform(x_train) #调用fit_transform()
data_train = pd.DataFrame(x_train,columns=df["feature_names"])
data_train["y"] = y_train
display(data_train.head(3))
# 标准化测试集
x_test=transfer.transform(x_test) #调用fit_transform()
'''
注意:为什么用transfer.transform(),而不是transfer.fit_transform()????
原因:前面fit()计算训练集每一列的平均值、标准差,
    transform()(x-mean)/std,再进行最终的转换,
    也就是说这样处理,使用的均值和标准差是训练集的,然后再标准化转化,
    否则对测试集样本再次求标准差和均值是不合理的。
    或者也可以先做完特征工程后,再拆分数据集,也是合理的。
'''
data_test = pd.DataFrame(x_test,columns=df["feature_names"])
data_test["y"] = y_test
display(data_test.head(3))

# 4、knn预估器训练模型
from sklearn.neighbors import KNeighborsClassifier  #knn算法库
from sklearn.model_selection import GridSearchCV    #网格搜索和交叉验证

#实例化一个转换器类
#estimator = KNeighborsClassifier(n_neighbors=5,algorithm='auto') #直接选择好参数k后执行

#加入模型选择与调优,网格搜索和交叉验证
#网格搜索和交叉验证原理:后面单独一篇文章介绍
estimator = KNeighborsClassifier()
#准备参数
param_dict = {"n_neighbors":[1,3,5,7,9,11,13,15,17,19]} #k值设定的可能取值
estimator = GridSearchCV(estimator,param_grid=param_dict,cv=10) #cv=10是10折交叉验证

#执行预估器
estimator.fit(data_train.iloc[:,:4],data_train.iloc[:,-1])
#输出结果反映最开始按照默认k=5执行,然后从传入的k值进行模型对比,然后选出最优
'''
GridSearchCV(cv=10, error_score='raise',
       estimator=KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
           metric_params=None, n_jobs=1, n_neighbors=5, p=2,
           weights='uniform'),
       fit_params=None, iid=True, n_jobs=1,
       param_grid={'n_neighbors': [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]},
       pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',
       scoring=None, verbose=0)
'''
# 5、模型评估选择
#方法1:比对真实值和预测值
y_predict = estimator.predict(data_test.iloc[:,:4])  #计算预测值
print(y_predict)
b = data_test.iloc[:,-1] == y_predict  #比对真实值和预测值,相同的返回True
coun = data_test[b].count()[0]  #统计正确的个数
scale = coun/data_test.iloc[:,-1].count()  #计算正确的比例
display(scale)
#方法2:直接计算准确率
accuracy=estimator.score(x_test,y_test)
print(accuracy)

# 3、查看网格搜索和交叉验证返回结果
# 最佳参数:best_params_
print("最佳参数k:",estimator.best_params_)
# 验证集的最佳结果:best_score_
print("验证集的最佳结果准确率:",estimator.best_score_)
# 最佳估计器:best_estimator_
print("最佳估计器",estimator.best_estimator_)
#注意best_estimator_的输出解释:metric='minkowski'是名可夫斯基距离,当p=1时是使用曼哈顿距离,当p=2时是使用欧式距离
# 交叉验证结果:cv_results_
#print(estimator.cv_results_)  #比较长这里就不输出了
# 封装与应用
'''
组织封装代码,为节约运算成本,需要将模型调优选择测试部分的代码单独封装,直接调用最优秀模型。
时间久了,需要再次出入新的数据验证模型是否最优,再调用调优部分的代码,然后修改为新的最优模型。

写入实际需要预测的数据接口,预测返回需要的结果。完事!!!

后面有文章单独详细介绍和操作
'''
发布了129 篇原创文章 · 获赞 143 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_41685388/article/details/104443542