python - 如何有效地将稀疏矩阵列添加到另一个稀疏矩阵中的每一列?
问题描述
感谢您花时间看我的问题。
我正在尝试创建一个程序,该程序可以将值数组添加到稀疏矩阵中的每个“列”,如下所示:
A = [[1,1,0],
[0,0,1],
[1,0,1]]
B = [[1],
[0],
[1]]
A + B = [[2,2,1],
[0,0,1],
[2,1,2]]
以稀疏矩阵的坐标格式表示,如下所示:
A = [[0,0,1],
[2,0,1],
[0,1,1],
[1,2,1],
[2,2,1]]
B = [[0,0,1],
[2,0,1]]
A + B = [[0,0,2],
[2,0,2],
[0,1,2],
[2,1,1],
[0,2,1],
[1,2,1],
[2,2,2]]
我正在处理由于其大小而必须以稀疏方式表示的大型矩阵。我需要能够将一列值添加到矩阵中的每一列,但使用专门处理稀疏三元组的算法。
我花了一整天的时间来解决这个问题,实际上是连续 10 个小时,我真的很震惊,我无法在任何地方找到一个好的答案。用乘法执行这个操作既简单又高效,但是 scipy 或 numpy 中似乎没有任何时间和空间有效的解决方案可以做到这一点,或者如果有,当我发现它会杀了我。我试图实施一个解决方案,但它最终效率低下。
从本质上讲,我的解决方案在技术上确实有效,但时间效率却很差,它遵循以下步骤:
- 检查 A 和 B 之间的行上的共享值,将相关的三元组值加在一起
- 添加来自 A 的唯一值
- 在矩阵的列中为 i 添加 B_row_i、x_i、B_value_i,检查我们没有从 A 三元组中添加逐字记录值。
至少,我认为这就是它的作用......我现在完全筋疲力尽了,我开始在编码时逐步退出。如果有人能提出快速解决方案,将不胜感激!
from scipy.sparse import coo_matrix
from tqdm import tqdm
class SparseCoordinates:
def __init__(self,coo_a,coo_b):
self.shape = coo_a.shape
self.coo_a_rows = coo_a.row
self.coo_a_cols = coo_a.col
self.coo_a_data = coo_a.data
self.coo_b_rows = coo_b.row
self.coo_b_cols = coo_b.col
self.coo_b_data = coo_b.data
self.coo_c_rows = []
self.coo_c_cols = []
self.coo_c_data = []
def __check(self,a,b,c,lr,lc,lv):
for i in range(len(lr)):
if lr[i] == a and lc[i] == b and lv[i] == c:
return True
return False
def __check_shared_rows(self):
for i in tqdm(range(len(self.coo_a_rows))):
for j in range(len(self.coo_b_rows)):
if self.coo_a_rows[i] == self.coo_b_rows[j]:
self.coo_c_rows.append(self.coo_a_rows[i])
self.coo_c_cols.append(self.coo_a_cols[i])
self.coo_c_data.append(self.coo_a_data[i] + self.coo_b_data[j])
def __add_unique_from_a(self):
a_unique = set(self.coo_a_rows) - set(self.coo_b_rows)
for i in tqdm(range(len(self.coo_a_rows))):
if self.coo_a_rows[i] in a_unique:
self.coo_c_rows.append(self.coo_a_rows[i])
self.coo_c_cols.append(self.coo_a_cols[i])
self.coo_c_data.append(self.coo_a_data[i])
def __add_all_remaining_from_b(self):
for i in tqdm(range(len(self.coo_b_rows))):
for j in range(self.shape[1]):
if not self.__check(self.coo_b_rows[i],j,self.coo_b_data[i],
self.coo_a_rows,self.coo_a_cols,self.coo_a_data):
self.coo_c_rows.append(self.coo_b_rows[i])
self.coo_c_cols.append(j)
self.coo_c_data.append(self.coo_b_data[i])
def add(self):
self.__check_shared_rows()
self.__add_unique_from_a()
self.__add_all_remaining_from_b()
return coo_matrix((self.coo_c_data,(self.coo_c_rows,self.coo_c_cols)),shape=self.shape)
解决方案
对于numpy
数组,A+B
由于broadcasting
. broadcasting
在核心迭代级别实现,利用strides
. scipy.sparse
不执行broadcasting
。如果B
扩展为 (3,3) 矩阵以匹配A
加法确实有效
In [76]: A = np.array([[1,1,0],
...: [0,0,1],
...: [1,0,1]])
...:
...: B = np.array([[1],
...: [0],
...: [1]])
In [77]: B.shape
Out[77]: (3, 1)
In [78]: A+B
Out[78]:
array([[2, 2, 1],
[0, 0, 1],
[2, 1, 2]])
疏:
In [79]: from scipy import sparse
In [81]: M=sparse.csr_matrix(A);N=sparse.csr_matrix(B)
矩阵乘法非常适合稀疏矩阵:
In [82]: M@N
Out[82]:
<3x1 sparse matrix of type '<class 'numpy.int64'>'
with 3 stored elements in Compressed Sparse Row format>
In [84]: N.T@M
Out[84]:
<1x3 sparse matrix of type '<class 'numpy.int64'>'
with 3 stored elements in Compressed Sparse Column format>
矩阵乘法用于行或列索引以及求和。
定义一个助手:
In [86]: O=sparse.csr_matrix([1,1,1])
In [87]: O
Out[87]:
<1x3 sparse matrix of type '<class 'numpy.int64'>'
with 3 stored elements in Compressed Sparse Row format>
In [88]: N@O
Out[88]:
<3x3 sparse matrix of type '<class 'numpy.int64'>'
with 6 stored elements in Compressed Sparse Row format>
在总和中使用它:
In [89]: M+N@O
Out[89]:
<3x3 sparse matrix of type '<class 'numpy.int64'>'
with 7 stored elements in Compressed Sparse Row format>
In [90]: _.A
Out[90]:
array([[2, 2, 1],
[0, 0, 1],
[2, 1, 2]])
这个矩阵比M
- 更少的 0 更稀疏。这减少了使用稀疏矩阵的好处。
coo_matrix
格式用于创建矩阵和构建新矩阵,如sparse.bmat
,sparse.hstack
和sparse.vstack
,但csr_matrix
用于大多数数学。有时可以通过intptr
数组迭代“行”来进行自定义数学运算。有各种各样的答案可以做到这一点。使用属性的数学coo
通常不是一个好主意。
但是,由于coo
在转换为 时会对重复项求和csr
,因此我可能可以对M
和的 coo 格式进行合理的求和N
。
In [91]: Mo=M.tocoo(); No=N.tocoo()
In [95]: Oo=O.tocoo()
In [98]: rows = np.concatenate((Mo.row, Oo.row))
In [99]: cols = np.concatenate((Mo.col, Oo.col))
In [100]: data = np.concatenate((Mo.data, Oo.data))
In [101]: sparse.coo_matrix((data,(rows,cols)),M.shape)
Out[101]:
<3x3 sparse matrix of type '<class 'numpy.int64'>'
with 8 stored elements in COOrdinate format>
In [102]: _.A
Out[102]:
array([[2, 2, 1],
[0, 0, 1],
[1, 0, 1]])
这里我加入了Mo
和的属性Oo
。我可以对 的属性做同样的事情No
,但是因为我已经有了Oo
,所以我认为这是值得的。我会把它留给你。
In [103]: Oo.row,Oo.col,Oo.data
Out[103]:
(array([0, 0, 0], dtype=int32),
array([0, 1, 2], dtype=int32),
array([1, 1, 1]))
In [104]: No.row,No.col,No.data
Out[104]: (array([0, 2], dtype=int32), array([0, 0], dtype=int32), array([1, 1]))
我不知道这种coo
方法是否值得努力。
推荐阅读
- node.js - 在弹性搜索中跨不同索引自动完成和搜索
- javascript - 单击特定项目时执行js函数
- excel - 为什么 Vlookup 给我错误的答案?
- node.js - 使用 nodejs 对 graphql 使用什么
- .net - 要在类的新实例之间持久化的静态列表
- php - 在php中将十进制数量赋给类购物车
- python - 如何使用 Pandas 动态分配列名?
- html - 传递 W3.org 验证器时出错:方案数据中的非法字符
- iis - 无法连接到本地网络 IP:错误 404
- powershell - 适用于 Sky for Business 的 Foreach Powershell 命令