机器学习给我们提供了一些强大的工具,能从未知数据中抽取出有用的信息。因此,能否这些信息以易于人们理解的方式呈现十分重要。如果人们可以直接与算法和数据交互,将可以比较轻松的进行解释。其中一个能够同时支持数据呈现和用户交互的方式就是构建一个图形用户界面(GUI)。
利用GUI对回归树调优的基本步骤:
1、收集数据:所提供的文本文件
2、准备数据:用Python解析上述文件,得到数值型数据
3、分析数据:用tkinter构建一个GUI来展示模型和数据
4、训练算法:训练一棵回归树和一颗模型树,并与数据集一起展示
5、测试算法:这里一般不需要测试过程
6、使用算法:GUI使得人们可以在预剪枝时测试不同参数的影响,还可以帮助我们选择模型的类型。
用tkinter创建GUI
Python有很多GUI框架,其中一个易于使用的tkinter,是随Python的标准编译版本发布的。tkinter可以在Windows、Mac OS和大多数的Linux平台上使用。
简答的GUI窗口:
from tkinter import *
root=Tk()
myLabel=Label(root,text='hello')
myLabel.grid()
root.mainloop()
tkinter的GUI由一些小部件组成。所谓小部件,指的是文本框、按钮、标签和复选按钮等对象。
下面将所需要的小部件集成在一起,构建树管理器。建立一个新的Python文件:
from tkinter import *
from numpy import *
def loadDataSet(fileName):
dataMat=[]
fr=open(fileName)
for line in fr.readlines():
curLine=line.strip().split('\t')
fltLine=list(map(float,curLine))
#print(list(fltLine))
dataMat.append(fltLine)
return dataMat
def reDraw(tolS,tolN):
pass
def drawNewTree():
pass
root=Tk()
Label(root,text='Plot Place Holder').grid(row=0,columnspan=3)
Label(root,text='tolN').grid(row=1,column=0)
tolNentry=Entry(root)
tolNentry.grid(row=1,column=1)
tolNentry.insert(0,'10')
Label(root,text='tolS').grid(row=2,column=0)
tolSentry=Entry(root)
tolSentry.grid(row=2,column=1)
tolSentry.insert(0,'1.0')
Button(root,text='ReDraw',command=drawNewTree).grid(row=1,column=2,rowspan=3)
chkBtnVar=IntVar()
chkbtn=Checkbutton(root,text='model Tree',variable=chkBtnVar)
chkbtn.grid(row=3,column=0,columnspan=2)
reDraw.rawDat=mat(loadDataSet('test/sine.txt'))
reDraw.testDat=arange(min(reDraw.rawDat[:,0]),max(reDraw.rawDat[:,0]),0.01)
reDraw(1.0,10)
root.mainloop()
上述代码中,先是建立了一组tkinter模块,并用网格布局管理器安排了它们的位置,这里还给出了两个绘制占位符函数。代码中先创建了一个Tk类型的根部件然后插入标签,我们可以使用grid()方法设定行和列的位置,也可以通过设定columnspan和rowspan的值来告诉布局管理器是否允许一个小部件跨行或跨列。除此以外还有其他设置项可供使用。
现在GUI可以按照要求正常运行,下面利用它来绘图。
集成matplotlib和tkinter
matplotlib的构建程序包括一个前端,同时创建一个后端,用于实现绘图和不同应用之间接口。通过改变后端可以将图像绘制在PNG、PDF、SVG等格式的文件上。
下面将设置后端为TkAgg。TkAgg可以在所选GUI框架上调用Agg,把Agg呈现在画布上。我们可以在Tk的GUI上放置一个画布,并用grid()来调整布局。
先用画布来替换绘制占位符,删掉对应标签并添加以下代码:
reDraw.f = Figure(figsize=(5,4), dpi=100) #create canvas
reDraw.canvas = FigureCanvasTkAgg(reDraw.f, master=root)
reDraw.canvas.draw()
reDraw.canvas.get_tk_widget().grid(row=0, columnspan=3)
下面将树创建函数与画布链接起来:
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
def reDraw(tolS,tolN):
reDraw.f.clf()
reDraw.a=reDraw.f.add_subplot(111)
if chkBtnVar.get():
if tolN<2:
tolN=2
myTree=createTree(reDraw.rawDat,modelLeaf,modelErr,ops=(tolS,tolN))
yHat=createForeCase(myTree,reDraw.testDat,modelTreeEval)
else:
myTree=createTree(reDraw.rawDat,ops=(tolS,tolN))
yHat=createForeCase(myTree,reDraw.testDat)
reDraw.a.scatter(reDraw.rawDat[:,0].tolist(),reDraw.rawDat[:,1].tolist(),s=5)
reDraw.a.plot(reDraw.testDat,yHat,linewidth=2.0)
reDraw.canvas.draw()
def getInputs():
try:
tolN=int(tolNentry.get())
except:
tolN=10
print('enter Integer for tolN')
tolNentry.delete(0,END)
tolNentry.insert(0,'10')
try:
tolS=float(tolSentry.get())
except:
tolS=1.0
print('enter Float for tolS')
tolSentry.delete(0,END)
tolSentry.insert(0,'1.0')
return tolN,tolS
def drawNewTree():
tolN,tolS=getInputs()
reDraw(tolS,tolN)
上述代码中,一开始导入matplotlib文件并设定后端为TkAgg。
drawNewTree()函数在ReDraw按钮被点击时被调用,它实现了两个功能:1、调用getInputs()方法得到输入框的值;2、利用该值调用reDraw()方法生成图
getInputs()函数试图理解用户的输入并防止程序崩溃。其中tolS期望的输入是浮点数,而tolN期望的输入是整数。为了得到用户输入的文本,可以在Entry部件上调用.get()方法。另外这里使用了try和except模式,如果Python可以把输入文本解析成整数就继续执行,如果不能识别则输出错误信息,同时清空输入框并恢复为默认值。
reDraw()函数的主要目的是把树绘制出来。该函数假定输入是合法的,它首先要做的是清空之前的图像,使得前后两个图像不会重叠。清空时图像的各个子图也都会被清除,所以需要重新添加一个新图。接下来函数会检查复选框是否被选中。根据复选框是否被选中,确定基于tolS和tolN参数构建模型树还是回归树。当树构建完成之后就对测试集testDat进行预测,该测试集与训练集有相同的范围且点的分布均匀。最后,真实数据和预测值都会被绘制出来。具体实现是,真实值采用scatter()方法绘制,而预测值则采用plot()方法绘制,这是因为scatter()方法构建的是离散型散点图,而plot()方法则构建连续曲线。
实际绘制效果: