Выборка определенного возрастного распределения из набора данных

Предположим, у меня есть набор данных с 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
Другие вопросы по тегам