Python生成决策树的.dot文件,使用graphviz转换成png等图片格式(具体函数源码自己写)

最近因为大创的事情,开始学习机器学习。在学习决策树的过程中,看到了有关决策树可视化的相关操作。

首先,使用的是sklearn库的tree对象进行建树与模型训练,我用的数据集是sklearn.datasets.load_breast_cancer():

from sklearn import tree
# 建立决策树分类器
    dtc = tree.DecisionTreeClassifier()
# 训练决策树模型
    dtc.fit(x_train, y_train)

当然,这个不是本文关注的重点,由于这样生成的训练模型,内部信息并不直观,只能够调用一些诸如.score()(查看对于某一数据集适应性的决定系数)的数值来粗略地判断模型对于新的数据集的适应程度,显然不太符合当下可视化的潮流,因此tree对象自身定义了一些导出(export)的方法,来将本来是抽象数据矩阵的决策树算法,转化为了可读性较高的文字语言。

先来看一看第一种方法:

tree.export_text(dtc)

这种方法所做的和它的名称一样,是将原来的tree对象(代码中叫作dtc)表达为一段文本(text),下面是打印出来的实际效果

还是很不直观,每个feature是什么并没有体现在文本上。这个问题我尝试解决,虽然在这个方法里面有一个feature_names的参数,但是我设置了一下,结果给我报了个这样的错:

我拿着它的源码来来回回看了几遍,都没发现问题出在哪里。辛亏急中生智,去搜了一下报错最后的a.any()和a.all()的含义,隐隐约约感觉是数据类型出了问题(我的feature_names参数指定的是一个ndarray数组),于是将ndarray数组类型转化成了list试一下:

tree.export_text(dtc, feature_names=list(feature_names))

结果:

 Nice!

但是这样的表示方法还是过于冗长,可读性上也不是很好,因此我还是决定采用第二种方法:

# 导出一个可视化的决策树图
with open('breast_cancer_tree_graph.dot', 'w') as dot_file:
    tree.export_graphviz(dtc, out_file=dot_file, feature_names=feature_names)

这种方法会生成一个.dot文档,里面保存了关于决策树的信息。由于Windows本身会按照文档的格式对.dot进行打开,因此看到的是这样的一个文档:

安装Graphviz库:

这样显然不是我所想要的直观的表示方式。想要用图像化的形式来对决策树进行解析的话,还需要安装Graphviz库

(其实我所使用的pycharm professional可以下载解析.dot文档的扩展,但是毕竟是用的教育邮箱,还是要以防万一,而且通过扩展加载出来的效果并不是很好,清晰度很低,而且还不能缩放和保存)

提示:使用pycharm中包管理工具下载的Graphviz库好像并不包含我们之后所要使用的工具,因此建议大家还是到官网下载安装包。

Graphviz下载地址

下面是Graphviz库的官方网站:

Graphviz下载地址

从上面的信息来看,Linux系统好像是可以通过sudo命令直接下载,但是Windows就只能老老实实下载安装包了。这里我下载的是最新的2.50.0版本的。

 之后就是按照提示进行安装,这里就不再赘述过程。安装完后,需要对安装文件夹中的bin文件夹进行path路径环境变量配置:

环境变量配置:

 Graphviz2.50是总的安装目录,打开应该是有下面四个文件夹,我们需要将第一个bin文件夹添加到path环境变量中,具体方法可以自行查找环境变量配置的相关文章教程,总的来说就是新建一行,然后将bin文件夹的绝对路径填入输入框中,如上图所示。

 配置好之后,我们可以到命令行输入dot -version来检查是否成功安装了和配置了Graphviz库:

 成功安装了之后,我们便可以开始最后一步转化了:

在命令行中先切换目录到.dot文档所在目录,再输入如下的指令:

dot -Tpng breast_cancer_tree_graph.dot -o tree.png

breast_cancer_tree_graph.dot:.dot文档名

tree.png:要生成的图片文件名,可以是别的类型,不一定要是png

然后就得到了我们想要的可以自由缩放的图片文件:

 可以看到,这样的图像化表示方式,就要比之前的纯文本形式清晰多了

但是仔细想想,总觉得有哪里不太对劲……

对了! 每次生成一张图片,我们都需要进入命令行,切换directory,然后再输入上面那串冗长的命令。漆黑一片的命令行里,一不小心就会输错字母,十分搞人心态。要是能够在IDE中直接通过一行简单的代码调用,就能生成这样一张图片,那该多好啊!

这就是我真正想做的。

由.dot文档自动生成.png图片源码:

现在是凌晨一点二十五,废话少说,先上代码:

# _*_ coding utf-8 _*_
# Designer: はなちゃん
# Time: 2022/1/29 19:20
# Name: dot2png.py
from pathlib import Path
import subprocess


def check_valid_path(path):
    """检查文件路径是否有效,并返回以'/'分割的文件路径"""
    if '\\' in path:
        elements = str(Path(path)).split(sep='\\')
        final_path = Path('/'.join(elements))
    elif '/' in path:
        final_path = Path(path)
    else:
        if not Path(path).exists():
            raise Exception("Error: File path pattern is not correct.")
        else:
            final_path = Path(path)
    if not final_path.exists():
        raise Exception("Error: Your file path does not exist.")
    if final_path != '':
        return final_path
    else:
        return None


def dot2png(dot_file_path=None, img_path=None):
    """决策树可视化中.dot文件转化为.png图片的函数"""
    if not dot_file_path:
        raise Exception(".dot file is not given.")
    elif not dot_file_path.endswith('.dot'):
        raise Exception("file provided is not '.dot' type.")

    DOT_PATH = check_valid_path(dot_file_path)

    if not img_path:
        img_path = 'dt_png.png'
    elif not img_path.endswith('.png'):
        raise Exception("image file not end with '.png'.")

    IMG_PATH = img_path

    cmd_args = ['dot', '-Tpng', DOT_PATH, '-o', IMG_PATH]

    cmd_pro = subprocess.Popen(args=cmd_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    retval = cmd_pro.stdout.read().decode('gbk')
    if retval == '':
        print("successfully create file " + IMG_PATH)
    else:
        print("The program encountered some error: ")
        print(retval)

 使用了subprocess库来在后台开启子进程(今天临时抱佛脚刚学的。哦不,是昨天),文件路径处理方面采用了Path类,这是一个被我遗忘了很久,但确实很好用的文件路径处理模块。

第一个check_valid_path函数没有什么好说的,就是一些处理路径,并在合适的时候抛出异常,用来应付一下用户们千奇百怪的文件路径错误;dot2png函数是由.dot文档生成图片的主调函数,给定了两个参数:

dot_file_path:.dot文档的路径,绝对相对都可以,但是一定要正确指向文件,不然不出意外的话,应该会出现异常

img_path:生成图片的路径,可选参数,如果不写的话会默认在当前的cwd下新建一张名为dt_png的图片

最后是通过Popen调用命令行,我测试了一下,好像一般正常执行的话,得到的返回值retval是不会有内容的,反之若发生了异常,则会返回描述异常的字符串。因此通过这一标识来判定是否生成成功了。

 

当然,这个小程序肯定还存在很多没有被发现和测试到的漏洞。如果大家在使用过程中遇到了什么问题,欢迎在评论区提出来。虽然提出来了我也不一定会想回答——因为我懒 ╯︿╰。

 小插曲:

写这篇博客是晚上十一点多,我写到一半的时候,因为打错了个回车不小心按了下ctrl+z,结果一瞬间整篇博客回到了差不多刚开头的地方,惊慌失措的我马上下意识地按了下ctrl+y,结果是重做的框也没了……我在原地怔了一会,想着是不是太久没写东西了,电脑都嫌我文风太啰嗦了。

最后祝大家新年快乐!

物联沃分享整理
物联沃-IOTWORD物联网 » Python生成决策树的.dot文件,使用graphviz转换成png等图片格式(具体函数源码自己写)

发表评论