如何高效地从稀疏矩阵中删除一列?

18

如果我正在使用sparse.lil_matrix格式,如何轻松高效地从矩阵中删除一列?

6个回答

12

更简单和更快速。您甚至可能不需要将其转换为csr格式,但我只知道csr稀疏矩阵可以使用,并且在两种格式之间转换不应该成为问题。

from scipy import sparse

x_new = sparse.lil_matrix(sparse.csr_matrix(x)[:,col_list])

3
为什么你在使用CSR(压缩稀疏行)矩阵进行列切片?CSR格式的一个缺点是“慢速的列切片操作(应该考虑CSC)”(根据scipy文档)。你可能应该使用csc_matrix转换代替。 - silentser

8

我自己也一直想要实现这个功能,但事实上目前还没有很好的内置方法来完成它。这里提供了一种方法。我选择创建了一个lil_matrix的子类,并添加了remove_col函数。如果您愿意,您可以将remove_col函数添加到lib/site-packages/scipy/sparse/lil.py文件中的lil_matrix类中。以下是代码:

from scipy import sparse
from bisect import bisect_left

class lil2(sparse.lil_matrix):
    def removecol(self,j):
        if j < 0:
            j += self.shape[1]

        if j < 0 or j >= self.shape[1]:
            raise IndexError('column index out of bounds')

        rows = self.rows
        data = self.data
        for i in xrange(self.shape[0]):
            pos = bisect_left(rows[i], j)
            if pos == len(rows[i]):
                continue
            elif rows[i][pos] == j:
                rows[i].pop(pos)
                data[i].pop(pos)
                if pos == len(rows[i]):
                    continue
            for pos2 in xrange(pos,len(rows[i])):
                rows[i][pos2] -= 1

        self._shape = (self._shape[0],self._shape[1]-1)

我已经试过了,没有发现任何漏洞。我认为这比我知道的切割列出来创建新矩阵要好得多。

我还决定加入一个removerow函数,但我不认为它像removecol那样好用。我受限于无法按我想要的方式从ndarray中删除一行。下面是可以添加到上述类中的removerow函数。

    def removerow(self,i):
        if i < 0:
            i += self.shape[0]

        if i < 0 or i >= self.shape[0]:
            raise IndexError('row index out of bounds')

        self.rows = numpy.delete(self.rows,i,0)
        self.data = numpy.delete(self.data,i,0)
        self._shape = (self._shape[0]-1,self.shape[1])

也许我应该将这些函数提交到Scipy代码库中。

8
对于一个稀疏的csr矩阵(X)和一个需要删除的索引列表(index_to_drop):
to_keep = list(set(xrange(X.shape[1]))-set(index_to_drop))    
new_X = X[:,to_keep]

将lil_matrices转换为csr_matrices非常容易。请查看lil_matrix文档中的tocsr()。

但是请注意,使用tolil()从csr矩阵转换为lil矩阵是很耗费资源的。因此,仅当您不需要将矩阵保留在lil格式中时才选择此选项。


2

我是一名新手,所以我的答案可能不正确,但我想知道为什么像下面这样的代码不够高效?

假设你的lil_matrix被称为mat,你想要删除第i列:

mat=hstack( [ mat[:,0:i] , mat[:,i+1:] ] )

现在,在此之后,矩阵将变为coo_matrix,但您可以将其转换回lil_matrix。
好的,我理解这将在hstack内创建两个矩阵,然后才对mat变量进行赋值,因此会像同时拥有原始矩阵和另一个矩阵一样,但我想如果稀疏度足够大,那么就不应该有任何内存问题(由于内存(和时间)是使用稀疏矩阵的整个原因)。

这看起来像是一个问题,而不是一个答案。 - Austin Henley

0

def removecols(W, col_list):
        if min(col_list) = W.shape[1]:
                raise IndexError('column index out of bounds')
        rows = W.rows
        data = W.data
        for i in xrange(M.shape[0]):
            for j in col_list:
                pos = bisect_left(rows[i], j)
                if pos == len(rows[i]):
                        continue
                elif rows[i][pos] == j:
                        rows[i].pop(pos)
                        data[i].pop(pos)
                        if pos == len(rows[i]):
                                continue
                for pos2 in xrange(pos,len(rows[i])):
                        rows[i][pos2] -= 1
        W._shape = (W._shape[0], W._shape[1]-len(col_list))
        return W

我刚刚重写了你的代码,使其能够使用col_list作为输入 - 或许这对某些人会有所帮助。


1
我很高兴有人试图改进我的第一个尝试。然而,if min(col_list) = W.shape[1]:这行代码在很多方面都不合理。首先,在Python中,在if语句中使用赋值是无效的语法。其次,为什么要检查col_list的最小值和形状?也许你是想做if max(col_list) >= W.shape[1]:吧?当然,这意味着您也不能使用负索引,并且没有对索引低于0的情况进行任何检查以及如何处理它们的操作。 - Justin Peel

0

通过查看每个稀疏矩阵的注释,特别是在我们的情况下是csc矩阵,它具有以下优点,如文档中所列[1]

  • 高效的算术运算CSC + CSC,CSC * CSC等。
  • 高效的列切片。
  • 快速的矩阵向量乘积(CSR,BSR可能更快)。

如果您要删除列索引,请使用切片。对于删除行,请使用csr矩阵,因为它在行切片方面效率高。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接