matrix python numpy with positif and negative value - python

i want to generate a diagonal matrix with size such as nxn

This is a toeplitz matrix, you can use SciPy's linalg.toeplitz to construct such a pattern. You can look at its implementation code here which uses from np.lib.stride_tricks.as_strided under the hood.
>>> toeplitz(-np.arange(3), np.arange(3))
array([[ 0, 1, 2],
[-1, 0, 1],
[-2, -1, 0]])
>>> toeplitz(-np.arange(6), np.arange(6))
array([[ 0, 1, 2, 3, 4, 5],
[-1, 0, 1, 2, 3, 4],
[-2, -1, 0, 1, 2, 3],
[-3, -2, -1, 0, 1, 2],
[-4, -3, -2, -1, 0, 1],
[-5, -4, -3, -2, -1, 0]])

It's quite easy to write as a custom function:
def diagonal(N):
a = np.arange(N)
return a-a[:,None]
diagonal(3)
array([[ 0, 1, 2],
[-1, 0, 1],
[-2, -1, 0]])
diagonal(6)
array([[ 0, 1, 2, 3, 4, 5],
[-1, 0, 1, 2, 3, 4],
[-2, -1, 0, 1, 2, 3],
[-3, -2, -1, 0, 1, 2],
[-4, -3, -2, -1, 0, 1],
[-5, -4, -3, -2, -1, 0]])

Related

Interchanging rows in Numpy produces an embedded array

I'm trying to interchange the rows of np.array A using the following array:
A = np.array([[0,-3,-6,4,9],
[-1,-2,-1,3,1],
[-2,-3,0,3,-1],
[1,4,5,-9,-7]])
When I use the following code:
A = np.array([A[3],A[0],A[1],A[2]])
my array becomes
array([[ 1, 4, 5, -9, -7],
[ 0, -3, -6, 4, 9],
[-1, -2, -1, 3, 1],
[-2, -3, 0, 3, -1]])
like I hoped, wished and dreamed. When I try a broader slice, though (as I would need for larger matrices), it doesn't work quite as well:
A = np.array([A[3], A[0:3]])
A
array([array([-2, -3, 0, 3, -1]),
array([[ 1, 4, 5, -9, -7],
[ 0, -3, -6, 4, 9],
[-1, -2, -1, 3, 1]])], dtype=object)
Why is this happening/how can I correctly perform this slice?
The first expression can be written much more simply as
A = A[[3, 0, 1, 2], :])
The second can therefore be written as
A = A[[3, *range(3)], :]
This is more general than using roll, since you can move an arbitrary row with something like
A = A[[1, *range(1), *range(2, 4)], :]
You could use vstack:
In [5]: np.vstack([A[3], A[0:3]])
Out[5]:
array([[ 1, 4, 5, -9, -7],
[ 0, -3, -6, 4, 9],
[-1, -2, -1, 3, 1],
[-2, -3, 0, 3, -1]])
np.roll as commented is probably the best choice. You could also use np.r_:
A[np.r_[3,0:3]]
Out:
array([[ 1, 4, 5, -9, -7],
[ 0, -3, -6, 4, 9],
[-1, -2, -1, 3, 1],
[-2, -3, 0, 3, -1]])

Finding the distance to the next higher value in pandas dataframe

I have a data frame containing floating point values
my_df = pd.DataFrame([1,2,1,4,3,2,5,4,7])
I'm trying to find for each number, when (how many indices need to move forward) till I find the next number larger than the current number, if there is no larger number, I mark it with some value (like 999999).
So for the example above, the correct answer should be
result = [1,2,1,3,2,1,2,1,999999]
Currently I've solved it by very slow double loop with itertuples (meaning O(n^2))
Is there a smarter way to do it ?
Here's a numpy based one leveraging broadcasting:
a = my_df.squeeze().to_numpy() # my_df.squeeze().values for versions 0.24.0.<
diff_mat = a - a[:,None]
result = (np.triu(diff_mat)>0).argmax(1) - np.arange(diff_mat.shape[1])
result[result <= 0] = 99999
print(result)
array([ 1, 2, 1, 3, 2, 1, 2, 1, 99999],
dtype=int64)
Where diff_mat is the distance matrix, and we're looking for the values from the main diagonal onwards, which are greater than 0:
array([[ 0, 1, 0, 3, 2, 1, 4, 3, 6],
[-1, 0, -1, 2, 1, 0, 3, 2, 5],
[ 0, 1, 0, 3, 2, 1, 4, 3, 6],
[-3, -2, -3, 0, -1, -2, 1, 0, 3],
[-2, -1, -2, 1, 0, -1, 2, 1, 4],
[-1, 0, -1, 2, 1, 0, 3, 2, 5],
[-4, -3, -4, -1, -2, -3, 0, -1, 2],
[-3, -2, -3, 0, -1, -2, 1, 0, 3],
[-6, -5, -6, -3, -4, -5, -2, -3, 0]], dtype=int64)
We have np.triu for that:
np.triu(diff_mat)
array([[ 0, 1, 0, 3, 2, 1, 4, 3, 6],
[ 0, 0, -1, 2, 1, 0, 3, 2, 5],
[ 0, 0, 0, 3, 2, 1, 4, 3, 6],
[ 0, 0, 0, 0, -1, -2, 1, 0, 3],
[ 0, 0, 0, 0, 0, -1, 2, 1, 4],
[ 0, 0, 0, 0, 0, 0, 3, 2, 5],
[ 0, 0, 0, 0, 0, 0, 0, -1, 2],
[ 0, 0, 0, 0, 0, 0, 0, 0, 3],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=int64)
And by checking which are greater than 0, and taking the argmax of the boolean ndarray we'll find the first value greater than 0 in each row:
(np.triu(diff_mat)>0).argmax(1)
array([1, 3, 3, 6, 6, 6, 8, 8, 0], dtype=int64)
We only need to subtract the corresponding offset from the main diagonal to the beginning

Transform matrix via rotation of values

How would you go about transofrming the values of a matrix from
A=
[0, 1, 2]
[-1, 0, 1]
[-2, -1, 0]
To this:
[0, -1, -2]
[1, 0, -1]
[2, 1, 0]
The operation is a mirror over the y=-x axis
In numpy, do .T:
>>> A = np.array([[0, 1, 2],
[-1, 0, 1],
[-2, -1, 0]])
>>> A.T
array([[ 0, -1, -2],
[ 1, 0, -1],
[ 2, 1, 0]])
>>>
In regular python, do zip:
>>> A = [[0, 1, 2],
[-1, 0, 1],
[-2, -1, 0]]
>>> list(zip(*A))
[(0, -1, -2), (1, 0, -1), (2, 1, 0)]
>>>

How to set array entries to zero in Python

I have an array
A = [[1, 2, 4, 0, -2, 6],
[3, 5, 4, 9, 10, -3],
[4, 6, 0, -5, 11, 2],
[0, -3, -4, 0, 12, 8]]
and I want to create another array by setting half of A entries to zero i.e.
B = [[1, 2, 4, 0, -0, 0],
[3, 5, 4, 0, 0, 0],
[4, 6, 0, 0, 0, 0],
[0, -3, -4, 0, 0, 0]]
Use numpy
import numpy as np
a = np.array([[1, 2, 4, 0, -2, 6],
[3, 5, 4, 9, 10, -3],
[4, 6, 0, -5, 11, 2],
[0, -3, -4, 0, 12, 8]])
a[:, a.shape[1]//2:] = 0
print(a)
gives
array([[ 1, 2, 4, 0, 0, 0],
[ 3, 5, 4, 0, 0, 0],
[ 4, 6, 0, 0, 0, 0],
[ 0, -3, -4, 0, 0, 0]])
To convert back to a python list, use a.tolist()
You can try something like this :
One line solution:
A = [[1, 2, 4, 0, -2, 6],
[3, 5, 4, 9, 10, -3],
[4, 6, 0, -5, 11, 2],
[0, -3, -4, 0, 12, 8]]
[item.__setitem__(item.index(value), 0)for item in A for index,value in enumerate(item[len(item)//2:])]
print(A)
output:
[[1, 2, 4, 0, 0, 0], [3, 5, 4, 0, 0, 0], [4, 6, 0, 0, 0, 0], [0, -3, -4, 0, 0, 0]]
Detailed solution:
Above list comprehension is same as:
for item in A:
for index,value in enumerate(item[len(item)//2:]):
item[item.index(value)]=0
print(A)
Using list comprehension
[[0 if i>=len(l)/2 else j for i,j in enumerate(l)] for l in A]
Output:
[[1, 2, 4, 0, 0, 0],
[3, 5, 4, 0, 0, 0],
[4, 6, 0, 0, 0, 0],
[0, -3, -4, 0, 0, 0]]
Simple solution assuming all the rows are of the same length
c = len(a[0])
[row[:c/2] + [0] * (c/2) for row in a]

Defining a multidimensional field with nonstandard domain

I have an array a in Python, let's say a=np.array([3, 4]), and would like to define an ndarray (or something like that) of type [-3:3, -4:4], in other words, a collection x of real numbers x[-3,-4], x[-3,-3],...,x[3,4], the i'th coordinate ranging over integers between -a[i] and a[i]. If the array length is given (2 in this example), I could use
np.mgrid[-a[0]:a[0]:1.0,-a[1]:a[1]:1.0][0].
But what should I do if the length of a is unknown?
You could generate a list of ranges with
[np.arange(-x,x+1) for x in a]
I'd have to play around with mgrid, or another function in index_tricks to figure how to use it. I may to make it a tuple or pass it with a *.
mgrid wants slices, so this would replicate your first call
In [60]: np.mgrid[[slice(-x,x+1) for x in [3,4]]]
Out[60]:
array([[[-3, -3, -3, -3, -3, -3, -3, -3, -3],
[-2, -2, -2, -2, -2, -2, -2, -2, -2],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[ 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 1, 1, 1, 1, 1, 1, 1, 1, 1],
[ 2, 2, 2, 2, 2, 2, 2, 2, 2],
[ 3, 3, 3, 3, 3, 3, 3, 3, 3]],
[[-4, -3, -2, -1, 0, 1, 2, 3, 4],
[-4, -3, -2, -1, 0, 1, 2, 3, 4],
[-4, -3, -2, -1, 0, 1, 2, 3, 4],
[-4, -3, -2, -1, 0, 1, 2, 3, 4],
[-4, -3, -2, -1, 0, 1, 2, 3, 4],
[-4, -3, -2, -1, 0, 1, 2, 3, 4],
[-4, -3, -2, -1, 0, 1, 2, 3, 4]]])
which of course can be generalized to use a.
My initial arange approach works with meshgrid (producing a list of arrays):
In [71]: np.meshgrid(*[np.arange(-x,x+1) for x in [3,4]],indexing='ij')
Out[71]:
[array([[-3, -3, -3, -3, -3, -3, -3, -3, -3],
[-2, -2, -2, -2, -2, -2, -2, -2, -2],
...
[-4, -3, -2, -1, 0, 1, 2, 3, 4],
[-4, -3, -2, -1, 0, 1, 2, 3, 4],
[-4, -3, -2, -1, 0, 1, 2, 3, 4]])]

Categories

Resources