Numpy 稀疏矩阵和删除操作
阅读更多:Numpy 教程
稀疏矩阵简介
Numpy是目前最常用的数值计算库之一,其强大的矩阵计算功能深受广大工程师的喜爱。而对于大规模的数据集,通常会采用稀疏矩阵进行存储和计算,以降低空间和计算时间的复杂度。那么什么是稀疏矩阵呢?
稀疏矩阵是指矩阵中大部分元素为0,只有极少数的非零元素。在Numpy中,我们可以使用scipy.sparse模块来创建和操作稀疏矩阵。以下是一个稀疏矩阵的示例:
import numpy as np
from scipy.sparse import csr_matrix
A = np.array([[0, 4, 0], [3, 0, 7], [0, 2, 0]])
sparse_A = csr_matrix(A)
print(sparse_A)
输出结果为:
(1, 1) 4
(2, 0) 3
(2, 2) 7
(0, 1) 2
可以看到,真正有值的元素只有4个,其余的都是0。这样的矩阵在计算和存储时都具有很大的优势。
删除操作
在数字计算领域,删除操作经常用到,可以删除某一维度上的元素,或者删除整行/列等。Numpy提供的其中一个功能就是删除一个数组中的元素,即numpy.delete()函数。那么,在稀疏矩阵中是否也有类似的删除操作呢?
我们可以尝试在scipy.sparse模块中寻找这样的函数,但是很遗憾,目前没有直接的删除函数。那么我们可以自己编写实现删除操作的代码。
首先,我们需要知道删除的原理。在Dense矩阵中,删除一行/列等操作可以直接使用numpy.delete()函数实现,但是在Sparse矩阵中,删除操作需要涉及到Sparse matrix format的变化。比如,删除非0元素时,需要同时更新indices和data数组;删除整行/列时,还需要更新行/列偏移量。
自定义删除函数
接下来,我们编写一个自定义的删除函数,实现对稀疏矩阵的删除操作。为了方便起见,我们针对CSR格式的稀疏矩阵进行操作。
from scipy.sparse import csr_matrix
def sparse_delete(matrix, n, axis=0):
"""
matrix: csr_matrix, 待删除的稀疏矩阵
n: 删除的行号或列号
axis: 删除的轴,0为行,1为列,默认为0
"""
if axis == 0:
# 取出第n行非零元素的列号和值
row = matrix.getrow(n).indices
val = matrix.getrow(n).data
# 获取需要删除的非零元素的indices
indices_to_delete = list(row)
# 删除数据
new_data = list(matrix.data)
new_indices = list(matrix.indices)
for i in range(len(indices_to_delete)):
index = new_indices.index(indices_to_delete[i])
new_indices.pop(index)
new_data.pop(index)
# 更新行偏移量和非零元素的总数
new_offsets = list(matrix.indptr)
for i in range(n + 1, len(new_offsets)):
new_offsets[i] -= sum([1 for ind in indices_to_delete if ind < i])
new_offsets.pop()
# 返回新的稀疏矩阵
return csr_matrix((new_data, new_indices, new_offsets),shape=matrix.shape)
elif axis == 1:
# 取出第n列非零元素的行号和值
col = matrix.getcol(n).indices
val = matrix.getcol(n).data
# 获取需要删除的非零元素的indices
indices_to_delete = list(col)
# 删除数据
new_data = list(matrix.data)
new_indices = list(matrix.indices)
for i in range(len(indices_to_delete)):
index = new_indices.index(indices_to_delete[i])
new_indices.pop(index)
new_data.pop(index)
# 更新列偏移量和非零元素的总数
new_offsets = list(matrix.indptr)
new_offsets.pop(n + 1)
for i in range(n + 2, len(new_offsets)):
new_offsets[i] -= sum([1 for ind in indices_to_delete if ind < i])
# 获取新的行偏移量
new_offsets_row = [0]
for i in range(matrix.shape[0]):
new_offsets_row.append(new_offsets_row[-1] + len(matrix.getrow(i).indices))
# 返回新的稀疏矩阵
return csr_matrix((new_data, new_indices, new_offsets), shape=matrix.shape, indptr=new_offsets_row)
上述代码中,我们首先判断需要删除的是行还是列,然后按照相应的方式进行操作。对于删除行操作,我们先取出需要删除的非零元素的列号和值,然后获取这些非零元素在data和indices数组中的索引,依次从data和indices中删除这些元素,同时更新indptr数组中的偏移量。对于删除列操作,我们只需将上述操作中的行和列互换即可。
使用示例
接下来我们给出一些使用示例,展示我们编写的自定义删除函数的使用方法。
import numpy as np
from scipy.sparse import csr_matrix
from sparse_delete import sparse_delete
# 创建稀疏矩阵
A = np.array([[0, 1, 0, 0], [2, 0, 0, 4], [0, 0, 0, 0], [0, 0, 3, 0]])
sparse_A = csr_matrix(A)
# 删除第1行
sparse_A_deleted = sparse_delete(sparse_A, 1, axis=0)
print(sparse_A_deleted.toarray())
"""
输出结果为:
[[0 1 0 0]
[0 0 0 0]
[0 0 3 0]]
"""
# 删除第2列
sparse_A_deleted = sparse_delete(sparse_A, 2, axis=1)
print(sparse_A_deleted.toarray())
"""
输出结果为:
[[0 1 0]
[2 0 4]
[0 0 0]
[0 0 0]]
"""
总结
虽然Numpy中没有提供直接的稀疏矩阵删除函数,但是我们可以自己定义函数来实现这一功能。在实现时,我们需要根据稀疏矩阵格式的特点进行操作,如CSR格式需更新行偏移量、COO格式需更新nnz等。通过自定义删除函数,我们可以很方便地对稀疏矩阵进行删除操作,以满足不同场景的需求。
极客教程