用R中的嵌套ifs评估一系列标准-有更好的方法吗?
我的大部分工作都是围绕肺结核的诊断测试展开的。正如您所想象的,能够快速评估和验证这些测试的输出非常方便。我写了一个函数,它就是这样做的(为了清晰起见进行了精简)。简而言之,它从测试中获取数值结果,并生成制造商指定的解释 这个函数对我来说运行得很好——我已经通过了数千个测试对它进行了验证,并且它的速度足够快,可以处理任何我抛出的东西。不过,我想将它和几个类似的函数捆绑到一个包中以供更广泛的使用,我想在这样做之前获得一些反馈:用R中的嵌套ifs评估一系列标准-有更好的方法吗?,r,coding-style,package,control-flow,R,Coding Style,Package,Control Flow,我的大部分工作都是围绕肺结核的诊断测试展开的。正如您所想象的,能够快速评估和验证这些测试的输出非常方便。我写了一个函数,它就是这样做的(为了清晰起见进行了精简)。简而言之,它从测试中获取数值结果,并生成制造商指定的解释 这个函数对我来说运行得很好——我已经通过了数千个测试对它进行了验证,并且它的速度足够快,可以处理任何我抛出的东西。不过,我想将它和几个类似的函数捆绑到一个包中以供更广泛的使用,我想在这样做之前获得一些反馈: 该函数依赖于围绕嵌套if-else函数的大for循环。它并不特别优雅,对
根据要求,.如果您不希望
用于
循环,请使用应用
并编写函数以返回解释。编辑以反映注释并根据测试数据进行验证
您可以避免任何类型的循环或(如果
),只需使用R向量下标:
qft.interp <- function(nil, tb, mitogen, tbnil.cutoff = 0.35){
# Set a tolerance to avoid floating point comparison troubles.
tol <- .Machine$double.eps ^ 0.5
# Set up the results vector
result <- rep(NA, times = length(nil))
result[nil+tol > 8.0] <- "Indeterminate"
result[is.na(result) & (tb-nil+tol > tbnil.cutoff) &
(tb-nil+tol > .25*nil)] <- "Positive"
result[is.na(result) & (tb-nil+tol < tbnil.cutoff | tb-nil+tol < .25*nil) &
!(mitogen-nil+tol < 0.5)] <- "Negative"
result[is.na(result) & ((tb-nil+tol < tbnil.cutoff | tb-nil+tol < .25*nil) &
mitogen-nil+tol < 0.5)] <- "Indeterminate"
result
}
all(with(tests, qft.interp(nil, tb, mitogen)) == tests$interp)
[1] TRUE
qft.interpresult[nil+(tol>8.0)]tbnil.cutoff]&(tb-nil+(tol>0.25*nil))]潜在变化的标准是硬编码值,如8、.25等?或术语,例如中间术语?或者别的什么?你能发布一些示例数据和预期结果,这样我们就可以测试我们所做的任何更改吗?事实上,我已经有一段时间没有看过全球标准了——看起来这只是北美独有的最后一组标准(第23-26行)。这将很容易切换开关。但也有可能我想为不同的人群(如免疫功能低下的患者)添加其他标准集,或在研究中制定的替代标准。关于#1,编写良好的for循环通常比*apply
方法更快(for循环在过去版本的R中更慢)。矢量化解决方案将是最快的。谢谢大家的帮助。虽然控制流是一个大问题,但这一问题可能有点过分了。我将进一步研究这个问题,看看是否还有问题。添加了示例数据!谢谢你的建议。我认为你需要删掉一些[I]实例来获得一个完全矢量化的解决方案,但我同意这是最干净的方法。请参阅下面我在评论中的行,这行不通。这种方法的问题是,后面的标准可能会覆盖前面的标准:例如,在样本数据中有一个测试,nil=9.41,tb=6.73,mitogen=10。这是最初设定的(正确的)不确定值,但后来改为负数。原始的if()
流阻止了这种情况的发生。@马特·帕克:您可以将is.na(result)
添加到后面的每个条件中。那么你会保留优先权。@Joshua:的确如此!刚刚在一个更大的数据集上验证了这一点,结果与以前一样。apply
只是for
的一种很好的形式,通常不是快速正确的,这就是为什么我倾向于忘记它。无论如何,速度在这里并不重要——它已经足够快了。不过,相当不错。谢谢你的评论。注意Matt Parker的评论,即标准不是MECE,因此您应该添加!将.na(result)
添加到一些测试中。看看我的最新答案。@Andrie:很好,你已经找到了。我不知道他们是否真的相互排斥。我确实认为收紧代码(如di)将使维护和调试更容易。
result[ nil + (tol > 8.0)] <- "Indeterminate"
result[(tb - nil + (tol > tbnil.cutoff) ) & (tb - nil + (tol > .25 * nil) )] <- "Positive"
result[ (tb - nil + (tol < tbnil.cutoff) )| (tb - nil + (tol < .25 * nil)) &
!(mitogen - nil + tol < 0.5) ] <- "Negative"
result[ (tb - nil + (tol < tbnil.cutoff) ) | (tb - nil + (tol < .25 * nil) ) &
(mitogen - nil + (tol < 0.5) ) ] <- "Indeterminate"