如何基于数据框指定rank而非值顺序用cumsum()计算累积倒数
问题解决:基于指定Rank计算累积倒数替换数据框
原始数据与需求
给定数据框,各列值为预先指定的排名(rank):
df <- data.frame("A" = c(3, 1, 2), "B" = c(1, 2, 3))
需求是用累积倒数替换原数据框的每个值,计算逻辑为:对应第n名的rank值,替换为 1/(1/1 + 1/2 + ... + 1/n)。例如:
- 第1名:1.0000
- 第2名:0.6667
- 第3名:0.5454
预期输出数据框为:
expected.df <- data.frame("A" = c(0.5454, 1.0000, 0.6667), "B" = c(1.0000, 0.6667, 0.5454))
现有代码问题
当前使用的代码:
df.current <- apply(df, 2, function(x) 1 /cumsum(1 / rank(x)))
未得到符合预期的列A结果,原因是rank(x)会重新计算输入值的排名,而非直接使用原数据中已指定的rank值,导致cumsum的计算顺序不符合需求。
正确解决方案
直接使用原数据中的rank值,无需重新计算排名,对每一列执行以下操作:
- 先计算1到最大rank值的累积倒数和
- 根据每个位置的rank值,取出对应的累积和并计算倒数
代码实现:
# 定义计算累积倒数的函数 calc_cum_reciprocal <- function(rank_vec) { max_rank <- max(rank_vec) # 预计算所有rank对应的累积倒数和 cum_sum <- cumsum(1 / 1:max_rank) # 根据每个位置的rank值匹配对应的结果,保留4位小数 round(1 / cum_sum[rank_vec], 4) } # 应用到数据框的每一列 df.fixed <- as.data.frame(lapply(df, calc_cum_reciprocal))
运行后得到的df.fixed与预期的expected.df完全一致:
> df.fixed A B 1 0.5454 1.0000 2 1.0000 0.6667 3 0.6667 0.5454
内容的提问来源于stack exchange,提问作者hadi
相关产品推荐
相关产品推荐

