我试图找到一个内置的几何均值,但找不到。
(显然,内置程序在外壳程序中工作不会节省我的时间,我也不怀疑准确性是否存在任何差异;对于脚本,我尝试尽可能多地使用内置程序,其中(累计)性能提升通常很明显。
万一没有(我怀疑是这样)这是我的。
gm_mean = function(a){prod(a)^(1/length(a))}
我试图找到一个内置的几何均值,但找不到。
(显然,内置程序在外壳程序中工作不会节省我的时间,我也不怀疑准确性是否存在任何差异;对于脚本,我尝试尽可能多地使用内置程序,其中(累计)性能提升通常很明显。
万一没有(我怀疑是这样)这是我的。
gm_mean = function(a){prod(a)^(1/length(a))}
Answers:
这是一个矢量化的,零容忍和NA容忍的函数,用于计算R中的几何平均值。mean
涉及包含非正值length(x)
的情况下,需要进行冗长的计算x
。
gm_mean = function(x, na.rm=TRUE){
exp(sum(log(x[x > 0]), na.rm=na.rm) / length(x))
}
感谢@ ben-bolker注意na.rm
传递,并感谢@Gregor确保传递正确。
我认为某些评论与NA
数据和零值的错误等价性有关。在我想到的应用程序中,它们是相同的,但是当然,通常情况并非如此。因此,如果要包括可选的零传播,并且length(x)
在NA
删除时进行不同的处理,则以下内容是上述函数的稍长替代方法。
gm_mean = function(x, na.rm=TRUE, zero.propagate = FALSE){
if(any(x < 0, na.rm = TRUE)){
return(NaN)
}
if(zero.propagate){
if(any(x == 0, na.rm = TRUE)){
return(0)
}
exp(mean(log(x), na.rm = na.rm))
} else {
exp(sum(log(x[x > 0]), na.rm=na.rm) / length(x))
}
}
请注意,它还会检查任何负值,并返回更多信息和适当的信息,NaN
即没有为负值定义几何平均值(而是为零)。感谢发表评论的评论者,他们一直在我的案子上发表评论。
na.rm
作为参数传递会更好吗(即,为了与其他R摘要函数保持一致,让用户决定是否要接受NA容忍)?我很担心自动排除零-我也会选择这个。
na.rm
的选择。我将更新我的答案。至于排除零,对于非零值(包括零),几何平均值是不确定的。上面是几何平均值的通用修正方法,其中零(或在这种情况下为所有非零)的虚拟值为1,这对乘积没有影响(或对数和为零)。
na.rm
传递功能无法按编码方式工作...请参阅gm_mean(c(1:3, NA), na.rm = T)
。您需要& !is.na(x)
从向量子集中删除,并且由于sum
is 的第一个arg ...
,您需要na.rm = na.rm
按名称传递,并且还需要在调用中从向量中排除0
“和NA
” length
。
x
仅包含零(例如)x <- 0
,就exp(sum(log(x[x>0]), na.rm = TRUE)/length(x))
给出1
了几何平均值,这是没有意义的。
我们可以使用心理包并调用geometric.mean函数。
psych::geometric.mean()
的
exp(mean(log(x)))
除非x中为0,否则它将起作用。如果是这样,对数将产生-Inf(-Infinite),该结果的几何平均值始终为0。
一种解决方案是在计算平均值之前删除-Inf值:
geo_mean <- function(data) {
log_data <- log(data)
gm <- exp(mean(log_data[is.finite(log_data)]))
return(gm)
}
您可以使用单线来执行此操作,但这意味着两次计算日志效率不高。
exp(mean(log(i[is.finite(log(i))])))
sum(x) / length(x)
如果过滤x并将其传递给,则均值的分母是错误的mean
。
这个版本提供了比其他答案更多的选择。
它允许用户区分不是(真实)数字的结果和不可用的结果。如果存在负数,则答案将不是实数,因此NaN
将返回。如果是所有NA
值,则函数将返回NA_real_
以反映实际值实际上不可用。这是一个细微的差异,但可能会产生(稍微)更可靠的结果。
第一个可选参数zero.rm
旨在使用户零影响输出而不将其设为零。如果zero.rm
将设置为FALSE
并将eta
其设置为NA_real_
(其默认值),则零将结果缩小为一。我对此没有任何理论上的理由-似乎更有意义的是不忽略零,而是“做一些不涉及自动使结果为零的事情”。
eta
下列讨论启发了这种处理零的方法:https : //support.bioconductor.org/p/64014/
geomean <- function(x,
zero.rm = TRUE,
na.rm = TRUE,
nan.rm = TRUE,
eta = NA_real_) {
nan.count <- sum(is.nan(x))
na.count <- sum(is.na(x))
value.count <- if(zero.rm) sum(x[!is.na(x)] > 0) else sum(!is.na(x))
#Handle cases when there are negative values, all values are missing, or
#missing values are not tolerated.
if ((nan.count > 0 & !nan.rm) | any(x < 0, na.rm = TRUE)) {
return(NaN)
}
if ((na.count > 0 & !na.rm) | value.count == 0) {
return(NA_real_)
}
#Handle cases when non-missing values are either all positive or all zero.
#In these cases the eta parameter is irrelevant and therefore ignored.
if (all(x > 0, na.rm = TRUE)) {
return(exp(mean(log(x), na.rm = TRUE)))
}
if (all(x == 0, na.rm = TRUE)) {
return(0)
}
#All remaining cases are cases when there are a mix of positive and zero
#values.
#By default, we do not use an artificial constant or propagate zeros.
if (is.na(eta)) {
return(exp(sum(log(x[x > 0]), na.rm = TRUE) / value.count))
}
if (eta > 0) {
return(exp(mean(log(x + eta), na.rm = TRUE)) - eta)
}
return(0) #only propagate zeroes when eta is set to 0 (or less than 0)
}
dplyr
除非有必要,否则我个人不想像这样的实用程序那样增加严重的依赖关系……)
case_when
s有点愚蠢,因此我删除了它们,并删除了对if
s 的依赖。我还提供了一些详细说明。
nan.rm
,以TRUE
对齐所有三个```.rm``参数。
ifelse
设计用于矢量化。仅需检查一个条件,使用起来就更惯用了value.count <- if(zero.rm) sum(x[!is.na(x)] > 0) else sum(!is.na(x))
ifelse
。变了 谢谢!