Выборка определенного возрастного распределения из набора данных
Предположим, у меня есть набор данных с 1000 000 наблюдений. Переменные: возраст, раса, пол. Этот набор данных представляет весь США.
Как я могу взять выборку из 1000 человек из этого набора данных, учитывая определенное возрастное распределение? Например, я хочу, чтобы этот набор данных с 1000 человек был распределен следующим образом:
0,3 * Возраст 0 - 30
0,3 * Возраст 31 - 50
0,2 * Возраст 51 - 69
0,2 * Возраст 70 - 100
Есть ли быстрый способ сделать это? Я уже создал выборку из 1000 человек с желаемым распределением по возрасту, но как мне теперь объединить это с моим исходным набором данных?
Как пример, вот как я создал распределение населения штата Мэн:
set.seed(123)
library(magrittr)
popMaine <- data.frame(min=c(0, 19, 26, 35, 55, 65), max=c(18, 25, 34, 54, 64, 113), prop=c(0.2, 0.07, 0.11, 0.29, 0.14, 0.21))
Mainesample <- sample(nrow(popMaine), 1000, replace=TRUE, prob=popMaine$prop)
Maine <- round(popMaine$min[Mainesample] + runif(1000) * (popMaine$max[Mainesample] - popMaine$min[Mainesample])) %>% data.frame()
names(Texas) <- c("Age")
Теперь я не знаю, как объединить это с моим другим набором данных, который имеет все население США... Я был бы признателен за любую помощь, я застрял на некоторое время...
1 ответ
Ниже приведены четыре разных подхода. Две функции использования от, соответственно, splitstackshape
а также sampling
пакеты, один использует базу mapply
и один использует map2
от purrr
пакет (который является частью tidyverse
коллекция пакетов).
Сначала давайте настроим некоторые поддельные данные и параметры выборки:
# Fake data
set.seed(156)
df = data.frame(age=sample(0:100, 1e6, replace=TRUE))
# Add a grouping variable for age range
df = df$age.groups = cut(df$age, c(0,30,51,70,Inf), right=FALSE)
# Total number of people sampled
n = 1000
# Named vector of sample proportions by group
probs = setNames(c(0.3, 0.3, 0.2, 0.2), levels(df$age.groups))
Используя приведенные выше параметры выборки, мы хотим n
итоговые значения с долей probs
из каждой возрастной группы.
Опция 1: mapply
mapply
может применить несколько аргументов к функции. Здесь аргументы (1) фрейм данных df
разделить на четыре возрастные группы, и (2) probs*n
, который дает количество строк, которые мы хотим от каждой возрастной группы:
df.sample = mapply(a=split(df, df$age.groups), b=probs*n,
function(a,b) {
a[sample(1:nrow(a), b), ]
}, SIMPLIFY=FALSE)
mapply
возвращает список с четырьмя фреймами данных, по одному для каждой страты. Объедините этот список в один фрейм данных:
df.sample = do.call(rbind, df.sample)
Проверьте выборку:
table(df.sample$age.groups)
[0,30) [30,51) [51,70) [70,Inf) 300 300 200 200
Вариант 2: stratified
функция от splitstackshape
пакет
size
Аргумент требует именованный вектор с количеством выборок из каждой страты.
library(splitstackshape)
df.sample2 = stratified(df, "age.groups", size=probs*n)
Вариант 3: strata
функция от sampling
пакет
Этот вариант, безусловно, самый медленный.
library(sampling)
# Data frame must be sorted by stratification column(s)
df = df[order(df$age.groups),]
sampled.rows = strata(df, 'age.groups', size=probs*n, method="srswor")
df.sample3 = df[sampled.rows$ID_unit, ]
Вариант 4: tidyverse
пакеты
map2
как mapply
в том, что он применяет два аргумента параллельно к функции, в этом случае dplyr
пакет-х sample_n
функция. map2
возвращает список из четырех фреймов данных, по одному для каждой страты, которые мы объединяем в один фрейм данных с bind_rows
,
library(dplyr)
library(purrr)
df.sample4 = map2(split(df, df$age.groups), probs*n, sample_n) %>% bind_rows
Задержки
library(microbenchmark)
Unit: milliseconds expr min lq mean median uq max neval cld mapply 86.77215 110.82979 156.66855 123.95275 145.25115 486.2078 10 a strata 5028.42933 5541.40442 5709.16796 5699.50711 5845.69921 6467.7250 10 b stratified 38.33495 41.76831 89.93954 45.43525 79.18461 408.2346 10 a tidyverse 71.48638 135.49113 143.12011 142.86866 155.72665 192.4174 10 a