Sto cercando modi per accelerare (o sostituire) il mio algoritmo per il raggruppamento dei dati.Algoritmo veloce per trovare indici in cui più array hanno lo stesso valore
Ho una lista di array numpy. Voglio generare un nuovo array numpy, in modo tale che ogni elemento di questo array sia lo stesso per ogni indice in cui anche gli array originali sono uguali. (E diverso dove questo non è il caso.)
Sembra tipo di scomodo, in modo da avere un esempio:
# Test values:
values = [
np.array([10, 11, 10, 11, 10, 11, 10]),
np.array([21, 21, 22, 22, 21, 22, 23]),
]
# Expected outcome: np.array([0, 1, 2, 3, 0, 3, 4])
# * *
nota che gli elementi sono contrassegnati (indici 0 e 4) del risultato atteso avere la stesso valore (0
) perché anche i due array originali erano uguali (ovvero 10
e 21
). Simile per gli elementi con indici 3 e 5 (3
).
L'algoritmo deve gestire un numero arbitrario di matrici di input (uguali alle dimensioni) e anche restituire, per ciascun numero risultante, i valori delle matrici originali a cui corrispondono. (Così, per questo esempio, "3" si riferisce a (11, 22)
.)
Ecco il mio algoritmo attuale:
import numpy as np
def groupify(values):
group = np.zeros((len(values[0]),), dtype=np.int64) - 1 # Magic number: -1 means ungrouped.
group_meanings = {}
next_hash = 0
matching = np.ones((len(values[0]),), dtype=bool)
while any(group == -1):
this_combo = {}
matching[:] = (group == -1)
first_ungrouped_idx = np.where(matching)[0][0]
for curr_id, value_array in enumerate(values):
needed_value = value_array[first_ungrouped_idx]
matching[matching] = value_array[matching] == needed_value
this_combo[curr_id] = needed_value
# Assign all of the found elements to a new group
group[matching] = next_hash
group_meanings[next_hash] = this_combo
next_hash += 1
return group, group_meanings
Si noti che l'espressione value_array[matching] == needed_value
viene valutato molte volte per ogni singolo indice, che è dove la lentezza viene da.
Non sono sicuro che il mio algoritmo possa essere velocizzato molto di più, ma non sono nemmeno sicuro se sia l'algoritmo ottimale per iniziare. C'è un modo migliore per farlo?
Puoi spiegare un po 'di più cosa succede realmente qui? In particolare: cosa fa 'np.ravel_multi_index'? (I documenti non mi stanno chiarendo molto.) Perché lo chiamate su arr.max (1) + 1'? – acdr
@acdr In pratica considera ogni coppia come una tupla di indicizzazione. Quindi, per la prima coppia dal campione '(10,21)' su una griglia 2D con una forma appropriata corrisponderebbe a un numero indicizzato linearmente. Diciamo che prendiamo una griglia di forma '(100,100)'. Quindi, l'indice lineare sarebbe '10 * 100 + 21 = 1021'. Facciamo questo per tutte le coppie in una volta con 'ravel_multi_index'. Inoltre, la forma della griglia 2D può essere considerata come un massimo di '(prima e seconda coppia di elementi) + 1'. Spero che abbia senso. Il meglio che potrei suggerire sarebbe esaminare l'indicizzazione lineare come anche usato in MATLAB. – Divakar
Questo ha senso. In tal caso, quella funzione fa tutto ciò di cui ho bisogno. (Non ho necessariamente bisogno degli ID per iniziare da 0 e incrementare di 1, a patto che siano unici.) Direi quindi che questa soluzione non funzionerebbe con array non interi? (Per esempio.supponiamo di avere un array di stringhe, i valori non si associano a una griglia per niente.) – acdr