从每个层中采样一行以模拟 r 中变量的分布

问题描述 投票:0回答:1

我有一个数据

da
,它具有一些
date
频率分布(见下文)。我还有另外一个数据
db
,其中每个id可能有一条或多条记录。有没有一种可行的方法,让每组都得到一条记录(不多也不少),使得
db
中日期的采样分布尽可能接近
da
中的日期分布?

library(data.table)
library(dplyr)
library(lubridate)

# da is the data to be emulated
da = data.table(id = paste0('a', 1:7),
                date = ymd(c('2021-1-10', 
                             rep('2021-1-11', 2), 
                             rep('2021-1-12', 3), 
                             '2021-1-13')))

da
da[,.N,(date)][,.(date, N, perc = N/sum(N))]
#          date N      perc
# 1: 2021-01-10 1 0.1428571
# 2: 2021-01-11 2 0.2857143
# 3: 2021-01-12 3 0.4285714
# 4: 2021-01-13 1 0.1428571


# need to get only one (no more and no less) sample for each id 
# to emulate the distribution of date in da
set.seed(123)
db = structure(list(id = c(1L, 2L, 3L, 3L, 3L, 4L, 5L, 6L, 6L, 8L), 
               date = structure(c(18638, 18639, 18639, 18640, 18640, 18637, 
                                  18640, 18637, 18638, 18639), class = "Date")), 
          class = c("data.table", "data.frame"))

> db
    id       date
 1:  1 2021-01-11
 2:  2 2021-01-12
 3:  3 2021-01-12
 4:  3 2021-01-13
 5:  3 2021-01-13
 6:  4 2021-01-10
 7:  5 2021-01-13
 8:  6 2021-01-10
 9:  6 2021-01-11
10:  8 2021-01-12
r sampling
1个回答
0
投票

对于概率方法(如果数据相当大,则效果很好),您可以使用

sampling
包中的strata函数。

这是要模拟的分布,我们将其保存到 R 对象中。

da.N <- da[,.N,(date)][,.(date, N, perc = N/sum(N))]; da.N

date     N      perc
<Date> <int>     <num>
1: 2021-01-10     1 0.1428571
2: 2021-01-11     2 0.2857143
3: 2021-01-12     3 0.4285714
4: 2021-01-13     1 0.1428571

合并

date
上的两个表,以便百分比列位于我们想要从中采样的数据中。

db <- da.N[db, on='date']

然后对db进行系统的不等概率抽样。这将从每个

id
(层)中随机选择一行(大小=1),包含概率(“pik”)由da(第
perc
列)中的日期分布给出。

library(sampling)
set.seed(12)  # for reproducibility (omit in reality)

s <- strata(db, 
            stratanames="id", 
            size=rep(1, length(unique(db$id))), 
            pik=db$perc,  # must be db$perc
            method="systematic")

获取数据并检查日期的频率分布。

db2 <- getdata(db, s)
setDT(db2)[,.N,(date)][,.(date, N, perc = N/sum(N))]

date     N      perc
<Date> <int>     <num>
1: 2021-01-10     2 0.2857143
2: 2021-01-11     1 0.1428571
3: 2021-01-12     2 0.2857143
4: 2021-01-13     2 0.2857143

很难说它是否适用于如此小的样本。让我们尝试一下更大的数据集。

set.seed(123)
db <- data.table(id = sample(1:400, 10000, TRUE),
                date = ymd(rep('2021-1-10', 100),
                           rep('2021-1-11', 100),
                           rep('2021-1-12', 100),
                           rep('2021-1-13', 100)))
db <- da.N[db, on='date']

set.seed(123)
s <- strata(db, 
            stratanames="id", 
            size=rep(1, length(unique(db$id))), 
            pik=db$perc,
            method="systematic")

db2 <- getdata(db, s)
setDT(db2)[,.N,(date)][,.(date, N, perc = N/sum(N))][order(date)]

         date     N   perc
       <Date> <int>  <num>
1: 2021-01-10    71 0.1775  # 0.1428571
2: 2021-01-11   109 0.2725  # 0.2857143
3: 2021-01-12   166 0.4150  # 0.4285714
4: 2021-01-13    54 0.1350  # 0.1428571

这非常接近所需的分布(# 后面的数字),并且每个日期我们应该只有一个 id。

db2[, .N, (id)]
        id     N
     <int> <int>
  1:   179     1
  2:    14     1
  3:   195     1
  4:   306     1
  5:   118     1
 ---            
396:   233     1
397:   192     1
398:    15     1
399:    62     1
400:    97     1
© www.soinside.com 2019 - 2024. All rights reserved.