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

如何用R从10列data frame中抽取500样本,最大化多列多样性?

问题描述

我有一个包含10966行、10列的data frame,希望使用R从中抽取约500个样本,以最大化各列唯一值的多样性。对该数据集运行data %>% summarise_all(n_distinct)后,得到各列唯一值数量如下:

IDABCDEFIJKL
109662055691329167133612433

注:ID列所有行均为唯一ID。由于无法捕获所有列的全部多样性(部分列的唯一值数量超过500),请问是否存在可最大化样本多样性的方法?


可行解决方案

1. 优先覆盖低基数列全值,再补充高基数列抽样

先把J、K、L、D、I这类唯一值远少于500的列的所有取值组合对应的行保留,确保这些列的多样性完全覆盖,再从剩余行里针对A、F这类高基数列抽样,补满500个样本:

library(dplyr)

# 定义低基数列(唯一值数量≤500的列)
low_card_cols <- c("J", "K", "L", "D", "I", "B", "E", "C")
# 提取这些列所有唯一组合对应的行(去重,保留每个组合至少一行)
base_sample <- data %>% 
  distinct(across(all_of(low_card_cols)), .keep_all = TRUE)

# 计算还需要补充的样本量
needed <- 500 - nrow(base_sample)

# 从剩余行中优先保留A、F的唯一组合,再抽样
remaining_rows <- data %>% 
  anti_join(base_sample, by = low_card_cols) %>%
  distinct(A, F, .keep_all = TRUE)

# 合并基础样本和补充样本
final_sample <- bind_rows(
  base_sample,
  slice_sample(remaining_rows, n = min(needed, nrow(remaining_rows)))
)

# 如果仍未达到500,从全数据集未选中的行里随机补充
if(nrow(final_sample) < 500) {
  final_sample <- bind_rows(
    final_sample,
    data %>% 
      anti_join(final_sample, by = "ID") %>%
      slice_sample(n = 500 - nrow(final_sample))
  )
}

2. 贪心算法精准最大化唯一值覆盖

每次选择能新增最多未覆盖列唯一值的行,直到样本量达到500。这种方法对多样性的提升更精准,但计算量略大:

library(dplyr)

# 初始化各列已覆盖的唯一值列表(排除ID列)
covered <- lapply(data[-1], function(x) character(0))
sample_ids <- c()

while(length(sample_ids) < 500) {
  # 给未选中的行打分:计算该行能新增的未覆盖唯一值数量
  row_scores <- data %>%
    filter(!ID %in% sample_ids) %>%
    rowwise() %>%
    mutate(
      score = sum(
        !A %in% covered$A, !B %in% covered$B, !C %in% covered$C,
        !D %in% covered$D, !E %in% covered$E, !F %in% covered$F,
        !I %in% covered$I, !J %in% covered$J, !K %in% covered$K, !L %in% covered$L
      )
    ) %>%
    ungroup() %>%
    arrange(desc(score))
  
  # 选中得分最高的行
  top_row <- row_scores %>% slice(1)
  sample_ids <- c(sample_ids, top_row$ID)
  
  # 更新已覆盖的唯一值集合
  covered$A <- unique(c(covered$A, top_row$A))
  covered$B <- unique(c(covered$B, top_row$B))
  covered$C <- unique(c(covered$C, top_row$C))
  covered$D <- unique(c(covered$D, top_row$D))
  covered$E <- unique(c(covered$E, top_row$E))
  covered$F <- unique(c(covered$F, top_row$F))
  covered$I <- unique(c(covered$I, top_row$I))
  covered$J <- unique(c(covered$J, top_row$J))
  covered$K <- unique(c(covered$K, top_row$K))
  covered$L <- unique(c(covered$L, top_row$L))
}

final_sample <- data %>% filter(ID %in% sample_ids)

3. 用专业抽样包实现分层平衡抽样

借助caret包的分层抽样功能,以低基数列的组合作为分层依据,尽量覆盖所有分层后调整样本量到500:

library(caret)

# 用低基数列的组合生成分层标识
data$strata <- interaction(data[, low_card_cols])
# 按分层抽样,比例对应500/总样本量
sample_indices <- createDataPartition(data$strata, p = 500/nrow(data), list = FALSE)
final_sample <- data[sample_indices, ]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 15:03:32