R中coin::kruskal_test加权秩转换警告问题及替代方案咨询
加权Kruskal-Wallis检验的警告问题与替代方案
我正在使用R中的coin::kruskal_test函数执行加权Kruskal-Wallis检验,但遇到了**“秩转换未考虑权重”**的警告。
触发警告的代码
library(tidyverse) library(coin) library(purrr) set.seed(1) punteggi = tibble( Codice = paste0("cod_", 1:200), Regione = sample(c("FVG", "Lazio", "Sicilia"), size = 200, replace = T, prob = c(.4, .2, .4)), Genere = sample(c("Femminile", "Maschile"), size = 200, replace = T, prob = c(.6, .4)), Area = sample(c("Urbana", "Extra urbana"), size = 200, replace = T, prob = c(.6, .4)), ) punteggi = punteggi |> group_by(Regione, Genere, Area) |> mutate( mu = runif(1, 4, 7), sd = runif(1, 1, 2), weight = n() ) |> ungroup() |> rowwise() |> mutate(pt_tot = rnorm(1, mu, sd)) punteggi kruskal_per_group_weighted <- function(data) { test_result <- tryCatch({ coin::kruskal_test(pt_tot ~ value, data = data, weights = ~ weight) }, error = function(e) { message("Errore in kruskal_test: ", e) return(NULL) }) return(coin::pvalue(test_result)) } kruskal_per_group_NO_weighted <- function(data) { test_result <- tryCatch({ coin::kruskal_test(pt_tot ~ value, data = data) }, error = function(e) { message("Errore in kruskal_test: ", e) return(NULL) }) return(coin::pvalue(test_result)) } punteggi |> pivot_longer(c(Regione, Genere, Area)) |> mutate(across(value, as.factor)) |> nest(.by = name) |> mutate( kruskal = map_dbl(data, kruskal_per_group_NO_weighted), kruskal_weighted = map_dbl(data, kruskal_per_group_weighted) )
收到的警告信息
<warning/rlang_warning> Warning in `mutate()`: i In argument: `kruskal_weighted = map_dbl(data, kruskal_per_group_weighted)`. Caused by warning in `ft()`: ! rank transformation doesn't take weights into account --- Backtrace: x 1. +-dplyr::mutate(...) 2. \-dplyr:::mutate.data.frame(...)
问题补充
加权与非加权Kruskal-Wallis检验的p值存在差异。请问是否有方法解决该警告,让coin::kruskal_test的秩转换正确考虑权重?或者在R中执行加权Kruskal-Wallis检验有什么替代方法?
解决方案
1. 理解coin::kruskal_test的权重限制
coin包的kruskal_test函数的weights参数仅用于检验统计量计算阶段的权重调整,不会在秩转换时应用权重,这就是警告的核心原因。当前得到的“加权”结果并非严格意义上的加权Kruskal-Wallis检验。
2. 手动实现加权秩转换
可以先手动计算考虑权重的秩,再用kruskal_test检验:
# 自定义加权秩计算函数(处理结值) weighted_rank <- function(x, w) { order_x <- order(x) x_ordered <- x[order_x] w_ordered <- w[order_x] ties <- rle(x_ordered) rank_pos <- cumsum(ties$lengths) rank_start <- rank_pos - ties$lengths + 1 weighted_ranks <- numeric(length(x)) for (i in seq_along(ties$values)) { idx <- rank_start[i]:rank_pos[i] total_w <- sum(w_ordered[idx]) avg_rank <- sum(w_ordered[idx] * rank_start[i]:rank_pos[i]) / total_w weighted_ranks[idx] <- avg_rank } weighted_ranks[order(order_x)] <- weighted_ranks return(weighted_ranks) } # 修改加权检验函数 kruskal_per_group_weighted_fixed <- function(data) { data <- data |> mutate(pt_tot_weighted_rank = weighted_rank(pt_tot, weight)) test_result <- tryCatch({ coin::kruskal_test(pt_tot_weighted_rank ~ value, data = data) }, error = function(e) { message("Errore in kruskal_test: ", e) return(NULL) }) return(coin::pvalue(test_result)) } # 重新运行检验 punteggi |> pivot_longer(c(Regione, Genere, Area)) |> mutate(across(value, as.factor)) |> nest(.by = name) |> mutate( kruskal = map_dbl(data, kruskal_per_group_NO_weighted), kruskal_weighted = map_dbl(data, kruskal_per_group_weighted), kruskal_weighted_fixed = map_dbl(data, kruskal_per_group_weighted_fixed) )
3. 使用替代包:wrs2
wrs2包提供了专门的kruskalwallisW函数,直接支持加权Kruskal-Wallis检验,无需手动处理秩转换:
library(wrs2) # 修改函数使用wrs2包 kruskal_per_group_weighted_wrs2 <- function(data) { test_result <- tryCatch({ wrs2::kruskalwallisW(pt_tot ~ value, data = data, weights = weight) }, error = function(e) { message("Errore in kruskalwallisW: ", e) return(NULL) }) return(test_result$p.value) } # 运行检验 punteggi |> pivot_longer(c(Regione, Genere, Area)) |> mutate(across(value, as.factor)) |> nest(.by = name) |> mutate( kruskal = map_dbl(data, kruskal_per_group_NO_weighted), kruskal_weighted_wrs2 = map_dbl(data, kruskal_per_group_weighted_wrs2) )
4. 注意事项
- 手动计算加权秩时必须正确处理结值(相同观测值),否则会影响结果准确性;
wrs2包的实现经过验证,是更简便可靠的选择。
内容的提问来源于stack exchange,提问作者Erik De Luca
相关产品推荐
相关产品推荐

