我构建了一个R包,它运行复杂的贝叶斯模型(空间数据上的Dirichlet Process Mixture模型),包括MCMC,细化和验证以及与Googlemaps的接口。我对性能非常满意并且运行没有问题。唯一的问题是我想在CRAN上得到它,它会被拒绝,因为我广泛使用全局变量。
该软件包围绕使用8个核心功能(用户与之交互)构建:
1)LoadData:加载数据,提取关键信息并设置一系列全局矩阵以及其他小型列表对象。
2)ModelParameters:设置模型参数,在Googlemap上绘制参数sigma之前的选项。此时计算超前验并将大矩阵保存到全局环境
3)GraphicParameters:设置地图和地块的图形参数(见下面的代码)
4)CreateMaps:在源位置tau创建先前曲面并在Google地图上绘制数据。保留许多全局对象,以便重复绘制此地图。
5)RunMCMC:使用MCMC(时间密集的步骤)运行大部分分析,创建许多全局对象。
6)ThinandAnalsye:改变后验样本并构建地理位置(时间密集的步骤)
7)PlotGP:绘制数据并将地理信息页覆盖到Google地图上
8)reporthitscores:如果导入了源数据,则可选,计算潜在来源的命中分数
每个都在下一个之前依次运行,并且我传递全局变量,这些变量由一个或多个其他函数使用。
我出于某种原因以这种方式构建它,因为用户必须停止并评估这些函数的结果,然后再向前推进。
这些函数中的每一个不仅传递固定参数,还传递大型地图对象,列表和矩阵作为全局对象。我认为这是一个很好的简单解决方案,具有流畅的工作流程(您可以在继续之前检查主要工作环境中的结果,可能应用转换等)并且我已经为所有对象提供了唯一且信息丰富的名称。
如何解决这个问题,并通过CRAN的检查,同时保持一系列交互功能的用户友好工作流程?
我不想发布大量代码(因为MCMC部分只有几百行)
但我将包括一个简单的例子。 GraphicParameters是我的简单参数设置功能之一,它带有默认值设置。这是一个简单的例子,包中有更复杂的例子。例如,有一个模型参数函数可以从现有的数据加载函数中提取许多变量。
GraphicParameters <-
function(Guardrail=0.05, nring=20,transp=0.4,gridsize=640,gridsize2=300,MapType= "roadmap",Location=getwd(),pointcol="black") {
Guardrail<<-Guardrail
nring<<-nring
transp<<-transp
gridsize<<-gridsize
gridsize2<<-gridsize2
MapType<<-MapType
Location<<-Location
pointcol<<-pointcol
}
我见过的关于避免全局对象的大多数材料都是围绕一个能完成所有工作的函数解决的。我想保持我的一步一步多功能方法,但松散全局对象。
非常感谢任何帮助。
我知道这可能是代码的重大改造(当前是几千行),所以我也喜欢最低限度影响包的整体结构的解决方案。
P.S。我希望在开始之前我已经知道CRAN对全局对象的不满!!!
答案 0 :(得分:1)
您的问题非常适合OOP风格的设计。您可以使用reference classes or S4导出单个全局,例如MapAnalysis
类生成器。那个想法就是有人用
ma <- new('MapAnalysis', option1 = ..., option2 = ..., ...) # S4
# or
ma <- MapAnalysis$new(option1 = ..., ...) # refClass
然后可以使用
调用您的方法 ma$loadData(...)
ma$setParameters(...)
对象在内部对选项和辅助对象进行任何记录。重构不应该那么多。如果你阅读了我在这篇文章顶部链接到的页面,你会发现你可能只需用refClass('MapAnalysis', fields = (...), methods = (...))
包装你的所有函数,只需要进一步修改。 (虽然在OOP术语中重新考虑架构会对你带来很多好处。)