Using the following notation:
$s_i$: the number of samples for the $i^{th}$ round
$k_i$: the number of words sampled in the $i^{th}$ round that had not been previously sampled
$m_i=\sum_{j=1}^ik_j$
$\pi_1(n)$: the prior distribution of $n$
We'll also assume $n\geq{s}$; otherwise we can determine $n$ after the first round of sampling. We can update $\pi(n)$ beginning with the second round of sampling:
$$\pi_i(n)\propto\frac{\binom{m_{i-1}}{s_i-k_i}\binom{n-m_{i-1}}{k_i}}{\binom{n}{s_i}}\pi_{i-1}(n)$$
$$\propto\pi_1(n)\prod_{j=2}^i\frac{(n-m_{j-1})!(n-s_j)!}{n!(n-m_{j-1}-k_j)!}$$
Implemented as an R function:
pn <- function(s, k, prior) {
l <- length(s)
m <- cumsum(k[-l])
s <- s[-1]
k <- k[-1]
function(n) pmax(prior(n)*exp(colSums(lgamma(outer(1 - m, n, "+")) + lgamma(outer(1 - s, n, "+")) - lgamma(outer(1 - m - k, n, "+"))) - (l - 1)*lgamma(n + 1)), 0, na.rm = TRUE)
}
For example, say $\pi_1(n)\sim{U(8,30)}$, $k=5,3,1$, and $s=5,5,5$.
k <- c(5, 3, 1)
s <- rep(5, 3)
post <- pn(s, k, function(n) 1)
like <- post(8:30)
plot(8:30, like/sum(like), xlab = "n", ylab = "p(n)", col = "blue", pch = 3)
We can verify the results with simulation:
library(parallel)
set.seed(724526144)
nreps <- tabulate(sample(23, 23e6, TRUE), 23)
clust <- makeCluster(detectCores() - 1)
clusterExport(clust, c("nreps", "s", "k"))
sim <- unlist(parLapply(clust, 1:23, function(i) sum(replicate(nreps[i], all(cumsum(!duplicated(c(replicate(3, sample(i + 7, 5)))))[cumsum(s)] == cumsum(k))))))
stopCluster(clust)
points(8:30, sim/sum(sim), col = "orange")
legend("topright", legend = c("Posterior likelihood", "Simulation"), col = c("blue", "orange"), pch = c(3, 1))
If we had observed $k=5,4,2$ instead of $k=5,3,1$, we can see the posterior distribution shift toward larger values of $n$.
k <- c(5, 4, 2)
post <- pn(s, k, function(n) 1)
like <- post(8:30)
plot(8:30, like/sum(like), xlab = "n", ylab = "p(n)", col = "blue", pch = 3)
Again verifying the results with simulation:
set.seed(353678169)
nreps <- tabulate(sample(23, 23e6, TRUE), 23)
clust <- makeCluster(detectCores() - 1)
clusterExport(clust, c("nreps", "s", "k"))
sim <- unlist(parLapply(clust, 1:23, function(i) sum(replicate(nreps[i], all(cumsum(!duplicated(c(replicate(3, sample(i + 7, 5)))))[cumsum(s)] == cumsum(k))))))
stopCluster(clust)
points(8:30, sim/sum(sim), col = "orange")
legend("topright", legend = c("Posterior likelihood", "Simulation"), col = c("blue", "orange"), pch = c(3, 1))