几何平均值: 是否有一个内置的?

我试图找到一个内置的几何平均值,但不能。

(很明显,在 shell 中工作时,内置功能不会节省我任何时间,我也不怀疑在准确性方面有任何差异; 对于脚本,我尽可能多地使用内置功能,这样(累积的)性能提升通常是显而易见的。

如果没有的话(我对此表示怀疑) ,这是我的。

gm_mean = function(a){prod(a)^(1/length(a))}
92891 次浏览

没有,但是有一些人写过,比如 给你

另一种可能性是使用:

exp(mean(log(x)))

I use exactly what Mark says. This way, even with tapply, you can use the built-in mean function, no need to define yours! For example, to compute per-group geometric means of data$value:

exp(tapply(log(data$value), data$group, mean))

我们可以使用 心理包裹并调用 几何学,平均数函数。

那个

exp(mean(log(x)))

将工作,除非有一个0在 x。如果是这样,对数将产生-Inf (- Inlimited) ,其结果总是一个几何平均值为0。

One solution is to remove the -Inf value before calculating the mean:

geo_mean <- function(data) {
log_data <- log(data)
gm <- exp(mean(log_data[is.finite(log_data)]))
return(gm)
}

You can use a one-liner to do this but it means calculating the log twice which is inefficient.

exp(mean(log(i[is.finite(log(i))])))

如果数据中缺少值,这种情况并不罕见。 你需要再加一个论点。

您可以尝试以下代码:

exp(mean(log(i[ is.finite(log(i)) ]), na.rm = TRUE))

这里有一个向量化的,零和 NA 容忍的函数,用于计算 R 中的几何平均值。对于 x包含非正值的情况,涉及 length(x)的详细的 mean计算是必要的。

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值的错误等价性有关。在我心目中的应用程序中,它们是相同的,但是当然这不是普遍正确的。因此,如果希望包含可选的零传播,并且在删除 NA的情况下以不同的方式处理 length(x),那么下面的函数比上面的函数稍微长一些。

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,因为几何平均值不是为负值定义的(而是为零定义的)。感谢评论家们对我的案例的关注。

EnvStats 包有一个 geoMeanGeoSd的函数。

这个版本提供了比其他答案更多的选项。

  • 它允许用户区分不是(实数)的结果和不可用的结果。如果存在负数,那么答案将不是实数,因此返回 NaN。如果它是所有的 NA值,那么函数将返回 NA_real_,以反映实际值是不可用的。这是一个细微的差别,但是可能会产生(稍微)更加健壮的结果。

  • 第一个可选参数 zero.rm用于允许用户使用零来影响输出,而不使输出为零。如果将 zero.rm设置为 FALSE,将 eta设置为 NA_real_(它的默认值) ,则零的作用是将结果收缩为1。我没有任何理论上的理由来证明这一点——只是似乎更有意义的不是忽略这些零,而是“做一些事情”,而不是自动地使结果为零。

  • 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)
}
exp(mean(log(x1))) == prod(x1)^(1/length(x1))