k邻近算法(k-NearestNeighbor)又成为KNN,属于分类算法中的一种。KNN通过计算新数据与历史样本数据中不同类别数据点间的距离,从而对新数据进行分类。换句话说,就是通过新数据与最邻近的k个数据点,来对新数据进行分析和分类。
环境:mac + python3.6.3(另外需要的第三方库请自行下载)
python KNN算法原理demo代码如下:
from numpy import *
from PIL import Image
import operator
from os import listdir
import time
import os
# 图片处理
# pillow
# 将bmp格式的图片转化为只有0和1的txt文本,这样就有了训练数据了
def transformAllBmp2Txt():
rootdir = "手写体素材"
list = os.listdir(rootdir) # 列出文件夹下所有的目录与文件
time1 = time.time()
for i in range(0, len(list)):
path = os.path.join(rootdir, list[i])
if os.path.isdir(path):
# 具体某个文件夹下的所有文件与目录
path_dir = os.listdir(path)
for index in range(0, len(path_dir)):
# 好吧,这里做一层保护
file = os.path.join(path, path_dir[index])
if os.path.isfile(file):
bmp2txt(file)
time2 = time.time()
print("总共耗时:" + str(time2 - time1))
def bmp2txt(file):
im = Image.open(file)
fileSplit = file.split("/")
# dir = "transdata/" + fileSplit[1] + "/"
dir = "transdata/"
if os.path.exists(dir) == False:
os.makedirs(dir)
destination_file = dir + fileSplit[2].split(".")[0] + ".txt"
fh = open(destination_file, "a")
width = im.size[0]
height = im.size[1]
# print("图片的模式为:" + im.mode) # 此bmp模式为L,模式L”为灰色图像,它的每个像素用8个bit表示,0表示黑,255表示白
for i in range(0, width):
for j in range(0, height):
cl = im.getpixel((i, j))
if (cl == 0):
# 黑色,由于选择的bmp背景色是黑色,所以默认的是黑色
fh.write("0")
else:
fh.write("1")
fh.write("\n")
fh.close()
print(destination_file + "保存成功。。。")
# 从列方向扩展
# tile(a,(size,1))
def knn(k, testdata, traindata, labels):
# testdata:一维数组[0,0,1,……]
# traindata:二维数组[[0,0,1……],[],]
# labels:一维列表,跟traindata一一对应
# 以下shape取的是训练数据的第一维,即其行数,也就是训练数据的个数
traindatasize = traindata.shape[0]
dif = tile(testdata, (traindatasize, 1)) - traindata
# tile()的意思是给一维的测试数据转为与训练数据一样的行和列的格式
sqdif = dif ** 2
# axis=1-----》横向相加的意思
sumsqdif = sqdif.sum(axis=1)
# sumsqdif在此时已经成为1维的了
distance = sumsqdif ** 0.5
sortdistance = distance.argsort()
# sortdistance为测试数据到各个训练数据的距离按近到远排序之后的结果
count = {}
for i in range(0, k):
vote = labels[sortdistance[i]]
# sortdistance[i]测试数据最近的K个训练数据的下标
# vote测试数据最近的K个训练数据的类别
count[vote] = count.get(vote, 0) + 1
sortcount = sorted(count.items(), key=operator.itemgetter(1), reverse=True)
return sortcount[0][0]
# 加载数据
def datatoarray(fname):
arr = []
fh = open(fname)
# 28表示图片像素中的宽和高,比如我这里的图片是28*28的像素,转成txt文本就是28行*28列
for i in range(0, 28):
thisline = fh.readline()
for j in range(0, 28):
arr.append(int(thisline[j]))
return arr
# 建立一个函数取文件名前缀,为了验证用
def seplabel(fname):
filestr = fname.split(".")[0]
label = int(filestr.split("_")[0])
return label
# 建立训练数据
def traindata():
labels = []
trainfile = listdir("traindata")
num = len(trainfile)
print("文件的总数为:" + str(num))
# 长度784(列),每一行存储一个文件
# 用一个数组存储所有训练数据,行:文件总数,列:784
# 28*28=784
trainarr = zeros((num, 784))
for i in range(0, num):
thisfname = trainfile[i]
thislabel = seplabel(thisfname)
labels.append(thislabel)
trainarr[i, :] = datatoarray("traindata/" + thisfname)
return trainarr, labels
# 用测试数据调用KNN算法去测试,看是否能够准确识别
def datatest():
n1 = 0
n2 = 0
time1 = time.time()
trainarr, labels = traindata()
testlist = listdir("testdata")
tnum = len(testlist)
# print(trainarr)
for i in range(0, tnum):
n1 += 1
thistestfile = testlist[i]
testarr = datatoarray("testdata/" + thistestfile)
thislabel = seplabel(thistestfile)
rknn = knn(3, testarr, trainarr, labels)
print(rknn)
if (thislabel == rknn):
n2 += 1
time2 = time.time()
print("耗时:" + str(time2 - time1) + "秒")
print("准确率:" + str(n2 / n1))
# #抽某一个测试文件出来进行试验
# trainarr,labels=traindata()
# thistestfile="a.txt"
# testarr=datatoarray("testdata/"+thistestfile)
# #print(testarr)
# rknn=knn(3,testarr,trainarr,labels)
# print(rknn)
datatest()
# ------------------------------------------------------python算法原理结束-------------------------------------------------------
完整代码在python_study/w7-罗小辉-380226205/test_knn.py中,运行test_knn.py即可。