巧用决策树消灭 if

Wesley13
• 阅读 485

前言

最近公司在搞技术创新,老板把一群程序员拉到山上,锁在酒店会议室里憋了一晚总结出来几条意见,其中之一就是之所以每次产品改需求我们都会苦哈哈的加班写bug,主要不是因为产品今天提的需求,昨天就该上线,而是因为我们没有一种无需硬编码就能修改系统逻辑的方法。大家一致同意改变命运的关键在于开发一个可视化的规则编辑和执行引擎。我一听这不就是我N年前搞过的决策树吗,虽然具体需求拔高了许多,但现成的代码改吧,改吧就能用啊。于是把代码拉出来,一通操作猛如虎之后,搞定。

本文将简单介绍一下决策树,以及如何利用可视化编辑器创建决策树模型并在应用中加以使用。想要升职加薪,又想减少秀发流失率的程序员,和希望在工具的逼格上PK掉隔壁开发小组的dev leader适合阅读本文。

巧用决策树消灭 if

决策树定义

决策树是一种树形结构,其中每个内部节点表示一个属性上的测试,每个分支代表一个测试输出,每个叶节点代表一种类别。它是一种简单但是广泛使用的分类器。可以高效的对未知的数据进行分类。例如:

巧用决策树消灭 if

决策树有两大优点:

  1. 决策树模型可以读性好,具有描述性,有助于人工分析

  2. 效率高,决策树只需要一次构建,反复使用,每一次预测的最大计算次数不超过决策树的深度。

决策树适用场景

决策树主要用于核心的判断和分类逻辑。是否用决策树代替硬编码的if-else或者switch语句,可以参考以下几个判断标准:

1.     判断逻辑是否相对独立,在判断中是否主要是分类判断,不大涉及到计算过程

2.     判断逻辑是否会经常调整,比如是否依赖于节假日,市场或政策的变动,例如优惠规则等。如果是常识,或者基本固定的技术层面的判断或校验,则无需使用决策树

3.     影响判断的因素是否较多,比如大于等于3个因素,每个因素有2个或以上的分类判断

4.     判断逻辑是否是重要的业务需求,比如业务需求描述了明确的分类算法等

如果上述问题的答案中是的较多,建议使用决策树。

如果没有趁手的工具,光知道决策树的概念并没有什么用。接下来我就为大家介绍一款与IDE集成的,非常方便好用的可视化决策树编辑器xDecision。

XDecision简介

xDecision是一套包括编辑器和引擎在内的决策树工具。其中编辑器可以以插件形式安装到流行的IDE中,目前支持Eclipse和IDEA。研发人员通过编辑器在IDE里面创建决策树模型,再在应用中使用引擎对事实做判断以获取决策。

项目地址:

https://github.com/hejiehui/xDecision

安装编辑器插件

Eclipse编辑器插件

如果要安装Eclipse版本,请下载xDecision Eclipse插件

在Eclipse里面按照时记得选型按照下图勾选:

巧用决策树消灭 if

IDEA编辑器插件

如果安装IDEA版本,请下载xDecision IDEA插件

在File->Settings->Plugins->Install plugin from disk里面选择下载好的插件,安装重启即可

获取xDecision引擎依赖

引擎是标准maven项目。项目地址在:

xDecision

下载后即可编译打包

快速体验

如果希望快速体验决策树的魅力,可以直接下载样例工程:

xdecision sample

在IDE里面双击src/main/resources下的

Sample.xdecision

expression.xdecision

即可在编辑器中打开对应模型

巧用决策树消灭 if

创建决策树

决策树编辑器的使用真的超简单。

在Eclipse中安装插件后,在New菜单里面可以看到New Decision Tree Wizard创建向导。

巧用决策树消灭 if

在IDEA插件安装好后可以看到Xross Decision Model菜单

巧用决策树消灭 if

点击后输入文件名即可创建一个空白的决策树模型。Eclipse版本的编辑器需要配合Properties View,既属性窗口,可以在windows菜单找到并打开。IDEA版本的编辑器会自动显示,无需用户处理。

巧用决策树消灭 if

缺省模型

xDecision相关概念

点击编辑器的空白处,即可选中决策树模型本身,在对应的Properties里面,你可以看到有Configure,Decisions和Factor。

巧用决策树消灭 if

这些就是构建决策树的基本元素。我们先不管Configure里面的内容,先来看看Decisions和Factor。

Decisions

以字符串表示的所有可以通过决策树的路径到达的decision。在编辑器中如果选择的话,会以暗绿色显示在节点上。

Factor

用于决策判断的事实依据,可以看做是变量或属性。每个Factor按照创建顺序自动赋予一个递增的id。每个事实包括name属性和其取值范围的枚举集合 Factor X value [0,N]。Name会显示在节点的顶端,代表本节点基于那个事实进行判断。Value会作为连接该节点和子节点的边的选项,代表当事实为何值的时候,选择这条路径。

预定义值

为了方便大家使用,新决策树模型预先创建了3个factor,每个两个取值,和6个decision作为初始数据。你可以在Properties窗口对这些预定义的数据做修改并里面反映到图上。

创建节点

下面的操作以IDEA作为代表,Eclipse的操作基本相同

点击

巧用决策树消灭 if

按钮,再点击编辑器空白处,即可创建一个新节点。点击节点,在属性窗口的Factor栏可以选择该节点判断所需的事实。如果该节点同时对应一个可以到达的决策,则可在Decision栏选择对应decision

巧用决策树消灭 if

关联节点

点击

巧用决策树消灭 if

进入关联节点模式,依次点击父节点和子节点,将在两节点之间产生一个连线代表关联关系,点击该连接可以选择父节点factor中的一个取值作为判断依据

巧用决策树消灭 if

重复上面的步骤,创建所需节点并建立连接,从而最终形成一个决策树。

增加事实和决策

如果情况复杂,缺省的factor和decision不够用,可以随时增加新的。右键调出弹出菜单或者点击

巧用决策树消灭 if

这两个工具按钮(Eclipse只有菜单,没有这两个工具按钮),输入factor或decision的名字即可创建。

巧用决策树消灭 if

自动布局

如果觉得决策树布局不美观,编辑器上方提供了自动布局的工具按钮,横竖,间隔都可以随意调整,即使是我等手残党也可以一键搞定

巧用决策树消灭 if

自定义功能

缺省情况下,factor和decision都是字符串,在大多数场景里面够用了。但有时候希望最终获取的decision是个自定义对象,比如实现了某个接口的,可以做方法调用的实例;或者希望对factor的判断可以基于表达式,这时候就是xDecision插件登场的时候了。还记得之前我们暂时放下的Configure配置吗?在这里可以设置用户自定义的扩展。具体不在这里细说,有兴趣可以参考:

  1. 结构解析plugin

  2. 路径选择plugin

验证决策树

生成出来的决策树到底灵不灵是大家最关心的问题。点击

巧用决策树消灭 if

可以自动帮你生成基于当前决策树的测试代码。代码包含完整的类定义,提供类名,获取决策树模型的逻辑,和对每个可到达的decision的factor构建和调用的逻辑。你可以新建一个java类文件将代码手工copy进去,为项目添加xDecision依赖后,按照标准的junit的方式去运行。这个测试代码同时可以作为学习xDecision用法的例子。

例如我们为刚才创建的决策树生成的测试代码长这样:

巧用决策树消灭 if

其中关键代码就是:

tree =  XDecisionTreeFactory.create("D:/test/com.xrosstools.xunit.sample/src/main/resources/xdecision_demo.xdecision");

//Verify tree

MapFacts test;

test = new MapFacts();

test.set("factor0", "value1");

assertEquals("decision2", tree.get(test));

可以直观的看到使用决策树能大幅简化代码,从此和if-else say bye-bye!

样例工程里面的测试代码也是通过这个功能生产的,其中:

  1. SampleTest.java是原始代码没有修改,

  2. ExpressionTest.java利用了扩展,在生成的代码基础上简化了factor的赋值

总结

只要是做过几年开发的人都知道,软件系统在上线的那一刻,才真正开始自己的生命周期。接下来会是无尽的修改和优化。这其中最麻烦的就是理解现有逻辑并加以修改。当年我写if-else简直快写吐了,碰到生产问题时面对一大坨自己或别人写的分支简直欲哭无泪。

使用决策树可以大幅简化代码,因为没有代码开发工作,也就没有代码风格,严谨度等人的因素造成的各种问题。如果将模型存储在配置中心,还可以方便的做到热部署,做到实时生效,节约大量测试和发布时间。

这个工具安装快捷,使用直观,简单培训即可上手,作为通用的模型,产品也可以看懂并参与讨论,让甩锅更困难。非常适合公司作为研发规范推广。

想象一下,当产品又双叒提了一个变更的时候,你拉风的点开决策树模型,一棵精致的决策树刷的闪在大家眼前,你懒懒的抬起手,随便划拉几下鼠标就搞定了变更需求,再实时部署到测试或者生产环境,立马生效。你回头看了一眼目瞪口呆的产品和旁边团队leader羡慕嫉妒恨的眼神,嘴角露出了难以察觉的微笑

巧用决策树消灭 if

参考资料

决策树

作者介绍

赫杰辉,信也科技基础组件部门主管、架构研究员、信也 DAS 产品负责人、布道师。图形化构建工具集 x-series 的作者。曾主持开发携程开源数据库访问框架 DAL。对应用开发效率提升和分布式数据库访问机制有多年的深入研究

如果对决策树或其他可视化开发工具感兴趣,可以加入QQ群获取进一步信息

巧用决策树消灭 if

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
2年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这