Is There a Multi-Dimensional Version of Arange/Linspace in Numpy

Is there a multi-dimensional version of arange/linspace in numpy?

You can use np.mgrid for this, it's often more convenient than np.meshgrid because it creates the arrays in one step:

import numpy as np
X,Y = np.mgrid[-5:5.1:0.5, -5:5.1:0.5]

For linspace-like functionality, replace the step (i.e. 0.5) with a complex number whose magnitude specifies the number of points you want in the series. Using this syntax, the same arrays as above are specified as:

X, Y = np.mgrid[-5:5:21j, -5:5:21j]

You can then create your pairs as:

xy = np.vstack((X.flatten(), Y.flatten())).T

As @ali_m suggested, this can all be done in one line:

xy = np.mgrid[-5:5.1:0.5, -5:5.1:0.5].reshape(2,-1).T

Best of luck!

Vectorized NumPy linspace across multi-dimensional arrays

Here's one vectorized approach based on this post to cover for generic n-dim cases -

def create_ranges_nd(start, stop, N, endpoint=True):
if endpoint==1:
divisor = N-1
else:
divisor = N
steps = (1.0/divisor) * (stop - start)
return start[...,None] + steps[...,None]*np.arange(N)

Sample run -

In [536]: mins = np.array([[3,5],[2,4]])

In [537]: maxs = np.array([[13,16],[11,12]])

In [538]: create_ranges_nd(mins, maxs, 6)
Out[538]:
array([[[ 3. , 5. , 7. , 9. , 11. , 13. ],
[ 5. , 7.2, 9.4, 11.6, 13.8, 16. ]],

[[ 2. , 3.8, 5.6, 7.4, 9.2, 11. ],
[ 4. , 5.6, 7.2, 8.8, 10.4, 12. ]]])

2D of numpy arange

You can use numpy.mgrid or numpy.meshgrid():

np.mgrid[0:6, 0:6]
# array([[[0, 0, 0, 0, 0, 0],
# [1, 1, 1, 1, 1, 1],
# [2, 2, 2, 2, 2, 2],
# [3, 3, 3, 3, 3, 3],
# [4, 4, 4, 4, 4, 4],
# [5, 5, 5, 5, 5, 5]],
#
# [[0, 1, 2, 3, 4, 5],
# [0, 1, 2, 3, 4, 5],
# [0, 1, 2, 3, 4, 5],
# [0, 1, 2, 3, 4, 5],
# [0, 1, 2, 3, 4, 5],
# [0, 1, 2, 3, 4, 5]]])

np.meshgrid(np.arange(6), np.arange(6))
# [array([[0, 1, 2, 3, 4, 5],
# [0, 1, 2, 3, 4, 5],
# [0, 1, 2, 3, 4, 5],
# [0, 1, 2, 3, 4, 5],
# [0, 1, 2, 3, 4, 5],
# [0, 1, 2, 3, 4, 5]]),
# array([[0, 0, 0, 0, 0, 0],
# [1, 1, 1, 1, 1, 1],
# [2, 2, 2, 2, 2, 2],
# [3, 3, 3, 3, 3, 3],
# [4, 4, 4, 4, 4, 4],
# [5, 5, 5, 5, 5, 5]])]

and simply unpack the result

a, b = np.mgrid[0:6, 0:6]    

What is the difference between np.linspace and np.arange?

np.linspace allows you to define how many values you get including the specified min and max value. It infers the stepsize:

>>> np.linspace(0,1,11)
array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ])

np.arange allows you to define the stepsize and infers the number of steps(the number of values you get).

>>> np.arange(0,1,.1)
array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])

contributions from user2357112:

np.arange excludes the maximum value unless rounding error makes it do otherwise.

For example, the following results occur due to rounding error:

>>> numpy.arange(1, 1.3, 0.1)
array([1. , 1.1, 1.2, 1.3])

You can exclude the stop value (in our case 1.3) using endpoint=False:

>>> numpy.linspace(1, 1.3, 3, endpoint=False)
array([1. , 1.1, 1.2])

Vectorized NumPy linspace for multiple start and stop values

Here's an approach using broadcasting -

def create_ranges(start, stop, N, endpoint=True):
if endpoint==1:
divisor = N-1
else:
divisor = N
steps = (1.0/divisor) * (stop - start)
return steps[:,None]*np.arange(N) + start[:,None]

Sample run -

In [22]: # Setup start, stop for each row and no. of elems in each row
...: start = np.array([1,4,2])
...: stop = np.array([6,7,6])
...: N = 5
...:

In [23]: create_ranges(start, stop, 5)
Out[23]:
array([[ 1. , 2.25, 3.5 , 4.75, 6. ],
[ 4. , 4.75, 5.5 , 6.25, 7. ],
[ 2. , 3. , 4. , 5. , 6. ]])

In [24]: create_ranges(start, stop, 5, endpoint=False)
Out[24]:
array([[ 1. , 2. , 3. , 4. , 5. ],
[ 4. , 4.6, 5.2, 5.8, 6.4],
[ 2. , 2.8, 3.6, 4.4, 5.2]])

Let's leverage multi-core!

We can leverage multi-core with numexpr module for large data and to gain memory efficiency and hence performance -

import numexpr as ne

def create_ranges_numexpr(start, stop, N, endpoint=True):
if endpoint==1:
divisor = N-1
else:
divisor = N
s0 = start[:,None]
s1 = stop[:,None]
r = np.arange(N)
return ne.evaluate('((1.0/divisor) * (s1 - s0))*r + s0')

Numpy modify each array in multidimensional array with arange

Since by necessity all of the aranges need to be equally long, we can create an arange along the first entry and then replicate it for the others.

For example:

x = np.array([[78, 82],
[90, 94],
[102, 106]])

>>> x[:, :1] + np.arange(0, 1 + x[0, 1] - x[0, 0])
# array([[ 78, 79, 80, 81],
# [ 90, 91, 92, 93],
# [102, 103, 104, 105]])

Python numpy unexpected results in arange and linspace

In the Python console you will see

>>> 0.29/0.01
28.999999999999996
>>> import numpy as np
>>> np.int32(0.29/0.01)
28

So you are on the right path. This is due to floating point calculation. As soon as you cast it to np.int32, the decimal places will be truncated and the result is 28. Instead of just casting, you should round the result:

>>> np.int32(np.round(0.29/0.01))
29

For your application that means you have to write

lattice = np.asarray(np.round(lattice/cell_size),dtype=np.int32) ###This is supposed to contain matrix indices.


Related Topics



Leave a reply



Submit