Sampling from D dimensional simplex by specifying the number of non-zero entries

Viewed 88

I would like to write a simple function to sample points from some d dimensional simplex, also specifying how many values I want to be different than zero.

For example, if d=5 and I want only two non-zero values then it could sample the points

np.array([0.,0.,0.,0.25,0.75])
np.array([0.5, 0.5, 0., 0., 0.])
np.array([0.0, 0.0, 0.8 ,0.2,0.])
1 Answers

Assuming d is the dimension of the simplex and n the number of non-null values, and that you want to sample uniformly at random.

You can decompose this as a two-step process, with:

1- Pick n elements in the [0, d[ range without replacement, which can be done with the np.random.choice

2- Sample on the n-dimensional simplex for those n elements. See here for details on this part: https://cs.stackexchange.com/questions/3227/uniform-sampling-from-a-simplex

import numpy as np

def simplex_sample(dim):
  xs = np.random.uniform(0, 1, dim-1)
  xs = np.append(xs, [0, 1])
  xs = np.sort(xs)
  xs = xs[1:] - xs[0:-1]
  return xs

def simplex_sample_with_non_zeros(dim, n):
  xs = simplex_sample(n)
  ys = np.zeros(dim)
  idx = np.random.choice(dim, n, replace=False)
  ys[idx] = xs
  return ys

Here's what it looks like visually:

import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(projection='3d')

n = 100
data = np.array([simplex_sample_with_non_zeros(3, 2) for i in range(n)])

ax.scatter(data[:,0], data[:,1], data[:,2])

plt.show()

See https://1000words-hq.com/n/1x4Wk0FtZM5 for a live implementation.

Related