Numpy get secondary diagonal with offset=1 and change the values - python

I have this 6x6 matrix filled with 0s. I got the secondary diagonal in sec_diag. The thing I am trying to do is to change the values of above the sec_diag inside the matrix with the odds numbers from 9-1 [9,7,5,3,1]
import numpy as np
x = np.zeros((6,6), int)
sec_diag = np.diagonal(np.fliplr(x), offset=1)
The result should look like this:
[[0,0,0,0,9,0],
[0,0,0,7,0,0],
[0,0,5,0,0,0],
[0,3,0,0,0,0],
[1,0,0,0,0,0],
[0,0,0,0,0,0]]
EDIT: np.fill_diagonal isn't going to work.

You should use roll
x = np.zeros((6,6),dtype=np.int32)
np.fill_diagonal(np.fliplr(x), [9,7,5,3,1,0])
xr = np.roll(x,-1,axis=1)
print(xr)
Output
[[0 0 0 0 9 0]
[0 0 0 7 0 0]
[0 0 5 0 0 0]
[0 3 0 0 0 0]
[1 0 0 0 0 0]
[0 0 0 0 0 0]]

Maybe you should try with a double loop

Related

Fill the secondary diagonal with respect to a point?

The problem is that I have a point, say P = (p1,p2), in a 2x2 numpy array in Python. Now using the point P I want to fill the all the entries in the secondary diagonal passing through with that point.
So what it looks like is:
arr = [0,0,0,0,0
0,0,0,0,0
0,0,0,0,0
0,0,0,0,0
0,0,0,0,0]
P = (1,4)
arr = [0,0,0,0,0
0,0,0,0,1
0,0,0,1,0
0,0,1,0,0
0,1,0,0,0]
or let's say P = (3,0):
arr = [0,0,0,1,0
0,0,1,0,0
0,1,0,0,0
1,0,0,0,0
0,0,0,0,0]
The array with ones is the final result required.
You can slice the array using the indices and feed it to np.fliplr and p.fill_diagonal to get the reversed diagonal
arr = np.zeros(shape=(5, 5), dtype=int)
p = (...)
np.fill_diagonal(np.fliplr(arr[p[0]:, :p[1]+1]), 1)
print(arr)
Output
p = 1, 4
[[0 0 0 0 0]
[0 0 0 0 1]
[0 0 0 1 0]
[0 0 1 0 0]
[0 1 0 0 0]]
p = 0, 3
[[0 0 0 1 0]
[0 0 1 0 0]
[0 1 0 0 0]
[1 0 0 0 0]
[0 0 0 0 0]]

Write functions resilient to variable dimension array

I'm struggling when writing a function that would seemlessly apply to any numpy arrays whatever its dimension.
At one point in my code, I have boolean arrays that I consider as mask for other arrays (0 = not passing, 1 = passing).
I would like to "enlarge" those mask arrays by overriding zeros adjacent to ones on a defined range.
Example :
input = [0,0,0,0,0,1,0,0,0,0,1,0,0,0]
enlarged_by_1 = [0,0,0,0,1,1,1,0,0,1,1,1,0,0]
enlarged_by_2 = [0,0,0,1,1,1,1,1,1,1,1,1,1,0]
input = [[0,0,0,1,0,0,1,0],
[0,1,0,0,0,0,0,0],
[0,0,0,0,0,0,1,0]]
enlarged_by_1 = [[0,0,1,1,1,1,1,1],
[1,1,1,0,0,0,0,0],
[0,0,0,0,0,1,1,1]]
This is pretty straighforward when inputs are 1D.
However, I would like this function to take seemlessy 1D, matrix, 3D, and so on.
So for a matrix, the same logic would be applied to each lines.
I read about ellipsis, but it does not seem to be applicable in my case.
Flattening the input applying the logic and reshaping the array would lead to possible contamination between individual arrays.
I do not want to go through testing the shape of input numpy array / recursive function as it does not seems very clean to me.
Would you have some suggestions ?
The operation that you are described seems very much like a convolution operation followed by clipping to ensure that values remain 0 or 1.
For your example input:
import numpy as np
input = np.array([0,0,0,0,0,1,0,0,0,0,1,0,0,0], dtype=int)
print(input)
def enlarge_ones(x, k):
mask = np.ones(2*k+1, dtype=int)
return np.clip(np.convolve(x, mask, mode='same'), 0, 1).astype(int)
print(enlarge_ones(input, k=1))
print(enlarge_ones(input, k=3))
which yields
[0 0 0 0 0 1 0 0 0 0 1 0 0 0]
[0 0 0 0 1 1 1 0 0 1 1 1 0 0]
[0 0 1 1 1 1 1 1 1 1 1 1 1 1]
numpy.convolve only works for 1-d arrays. However, one can imagine a for loop over the number of array dimensions and another for loop over each array. In other words, for a 2-d matrix first operate on every row and then on every column. You get the idea for nd-array with more dimensions. In other words the enlarge_ones would become something like:
def enlarge_ones(x, k):
n = len(x.shape)
if n == 1:
mask = np.ones(2*k+1, dtype=int)
return np.clip(np.convolve(x, mask, mode='same')[:len(x)], 0, 1).astype(int)
else:
x = x.copy()
for d in range(n):
for i in np.ndindex(x.shape[:-1]):
x[i] = enlarge_ones(x[i], k) # x[i] is 1-d
x = x.transpose(list(range(1, n)) + [0])
return x
Note the use of np.transpose to rotate the dimensions so that np.convolve is applied to the 1-d along each dimension. This is exactly n times, which returns the matrix to original shape at the end.
x = np.zeros((3, 5, 7), dtype=int)
x[1, 2, 2] = 1
print(x)
print(enlarge_ones(x, k=1))
[[[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]]
[[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 1 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]]
[[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]
[0 0 0 0 0 0 0]]]
[[[0 0 0 0 0 0 0]
[0 1 1 1 0 0 0]
[0 1 1 1 0 0 0]
[0 1 1 1 0 0 0]
[0 0 0 0 0 0 0]]
[[0 0 0 0 0 0 0]
[0 1 1 1 0 0 0]
[0 1 1 1 0 0 0]
[0 1 1 1 0 0 0]
[0 0 0 0 0 0 0]]
[[0 0 0 0 0 0 0]
[0 1 1 1 0 0 0]
[0 1 1 1 0 0 0]
[0 1 1 1 0 0 0]
[0 0 0 0 0 0 0]]]

using 1's in the arrays to make a shape like '+' using numpy in python

Numpy Three Four Five Dimensional Array in Python
Input 1: 3
Output 1:
[[0 1 0]
[1 1 1]
[0 1 0]]
Input 2:5
Output 1:
[[0 0 1 0 0]
[0 0 1 0 0]
[1 1 1 1 1]
[0 0 1 0 0]
[0 0 1 0 0]]
Notice that the 1s in the arrays make a shape like +.
My logic is shown below
a=np.zeros((n,n),dtype='int')
a[-3,:] = 1
a[:,-3] = 1 print(a)
This logic is only working for five dimensional array but not for three dimensional array.
can someone assist me to get the expected output for both three and five dimensional array using np.zeros & integer division //
As you can see, n//2 = 3 when n=5. So, that's the solution to your question as see here:
import numpy as np
def create_plus_matrix(n):
a = np.zeros((n,n),dtype='int')
a[-n//2,:] = 1
a[:,-n//2] = 1
return a
So, let's try it out:
>>> create_plus_matrix(3)
[[0 1 0]
[1 1 1]
[0 1 0]]
>> create_plus_matrix(5)
[[0 0 1 0 0]
[0 0 1 0 0]
[1 1 1 1 1]
[0 0 1 0 0]
[0 0 1 0 0]]
Do this
import numpy as np
def plus(size):
a = np.zeros([size,size], dtype = int)
a[int(size/2)] = np.ones(size)
for i in a:
i[int(size/2)] = 1
return a
print(plus(3)) //3 is the size
//Output
[[0 1 0]
[1 1 1]
[0 1 0]]

Can i change value of Adjacency Matrix on Python Programming?

I have problem with my code, i cannot print or change value of Adjacency matrix, can you help me sir?
i have code like this
for i in range(len(A.todense())):
for j in A[i].todense()*1:
print(j)
and the output is
[[0 0 0 0 0 1 1 0]]
[[0 0 0 0 0 0 0 1]]
[[0 0 0 0 0 1 0 0]]
[[0 0 0 0 0 1 0 0]]
[[0 0 0 0 0 0 0 1]]
[[1 0 1 1 0 0 1 0]]
[[1 0 0 0 0 1 0 0]]
[[0 1 0 0 1 0 0 0]]
and want to change zero to one, or one to zero, but i cannot print or change with A.todense()[i][j]. Can you help me to change the value of adjacency matrix? Thanks you
top up saldo paypal
You can't change value in Adjancency matrix, so that you have to convert to numpy or other array type that can change value.
One Solution Below
A = np.array(A.data)
for i in range(len(A)):
for j in range(len(A[i])):
if A[i][j] == 0:
A[i][j] = 1
else:
A[i][j] = 0
That will change values and then convert to Adjancency matrix.

find mean position and area of labelled objects

I have a 2D labeled image (numpy array), each label represents an object. I have to find the object's center and its area. My current solution:
centers = [np.mean(np.where(label_2d == i),1) for i in range(1,num_obj+1)]
surface_area = np.array([np.sum(label_2d == i) for i in range(1,num_obj+1)])
Note that label_2d used for centers is not the same as the one for surface area, so I can't combine both operations. My current code is about 10-100 times to slow.
In C++ I would iterate through the image once (2 for loops) and fill the table (an array), from which I would than calculate centers and surface area.
Since for loops are quite slow in python, I have to find another solution. Any advice?
You could use the center_of_mass function present in scipy.ndimage.measurements for the first problem and then use np.bincount for the second problem. Because these are in the mainstream libraries, they will be heavily optimized, so you can expect decent speed gains.
Example:
>>> import numpy as np
>>> from scipy.ndimage.measurements import center_of_mass
>>>
>>> a = np.zeros((10,10), dtype=np.int)
>>> # add some labels:
... a[3:5, 1:3] = 1
>>> a[7:9, 0:3] = 2
>>> a[5:6, 4:9] = 3
>>> print(a)
[[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 1 1 0 0 0 0 0 0 0]
[0 1 1 0 0 0 0 0 0 0]
[0 0 0 0 3 3 3 3 3 0]
[0 0 0 0 0 0 0 0 0 0]
[2 2 2 0 0 0 0 0 0 0]
[2 2 2 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]]
>>>
>>> num_obj = 3
>>> surface_areas = np.bincount(a.flat)[1:]
>>> centers = center_of_mass(a, labels=a, index=range(1, num_obj+1))
>>> print(surface_areas)
[4 6 5]
>>> print(centers)
[(3.5, 1.5), (7.5, 1.0), (5.0, 6.0)]
Speed gains depend on the size of your input data though, so I can't make any serious estimates on that. Would be nice if you could add that info (size of a, number of labels, timing results for the method you used and these functions) in the comments.

Categories