# 在Python中稀疏的3dmatrix/数组？

ps我有很多稀疏的3D数据，需要张量来存储/执行乘法。 如果没有现有的数据结构，有什么build议来实现这样一个张量？

N维中的稀疏matrix可以假设大多数元素是空的，所以我们使用一个字典在元组上键入：

``class NDSparseMatrix: def __init__(self): self.elements = {} def addValue(self, tuple, value): self.elements[tuple] = value def readValue(self, tuple): try: value = self.elements[tuple] except KeyError: # could also be 0.0 if using floats... value = 0 return value` `

` `sparse = NDSparseMatrix() sparse.addValue((1,2,3), 15.7) should_be_zero = sparse.readValue((1,5,13))` `

` `#cython: boundscheck=False #cython: wraparound=False cimport numpy as np def sparse_mult(object sparse, np.ndarray[double, ndim=3] u): cdef unsigned int i, j, k out = np.ndarray(shape=(u.shape[0],u.shape[1],u.shape[2]), dtype=double) for i in xrange(1,u.shape[0]-1): for j in xrange(1, u.shape[1]-1): for k in xrange(1, u.shape[2]-1): # note, here you must define your own rank-3 multiplication rule, which # is, in general, nontrivial, especially if LxMxN tensor... # loop over a dummy variable (or two) and perform some summation: out[i,j,k] = u[i,j,k] * sparse((i,j,k)) return out` `

` `def sparse_mult(sparse, other_sparse): out = NDSparseMatrix() for key, value in sparse.elements.items(): i, j, k = key # note, here you must define your own rank-3 multiplication rule, which # is, in general, nontrivial, especially if LxMxN tensor... # loop over a dummy variable (or two) and perform some summation # (example indices shown): out.addValue(key) = out.readValue(key) + other_sparse.readValue((i,j,k+1)) * sparse((i-3,j,k)) return out` `

` `typedef struct { int index[3]; float value; } entry_t;` `

` `import scipy.sparse as sp import numpy as np class Sparse3D(): """ Class to store and access 3 dimensional sparse matrices efficiently """ def __init__(self, *sparseMatrices): """ Constructor Takes a stack of sparse 2D matrices with the same dimensions """ self.data = sp.vstack(sparseMatrices, "dok") self.shape = (len(sparseMatrices), *sparseMatrices[0].shape) self._dim1_jump = np.arange(0, self.shape[1]*self.shape[0], self.shape[1]) self._dim1 = np.arange(self.shape[0]) self._dim2 = np.arange(self.shape[1]) def __getitem__(self, pos): if not type(pos) == tuple: if not hasattr(pos, "__iter__") and not type(pos) == slice: return self.data[self._dim1_jump[pos] + self._dim2] else: return Sparse3D(*(self[self._dim1[i]] for i in self._dim1[pos])) elif len(pos) > 3: raise IndexError("too many indices for array") else: if (not hasattr(pos[0], "__iter__") and not type(pos[0]) == slice or not hasattr(pos[1], "__iter__") and not type(pos[1]) == slice): if len(pos) == 2: result = self.data[self._dim1_jump[pos[0]] + self._dim2[pos[1]]] else: result = self.data[self._dim1_jump[pos[0]] + self._dim2[pos[1]], pos[2]].T if hasattr(pos[2], "__iter__") or type(pos[2]) == slice: result = result.T return result else: if len(pos) == 2: return Sparse3D(*(self[i, self._dim2[pos[1]]] for i in self._dim1[pos[0]])) else: if not hasattr(pos[2], "__iter__") and not type(pos[2]) == slice: return sp.vstack([self[self._dim1[pos[0]], i, pos[2]] for i in self._dim2[pos[1]]]).T else: return Sparse3D(*(self[i, self._dim2[pos[1]], pos[2]] for i in self._dim1[pos[0]])) def toarray(self): return np.array([self[i].toarray() for i in range(self.shape[0])])` `