机器学习小记——KNN(K近邻) ^_^ (一)
为了让绝大多数人都可以看懂,所以我就用简单的话语来讲解机器学习每一个算法
第一次写ML的博文,所以可能会有些地方出错,欢迎各位大佬提出意见或错误
祝大家开心进步每一天~
博文代码全部为python
简单的说一下什么是机器学习,机器学习英文名称是Machine Learning, ML
机器学习(Machine Learning, ML)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。
机器学习学习形式可分为监督学习,监督学习,半监督学习和强化学习
KNN(k-Nearest Neighbor)中文名为K近邻,是分类算法的一种,KNN的思路为在在数据和标签已知的情况下将测试数据的特征和训练集中的特征进行比较,找到与之最相似的k的数据,那么这个数据对应的类别就是k个数据中出现次数最多的那个类别
寻找相似度有多重方法,最常用的为欧几里得度量,皮尔逊相关系数,余弦相似度
算法流程大致分为
1)计算测试数据与各个训练数据之间的距离;
2)按照距离的递增关系进行排序;
3)选取距离最小的K个点;
4)确定前K个点所在类别的出现频率;
5)返回前K个点中出现频率最高的类别作为测试数据的预测分类。
本文使用iris数据集,可从UCI处下载 传送门
使用py的三种库pandas,numpy,sklearn
查看数据集
前4列为特征,最后一列为标签
1 #获取数据 2 X=np.loadtxt("/Users/galan/py/ML-D/iris.data.txt",delimiter=",",dtype=float,usecols=(0,1,2,3)) 3 y=np.loadtxt("/Users/galan/py/ML-D/iris.data.txt",delimiter=",",dtype=str,usecols=(4,)) 4 #创建训练数据和测试数据 5 X_train,X_test,y_train,y_test=train_test_split(X,y,train_size=.7)
第2,3行为获取特征和标签
第五行中使用sklearn库的train_test_split函数,用来方便分隔测试集和训练集
本文使用欧几里得度量算法,在下方也会列出皮尔逊相似性和余弦相似度的py代码
欧几里得度量多为计算空间中两点间的距离
表达式为 |x| = √( x[1]2 + x[2]2 + … + x[n]2 )
代码表现形式为 [(p1-q1)**2+(p2-q2)**2+...+(pn-qn)**2]**0.5
def eculidean(p,q): sumSq=0.0 #讲差值德平方累加起来 for i in range(len(p)): sumSq+=sum(p[i]-q[i])**2 #求平方根 return (sumSq**0.5)
皮尔逊相关系数是度量两个变量之间相关程度,介于-1和1之间,1代表变量完全正相关,0代表无关,-1代表完全负关系
def pearson(x,y): n=len(x) vals=range(n) #简单求和 sumx=sum([float(x[i]) for i in vals]) sumy=sum([float(y[i]) for i in vals]) #求平方和 sumxSq=sum([x[i]**2.0 for i in vals]) sumySq=sum([y[i]**2.0 for i in vals]) #求乘积之和 pSum=sum([x[i]*y[i] for i in vals]) #计算皮尔逊评价值 num=pSum-(sumx*sumy/n) den=((sumxSq-pow(sumx,2)/n)*(sumySq-pow(sumy,2)/n))**.5 if den==0:return 1 r=num/den return r
余弦相似度将向量根据坐标值,绘制到向量空间中求得他们的夹角,并得出夹角对应的余弦值,夹角越小,余弦值越接近于1,它们的方向更加吻合,则越相似。
#vect1,vect2位两个一维向量如(1,1) def getCost(vect1,vect2): sum_x=0.0 sum_y=0.0 sum_xy=0.0 for a,b in zip(vect1,vect2): sum_xy+=a*b sum_x+=a**2 sum_y+=b**2 if sum_x==0.0 or sum_y==0.0: return None else: return sum_xy/((sum_x*sum_y)**0.5)
knn的求证过程
#K值 k=5 #计算所有的欧氏距离组合成字典 Dists={} for i in range(len(X_train)): Dists[eculidean(X_test[0],X_train[i])]=y_train[i] #排序字典 sortedDist=sorted(Dists.iteritems(),reverse=True,key=lambda x:x[0])[:k] classCount={} #寻找最多的类别标签 for i in sortedDist: if i[1] in classCount: classCount[i[1]]+=1 else: classCount[i[1]]=1 print classCount
下面贴出所有的代码
#coding:utf-8 import pandas as pd import numpy as np from sklearn.model_selection import train_test_split #获取数据 X=np.loadtxt("./ML-D/iris.data.txt",delimiter=",",dtype=float,usecols=(0,1,2,3)) y=np.loadtxt("./ML-D/iris.data.txt",delimiter=",",dtype=str,usecols=(4,)) #创建训练数据和测试数据 X_train,X_test,y_train,y_test=train_test_split(X,y,train_size=.7) def eculidean(p,q): sumSq=0.0 #讲差值德平方累加起来 for i in range(len(p)): sumSq+=sum(p-q[i])**2 #求平方根 return (sumSq**0.5) def classify(X_train,X_test,k): #计算所有的欧氏距离 Dists={} for i in range(len(X_train)): Dists[eculidean(X_test,X_train[i])]=y_train[i] #排序字典 sortedDist=sorted(Dists.iteritems(),reverse=True,key=lambda x:x[0])[:k] classCount={} #寻找最多的类别标签 for i in sortedDist: if i[1] in classCount: classCount[i[1]]+=1 else: classCount[i[1]]=1 return sorted(classCount.iteritems(),key=lambda x:x[1],reverse=True) if __name__ == '__main__': print "%s的类别为%s"%(X_test[15],classify(X_train,X_test[0],5)[0][0])
我会每周更新一篇ML博文,方便大家学习,^_^ 共同学习共同提高,欢迎大家前来对我的文章提出宝贵意见
祝大家周末愉快~