如何使用dplyr填补排序分级索引中的空缺?
分级索引生成:空缺槽位的填补解决方案
我正在编写一个R函数,根据用户输入的初始值列表和总槽位数量生成排序后的分级索引,规则如下:
- 当列表元素数量少于总槽位时,需在空缺处插入连续数字
- 所有情况下第一个索引槽位必须为1(若列表未提供1.1)或1.1(若列表提供了1.1)
我用dplyr::dense_rank实现了示例1的基础场景(提供的列表元素均小于总槽位),能正确填补空缺,但不确定如何处理以下场景:
- 列表元素均大于1或1.1(如示例2、3)
- 列表元素间存在其他空缺(如示例4)
示例1输出(符合要求)
# A tibble: 5 x 2 Slot Value <int> <dbl> 1 1 1.1 2 2 1.2 3 3 2.1 4 4 2.2 5 5 3
可复现代码
library(dplyr) # 示例1:基础场景 Value <- c(2.1, 1.2, 1.1, 2.2) totalSlots <- 5 # 示例2:元素均大于1.1 # Value <- c(2.1, 2.2) # totalSlots <- 3 # # 示例3:元素均远大于1 # Value <- c(4.1, 4.2, 4.3) # totalSlots <- 6 # 示例4:元素间存在空缺 # Value <- c(1.1, 1.2, 3.1, 3.2, 3.3, 6.1, 6.2) # totalSlots <- 10 tibble(Value) %>% mutate(Slot = row_number()) %>% complete(Slot = seq_len(totalSlots)) %>% mutate( Value = coalesce(Value[order(Value)], Slot), Value = dense_rank(as.integer(Value)) + Value - as.integer(Value) )
解决方案
Richard Berry的基础实现
该方案通过合并空缺数字与原始值并排序,直接生成符合要求的索引数据框,能覆盖所有场景:
indexDF <- data.frame(Slot = c(1:totalSlots), Value = sort(c(setdiff(1:totalSlots, floor(Value)), Value))[1:totalSlots]) indexDF
逻辑说明:
setdiff(1:totalSlots, floor(Value)):找出总槽位范围内,未被原始值整数部分占用的连续数字(即需要填补的空缺)- 将填补数字与原始值合并后排序,取前
totalSlots个元素作为最终的Value列 - 生成包含
Slot(1到总槽位)和Value的结果数据框
各示例验证:
- 示例2运行结果:
Slot Value 1 1 1.0 2 2 2.1 3 3 2.2
- 示例3运行结果:
Slot Value 1 1 1.0 2 2 2.0 3 3 3.0 4 4 4.1 5 5 4.2 6 6 4.3
- 示例4运行结果:
Slot Value 1 1 1.1 2 2 1.2 3 3 2.0 4 4 3.1 5 5 3.2 6 6 3.3 7 7 4.0 8 8 5.0 9 9 6.1 10 10 6.2
dplyr风格的封装版本
如果需要更灵活的函数式调用,可以用dplyr封装逻辑:
library(dplyr) generate_index <- function(Value, totalSlots) { # 生成需要填补的连续数字 fill_nums <- setdiff(1:totalSlots, floor(Value)) # 合并、排序并截取指定数量的元素 full_values <- sort(c(fill_nums, Value))[1:totalSlots] tibble(Slot = 1:totalSlots, Value = full_values) } # 测试示例2 generate_index(c(2.1, 2.2), 3) # 测试示例3 generate_index(c(4.1, 4.2, 4.3), 6) # 测试示例4 generate_index(c(1.1, 1.2, 3.1, 3.2, 3.3, 6.1, 6.2), 10)
这个函数完全满足所有需求:
- 自动确保第一个槽位为1或1.1(取决于原始输入)
- 填补所有空缺的连续数字
- 保留原始分级索引的排序逻辑
内容的提问来源于stack exchange,提问作者Curious Jorge - user9788072
相关产品推荐
相关产品推荐

