Gvien two arrays with identical entries but different orders, is there a way to find the index mapping which would rearrange one array such that it is equivalent to the other?
i.e.
x1 = np.array([[1,2],
[3,4],
[5,6],
[7,8],
[9,10]])
x2 = np.array([[3,4],
[7,8],
[1,2],
[5,6],
[9,10]])
The mapping from x1
to x2
would be np.array([1,3,0,2,4])
, and the mapping from x2
to x1
would be np.array([2,0,3,1,4])
Note, in this example x1 is sorted, however I do not wish to make this assumption in general.
CodePudding user response:
Assuming the first array's elements are sorted as in the example, an efficient option would be to view the two-column arrays as 1d arrays of tuples, and use np.searchsorted
to find the indices where these tuples are in x2_view
:
x1_view = x1.view(dtype='i,i').ravel()
x2_view = x2.view(dtype='i,i').ravel()
np.searchsorted(x1_view, x2_view)
# array([1, 3, 0, 2, 4], dtype=int64)
In the case the first array is not sorted, you can pass np.searchsorted
a sorter
:
x1_sorted_view = np.argsort(x1_view)
np.searchsorted(x1_view, x2_view, sorter=x1_sorted_view)
For the second case, you only need np.argsort
on x2
:
np.argsort(x2_view)
# array([2, 0, 3, 1, 4], dtype=int64)
CodePudding user response:
Using array comprehension this is what I do:
x1_in_x2 = [x2.index(e) for e in x1]
ButI do now know if this is what you expect. Please confirm If I understood you correctly
CodePudding user response:
I don't know much about numpy, but here's one janky way to do it with just Python lists:
x1 = [[1, 2],
[3, 4],
[5, 6],
[7, 8],
[9, 10]]
x2 = [[3, 4],
[7, 8],
[1, 2],
[5, 6],
[9, 10]]
map_1_to_2 = []
map_2_to_1 = []
for element_1, element_2 in zip(x1, x2):
map_1_to_2.append(x2.index(element_1))
map_2_to_1.append(x1.index(element_2))
print(map_1_to_2)
print(map_2_to_1)
CodePudding user response:
There are several ways to create order of indices. They could be summarised as follows:
def find_mappings(sidx1, sidx2):
x1_to_x2 = np.empty(len(x1), dtype=x1.dtype)
x2_to_x1 = np.empty(len(x1), dtype=x1.dtype)
x1_to_x2[sidx2] = sidx1
x2_to_x1[sidx1] = sidx2
return x1_to_x2, x2_to_x1
So you could pass sorting indices like so:
sidx1 = np.lexsort(x1.T[::-1])
sidx2 = np.lexsort(x2.T[::-1])
find_mappings(sidx1, sidx2)
>>> (array([1, 3, 0, 2, 4]), array([2, 0, 3, 1, 4]))
There should be also a way to pass sidx1
and sidx2
it using np.searchsorted
(possibly with sorter
parameter) creating views but yatu
's example is not working for me as expected. I believe there are also alternative (and more effective) ways such as np.argsort
of reduced dimensions but they are more difficult to implement.
Note that in case sidx1
or sidx2
is np.arange(len(x1))
(in case you are attempting to use np.searchsorted
) you could omit some excessive commands in definition of find_mappings
.