我有一个数据
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
对于概率方法(如果数据相当大,则效果很好),您可以使用
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