I need to sample from a distribution that is a hybrid of uniform and hypergeometric in the sense that all elements are sampled uniformly until an element reaches some specified maximum observations, upon which that element will no longer be sampled.
Think of it as an urn with some $N$ distinctly colored balls, and I sample with replacement $M$ times, but any time a ball has been observed $O$ times in a sample, it is not replaced.
A quick-n-dirty implementation is:
genoutcomes[src_, max_, len_] :=
Module[{oc = {}, cnt = ConstantArray[max, Length@src], rc, r = Range@Length@src},
Do[oc = {oc, src[[rc = RandomChoice[Unitize@cnt -> r]]]};
cnt[[rc]]--;, len];
Flatten@oc];
For example, if the urn has 3 differently colored balls, I want to sample 6, with a maximum observation limit for any ball of 2,
genoutcomes[{red, green, blue}, 2, 6]
produces such a sample.
I'd like to get a more efficient mechanism for doing this (pure Mathematica - I can write it in C or Lisp or whatever, but I'm not after that), ideally for multiple samples in bulk vs calling a routine once per sample.
The above is as I said a quick-n-dirty sketch, I'm pondering but it's late and Morpheus is calling, figured it's an interesting puzzle to throw out here....
Edit: From interactions with posters, here's a quick sanity check for testing.
Generating a large batch of results for 3 elements, 5 max, 9 sample length (something like res = Table[genoutcomes[Range@3, 5, 9], 1000000]
for my routine, substitute yours), the result of
Count[res, #] & /@ {{x_, x_, x_, x_, x_, ___}, {___, x_, x_, x_, x_, x_}}
should have a ratio of ~5:1.
Table
and check the distribution. $\endgroup$DeleteDuplicates
, it gets closer with larger samples, but then why bother, better to just generate them in the first place. Make no mistake, I appreciate your efforts. $\endgroup$