Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python sampling from different distributions with different probability

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 ?

like image 896
Shew Avatar asked Jul 14 '26 11:07

Shew


2 Answers

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]
like image 170
Ami Tavory Avatar answered Jul 20 '26 06:07

Ami Tavory


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]
like image 38
handraqui Avatar answered Jul 20 '26 04:07

handraqui