KNN邻近算法与python实践

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即可。

你可能感兴趣的:(python)