遇到的问题

在对微软\(OCR\)的\(api\)进行测试的过程中,我发现有时候它并不能分析出一个表格的形态,也就是说不知道每个文本对应在表格中的第几行第几列。但是它可以较为准确的给出这些文本的坐标。

不过问题是,位于同一行的文本,他们的纵坐标不是完全相同的,但是在一个大致的范围内。位于同一列的坐标也是有这样的问题。比如一个两行三列的表格,得到的\(6\)个纵坐标可能是这样的:\([32, 32, 37, 68, 70, 72]\)。那么怎么才能较为准确的分辨出哪些纵坐标其实是属于同一行的呢?

开始想过排序后看相邻差的变化量,但是这个值很难确定,大了会把两行分到一行,小了会把一行划成两行,在咨询了学长以后,学长推荐了我\(K-Means\)算法,于是对这个算法进行了学习。

K-Means

\(K-Means\)算法是聚类算法中的最常用的一种,算法最大的特点是简单,好理解,运算速度快,但是只能应用于连续型的数据,并且一定要在聚类前需要手工指定要分成几类。

​聚类算法完全是靠算法自己来判断各条数据之间的相似性,相似的就放在一起。非常适合于解决我遇到的问题。

算法流程

  • 随机选取\(k\)个中心点
  • 遍历所有数据,将每个数据划分到最近的中心点中
  • 计算每个聚类的平均值,并作为新的中心点
  • 重复\(2\sim 3\)步,直到这\(k\)个中心点不再变化,或迭代次数足够多

如下图所示:

图\((a)\)为初始的数据集,图\((b)\)中随机选取了\(2\)个中心点,一个标红一个标蓝。接下来把离红点近的绿点标红,把离蓝点近的绿点标蓝。计算红点的质心和蓝点的质心作为新的中心点并不断迭代,最终得到图\((f)\)。

应用K-Means解决问题

​可以看出,横、纵坐标互相独立,于是把他们分开处理。相当于在一维的直线上做聚类。

​以下以对纵坐标处理为例进行说明。

K值的确定

最开始时打算使用行数作为\(K\)值,但是经过实测,这样的聚类效果并不好,而且中心点难以选取。经过思考,决定把纵坐标排序以后相邻的作差。最终分为两类,一类差值表示他们是同一行之内的坐标差值,设他们的最大值为\(eps\),另一类的差值表示它们是不同行之间的坐标差值。最终认为两个坐标的差值\(\leq eps\)则表示它们属于同一行。

于是\(k\)值被设定为2。这样在只有一行或者一列的话会容易出问题,不过这种表格比较少见而且没有太大意义,所以暂不考虑(没想到咋处理)。

初始质心的选择

随机的话我担心有时候可能效果不好,于是固定为最小的差和最大的差。实测效果还行。

距离计算

​因为是在一维的直线上,所以采取差的绝对值即可。

代码实现

def distEclud(a, b):
return abs(a - b) def K_Means(arr):
K = 2
p = []
arr.sort()
N = len(arr) - 1
for i in range(0, N):
p.append(arr[i + 1] - arr[i])
p.sort()
cluster = [p[0], p[N - 1]]
pos = [1 for i in range(0, N)]
for t in range(1, 101):
for i in range(0, N):
pos[i] = 0
for j in range(1, K):
if distEclud(cluster[pos[i]], p[i]) > distEclud(cluster[j], p[i]):
pos[i] = j
num = [0 for i in range(0, K)]
cluster = [0 for i in range(0, K)]
for i in range(0, N):
num[pos[i]] += 1
cluster[pos[i]] += p[i]
for i in range(0, K):
cluster[i] /= num[i]
eps = 0
for i in range(N):
if pos[i] == pos[0]:
eps = max(eps, p[i])
cnt = 0
dic = {}
lastVal = -2147483647
for i in range(N + 1):
if arr[i] - lastVal > eps:
cnt = cnt + 1
dic[arr[i]] = cnt
lastVal = arr[i]
dic["size"] = cnt
return dic

最新文章

  1. Google Chrome开发者工具
  2. unity assert server 与 cache server
  3. javascript 变量声明有var与无var 的区别
  4. HDU--杭电--1501--Zipper--深搜、DP都好
  5. 为什么推荐std::string而不是char*
  6. 实时计算storm流程架构总结
  7. javascript类的继承
  8. HDU 1392 Surround the Trees(凸包)
  9. 【bzoj3598】: [Scoi2014]方伯伯的商场之旅
  10. gdb调试android
  11. 本人亲身讲解本科期间学习Linux系统过程
  12. phpstorm界面不停的indexing,不停的闪烁
  13. PlugNT CMS v4.6.3 最新功能
  14. Aop事务小结(事务管理器和自身构建)
  15. flask+mako+peewee(下)(解决了Error 2006: MySQL server has gone away)
  16. 网页如何检查浏览器是否安装flash插件
  17. 软件测试_测试工具_LoadRunner
  18. (字符串)最长公共字串(Longest-Common-SubString,LCS)
  19. Python标准库:内置函数getattr(object, name[, default])
  20. selenium + python自动化测试unittest框架学习(一)selenium原理及应用

热门文章

  1. MongoDB(3)- Database 数据库相关
  2. java 使用匿名内部类实现多线程的创建
  3. 富文本编辑器-SpringBoot
  4. 【第二篇】- Git 安装配置之Spring Cloud直播商城 b2b2c电子商务技术总结
  5. 六种多线程方法解决UI线程堵塞
  6. 2. Go并发编程--GMP调度
  7. js复制功能代码
  8. ecshop不同的文章分类使用不同的模板的方法
  9. Linux系列(20) - shutdown
  10. nginx rewrite重写规则集合