Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find closest elements in two array?

I have two numpy arrays, like X=[x1,x2,x3,x4], y=[y1,y2,y3,y4]. Three of the elements are close and the fourth of them maybe close or not.

Like:

X   [ 84.04467948  52.42447842  39.13555678  21.99846595]
y   [ 78.86529444  52.42447842  38.74910101  21.99846595]

Or it can be:

X   [ 84.04467948  60  52.42447842  39.13555678]
y   [ 78.86529444  52.42447842  38.74910101  21.99846595]

I want to define a function to find the the corresponding index in the two arrays, like in first case:

  • y[0] correspond to X[0],
  • y[1] correspond to X[1],
  • y[2] correspond to X[2],
  • y[3] correspond to X[3]

And in second case:

  • y[0] correspond to X[0],
  • y[1] correspond to X[2],
  • y[2] correspond to X[3]
  • and y[3] correspond to X[1].

I can't write a function to solve the problem completely, please help.

like image 816
insomnia Avatar asked Aug 22 '16 11:08

insomnia


People also ask

How do you find the closest pair of an array?

Traverse the array and for each i, do the following : Find the lower bound for x/arr[i] in the sub-array on the right of arr[i], i.e., in subarray arr[i+1..n-1]. Let it be denoted by l. Find the upper bound for x/arr[i] in the sub array on the right of arr[i], i.e., in sub array arr[i+1..n-1].

How do you find the element of two arrays?

Approach: Add all elements of first array into a hashset. Iterate the second array and check whether element present in hashset using contains method. If contains == true, add the element to result in array.

How do I find the closest number in an array in C?

So if the array is like [2, 5, 6, 7, 8, 8, 9] and the target number is 4, then closest element is 5. We can solve this by traversing through the given array and keep track of absolute difference of current element with every element. Finally return the element that has minimum absolute difference.


2 Answers

You can start by precomputing the distance matrix as show in this answer:

import numpy as np

X = np.array([84.04467948,60.,52.42447842,39.13555678])
Y = np.array([78.86529444,52.42447842,38.74910101,21.99846595])

dist = np.abs(X[:, np.newaxis] - Y)

Now you can compute the minimums along one axis (I chose 1 corresponding to finding the closest element of Y for every X):

potentialClosest = dist.argmin(axis=1)

This still may contain duplicates (in your case 2). To check for that, you can find find all Y indices that appear in potentialClosest by use of np.unique:

closestFound, closestCounts = np.unique(potentialClosest, return_counts=True)

Now you can check for duplicates by checking if closestFound.shape[0] == X.shape[0]. If so, you're golden and potentialClosest will contain your partners for every element in X. In your case 2 though, one element will occur twice and therefore closestFound will only have X.shape[0]-1 elements whereas closestCounts will not contain only 1s but one 2. For all elements with count 1 the partner is already found. For the two candidates with count 2, though you will have to choose the closer one while the partner of the one with the larger distance will be the one element of Y which is not in closestFound. This can be found as:

missingPartnerIndex = np.where(
        np.in1d(np.arange(Y.shape[0]), closestFound)==False
        )[0][0]

You can do the matchin in a loop (even though there might be some nicer way using numpy). This solution is rather ugly but works. Any suggestions for improvements are very appreciated:

partners = np.empty_like(X, dtype=int)
nonClosePartnerFound = False
for i in np.arange(X.shape[0]):
    if closestCounts[closestFound==potentialClosest[i]][0]==1:
        # A unique partner was found
        partners[i] = potentialClosest[i]
    else:
        # Partner is not unique
        if nonClosePartnerFound:
            partners[i] = potentialClosest[i]
        else:
            if np.argmin(dist[:, potentialClosest[i]]) == i:
                partners[i] = potentialClosest[i]
            else:
                partners[i] = missingPartnerIndex
                nonClosePartnerFound = True
print(partners)

This answer will only work if only one pair is not close. If that is not the case, you will have to define how to find the correct partner for multiple non-close elements. Sadly it's neither a very generic nor a very nice solution, but hopefully you will find it a helpful starting point.

like image 116
jotasi Avatar answered Sep 21 '22 23:09

jotasi


Using this answer https://stackoverflow.com/a/8929827/3627387 and https://stackoverflow.com/a/12141207/3627387

FIXED

def find_closest(alist, target):
    return min(alist, key=lambda x:abs(x-target))

X = [ 84.04467948,  52.42447842,  39.13555678,  21.99846595]
Y = [ 78.86529444,  52.42447842,  38.74910101,  21.99846595]

def list_matching(list1, list2):
    list1_copy = list1[:]
    pairs = []
    for i, e in enumerate(list2):
        elem = find_closest(list1_copy, e)
        pairs.append([i, list1.index(elem)])
        list1_copy.remove(elem)
    return pairs
like image 28
Sardorbek Imomaliev Avatar answered Sep 17 '22 23:09

Sardorbek Imomaliev