如何实现满足最小计数阈值的整数数据非均匀分箱(隐私保护)
整数型数据非均匀分箱实现(最小频数阈值约束)
需求说明
出于隐私保护目的,需对整数型数值数据进行非均匀分箱处理:
- 每个分箱的频数不得低于最小阈值
x - 尽可能最小化箱宽,减少数据损失
需要实现一个函数,输入整数集合(如data$column)与最小计数阈值x,返回包含分箱结果的treated_column字段。
示例(阈值x=3)
set.seed(10) data <- tibble(column = sample(1:5, 10, replace = TRUE)) # 原数据频数统计 data %>% count(column) # 预期分箱结果 expected_data <- data %>% mutate(treated_column = c('3-5','1-2','1-2','3-5','3-5','1-2','1-2','1-2','3-5','3-5')) expected_data %>% count(treated_column)
贴近实际的测试数据
set.seed(5) data <- tibble(columnA = sample(1:100, 1000, replace = TRUE), columnB = sample(10:1000, 1000, replace = TRUE))
实现方案
以下是基于梳理的逻辑实现的R函数,依赖dplyr和tibble包:
library(dplyr) library(tibble) bin_integer_data <- function(data_col, x) { # 统计频数并按整数升序排列 freq_table <- data_col %>% enframe(name = NULL, value = "value") %>% count(value, sort = FALSE) %>% arrange(value) if(nrow(freq_table) == 0) { stop("输入数据为空") } bins <- list() current_bin_start <- freq_table$value[1] current_count <- freq_table$n[1] # 遍历合并分箱,直到满足阈值要求 for(i in 2:nrow(freq_table)) { if(current_count < x) { current_count <- current_count + freq_table$n[i] } else { bins <- append(bins, list(c(current_bin_start, freq_table$value[i-1]))) current_bin_start <- freq_table$value[i] current_count <- freq_table$n[i] } } # 添加最后一个临时分箱 bins <- append(bins, list(c(current_bin_start, freq_table$value[nrow(freq_table)]))) # 检查最后一个分箱的频数,不足则合并最后两个分箱 if(length(bins) >= 2) { last_bin_vals <- freq_table %>% filter(value >= bins[[length(bins)]][1], value <= bins[[length(bins)]][2]) %>% pull(n) %>% sum() if(last_bin_vals < x) { merged_bin <- c(bins[[length(bins)-1]][1], bins[[length(bins)]][2]) bins <- bins[-c(length(bins)-1, length(bins))] bins <- append(bins, list(merged_bin)) } } # 生成分箱标签与原数值的映射表 bin_mapping <- tibble( value = integer(), treated_column = character() ) for(bin in bins) { start <- bin[1] end <- bin[2] label <- if(start == end) as.character(start) else paste0(start, "-", end) bin_mapping <- bind_rows( bin_mapping, tibble(value = start:end, treated_column = label) ) } # 将原数据映射为分箱结果 treated_col <- data_col %>% enframe(name = NULL, value = "value") %>% left_join(bin_mapping, by = "value") %>% pull(treated_column) return(treated_col) }
使用示例
# 测试基础示例 set.seed(10) data <- tibble(column = sample(1:5, 10, replace = TRUE)) data$treated_column <- bin_integer_data(data$column, 3) data %>% count(treated_column) # 测试实际数据 set.seed(5) data <- tibble(columnA = sample(1:100, 1000, replace = TRUE), columnB = sample(10:1000, 1000, replace = TRUE)) data$treated_columnA <- bin_integer_data(data$columnA, 20) data$treated_columnB <- bin_integer_data(data$columnB, 15) # 查看分箱结果 data %>% count(treated_columnA) data %>% count(treated_columnB)
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

