Merge between two elements of an array - python

I have the following example array:
[[ 3, 5, 6],
[ 4, -1, -1],
[ 5, 7, -1],
[ 1, 6, -1],
[ 1, 0, 6],
[ 3, 4, 8],
[ 2, 3, 5],
[ 2, -1, -1],
[ 0, 4, 5],
[ 0, 5, -1]]
I am trying to:
merge two of the elements into one (in this case elements idx 2 and 4)
delete duplicates in the merged element (if any)
move any (-1) to the end of the element
supplement the rest of the elements with (-1) to pertain the rectangle shape and symmetry of the array
move merged element to position 0, like in the example below:
[[ 5, 7, 1, 0, 6, -1],
[ 3, 5, 6, -1, -1, -1],
[ 4, -1, -1, -1, -1, -1],
[ 1, 6, -1, -1, -1, -1],
[ 3, 4, 8, -1, -1, -1],
[ 2, 3, 5, -1, -1, -1],
[ 2, -1, -1, -1, -1, -1],
[ 0, 4, 5, -1, -1, -1],
[ 0, 5, -1, -1, -1, -1]]
Please suggest possible solution.

I'm not sure why people are saying your question is unclear (it's quite clear IMO), but here is a function that can merge any of the two elements like you specified:
import pprint
def move_n1_to_end(row): #function that moves all -1's to the end
n1_count = 0
for i in row:
if i==-1:
n1_count += 1
new_row = [e for e in row if e != -1]
new_row.extend([-1] * n1_count)
return new_row
def merge_move(arr, idx1, idx2):
merged_list = [*dict.fromkeys(arr[idx1] + arr[idx2])] #merge and remove duplicates
merged_list = move_n1_to_end(merged_list) #move -1's to the end
#removes the two lists that were merged
arr = [arr[i] for i in range(len(arr)) if i not in [idx1, idx2]]
#make a copy of the merged list (essentially moves it to the front of the new matrix)
new_arr = [merged_list[:]]
#find the maximum length of all the rows
max_length = max(len(e) for e in arr + new_arr)
for i in range(len(arr)): #for each index of the original matrix...
#set row to the i'th row
row = arr[i]
#move all -1's to the end
row = move_n1_to_end(row)
#insert -1's at the end of each row to make the matrix rectangular
new_arr.append(row + [-1] * (max_length-len(row)))
#append the result to the new matrix
return new_arr #return the resulting matrix
test_matrix = [[ 3, 5, 6],
[ 4, -1, -1],
[ 5, 7, -1],
[ 1, 6, -1],
[ 1, 0, 6],
[ 3, 4, 8],
[ 2, 3, 5],
[ 2, -1, -1],
[ 0, 4, 5],
[ 0, 5, -1]]
pprint.pprint(merge_move(test_matrix, 2, 4))
"""
Output:
[[5, 7, 1, 0, 6, -1],
[3, 5, 6, -1, -1, -1],
[4, -1, -1, -1, -1, -1],
[1, 6, -1, -1, -1, -1],
[3, 4, 8, -1, -1, -1],
[2, 3, 5, -1, -1, -1],
[2, -1, -1, -1, -1, -1],
[0, 4, 5, -1, -1, -1],
[0, 5, -1, -1, -1, -1]]
"""

Related

matrix python numpy with positif and negative value

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]])

Fill specific values of a numpy array (master) with values from another numpy array (slave) from same index position [duplicate]

This question already has answers here:
fastest way to replace values in an array with the value in the same position in another array if they match a condition
(2 answers)
Closed 1 year ago.
I prepared a mini example for my question.
Assume we have a master numpy array
master =
array([[-1, -1, -1, 2, 2, 2],
[-1, -1, -1, 2, 2, 2],
[-1, -1, -1, 2, 2, 2],
[ 2, 2, 2, -1, -1, -1],
[ 2, 2, 2, -1, -1, -1],
[ 2, 2, 2, -1, -1, -1]])
Secondly we have a slave numpy array with the exact same shape:
slave=
array([[-1, -1, -1, 3, 3, 3],
[-1, -1, -1, 3, 3, 3],
[-1, -1, -1, 3, 3, 3],
[ 3, 3, 3, 3, 3, 3],
[ 3, 3, 3, 3, 3, 3],
[ 3, 3, 3, 3, 3, 3]])
What I'm looking for is the following:
result = fill master array with slave values where master = -1
result=
array([[-1, -1, -1, 2, 2, 2],
[-1, -1, -1, 2, 2, 2],
[-1, -1, -1, 2, 2, 2],
[ 2, 2, 2, 3, 3, 3],
[ 2, 2, 2, 3, 3, 3],
[ 2, 2, 2, 3, 3, 3]])
In my real world scenario I have dozens of arrays with more than 12 million values each and they all have nodata values on different places. I want to fill the master array with the other arrays, where master values are nodata.
I really searched and tried a lot, like extract boolean masks but I really do not know how to fill on the exact same index coordinates without iterating over all single cells.
Would be great if I get help from you...
np.where can take arrays as arguments hence:
result = np.where(master == -1, slave, master)
Use:
result = np.where(master == -1, slave, master)
Use numpy.where:
result = np.where(master==-1, slave, master)
output:
array([[-1, -1, -1, 2, 2, 2],
[-1, -1, -1, 2, 2, 2],
[-1, -1, -1, 2, 2, 2],
[ 2, 2, 2, 3, 3, 3],
[ 2, 2, 2, 3, 3, 3],
[ 2, 2, 2, 3, 3, 3]])

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

get one array from vectors - python

I am struggling with this problem for some time and i dont find a solution. I try to plot a heatmap and have read some stuff but the problems are different.
I have 3 Vectors:
x = [ -1, 0, 1, -1, 0, 1, 0, -1, 1 ]
y = [ -1, -1, -1, 0, 0, 0, 1, 1, 1 ]
E = [ 3, 1, 4, 1, 5, 9, 6, 2, 5 ]
What i want is a matrix like the one below for the actual plotting:
E_xy = [ [ 3, 1, 4],
[ 1, 5, 9],
[ 2, 6, 5]]
x[0] belongs to y[0] belongs to E[0] and so on.
What is the best/easiest way to do this?
Please note: The ordering of the matrix can not be used (see E[7] and E[8] and the resulting E_xy[2,0] and E_xy[2,1]).
Assuming a square NxN matrix
import numpy as np
x = np.array([ -1, 0, 1, -1, 0, 1, 0, -1, 1 ])
y = np.array([ -1, -1, -1, 0, 0, 0, 1, 1, 1 ])
E = np.array([ 3, 1, 4, 1, 5, 9, 6, 2, 5 ])
N = int(np.sqrt(E.size))
sorting = np.argsort(x + y*N)
E_xy = E[sorting].reshape(N,N)
Interpreting your x and y lists as definitions of positional offsets in relation to the matrix' center element, you can first create tuples containing your positions and then fill everything into a newly created matrix of desired dimensions:
x = [ -1, 0, 1, -1, 0, 1, 0, -1, 1 ]
y = [ -1, -1, -1, 0, 0, 0, 1, 1, 1 ]
E = [ 3, 1, 4, 1, 5, 9, 6, 2, 5 ]
positions = [
(x[i] + 1, y[i] + 1, E[i])
for i in range(len(x))
]
result = [
[None] * 3 for _ in range(3)
]
for x, y, value in positions:
result[y][x] = value
print(result)
Note that this is not a general solution; it assumes the matrix to always be 3x3; it requires changes to make this a general approach for arbitrarily shaped matrices.
The above code prints:
>>> [[3, 1, 4], [1, 5, 9], [2, 6, 5]]
Additionally, the above code surely can be written more efficient, but would lose in readability then; so it's up to you to save on memory, if you need to (if matrices are growing large).

How would I sort a hierarchical list into a tree/pyrimid model of dicts?

I am trying to generate a hierarchy of dicts to use to create a Tree Model in Qt.
The data is in a list with each entry being [Next Sibling, Previous Sibling, First_Child, Parent] and the index of the element in the list is the name/index of the contour described by the hierarchy entry.
For example if I were to input the hierarchy from section 4.RETR_TREE here
hierarchy =
array([[[ 7, -1, 1, -1],
[-1, -1, 2, 0],
[-1, -1, 3, 1],
[-1, -1, 4, 2],
[-1, -1, 5, 3],
[ 6, -1, -1, 4],
[-1, 5, -1, 4],
[ 8, 0, -1, -1],
[-1, 7, -1, -1]]])
I would like to get this output:
{0:{1:{2:{3:{4:{5:{},6:{}}}}}},
7:{},
8:{}}
I am looking to do this to build a tree model in Qt so I can easily see which contours contain which others. If you have a better idea of how to turn the hierarchy data into a Qt tree model that would also be appreciated.
Thanks in advance!
Similar to #uselpa I'm coming up with a solution that does not sort nodes having the same parent node, since a Python dictionary has no fixed order:
import numpy as np
H = np.array(
[[ 7, -1, 1, -1],
[-1, -1, 2, 0],
[-1, -1, 3, 1],
[-1, -1, 4, 2],
[-1, -1, 5, 3],
[ 6, -1, -1, 4],
[-1, 5, -1, 4],
[ 8, 0, -1, -1],
[-1, 7, -1, -1]])
def T(i):
children = [(h, j) for j, h in enumerate(H) if h[3] == i]
children.sort(key = lambda h: h[0][1])
return {c[1]: T(c[1]) for c in children}
print T(-1)
Output:
{0: {1: {2: {3: {4: {5: {}, 6: {}}}}}}, 8: {}, 7: {}}
Thus you can skip sorting the children and end up with the following compact code:
T = lambda i: {j: T(j) for j, h in enumerate(H) if h[3] == i}
print T(-1)
I not familiar with Qt, numpy or opencv so I'm probably missing something here, but I'll give it a try anyway.
The following algorithm creates the dictionary as requested:
def make_hdict(hier):
def recur(parent):
res = {}
for i,n in enumerate(hier):
if n[3] == parent:
res[i] = recur(i)
return res
return recur(-1)
Testing:
hierarchy = [[ 7, -1, 1, -1], #0
[-1, -1, 2, 0], #1
[-1, -1, 3, 1], #2
[-1, -1, 4, 2], #3
[-1, -1, 5, 3], #4
[ 6, -1, -1, 4], #5
[-1, 5, -1, 4], #6
[ 8, 0, -1, -1], #7
[-1, 7, -1, -1]] #8
print(make_hdict(hierarchy))
=> {0: {1: {2: {3: {4: {5: {}, 6: {}}}}}}, 8: {}, 7: {}}
As you can see, I only use the last field ("Parent") at this point.
In particular,
I am not using "next sibling" and "previous sibling" since a dictionary is unordered
I am not using "first child" since it is redundant information.
Is that what you want?

Categories

Resources