用于计算熵的向量化函数

Vectorizing function to calculate entropy

我正在编写一个函数来计算香农多样性指数。我有广泛的数据,每个值的观察百分比作为单独的变量,每一行代表一个不同的站点。根据数据集,我将有 2 到 7 个变量。我想为每一行计算信息索引。

我有一个循环函数,但它很慢,我正在寻求帮助对其进行矢量化。我也很高兴有一个 tidyverse 风格的解决方案。

我一直在考虑使用 entropy 包,但它似乎需要长格式的数据,虽然我可以扩展我的数据,但这似乎会不必要地慢。我目前有 20k 个站点,每个站点有 100 到 1000 个观测值,这些观测值已经汇总到宽格式百分比分布中。 同样适​​用于长格式数据。

示例数据

# Wide data, between 2 and 7 columns recording the percent of observations with each value, example using 3
df <- data.frame(
  site = 1:3, 
  l1 = c(.33, .5, 0), 
  l2 = c(.33, .5, 0), 
  l3 = c(.33, 0, 1)
)

电流循环功能

entropy <- function(df, vars) {

  entropy_calc <- function(df, i, vars) {
    sum <- 0
    for (j in vars) { 
      x <- df[i,j]
      if(x != 0) { # skip zeros
        sum <- sum + x * log(x)
      }
    }
    return(-sum)
  }

  entropy <- rep(NA, nrow(df))
  for(i in 1:nrow(df)) {
    entropy[i] <- entropy_calc(df, i, vars)
  }

  return(as.numeric(entropy))
}

df$entropy <- entropy(df, 2:4)

这可以很容易地向量化,因为所需的底层函数已经向量化。您不需要手动跳过零,因为 log(0) returns -Inf0*log(0) returns NaN。通过指定 na.rm = TRUE 对单元格值求和时,可以省略 NaN

entropy <- function(p) rowSums(-(p * log(p)), na.rm = TRUE)

entropy(df[,2:4])

另请查看 vegan 包中的 diversity() 函数,它主要执行此操作以及其他可能性。