Goal
I am trying to build a function that draws a specific number of random numbers from an an "incomplete uniform distribution".
What do I call an incomplete uniform distribution?
I call an incomplete uniform distribution a probability distribution where each value of X
within a series of boundaries have an equal probability to be picked. In other words it is a uniform distribution with holes (where the probability is zero) as represented below
x = list(12:25, 34:54, 67:90, 93:115)
y = 1/sum(25-12, 54-34, 90-67, 115-93)
plot(y=rep(y, length(unlist(x))), x=unlist(x), type="n", ylab="Probability", xlab="X")
for (xi in x)
{
points(xi,rep(y, length(xi)), type="l", lwd=4)
}
Ugly Solution
Here is a slow and ugly solution
IncompleteUnif = function(n,b)
{
#################
# "n" is the desired number of random numbers
# "b" is a list describing the boundaries within which a random number can possibly be drawn.
#################
r = c() # Series of random numbers to return
for (ni in n)
{
while (length(r) < n) # loop will continue until we have the "n" random numbers we need
{
ub = unlist(b)
x = runif(1,min(ub), max(ub)) # one random number taken over the whole range
for (bi in b) # The following loop test if the random number is withinn the ranges specified by "b"
{
if (min(bi) < x & max(bi) > x) # if found in one range then just add "x" to "r" and break
{
r = append(r,x)
break
}
}
}
}
return (r)
}
b = list(c(5,94),c(100,198),c(220,292), c(300,350))
set.seed(12)
IncompleteUnif(10,b)
[1] 28.929516 287.132444 330.204498 63.425103 16.693990 66.680826 226.374551 12.892821 7.872065 140.480533
Another solution is to transform the output. The idea is to sample from a random uniform distribution, then apply a conditional transformation so that the numbers fall only in the selected ranges:
I'm a few years late to the party, but seeing that there wasn't a solution without an explicit loop yet, here's one such implementation (following @RobertDodier's approach):
Created on 2018-03-11 by the reprex package (v0.2.0).
I believe this works, using the algorithm suggested by Robert Dodier:
I like Sam Dickson's histogram visual check, here's my version:
It could be fancied up with some input-checking (and maybe an
mapply
like suggested in the comments), but I'll leave that to others.Thanks to alexis_iaz for the
tabulate()
suggestion!Slightly convoluted version of the @Gregor's solution.
Your incomplete uniform distribution can be represented as a mixture of four ordinary uniform distributions, with mixing weight for each segment proportional to its length (i.e., so that the longer the segment, the more weight it has).
To sample from such a distribution, first choose a segment (taking the weights into account). Then from the chosen segment, choose an element.