You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言SDC包ProtectTable()不收敛问题求解

问题描述

我有一个包含4个多标签分类变量的数据集:两个变量的基数为4,一个为2,一个为3。为了支持单个变量内多个值为真的场景,我将这些变量独热编码为二进制矩阵,最终得到13个基数为2的变量。但此时使用sdc包的ProtectTable()函数时无法收敛。我曾尝试创建变量所有可能组合的联合变量,但披露控制未成功;未编码原始变量时函数运行正常。

重现代码
onehotencoded <- df_ref %>%
  mutate(
    FQuarter_1 = if_else(FQuarter == "Q1", 1, 0),
    FQuarter_2 = if_else(FQuarter == "Q2", 1, 0),
    FQuarter_3 = if_else(FQuarter == "Q3", 1, 0),
    FQuarter_4 = if_else(FQuarter == "Q4", 1, 0),
    FYear_24 = if_else(FYear == "2024", 1, 0),
    FYear_23 = if_else(FYear == "2023", 1, 0),
    FYear_22 = if_else(FYear == "2022", 1, 0),
    FYear_21 = if_else(FYear == "2021", 1, 0),
    Working_model_FT = if_else(Working_model == "Full-time", 1, 0),
    Working_model_PT = if_else(Working_model == "Part-time", 1, 0),
    Gender_Male = if_else(Gender == "men", 1, 0),
    Gender_Female = if_else(Gender == "women", 1, 0),
    Gender_Diverse = if_else(Gender == "else", 1, 0)
  ) %>%
  select(-FQuarter, -FYear, -Working_model, -Gender)


df_ref <- onehotencoded


# Negative Threshold ------------------------------------------------------

negative_threshold_function <- function(df_ref, threshold) {
  # convert inputs to character type
  df_ref <- df_ref %>% mutate_all(as.character)
  
  # Create dimList object dynamically for all dimensions in df_ref (except the first column org_level_hierachy)
  dimList <- list()
  
  for (col_name in colnames(df_ref)) {
    dim_hierarchy <- sdcHierarchies::hier_create(root = "Total", nodes = unique(df_ref[[col_name]]))
    dim_data <- matrix(nrow = nrow(dim_hierarchy), ncol = 2)
    dim_data[,1] <- sapply(dim_hierarchy$level, function(x) paste(replicate(x, "@"), collapse = ""))
    dim_data[,2] <- dim_hierarchy$leaf
    colnames(dim_data) <- c("levels", "codes")
    dim_data <- as.data.frame(dim_data)
    dimList[[col_name]] <- dim_data
  }
  
  # Protect table, with secondary suppression
  df_aggregated_protected <- ProtectTable(df_ref,
                                          dimList = dimList,
                                          infoAsFrame = T,
                                          #method = "HITAS",
                                          method = "SIMPLEHEURISTIC_OLD",
                                          maxN = threshold,
                                          maxVars = 2,
                                          #maxVars = ncol(df_ref) - 1,
                                          fastSolution = TRUE,
                                          save = FALSE, # save tables in between
                                          timeLimit = 0.1, #so to say a timeout, set very low, trying to fasten computation
                                          verbose = TRUE) #"Total" means filter is not selected.
  
  #small adjustments: sdcStatusLegend, Suppression column
  df_aggregated_protectedFinal <- df_aggregated_protected[["data"]] %>% 
    mutate(sdcStatusLegend = case_when(
      sdcStatus == "u" ~ "cell is primary suppressed and needs to be protected",
      sdcStatus == "x" ~ "cell has been secondary suppressed",
      sdcStatus == "s" ~ "cell can be published",
      sdcStatus == "z" ~ "cell must not be suppressed"
    )) %>% 
    mutate(suppressed = case_when(
      is.na(suppressed) ~ "yes",
      !is.na(suppressed) ~ NA_character_
    )) %>% 
    rename(group_size = freq, suppress = suppressed) %>% 
    relocate(sdcStatus, .after = suppress)
  
  return(df_aggregated_protectedFinal)
}

runtime <- system.time({
  final_table <- negative_threshold_function(df_ref, threshold = 5)
})
解决方案建议

1. 调整ProtectTable()参数解决收敛问题

独热编码后维度数量剧增(13个)导致计算量爆炸,当前参数设置过于严苛是无法收敛的核心原因:

  • 增大timeLimit:将timeLimit从0.1调整为60甚至300,给算法足够时间完成计算。
  • 关闭fastSolution:设置fastSolution = FALSE,牺牲部分速度换取更高的收敛概率。
  • 切换抑制算法:尝试method = "HITAS",该算法在高维度场景下比SIMPLEHEURISTIC_OLD更稳定。
  • 调整maxVars:适当增大maxVars(比如设为3或4),允许算法考虑更多变量组合的抑制策略,避免陷入局部最优。

调整后的核心代码片段:

df_aggregated_protected <- ProtectTable(df_ref,
                                        dimList = dimList,
                                        infoAsFrame = T,
                                        method = "HITAS",
                                        maxN = threshold,
                                        maxVars = 3,
                                        fastSolution = FALSE,
                                        save = FALSE,
                                        timeLimit = 60,
                                        verbose = TRUE)

2. 避免独热编码,直接处理多标签变量

独热编码会大幅增加维度数,转而直接处理多标签变量的组合更高效:

  • 生成标签组合变量:将每个原始多标签变量的取值转换为标签组合字符串(比如某观测同时属于Q1和Q2,FQuarter取值为"Q1+Q2"),保留原始的4个变量维度,而非拆分为13个二进制变量。
  • 构建合理层级:使用sdcHierarchies::hier_create()为每个组合变量创建层级结构(比如将单个标签作为底层,组合标签作为上层),帮助ProtectTable()利用层级减少计算复杂度。

示例代码(以FQuarter为例生成组合):

library(tidyr)
library(dplyr)

# 假设原始df_ref中FQuarter是多标签(用逗号分隔)
df_ref <- df_ref %>%
  mutate(FQuarter_comb = case_when(
    grepl("Q1", FQuarter) & grepl("Q2", FQuarter) ~ "Q1+Q2",
    grepl("Q1", FQuarter) & grepl("Q3", FQuarter) ~ "Q1+Q3",
    # 补充其他组合情况
    TRUE ~ FQuarter
  )) %>%
  select(-FQuarter)

3. 手动构建sdcProblem对象

如果上述方法仍不生效,可以手动构建问题对象,精准控制计算范围:

  • 使用sdcTable::makeProblem()函数,先定义所有需要聚合的维度和频数阈值。
  • 手动标记需要抑制的单元格,再调用sdcTable::protectTable()处理,减少不必要的计算开销。

内容的提问来源于stack exchange,提问作者stringdetector

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 12:06:03