一 理论基础
kk近邻法是一种基本地分类与回归算法,属于判别模型。没有学习策略,不具备显式学习过程。本文主要讨论分类问题。
原理:给定一个训练数据集,对于新的输入实例,在训练数据集中找到与该实例最邻近的kk个点,这kk个点的多数属于某个类,就把输入实例归为这个类。
三个基本要素:kk值得选择,距离度量以及分类决策规则
1.超参数k:选择较小的k值,对噪声比较敏感。意味着整体模型变得复杂,容易过拟合;选择较大的k值,较远的实例也会对预测起作用,使预测发生错误。意味着模型变得简单。
2.距离度量:距离是空间两个实力点相似程度的反映。xi=(x(1)i,x(2)i,...,x(n)i)T,xj=(x(1)j,x(2)j,...,x(n)j)Txi=(xi(1),xi(2),...,xi(n))T,xj=(xj(1),xj(2),...,xj(n))T,距离定义如下:Lp=(∑l=1n|x(l)i−x(l)j|p)1pLp=(∑l=1n|xi(l)−xj(l)|p)1p
p=1时称为曼哈顿距离,p=2时称为欧氏距离。
3.分类决策规则:一般采用多数表决。
二 代码实现
编写的分类器实现功能:超参数k,超参数p,拟合训练集,对新的数据进行分类,对分类结果计算精度。感兴趣的还可以加入超参数距离的权重以及kd树,球树等实现方法。这里不再赘述。
KNN算法实现代码如下
class KNNClassify(): def __init__(self,k=5, p=2): self.k = k self.p = p self._X_train = None self._y_train = None def fit(self, X_train, y_train): self._X_train = X_train self._y_train = y_train return self def predict_y(self, X_test): m = self._X_train.shape[0] y_pre = [] for intX in X_test: minus_mat = np.fabs(np.tile(intX, (m, 1)) - self._X_train) # 将新的实例复制成m行1列,并进行相减 sq_minus_mat = minus_mat ** self.p sq_distance = sq_minus_mat.sum(axis=1) diff_sq_distance = sq_distance ** float(1/self.p) sorted_distance_index = diff_sq_distance.argsort() # 记录距离最近的k个点的索引 class_count = {} vola = [] for i in range(self.k): vola = self._y_train[sorted_distance_index[i]] class_count[vola] = class_count.get(vola, 0) + 1 # 统计k个点中所属各个类别的实例数目 sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True) # 返回列表,元素为元组。每个类别以及对应的实例数目 y_pre.append((sorted_class_count[0][0])) return (np.array(y_pre)) def score(self, X_test, y_test): j = 0 for i in range(len(self.predict_y(X_test))): if self.predict_y(X_test)[i] == y_test[i]: j += 1 return ('accuracy: {:.10%}'.format(j / len(y_test)))
下面以鸢尾花数据集来评估编写的分类器效果
import numpy as np import operator from sklearn import datasets from sklearn.model_selection import train_test_split# 获取数据集,并进行8:2切分iris = datasets.load_iris() X = iris.data y = iris.target X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)# 定义分类器的实例,并进行拟合预测f = KNNClassify() f.fit(X_train, y_train) y_pre = f.predict_y(X_test) accuracy = f.score(X_test, y_test)print(y_test)print(y_pre)print(accuracy)
输出结果如下,可以看出分类效果还可以。
[1 2 2 2 0 1 2 0 0 0 1 2 0 0 2 1 2 0 2 2 2 2 0 2 1 1 0 2 0 1]
[1 2 2 2 0 1 2 0 0 0 1 2 0 0 2 1 1 0 2 2 2 2 0 2 1 1 0 2 0 1]
accuracy: 96.6666666667%需要注意的是KNN由于与距离有关,如果某个特征数值相比其他特征较大大,会对距离产生很大的影响。例如具有实例x1=[1 3 1000 2],x2=[1.5 4 1100 2],计算距离时第三个特征差基本起到了主导作用,弱化了其他特征。为避免这种情况,应先对数据进行预理。
预处理方法。关于标准化与归一化,不同的人有不同看法,这里以sklearn为准,标准化对象为特征,归一化对象为样本,当然两者实质都是对训练集数据的改变。可以参考[http://sklearn.apachecn.org/cn/0.19.0/modules/preprocessing.html#preprocessing-scaler]
1.标准化(对特征),也称去均值和方差按比例缩放。数据集的标准化对scikit-learn中实现的大多数机器学习算法来说是常见的要求 。(对象为特征,依赖于训练集中所有样本)2.归一化(对样本)。归一化 是缩放单个样本以具有单位范数的过程。注意对象为样本而非某个特征!!通常使用 L1 或 L2 范数。例如实例x1=(1,2,2)Tx1=(1,2,2)T,归一化后x1=(0.33,0.66,0.66)Tx1=(0.33,0.66,0.66)T。不依赖于其他样本特征数值。
3.二值化。
4.非线性变换
5.特征编码L
6.缺失值插补如果个别特征或多或少看起来不是很像标准正态分布(具有零均值和单位方差),那么它们的表现力可能会较差。在实际情况中,我们经常忽略特征的分布形状,直接减去均值来对某个特征进行中心化,再通过除以非常量特征(non-constant features)的标准差进行缩放。
x=x−x¯σx=x−x¯σ
将特征缩放到给定的区间,通常为[0,1]。或者也可以将每个特征的最大值转换至单位大小,它通过除以每个特征的最大值将训练数据特征缩放至 [-1, 1] 范围内,这就意味着训练数据应该是已经零中心化或者是稀疏数据。两者分别使用MinMaxScaler和MaxAbsScaler实
现。对于两者计算公式分别为x=x−min(x)max(x)−min(x),x=xmax(x)x=x−min(x)max(x)−min(x),x=xmax(x)
由此可以看出,对于kNN而言,当某个特征的差值相比其他特征较大时,可以采用标准化,以避免某个特征对距离影响。如果进行归一化,虽然也是改变了特征取值区间,但是特征间量级关系依然会相差很大。
当我们得出一个算法模型后,如何评判模型的好坏呢?包括许多性能度量方法,例如精度与错误率、查准率查全率与F1、ROC与AUC等等。假如我们选择精度作为衡量指标,我们采用多次留出法或者p次k折交叉验证,然后将各个精度取均值作为此模型的评估指标。
1.留出法。将数据集分成互斥的训练集与测试集,可以得出一个精度。因为划分方式存在多种方式,因此使用留出法时,采用若干次随机划分,重复进行实验取平均值作为留出法评估结果。
2.交叉验证。将数据划分成k个互斥大小相似的集合,每次采用k-1个作为训练集,剩下一个作为测试集,总共可进行k次,最终返回k次结果的均值。同样由于划分方式不同,可进行p次划分,每次都进行k折交叉验证,取最后均值作为评估结果,称为p次k折交叉验证。
原文出处:https://www.cnblogs.com/lyxML/p/9509059.html
共同学习,写下你的评论
评论加载中...
作者其他优质文章