Me gustaría escribir una función que normaliza las filas de una gran matriz dispersa (de tal manera que se suma a uno).

from pylab import *
import scipy.sparse as sp

def normalize(W):
    z = W.sum(0)
    z[z < 1e-6] = 1e-6
    return W / z[None,:]

w = (rand(10,10)<0.1)*rand(10,10)
w = sp.csr_matrix(w)
w = normalize(w)

Sin embargo esto le da la siguiente excepción:

File "/usr/lib/python2.6/dist-packages/scipy/sparse/base.py", line 325, in __div__
     return self.__truediv__(other)
File "/usr/lib/python2.6/dist-packages/scipy/sparse/compressed.py", line 230, in  __truediv__
   raise NotImplementedError

Hay razonablemente soluciones simples? He mirado en este, pero todavía estoy claro en cuanto a la forma de hacer la división.

  • Esto es, básicamente, un duplicado de: stackoverflow.com/questions/12237954/… como no importa si su fila elementwise la multiplicación o la división. Por supuesto, si alguien tiene una mejor respuesta, genial 🙂
  • No estoy de acuerdo, este es un problema diferente. El duplicado se apuntaba a qué elemento sabio multiplicación, mientras que esta pregunta parece querer dividir cada fila por un valor diferente (en lugar de todos los no-cero de los elementos por el mismo valor). Aarón McDaid de la solución a continuación debe trabajar de manera eficiente (y no requiere ningún tipo de copia de datos).
  • AFAICT es un duplicado de la stackoverflow.com/questions/8358962/…
InformationsquelleAutor sterne | 2012-09-06

4 Comentarios

  1. 39

    Este ha sido implementado en scikit-learn sklearn.preprocesamiento.normalizar.

    from sklearn.preprocessing import normalize
    w_normalized = normalize(w, norm='l1', axis=1)

    axis=1 debe normalizar por filas, axis=0 para normalizar por la columna. Utilice el argumento opcional copy=False para modificar la matriz en su lugar.

    • Tenga en cuenta que si usted normalizar las funciones (eje=0), a continuación, devuelve la matriz es de tipo » csc » incluso si w era un ‘csr’. Esto puede ser desagradable si usted contó en un ‘csr’
  2. 3

    aquí está mi solución.

    • transposición de Una
    • calcular la suma de cada col
    • formato de la diagonal de la matriz B con el recíproco de la suma
    • A*B es igual a la normalización
    • transponer C

      import scipy.sparse as sp
      import numpy as np
      import math
      
      minf = 0.0001
      
      A = sp.lil_matrix((5,5))
      b = np.arange(0,5)
      A.setdiag(b[:-1], k=1)
      A.setdiag(b)
      print A.todense()
      A = A.T
      print A.todense()
      
      sum_of_col = A.sum(0).tolist()
      print sum_of_col
      c = []
      for i in sum_of_col:
          for j in i:
              if math.fabs(j)<minf:
                  c.append(0)
              else:
                  c.append(1/j)
      
      print c
      
      B = sp.lil_matrix((5,5))
      B.setdiag(c)
      print B.todense()
      
      C = A*B
      print C.todense()
      C = C.T
      print C.todense()
  3. 1

    Mientras Aarons respuesta es correcta, he implementado una solución cuando yo quería normalizar con respecto a la máxima de la absoluta valores, que sklearn no está ofreciendo. Mi método utiliza el cero entradas y las encuentra en el csr_matrix.matriz de datos para reemplazar los valores de allí rápidamente.

    def normalize_sparse(csr_matrix):
        nonzero_rows = csr_matrix.nonzero()[0]
        for idx in np.unique(nonzero_rows):
            data_idx = np.where(nonzero_rows==idx)[0]
            abs_max = np.max(np.abs(csr_matrix.data[data_idx]))
            if abs_max != 0:
                csr_matrix.data[data_idx] = 1./abs_max * csr_matrix.data[data_idx]

    En contraste con el sunan de la solución, este método no requiere ningún tipo de casting de la matriz dentro de la densa formato (lo que puede plantear problemas de memoria) y no de la matriz de multiplicaciones bien. He probado el método en una matriz dispersa de forma (35’000, 486’000) y se llevó a ~ 18 segundos.

  4. 0

    Sin importar sklearn, convirtiendo a la densa o la multiplicación de matrices y mediante la explotación de la representación de datos de la rse de las matrices:

    from scipy.sparse import isspmatrix_csr
    
    def normalize(W):
        """ row normalize scipy sparse csr matrices inplace.
        """
        if not isspmatrix_csr(W):
            raise ValueError('W must be in CSR format.')
        else:
            for i in range(W.shape[0]):
                row_sum = W.data[W.indptr[i]:W.indptr[i+1]].sum()
                if row_sum != 0:
                    W.data[W.indptr[i]:W.indptr[i+1]] /= row_sum

    Recuerde que W.indices es la matriz de índices de columna,
    W.data es la matriz de los correspondientes valores distintos de cero
    y W.indptr puntos de la fila comienza en los índices y datos.

    Puede agregar un numpy.abs() cuando se toma la suma si usted necesita la L1 norma o uso numpy.max() para normalizar por el valor máximo por fila.

Dejar respuesta

Please enter your comment!
Please enter your name here