простое построение разреженной (переходной) матрицы

#python #numpy #multidimensional-array #sparse-matrix #simplify

#python #numpy #многомерный массив #разреженная матрица #упростить

Вопрос:

Я создаю матрицу перехода из n1 x n2 x ... x nN x nN массива. Для конкретности пусть N = 3 , например,

 import numpy as np

# example with N = 3
n1, n2, n3 = 3, 2, 5
dim = (n1, n2, n3)
arr = np.random.random_sample(dim   (n3,))
 

Здесь arr содержатся вероятности перехода между 2 состояниями, где состояние «от» индексируется по первым 3 измерениям, а состояние «до» индексируется по первым 2 и последнему измерению. Я хочу построить матрицу перехода, которая выражает эти вероятности, преобразованные в разреженную (n1*n2*n3) x (n1*n2*n3 матрицу.

Чтобы уточнить, позвольте мне представить мой текущий подход, который делает то, что я хочу сделать. К сожалению, это медленно и не работает, когда N и n1, n2, ... большие. Поэтому я ищу более эффективный способ сделать то же самое, который лучше масштабируется для более крупных задач.

Мой подход

 import numpy as np
from scipy import sparse as sparse

## step 1: get the index correponding to each dimension of the from and to state

# ravel axes 1 to 3 into single axis and make sparse 
spmat = sparse.coo_matrix(arr.reshape(np.prod(dim), -1))
data = spmat.data
row = spmat.row
col = spmat.col

# use unravel to get idx for 
row_unravel = np.array(np.unravel_index(row, dim))
col_unravel = np.array(np.unravel_index(col, n3))

## step 2: combine "to" index with rows 1 and 2 of "from"-index to get "to"-coordinates in full state space

row_unravel[-1, :] = col_unravel # first 2 dimensions of state do not change
colnew = np.ravel_multi_index(row_unravel, dim) # ravel back to 1d

## step 3: assemble transition matrix

out = sparse.coo_matrix((data, (row, colnew)), shape=(np.prod(dim), np.prod(dim)))
 

Последняя мысль

Я буду запускать этот код много раз. На протяжении итераций данные arr могут меняться, но размеры останутся прежними. Итак, одна вещь, которую я мог бы сделать, это сохранить и загрузить row и colnew из файла, пропустив все между определением data (строка 2) и последней строкой моего кода. Как вы думаете, это был бы лучший подход?

Редактировать: Одна проблема, которую я вижу в этой стратегии, заключается в том, что если некоторые элементы arr равны нулю (что возможно), то размер data будет меняться на итерациях.

Ответ №1:

Один подход, который превосходит тот, который опубликован в OP. Не уверен, что это наиболее эффективно.

 import numpy as np
from scipy import sparse

# get col and row indices
idx = np.arange(np.prod(dim))
row = idx.repeat(dim[-1])
col = idx.reshape(-1, dim[-1]).repeat(dim[-1], axis=0).ravel()

# get the data
data = arr.ravel()

# construct the sparse matrix
out = sparse.coo_matrix((data, (row, col)), shape=(np.prod(dim), np.prod(dim)))
 

Две вещи, которые можно было бы улучшить:

(1) если arr является разреженным, выходная матрица out будет иметь нули, отличные от нуля.

(2) Подход основан на том, что новое состояние является последним измерением dim . Было бы неплохо обобщить, чтобы последняя ось arr могла заменить любую исходную ось, а не только последнюю.