简单的加权算法
写在前面
距离上一次更新已经很久远了,所以这一次趁着放假就把全部补完,这一次主要写的地方是针对上一章我们得出的排名来进行一个加权处理,令最后的结果更可信一点。
因为加权的方法种类繁多,所以我这里只是简单的自己随意“创造”了一种方法,主要目的还是训练编程能力,所以如果在逻辑方面上存在某些缺陷的话还望见谅。
方法概要
接着上一篇文章,我们得到了距离某一个待检测图片A1最近的十个训练用图片B1, B2, ...,B10。如果通过直接观察,我们通常情况下可以自己分析出这个图片上的数字很有可能是几。
比如说我举个例子,这十个图片上的数字分别为:3, 1, 1, 2, 1, 4, 1, 1, 2, 3.如果我们看第一名可以知道是3,但是在这十个数字中出现频率最高的是1,并且还占据挺靠前的位置,另一个3是出现在最末尾。所以这时候我们可能会认为这个数字是1的可能性更大一点。
也就是说,我们要设计一种加权算法,令最后的排名实现我们上述思考过程,得到一个处理后的真实结果。
加权
所以我的思路就是为每个排名分别加上权重。当然,因为上一篇文章中我们求得的是离被识别数字的距离,通常我们认为是距离越短就越相似,所以说我们最终的评判标准是越小越好的,那么我们这里的权重也设置为是越小越重要。比如说有三个权重1, 2, 3,那么1就要比2重要,2比3重要。
按照这样的思路,我们为了方便,只取距离被识别数字最近的五个图片B1-B5,权重分别为1, 2, 3, 4, 5。取成这样的权重仅仅是为了方便,目前没有其他意义。因为是顺手取的,所以说在准确度可能并没有十分好。在以后的任务中我会想办法找到一种能够根据结果反馈权重的算法,从而来确定权重。
当然,我们需要将上面五个权重进行归一化处理,也就是说权重之和为1.那么我们可以简单地列一个方程式,为
x + 2x + 3x + 4x + 5x = 1
其中的x就代表权重为1的归一化后的权重,解出x就可以得到五个权重。因此我们可以通过编程很简单的得到归一化后的权重列表
temp = np.array([1, 2, 3, 4, 5])
weight = list(temp/np.sum(temp))
可以得到五个权重分别为
B1 | B2 | B3 | B4 | B5 |
---|---|---|---|---|
0.066 | 0.133 | 0.200 | 0.266 | 0.333 |
求相对距离
既然权重求出来了,那么某一个数字的总相对距离就很容易了。我们假设现在B1, B2属于同一个数字2,B3,B5属于同一个数字3,B4属于数字4.所以数字2的总相对距离为
d2 = B1w1 + B2w2
数字3的总相对距离为
d3 = B3w3 + B5w5
数字4的总相对距离为
d4 = B4*w4
因此我们只需要比较d2, d3, d4就可以知道哪一个数字可能是这个待识别图片上的数字。
放代码
我们把以上内容全部设定成一个函数,为CalculateWeight函数。
def CalculateWeight(pictures, n, testFiles):
'''计算加权距离'''
#权重(前五名)
temp = np.array([1, 2, 3, 4, 5])
weight = list(temp/np.sum(temp))
weightNum = len(weight)
for j, pic in enumerate(pictures):
print(testFiles[j])
#存储加权距离的字典
weightDict = {}
for i in range(weightNum):
#判断该数字之前是否出现过
if str(pic[n+i]) in weightDict:
weightDict[str(pic[n+i])] = weightDict[str(pic[n+i])] + weight[i]*pic[i]
else:
weightDict[str(pic[n+i])] = weight[i]*pic[i]
ShowRank(weightDict)
pictures是存储目前所有待检测图片距离其最近的n个训练图片的距离以及其对应的数字,以array形式存在,每一行代表一个待检测图片,其中前n列寸的是距离,后n列存的是对应的数字。
testFiles存储的是每一个待检测图片的名称。
利用for对每一个待检测图片进行循环,首先输出当前待检测图片的名称,然后建立一个字典weightDict。这个字典用来存储某一个数字的总相对距离,key为数字,value为总相对距离。
首先我们需要判断当前的数字是否已经存在于这个字典中,如果存在,那么就将当前算出来的相对距离加到这个key对应的的value中;如果不存在,那么就直接将当前的相对距离赋予key对应的value。循环了weightNum次以后,我们就可以得到当前图片的所有数字的总相对距离。这里我们就需要一个ShowRank函数来讲结果展示出来。
def ShowRank(weightDict):
'''输出单个图片的排名顺序'''
maxRank = [0, 9999]
for item in weightDict:
#寻找最小距离的数字
if weightDict[item] < maxRank[1]:
maxRank = [item, weightDict[item]]
print('数字'+item+'的相对距离为'+str(weightDict[item]))
print('最有可能为数字'+maxRank[0]+',相对距离为'+str(weightDict[item]))
这个函数内容就比较简单了,我就不再细说,主要是输出每一个数字与其对应的总相对距离,并找到最有可能(相对距离最小)的数字。
结果演示
我们可以拿五个测试,如下图所示:
运行程序以后我们直接得到了结果为
测试1.png
数字3.0的相对距离为14.5295906976
数字7.0的相对距离为21.6757647617
最有可能为数字3.0,相对距离为21.6757647617
测试2.png
数字4.0的相对距离为38.3158180871
最有可能为数字4.0,相对距离为38.3158180871
测试3.png
数字8.0的相对距离为2.51083001901
数字3.0的相对距离为29.8009289468
数字5.0的相对距离为8.16783067288
最有可能为数字8.0,相对距离为8.16783067288
测试4.png
数字1.0的相对距离为32.5987662245
数字3.0的相对距离为12.2730692216
最有可能为数字3.0,相对距离为12.2730692216
测试5.png
数字7.0的相对距离为18.5295580926
数字9.0的相对距离为7.94675193285
数字8.0的相对距离为14.284403787
最有可能为数字9.0,相对距离为14.284403787
可以看出除了测试4以外,其他全对,测试4中可能的结果也有1,也说不上错得太离谱。当然,之所以会出现这样的结果,是因为所有的训练图片都是我写的,所以识别我写的数字也就比较准,如果换一个人写就不一定了。出现失误的一切原因都是因为训练库太少啊,所以做这种识别的算法,最主要的还是我们的训练的库存。库存越多,信心也就越大。
总结
这一次就相当于告了一段落了,下一次就可能更加复杂,我想借用神经网络的那种负反馈机制来自动修改权重,从而来达到更精确的效果。当然,这就更加复杂了,也指不定什么时候能做出来。
目前来说下一篇应该会是利用qqbot来做qq自动回复机器人。其包括的功能大概有:指定短语回复,天气查询,签到与积分系统等。
如果喜欢的话,麻烦给一个喜欢或者赞或者收藏噢~