Как я могу эффективно удалить столбец из разреженной матрицы?

Если я использую формат sparse.lil_matrix, как я могу легко и эффективно удалить столбец из матрицы?


person Brandon Pelfrey    schedule 03.03.2010    source источник


Ответы (6)


Я сам этого хотел, и, по правде говоря, пока нет отличного встроенного способа сделать это. Вот как это сделать. Я решил создать подкласс lil_matrix и добавить функцию remove_col. Если вы хотите, вы можете вместо этого добавить функцию removecol в класс lil_matrix в вашем файле lib/site-packages/scipy/sparse/lil.py. Вот код:

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.

person Justin Peel    schedule 03.03.2010

Гораздо проще и быстрее. Возможно, вам даже не понадобится преобразование в csr, но я точно знаю, что оно работает с разреженными матрицами csr, и преобразование между ними не должно быть проблемой.

from scipy import sparse

x_new = sparse.lil_matrix(sparse.csr_matrix(x)[:,col_list])
person Newmu    schedule 19.06.2013
comment
Почему вы используете матрицу CSR (сжатая разреженная строка) для нарезки столбцов? Одним из недостатков формата CSR являются «медленные операции нарезки столбцов (рассмотрите CSC)» (согласно scipy docs). Вместо этого, вероятно, следует использовать преобразование csc_matrix. - person silentser; 09.03.2017

Для разреженной матрицы 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. Проверьте tocsr() в документации lil_matrix

Однако обратите внимание, что переход от матриц csr к матрицам lil с использованием tolil() обходится дорого. Таким образом, этот выбор хорош, когда вам не требуется, чтобы ваша матрица была в формате lil.

person JRun    schedule 29.06.2015

Я новичок в python, поэтому мой ответ, вероятно, неверен, но мне было интересно, почему что-то вроде следующего не будет эффективным?

Допустим, ваша lil_matrix называется mat и вы хотите удалить i-й столбец:

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

После этого матрица превратится в coo_matrix, но вы можете снова превратить ее в lil_matrix.

Хорошо, я понимаю, что это должно будет создать две матрицы внутри hstack, прежде чем он выполнит назначение переменной mat, так что это будет похоже на наличие исходной матрицы плюс еще одна одновременно, но я думаю, если разреженность достаточно велика тогда я думаю, что не должно быть проблем с памятью (поскольку память (и время) - это вся причина использования разреженных матриц).

person nobody    schedule 30.05.2012
comment
Это похоже на вопрос, а не на ответ. - person Austin Henley; 21.10.2012


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 в качестве входных данных - возможно, это будет кому-то полезно.

person Michał Meina    schedule 03.06.2010
comment
Я рад, что кто-то пытается улучшить мою первую попытку. Однако строка if min(col_list) = W.shape[1]: во многих отношениях не имеет для меня никакого смысла. Во-первых, использование присваивания в аргументе if в Python является недопустимым синтаксисом. Во-вторых, почему вы проверяете мин. col_list с формой? Я думаю, что, может быть, вы хотели сделать if max(col_list) >= W.shape[1]:? Конечно, это означает, что нельзя использовать и отрицательные индексы, и нет никаких проверок на индексы ниже 0 и что с ними делать. - person Justin Peel; 03.06.2010

Глядя на примечания для каждой разреженной матрицы, особенно в нашем случае это матрица csc, она имеет следующие преимущества, перечисленные в документации [1]

  • эффективные арифметические операции CSC+CSC, CSC*CSC и т.д.
  • эффективная нарезка столбцов
  • быстрые матричные векторные произведения (CSR, BSR могут быть быстрее)

Если у вас есть индексы столбцов, которые вы хотите удалить, просто используйте нарезку. Для удаления строк используйте матрицу csr, поскольку она эффективна при нарезке строк.

person Community    schedule 26.12.2016