Note to moderators : this question have not been answered in another post yet, because I want to use spherical coordinates.
In an optimization algorithm, I have a categorical variable with N+1 categories. But to represent these categories, I want to manage only N parameters because the optimization process is way more efficient with less parameters to optimize.
So let's imagine that this variable is represented by a point in a RN+1 space whose each direction is a category : the point lies on a unit N-sphere and its distance to each category determinates which category the variable is equal to. Using N coordinates instead of N+1 means using spherical coordinates instead of cartesian ones.
The optimization algorithm manages each N parameters in [0, 1]. But using these directly as spherical coordinates (multiplying them by $\frac{\pi}2$) doesn't work because each of these parameters have different weight on the displacement of the point on the N-Sphere. I need that a given change of any parameter always induce the same amount of displacement of the point on the N-sphere. The corollary is that if I sample uniformly at random these N parameters, I must obtain uniformly distributed points on the N-sphere.
As a try, I uniformly sampled N parameters in [0,1] : the 1st to (N-1)th were cosines of the polar angles and the last one was the normalized angle of the azimuth.
Then, I calculated the distance between each point and each category :
- when N=1 (circle), average distance to 1st and 2nd categories was 0.745, so the distribution is uniform ;
- when N=2 (sphere), average distance to 1st, 2nd and 3rd categories was 0.943, so the distribution is uniform. BUT :
- starting from N=3, points seemed to be closer to the first category (so the distibution is NOT uniform anymore) : average distance to 1st category was 0,943 while it was 1,067 for the 3 last categories ;
- as N increases, the non-uniformity became worse and worse.
Here is a minimal python code to reproduce my issue :
import numpy as np
import math
def spherical_to_cartesian(spherical_coords):
angles = [math.acos(spherical_coords[i]) for i in range(len(spherical_coords)-1)] + [spherical_coords[-1]*math.pi/2]
N = len(angles) + 1
cartesian_coords = np.zeros(N)
sin_cumul = 1
for i in range(0, N-1):
cartesian_coords[i] = np.cos(angles[i]) * sin_cumul
sin_cumul *= np.sin(angles[i])
cartesian_coords[-1] = sin_cumul
return cartesian_coords
def distance_to_categories(angles):
coords = spherical_to_cartesian(angles)
dist = []
vertex = len(angles)+1
for a in range(vertex):
category = np.zeros(vertex)
category[a] = 1
dist.append(math.dist(coords, category))
return np.array(dist)
points = 100_000
N = 20
dist_to_categories = np.ndarray(shape=(points, N+1))
for i in range(points):
angles = []
for j in range(N):
angles.append(np.random.uniform(0, 1))
dist_to_categories[i] = distance_to_categories(angles)
mean = [np.mean(dist_to_categories[:,i]) for i in range(dist_to_categories.shape[1])]
print(mean)
So the question is here : how to we sample spherical coordinates to be uniformly distributed on the N-sphere ?
(Please note that I only want to consider points on the N-sphere whose all the cartesian coordinates are non-negative)