如何移除随机样本使数据框中各国家Gender组比例匹配?
按国家匹配Gender样本量的实现方法
问题背景
现有一个包含国家和性别数据的dataframe,当前Gender与COUNTRY的交叉表如下:
> table(df$Gender , df$COUNTRY) 1 2 3 0 86 81 282 1 21 7 23
需要将每个国家内Gender=0的样本量缩减到与Gender=1的样本量一致,最终期望的交叉表为:
> table(df$Gender , df$COUNTRY) 1 2 3 0 21 7 23 1 21 7 23
一、手动实现方法
核心逻辑:按COUNTRY分组,对每个组内的Gender=0样本随机抽取与Gender=1相同的数量,再合并两类样本。
方法1:用tidyverse工具链实现
# 设置随机种子保证结果可重复 set.seed(123) library(dplyr) balanced_df <- df %>% group_by(COUNTRY) %>% group_modify(function(.x, .y) { # 获取当前组内Gender=1的样本量 n_gender1 <- sum(.x$Gender == 1) # 筛选Gender=1的样本 gender1 <- .x %>% filter(Gender == 1) # 从Gender=0的样本中随机抽取n_gender1条 gender0_sample <- .x %>% filter(Gender == 0) %>% sample_n(n_gender1) # 合并两类样本 bind_rows(gender1, gender0_sample) }) %>% ungroup() # 验证结果 table(balanced_df$Gender, balanced_df$COUNTRY)
方法2:用基础R实现
set.seed(123) balanced_list <- list() countries <- unique(df$COUNTRY) for (cntry in countries) { # 筛选当前国家的数据 cntry_data <- df[df$COUNTRY == cntry, ] # 计算Gender=1的样本数量 n1 <- sum(cntry_data$Gender == 1) # 提取Gender=1的样本 g1 <- cntry_data[cntry_data$Gender == 1, ] # 随机抽取对应数量的Gender=0样本 g0_idx <- sample(which(cntry_data$Gender == 0), n1) g0 <- cntry_data[g0_idx, ] # 合并后存入列表 balanced_list[[as.character(cntry)]] <- rbind(g1, g0) } # 合并所有组的结果 balanced_df <- do.call(rbind, balanced_list) rownames(balanced_df) <- NULL # 验证结果 table(balanced_df$Gender, balanced_df$COUNTRY)
二、使用R包实现
可以用caret包的downSample函数快速完成下采样(缩减多数类样本量到少数类水平),无需手动写循环。
步骤:
- 安装并加载包
install.packages("caret") library(caret) library(dplyr)
- 分组应用下采样
set.seed(123) balanced_df <- df %>% group_by(COUNTRY) %>% group_modify(function(.x, .y) { # 将Gender转为因子(downSample要求响应变量为因子) .x$Gender <- as.factor(.x$Gender) # 执行下采样,自动将多数类(Gender=0)缩减到少数类(Gender=1)的数量 downsampled <- downSample(x = .x[, !names(.x) %in% "Gender"], y = .x$Gender) # 还原Gender为数值型(按需选择) downsampled$Class <- as.numeric(as.character(downsampled$Class)) # 重命名列名回原名称 colnames(downsampled)[colnames(downsampled) == "Class"] <- "Gender" downsampled }) %>% ungroup() # 验证结果 table(balanced_df$Gender, balanced_df$COUNTRY)
数据集dput
df <- structure(list(Gender = c(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0), COUNTRY = c(2, 3, 2, 1, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 2, 3, 3, 1, 3, 3, 3, 3, 1, 2, 3, 2, 3, 1, 3, 2, 3, 3, 3, 2, 2, 3, 3, 3, 2, 3, 2, 2, 1, 3, 3, 3, 2, 2, 3, 1, 1, 2, 2, 1, 3, 3, 1, 2, 1, 3, 3, 3, 1, 1, 3, 3, 3, 1, 3, 2, 1, 3, 2, 3, 3, 2, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 1, 1, 1, 1, 3, 1, 2, 1, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 1, 2, 3, 3, 3, 1, 1, 3, 1, 1, 2, 2, 3, 3, 1, 2, 3, 3, 3, 2, 3, 3, 1, 3, 3, 1, 3, 1, 1, 3, 3, 2, 3, 1, 1, 1, 3, 3, 3, 2, 3, 3, 2, 3, 2, 1, 3, 2, 3, 1, 3, 2, 2, 2, 3, 3, 2, 1, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 2, 2, 1, 1, 3, 1, 1, 1, 3, 3, 1, 2, 1, 1, 1, 1, 3, 3, 3, 1, 3, 3, 2, 3, 3, 3, 3, 3, 1, 3, 3, 2, 1, 1, 2, 3, 2, 3, 3, 3, 2, 2, 3, 3, 3, 3, 1, 3, 2, 2, 1, 3, 2, 1, 3, 2, 3, 2, 3, 3, 2, 3, 2, 3, 3, 3, 1, 3, 2, 1, 1, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 1, 2, 3, 1, 2, 3, 2, 1, 2, 1, 3, 1, 3, 3, 3, 3, 3, 1, 3, 1, 1, 3, 1, 3, 1, 1, 3, 3, 1, 3, 1, 1, 1, 2, 3, 2, 2, 3, 3, 3, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 1, 3, 3, 3, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3, 1, 2, 3, 1, 3, 3, 3, 1, 3, 1, 3, 3, 3, 1, 1, 3, 2, 3, 1, 3, 3, 3, 1, 2, 3, 3, 3, 3, 1, 3, 1, 3, 1, 1, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 1, 1, 3, 3, 2, 3, 3, 3, 3, 1, 3, 3, 2, 3, 3, 1, 3, 3, 3, 2, 3, 1, 3, 3, 1, 3, 2, 1, 2, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3, 2, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 2, 1, 3, 3, 3, 3, 3, 3, 1, 3, 1, 2, 3, 3, 2, 3, 3, 3, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 1,
相关产品推荐
相关产品推荐

