Быстрый векторизованный способ преобразования вектора строк в inptrs для разреженной матрицы?

#python #arrays #numpy #scipy #sparse-matrix

#python #массивы #numpy #scipy #разреженная матрица

Вопрос:

Для разреженных матриц мы обычно передаем индексы столбцов ( indices ) и indptr вектор, который индексирует indices вектор так, что indices[indptr[i]:indptr[i 1]] являются элементами строки i в разреженной матрице.

Существует ли быстрое, векторизованное, предпочтительно простое решение для преобразования вектора последовательных индексов строк в indptr в Python?

Например, если это мой rows вектор индексов: [0,1,1,2,2,2,3,5]

indptr Вектор будет [0,1,3,6,7,7,8] там, где 7 повторяется, потому что в векторе строк отсутствует строка 4.

Я могу сделать это с помощью простого цикла:

 for i in range(len(rows)):
    indptr[rows[i] 1]  = 1
    indptr=np.cumsum(indptr)
  

Но мне было интересно, есть ли более быстрый, векторизованный способ сделать это?

Комментарии:

1. в вашем коде, что такое rows и каковы начальные значения indptr ? Неясно, как [0,1,3,6,7,7,8] строится из [0,1,1,2,2,2,3,5]

2. @Ehsan rows — это индексы строк данных, и они отсортированы сверху вниз. итак, если матрица выглядит как [[1, 2], [3, 4]], массив данных был бы [1, 2, 3, 4], индексы строк будут следующими [0, 0, 1, 1], и индексы столбцов должны быть [0, 1, 0, 1]. Индексы строк, преобразованные в indptrs, будут равны [0, 2, 4].

3. Пожалуйста, посмотрите, соответствует ли опубликованный ответ тому, что вы ищете. Если это так, не стесняйтесь принять это. Если нет, пожалуйста, уточните, как вы создаете свой массив indptr

Ответ №1:

Я думаю, что вы ищете это:

 np.bincount(rows).cumsum()
#[1 3 6 7 7 8]
  

И если в нижней части вашей матрицы есть строки, которые могут быть пустыми, просто добавьте это в качестве аргумента в bincount (согласно рекомендации @ CJR):

 np.bincount(rows, minlength=num_rows).cumsum()
#[1 3 6 7 7 8]
  

Вы, вероятно, хотите также вставить 0 спереди. Что bincount делает, так это подсчитывает количество элементов в каждой ячейке / строке, а затем cumsum суммирует их. Таким образом, вы также включите отсутствующие ячейки / строки.

Вероятно, лучший способ вставить 0 — это:

 np.bincount(np.array(rows) 1).cumsum()
#[0 1 3 6 7 7 8]
  

или вы можете сделать это напрямую с помощью:

 np.insert(np.bincount(rows).cumsum(),0,0)
#[0 1 3 6 7 7 8]
  

Комментарии:

1. Убедитесь, что вы установили minlength в bincount значение # rows в матрице, иначе вы пропустите пустые строки в конце вашего массива indptr.

Ответ №2:

Другой идеей было бы

 n = len(rows)
indptr = np.searchsorted(rows, np.arange(-1,n), side='right')
  

Не уверен, что быстрее / лучше