基于后关节概率的采样数据

时间:2018-01-24 13:47:22

标签: python r random statistics probability

我有一个数据集,想根据我手动设置的概率获取样本。

示例:(id = user,score(按desc排序),b1-b6(虚拟变量)), 1表示用户具有此功能,否则为0 < / p>

id score b1 b2 b3 b4 b5 b6

1 0.99 1 0 0 0 1 0

2 0.98 1 0 0 0 0 0

3 0.97 1 1 1 0 1 1

4 0.96 0 1 0 0 0 0

给出一个参数集( p1,p2,p3,p4,p5,p6 ),用于控制列中具有此功能的用户的比例(b1,b2,b3,b4,b5, b6)分别

让我们看看我设置p1 = 0.1,p2 = 0.2,p3 = 0.9,p4 = 0.32,p5 = 0.2,p6 = 0.21 并且期望从数据集中采样,其分布大致遵循p1-p6值。

大约10%的用户在b1中有1个,20%的用户在b2中有1个,依此类推)

问题是原始数据集的分布是否跨越b1到b6,以及如何分配 从中获取样本,其分布符合p1-p6值

任何想法都将不胜感激

更新 这是从大型数据集(1000k的1k样本)中绘制样本,该样本遵循分布(p1,p2等),而不是模拟虚假数据

方法1 :可以通过重复随机样本来解决。并使用最接近的一个(需要重新采样或迭代技巧)。

方法2 :使用线性优化算法(可能很复杂,因为2 ^ 6种可能性,需要求解大方程)

1 个答案:

答案 0 :(得分:0)

亨利,正如评论中所建议的那样,有两种生成这类数据的通用方法。一种是计算“每个单元格将为0或1”的概率,另一种是“向量的随机抽样,以便选择n%”。两者完全不同(至少在不大规模上)。

示范。基本概率/比例:

probs <- c(0.1, 0.2, 0.9, 0.32, 0.2, 0.21)
names(probs) <- paste0('b', seq_along(probs))

set.seed(2)
n <- 1e5
dat <- cbind.data.frame(sapply(probs, function(p) {
  sample(0:1, size=n, replace=TRUE, prob=c(1-p, p))
}))
head(dat)
#   b1 b2 b3 b4 b5 b6
# 1  0  0  1  1  0  1
# 2  0  0  0  1  1  0
# 3  0  0  1  1  0  0
# 4  0  0  1  0  0  0
# 5  1  0  1  0  0  0
# 6  1  0  1  0  1  0
colSums(dat)/n
#      b1      b2      b3      b4      b5      b6 
# 0.10125 0.20100 0.89975 0.32013 0.20182 0.20827 

这看起来是正确的,比例非常接近。现在让我们来看一个较小的人口:

set.seed(2)
n <- 10
dat <- cbind.data.frame(sapply(probs, function(p) {
  sample(0:1, size=n, replace=TRUE, prob=c(1-p, p))
}))
dat
#    b1 b2 b3 b4 b5 b6
# 1   0  0  1  0  1  0
# 2   0  0  1  0  0  0
# 3   0  0  1  1  0  0
# 4   0  0  1  1  0  1
# 5   1  0  1  0  1  0
# 6   1  1  1  0  0  1
# 7   0  1  1  1  1  0
# 8   0  0  1  0  0  1
# 9   0  0  0  0  0  0
# 10  0  0  1  0  1  0
colSums(dat)/n
#  b1  b2  b3  b4  b5  b6 
# 0.2 0.2 0.9 0.3 0.4 0.3 

即使在四舍五入的情况下,某些列甚至都没有“接近”。这就是问题。为此,我们对随机性的“观点”实际上是“一次一个单元格”,而不是“一次一列”。

好的,让我们一次尝试一列。

set.seed(2)
n <- 10
dat <- cbind.data.frame(sapply(probs, function(p) {
  i <- sample(n, size=n*p)
  vec <- integer(n)
  vec[i] <- 1
  vec
}))
dat
#    b1 b2 b3 b4 b5 b6
# 1   0  0  1  0  0  0
# 2   1  0  1  1  0  0
# 3   0  0  1  0  0  1
# 4   0  0  0  1  0  0
# 5   0  0  1  0  0  1
# 6   0  1  1  0  0  0
# 7   0  0  1  0  0  0
# 8   0  1  1  1  0  0
# 9   0  0  1  0  1  0
# 10  0  0  1  0  1  0
colSums(dat)/n
#  b1  b2  b3  b4  b5  b6 
# 0.1 0.2 0.9 0.3 0.2 0.2 

在四舍五入中,这看起来更接近。 (您可以选择使用size=ceiling(n*p)size=max(1,n*p)来处理低概率,否则会被截断,而不是舍入。)请注意,如果人口较多,它的行为仍然与上面的实现一样好。< / p>

幸运的是,它们的表现大致相同,所以你可以选择符合你的抽样要求。

library(microbenchmark)
n <- 10
microbenchmark(
  probability = cbind.data.frame(sapply(probs, function(p) { sample(0:1, size=n, replace=TRUE, prob=c(1-p, p)) })),
  proportion = cbind.data.frame(sapply(probs, function(p) { i <- sample(n, size=n*p); vec <- integer(n); vec[i] <- 1; vec; }))
)
# Unit: microseconds
#         expr     min       lq     mean   median       uq     max neval
#  probability  99.191 104.6620 126.0461 114.5075 139.4880 384.001   100
#   proportion 106.485 113.2315 131.9465 122.7135 149.1515 213.334   100
n <- 1e5
...
# Unit: milliseconds
#         expr      min       lq     mean   median       uq      max neval
#  probability 254.9634 298.0875 349.3892 331.2826 364.0245 680.3098   100
#   proportion 281.7271 351.9515 418.4833 386.5976 449.6032 931.0893   100