ggplot中的概率热图

时间:2013-01-16 16:37:48

标签: r ggplot2 probability

一年前我问this question并获得了此“概率热图”的代码: heatmap

numbet <- 32
numtri <- 1e5
prob=5/6
#Fill a matrix 
xcum <- matrix(NA, nrow=numtri, ncol=numbet+1)
for (i in 1:numtri) {
x <- sample(c(0,1), numbet, prob=c(prob, 1-prob), replace = TRUE)
xcum[i, ] <- c(i, cumsum(x)/cumsum(1:numbet))
}
colnames(xcum) <- c("trial", paste("bet", 1:numbet, sep=""))

mxcum <- reshape(data.frame(xcum), varying=1+1:numbet, 
idvar="trial", v.names="outcome", direction="long", timevar="bet")


library(plyr)
mxcum2 <- ddply(mxcum, .(bet, outcome), nrow)
mxcum3 <- ddply(mxcum2, .(bet), summarize, 
            ymin=c(0, head(seq_along(V1)/length(V1), -1)), 
            ymax=seq_along(V1)/length(V1),
            fill=(V1/sum(V1)))
head(mxcum3)

library(ggplot2)

p <- ggplot(mxcum3, aes(xmin=bet-0.5, xmax=bet+0.5, ymin=ymin, ymax=ymax)) + 
geom_rect(aes(fill=fill), colour="grey80") + 
scale_fill_gradient("Outcome", formatter="percent", low="red", high="blue") +
scale_y_continuous(formatter="percent") +
xlab("Bet")

print(p)

(由于this

,可能需要稍微更改此代码

几乎正是我想要的。除了每个垂直轴应具有不同数量的箱,即第一个应具有2,第二,第三,第四(N + 1)。在曲线图中,轴6 + 7具有相同数量的箱(7),其中7应具有8(N + 1)。

如果我是对的,代码执行此操作的原因是因为它是观察到的数据,如果我运行更多试验,我们会获得更多的箱子。我不想依靠试验次数来获得正确数量的垃圾箱。

如何调整此代码以提供正确数量的垃圾箱?

1 个答案:

答案 0 :(得分:13)

我已使用R dbinom生成n=1:32试验的头部频率,并立即绘制图表。这将是你所期望的。我已在SO和math.stackexchange上阅读了您之前的一些帖子。我仍然不明白为什么你想要simulate实验,而不是从二项式R.V.产生。如果你能解释一下,那就太好了!我将尝试使用@Andrie的模拟解决方案来检查我是否可以匹配下面显示的输出。现在,这是你可能感兴趣的东西。

set.seed(42)
numbet <- 32
numtri <- 1e5
prob=5/6

require(plyr)
out <- ldply(1:numbet, function(idx) {
    outcome <- dbinom(idx:0, size=idx, prob=prob)
    bet     <- rep(idx, length(outcome))
    N       <- round(outcome * numtri)
    ymin    <- c(0, head(seq_along(N)/length(N), -1))
    ymax    <- seq_along(N)/length(N)
    data.frame(bet, fill=outcome, ymin, ymax)
})

require(ggplot2)
p <- ggplot(out, aes(xmin=bet-0.5, xmax=bet+0.5, ymin=ymin, ymax=ymax)) + 
geom_rect(aes(fill=fill), colour="grey80") + 
scale_fill_gradient("Outcome", low="red", high="blue") +
xlab("Bet")

The plot:

ggplot2

修改:解释Andrie中的旧代码如何工作以及为什么它不能提供您想要的内容。

基本上,Andrie所做的(或者更确切地说是一种方式)是使用这样的想法:如果你有两个二项分布,X ~ B(n, p)Y ~ B(m, p),其中n, m = sizep = probability of success,然后,他们的总和,X + Y = B(n + m, p)(1)。因此,xcum的目的是获得所有n = 1:32投掷的结果,但为了更好地解释它,让我逐步构建代码。除了解释之外,xcum的代码也将非常明显,并且可以立即构建(无需for-loop并且每次都构建cumsum

如果您到目前为止跟踪了我,那么我们的想法是首先创建一个numtri * numbet矩阵,每列(length = numtri)都有0's1's概率= 5/61/6。也就是说,如果您有numtri = 1000,则每个0's列(此处为= 32),您将拥有~834 1's和166 numbet *。让我们构建它并首先测试它。

numtri <- 1e3
numbet <- 32
set.seed(45)
xcum <- t(replicate(numtri, sample(0:1, numbet, prob=c(5/6,1/6), replace = TRUE)))

# check for count of 1's
> apply(xcum, 2, sum)
[1] 169 158 166 166 160 182 164 181 168 140 154 142 169 168 159 187 176 155 151 151 166 
163 164 176 162 160 177 157 163 166 146 170

# So, the count of 1's are "approximately" what we expect (around 166).

现在,这些列中的每一列都是n = 1size = numtri的二项分布样本。如果我们要添加前两列并用这个和替换第二列,那么,从(1)开始,由于概率相等,我们最终会得到一个带有n = 2的二项分布。类似地,相反,如果您已添加前三列并用此总和替换第三列,您将获得具有n = 3的二项分布,依此类推...... 这个概念是,如果您cumulatively添加每列,那么最终会得到numbet个二项分布(此处为1到32)。所以,让我们这样做。

xcum <- t(apply(xcum, 1, cumsum))

# you can verify that the second column has similar probabilities by this:
# calculate the frequency of all values in 2nd column.
> table(xcum[,2])
  0   1   2 
694 285  21 

> round(numtri * dbinom(2:0, 2, prob=5/6))
[1] 694 278  28
# more or less identical, good!

如果您划分xcum,我们就会以这种方式在每行上生成cumsum(1:numbet)

xcum <- xcum/matrix(rep(cumsum(1:numbet), each=numtri), ncol = numbet)

这将与xcum中出现的for-loop矩阵相同(如果使用相同的种子生成它)。但是我并不完全理解Andrie进行这种划分的原因,因为这不是生成所需图形所必需的。但是,我认为它与您谈到的frequency值有关in an earlier post on math.stackexchange

现在说明为什么你难以获得我附加的图表(使用n+1箱子):

对于n=1:32次试验的二项式分布,5/6作为尾部概率(失败),1/6作为头部概率(成功),k的概率负责人由:

nCk * (5/6)^(k-1) * (1/6)^k # where nCk is n choose k

对于我们为n=7n=8(试验)生成的测试数据,k=0:7k=0:8头的概率由下式给出:

# n=7
   0    1    2     3     4     5 
.278 .394 .233  .077  .016  .002 

# n=8
   0    1    2    3     4      5 
.229 .375 .254 .111  .025   .006 

为什么他们都有6个箱子而不是8个箱子和9个箱子?当然这与numtri=1000的价值有关。让我们通过使用dbinom直接从二项分布生成概率来了解这8个和9个分箱中的每个分箱的概率是什么,以了解为什么会发生这种情况。

# n = 7
dbinom(7:0, 7, prob=5/6)
# output rounded to 3 decimal places
[1] 0.279 0.391 0.234 0.078 0.016 0.002 0.000 0.000

# n = 8
dbinom(8:0, 8, prob=5/6)
# output rounded to 3 decimal places
[1] 0.233 0.372 0.260 0.104 0.026 0.004 0.000 0.000 0.000

您会看到与k=6,7k=6,7,8对应的n=7n=8对应的概率为〜0。它们的价值非常低。这里的最小值实际为5.8 * 1e-7n=8k=8)。这意味着如果您模拟1/5.8 * 1e7次,则有可能获得1个值。如果您对n=32 and k=32选中相同内容,则值为1.256493 * 1e-25。因此,您必须模拟许多值才能获得至少1个结果,其中所有32结果都是n=32的结果。

这就是为什么你的结果没有某些二进制值的原因,因为对于给定的numtri,它的概率非常低。出于同样的原因,直接从二项分布中生成概率克服了这个问题/限制。

我希望我已经设法写得足够清晰,你可以关注。如果您遇到麻烦,请告诉我。

编辑2: 当我使用numtri=1e6模拟上面编辑过的代码时,我得到n=7n=8的代码并计算k=0:7和{{1}的头数}:

k=0:8

注意,对于n = 7和n = 8,现在有k = 6和k = 7。此外,对于n = 8,k = 8时的值为1。随着# n = 7 0 1 2 3 4 5 6 7 279347 391386 233771 77698 15763 1915 117 3 # n = 8 0 1 2 3 4 5 6 7 8 232835 372466 259856 104116 26041 4271 392 22 1 的增加,您将获得更多其他丢失的垃圾箱。但它需要大量的时间/内存(如果有的话)。