Numpy: получить индекс элементов 1d массива в виде 2d массива - PullRequest
1 голос
/ 20 октября 2019

У меня есть такой массив: [1 2 2 0 0 1 3 5]

Можно ли получить индекс элементов в виде 2-мерного массива? Например, ответ для вышеупомянутого ввода будет [[3 4], [0 5], [1 2], [6], [], [7]]

В настоящее время я должен зациклить различные значения и вызывать numpy.where(input == i) для каждого значения, которое имеет ужасную производительность с достаточно большим вводом.

Ответы [ 3 ]

2 голосов
/ 20 октября 2019

Вот подход O (max (x) + len (x)) с использованием scipy.sparse:

import numpy as np
from scipy import sparse

x = np.array("1 2 2 0 0 1 3 5".split(),int)
x
# array([1, 2, 2, 0, 0, 1, 3, 5])


M,N = x.max()+1,x.size
sparse.csc_matrix((x,x,np.arange(N+1)),(M,N)).tolil().rows.tolist()
# [[3, 4], [0, 5], [1, 2], [6], [], [7]]

Это работает путем создания разреженной матрицы с записями в позициях (x [0],0), (x [1], 1), ... Используя формат CSC (сжатый разреженный столбец), это довольно просто. Затем матрица преобразуется в формат LIL (связанный список). Этот формат хранит индексы столбцов для каждой строки в виде списка в атрибуте rows, поэтому все, что нам нужно сделать, это взять его и преобразовать в список.

Обратите внимание, что для небольших массивов argsort основанные решениявероятно, быстрее, но при некоторых не слишком больших размерах это пересекается.

2 голосов
/ 20 октября 2019

Один из возможных вариантов, в зависимости от размера ваших данных, состоит в том, чтобы просто отказаться от numpy и использовать collections.defaultdict:

In [248]: from collections import defaultdict

In [249]: d = defaultdict(list)

In [250]: l = np.random.randint(0, 100, 100000)

In [251]: %%timeit
     ...: for k, v in enumerate(l):
     ...:     d[v].append(k)
     ...:
10 loops, best of 3: 22.8 ms per loop

Тогда вы получите словарь {value1: [index1, index2, ...], value2: [index3, index4, ...]}. Масштабирование времени довольно близко к линейному с размером массива, поэтому 10000000 занимает на моей машине ~ 2,7 с, что кажется достаточно разумным.

0 голосов
/ 20 октября 2019

Псевдокод:

  1. получить «количество 1d массивов в 2d массиве», вычитая минимальное значение вашего массива numpy из максимального значения, а затем плюс один. В вашем случае это будет 5-0 + 1 = 6

  2. , инициализируйте 2d массив с количеством 1d массивов в нем. В вашем случае инициализируйте 2d массив с 6 1d массивом в нем. Каждый 1d массив соответствует уникальному элементу в вашем массиве numpy, например, первый 1d массив будет соответствовать '0', второй 1d массив будет соответствовать '1', ...

  3. переберите ваш массив numy, поместите индекс элемента в соответствующий соответствующий 1d массив. В вашем случае индекс первого элемента в вашем массиве numpy будет помещен во второй массив 1d, индекс второго элемента в вашем массиве numpy будет помещен в третий массив 1d, ....

Этот псевдокод будет работать линейно, поскольку это зависит от длины вашего массива.

...