大概是上半年准备美赛的时候,才发现仅仅具备C语言的知识,如果想对数据进行分析和挖掘,实在太过简陋,并且当时对相关算法了解甚少。这个学期有幸选了黄教授的数据科学概论一课,他曾经在课上向我们推荐了《机器学习实战》一书。这段时间抽空读了一下,感觉受益颇深,正巧赶完了期末大作业,便把学到的算法以专栏的形式整理出来。一方面便于自己复习巩固,另一方面书中的Python代码并非最新版本,许多参数已经删改,博主也趁此机会完善一下代码,并且给予充足的注释,以飨读者。
k-近邻算法本质上是一种分类算法,主要采用测量不同特征值之间距离的方法实现
精度高、对异常值不敏感、无数据输入假定
计算复杂度高、空间复杂度高
数值型、标称型
(1)计算输入数据与样本集中数据的距离
(2)对距离进行排序
(3)选出前k个最相似的数据(距离最短)
(4)将这些数据中类别出现次数最多的类别作为新数据的分类
我们以二维数据为例
import numpy as np
import operator
def createDataSet(): #生成数据集的函数
group = np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]]) #数值坐标
labels = ['A','A','B','B'] #类别
return group, labels
def title(inY, Size): #对输入数据进行预处理的函数
x = Size[0] #数据个数
y = Size[1] #数据维数
result = np.zeros((x, y))
for i in range(x):
result[[i],:] = inY #利用逐层替换的方式生成初始化数据,这一矩阵由输入数据重复x遍构成
return result
def classify0(inX, dataSet, labels, k): #分类器函数
dataSetxSize = dataSet.shape[0]
dataSetySize = dataSet.shape[1]
diffMat = title(inX, (dataSetxSize, dataSetySize)) - dataSet #开始计算欧氏距离
sqDiffMat = diffMat**2
sqDistances = sqDiffMat.sum(axis=1)
distances = sqDistances**0.5
sortedDistIndicies = distances.argsort() #排序
classCount={}
for i in range(k): #获取前k个数据的类别
voteIlabel = labels[sortedDistIndicies[i]]
classCount[voteIlabel] = classCount.get(voteIlabel,0) + 1
sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
return sortedClassCount[0][0]
group,labels = createDataSet()
classify0([0,0], group, labels, 3) #测试语句
当然,强大的Python自带KNN算法包,下面简述一下几个重要参数的意义
def KNeighborsClassifier(n_neighbors, #k值
weights, #权重
algorithm, #用于实现KNN的算法
leaf_size, #停止建子树的叶子节点数量,默认30
p, #当metric参数设置为“minkowski”时,p=1为曼哈顿距离,p=2为欧式距离,默认p=2
metric) #距离度量方法
此外有两个参数有具体选项
uniform | distance | 自定义函数 |
---|---|---|
不加权 | 权重和距离成反比 |
brute | kd_tree | ball_tree | auto |
---|---|---|---|
暴力实现 | KD树实现 | KD球树实现 | 默认参数,自动选择合适的方法 |
import numpy as np
import operator
from sklearn.neighbors import KNeighborsClassifier
def createDataSet():
group = np.array([[1.0,1.1],[1.0,1.0],[0,0],[0,0.1]])
labels = ['A','A','B','B']
return group, labels
def classify0(inX, dataSet, labels, k):
inX = np.array(inX).reshape(-1,2) #改变输入数据格式以符合要求
knn = KNeighborsClassifier(n_neighbors=k) #设定k值,构建分类器
result = knn.fit(dataSet, labels) #拟合数据
pre = knn.predict(inX) #预测新数据
return pre
group,labels = createDataSet()
print(classify0([0,0], group, labels, 3))
很明显,用自带的库实现这一算法,其代码实现更为简洁(功能、效率都更加强大)
这里我们采用的方法是K折交叉验证
(1)不重复抽样,将原始数据随机分为 k 份
(2)挑选其中一份作为测试集,剩余 k-1 份作为样本集,进行测试
(3)重复第二步 k 次
(4)计算 k 组测试结果的平均值,作为模型的性能指标
sklearn.model_selection.cross_val_score(estimator, #需要验证的算法
X, #数据数值
y, #数据类别
cv) #交叉验证折数
由于我们构建的数据集已不再适合应用这一检验,遂使用更庞大的数据集
(代码来源)
from sklearn.datasets import load_iris
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
from sklearn.neighbors import KNeighborsClassifier
iris = load_iris() #Python自带数据集读取
x = iris.data
y = iris.target
k_range = range(1, 31)
k_error = []
for k in k_range:
knn = KNeighborsClassifier(n_neighbors=k)
scores = cross_val_score(knn, x, y, cv=6, scoring='accuracy') #cv参数决定数据集划分比例,这里是按照5:1划分训练集和测试集
k_error.append(1 - scores.mean())
plt.plot(k_range, k_error)
plt.xlabel('Value of K for KNN')
plt.ylabel('Error')
plt.show()
以后有机会用书中实例予以补充
这是这个专栏的第一篇博客,写完后还是有很多感触的。
初次建模,或者说进行数据分析,一定要构建整个过程的框架,从数据的预处理、构建数据集,到模型的选择、建立、优化,再到预测与评估。
记得曾经在知乎上看到过一项挑战,大致意思是给出一张图片,根据图中信息判断拍摄者所处的位置,看视频时我情绪高涨,事后想了想,当初参与建模比赛,其实向往的是数据背后的故事。
死气沉沉的数字,总能带给我们一些现实意义,对于追寻这些意义的过程,最起码到目前为止,我认为是快乐的。
博主非统计专业,这方面不是专家,如有纰漏或需要补充的地方,烦请各位大佬在评论区指出,如您觉得写的不错,记得一键三连哟
(^U^)ノ~YO