全文共5270个字,4张图,预计阅读时间25分钟。
关键词: 可视化,D3.js,python,前端,代码
why
今天新来的实习生需要对部分分类文本进行多标签的检测,即根据已构建好的一、二级标签Excel文档,对众包平台人工标注的数据以及机器标注的数据进行评测。
此情此景,让我想起了曾经在实验做的文本多标签分类的工作,所以就想用Echart 或D3.js实现层级标签可视化为一个Tree的结构,方便实习生们查阅,提高工作效率。
说干就干!
How
处理数据
首先,找一个标准的基于D3.js实例程序,明确一下我们的工作目标以及步骤[数据的格式+前端代码]。
看一下需要将我们目前的结构化数据:
体育,篮球,NBA体育,篮球,CNA体育,篮球,CUBA体育,足球,中超体育,足球,欧冠体育,羽毛球体育,羽毛球,汤姆斯杯数码,手机,iPhone数码,手机,小米数码,电脑,MacPro数码,电脑,Dell数码,电脑,小米数码,照相机,索尼数码,照相机,尼康教育,大学,高数教育,大学,英语教育,高中,物理教育,高中,化学教育,高中,生物教育,小学教育,幼儿
标准的可以被D3.js加载的数据格式:
加载之后的Tree型结构效果图:
以上的Tree型图就是我们想要达到的目标。
我们需要将我们的数据,转换为D3.js可以加载的标准数据。
我决定使用python编写处理的脚本:编写的逻辑完全是自己瞎想的,如果各位有什么更好、更标准的方法,欢迎指出。
# coding:utf-8import sysreload(sys)sys.setdefaultencoding( "utf-8" )dic={}with open("testtag.txt") as f:for i in f:# print ii=i.split(",")k=str(i[0]).strip()if k not in dic: dic[k]=[".".join(i[1:]).strip()] # 是为了预防存在二级标签的缺失 dic[k].append(str(i[1]).strip()) # 又不能存在重复,使用set去重 dic[k]=list(set(dic[k]))else: dic[k].append(str(i[1]).strip()) dic[k].append(".".join(i[1:]).strip()) dic[k]=list(set(dic[k]))with open("3tag.csv","w") as w:w.writelines("id,value"+'\n')w.writelines("3Tag"+'\n')for i in dic.keys():w.writelines("3Tag."+i+'\n')for j in dic[i]: w.writelines("3Tag."+str(i)+"."+str(j).strip()+'\n')
处理之后的结果存储到本地的文件3tag.csv中:
一定要完全按照标准的D3.js的格式处理的。
id,value3Tag3Tag.体育3Tag.体育.篮球.CNA3Tag.体育.足球.中超3Tag.体育.篮球.CUBA3Tag.体育.篮球3Tag.体育.羽毛球3Tag.体育.足球3Tag.体育.羽毛球.汤姆斯杯3Tag.体育.篮球.NBA3Tag.体育.足球.欧冠3Tag.教育3Tag.教育.大学.高数3Tag.教育.高中3Tag.教育.幼儿3Tag.教育.高中.生物3Tag.教育.大学3Tag.教育.大学.英语3Tag.教育.高中.物理3Tag.教育.小学3Tag.教育.高中.化学3Tag.数码3Tag.数码.电脑.MacPro3Tag.数码.手机.小米3Tag.数码.照相机.索尼3Tag.数码.电脑.Dell3Tag.数码.手机.iPhone3Tag.数码.电脑.小米3Tag.数码.手机3Tag.数码.电脑3Tag.数码.照相机.尼康3Tag.数码.照相机
注意事项:
正确的数据:'''id,value3Tag3Tag.体育3Tag.体育.篮球3Tag.体育.篮球.CNA3Tag.体育.足球.中超3Tag.体育.足球'''1.处理数据的过程中要注意,不允许存在隔级的情况:eg:'''id,value3Tag3Tag.体育3Tag.体育.篮球.CNA'''*是错误,必须存在“3Tag.体育.篮球”这一级才可以,否则数据加载失败!
2.不允许存在重复的行数据,否则加载失败!'''id,value3Tag3Tag.体育3Tag.体育3Tag.体育.篮球.CNA'''
所以,整个处理的过程中,其实最麻烦的就是数据的处理了。
前端的web界面
标准数据有了,剩下的就是需要一个前端的web界面,这个代码在上面的示例页面中已经有了,只需要我们自己替换为我们的数据源就可以了,我还是贴出自己的代码吧。
<!DOCTYPE html><meta charset="utf-8"><style>.node circle {fill: #999;}.node text {font: 10px sans-serif;}.node--internal circle {fill: #555;}.node--internal text {text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;}.link {fill: none;stroke: #555;stroke-opacity: 0.4;stroke-width: 1.5px;}form {font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;position: absolute;left: 10px;top: 10px;}label {display: block;}</style><form><label><input type="radio" name="mode" value="cluster" checked> Dendrogram</label><label><input type="radio" name="mode" value="tree"> Tree</label></form><!-- <iframe src="http://10.73.20.41/mblog_info_test/library3_quality_mbblog_line_tag_distrib/" width="1300" height="1900" frameborder="0" name="" scrolling="yes"> </iframe> --><svg width="560" height="800"></svg><!-- <script src="d3.js"></script> --><script src="https://d3js.org/d3.v4.min.js"></script><script>var svg = d3.select("svg"),width = +svg.attr("width"),height = +svg.attr("height"),g = svg.append("g").attr("transform", "translate(40,0)");var tree = d3.tree().size([height - 400, width - 160]);var cluster = d3.cluster().size([height, width - 160]);var stratify = d3.stratify().parentId(function(d) { return d.id.substring(0, d.id.lastIndexOf(".")); });d3.csv("3tag.csv", function(error, data) {if (error) throw error;var root = stratify(data).sort(function(a, b) { return (a.height - b.height) || a.id.localeCompare(b.id); });cluster(root);var link = g.selectAll(".link").data(root.descendants().slice(1)).enter().append("path").attr("class", "link").attr("d", diagonal);var node = g.selectAll(".node").data(root.descendants()).enter().append("g").attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); }).attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });node.append("circle").attr("r", 5);node.append("text").attr("dy", 3).attr("x", function(d) { return d.children ? -8 : 8; }).style("text-anchor", function(d) { return d.children ? "end" : "start"; }).text(function(d) { return d.id.substring(d.id.lastIndexOf(".") + 1); });d3.selectAll("input").on("change", changed);var timeout = setTimeout(function() {d3.select("input[value=\"tree\"]").property("checked", true).dispatch("change");}, 1000);function changed() {timeout = clearTimeout(timeout);(this.value === "tree" ? tree : cluster)(root);var t = d3.transition().duration(750);node.transition(t).attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });link.transition(t).attr("d", diagonal);}});function diagonal(d) {return "M" + d.y + "," + d.x+ "C" + (d.parent.y + 100) + "," + d.x+ " " + (d.parent.y + 100) + "," + d.parent.x+ " " + d.parent.y + "," + d.parent.x; }</script></body>RESULT
最后,展示一下我们的成果:
以上就是本次层级标签可视化的实践,以后大家工作中再遇到多标签的问题,可以使用该方法快速的实现Tree型结构的可视化了,方便阅读与理解。
原文链接:https://www.jianshu.com/p/77708cfe3716
查阅更为简洁方便的分类文章以及最新的课程、产品信息,请移步至全新呈现的“LeadAI学院官网”:
www.leadai.org
请关注人工智能LeadAI公众号,查看更多专业文章
大家都在看
LSTM模型在问答系统中的应用
基于TensorFlow的神经网络解决用户流失概览问题
最全常见算法工程师面试题目整理(一)
最全常见算法工程师面试题目整理(二)
TensorFlow从1到2 | 第三章 深度学习革命的开端:卷积神经网络
装饰器 | Python高级编程
今天不如来复习下Python基础
