记得大三初期,刚从大连理工大学回来,眼巴巴的望着同学各自都有着落了,就我一副“初出茅庐,不谙世事”的样子,于是不得不觍着脸厚着皮去找老师,恳求他让我去海洋所实习。他给我的第一份差事便是将几个G的图片里的数字输入到excel,我整整输了一个国庆节假日。当时就在到处询问,有没有那种算法可以让自动识别图片里的数字,存入到excel中去,想来,那时的自己也是够拼的。
如今这个自动识别数字的算法算是写出来了吧, 我至少可以这样自我安慰到。
KNN算法的理论算的上是最简单最直观的一种了,比起前几次的支持向量机、贝叶斯、逻辑斯特回归那是简单太多了,都不用推导半个公式。这周的核心都是在完成k-近邻中kd树的构建和搜索,几乎都是自己完成的,也没有经过周密的测试,只是调试调通了。
我想,它的用例定不止于此,但这个用例说出去可谓是最唬人的了。
识别下面的“图片”为数字2 0 8
原理就不多讲了,感兴趣的网上都有,理论很简单,只是构建和搜索kd树可能会有些麻烦,而kd树只是为了让它运行的更快,其实用最简单粗暴的方法计算目标点与每个训练集点的距离也未尝不可。
程序运行的效果还行,识别近千个数字只错了10个,错误率1%左右。效果如下,为了好看,我就仅截图出识别几个数字的效果:
下面为实现的程序,注释写的很明白,训练数据在网上也不难找到:
KnnHelper.py
import numpy as np
'''
Created on 2017年7月17日
@author: fujianfei
'''
class KDNode(object):
'''
定义KD节点:
point:节点里面的样本点,指的就是一个样本点
split:分割纬度(即用哪个纬度的数据进行切分,比如4维数据,split=3,则表示按照第4列的数据进行切分空间)
left:节点的左子节点
right:节点的右子节点
'''
def __init__(self, point=None, split=None, left=None, right=None):
'''
Constructor
'''
self.point = point
self.split = split
self.left = left
self.right = right
class KDTree(object):
'''
定义:
KDNode:kd-tree的节点
dimensions:数据的纬度
right:节点的右子节点
left:节点的左子节点
curr_axis:当前需要切分的纬度
next_axis:下一次需要切分的纬度
'''
def __init__(self, data=None):
'''
Constructor
'''
def createNode(split=None, data_set=None):
'''
创建KD节点
输入值:split:分割纬度 data_set:需要分割的样本点集合
返回值:KDNode:KD节点
'''
if len(data_set) == 0: # 数据集为空,作为递归的停止条件
return None
#找到split维的中位数median,先对数据进行排序,按照split维的数据大小排序
data_set = list(data_set)
data_set.sort(key=lambda x: x[split])#对data_set进行排序,lambda是隐函数,具体用法请百度。排序方式为按照split维的数据大小排序
data_set = np.array(data_set)
median = len(data_set) // 2#//为python的整数除法,找到中间点的位置median,按照这个位置进行空间切分
#返回KD节点
#输入的变量分别是: