kNN原理与python应用

文章目录

      • 0. 原理
      • 1. 应用-Iris数据集
        • 查看数据
        • 数据拆分为训练集与测试集
        • 观察数据-可视化
        • kNN-model
        • 评估模型-使用测试集,进行结果对比
        • 进行预测
      • 2. 模型复杂度和泛化能力之间的关系-乳腺癌数据集
      • 3. kNN回归

0. 原理

待更

1. 应用-Iris数据集

来源于《Python机器学习基础教程》一书,机器学习之旅从鸢尾花开始~
注意:python中机器学习数据集结构:

feature target
X1,…,Xn y
data target
X y

scikit-learn 中的数据通常用大写的X 表示,而标签用小写的y 表示。这是来源于f(x)=y ,其中x 是函数的输入,y 是输出。大写的X是因为数据是一个二维数组(矩阵),小写的y 是因为目标是一个一维数组(向量),这也是数学中的约定。

导入包并加载数据

import numpy as np
import pandas as pd
import seaborn as sns  # 美化绘图
import sklearn
from sklearn.datasets import load_iris  # 导入数据集
iris_dataset = load_iris()  # 加载后的数据是Bunch对象,类似于字典

查看数据

print("Keys of iris_dataset:\n{}".format(iris_dataset.keys()))  

# 其中DESCR是数据集的说明
Keys of iris_dataset:
dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names', 'filename'])
print(iris_dataset['DESCR'])  # print带格式,直接输出没有格式

kNN原理与python应用_第1张图片

著名的鸢尾花数据集, 请注意,它与R中的相同,但与UCI中的不同
机器学习存储库,其中有两个错误的数据点。

print(iris_dataset['target_names'])  # 类别名
print(iris_dataset['feature_names'])  # 特征名
print(type(iris_dataset['data']))  # 数据结构
print(iris_dataset['data'].shape)  # 维度
print(iris_dataset['data'][:5])  # 数据前五行
print(type(iris_dataset['target']))  # target's type
print(iris_dataset['target'].shape)  # target's shape

kNN原理与python应用_第2张图片

iris_dataset['target']  # 0,1,2
iris_dataset['target_names']  
# array(['setosa', 'versicolor', 'virginica'], dtype='

数据拆分为训练集与测试集

scikit-learn 中的train_test_split 函数可以随机打乱数据集并进行拆分。默认将75% 的行数据及对应标签作为训练集,剩下25% 的数据及其标签作为测试集。使用25% 的数据作为测试集是很好的经验法则。

from sklearn.model_selection import train_test_split

X, y = iris_dataset['data'], iris_dataset['target']
X_train, X_test, y_train, y_test = train_test_split(X,y,random_state=0)

print(X_train.shape)  # (112, 4)
  • 为什么要打乱顺序?如果只将后25%用于测试,则测试集都来自第3种花,不合理,确保test中含有所有类别的数据
  • 为什么指定随机数种子?为了确保多次运行同一函数能够得到相同的输出
# Split arrays or matrices into random train and test subsets
?train_test_split  

X_train, X_test, y_train, y_test = train_test_split(data_X,data_y,…) : 返回4个array

  1. test_size : if float,between 0.0 and 1.0,测试集应占的比例,默认0.25;if int,表示测试集中的样本数
  2. random_state : If int, random_state is the seed used by the random number generator;随机数种子
  3. shuffle :(default=True):在拆分前是否随机打乱数据顺序
    注:详情与示例见docstring

观察数据-可视化

散点图,将一个特征作为x 轴,另一个特征作为y 轴,将每一个数据点绘制为图上的一个点,一次只能绘制两个特征,对多于3 个特征的数据集作图,绘制散点图矩阵。
散点图矩阵无法同时显示所有特征之间的关系,只能两两查看,所以这种可视化方法可能无法展示数据的某些有趣内容。
建议使用seaborn绘制

# 先转换为dataframe,然后使用pandas.scatter_matrix(),对角线是每个特征的直方图或密度图
df = pd.DataFrame(X_train,columns=iris_dataset['feature_names'])

# 创建散点图矩阵,按y_train着色(一列标签)。因为X_train和y_train一一对应
grr = pd.plotting.scatter_matrix(df,c=y_train,figsize=(10,10),marker='.',hist_kwds={'bins':20},s=60,alpha=0.8)

pandas自带绘图函数pd.plotting.scatter_matrix(frame)
可选参数:(详见docstring)

  1. diagonal:必须且只能在{‘hist’, ‘kde’}中选择1个,’hist’表示直方图,’kde’表示核密度估计(Kernel Density Estimation),该参数是scatter_matrix函数的关键参数。
  2. hist_kwds:与hist相关的字典参数
  3. c:颜色

对于散点图矩阵,seaborn包画图更美观。
sns绘制散点图矩阵所需的数据结构是X与y在一起的一个df。
使用详情参见docstring。

y_train_se = pd.Series(y_train)  # se可以自动变换类型,array不可以
y_train_se[y_train_se == 0] = 'setosa'  # 方便图例生成
y_train_se[y_train_se == 1] = 'versicolor'
y_train_se[y_train_se == 2] = 'virginica'
df['class'] = y_train_se  # sns绘制散点图矩阵所需的数据结构是X与y在一起的一个df

sns.pairplot(df,plot_kws={'alpha':0.8},hue='class')  # hue为df中一列的列名,为不同的点标记颜色,该列的值为图例,按类别标签着色

kNN原理与python应用_第3张图片
参考:
https://blog.csdn.net/zyb228/article/details/101940096/
https://www.jianshu.com/p/6e18d21a4cad

kNN-model

  1. k近邻分类器:构建此模型只需要保存训练集即可。要对一个新的数据点做出预测,算法会在训练集中寻找与这个新数据点距离最近的数据点,然后将找到的数据点的标签赋值给这个新数据点。
  2. k的含义是,我们可以考虑训练集中与新数据点最近的任意k个邻居,用这些邻居中数量最多的类别做出预测。
  3. scikit-learn 中所有的机器学习模型都在各自的类中实现。k 近邻分类算法是在neighbors 模块的KNeighborsClassifier 类中实现的。需要将这个类实例化为一个对象,然后才能使用这个模型。这时我们需要设置模型的参数。
  4. KNeighborsClassifier 最重要的参数就是邻居的数目

docstring的示例:

?KNeighborsClassifier

Examples
--------
>>> X = [[0], [1], [2], [3]]
>>> y = [0, 0, 1, 1]
>>> from sklearn.neighbors import KNeighborsClassifier
>>> neigh = KNeighborsClassifier(n_neighbors=3)
>>> neigh.fit(X, y) # doctest: +ELLIPSIS
KNeighborsClassifier(...)
>>> print(neigh.predict([[1.1]]))
[0]
>>> print(neigh.predict_proba([[0.9]]))
[[0.66666667 0.33333333]]

应用:

from sklearn.neighbors import KNeighborsClassifier  # knn也可用于回归,是KNeighborsRegression

knn = KNeighborsClassifier(n_neighbors=1)  # 设置具体参数来实例化

knn 对象对算法进行了封装,既包括用训练数据构建模型的算法,也包括对新数据点进行预测的算法。它还包括算法从训练数据中提取的信息。
对KNeighborsClassifier 来说,里面只保存了训练集。

想要基于训练集来构建模型,需要调用knn 对象的fit 方法,输入参数为X_train 和y_train,二者都是NumPy 数组,前者包含训练数据,后者包含相应的训练标签:

knn.fit(X_train,y_train) # fit 方法返回的是knn 对象本身并做原处修改,因此得到分类器的字符串表示。从中可以看出构建模型时用到的参数。
# 模型都有很多参数,但多用于速度优化或非常特殊的用途。

在这里插入图片描述

评估模型-使用测试集,进行结果对比

可以通过计算精度(accuracy)来衡量模型的优劣,精度就是品种预测正确的花所占的比例:

# 得到测试集的预测值
y_pred = knn.predict(X_test)
y_pred  # array([2, 1, 0, 2, 0, 2, 0, 1, 1, 1, 2, 1, 1, 1, 1, 0, 1, 1, 0, 0, 2, 1,0, 0, 2, 0, 0, 1, 1, 0, 2, 1, 0, 2, 2, 1, 0, 2])

# 与测试集的真实值比较得到精度
np.mean(y_pred == y_test)  # 0,1之间算1的比例就是所有的平均值,等价于
knn.score(X_test,y_test)   # 0.9736842105263158

?knn.score
Returns the mean accuracy on the given test data and labels.

进行预测

X_new = np.array([[5,2.9,1,0.2]])  # 一条新数据
print(X_new.shape)  # (1, 4),二维数组的一行,因为scikit-learn的输入数据必须是二维数组。
prediction = knn.predict(X_new)  # 预测
prediction  # array([0]) ,类别是0
iris_dataset['target_names'][prediction]  # array(['setosa'], dtype='

2. 模型复杂度和泛化能力之间的关系-乳腺癌数据集

from sklearn.datasets import load_breast_cancer
import sklearn
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt

cancer = load_breast_cancer()
cancer.keys()
print(cancer.DESCR)
# 拆分训练集与测试集
X_train,X_test,y_train,y_test = train_test_split(cancer.data,cancer.target,stratify=cancer.target,random_state=66)

strtigy : array-like, 数据以分层方式拆分,并将其用作类标签。按不同类别所占比例拆分?并转换为0,1标签?

## 记录训练集精度和测试集精度
n_max = 10
n_range = range(1,n_max+1)   # 邻居范围
train_acc = np.zeros(n_max)
test_acc = np.zeros(n_max)

for i,n in enumerate(n_range):
    knn = KNeighborsClassifier(n_neighbors=n)
    knn.fit(X_train,y_train)
    train_acc[i] = knn.score(X_train,y_train)
    test_acc[i] = knn.score(X_test,y_test)
## 画图
plt.plot(n_range,train_acc,label='train acc')
plt.plot(n_range,test_acc,label='test_acc',linestyle='--')
plt.xlabel('n neighbors')
plt.ylabel('Accuracy')
plt.legend()

kNN原理与python应用_第4张图片
可以看出,更少的邻居对应更复杂的模型,训练集精度高,测试集精度低,最近邻是过拟合。
泛化最佳性能在n=6时,测试集精度最高。
最差的性能约为88% 的精度,这个结果仍然可以接受。

3. kNN回归

  1. 在使用多个近邻进行时,预测结果为这些邻居的平均值。
  2. 评估模型:score 方法,对于回归问题,返回R2,即决定系数,是回归模型预测的优度度量,等于1 对应完美预测,等于0 对应常数模型,即总是预测训练集响应(y_train)的平均值。R2越大拟合越好
from sklearn.neighbors import KNeighborsRegressor  # kNN回归器

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
# 模型实例化,并将邻居个数设为3
reg = KNeighborsRegressor(n_neighbors=3)
# 利用训练数据和训练目标值来拟合模型
reg.fit(X_train, y_train)
# 预测结果
reg.predict(X_test)
# 评估模型
reg.score(X_test, y_test)

你可能感兴趣的:(Python,python)