说我有一个2D SciPy稀疏矩阵:
import numpy as np
from scipy.sparse import csc_matrix
arr = np.array([[0, 0, 1, 0, 1],
[1, 0, 0, 1, 0],
[0, 1, 1, 0, 0],
[1, 0, 0, 1, 0],
[0, 1, 0, 0, 0],
])
csc = csc_matrix(arr)
对于矩阵中的每个非零元素,我想创建四个新的稀疏矩阵,它们包含与下一个最近的Left,Right,Up和Down非零邻居相对应的索引。末端的元素可以具有环绕的相邻元素(考虑水平和垂直方向上的圆形双向链表或环形)。如果元素是其行/列中唯一的非零元素,则相应的索引将指向自身。另外,由于索引可以具有零值(在引用第一行或第一列时),并且与自然零元素没有区别,因此我们将这些零索引设置为-1,以使真实索引与零元素有歧义。>
对于上面的矩阵,密集的Left和Down矩阵如下所示:
left = np.array([[0, 0, 4, 0, 2],
[3, 0, 0, -1, 0],
[0, 2, 1, 0, 0],
[3, 0, 0, -1, 0],
[0, 1, 0, 0, 0],
])
down = np.array([[0, 0, 2, 0, -1],
[3, 0, 0, 3, 0],
[0, 4, -1, 0, 0],
[1, 0, 0, 1, 0],
[0, 2, 0, 0, 0],
])
请记住,索引值为-1的元素实际上是对索引零的引用。当然,我需要以稀疏矩阵形式存储这些矩阵,因为我的真实矩阵太大且稀疏,无法容纳到内存中。
答案 0 :(得分:1)
这是做左邻居的一种可能方法。
它不是特别有效,但如果整个矩阵中没有很多非零条目,可能就可以了。您可以通过获取行中每行的非零条目并仅计算一次"bad json"
来对其进行稍微优化。
请注意,我只是将索引上移了一个,而不是将j[i==row]
设置为0
。
-1
答案 1 :(得分:1)
In [183]: arr = np.array([[0, 0, 1, 0, 1],
...: [1, 0, 0, 1, 0],
...: [0, 1, 1, 0, 0],
...: [1, 0, 0, 1, 0],
...: [0, 1, 0, 0, 0],
...: ])
...:
In [184]: from scipy import sparse
In [185]: M = sparse.lil_matrix(arr)
In [186]: M.rows
Out[186]:
array([list([2, 4]), list([0, 3]), list([1, 2]), list([0, 3]), list([1])],
dtype=object)
与使用以下方法从密集数组中获得的信息相同:
In [187]: [np.where(row)[0] for row in arr]
Out[187]: [array([2, 4]), array([0, 3]), array([1, 2]), array([0, 3]), array([1])]
我假设您已经想出了如何从密集数组中生成所需的left
(或right
),所以我不会深入探讨这些细节(我太懒了,无法进行搏斗以及您的包装规格)。
对于列:
In [189]: M.T.rows
Out[189]:
array([list([1, 3]), list([2, 4]), list([0, 2]), list([1, 3]), list([0])],
dtype=object)
可以使用csc
格式:
In [190]: Mc = sparse.csc_matrix(arr)
In [191]: Mc.indptr
Out[191]: array([0, 2, 4, 6, 8, 9], dtype=int32)
In [192]: Mc.indices
Out[192]: array([1, 3, 2, 4, 0, 2, 1, 3, 0], dtype=int32)
In [193]: for i in range(5):
...: print(Mc.indices[Mc.indptr[i]:Mc.indptr[i+1]])
...:
[1 3]
[2 4]
[0 2]
[1 3]
[0]
在此示例中,所有行或列都只有1个或2个非零。我想在更大的范围内,会有很多非零。同样,对于csc
(和csr
,还有可能未对每个“行”的索引进行排序-有一种稀疏的方法可以解决该问题。
关于构建返回稀疏矩阵,您可以修改副本的data
属性(它将具有相同的稀疏性)。
In [194]: M.data
Out[194]:
array([list([1, 1]), list([1, 1]), list([1, 1]), list([1, 1]), list([1])],
dtype=object)
In [195]: Mc.data
Out[195]: array([1, 1, 1, 1, 1, 1, 1, 1, 1], dtype=int64)
或从数组构造稀疏矩阵(这对于coo
样式输入是正常的)。
在我的lil
版本中,tch's
解决方案的速度要适中:
ind = sparse.lil_matrix(M.shape,dtype='int')
for i,row in enumerate(M.rows):
k = np.array(row)
ind[i,k] = np.roll(k+1,1)
以我替换data
的想法更好:
ind = M.copy()
for row,dat in zip(ind.rows,ind.data):
k = np.array(row)
dat[:] = np.roll(k+1,1).tolist()
或与Mr = Mc.tocsr()
ind = Mr.copy()
for i in range(Mr.shape[0]):
slc = slice(Mr.indptr[i],Mr.indptr[i+1])
k = Mr.indices[slc]
ind.data[slc] = np.roll(k+1,1)
答案 2 :(得分:0)
一个可能的答案(密集形式):
ix, iy = csc.nonzero()
w = np.where(np.insert(np.diff(ix), 0,1) != 0)[0]
iy2 = np.concatenate([np.roll(_, 1) for _ in np.split(iy,w)])
iy2[iy2==0] = -1
left = csc_matrix(arr.shape)
left[ix, iy] = iy2
ix, iy = csc.transpose().nonzero()
w = np.where(np.insert(np.diff(ix), 0,1) != 0)[0]
iy2 = np.concatenate([np.roll(_, 1) for _ in np.split(iy,w)])
iy2[iy2==0] = -1
down = csc_matrix(arr.T.shape)
down[ix, iy] = iy2
down = down.transpose()
print(left.todense(), '\n', down.todense())
>> [[ 0 0 4 0 2]
[ 3 0 0 -1 0]
[ 0 2 1 0 0]
[ 3 0 0 -1 0]
[ 0 1 0 0 0]]
[[ 0 0 2 0 -1]
[ 3 0 0 3 0]
[ 0 4 -1 0 0]
[ 1 0 0 1 0]
[ 0 2 0 0 0]]
答案 3 :(得分:0)
一种更加矢量化的方法:
csc = csc_matrix(arr)
inds = (csc.indices,csc.indptr)
irows = np.split(*inds)[1:-1]
down = csc_matrix((np.hstack([np.roll(row,-1) for row in irows]),*inds))
up = csc_matrix((np.hstack([np.roll(row,1) for row in irows]),*inds))
检查:
>>> down.A
array([[0, 0, 2, 0, 0],
[3, 0, 0, 3, 0],
[0, 4, 0, 0, 0],
[1, 0, 0, 1, 0],
[0, 2, 0, 0, 0]], dtype=int32)
左和右可以通过CSR表示获得。
我认为用-1编码0是个好主意,因为如果这样做会破坏所有稀疏计算的改进。只有csc.nonzeros()
设计的地方必须参观。