I am trying to implement a fucntion which returns 100 samples from three different multivariate gaussian distributions.
numpy provides a way to sample from a sinle multivariate gaussian. But I could not find a way to sample from three different multivariate with different sampling probability.
My requirement is to sample with probability $[0.7, 0.2, 0.1]$ from three multivariate gaussians with mean and covariances as given below
G_1 mean = [1,1] cov =[ [ 5, 1] [1,5]]
G_2 mean = [0,0] cov =[ [ 5, 1] [1,5]]
G_3 mean = [-1,-1] cov =[ [ 5, 1] [1,5]]
Any idea ?
Say you create an array of your generators:
generators = [
np.random.multivariate_normal([1, 1], [[5, 1], [1, 5]]),
np.random.multivariate_normal([0, 0], [[5, 1], [1, 5]]),
np.random.multivariate_normal([-1, -1], [[5, 1], [1, 5]])]
Now you can create a weighted random of generator indices, since np.random.choice supports weighted sampling:
draw = np.random.choice([0, 1, 2], 100, p=[0.7, 0.2, 0.1])
(draw is a length-100 array of entries, each from {0, 1, 2} with probability 0.7, 0.2, 0.1, respectively.)
Now just generate the samples:
[generators[i] for i in draw]
I couldn't comment the other answer since I don't have the enough reputation, so my answer is an improvement meant to work.
When creating a list as [np.random.multivariate_normal([1, 1], [[5, 1], [1, 5]])], you are keeping the sample from a multivariate normal distribution, and not the distribution itself. So, every time the program reads generator[i] for the same i, it'll get the exact same value. So you won't have a sample from the mixture of multivariate normal distributions, but instead a sample from a discrete distribution with possible values coming from different distributions.
A working method would be:
from scipy.stats import multivariate_normal
generators = [
multivariate_normal([1, 1], [[5, 1], [1, 5]]),
multivariate_normal([0, 0], [[5, 1], [1, 5]]),
multivariate_normal([-1, -1], [[5, 1], [1, 5]])]
Now we use multivariate_normal from the scipy.stats package. Instead of creating a sample from the distribution, as in numpy.random, it creates a object regarding to the distribution, from which we can take a sample using the method rvs:
# As before, I create the weighted random list of indeces:
draw = np.random.choice([0, 1, 2], 100, p=[0.7, 0.2, 0.1])
# And then I generate the random values, each one from a different distribuion
[generators[i].rvs() for i in draw]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With