Хранить и извлекать большую разреженную матрицу

У меня довольно большая разреженная матрица, которая, я полагаю, займет 1 ГБ при загрузке в память.

Мне не нужен доступ ко всей матрице во все времена, поэтому будет работать какое-то отображение памяти; однако, по-видимому, не представляется возможным, чтобы память отображала разреженную матрицу с использованием numpy или spicy (инструменты, с которыми я знаком).

Он может легко вписаться в память, но было бы больно, если бы мне приходилось загружать его каждый раз, когда я запускаю программу. Может быть, каким-то образом сохранить память в промежутках между прогонами?

Итак, что вы предлагаете: 1. Найдите путь к карте памяти с разреженной матрицей; 2. Просто загружайте все мысли в память каждый раз 3.?

Следующее может работать как общая концепция, но вам нужно будет найти много деталей … Сначала вы должны ознакомиться с форматом CSR , где вся информация для массива хранится в 3 массивах, две длины количество ненулевых записей, одна из которых – количество строк плюс одна:

>>> import scipy.sparse as sps >>> a = sps.rand(10, 10, density=0.05, format='csr') >>> a.toarray() array([[ 0. , 0.46531486, 0.03849468, 0.51743202, 0. ], [ 0. , 0.67028033, 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0. ], [ 0. , 0. , 0. , 0. , 0.9967058 ], [ 0. , 0. , 0. , 0. , 0. ]]) >>> a.data array([ 0.46531486, 0.03849468, 0.51743202, 0.67028033, 0.9967058 ]) >>> a.indices array([1, 2, 3, 1, 4]) >>> a.indptr array([0, 3, 4, 4, 5, 5]) 

Таким образом, a.data имеет ненулевые записи, в a.indices основном порядке, a.indices имеет соответствующие индексы столбцов ненулевых записей, а a.indptr имеет начальные индексы в двух других массивах, где начинаются данные для каждой строки , например a.indptr[3] = 4 и a.indptr[3+1] = 5 , поэтому отличные от нуля записи в четвертой строке являются a.data[4:5] и их индексы столбцов a.indices[4:5] .

Таким образом, вы можете хранить эти три массива на диске и получать к ним доступ в виде memmaps, и затем вы можете извлекать строки от m до n следующим образом:

 ip = indptr[m:n+1].copy() d = data[ip[0]:ip[-1]] i = indices[ip[0]:ip[-1]] ip -= ip[0] rows = sps.csr_matrix((d, i, ip)) 

В качестве общего доказательства концепции:

 >>> c = sps.rand(1000, 10, density=0.5, format='csr') >>> ip = c.indptr[20:25+1].copy() >>> d = c.data[ip[0]:ip[-1]] >>> i = c.indices[ip[0]:ip[-1]] >>> ip -= ip[0] >>> rows = sps.csr_matrix((d, i, ip)) >>> rows.toarray() array([[ 0. , 0. , 0. , 0. , 0.55683501, 0.61426248, 0. , 0. , 0. , 0. ], [ 0. , 0. , 0.67789204, 0. , 0.71821363, 0.01409666, 0. , 0. , 0.58965142, 0. ], [ 0. , 0. , 0. , 0.1575835 , 0.08172986, 0.41741147, 0.72044269, 0. , 0.72148343, 0. ], [ 0. , 0.73040998, 0.81507086, 0.13405909, 0. , 0. , 0.82930945, 0.71799358, 0.8813616 , 0.51874795], [ 0.43353831, 0.00658204, 0. , 0. , 0. , 0.10863725, 0. , 0. , 0. , 0.57231074]]) >>> c[20:25].toarray() array([[ 0. , 0. , 0. , 0. , 0.55683501, 0.61426248, 0. , 0. , 0. , 0. ], [ 0. , 0. , 0.67789204, 0. , 0.71821363, 0.01409666, 0. , 0. , 0.58965142, 0. ], [ 0. , 0. , 0. , 0.1575835 , 0.08172986, 0.41741147, 0.72044269, 0. , 0.72148343, 0. ], [ 0. , 0.73040998, 0.81507086, 0.13405909, 0. , 0. , 0.82930945, 0.71799358, 0.8813616 , 0.51874795], [ 0.43353831, 0.00658204, 0. , 0. , 0. , 0.10863725, 0. , 0. , 0. , 0.57231074]]) 

Scipy поддерживает различные виды разреженных матриц . Но вам придется написать рутину, чтобы прочитать ее в памяти. Какой тип вы должны использовать, зависит от того, что вы хотите с ним делать.

Если ваша матрица очень разрежена, вы можете сохранить кортежи (row, column, value) на диск в виде двоичных данных с помощью модуля struct . Это сделало бы данные на диске более компактными и упростило бы загрузку, предполагая, что переносимость не является проблемой.

Затем вы можете прочитать такие данные:

 import struct from functools import partial fmt = 'IId' size = struct.calcsize(fmt) with open('sparse.dat', 'rb') as infile: f = partial(infile.read, size) for chunk in iter(f, ''): row, col, value = struct.unpack(fmt, chunk) # put it in your matrix here