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

R语言基于性别、年龄两类人口变量重采样使样本匹配总体分布

R多阶段抽样样本匹配人口学分布实现方案

需求说明

多阶段抽样得到的数据集存在抽样偏差,需要调整数据使其匹配性别、年龄两个因子类型人口学变量的总体分布,要求每个年龄组内部男女性别占比为50%/50%。
样本原始分布如下图:
sampling

示例数据集

x<-structure(list(age_cat = c("25-29", "30-34", "25-29", "20-24", 
                              "25-29", "20-24", "35-39", "30-34", "25-29", "30-34", "25-29", 
                              "30-34", "35-39", "45-49", "40-45", "20-24", "20-24", "25-29", 
                              "35-39", "35-39", "25-29", "20-24", "30-34", "30-34", "40-45", 
                              "25-29", "25-29", "25-29", "20-24", "40-45", "20-24", "40-45", 
                              "30-34", "25-29", "45-49", "30-34", "45-49", "40-45", "25-29", 
                              "35-39", "40-45", "25-29", "45-49", "35-39", "45-49", "40-45", 
                              "20-24", "45-49", "40-45", "25-29", "35-39", "30-34", "30-34", 
                              "25-29", "20-24", "20-24", "40-45", "35-39", "25-29", "25-29", 
                              "20-24", "40-45", "20-24", "20-24", "45-49", "20-24", "35-39", 
                              "20-24", "35-39", "45-49", "15-19", "45-49", "35-39", "35-39", 
                              "30-34", "35-39", "45-49", "35-39", "30-34", "20-24", "35-39", 
                              "40-45", "40-45", "40-45", "30-34", "45-49", "20-24", "30-34", 
                              "45-49", "35-39", "20-24", "20-24", "20-24", "45-49", "20-24", 
                              "45-49", "35-39", "25-29", "40-45", "40-45", "25-29", "35-39", 
                              "45-49", "30-34", "45-49", "45-49", "45-49", "15-19", "30-34", 
                              "45-49", "30-34", "30-34", "35-39", "25-29", "40-45", "15-19", 
                              "20-24", "20-24", "40-45", "40-45", "45-49", "45-49", "35-39", 
                              "40-45", "30-34", "35-39", "35-39", "25-29", "25-29", "20-24", 
                              "20-24", "40-45", "20-24", "35-39", "20-24", "20-24", "30-34", 
                              "25-29", "45-49", "25-29", "35-39", "20-24", "35-39", "35-39", 
                              "35-39", "40-45", "35-39", "35-39", "20-24", "30-34", "25-29", 
                              "15-19", "30-34", "35-39", "15-19", "20-24", "20-24", "35-39", 
                              "25-29", "25-29", "25-29", "25-29", "30-34", "40-45", "35-39", 
                              "30-34", "35-39", "40-45", "25-29", "30-34", "25-29", "25-29", 
                              "45-49", "30-34", "30-34", "25-29", "15-19", "25-29", "20-24", 
                              "15-19", "20-24", "30-34", "20-24", "40-45", "25-29", "25-29", 
                              "30-34", "30-34", "25-29", "20-24", "40-45", "45-49", "25-29", 
                              "25-29", "40-45", "35-39", "25-29", "45-49", "35-39", "30-34", 
                              "45-49", "30-34", "30-34", "45-49", "35-39", "20-24", "45-49", 
                              "30-34", "25-29", "45-49", "45-49", "40-45", "25-29", "20-24", 
                              "40-45", "30-34", "35-39", "30-34", "20-24", "35-39", "20-24", 
                              "30-34", "20-24", "35-39", "35-39", "30-34", "45-49", "40-45", 
                              "45-49", "25-29", "35-39", "40-45", "30-34", "35-39", "30-34", 
                              "35-39", "20-24", "25-29", "35-39", "30-34", "30-34", "25-29", 
                              "45-49", "45-49", "40-45", "40-45", "35-39", "30-34", "25-29", 
                              "35-39", "20-24", "40-45", "20-24", "30-34", "40-45", "20-24", 
                              "45-49", "20-24", "40-45", "25-29", "40-45", "25-29", "45-49", 
                              "30-34", "30-34", "45-49", "40-45", "30-34", "30-34", "20-24", 
                              "20-24", "35-39", "30-34", "15-19", "35-39", "25-29", "45-49", 
                              "30-34", "25-29", "35-39", "15-19", "40-45", "45-49", "15-19", 
                              "35-39", "45-49", "45-49", "25-29"), sex_cat = structure(c(1L, 
                                                                                         2L, 1L, 2L, 1L, 1L, 1L, 2L, 2L, 1L, 1L, 2L, 1L, 2L, 1L, 1L, 1L, 
                                                                                         1L, 1L, 1L, 2L, 1L, 1L, 1L, 2L, 2L, 2L, 1L, 2L, 2L, 1L, 2L, 2L, 
                                                                                         2L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 1L, 1L, 2L, 2L, 1L, 1L, 2L, 2L, 
                                                                                         2L, 1L, 2L, 1L, 1L, 2L, 2L, 1L, 2L, 2L, 1L, 1L, 1L, 1L, 2L, 1L, 
                                                                                         1L, 2L, 1L, 2L, 2L, 1L, 2L, 1L, 1L, 1L, 2L, 2L, 1L, 1L, 2L, 1L, 
                                                                                         1L, 2L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 1L, 2L, 1L, 2L, 1L, 1L, 
                                                                                         1L, 1L, 1L, 2L, 1L, 1L, 2L, 1L, 1L, 2L, 1L, 2L, 1L, 1L, 1L, 1L, 
                                                                                         1L, 1L, 2L, 2L, 2L, 1L, 1L, 1L, 2L, 1L, 1L, 1L, 1L, 2L, 2L, 1L, 
                                                                                         1L, 1L, 1L, 2L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 2L, 2L, 1L, 
                                                                                         1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L, 2L, 2L, 1L, 2L, 1L, 2L, 1L, 1L, 
                                                                                         2L, 2L, 1L, 2L, 1L, 1L, 1L, 1L, 2L, 2L, 1L, 1L, 1L, 2L, 1L, 2L, 
                                                                                         1L, 1L, 2L, 1L, 2L, 2L, 2L, 1L, 2L, 2L, 2L, 1L, 2L, 1L, 2L, 1L, 
                                                                                         1L, 2L, 1L, 2L, 1L, 1L, 1L, 1L, 2L, 2L, 1L, 2L, 1L, 1L, 2L, 1L, 
                                                                                         2L, 1L, 1L, 1L, 2L, 2L, 1L, 1L, 1L, 2L, 1L, 2L, 2L, 1L, 1L, 2L, 
                                                                                         1L, 2L, 1L, 2L, 2L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 
                                                                                         1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 1L, 1L, 2L, 1L, 2L, 2L, 1L, 2L, 
                                                                                         1L, 1L, 1L, 1L, 1L, 2L, 1L, 2L, 2L, 2L, 1L, 1L, 2L, 1L, 2L, 1L, 
                                                                                         2L, 1L, 1L, 2L, 1L, 1L, 2L, 2L, 2L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = c("M", 
                                                                                                                                                                 "F"), class = "factor")), row.names = c(NA, -288L), class = c("tbl_df", 
                                                                                                                                                                                                                               "tbl", "data.frame"))

实现方法

不需要手动编写循环,两种成熟方案可直接满足需求:

方案1:后分层加权(保留全部原始样本)

适合不需要调整样本量,仅通过权重校正分布的场景:

library(survey)
library(dplyr)

# 构造目标分布:每个年龄组男女占比各50%
age_total <- x %>% count(age_cat, name = "total")
pop_dist <- expand.grid(age_cat = unique(x$age_cat), sex_cat = c("M", "F")) %>%
  left_join(age_total, by = "age_cat") %>%
  mutate(Freq = total / 2) %>%
  select(age_cat, sex_cat, Freq)

# 定义调查设计并执行后分层加权
base_des <- svydesign(id = ~1, data = x, weights = ~1)
post_des <- postStratify(base_des, strata = ~age_cat + sex_cat, population = pop_dist)

# 提取带权重的结果数据集
weighted_data <- post_des$variables %>% mutate(weight = weights(post_des))

后续分析直接使用weight列作为样本权重即可,加权后每个年龄组的性别占比完全符合50%/50%的要求。

方案2:分层重抽样(调整样本量得到完全匹配的数据集)

如果需要得到实际样本分布匹配目标要求的数据集,直接按组抽样即可:

library(dplyr)

adjusted_data <- x %>%
  # 按年龄分组,确定每组可抽取的男女最大等量子样量
  group_by(age_cat) %>%
  mutate(sample_n = min(table(sex_cat))) %>%
  # 按年龄+性别分组抽样
  group_by(age_cat, sex_cat) %>%
  slice_sample(n = first(sample_n)) %>%
  ungroup() %>%
  select(-sample_n)

执行后可通过adjusted_data %>% count(age_cat, sex_cat)验证结果,每个年龄组的男女样本量完全相等。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 03:06:03