numpy for Numerical and Scientific Computing

Beware of copies

One has to be a bit careful with copying objects in Python. By default, if you just assign one object to a new name, it does a shallow copy, which means that both names point to the same memory. So if you change something in the original, it also changes in the new copy.
A[0,:]
array([3, 4, 2, 1, 3])
A1 = A
 A1[0,0] = 4
 A[0,0]
4

To actually create a copy that is not linked back to the original, you have to make a deep copy, which creates a new space in memory and a new pointer and copies the original object to the new memory location

A1 = A.copy()
 A1[0,0] = 6
 A[0,0]
4

You can also replace sub-matrices of a matrix with new data, provided that the dimensions are compatible. (Make sure that the sub-matrix we are replacing below truly has 2 rows and 2 columns, which is what np.eye(2) will produce)

A[:2,:2] = np.eye(2)
 A
array([[1, 0, 2, 1, 3],
       [0, 1, 1, 1, 1],
       [4, 0, 2, 0, 4]])


Reducing matrix dimensions

Sometimes the output of some operation ends up being a matrix of one column or one row. We can reduce it to become a vector. There are two functions that can do that, flatten and ravel.

A = rng.randint(0,5, (5,1))
 A
array([[2],
       [1],
       [4],
       [2],
       [4]])
A.flatten()
array([2, 1, 4, 2, 4])
A.ravel()
array([2, 1, 4, 2, 4])

So why two functions? I'm not sure, but they do different things behind the scenes. flatten creates a copy, i.e., a new array disconnected from A. ravel creates a view, so a representation of the original array. If you then changed a value after a ravel operation, you would also change it in the original array; if you did this after a flatten operation, you would not.