Получить все остальные индексы ndArray / list - PullRequest
0 голосов
/ 08 января 2019

Учитывая массив значений и допустимый массив индексов, я хотел бы получить все остальные индексы.

В поисках питонского способа сделать это, но вот пример решения, а также уточнить, что я пытаюсь сделать:

A = np.array(['a', 'b', 'c', 'd', 'e', 'f', 'g'])  # Array of values. Shape: (7,)
B = np.array([0,3,5])  # Array of indices.

# Looking for a more elegant way to do this following line
C = np.array([i for i in range(len(A)) if i not in B])  # Array indices not in B

# Expected Output: C = [1, 2, 4, 6]

Редактировать : Сравнительный анализ решений

A = np.ones(10000)  
B = np.random.random_integers(low=0, high=len(A) - 1, size=8000)  

t1 = time()  
mask = np.ones(len(A), dtype=bool)  
mask[B] = False  
C = np.arange(len(A))[mask]  
t1 = time() - t1  

t2 = time()  
C = np.delete(np.arange(A.size), B)  
t2 = time() - t2  

t3 = time()  
C = np.array([i for i in range(len(A)) if i not in B])  
t3 = time() - t3  

t4 = time()  
C = set(np.arange(len(A))).difference(B)  
t4 = time() - t4  

print("T1: %.5f" % np.round(t1, 5))    
print("T2: %.5f" % np.round(t2, 5))  
print("T3: %.5f" % np.round(t3, 5))  
print("T4: %.5f" % np.round(t4, 5))  

Результаты (Значения менялись при изменении числа индексов в B, но самый быстрый всегда оставался T1:

T1: 0.00011 <<< Запуск приведенного выше сценария несколько раз, он всегда был самым быстрым. Второй подход всегда был немного позади. <br> T2: 0.00017
T3: 0.05746 << Понимание списка заняло больше всего времени. Даже после удаления np.array. <br> T4: 0.00158

  • Вывод:
    Я буду использовать второй подход, описанный выше (T2) только потому, что это один лайнер и занимает (почти) то же время, что и самый быстрый подход.

Ответы [ 2 ]

0 голосов
/ 08 января 2019

Я не уверен, что это Pythonic, но он более Numpythonic (если это вещь). Прежде всего, поиск на массивах O (N). Во-вторых, падение на итерацию Python (в вашем понимании списка) нарушает цель использования в первую очередь пустых массивов.

A = np.array([1,2,3,4,5,6,7]) 
B = np.array([0,3,5])
mask = np.ones(len(A), dtype=bool)
mask[B] = False
not_in_b = np.arange(len(A))[mask]

Редактировать

Некоторые тесты.

In [9]: a = np.ones(1000000)

In [10]: b = np.random.choice(1000000, size=10000, replace=False)

In [11]: def test1(a, b):
    ...:     mask = np.ones(len(a), dtype=bool)
    ...:     mask[b] = False
    ...:     return np.arange(len(a))[mask]
    ...: 
    ...: 

In [12]: %timeit test1(a, b)
4.72 ms ± 15 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [13]: %timeit np.delete(np.arange(a.size), b)
4.72 ms ± 21.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Удивительно, но решение @ Kasramvd не быстрее моего, хотя и немного чище. Учитывая эти результаты, я не удивлюсь, если np.delete на самом деле является тонкой оболочкой вокруг той же логики, которую я реализовал. Поэтому я не вижу причин отдавать предпочтение моему решению над @ Kasramvd's.

0 голосов
/ 08 января 2019

Вы можете использовать np.delete, чтобы удалить элементы B из списка других индексов, которые вы можете создать с помощью np.arange:

inds = np.delete(np.arange(A.size), B)

Демо-версия:

In [53]: A = np.array(['a', 'b', 'c', 'd', 'e', 'f', 'g'])
    ...: B = np.array([0,3,5])

In [54]: inds = np.delete(np.arange(A.size), B)

In [55]: inds
Out[55]: array([1, 2, 4, 6])
...