web-dev-qa-db-fra.com

Le moyen le plus rapide de trouver toutes les paires de nombres proches dans une matrice numpue

Dis que j'ai un tableau engu de N = 10 nombres de flotteurs aléatoires:

import numpy as np
np.random.seed(99)
N = 10
arr = np.random.uniform(0., 10., size=(N,))
print(arr)

out[1]: [6.72278559 4.88078399 8.25495174 0.31446388 8.08049963 
         5.6561742 2.97622499 0.46695721 9.90627399 0.06825733]

Je veux trouver tous niques paires de nombres qui ne sont pas différents les uns des autres que la tolérance tol = 1. (c'est-à-dire une différence absolue <= 1). Plus précisément, je veux obtenir toutes les paires d'index uniques. Les index de chaque paire de fermeture doivent être triés et toutes les paires fermer doivent être triées par le premier index. J'ai réussi à écrire le code de travail suivant:

def all_close_pairs(arr, tol=1.):
    res = set()
    for i, x1 in enumerate(arr):
        for j, x2 in enumerate(arr):
            if i == j:
                continue
            if np.isclose(x1, x2, rtol=0., atol=tol):
                res.add(Tuple(sorted([i, j])))
    res = np.array(list(res))
    return res[res[:,0].argsort()]

print(all_close_pairs(arr, tol=1.))

out[2]: [[1 5]
         [2 4]
         [3 7]
         [3 9]
         [7 9]]

Cependant, dans la réalité, j'ai un tableau de N = 1000 Nombres, et mon code devient extrêmement lent en raison des boucles imbriquées. Je crois qu'il y a des moyens beaucoup plus efficaces de le faire avec une vectorisation numique. Est-ce que quelqu'un connaît le moyen le plus rapide de le faire dans NUMPY?

4
Shaun Han

Vous pouvez d'abord créer des combinaisons avec itertools.combinations:

def all_close_pairs(arr, tolerance):
    pairs = list(combinations(arr, 2))
    indexes = list(combinations(range(len(arr)), 2))
    all_close_pairs_indexes = [indexes[i] for i,pair in enumerate(pairs) if abs(pair[0] - pair[1]) <=  tolerance]
    return all_close_pairs_indexes

Maintenant, pour N = 1000, vous devrez comparer seulement 499500 paires au lieu de 1 million.

Comment ça marche :

  • Nous créons d'abord les paires via itertools.combinations.

  • Ensuite, nous créons la liste de leurs index.

  • Nous utilisons une compréhension de la liste au lieu d'une boucle pour des raisons de vitesse.

  • Dans cette compréhension, nous intituons toutes les paires, en utilisant enumerate afin que nous puissions obtenir l'index de la paire, nous calculons la différence absolue des numéros dans la paire, et si le chèque s'il est inférieur ou égal à la tolerance.

  • Si la différence absolue est inférieure ou égale à tolerance, nous obtenons les index des numéros de paires via la liste des index et les ajoutons à notre liste finale.

1
Rivers