将Matlab稀疏转换为Python scipy csr_matrix

时间:2015-10-22 09:49:57

标签: python arrays matlab scipy sparse-matrix

我是Matlab和Python的新手,并且正在将一些Matlab代码转换为它的Python等价物。我面临的问题是从稀疏(i,j,v,m,n)转换为 csr_matrix((data,(row_ind,col_ind)),[shape =(M, N)])即可。

在此代码中,i,j和row_in,col_ind将与索引数组一起传递 - idx 大小(124416,1),而v和数据将与2D数组一起传递 - D22 大小(290,434)

Matlab的:

...
H = 288;
W = 432;
N = (H+2)*(W+2);
mask = zeros(H+2, W+2);
mask(2:end-1, 2:end-1) = 1;

idx = find(mask==1);
>>>idx = [292, ..., 579, 582 ..., 869, ... , 125282, ..., 125569]

A = sparse(idx, idx+1, -D22(idx), N, N);
B = sparse(idx, idx-1, -D22(idx), N, N);
C = sparse(idx, idx+H+2, -D22(idx-1), N, N);
D = sparse(idx, idx-H-2, -D22(idx-1), N, N);
...

间谍(A)第一个条目是 m(293,292) - (idx,idx + 1),这是我的预期。

间谍(B) m(292,293) - (idx,idx-1)。 我期待它是m(291,292),相信idx-1将返回一个数组[291,...,578,581 ......,868,...,125281,...,125568]

间谍(C) - m(582,292) - (idx,idx + H + 2)

间谍(D) - m(292,582) - (idx,idx-H-2)

因此,鉴于我理解索引顺序,我将代码转换为Python格式

的Python:

...
H = 288
W = 432
N = (H+2) * (W+2)
mask = np.zeros([H+2, W+2])
mask[1:-1,1:-1] = 1

idx = np.nonzero(mask.transpose() == 1)                                 
idx = np.vstack((idx[1], idx[0]))                                        
idx = np.ravel_multi_index(idx, ((H+2),(W+2)), order='F').copy()     # Linear Indexing as per Matlab
>>> idx
array([291, ..., 578, 581 ..., 868, ... , 125281, ..., 125568])

idx_ = np.unravel_index(idx, ((H+2),(W+2)), order='F')               # *** Back to Linear Indexing
idx_ = np.column_stack((idx_[0], idx_[1]))                           # *** combine tuple of 2 arrays
idx_H_2 = np.unravel_index(idx-H-2, ((H+2),(W+2)), order='F')
idx_H_2 = np.column_stack((idx_H_2[0], idx_H_2[1]))

A = sp.csr_matrix((-D22[idx_[:,0], idx_[:,1]], (idx+1,idx)), shape = (N,N))
B = sp.csr_matrix((-D22[idx_[:,0], idx_[:,1]], (idx-1,idx)), shape = (N,N))
C = sp.csr_matrix((-D11[idx_[:,0], idx_[:,1]], (idx+H+2,idx)), shape = (N,N)) 
D = sp.csr_matrix((-D11[idx_H_2[:,0], idx_H_2[:,1]], (idx-H-2,idx)), shape = (N,N)) 
...

对于A,第一个条目是 p(292,291) - (idx + 1,idx),并且由于Python从零索引开始,它指的是Matlab m(293,292)

然而对于B,第一个条目是 p(290,291) - (idx-1,idx),这是我的预期(Matlab中的等价物应该是m(291, 292)),但如前所述,Matlab代码返回(292,293)。

C - p(581,291) - (idx + H + 2,idx)

D - p(1,291) - (idx-H-2,idx)

任何人都可以解释我可能错误理解的内容,我应该如何修改我的Python代码以更准确地反映Matlab代码。

哦,还有一个qns:)

Matlab的:

A = A(idx,idx);

的Python:

A = A[idx,:][:,idx]

是等效的吗?

非常感谢您的帮助和时间。

2 个答案:

答案 0 :(得分:0)

对我来说似乎很好,我能发现的唯一区别是:

MATLAB:

A = sparse(idx, idx+1, -D22(idx), N, N);
B = sparse(idx, idx-1, -D22(idx), N, N);

<强>的Python:

A = sp.csr_matrix((-D22[idx_[:,0], idx_[:,1]], (idx+1,idx)), shape = (N,N))
B = sp.csr_matrix((-D22[idx_[:,0], idx_[:,1]], (idx,idx-1)), shape = (N,N))

请注意,在Python中,对于矩阵B,您可以沿第二维更改索引,而对于矩阵A,您可以沿第一维更改。

您的Matlab代码中不存在这种差异,而所有其他行都是“对称的”

答案 1 :(得分:0)

这些行令人困惑:

py(A) first entry is m(293, 292) - (idx,idx+1), which was what I expected.

spy(B) m(292, 293) - (idx,idx-1). I was expecting it to be m(291, 292), believing that idx-1 would return an array [291, ..., 578, 581 ..., 868, ... , 125281, ..., 125568]

spy(C) - m(582, 292) - (idx,idx+H+2)

spy(D) - m(292, 582) - (idx,idx-H-2)

什么是m(293,292)?为什么坐标反转?这是因为spy如何绘制轴?对于numpy代码p(...)同样令人困惑。在我的(较小的)样本中,AB等都具有非预期的非零值。

顺便问一下,D22(idx)中有零吗?

在任何情况下,您都创建了4个稀疏矩阵,其值沿着一个对角线或其他对角线,具有周期性零间隙。

A(idx, idx+1)A具有相同的非零值,但在主对角线上是连续的。

numpy代码的简明版本是:

In [159]: idx=np.where(mask.ravel()==1)[0]
In [160]: A=sparse.csr_matrix((np.ones_like(idx),(idx,idx+1)),shape=(N,N))

我忽略了F v C订单和D22数组。如果我有D22矩阵,我会尝试使用D22.ravel[idx](以匹配我创建和索引mask的方式)。在比较矩阵的整体生成及其索引时,我不认为这些细节很重要。

A.tocoo().rowA.tocoo().col是查看非零元素的行索引和列索引的便捷方式。 A.nonzero()也会这样做(使用几乎相同的代码)。

是的,A[idx,:][:,idx+1]生成相同的子矩阵。

A[idx, idx+1]给出了这些对角线值的1d向量。

您需要将第一个索引数组转换为&#39;列&#39;用于选择块的向量(如MATLAB版本所示):

A[np.ix_(idx,idx+1)]  # or with
A[idx[:,None],idx+1]