1 KNN Algorithm
1.1 KNN工作原理
“存在一个样本数据集,也称为训练样本集trainSet,每一个样本数据集中都对应一个标签labe,即我们知道样本集中的每一个数据与所分类之间的关系。
输入没有标签的数据后,将新输入的数据的特征与样本数据集中的特征比较,然后算法提取出特征最相似数据(最近邻)的分类标签
,一般来说,我们只选择K个最相似的数据,通常K是不超过20 的整数。”
与trainSet中的数据特征值比较,是采用距离比较,这里采用
欧式距离
,对于距离探究见参考文档1(CSDN对距离的各种描述)
在python中对该算法的实现:
"KNN Algorithm"
def
knnClassify
(
self
,
inx
,
dataset
,
labels
,
k
)
:
dataSetSize
=
dataset.shape
[
0
]
#读取训练集矩阵的行数
diffMat
=
tile
(
inx
,
(
dataSetSize
,
1
))
-
dataset
sqDiffMat
=
diffMat
**
2
sqDistances
=
sqDiffMat.sum
(
axis
=
1
)
#计算欧式距离
distance
=
sqDistances
**
0.5
sortedDistIndicies
=
distance.argsort
() #对计算得到的距离排序
classCount
=
{} #分类集合
for
i
in
range
(
k
)
:
votelabel
=
labels
[
sortedDistIndicies
[
i
]]
classCount
[
votelabel
]
=
classCount.get
(
votelabel
,
0
)
+
1
sortClassCount
=
sorted
(
classCount.iteritems
()
,
key
=
operator.itemgetter
(
1
)
,
reverse
=
True
)
return
sortClassCount
[
0
][
0
]
pass
1.2 数据收集与预处理
一般我们都是从文本中得到并解析文件,所以我们需要做一个def,从文本中读取数据的函数:
"read data from the file"
def
readfile
(
self
,
path
)
:
self
.path
=
path
fr
=
open
(
self
.path
,
"r+"
)
arrayLines
=
fr.readlines
()
numberlines
=
len
(
arrayLines
) #读取行数
getMat
=
zeros
((
numberlines
,
3
)) #构建等行量矩阵
classlabelVector
=
[]
index
=
0
for
line
in
arrayLines:
line
=
line.strip
()
#截取所有回车字符
linePromLine
=
line.split
(
'\t'
) #将整行分割成一个列表
getMat
[
index
,
:
]
=
linePromLine
[
0
:3
] #赋值矩阵
classlabelVector.append
(
float
(
linePromLine
[
-
1
])) #添加分类
index
+=
1
return
getMat
,
classlabelVector
有时候我们的数据采用欧式距离,其中某些特征值数据过大,会影响我们的特征值比较结果,而且我们更想要一个等权特征值,所以进一步做数据归一化,将取值范围归到0-1之间或者-1-1之间,增加一个def autoNorm处理归一化数据
"deal data to normDataaet"
def
autoNorm
(
self
,
dataSet
)
:
self
.dataSet
=
dataSet
minVals
=
self
.dataSet.min
(
0
)
maxVals
=
self
.dataSet.max
(
0
)
ranges
=
maxVals
-
minVals
m
=
self
.dataSet.shape
(
0
)
normDataSet
=
self
.dataSet
-
tile
(
minVals
,
(
m
,
1
))
#重点理解
normDataSet
=
normDataSet
/
tile
(
ranges
,
(
m
,
1
))
return
normDataSet
,
ranges
,
minVals
完成对数据的收集与预处理之后,我们需要评估算法的正确性,即
算法的正确率,通常我们只提供90%作为训练样本来训练分类器,而使用其余10%数据去测试分类器,检测分类器的正确率
。我们写一个测试函数,来检测分类器的正确率:
"testing the KNN Algorithm"
def
test
()
:
knn
=
textClassify
() #这是我放在一个类中,生成的对象
hoRatio
=
0.10
dataMat
,
dataLabels
=
knn.readfile
(
'testdata.txt'
) #获取数据
normMat
,
ranges
,
minVals
=
knn.autoNorm
(
dataMat
) #得到归一化数据集矩阵
m
=
normMat.shape
[
0
]
numtestVecs
=
int
(
m
*
hoRatio
)
errorCount
=
0.0 #错误计数
for
i
in
range
(
numtestVecs
)
:
classifierResult
=
knn.knnClassify
(
normMat
[
i
,
:
]
,
normMat
[
numtestVecs:m
,
:
]
,
dataLabels
[
numtestVecs:m
]
,
3) #分类结果
)
print
"the classifier came back with:%d,the real answer is %d"
%
(
classifierResult
,
dataLabels
[
i
])
if
(
classifierResult
!=
dataLabels
[
i
])
:
errorCount
+=
1
print
"the classifier error rate is : %f"
%
(
errorCount
/
float
(
numtestVecs
))
#计算错误率
经过以上的小结,可以基本完成一个分类系统:
"build the completion system"
def
classify
()
:
knn
=
textClassify
()
resultList
=
[
'one'
,
'two'
,
'three'
] #测试向量
num1
=
float
(
raw_input
(
"the first
num
:\n"
))
num2
=
float
(
raw_input
(
"the second
num
:\n"
))
num3
=
float
(
raw_input
(
"the third
num
:\n"
))
dataMat
,
dataLabels
=
knn.readfile
(
'testdata.txt'
)
normMat
,
ranges
,
minVals
=
knn.autoNorm
(
dataMat
)
inArr
=
array
([
num1
,
num2
,
num3
])
classifierResult
=
knn.knnClassify
((
inArr
-
minVals
)
/
ranges
,
normMat
,
dataLabels
,
3
)
print
"the classifierResult you get is : "
,
resultList
[
int
(
classifierResult
-
1
)]
这就是KNN算法的基本内容,在过程中为了能更好的体现数据的可视化效果,也可以通过matplotlib库来展示数据集效果
"draw the data group"
def
draw
(
self
,
dataMat
,
dataLabels
,
classfeature
)
:
fig
=
plt.figure
()
ax
=
fig.add_subplot
(
111
)
if
classfeature
==
1
:
ax.scatter
(
dataMat
[
:
,
1
]
,
dataMat
[
:
,
2
]
,
15.0
*
array
(
dataLabels
)
,
15.0
*
array
(
dataLabels
))
plt.xlabel
(
"second data"
)
plt.ylabel
(
"third data"
)
elif
classfeature
==
2
:
ax.scatter
(
dataMat
[
:
,
1
]
,
dataMat
[
:
,
0
]
,
15.0
*
array
(
dataLabels
)
,
15.0
*
array
(
dataLabels
))
plt.xlabel
(
"second data"
)
plt.ylabel
(
"first data"
)
elif
classfeature
==
3
:
ax.scatter
(
dataMat
[
:
,
0
]
,
dataMat
[
:
,
2
]
,
15.0
*
array
(
dataLabels
)
,
15.0
*
array
(
dataLabels
))
plt.xlabel
(
"first data"
)
plt.ylabel
(
"third data"
)
plt.show
()
K-近邻算法是非常有效简单的算法,但是存在着很大的不足:
1 需要对训练集中的每个数据计算距离值,实际使用在考虑非常大的数据的时候非常耗时(计算复杂度高)
2 无法给出数据的基础结构信息,因此无法知道平均实例样本和典型实例样本具有什么特征
1.3
实战项目:
使用KNN算法改善约会网站
通过对以上KNN算法的探究,我们可以做一个实际的小项目
使用KNN算法改善约会网站,
需要的只是对数据集的收集。比如准备数据
trainSet { 年龄 身高 体重 收入 课余活动时长.......等等}
labelList { 不感兴趣:A ;一般感兴趣:B;十分感兴趣:C;可望立即交往:D}
根据上面的步骤即可简单的得到一个分类结果:你可能对谁“感兴趣”。当然,在这个过程中,我们需要人工的为每一个数据添加label分类,这是一个监督学习的特征,工作量还是蛮大的!