Python csr_矩阵的集合行
我有一个稀疏的csr_矩阵,我想将一行的值更改为不同的值。然而,我找不到一个简单有效的实现。这就是它必须做的:Python csr_矩阵的集合行,python,performance,sparse-matrix,Python,Performance,Sparse Matrix,我有一个稀疏的csr_矩阵,我想将一行的值更改为不同的值。然而,我找不到一个简单有效的实现。这就是它必须做的: A = csr_matrix([[0, 1, 0], [1, 0, 1], [0, 1, 0]]) new_row = np.array([-1, -1, -1]) print(set_row_csr(A, 2, new_row).todense()) >>> [[ 0, 1, 0], [
A = csr_matrix([[0, 1, 0],
[1, 0, 1],
[0, 1, 0]])
new_row = np.array([-1, -1, -1])
print(set_row_csr(A, 2, new_row).todense())
>>> [[ 0, 1, 0],
[ 1, 0, 1],
[-1, -1, -1]]
这是我当前的set\u row\u csr
:
def set_row_csr(A, row_idx, new_row):
A[row_idx, :] = new_row
return A
但这给了我一个
SparseEfficiencyWarning
。有没有办法不用手动索引杂耍来完成这项工作,或者这是我唯一的出路?最后,我设法用索引杂耍来完成这项工作
def set_row_csr(A, row_idx, new_row):
'''
Replace a row in a CSR sparse matrix A.
Parameters
----------
A: csr_matrix
Matrix to change
row_idx: int
index of the row to be changed
new_row: np.array
list of new values for the row of A
Returns
-------
None (the matrix A is changed in place)
Prerequisites
-------------
The row index shall be smaller than the number of rows in A
The number of elements in new row must be equal to the number of columns in matrix A
'''
assert sparse.isspmatrix_csr(A), 'A shall be a csr_matrix'
assert row_idx < A.shape[0], \
'The row index ({0}) shall be smaller than the number of rows in A ({1})' \
.format(row_idx, A.shape[0])
try:
N_elements_new_row = len(new_row)
except TypeError:
msg = 'Argument new_row shall be a list or numpy array, is now a {0}'\
.format(type(new_row))
raise AssertionError(msg)
N_cols = A.shape[1]
assert N_cols == N_elements_new_row, \
'The number of elements in new row ({0}) must be equal to ' \
'the number of columns in matrix A ({1})' \
.format(N_elements_new_row, N_cols)
idx_start_row = A.indptr[row_idx]
idx_end_row = A.indptr[row_idx + 1]
additional_nnz = N_cols - (idx_end_row - idx_start_row)
A.data = np.r_[A.data[:idx_start_row], new_row, A.data[idx_end_row:]]
A.indices = np.r_[A.indices[:idx_start_row], np.arange(N_cols), A.indices[idx_end_row:]]
A.indptr = np.r_[A.indptr[:row_idx + 1], A.indptr[(row_idx + 1):] + additional_nnz]
def set_row_csr(A,row_idx,new_row):
'''
替换CSR稀疏矩阵a中的一行。
参数
----------
A:csr_矩阵
改变矩阵
行_idx:int
要更改的行的索引
新行:np.array
表的行的新值列表
退换商品
-------
无(矩阵A已更改到位)
先决条件
-------------
行索引应小于表中的行数
新行中的元素数必须等于矩阵A中的列数
'''
断言sparse.isspmatrix_csr(A),“A应为csr_矩阵”
断言行_idx
physicalattraction的答案确实要快得多。这比我的解决方案要快得多,我的解决方案是只添加一个单独的矩阵和一行集合。虽然添加溶液比切片溶液快
对我来说,在csr_矩阵中设置行或在csc_矩阵中设置列的最快方法是自己修改底层数据
def time_copy(A, num_tries = 10000):
start = time.time()
for i in range(num_tries):
B = A.copy()
end = time.time()
return end - start
def test_method(func, A, row_idx, new_row, num_tries = 10000):
start = time.time()
for i in range(num_tries):
func(A.copy(), row_idx, new_row)
end = time.time()
copy_time = time_copy(A, num_tries)
print("Duration {}".format((end - start) - copy_time))
def set_row_csr_slice(A, row_idx, new_row):
A[row_idx,:] = new_row
def set_row_csr_addition(A, row_idx, new_row):
indptr = np.zeros(A.shape[1] + 1)
indptr[row_idx +1:] = A.shape[1]
indices = np.arange(A.shape[1])
A += csr_matrix((new_row, indices, indptr), shape=A.shape)
>>> A = csr_matrix((np.ones(1000), (np.random.randint(0,1000,1000), np.random.randint(0, 1000, 1000))))
>>> test_method(set_row_csr_slice, A, 200, np.ones(A.shape[1]), num_tries = 10000)
Duration 4.938395977020264
>>> test_method(set_row_csr_addition, A, 200, np.ones(A.shape[1]), num_tries = 10000)
Duration 2.4161765575408936
>>> test_method(set_row_csr, A, 200, np.ones(A.shape[1]), num_tries = 10000)
Duration 0.8432261943817139
切片解也会随着矩阵的大小和稀疏性而变得更糟
# Larger matrix, same fraction sparsity
>>> A = csr_matrix((np.ones(10000), (np.random.randint(0,10000,10000), np.random.randint(0, 10000, 10000))))
>>> test_method(set_row_csr_slice, A, 200, np.ones(A.shape[1]), num_tries = 10000)
Duration 18.335174798965454
>>> test_method(set_row_csr, A, 200, np.ones(A.shape[1]), num_tries = 10000)
Duration 1.1089558601379395
# Super sparse matrix
>>> A = csr_matrix((np.ones(100), (np.random.randint(0,10000,100), np.random.randint(0, 10000, 100))))
>>> test_method(set_row_csr_slice, A, 200, np.ones(A.shape[1]), num_tries = 10000)
Duration 13.371600151062012
>>> test_method(set_row_csr, A, 200, np.ones(A.shape[1]), num_tries = 10000)
Duration 1.0454308986663818
此
设置行\u csr
有问题。是的,它很快,而且似乎对一些测试用例有效。然而,在我的测试用例中,它似乎破坏了csr稀疏矩阵的内部csr结构。稍后尝试lil\u矩阵(A)
,您将看到错误消息。在physicalattraction的回答中,len(新行)
必须等于A.shape[1]
添加稀疏行时可能不感兴趣的内容
因此,根据他的回答,我提出了一种方法,在csr中设置行,同时保留sparcity属性。此外,我还添加了一种将密集数组转换为稀疏数组的方法(在数据、索引格式上)
def到_稀疏(密集arr):
稀疏=[(数据,索引)用于索引,如果数据!=0,则枚举(密集)中的数据
#将元组列表转换为列表
稀疏=列表(映射(列表,zip(*稀疏)))
#返回数据和索引
返回稀疏[0],稀疏[1]
def set_row_csr_unbounded(A、row_idx、new_row_数据、new_row_索引):
'''
替换CSR稀疏矩阵a中的一行。
参数
----------
A:csr_矩阵
改变矩阵
行_idx:int
要更改的行的索引
新的行数据:np.array
表的行的新值列表
新的行索引:np.array
新行的索引列表
退换商品
-------
无(矩阵A已更改到位)
先决条件
-------------
行索引应小于表中的行数
行数据和行索引的大小必须相同
'''
断言isspmatrix_csr(A),“A应为csr_矩阵”
断言行_idx
这是我的方法:
A = A.tolil()
A[index, :] = new_row
A = A.tocsr()
只需转换为
lil_矩阵
,更改行并转换回。您是否对其进行了时间测试?有了这些np.r\u
调用,我想知道它是否能节省时间。老实说:如果我对它进行了时间测试,我就不记得了。现在已经两年了。我创建了一个非常小的测试矩阵,使用set\u row\u csr
进行修改,并使用lil\u矩阵(a)
进行转换。没有出现错误,但。。。
A = A.tolil()
A[index, :] = new_row
A = A.tocsr()