2016-05-02 2 views
4

У меня есть список двумерных массивов numput на Python (все с одинаковой формой), и я хочу извлечь индексы равных массивов. Я пришел с этим:Найти индексы равных numpy 2D строк

a = np.array([[1, 2], [3, 4]]) 
b = np.array([[1, 2], [3, 4]]) 
c = np.array([[3, 4], [1, 2]]) 
d = np.array([[3, 4], [1, 2]]) 
e = np.array([[3, 4], [1, 2]]) 
f = np.array([[1, 2], [3, 4]]) 
g = np.array([[9, 9], [3, 4]]) 

li = [a, b, c, d, e, f, g] 

indexes = list(range(len(li))) 
equals = [] 
for i, a_i in enumerate(indexes): 
    a_equals = [] 
    for j, b_i in enumerate(indexes[i+1:]): 
     if np.array_equal(li[a_i], li[b_i]): 
      del indexes[j] 
      a_equals.append(b_i) 
    if a_equals: 
     equals.append((a_i, *a_equals)) 

print(equals) 
# [(0, 1, 5), (2, 3, 4)] 

Он работает (вы можете считать, что ни один из 2D массивов пустые), однако решение неуклюжее и, вероятно, медленно. Есть ли способ сделать это более элегантно с помощью Numpy?

+0

всех тех 2D массивов одинаковых фигур? – Divakar

+0

Да. Всегда такая же форма. – tsorn

+0

Имеет ли порядок строк выходного материала, т. Е. Что, если мы получим '[(2, 3, 4) (0, 1, 5)]' вместо? – Divakar

ответ

1

Учитывая тот факт, что входные массивы в списке имеют одинаковые формы, вы можете сцепить список массивов в единый 2D массив, с каждой строкой, представляющей каждый элемент списка входных данных. Это облегчает дальнейшие вычисления и облегчает векторизованные операции. Реализация будет выглядеть примерно так -

# Concatenate all elements into a 2D array 
all_arr = np.concatenate(li).reshape(-1,li[0].size) 

# Reduce each row with IDs such that each they represent indexing tuple 
ids = np.ravel_multi_index(all_arr.T,all_arr.max(0)+1) 

# Tag each such IDs based on uniqueness against other IDs 
_,unqids,C = np.unique(ids,return_inverse=True,return_counts=True) 

# Sort the unique IDs and split into groups for final output 
sidx = unqids.argsort() 

# Mask corresponding to unqids that has ID counts > 1 
mask = np.in1d(unqids,np.where(C>1)[0]) 

# Split masked sorted indices at places corresponding to cumsum-ed counts 
out = np.split(sidx[mask[sidx]],C[C>1].cumsum())[:-1] 

Примечание: Если есть огромное количество столбцов в каскадном входном массиве all_arr, вы можете получить индексы ids вручную с помощью np.cumprod, как так -

ids = all_arr.dot(np.append(1,(all_arr.max(0)+1)[::-1][:-1].cumprod())[::-1]) 
+0

Это, безусловно, решение с множеством точек и чрезвычайно быстрое (0,002 сек против 2 секунд для моего решения и 2 сек для решения @gdlmx на большом входе), но результат включает индексы массивов с частотой 1. Наивное решение заключается в удалении все массивы длиной 1 от 'out', но есть ли лучший способ сделать это? – tsorn

+0

@tsorn Требуется немного больше работы. Просто добавьте обновленную версию, чтобы покрыть это требование, проверьте ее. – Divakar

+0

Это умное использование ravel_multi_index для кодирования уникальных подмассивов; хотя я полагаю, что можно столкнуться с проблемами переполнения, если массивы становятся более объемными или их максимальное значение возрастает. –

0

Может быть, вы можете попробовать itertools

import itertools 
from collections import defaultdict 

equals=defaultdict(list) 
visited=[] 
for a, b in itertools.combinations(enumerate(li), 2): 
    if not b[0] in visited and np.array_equal(a[1], b[1]) : 
    equals[a[0]].append(b[0]) 
    visited += (a[0],b[0]) 

print equals 
# defaultdict(<type 'list'>, {0: [1, 5], 2: [3, 4]}) 
0

Эта проблема может быть решена с помощью элегантных numpy_indexed пакета (отказ от ответственности: Я ее автор):

import numpy_indexed as npi 
print(npi.group_by(npi.as_index(li).inverse).split(np.arange(len(li)))) 

Я подозреваю, что вполне вероятно, что поиск этих показателей не является вашей конечной целью, и если вы немного поиграете с numpy_indexed, вы можете обнаружить, что существует более прямой маршрут к вашей конечной цели.

Действительно, удаление индексов одного подсчета, вероятно, лучше оставить как шаг постобработки, хотя можно также использовать npi.multiplicity> 1 в качестве стадии предварительной обработки

Смежные вопросы