You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

大样本下R语言计算Cliffs delta遇整数溢出的解决方法咨询

解决R语言计算Cliffs Delta时的大整数溢出问题

问题背景

需要在R中计算Cliffs Delta,核心逻辑为:将A组n个观测值与B组m个观测值逐一比较,统计A组元素大于B组的次数、小于B组的次数,最终通过(大于次数 - 小于次数)/(n*m)得到结果。

但当A组有66208个观测值、B组有228691个观测值时,66208*228691的结果(约151亿)超过R中32位整数的最大值(约21亿),直接触发整数溢出:

set.seed(123)
a <- runif(228691)
b <- runif(66208)

x <- length(a) * length(b)
# 警告信息:In length(a) * length(b) : NAs produced by integer overflow

使用effsize包的cliff.delta()函数计算时,同样会抛出溢出警告,但仍能输出估计值:

library(effsize)
x <- cliff.delta(a, b)
# 警告信息:
# 1: In n1 * n2 : NAs produced by integer overflow
# 2: In n1 * n2 : NAs produced by integer overflow

x$estimate
# [1] -0.0005022877

自行实现计算逻辑时,无论是计算分母n*m还是分子的总比较次数,都会遇到相同的溢出问题。

原因分析

R默认整数类型为32位有符号整数,最大值为2^31 - 1(约2147483647)。本次数据量的乘积228691*66208=15141173728远大于该阈值,直接计算会触发溢出并返回NA。

解决方案

1. 复用effsize包的高效计算逻辑(无溢出风险)

提取effsize::cliff.delta()的核心计算代码可见,它并未直接计算n1*n2,而是通过排序+二分查找分步计算均值,完全避开超大整数运算,因此不会触发溢出:

set.seed(123)
vector1 <- runif(228691)
vector2 <- runif(66208)

.bsearch.partition <- function(x, a, b = 1, e = length(a)) {
  n <- length(x)
  low <- rep(NA, n)
  L <- rep(b, n)
  H <- rep(e, n)
  
  repeat {
    M <- as.integer((L + H) / 2)
    left <- x <= a[M]
    H[left] <- M[left]
    L[!left] <- M[!left] + 1
    if (all(H <= L)) {
      break
    }
  }
  
  H <- L
  repeat {
    below <- a[H] == x
    below[is.na(below)] <- FALSE
    if (!any(below)) 
      break
    H[below] <- H[below] + 1
  }
  
  repeat {
    L.clean <- L
    L.clean[L.clean < 1] <- NA
    above <- a[L.clean] >= x
    above[is.na(above)] <- FALSE
    if (!any(above)) 
      break
    L[above] <- L[above] - 1
  }
  
  if (any(L == H)){
    H[H == L] <- L[H == L] + 1
  }
  H[H > length(a) + 1] <- length(a) + 1
  cbind(below = L, above = H)
}

treatment <- sort(vector1)
control <- sort(vector2)

n1 <- length(treatment)
n2 <- length(control)

partitions <- .bsearch.partition(treatment, control)
partitions[, 2] <- n2 - partitions[, 2] + 1L
partitions[partitions[, 1] > n2, 1] <- n2

d_i. <- mean(partitions %*% c(1L, -1L) / n2)
d <- mean(d_i.)

d
# [1] -0.0005022877

该代码核心思路:

  • 对两组数据排序,用二分查找快速定位每个元素在另一组中的位置
  • 对每个元素计算(小于等于当前元素的数量 - 大于等于当前元素的数量)/n2后取均值
  • 最终结果等价于(总大于次数 - 总小于次数)/(n1*n2),全程无需计算超大整数乘积

2. 手动处理大整数运算

若需自行实现完整逻辑,可通过以下方式避免溢出:

  • 转换为64位整数:使用bit64包的integer64类型存储大整数:
    library(bit64)
    n1 <- as.integer64(length(a))
    n2 <- as.integer64(length(b))
    total <- n1 * n2  # 不会溢出
    
  • 转换为浮点数计算:双精度浮点数可精确表示2^53以内的整数(约9e15),远大于本次乘积,直接转换为numeric类型即可:
    total <- as.numeric(length(a)) * as.numeric(length(b))
    

关于effsize包结果的可信性

effsize包的溢出警告仅出现在计算置信区间等辅助统计量的步骤中,核心的Cliffs Delta估计值是通过上述高效逻辑计算的,与手动提取代码的结果完全一致,因此该估计值可信。

内容的提问来源于stack exchange,提问作者EmilA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 20:03:18