Reputation: 740
You can get evenly spaced numbers over a specified interval using Numpy's Linspace:
$ import numpy as np
$ np.linspace(0,10,5)
>>> array([ 0. , 2.5, 5. , 7.5, 10. ])
I, however, want to sample more numbers at the beginning and end of my interval. For instance, if my interval was [0-10]
and I wanted 5 samples. A good sample would be:
>>> array([0, 1, 5, 9, 10])
I know someone might say that there are many ways to sample this space, for instance: [0, 0.5, 5, 9.5, 10]
is another good sample. I do not mind how it is sampled, I am only interested in sampling methods which return more samples towards the beginning and end of my sample space.
One solution would be to sample indices from a Gaussian distribution, and if you get a number near the mean of the distribution you draw a number closer to the beginning or end of your sample space. However, this method seems more complicated than it needs to be, and you are not guaranteed to get good samples.
Does anyone know of a good way to generate samples towards the beginning and end of a sample space?
Upvotes: 3
Views: 1020
Reputation: 53029
You can rescale the tanh
to get sequences with adjustable clumpiness:
import numpy as np
def sigmoidspace(low,high,n,shape=1):
raw = np.tanh(np.linspace(-shape,shape,n))
return (raw-raw[0])/(raw[-1]-raw[0])*(high-low)+low
# default shape parameter
sigmoidspace(1,10,10)
# array([ 1. , 1.6509262 , 2.518063 , 3.60029094, 4.8461708 ,
# 6.1538292 , 7.39970906, 8.481937 , 9.3490738 , 10. ])
# small shape parameter -> almost linear points
sigmoidspace(1,10,10,0.01)
# array([ 1. , 1.99995391, 2.99994239, 3.99995556, 4.99998354,
# 6.00001646, 7.00004444, 8.00005761, 9.00004609, 10. ])
# large shape paramter -> strong clustering towards the ends
sigmoidspace(1,10,10,10)
# array([ 1. , 1.00000156, 1.00013449, 1.01143913, 1.87995338,
# 9.12004662, 9.98856087, 9.99986551, 9.99999844, 10. ])
Upvotes: 3
Reputation: 30589
This will give you more samples to the end of the intervall:
np.sqrt(np.linspace(0,100,5))
array([ 0. , 5. , 7.07106781, 8.66025404, 10. ])
You can choose a higher exponent to get more frequent intervalls towards the ends.
To get more samples towards beginning and end of the intervall, make the original linspace symmetrical to 0 and then just shift it.
General function:
def nonlinspace(xmin, xmax, n=50, power=2):
'''Intervall from xmin to xmax with n points, the higher the power, the more dense towards the ends'''
xm = (xmax - xmin) / 2
x = np.linspace(-xm**power, xm**power, n)
return np.sign(x)*abs(x)**(1/power) + xm + xmin
Examples:
>>> nonlinspace(0,10,5,2).round(2)
array([ 0. , 1.46, 5. , 8.54, 10. ])
>>> nonlinspace(0,10,5,3).round(2)
array([ 0. , 1.03, 5. , 8.97, 10. ])
>>> nonlinspace(0,10,5,4).round(2)
array([ 0. , 0.8, 5. , 9.2, 10. ])
Upvotes: 3