Read one specific cell of numpy matrix - arrays

I wrote a function to see if a matrix is symmetric or not:
def issymmetric(mat):
if(mat.shape[0]!=mat.shape[1]):
return 0
for i in range(mat.shape[0]):
for j in range(i):
if (mat[i][j]!=mat[j][i]):
return 0
return 1
It works well with built-in ndarrays e.g. numpy.ones:
import numpy as np
a=np.ones((5,5), int)
print issymmetric(a)
And with numpy arrays:
import numpy as np
a=np.array([[1, 2, 3], [2, 1 , 2], [3, 2, 1]])
print issymmetric(a)
But when it comes to numpy matrixes:
import numpy as np
a=np.matrix([[1, 2, 3], [2, 1 , 2], [3, 2, 1]])
print issymmetric(a)
It gaves me this error:
File "issymetry.py", line 9, in issymmetric
if (mat[i][j]!=mat[j][i]):
File "/usr/lib/python2.7/dist-packages/numpy/matrixlib/defmatrix.py", line 316, in __getitem__
out = N.ndarray.__getitem__(self, index)
IndexError: index 1 is out of bounds for axis 0 with size 1
shell returned 1
That's because There is no a[0][1]
a[0] is matrix([[1, 2, 3]]). a[0][0] is matrix([[1, 2, 3]]) too., but there is no a[0][1].
How can I fix this issue, without changing the matrix type, or the function?
In general, what is the proper way to read and update one specific cell of a numpy matrix?

It is best to use [i,j] style indexing in numpy. Often you can get by with [i][j] when using np.array, but not with np.matrix. Remember an np.matrix is always 2d.
In a shell construct a simple 2d array, and try different methods of indexing. Now try it with np.matrix arrays. Pay attention to the shape.
In [2]: A = np.arange(6).reshape(2,3)
In [3]: A[1] # short for A[1,:]
Out[3]: array([3, 4, 5]) # shape (3,)
In [4]: A[1][2] # short for A[1,:][2]
Out[4]: 5
In [5]: M=np.matrix(A)
In [6]: M[1]
Out[6]: matrix([[3, 4, 5]]) # shape (1,3), 2d
In [7]: M[1][2]
...
IndexError: index 2 is out of bounds for axis 0 with size 1
correct indexing that works with both
In [9]: A[1,2]
Out[9]: 5
In [10]: M[1,2]
Out[10]: 5
A[i][j]=... is also prone to failure when used on the LHS. It only works if the first part A[i] returns a view. If fails if it produces a copy.

Related

Modifying a 3d array using a 2D index with Numpy

I have an array in three dimensions (a, b, c) and I need to modify the positions c indexed by an array in two dimensions (a, b).
I wrote a code that works as expected, but does anyone know if there is a way to solve this problem without the for loop?
import numpy as np
arr = np.random.randn(100, 5, 2)
mod = np.random.randn(100, 5)
ids = np.random.randint(0, 2, size=[100,5])
for i in range(100):
for j in range(5):
arr[i,j,ids[i,j]] = mod[i,j]
You can refer to and set each slice of the array directly. I think this code shows the behaviour you are asking about:
import numpy as np
arr = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
print(arr[:,:,2])
# Output:
#[[ 3 6]
# [ 9 12]]
new2DSlice = np.array([[23, 26], [29, 32]])
arr[:,:,2] = new2DSlice
print(arr[:,:,2])
# Outupt:
#[[23 26]
# [29 32]]
arr[:,:,2] refers to the third slice of the array and, in this example, sets it directly.
You can read about NumPy's array indexing and array slicing on W3Schools.
I got with this:
import numpy as np
arr = np.random.randn(100, 5, 2)
mod = np.random.randn(100, 5)
ids = np.random.randint(0, 2, size=[100,5])
x = np.arange(100)
y = np.arange(5)
arr[x[:,None],y,ids] = mod

array in array to array in numpy

Dear friends in stack overflow,
I have trouble calculation with Numpy and Sympy. A is defined by
import numpy as np
import sympy as sym
sym.var('x y')
f = sym.Matrix([0,x,y])
func = sym.lambdify( (x,y), f, "numpy")
X=np.array([1,2,3])
Y=np.array((1,2,3])
A = func(X,Y).
Here, X and Y are just examples. In general, X and Y are one dimensional array in numpy, and they have the same length. Then, A’s output is
array([[0],
[array([1, 2, 3])],
[array([1, 2, 3])]], dtype=object).
But, I'd like to get this as
np.array([[0,0,0],[1,2,3],[1,2,3]]).
If we call this B, How do you convert A to B automatically. B’s first column is filled by 0, and it has the same length with X and Y.
Do you have any ideas?
First let's make sure we understand what is happening:
In [52]: x, y = symbols('x y')
In [54]: f = Matrix([0,x,y])
...: func = lambdify( (x,y), f, "numpy")
In [55]: f
Out[55]:
⎡0⎤
⎢ ⎥
⎢x⎥
⎢ ⎥
⎣y⎦
In [56]: print(func.__doc__)
Created with lambdify. Signature:
func(x, y)
Expression:
Matrix([[0], [x], [y]])
Source code:
def _lambdifygenerated(x, y):
return (array([[0], [x], [y]]))
See how the numpy function looks just like the sympy, replacing sym.Matrix with np.array. lambdify just does a lexographic translation; it does not have a deep knowledge of the differences between the languages.
With scalars the func runs as expected:
In [57]: func(1,2)
Out[57]:
array([[0],
[1],
[2]])
With arrays the results is this ragged array (new enough numpy adds this warning:
In [59]: func(np.array([1,2,3]),np.array([1,2,3]))
<lambdifygenerated-2>:2: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
return (array([[0], [x], [y]]))
Out[59]:
array([[0],
[array([1, 2, 3])],
[array([1, 2, 3])]], dtype=object)
If you don't know numpy, sympy is not a short cut to filling in your knowledge gaps.
The simplest fix is to replace original 0 with another symbol.
Even in sympy, the 0 is not expanded:
In [65]: f.subs({x:Matrix([[1,2,3]]), y:Matrix([[4,5,6]])})
Out[65]:
⎡ 0 ⎤
⎢ ⎥
⎢[1 2 3]⎥
⎢ ⎥
⎣[4 5 6]⎦
In [74]: Matrix([[0,0,0],[1,2,3],[4,5,6]])
Out[74]:
⎡0 0 0⎤
⎢ ⎥
⎢1 2 3⎥
⎢ ⎥
⎣4 5 6⎦
In [75]: Matrix([[0],[1,2,3],[4,5,6]])
...
ValueError: mismatched dimensions
To make the desired array in numpy we have to do something like:
In [71]: arr = np.zeros((3,3), int)
In [72]: arr[1:,:] = [[1,2,3],[4,5,6]]
In [73]: arr
Out[73]:
array([[0, 0, 0],
[1, 2, 3],
[4, 5, 6]])
That is, initial the array and fill selected rows. There isn't simple expression that will do the desired 'automaticlly fill the first row with 0', much less something that can be naively translated from sympy.

Python change the array's dimension from (n,1) for (n,)

If I declare an array "v" whose shape is (3,100) when I want to change its values column by column making use a "for" python changes the dimension of "v[:,i]" for (3,) this is annoying and I can't make the change because at the left member it has a (3,) array and in the right, it has an (3,1) array.
I would like to know, why does this happen? and which are my options to cope with this?
Thanks.
v = np.ones( (3, 100) );
for i in range( 0 , 100 ):
v[:,i] = np.array([[1],
[2],
[3]])
ValueError: could not broadcast input array from shape (3,1) into shape (3)
In [379]: M = np.arange(12).reshape(3,4)
Indexing with a scalar reduced the dimension by one. That's a basic rule of indexing - in numpy and python.
In [380]: M[0,:]
Out[380]: array([0, 1, 2, 3])
In [381]: M[:,0]
Out[381]: array([0, 4, 8])
Same for a list:
In [383]: M.tolist()
Out[383]: [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
In [384]: M.tolist()[0]
Out[384]: [0, 1, 2, 3]
Index with a list/array or slice, does preserve the dimension:
In [385]: M[:,[0]]
Out[385]:
array([[0],
[4],
[8]])
So assigning a (3,) to the (3,) slot is fine:
In [386]: M[:,0] = [10,20,30]
Assigning a (3,1) to that slot produces an error:
In [387]: M[:,0] = [[10],[20],[30]]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'list'
The above exception was the direct cause of the following exception:
ValueError Traceback (most recent call last)
<ipython-input-387-1bbfa6dfa93c> in <module>
----> 1 M[:,0] = [[10],[20],[30]]
ValueError: setting an array element with a sequence.
In [388]: M[:,0] = np.array([[10],[20],[30]]) # or with an array
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-388-6e511ffdc44e> in <module>
----> 1 M[:,0] = np.array([[10],[20],[30]])
ValueError: could not broadcast input array from shape (3,1) into shape (3)
By broadcasting (3,) can go into (1,3), but not (3,1) into (3,). One solution is to flatten the RHS:
In [389]: M[:,0] = np.array([[10],[20],[30]]).ravel()
Assigning to a (3,1) slot also works:
In [390]: M[:,[0]] = np.array([[10],[20],[30]])
In [391]: M[:,0:1] = np.array([[10],[20],[30]])
We could also transpose the (3,1) to (1,3). Or assign to M[:,0][:,None] or M[:,0,None] (both of which create a (3,1)).
What I think you are asking is: how to set them column wise.
v = np.ones( (3,100) )
for i in range( 0 , 100 ):
v[:,i] = np.array([1,
3,
2])
The change is to remove extra brackets in your assignment.
If you are trying to do something else, you can try doing it for rows, and flip array sideways:
v = np.ones((100,3))
for i in range(0,100):
v[i] = np.array([1,3,2])
EDIT: changed the whitespace to be the same as the author

How to organize list of list of lists to be compatible with scipy.optimize fmin init array

I am very amateur when it comes to scipy. I am trying to use scipy's fmin function on a multidimensional variable system. For the sake of simplicity I am using list of list of list's. My data is 12 dimensional, when I enter np.shape(DATA) it returns (3,2,2), I am not even sure if scipy can handle that many dimensions, if not no problem I can reduce them, the point is that the optimize.fmin() function doesn't accept list based arrays as x0 initial parameters, so I need help either rewriting the x0 array into numpy compatible one or the entire DATA array into a 12 dimensional matrix or something like that.
Here is a simpler example illustrating the issue:
from scipy import optimize
import numpy as np
def f(x): return(x[0][0]*1.5-x[0][1]*2.0+x[1][0]*2.5-x[1][1]*3.0)
result = optimize.fmin(f,[[0.1,0.1],[0.1,0.1]])
print(result)
It will give an error saying invalid index to scalar variable which probably comes from not understanding the [[],[]] list of list structure, so it probably only understands numpy array formats.
So how to rewrite this to make it work, and also for my (3,2,2) shaped list of list as well!?
scipy.optimize.fmin needs the initial guess for the function parameters to be a 1D array with a number of elements that suits the function to optimize. In your case, maybe you can use flatten and reshape if you just need the output to be in the same shape as your input parameters. An example based on your illustration code:
from scipy import optimize
import numpy as np
def f(x):
return x[0]*1.5-x[1]*2.0+x[2]*2.5-x[3]*3.0
guess = np.array([[0.1, 0.1],
[0.1, 0.1]]) # guess.shape is (2,2)
out = optimize.fmin(f, guess.flatten()) # flatten upon input
# out.shape is (4,)
# reshape output according to guess
out = out.reshape(guess.shape) # out.shape is (2,2) again
or out = optimize.fmin(f, guess.flatten()).reshape(guess.shape) in one line. Note that this also works for a 3-dimensional array as you propose:
guess = np.arange(12).reshape(3,2,2)
# array([[[ 0, 1],
# [ 2, 3]],
# [[ 4, 5],
# [ 6, 7]],
# [[ 8, 9],
# [10, 11]]])
guess = guess.flatten()
# array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
guess = guess.reshape(3,2,2)
# array([[[ 0, 1],
# [ 2, 3]],
# [[ 4, 5],
# [ 6, 7]],
# [[ 8, 9],
# [10, 11]]])

Loop to perform operation on i+1 in numpy array

I have a numpy array, I'd like to take the 3 numbers in each row, minus them from the next row and store those values in another array.
something like
for i in array:
a = i - i+1
I know this is very wrong, but at least this gives the idea of what I want.
Obviously i+1 will just result in the value + 1 and then all I have is a = 1,1,1
When I say i+1 I mean the next in line.
So for example:
input = np.array([[4,4,5], [2,3,1],[1,2,0]])
output = np.array([2,1,4],[1,1,1]) etc....
What would be the best way to do this iteratively on thousands of rows?
IIUC, instead of looping, you can just shift your arrays 1 up using np.roll, subtract that from your original input, and take all the resulting arrays except the last (because there will be nothing to subtract from the last array):
>>> inp = np.array([[4,4,5], [2,3,1],[1,2,0]])
>>> inp
array([[4, 4, 5],
[2, 3, 1],
[1, 2, 0]])
>>> (inp - np.roll(inp,-1,axis=0))[:-1]
array([[2, 1, 4],
[1, 1, 1]])
Or, a more straightforward way would just be to use numpy indexing:
>>> inp[:-1] - inp[1:]
array([[2, 1, 4],
[1, 1, 1]])

Resources