Геометрическое среднее: есть ли встроенный?

Я попытался найти встроенный для среднего геометрический, но не смог.

(Очевидно, что встроенный не собирается меня спасать во время работы в оболочке, и я не подозреваю о какой-либо разнице в точности; для скриптов я стараюсь использовать встроенные модули как можно чаще, (кумулятивное) усиление производительности часто заметно.

В случае, если нет одного (что я сомневаюсь в этом), здесь мой.

gm_mean = function(a){prod(a)^(1/length(a))}

Ответ 1

Вот векторная, нулевая и 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 значение этого геометрического среднего для отрицательных значений (но для нулей). Спасибо комментаторам, которые остались в моем случае об этом.

Ответ 2

Нет, но есть несколько человек, которые написали один, например, здесь.

Другая возможность заключается в использовании этого:

exp(mean(log(x)))

Ответ 3

exp(mean(log(x)))

будет работать, если не будет 0 в x. Если это так, журнал будет создавать -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))])))

Ответ 4

вы можете использовать пакет psych и вызвать функцию geometric.mean в этом.

Ответ 5

Я использую именно то, что говорит Марк. Таким образом, даже при помощи вы можете использовать встроенную функцию mean, вам не нужно определять ваши! Например, для вычисления геометрических средств данных для каждой группы $value:

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

Ответ 6

Если в ваших данных отсутствуют значения, это не редкий случай. вам нужно добавить еще один аргумент. Вы можете попробовать следующие коды.

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

Ответ 7

В пакете EnvStats есть функция для geoMean и geoSd

Ответ 8

Вот моя версия. Он имеет следующие особенности, которые отличают его от принятого в настоящее время ответа Пола МакМерди:

  1. Когда na.rm == TRUE, значения NA игнорируются в знаменателе - следовательно, использование не пропущенных значений подсчитывает переменную values.count в знаменателе вместо length(x).
  2. При желании он различает значения NaN и общие значения NA с параметром .rm для каждого. По умолчанию NaN являются "плохими", так же как отрицательные числа являются плохими, поэтому возвращается NaN. Наличие двух параметров для обработки пропущенных значений, очевидно, не является идеальным, но способ, которым я установил значения по умолчанию для этих параметров и упорядочил case_when выражении case_when должен (мы надеемся) устранить возможность неожиданного поведения.
  3. Моя версия включает в себя еще один необязательный параметр eta который обрабатывает нули. eta умолчанию - NA_real_, в этом случае нули учитываются в знаменателе, но не распространяются (аналог необязательного параметра zero.propagate = FALSE в принятом ответе). Когда передается положительное число, eta функционирует как искусственная константа, добавляемая к x (но только в том случае, если x содержит нули). Когда передается любое другое число (предположительно 0), нули распространяются так же, как если бы zero.propagate был установлен равным TRUE в принятом ответе.

Я уверен, что могут потребоваться твики (например, может быть лучше добавить eta (учитывая, что eta - положительное число), независимо от того, есть нули или нет). Я думал даже о том, чтобы функция динамически выбирала значение для eta на основе x но не добавляла дополнительной сложности.

suppressMessages(library(dplyr))

geomean <- function(x, na.rm = TRUE, nan.rm = FALSE, eta = NA_real_) {
  nan.count <- is.nan(x) %>%
    sum()
  na.count <- is.na(x) %>%
    sum()
  value.count <- !is.na(x) %>%
    sum()
  case_when(
    #Handle cases when there are negative values, all values are missing, or
    #missing values are not tolerated.
    (nan.count > 0 & !nan.rm) | any(x < 0, na.rm = TRUE) ~ NaN,
    (na.count > 0 & !na.rm) | value.count == 0 ~ 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.
    all(x > 0, na.rm = TRUE) ~ exp(mean(log(x), na.rm = TRUE)),
    all(x == 0, na.rm = TRUE) ~ 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.
    is.na(eta) ~ exp(sum(log(x[x > 0]), na.rm = TRUE) / value.count),
    eta > 0 ~ exp(mean(log(x + eta), na.rm = TRUE)) - eta,
    TRUE ~ 0 #only propagate zeroes when eta is set to 0 (or less than 0)
  )
}