l'expansion (l'ajout d'une ligne ou d'une colonne) un scipy.sparse matrix
supposons que j'ai une matrice NXN m (lil_matrix ou csr_matrix) de scipy.rares, et je veux qu'il soit (N+1)xN où M_modified[i,j] = M[i,j] pour 0 <= i < N (et tous j) et M[I,j] = 0 pour tout j. Fondamentalement, je veux ajouter une ligne de zéros sur le fond de la M et de préserver le reste de la matrice. Est-il un moyen de le faire sans copier les données?
3 réponses
Je ne pense pas qu'il y ait un moyen d'échapper vraiment à faire la copie. Ces deux types de matrices éparses stockent leurs données sous forme de tableaux Numpy (dans les attributs données et indices pour csr et dans les attributs données et lignes pour lil) en interne et les tableaux Numpy ne peuvent pas être étendus.
mise à Jour avec plus d'informations:
LIL signifie liste liée, mais l'implémentation actuelle n'est pas tout à fait à la hauteur du nom. Les tableaux Numpy utilisés pour data
et rows
sont tous les deux des objets de type. Chacun des objets de ces tableaux sont en fait des listes Python (une liste vide lorsque toutes les valeurs sont zéro dans une rangée). Les listes Python ne sont pas exactement des listes liées, mais elles sont assez proches et franchement un meilleur choix en raison de la recherche O(1). Personnellement, je ne vois pas tout de suite l'intérêt d'utiliser un tableau minuscule d'objets ici plutôt qu'une simple liste Python. Vous pouvez facilement changer l'implémentation lil actuelle pour utiliser des listes Python à la place vous permettrait d'ajouter une ligne sans copier la matrice entière.
Scipy n'a aucun moyen de le faire sans copier les données mais vous pouvez le faire vous-même en changeant les attributs qui définissent la matrice clairsemée.
Il y a 4 attributs qui composent le csr_matrix:
données: Un tableau contenant les valeurs réelles dans la matrice
indices: Un tableau contenant l'index des colonnes correspondant à chaque valeur dans les données
indptr: un tableau qui spécifie l'indice avant la première valeur dans les données pour chaque rangée. Si la ligne est vide, alors l'indice est le même que la colonne précédente.
forme: Un tuple contenant la forme de la matrice
si vous ajoutez simplement une rangée de zéros dans le bas, tout ce que vous avez à faire est de changer la forme et indptr pour votre matrice.
x = np.ones((3,5))
x = csr_matrix(x)
x.toarray()
>> array([[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.]])
# reshape is not implemented for csr_matrix but you can cheat and do it yourself.
x._shape = (4,5)
# Update indptr to let it know we added a row with nothing in it. So just append the last
# value in indptr to the end.
# note that you are still copying the indptr array
x.indptr = np.hstack((x.indptr,x.indptr[-1]))
x.toarray()
array([[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1.],
[ 0., 0., 0., 0., 0.]])
Voici une fonction pour gérer le cas plus général du vstacking de 2 csr_matrices. Vous finissez toujours par copier les tableaux numpy sous-jacents, mais il est encore beaucoup plus rapide que le scipy méthode vstack.
def csr_vappend(a,b):
""" Takes in 2 csr_matrices and appends the second one to the bottom of the first one.
Much faster than scipy.sparse.vstack but assumes the type to be csr and overwrites
the first matrix instead of copying it. The data, indices, and indptr still get copied."""
a.data = np.hstack((a.data,b.data))
a.indices = np.hstack((a.indices,b.indices))
a.indptr = np.hstack((a.indptr,(b.indptr + a.nnz)[1:]))
a._shape = (a.shape[0]+b.shape[0],b.shape[1])
return a
Je ne sais pas si vous êtes toujours à la recherche d'une solution, mais peut-être que d'autres peuvent chercher dans hstack
et vstack
- http://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.hstack.html. Je pense que nous pouvons définir un csr_matrix pour la seule ligne supplémentaire et ensuite vstack
avec la précédente matrice.