2017-10-17 3 views
-2

Salut J'essaie de résoudre l'équation ci-dessous où A est une matrice clairsemée et ptotal est un tableau de nombres. Je dois additionner toutes les entrées dans une rangée en position diagonale.rapide façon de sommer les entrées de ligne en position diagonale de la matrice en python

A[ptotal, ptotal] = -sum(A[ptotal, :]) 

Le code semble être juste, mais depuis mon tableau ptotal est longue presque (100000 entrées), il est informatiquement pas efficace. Y at-il une méthode rapide pour résoudre ce problème.

+0

En quoi consiste la balise 'C++'? 'sparse' - un tableau chiffré avec beaucoup de 0 ou une matrice' scipy.sparse'? 'ptotal' - les valeurs sont-elles uniques ou y a-t-il des doublons? Un petit test peut aider. – hpaulj

+0

C'est une matrice 'scipy.sparse'. 'ptotal' est un tableau de valeurs commençant de 0 à 100000. Toutes les valeurs sont uniques, il n'y a pas de doublons. @hpaulj – ZAK

Répondre

0

D'abord une version réseau dense:

In [87]: A = np.arange(36).reshape(6,6) 
In [88]: ptotal = np.arange(6) 

En supposant ptotal est tous les indices de ligne, il peut être remplacé par un appel de méthode sum:

In [89]: sum(A[ptotal,:]) 
Out[89]: array([ 90, 96, 102, 108, 114, 120]) 
In [90]: A.sum(axis=0) 
Out[90]: array([ 90, 96, 102, 108, 114, 120]) 

Nous pouvons faire un tableau avec les valeurs sur la diagonale:

In [92]: np.diagflat(A.sum(axis=0)) 
Out[92]: 
array([[ 90, 0, 0, 0, 0, 0], 
     [ 0, 96, 0, 0, 0, 0], 
     [ 0, 0, 102, 0, 0, 0], 
     [ 0, 0, 0, 108, 0, 0], 
     [ 0, 0, 0, 0, 114, 0], 
     [ 0, 0, 0, 0, 0, 120]]) 

Ajouter à l'array d'origine - et le résultat est un tableau « somme nulle »:

In [93]: A -= np.diagflat(A.sum(axis=0)) 
In [94]: A 
Out[94]: 
array([[-90, 1, 2, 3, 4, 5], 
     [ 6, -89, 8, 9, 10, 11], 
     [ 12, 13, -88, 15, 16, 17], 
     [ 18, 19, 20, -87, 22, 23], 
     [ 24, 25, 26, 27, -86, 29], 
     [ 30, 31, 32, 33, 34, -85]]) 
In [95]: A.sum(axis=0) 
Out[95]: array([0, 0, 0, 0, 0, 0]) 

On pourrait faire la même chose avec clairsemés

In [99]: M = sparse.csr_matrix(np.arange(36).reshape(6,6)) 
In [100]: M 
Out[100]: 
<6x6 sparse matrix of type '<class 'numpy.int32'>' 
    with 35 stored elements in Compressed Sparse Row format> 
In [101]: M.sum(axis=0) 
Out[101]: matrix([[ 90, 96, 102, 108, 114, 120]], dtype=int32) 

une matrice diagonale clairsemée:

In [104]: sparse.dia_matrix((M.sum(axis=0),0),M.shape) 
Out[104]: 
<6x6 sparse matrix of type '<class 'numpy.int32'>' 
    with 6 stored elements (1 diagonals) in DIAgonal format> 
In [105]: _.A 
Out[105]: 
array([[ 90, 0, 0, 0, 0, 0], 
     [ 0, 96, 0, 0, 0, 0], 
     [ 0, 0, 102, 0, 0, 0], 
     [ 0, 0, 0, 108, 0, 0], 
     [ 0, 0, 0, 0, 114, 0], 
     [ 0, 0, 0, 0, 0, 120]], dtype=int32) 

Prenez la différence, obtenir une nouvelle matrice:

In [106]: M-sparse.dia_matrix((M.sum(axis=0),0),M.shape) 
Out[106]: 
<6x6 sparse matrix of type '<class 'numpy.int32'>' 
    with 36 stored elements in Compressed Sparse Row format> 
In [107]: _.A 
Out[107]: 
array([[-90, 1, 2, 3, 4, 5], 
     [ 6, -89, 8, 9, 10, 11], 
     [ 12, 13, -88, 15, 16, 17], 
     [ 18, 19, 20, -87, 22, 23], 
     [ 24, 25, 26, 27, -86, 29], 
     [ 30, 31, 32, 33, 34, -85]], dtype=int32) 

Il y a aussi une méthode setdiag

In [117]: M.setdiag(-M.sum(axis=0).A1) 
/usr/local/lib/python3.5/dist-packages/scipy/sparse/compressed.py:774: SparseEfficiencyWarning: Changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient. 
    SparseEfficiencyWarning) 
In [118]: M.A 
Out[118]: 
array([[ -90, 1, 2, 3, 4, 5], 
     [ 6, -96, 8, 9, 10, 11], 
     [ 12, 13, -102, 15, 16, 17], 
     [ 18, 19, 20, -108, 22, 23], 
     [ 24, 25, 26, 27, -114, 29], 
     [ 30, 31, 32, 33, 34, -120]], dtype=int32) 

Out[101] est une matrice 2d; .A1 le transforme en un tableau 1d que setdiag peut utiliser.

L'avertissement d'efficacité clairsemée est plus destiné à une utilisation itérative qu'à une application unique comme celle-ci. Pourtant, en regardant le code setdiag, je soupçonne que la première approche est plus rapide. Mais nous avons vraiment besoin de faire des tests de temps.

+0

M-sparse.dia_matrix ((M.sum (axe = 0), 0), M.shape) approche a diminué le temps de 38 sec à 1,2 sec quand len (ptotal) = 27000. Il y a donc une amélioration significative du temps. Merci beaucoup @hpaulj. – ZAK