用树结构描述和计算数据

描述数据最常见的结构是平面表格,数据库,Excel,CSV都是典型的表格。表格是扁平结构,理解起来简单,能方便的增删改查。 
下面是一个典型的表格:

时间小时分钟
12:03 12 03
15:32 15 32

从上面的表格,明显能看出表格的缺陷:

  • 所有的子项都是平级的,无法描述它们内在的结构
  • 列名很重要,否则很难确定其语义,这和第一条相辅相成
  • 在数据深度上进行规约和下钻时,不可避免的会造成数据重复。
  • 对列的描述,无法直接保存在表格中,还需要另外建立数据结构存储

如果我们将上面的表格描述成下面的树,这些问题就变得容易解决了:

  • (父节点) 
    • (子节点)12
    • (子节点):
    • (子节点)03

因此,父节点不需要存储数据,其值是子节点数据的组合,不会有重复。能够明确的描述数据的层级关系和结构,支持在不同层级检索数据,对上面的例子,第一层是12:03, 细分之后,第二层是12和03。
因此,将表格转换为树,笔者将其称为树表,可能会是两种情况:

  • 结构一致的树的森林,每一棵树代表一行数据
  • 只有一棵树,每个树节点是数组,分别对应了表格中的一列

推荐使用第二种,这样就能方便地将列的元属性记录在节点中,而不造成重复,也可以很容易的将树表打平,变成普通表格。树结构是递归的,因此支持递归操作,下面将讨论树表可能的操作类型。

节点结构

对树子节点的描述,通常有两种:

  • 将子节点作为数组,保存在父节点中
  • 将子节点保存为链表,只将头结点保存在父节点中

第二种方法的优点,比缺点多得多。第二种除了对子节点的索引访问不易之外,其他的操作都要比第一种方便。不用预先声明长度,能方便地拼接,删除。 
但最大的优点,是能够方便的实现缓存机制。重复的数据,能让多个节点指向同一个链表头结点,实现复用。而第一种方案则会复杂得多。 
因此,我们采用第二种策略作为树表的存储结构。

计算

  • 在不同节点读取数据,值为子节点值的组合
  • 在不同节点写入数据,节点负责将数据分配到不同子节点存储
  • 删除一个节点,对应的子节点都会被删除
  • 展平一个节点,将该节点替换为其子节点的头结点
  • 将节点拼接到其他子节点上
  • 描述嵌套结构,子节点的下一个节点指向父节点。
  • 同级节点的推导,如果父节点提供计算能力,则子节点能够被计算并返回结果
  • 转换为xml,json等递归结构类型

应用

从HTML中自动提取树表 

这几乎是树表最正常的用途,随便看一个html的例子,数据都是以树结构存储的,没有明确的列名,但其层级关系却表现了数据的关联性。

<div class="other">
    <div class="con">
        <a href="http://bj.lianjia.com/ershoufang/wangjing/"  data-el="region">望京二手房
        </a>
        <span>/</span>
        中楼层(共26层)
        <span>/</span>
        1997年建塔楼
    </div>
</div

我们很难通过树结构,自动标注“1997年建板楼”的列名,但却知道,它和“中楼层”属于一个层级。这样,自动清洗html就会方便地多。

信息抽取 
信息抽取的结果,一般是树,还是之前时间的例子,12:03提取子信息后,就变成了12点和03分,分别成为了12:03的两个子节点。 
这也同样避免了生成多个列,造成数据重复的问题。

自动推导 
对编译原理有概念的同学,自然会对语法树有印象。语法树代表了当前语句的逻辑结构,分析语法树,能够发现无用冗余节点,或进行规约计算。例如加法(+)的父节点,如果有两个int子节点,那么就可以求和。 
一样的道理,如果在同一层级,分别有长度和宽度,那么这两个指标一般衡量的都是同一个“物体”,那么自然就可以增加“面积”子节点。 
同时,节点可以代表“动作”,也可以保存函数,那么树表本身就提供了自动推导的能力。 
节点的上浮/下沉,都可以通过规则自动实现,而之前对数据上钻和下探,都可以理解为观察树不同的层级而已。 
这极大地简化了编程/推导,甚至能实现一个简单的人工智能。

易于实现Lazy执行 
是否延迟执行,可根据实际要求来决定。如果父节点计算代价高昂,那么可缓存子节点计算值,否则可随时返回子节点的规约新值。 
想要让平面表支持延迟执行,肯定不会太容易。

数据就是对象 
想象一下,以后访问一个数据表,都能通过object.property.subproperty来访问了,那种感觉多爽,还要什么ORM!

缺陷

树表最大的缺陷,是它对用户不友好,理解扁平的表结构是很容易的,但如果看到一片森林,肯定不少程序员会晕菜,普通用户更是不必说,所以这种审查数据的方式显然只应该在后台,面向程序员。 
我们可以用Excel等工具方便地查看表结构,但树表怎么看?这也同样需要可视化设计器,好在这种事情是苦力活,并不难做。

展望

想象一下以后如何处理和清洗数据,把树的某个节点拖到垃圾箱,这一列就自动删除了,可以新建某个层级的节点,然后添加几个节点的连线,它就自动成了它们的父节点;节点和节点之间可以插入新的计算节点,定义新的层级。也可以随时查看不同层级的数据,从而实现更好的洞察力。这一切简直太酷了。

这个问题,确实是我在实际开发爬虫和数据清洗工具时遇到的,平面表格大量的中间计算结果,重复列,无法定义的列名,让我深感平面模式的弊端,我甚至都已经迫不及待地开发这样的数据处理工具,以替代之前的工具。不过,在一切都不明朗之前,这种计划还是往后推一推吧。

有任何问题,欢迎随时讨论。

 

posted @ 2016-03-07 09:57  FerventDesert  阅读(1131)  评论(0编辑  收藏  举报