今天天有点热啊,刚好又停电了,闲来无事就实现了下K近邻算法。K近邻算法的思想是将欲分类新数据的特征与所有样本的特征一一做比较,找出K个最相似数据(距离最短)的标签,然后找出K个标签里出现最多的标签,即为所分类的新数据的标签。具体见K近邻算法
用Python实现了下,代码如下所示:
# -*- coding: utf-8 -*-
"""
Created on Sun Jul 07 15:40:25 2013
@author: lming_08
"""
import numpy as np
train_set_count = 16000
def create_dataset(file_name):
fd = open(file_name)
lines = fd.readlines()
#inst_count = len(lines) #实例数
#vec_dimension = len(lines[0]) #向量维数
class_label = [] #类别标签
feature_vec_set = np.zeros((train_set_count, 16), dtype = np.int) #特征向量集
index = 0
for line in lines:
if index >= train_set_count:
break
line = line.strip()
data = line.split(",")
class_label.append(data[0])
feature_vec_set[index, :] = [np.int(data[i]) for i in range(1, len(data))]
index += 1
#feature_vec_set is ndarray, and class_label is list
return feature_vec_set, class_label
def KNN(inX, feature_vec_set, class_label, k):
train_set_count = len(class_label)
dist_array = np.zeros((train_set_count, 1), dtype = np.int)
inX_repeat = np.tile(inX, (train_set_count, 1))
diff_array = inX_repeat - feature_vec_set
sqdiff_array = diff_array ** 2
dist_array = sqdiff_array.sum(axis = 1) #每一行求和
sorted_index = dist_array.argsort()
votelabel = [0] * 26 #26个字母分别对应0...25
for i in range(k):
ch = class_label[sorted_index[i]] #对应的标签
votelabel[ord(ch) - 65] = votelabel[ord(ch) - 65] + 1
votelabel_min_index = votelabel.index(max(votelabel))
return chr(votelabel_min_index + 65)
if __name__ == "__main__":
feature_vec_set, class_label = create_dataset("./letter_recognition/letter_recognition.txt")
fd = open("./letter_recognition/remain_4000rows.txt")
fd_result = open("./letter_recognition/test_result.txt", "a")
lines = fd.readlines()
test_count = 0
error_count = 0
for line in lines:
test_count += 1
line = line.strip()
data = line.split(",")
inX = np.array([np.int(data[i]) for i in range(1, len(data))])
ch = KNN(inX, feature_vec_set, class_label, 20)
if line[0] != ch:
#print(u"分类的标签是%c,其实际标签是%c" % (line[0], ch))
fd_result.write("分类的标签是%c,其实际标签是%c\n" % (line[0], ch))
error_count += 1
print(u"测试样本数为%d, 错误率为%f" % (test_count, error_count / float(test_count)))
fd.close()
fd_result.close()
代码中用到的训练样本集是来自于美国加州大学欧文分校的机器学习数据资源,用来对字母进行识别的数据集,具体见http://archive.ics.uci.edu/ml/datasets/Letter+Recognition
训练样本集是采用letter_recognition.txt中头16000行数据,而后4000行数据用于测试
运行代码如下所示:
F:\python_workspace>python KNN.py
测试样本数为4000, 错误率为0.073750
可以看出错误率为7.375%,再查看下误分类的情况,可以查看下test_result.txt文件,部分如下所示:
分类的标签是G,其实际标签是C
分类的标签是A,其实际标签是Y
分类的标签是K,其实际标签是L
分类的标签是P,其实际标签是H
分类的标签是H,其实际标签是B
分类的标签是K,其实际标签是G
分类的标签是G,其实际标签是R
分类的标签是X,其实际标签是E
分类的标签是H,其实际标签是D
分类的标签是J,其实际标签是I
分类的标签是E,其实际标签是G
分类的标签是H,其实际标签是Y
分类的标签是D,其实际标签是B
分类的标签是N,其实际标签是D
分类的标签是H,其实际标签是Q
分类的标签是G,其实际标签是X
分类的标签是H,其实际标签是K
分类的标签是Q,其实际标签是O
...
实际运行过程中速度很慢,这是因为每一个测试向量都要与每一个训练样本向量比较距离,算法复杂度较高