Построение разреженной матрицы из списка списков кортежей
у меня есть список строк Python для разреженной матрицы. Каждая строка представлена в виде списка кортежей (столбец, значение). Назовите это alist
:
alist = [[(1,10), (3,-3)],
[(2,12)]]
как я могу эффективно построить разреженную матрицу scipy из этого списка списков, в результате чего такая матрица:
0 10 0 -3
0 0 12 0
очевидный подход состоит в том, чтобы сделать scipy.sparse.lil_matrix
, который внутренне имеет эту структуру "список списков". Но от scipy.редкий.lil_matrix-SciPy v0.19.0 Ссылка Руководство Я вижу только три способа их построения:
- начиная с плотного массива
- начиная с другого разреженного массива
- просто построение пустого массива
таким образом, единственный способ получить свежие данные - либо решить эту проблему с помощью другого разреженного матричного представления, либо начать с плотного массива, ни один из которых не решает начальную проблему, и оба из которых, похоже, будут менее эффективными представления, чем lil_matrix
сам для этих данных.
думаю, я могу сделать пустой и использовать цикл для добавления значений, но, конечно, я что-то упускаю.
документация scipy действительно расстраивает, когда дело доходит до разреженных матриц.
4 ответов
ваш макет данных является необычным. Вот моя первая попытка использовать его.
In [565]: M = sparse.lil_matrix((2,4), dtype=int)
In [566]: M
Out[566]:
<2x4 sparse matrix of type '<class 'numpy.int32'>'
with 0 stored elements in LInked List format>
In [567]: for i,row in enumerate(alist):
...: for col in row:
...: M[i, col[0]] = col[1]
...:
In [568]: M
Out[568]:
<2x4 sparse matrix of type '<class 'numpy.int32'>'
with 3 stored elements in LInked List format>
In [569]: M.A
Out[569]:
array([[ 0, 10, 0, -3],
[ 0, 0, 12, 0]])
Да, это итеративно; и lil
является лучшим форматом для этой цели.
или с помощью общего coo
тип входов:
In [580]: data,col,row = [],[],[]
In [581]: for i, rr in enumerate(alist):
...: for cc in rr:
...: row.append(i)
...: col.append(cc[0])
...: data.append(cc[1])
...:
In [582]: data,col,row
Out[582]: ([10, -3, 12], [1, 3, 2], [0, 0, 1])
In [583]: M1=sparse.coo_matrix((data,(row,col)),shape=(2,4))
In [584]: M1
Out[584]:
<2x4 sparse matrix of type '<class 'numpy.int32'>'
with 3 stored elements in COOrdinate format>
In [585]: M1.A
Out[585]:
array([[ 0, 10, 0, -3],
[ 0, 0, 12, 0]])
другой вариант-создать пустой lil
матрицы и заполняет его атрибутов:
другими словами, начните с:
In [591]: m.data
Out[591]: array([[], []], dtype=object)
In [592]: m.rows
Out[592]: array([[], []], dtype=object)
и меняем их на:
In [587]: M.data
Out[587]: array([[10, -3], [12]], dtype=object)
In [588]: M.rows
Out[588]: array([[1, 3], [2]], dtype=object)
это все равно потребуется итерация 2 уровня на вашем alist
структура.
In [593]: for i, rr in enumerate(alist):
...: for cc in rr:
...: m.rows[i].append(cc[0])
...: m.data[i].append(cc[1])
In [594]: m
Out[594]:
<2x4 sparse matrix of type '<class 'numpy.int32'>'
with 3 stored elements in LInked List format>
In [595]: m.A
Out[595]:
array([[ 0, 10, 0, -3],
[ 0, 0, 12, 0]])
в другом комментарии Вы упомянули о трудности в понимании csr
indptr
. Самый простой способ получить это-преобразовать один из этих форматов:
In [597]: Mr=M.tocsr()
In [598]: Mr.indptr
Out[598]: array([0, 2, 3], dtype=int32)
In [599]: Mr.data
Out[599]: array([10, -3, 12])
In [600]: Mr.indices
Out[600]: array([1, 3, 2], dtype=int32)
если у вас есть всего alist
перед созданием разреженной матрицы нет необходимости использовать lil_matrix
, так как это оптимизировано для постепенного обновления разреженной матрицы.
если вы хотите сделать какую-либо арифметику с матричными послесловиями,csr_matrix
- вероятно, ваш лучший выбор. Вы можете построить csr_matrix
С помощью , например:
In [40]: alist = [[(1,10), (3,-3)],
...: [(2,12)]]
In [41]: i, j, data = zip(*((i, t[0], t[1]) for i, row in enumerate(alist) for t in row))
In [42]: (i, j, data)
Out[42]: ((0, 0, 1), (1, 3, 2), (10, -3, 12))
In [43]: csr_matrix((data, (i, j)), shape=(2, 4)).todense()
Out[43]:
matrix([[ 0, 10, 0, -3],
[ 0, 0, 12, 0]], dtype=int64)
если эффективность реальная забота, то вы можете создать csr_matrix
внутренний формат (используя indptr) напрямую:
In [57]: indptr = np.cumsum([0] + [len(row) for row in alist])
In [58]: j, data = zip(*(t for row in alist for t in row))
In [59]: csr_matrix((data, j, indptr), shape=(2, 4)).todense()
Out[59]:
matrix([[ 0, 10, 0, -3],
[ 0, 0, 12, 0]])
если вы конвертируете в послесловия панд,coo_matrix
это путь, так как панды преобразуется в coo_matrix
иначе:
In [41]: i, j, data = zip(*((i, t[0], t[1]) for i, row in enumerate(alist) for t in row))
In [43]: coo_matrix((data, (i, j)), shape=(2, 4))
вы можете создать dict
позиций и значений из списка (колонка, значение) кортежей alist
и затем использовать dok_matrix
построить разреженную матрицу
>>> d = {(i,j):v for i,l in enumerate(alist) for j,v in l}
>>> d
{(0, 1): 10, (0, 3): -3, (1, 2): 12}
>>>
>>> from operator import itemgetter
>>> m = max(d.keys(), key=itemgetter(0))[0] + 1
>>> n = max(d.keys(), key=itemgetter(1))[1] + 1
>>> m,n
(2, 4)
>>>
>>> from scipy.sparse import dok_matrix
>>> S = dok_matrix((m,n), dtype=int)
>>> for pos,v in d.items():
... S[pos] = v
...
>>> S.todense()
matrix([[ 0, 10, 0, -3],
[ 0, 0, 12, 0]])
>>>
просто хотел опубликовать другой ответ, используя coo_matrix
, Это быстрый формат для построения разреженных матриц.
>>> alist = [[(1, 10), (3, -3)], [(2, 12)]]
>>> row, col, data = zip(*((i,j,v) for i,l in enumerate(alist) for j,v in l))
>>>
>>> from scipy.sparse import coo_matrix
>>> S = coo_matrix((data, (row, col)), (max(row)+1,max(col)+1), dtype=np.int8)
>>> S.todense()
matrix([[ 0, 10, 0, -3],
[ 0, 0, 12, 0]], dtype=int8)
>>>