如何根据rank分组均值自动替换R数据框中的NA值
解决R语言中并列rank对应score的NA填充问题
问题背景
我们有两个数据框:
df_1:包含原始数据列,以及通过rank(ties.method = "average")生成的.rank列(并列值会取连续整数的均值,比如两个并列第1/2的rank值为1.5)df_2:存储整数rank与对应score的映射关系
当直接将.rank列映射到df_2的score时,非整数rank会产生NA值,需要按以下规则填充:
- 非整数rank是若干连续整数的均值,取这些整数rank对应score的均值填充NA
- 相同的rank值必须填充相同结果
解决方案代码
1. 准备原始数据
df_1 <- data.frame(A = c(5, 6.5, 5 , 7), B = c(0.1, 0.9, 0.7, 0.01), C = c(3.5, 3.5, 1, 2), D = c(0.1, 0.5, 0.7, 0.9)) df_1$A.rank <- rank(df_1$A, ties.method = "average") df_1$B.rank <- rank(-df_1$B, ties.method = "average") df_1$C.rank <- rank(df_1$C, ties.method = "average") df_1$D.rank <- rank(-df_1$D, ties.method = "average") df_2 <- data.frame(score_rank = c(1, 2, 3, 4), score = c(0.37, 0.25, 0.2, 0.18))
2. 生成初始映射后的数据集(含NA)
new_df_1 <- df_1[, grep("\\.rank$", colnames(df_1))] new_df_1[] <- df_2$score[match(unlist(new_df_1), df_2$score_rank)]
3. 定义rank转score的处理函数
get_score <- function(rank_val, score_df) { # 整数rank直接返回对应score if (rank_val %% 1 == 0) { return(score_df$score[score_df$score_rank == rank_val]) } # 非整数rank:计算对应的连续整数范围 n <- 2 / (rank_val %% 1) # 推导并列的整数数量 start_rank <- rank_val - (n - 1)/2 end_rank <- rank_val + (n - 1)/2 # 返回对应score的均值 mean(score_df$score[score_df$score_rank %in% start_rank:end_rank]) }
4. 生成rank-score映射表并替换NA
# 提取所有唯一的rank值 unique_ranks <- unique(unlist(new_df_1)) # 批量生成映射关系 rank_score_map <- sapply(unique_ranks, get_score, score_df = df_2) names(rank_score_map) <- unique_ranks # 替换数据框中的所有值(包括NA) new_df_1[] <- rank_score_map[as.character(unlist(new_df_1))]
5. 查看结果
print(new_df_1)
输出与预期一致:
A.rank B.rank C.rank D.rank 1 0.31 0.20 0.19 0.18 2 0.20 0.37 0.19 0.20 3 0.31 0.25 0.37 0.25 4 0.18 0.18 0.25 0.37
补充示例验证
当df_1的A列全为5时,A.rank会是2.5(1-4的均值),此时会自动填充df_2所有score的均值:
# 构造测试数据 df_1_test <- df_1 df_1_test$A <- rep(5, 4) df_1_test$A.rank <- rank(df_1_test$A, ties.method = "average") # 处理测试数据 new_df_test <- df_1_test[, grep("\\.rank$", colnames(df_1_test))] unique_ranks_test <- unique(unlist(new_df_test)) rank_score_map_test <- sapply(unique_ranks_test, get_score, score_df = df_2) new_df_test[] <- rank_score_map_test[as.character(unlist(new_df_test))] print(new_df_test$A.rank) # 输出:[1] 0.25 0.25 0.25 0.25(即(0.37+0.25+0.2+0.18)/4的结果)
内容的提问来源于stack exchange,提问作者Pierre Levoisin
相关产品推荐
相关产品推荐

