How to do an index increment for my case? - python

I have to find the minimum for each column in a matrix, but there are two rules;
Each column will start from the "index+1" of the previous column, except for the first column
If one of the columns has exactly the index equal to the total number of rows of the matrix, then the rest indices for all the columns will be equal to the number of rows
As an example;
[[ "-1". -11. 0. 8. 1. ]
[ 2. 1. 0. 5. 1. ]
[ 4. 1. -2. 6. 7. ]
[ 8. 3. 1. 3. 0. ]
[ 5. "0". 1. 0. 8. ]
[ 9. 3. "-1". -1. 6.5]
[ 5. 3. 2. 5. 3. ]
[ 10. 3. 7. "1". "-1". ]]
The indices are inside quotations, [0,4,5,7,7]
Another example;
[[ 1. 1. 0. 0. 1.]
[ 2. 1. 0. 5. 1.]
[-4. -1. 2. 6. 7.]
['-5' 3. 1. 1. 0.]
[ 5. '0'. 1. 0. 8.]
[ 5. 3. '-1'. -1. 0.]
[ 5. 3. 1. '1'. 0.]
[ 5. 3. 1. 1. 0.]]
The indices here are [3,4,5,6,7]
I tried to do the following, but I am having errors. Could you please tell me how to do so?
def lst_min(matrix, columnindex, minIndex):
if minIndex == matrix.shape[0]:
return matrix.shape[0]
else:
return np.argmin(matrix[minIndex:, columnindex]) + minIndex
currentMinIndex = 0
lst = []
for i in range(a.shape[1]):
w = lst_min(matrix=a, columnindex=i, minIndex=currentMinIndex)
if w > a.shape[0]:
w = a.shape[0]
lst.append(w)
if w == 0:
c = 1
currentMinIndex = w + c
if currentMinIndex > a.shape[0]:
currentMinIndex = a.shape[0]

Your code use lst.append(w) with some strange logic...
You use lst_min to find minimum index but you simply return matrix.shape[0] when currentMinIndex = 0 (minIndex == matrix.shape[0]) at start.
FIY,
# post source code next time if you can,
# it will be really helpful to others to run your question easily
# and focus on the main problem quickly.
a = np.array(
[[ -1, -11, 0, 8, 1. ],
[ 2, 1, 0, 5, 1. ],
[ 4, 1, -2, 6, 7. ],
[ 8, 3, 1, 3, 0. ],
[ 5, 0, 1, 0, 8. ],
[ 9, 3, -1, -1, 6.5],
[ 5, 3, 2, 5, 3. ],
[ 10, 3, 7, 1, -1. ]]
)
b = np.array(
[[ 1, 1, 0, 0, 1],
[ 2, 1, 0, 5, 1],
[-4, -1, 2, 6, 7],
[-5, 3, 1, 1, 0],
[ 5, 0, 1, 0, 8],
[ 5, 3, -1, -1, 0],
[ 5, 3, 1, 1, 0],
[ 5, 3, 1, 1, 0]]
)
lst = []
start_idx = 0
for vec in a.T: # forloop column-wise
if start_idx >= vec.shape[0]-1: # index compare shape, should -1
lst.append(vec.shape[0]-1) # put the last index
else: # find minimum index
min_idx = np.argmin(vec[start_idx:]) # slice it
start_idx += min_idx # add back the true index
lst.append(start_idx) # append to result
start_idx += 1 # next column, use index + 1 (your rule 1)
if start_idx >= vec.shape[0]-1: # but if it is larger or equal, fit it back for next column use
start_idx = vec.shape[0]-1
The results should be:
>>>lst
[0, 4, 5, 7, 7]
# code change to b.T
>>>lst
[3, 4, 5, 6, 7]

Related

Find all the rectangles coordinates in a numpy 2d array ( prioritizing the vertical rectangles)

I am trying to figure out a solution for finding all the rectangles in a 2d array.
But in the mean while, I need to get the vertical ones first.
For example:
[[0. 0. 1. 0. 0.]
[0. 0. 0. 1. 1.]
[0. 0. 1. 1. 1.]]
The desire output would be
[[0, 2, 0, 2], [2, 2, 2, 2], [1, 3, 2, 4]]
Or something like
[[1. 0. 0. 0. 0.]
[1. 1. 0. 1. 1.]
[1. 1. 1. 1. 0.]]
Output should be
[[0, 0, 0, 0], [1, 0, 2, 1], [2, 2, 2, 2], [1, 3, 2, 3], [1, 4, 1, 4]]
In other words, if it's a horizontal rectangle of the height of only 1, it is viewed as multiple 11.
I am kind of stuck on the logic which should proceed first, my results prioritize the horizontal ones and have troubles dealing with zeros when encounter a 2*2 or above rectangle.
UPDATE
A rectangle in here means an area composed of 1s in the 2d array. However when something like
[[0. 0. 0. 0. 0.]
[0. 0. 0. 1. 1.]
[0. 0. 0. 1. 0.]]
happens, the output should be
[[1, 3, 2, 3], [1, 4, 1, 4]]
instead of
[[1, 3, 1, 4], [2, 3, 2, 3]]
1*1 counts as a rectangle too
The code I have for now looks like this
def solve2(grid):
output = []
visited = set()
for j in range(len(grid[0])):
for i in range(len(grid)):
if (i,j) in visited:
continue
visited.add((i,j))
if grid[i][j] == 1:
s_row, s_col = i, j
e_row, e_col = i,j
while e_col < len(grid[0]) and grid[i][e_col]:
while e_row < len(grid) and grid[e_row][j]:
e_row += 1
e_col += 1
for x in range(s_row, e_row):
for y in range(s_col, e_col):
visited.add((x,y))
e_row -= 1
e_col -= 1
output.append([s_row, s_col, e_row, e_col])
return output

Python3: Remove array elements with same coordinate (x,y)

I have this array (x,y,f(x,y)):
a=np.array([[ 1, 5, 3],
[ 4, 5, 6],
[ 4, 5, 6.1],
[ 1, 3, 42]])
I want to remove the duplicates with same x,y. In my array I have (4,5,6) and (4,5,6.1) and I want to remove one of them (no criterion).
If I had 2 columns (x,y) I could use
np.unique(a[:,:2], axis = 0)
But my array has 3 columns and I don't see how to do this in a simple way.
I can do a loop but my arrays can be very large.
Is there a way to do this more efficiently?
If I understand correctly, you need this:
a[np.unique(a[:,:2],axis=0,return_index=True)[1]]
output:
[[ 1. 3. 42.]
[ 1. 5. 3.]
[ 4. 5. 6.]]
Please be mindful that it does not keep the original order of rows in a. If you want to keep the order, simply sort the indices:
a[np.sort(np.unique(a[:,:2],axis=0,return_index=True)[1])]
output:
[[ 1. 5. 3.]
[ 4. 5. 6.]
[ 1. 3. 42.]]
I think you want to do this?
np.rint will round your numbers to an integer
import numpy as np
a = np.array([
[ 1, 5, 3],
[ 4, 5, 6],
[ 4, 5, 6.1],
[ 1, 3, 42]
])
a = np.unique(np.rint(a), axis = 0)
print(a)
//result :
[[ 1. 3. 42.]
[ 1. 5. 3.]
[ 4. 5. 6.]]

Compare neighbours boolean numpy array in grid

I want to write a function which compares the 8 neighbours of a node in my grid. When minimum of 3 of the neighbours have the same value as the central node, we can define the node as happy.
for example in this array the central node and value is 0, we see that it has 3 neighbours of 0, so the node is happy:
array([[ 1, 0, 1],
[ 1, 0, 1],
[-1, 0, 0]])
I expect an boolean output with True or False.
Can I think of something like this or can I use easily numpy for this?
def nodehappiness(grid, i, j, drempel=3):
if i,j => 3:
node == True
Thanks in advance
Try this:
def neighbours(grid, i, j):
rows = np.array([-1, -1, -1, 0, 0, 1, 1, 1])
cols = np.array([-1, 0, 1, -1, 1, -1, 0, 1])
return grid[rows+i,cols+j]
Edit: Example:
grid = np.arange(25).reshape((5,5))
#array([[ 0, 1, 2, 3, 4],
# [ 5, 6, 7, 8, 9],
# [10, 11, 12, 13, 14],
# [15, 16, 17, 18, 19],
# [20, 21, 22, 23, 24]])
neighbours(grid, 0, 0)
# array([24, 20, 21, 4, 1, 9, 5, 6])
Explanation:
With numpy you can use negative indices allowing you to easily access the last entries of an array. This will also work for multiple dimensions:
x = np.array([0,1,2,3])
x[-1]
# 3
x.reshape((2,2))
#array([[0, 1],
# [2, 3]])
x[-1,-1]
# 3
You are interested in 8 entries of the matrix.
left above -> row - 1, column - 1
above -> row - 1, column + 0
right above -> row - 1, column + 1
left -> row + 0, column - 1
...
Thats what the arrays rows and cols represent. By adding i and j you get all the entries around these coordinates.
Try this.
y=[]
l= len(x)
for i in range(0,l):
for j in range(0,l):
if i==int(l/2) and j==int(l/2):
continue
y.append(x[j,i])
You search something like this?
def neighbour(grid, i, j):
return np.delete((grid[i-1:i+2,j-1:j+2]).reshape(1,9),4)
# Test code
grid = np.arange(16).reshape(4,4)
b = neighbour(m, 2, 2)
Some hackery using ndimage.generic_filter:
from scipy import ndimage
def get_neighbors(arr):
output = []
def f(x):
output.append(x)
return 0
t = tuple(int((x - 1) / 2) for x in arr.shape)
footprint = np.ones_like(arr)
footprint[t] = 0
ndimage.generic_filter(arr, f, footprint=footprint, mode='wrap')
return np.array(output)
arr = np.arange(9).reshape(3, 3)
neighbors = get_neighbors(arr)
neighbors_grid = neighbors.reshape(*arr.shape, -1)
print(neighbors)
print(neighbors_grid)
Which prints:
# neighbors
[[8. 6. 7. 2. 1. 5. 3. 4.]
[6. 7. 8. 0. 2. 3. 4. 5.]
[7. 8. 6. 1. 0. 4. 5. 3.]
[2. 0. 1. 5. 4. 8. 6. 7.]
[0. 1. 2. 3. 5. 6. 7. 8.]
[1. 2. 0. 4. 3. 7. 8. 6.]
[5. 3. 4. 8. 7. 2. 0. 1.]
[3. 4. 5. 6. 8. 0. 1. 2.]
[4. 5. 3. 7. 6. 1. 2. 0.]]
# neighbors_grid
[[[8. 6. 7. 2. 1. 5. 3. 4.]
[6. 7. 8. 0. 2. 3. 4. 5.]
[7. 8. 6. 1. 0. 4. 5. 3.]]
[[2. 0. 1. 5. 4. 8. 6. 7.]
[0. 1. 2. 3. 5. 6. 7. 8.]
[1. 2. 0. 4. 3. 7. 8. 6.]]
[[5. 3. 4. 8. 7. 2. 0. 1.]
[3. 4. 5. 6. 8. 0. 1. 2.]
[4. 5. 3. 7. 6. 1. 2. 0.]]]
If you merely want the padded array:
padded = np.pad(arr, pad_width=1, mode='wrap')
print(padded)
Which of course gives:
[[8 6 7 8 6]
[2 0 1 2 0]
[5 3 4 5 3]
[8 6 7 8 6]
[2 0 1 2 0]]

How to invert only negative elements in numpy matrix?

I have a matrix containing positive and negative numbers like this:
>>> source_matrix
array([[-4, -2, 0],
[-5, 0, 4],
[ 0, 6, 5]])
I'd like to had a copy of this matrix with inverted negatives:
>>> result
array([[-0.25, -0.5, 0],
[-0.2, 0, 4],
[ 0, 6, 5]])
Firstly, since your desired array is gonna contain float type you need to determine the array's dtype at creation time as float. The reason for that is because if you assign the float results of the inverted sub-array they'll automatically be casted to float. Secondly, you need to find the negative numbers in your array and then use a simple indexing in order to grab them and use np.true_divide() to perform the inversion.
In [25]: arr = np.array([[-4, -2, 0],
...: [-5, 0, 4],
...: [ 0, 6, 5]], dtype=np.float)
...:
...:
In [26]: mask = arr < 0
In [27]: arr[mask] = np.true_divide(1, arr[mask])
In [28]: arr
Out[28]:
array([[-0.25, -0.5 , 0. ],
[-0.2 , 0. , 4. ],
[ 0. , 6. , 5. ]])
You can also achieve this without masking, by using the where and out params of true_divide.
a = np.array([[-4, -2, 0],
[-5, 0, 4],
[ 0, 6, 5]], dtype=np.float)
np.true_divide(1, a, out=a, where=a<0)
Giving the result:
array([[-0.25, -0.5 , 0. ],
[-0.2 , 0. , 4. ],
[ 0. , 6. , 5. ]])
The where= parameter is passed an array of the same dimensions as your two inputs. Where this evaluates to True the divide is performed. Where it evaluates to False, the original input, passed in via out= is output into the result unchanged.

Python - add 1D-array as column of 2D

I want to add a vector as the first column of my 2D array which looks like :
[[ 1. 0. 0. nan]
[ 4. 4. 9.97 1. ]
[ 4. 4. 27.94 1. ]
[ 2. 1. 4.17 1. ]
[ 3. 2. 38.22 1. ]
[ 4. 4. 31.83 1. ]
[ 3. 4. 41.87 1. ]
[ 2. 1. 18.33 1. ]
[ 4. 4. 33.96 1. ]
[ 2. 1. 5.65 1. ]
[ 3. 3. 40.74 1. ]
[ 2. 1. 10.04 1. ]
[ 2. 2. 53.15 1. ]]
I want to add an aray [] of 13 elements as the first column of the matrix. I tried with np.stack_column, np.append but it is for 1D vector or doesn't work because I can't chose axis=1 and only do np.append(peak_values, results)
I have a very simple option for you using numpy -
x = np.array( [[ 3.9427767, -4.297677 ],
[ 3.9427767, -4.297677 ],
[ 3.9427767, -4.297677 ],
[ 3.9427767, -4.297677 ],
[ 3.942777 , -4.297677 ],
[ 3.9427767, -4.297677 ],
[ 3.9427767, -4.297677 ],
[ 3.9427767 ,-4.297677 ],
[ 3.9427767, -4.297677 ],
[ 3.9427772 ,-4.297677 ]])
b = np.arange(10).reshape(-1,1)
np.concatenate((b.T, x), axis=1)
Output-
array([[ 0. , 3.9427767, -4.297677 ],
[ 1. , 3.9427767, -4.297677 ],
[ 2. , 3.9427767, -4.297677 ],
[ 3. , 3.9427767, -4.297677 ],
[ 4. , 3.942777 , -4.297677 ],
[ 5. , 3.9427767, -4.297677 ],
[ 6. , 3.9427767, -4.297677 ],
[ 7. , 3.9427767, -4.297677 ],
[ 8. , 3.9427767, -4.297677 ],
[ 9. , 3.9427772, -4.297677 ]])
Improving on this answer by removing the unnecessary transposition, you can indeed use reshape(-1, 1) to transform the 1d array you'd like to prepend along axis 1 to the 2d array to a 2d array with a single column. At this point, the arrays only differ in shape along the second axis and np.concatenate accepts the arguments:
>>> import numpy as np
>>> a = np.arange(12).reshape(3, 4)
>>> b = np.arange(3)
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> b
array([0, 1, 2])
>>> b.reshape(-1, 1) # preview the reshaping...
array([[0],
[1],
[2]])
>>> np.concatenate((b.reshape(-1, 1), a), axis=1)
array([[ 0, 0, 1, 2, 3],
[ 1, 4, 5, 6, 7],
[ 2, 8, 9, 10, 11]])
For the simplest answer, you probably don't even need numpy.
Try the following:
new_array = []
new_array.append(your_array)
That's it.
I would suggest using Numpy. It will allow you to easily do what you want.
Here is an example of squaring the entire set. you can use something like nums[0].
nums = [0, 1, 2, 3, 4]
even_squares = [x ** 2 for x in nums if x % 2 == 0]
print even_squares # Prints "[0, 4, 16]"

Categories