最近在试图使用Julia语言来完成*吴恩达《机器学习》*的课后习题,进行到exercise3时,想要仿照这里对数据实现以下的可视化效果:
对于每一个子图,只需使用Plots.heatmap()
函数来绘制即可。但怎么才能绘制多个子图呢?
如果使用pyplot
作为Plots的后端(backend),则相对比较容易,最明显的方法是在循环中逐一使用subplot()
函数即可,但我无法成功安装PyPlot
包,其依赖包ORCA
一build就出错!我只能用成功编译了的GR
包作为后端!但翻了翻Plots
的官方文档中有关GR的部分,我却没找到能便捷绘制许多个子图的命令(也可能是我没有细致查阅吧)!如果我要实现一个5*5
的子图集,一个比较繁琐的方式是:
p1=heatmap(...)
p2=heatmap(...)
...
p25=heatmap(...)
plot(p1,p2,...,p25,layout=(5,5))
这是要写到猴年马月去了!而且蠢到家了!
但是上述语句有一个特点:相似性很高,所以可以考虑使用元编程+循环的形式来精简代码。
这里不作过多的介绍,我只使用其中两个简单的函数:eval()
和Meta.parse()
。
eval(expr)
:Evaluate an expression in the global scope of the containing module.Meta.parse()
:Parse the expression string and return an expression (which could later be passed to eval for execution).简单的用例如下:
Meta.parse("x=3") # 返回一个Expression:`:(x = 3)`,注意`:`是Symbol类型的标识符
eval(Meta.parse("x=3"))
println(x) # 返回3,说明上式执行了x=3的语句
下面假设我要生成100个变量,分别命名为x1,x2,...,x100
,且想让它们分别等于1,2,...,100
,就可以这样写:
for i in 1:100
eval(Meta.parse("x$i=$i"))
end
println(x49) # 返回49
仿照此例,最终的解决方案呼之欲出!
涉及了Julia的元编程+循环+字符串拼接:
# 准备阶段:数据读入
using MAT
dict=matread("ex3data1.mat")
size(dict["X"]),size(dict["y"]) # ((5000, 400), (5000, 1))
# 数据可视化
using Plots;gr()
function show_one_img()
i=rand(1:size(dict["X"],1),1)
s=dict["X"][i,:]
s=reverse(reshape(s,(20,20)),dims=1) # 每个样本都是20*20的灰度图
return heatmap(s,colorbar=:none)
end
show_one_img() # 重复几次看看
str_ps=""
for i in 1:25
eval(Meta.parse("p$i=show_one_img()"))
global str_ps *= "p$i," # 注意:julia的字符串拼接符是*,而非+
end
println(str_ps) # p1,p2,p3,p4,...,p22,p23,p24,p25,
eval(Meta.parse("plot(" * str_ps * "layout=(5,5))"))
求求了,哪家机构搭建个Julia包的国内镜像吧!