Here is the way how numpy.mgrid is used.
grid = np.mgrid[x1:y1:100j , x2:y2:100j, ..., xn:yn:100j]
However, I find this structure very irritating. Therefore, I would like to create function f which works as follows:
f([(x1,y1,100),...,(xn,yn,100)]) = np.mgrid[x1:y1:100j , x2:y2:100j, ..., xn:yn:100j]
How can I create f?
(Here is the source code for np.mgrid)
Just loop over each item passed to f and make a slice out of it with slice, and to get 100j from 100, multiply 100 by 1j:
def f(items):
slices = [slice(i[0], i[1], 1j * i[2]) for i in items]
return np.mgrid[slices]
Output:
>>> np.all( f([(1,2,5), (2,3,5)]) == np.mgrid[1:2:5j, 2:3:5j] )
True
You could make calling the function even simpler by using *items instead of items:
def f(*items):
slices = [slice(i[0], i[1], 1j * i[2]) for i in items]
return np.mgrid[slices]
Output:
>>> np.all( f([1,2,5], [2,3,5]) == np.mgrid[1:2:5j, 2:3:5j] )
True
mgrid is an instance of a cute class that lets us use indexing notation. Under the covers it uses np.linspace (or np.arange) to generate the ranges.
In [29]: x1,y1 = 0,1; x2,y2 = 1,3
In [30]: np.mgrid[x1:y1:3j, x2:y2:4j]
Out[30]:
array([[[0. , 0. , 0. , 0. ],
[0.5 , 0.5 , 0.5 , 0.5 ],
[1. , 1. , 1. , 1. ]],
[[1. , 1.66666667, 2.33333333, 3. ],
[1. , 1.66666667, 2.33333333, 3. ],
[1. , 1.66666667, 2.33333333, 3. ]]])
meshgrid is the function equivalent. I suspect it was the original function, and mgrid (and ogrid) was secondary version:
In [31]: np.meshgrid(np.linspace(x1,y1,3), np.linspace(x2,y2,4), indexing='ij')
Out[31]:
[array([[0. , 0. , 0. , 0. ],
[0.5, 0.5, 0.5, 0.5],
[1. , 1. , 1. , 1. ]]),
array([[1. , 1.66666667, 2.33333333, 3. ],
[1. , 1.66666667, 2.33333333, 3. ],
[1. , 1.66666667, 2.33333333, 3. ]])]
mgrid creates a n-d array; meshgrid returns a list of arrays. Otherwise they are equivalent. np.array(Out[31]) creates the array.
sparse versions
ogrid produces a "sparse" pair of arrays that, with broadcasting, functions the same way:
In [37]: np.ogrid[x1:y1:3j, x2:y2:4j]
Out[37]:
[array([[0. ],
[0.5],
[1. ]]),
array([[1. , 1.66666667, 2.33333333, 3. ]])]
meshgrid has an equivalent sparse mode:
In [38]: np.meshgrid(np.linspace(x1,y1,3), np.linspace(x2,y2,4), indexing='ij',
...: sparse=True)
Out[38]:
[array([[0. ],
[0.5],
[1. ]]),
array([[1. , 1.66666667, 2.33333333, 3. ]])]
We can create the same pair of arrays with:
In [39]: np.ix_(np.linspace(x1,y1,3), np.linspace(x2,y2,4))
Out[39]:
(array([[0. ],
[0.5],
[1. ]]),
array([[1. , 1.66666667, 2.33333333, 3. ]]))
or even:
In [40]: (np.linspace(x1,y1,3)[:,None], np.linspace(x2,y2,4)[None,:])
Out[40]:
(array([[0. ],
[0.5],
[1. ]]),
array([[1. , 1.66666667, 2.33333333, 3. ]]))
Related
I have a code snippet:
import numpy as np
x1 = [[1,4,2,1],
[1,1,4,5],
[0.5,0.3, 1,6],
[0.8,0.2,0.7,1]]
x2 = [[7,0,2,3],
[8,0,4,5],
[0.1,0, 2,6],
[0.1,0,0.16666667,6]]
np.true_divide(x1, x2)
The output is:
array([[0.14285714, inf, 1. , 0.33333333],
[0.125 , inf, 1. , 1. ],
[5. , inf, 0.5 , 1. ],
[8. , inf, 4.19999992, 0.16666667]])
I am aware that some elements will have zerodivision error which can be seen as 'inf'.
How can I use 'try and except' to change all these 'inf' results into 0? Or is there a better method to convert all those 'inf's into 0?
You can use numpy.where to select the values for which the division result or the original values be retained:
import numpy as np
x1 = np.array([[1,4,2,1],
[1,1,4,5],
[0.5,0.3, 1,6],
[0.8,0.2,0.7,1]])
x2 = np.array([[7,0,2,3],
[8,0,4,5],
[0.1,0, 2,6],
[0.1,0,0.16666667,6]])
np.where(x2==0, 0, x1/x2)
# or
# np.where(x2==0, x2, np.true_divide(x1, x2))
Output:
array([[0.14285714, 0. , 1. , 0.33333333],
[0.125 , 0. , 1. , 1. ],
[5. , 0. , 0.5 , 1. ],
[8. , 0. , 4.19999992, 0.16666667]])
0/0 can handle by adding invalid='ignore' to numpy.errstate()
introducing numpy.nan_to_num() to convert np.nan to 0.
with np.errstate(divide='ignore', invalid='ignore'):
c = np.true_divide(x1,x2)
c[c == np.inf] = 0
c = np.nan_to_num(c)
print(c)
Output
[[0.14285714 0. 1. 0.33333333]
[0.125 0. 1. 1. ]
[5. 0. 0.5 1. ]
[8. 0. 4.19999992 0.16666667]]
I tried this
x = np.array([
[0,0],
[1,0],
[2.61,-1.28],
[-0.59,2.1]
])
for i in X:
X = np.append(X[i], X[i][0]**2, axis = 1)
print(X)
But i am getting this
IndexError Traceback (most recent call last)
<ipython-input-12-9bfd33261d84> in <module>()
6 ])
7 for i in X:
----> 8 X = np.append(X[i], X[i][0]**2, axis = 1)
9
10 print(X)
IndexError: arrays used as indices must be of integer (or boolean) type
Someone please help!
How about concatenate:
np.concatenate((x,x**2))
Output:
array([[ 0. , 0. ],
[ 1. , 0. ],
[ 2.61 , -1.28 ],
[-0.59 , 2.1 ],
[ 0. , 0. ],
[ 1. , 0. ],
[ 6.8121, 1.6384],
[ 0.3481, 4.41 ]])
In [210]: x = np.array([
...: [0,0],
...: [1,0],
...: [2.61,-1.28],
...: [-0.59,2.1]
...: ])
...:
In [211]: x # (4,2) array
Out[211]:
array([[ 0. , 0. ],
[ 1. , 0. ],
[ 2.61, -1.28],
[-0.59, 2.1 ]])
In [212]: for i in x: # iterate on rows
...: print(i) # i is a row, not an index x[i] would be wrong
...:
[0. 0.]
[1. 0.]
[ 2.61 -1.28]
[-0.59 2.1 ]
Look at one row:
In [214]: x[2]
Out[214]: array([ 2.61, -1.28])
You can join that row with its square with:
In [216]: np.concatenate((x[2], x[2]**2))
Out[216]: array([ 2.61 , -1.28 , 6.8121, 1.6384])
And doing the same for the whole array. Where possible in numpy work with the whole array, not rows and elements. It's simpler, and faster.
In [217]: np.concatenate((x, x**2), axis=1)
Out[217]:
array([[ 0. , 0. , 0. , 0. ],
[ 1. , 0. , 1. , 0. ],
[ 2.61 , -1.28 , 6.8121, 1.6384],
[-0.59 , 2.1 , 0.3481, 4.41 ]])
I have the following code to plot scalar x vs scalar f(x) where there is some matrix multiplication inside the function:
import numpy as np
import matplotlib.pyplot as plt
from numpy.linalg import matrix_power
P=np.array([\
[0,0,0.5,0,0.5],\
[0,0,1,0,0], \
[.25,.25,0,.25,.25], \
[0,0,.5,0,.5], \
[0,0,0,0,1], \
])
t=np.array([0,1,0,0,0])
ones=np.array([1,1,1,1,0])
def f(x):
return t.dot(matrix_power(P,x)).dot(ones)
x=np.arange(1,20)
plt.plot(x, f(x))
Now, the function by itself works fine.
>>> f(1)
1.0
>>> f(2)
0.75
But the plotting raises the error exponent must be an integer.
To put it another way, how do I evaluate this function upon an array? e.g.
f(np.array([1,2]))
I tried replacing the plot line with
plt.plot(x, map(f,x))
But this didn't help.
How can I fix this?
In [1]: P=np.array([\
...: [0,0,0.5,0,0.5],\
...: [0,0,1,0,0], \
...: [.25,.25,0,.25,.25], \
...: [0,0,.5,0,.5], \
...: [0,0,0,0,1], \
...: ])
In [2]:
In [2]: P
Out[2]:
array([[0. , 0. , 0.5 , 0. , 0.5 ],
[0. , 0. , 1. , 0. , 0. ],
[0.25, 0.25, 0. , 0.25, 0.25],
[0. , 0. , 0.5 , 0. , 0.5 ],
[0. , 0. , 0. , 0. , 1. ]])
In [4]: np.linalg.matrix_power(P,3)
Out[4]:
array([[0. , 0. , 0.25 , 0. , 0.75 ],
[0. , 0. , 0.5 , 0. , 0.5 ],
[0.125, 0.125, 0. , 0.125, 0.625],
[0. , 0. , 0.25 , 0. , 0.75 ],
[0. , 0. , 0. , 0. , 1. ]])
In [5]: np.linalg.matrix_power(P,np.arange(0,4))
---------------------------------------------------------------------------
TypeError: exponent must be an integer
So just give it the integer that it wants:
In [10]: [f(i) for i in range(4)]
Out[10]: [1.0, 1.0, 0.75, 0.5]
pylab.plot(np.arange(25), [f(i) for i in np.arange(25)])
From the matrix_power code:
a = asanyarray(a)
_assertRankAtLeast2(a)
_assertNdSquareness(a)
try:
n = operator.index(n)
except TypeError:
raise TypeError("exponent must be an integer")
....
Here's what it does for n=3:
In [5]: x = np.arange(9).reshape(3,3)
In [6]: np.linalg.matrix_power(x,3)
Out[6]:
array([[ 180, 234, 288],
[ 558, 720, 882],
[ 936, 1206, 1476]])
In [7]: x#x#x
Out[7]:
array([[ 180, 234, 288],
[ 558, 720, 882],
[ 936, 1206, 1476]])
You could define a matrix_power function that accepts an array of powers:
def matrix_power(P,x):
return np.array([np.linalg.matrix_power(P,i) for i in x])
With this matrix_power(P,np.arange(25)) would produce a (25,5,5) array. And your f(x) actually does work with that, returning a (25,) shape array. But I wonder, was that just fortuitous, or was it intentional? Did you write f with a 3d power array in mind?
t.dot(matrix_power(P,x)).dot(ones)
I want to construct an array of list of arrays but my method breaks down if the arrays inside the list have equal dimensions.
I make a list of lists of arrays
and then I convert that list into an array
import numpy as np
foo = [[np.array([4. , 0. , 0.1]), np.array([5. , 0. , 0.1])],
[np.array([6. , 0. , 0.5])],
[],
[],
[]]
foo = np.array(foo)
foo
which results in an array of list of arrays:
Out[40]:
array([list([array([4. , 0. , 0.1]), array([5. , 0. , 0.1])]),
list([array([6. , 0. , 0.5])]), list([]), list([]), list([])],
dtype=object)
perfect.
Now consider the case where array dimensions are equal:
bar = [[np.array([4. , 0. , 0.1])],
[np.array([4. , 0. , 0.1])],
[np.array([4. , 0. , 0.1])],
[np.array([4. , 0. , 0.1])],
[np.array([4. , 0. , 0.1])]]
bar = np.array(bar)
print(bar)
The same method results in merely nested arrays.
Out[1]:
array([[[4. , 0. , 0.1]],
[[4. , 0. , 0.1]],
[[4. , 0. , 0.1]],
[[4. , 0. , 0.1]],
[[4. , 0. , 0.1]]])
Is there a way to make bar an array of list of arrays?
(I would like to have this format because I am appending more arrays to the individual lists)
I have a matrix that should have ones on the diagonal but the columns are mixed up.
But I don't know how, without the obvious for loop, to efficiently interchange rows to get unity on the diagonals. I'm not even sure what key I would pass to sort on.
Any suggestions?
You can use numpy's argmax to determine the goal column ordering and reorder your matrix using the argmax results as column indices:
>>> z = numpy.array([[ 0.1 , 0.1 , 1. ],
... [ 1. , 0.1 , 0.09],
... [ 0.1 , 1. , 0.2 ]])
numpy.argmax(z, axis=1)
>>> array([2, 0, 1]) #Goal column indices
z[:,numpy.argmax(z, axis=1)]
>>> array([[ 1. , 0.1 , 0.1 ],
... [ 0.09, 1. , 0.1 ],
... [ 0.2 , 0.1 , 1. ]])
>>> import numpy as np
>>> a = np.array([[ 1. , 0.5, 0.5, 0. ],
... [ 0.5, 0.5, 1. , 0. ],
... [ 0. , 1. , 0. , 0.5],
... [ 0. , 0.5, 0.5, 1. ]])
>>> np.array(sorted(a, cmp=lambda x, y: list(x).index(1) - list(y).index(1)))
array([[ 1. , 0.5, 0.5, 0. ],
[ 0. , 1. , 0. , 0.5],
[ 0.5, 0.5, 1. , 0. ],
[ 0. , 0.5, 0.5, 1. ]])
It actually sorts by rows, not columns (but the result is the same). It works by sorting by the index of the column the 1 is in.