2016-03-27 17 views
6

Sto facendo alcuni calcoli su una matrice completa che è ridondante (cioè può essere una matrice triangolare senza perdere informazioni). Mi sono reso conto che posso calcolare solo la parte inferiore del triangolo per risultati più rapidi. Come posso proiettare il triangolo inferiore nella parte superiore una volta fatto?Come convertire la matrice triangolare in quadrato in NumPy?

In altre parole, come è possibile invertire il metodo np.tril?

print DF_var.as_matrix() 
# [[1 1 0 1 1 1 0 1 0 0 0] 
# [1 1 1 1 1 0 1 0 1 1 1] 
# [0 1 1 0 0 0 0 0 0 0 0] 
# [1 1 0 1 0 0 0 0 0 0 0] 
# [1 1 0 0 1 0 0 0 0 0 0] 
# [1 0 0 0 0 1 1 0 0 0 0] 
# [0 1 0 0 0 1 1 0 0 0 0] 
# [1 0 0 0 0 0 0 1 1 0 0] 
# [0 1 0 0 0 0 0 1 1 0 0] 
# [0 1 0 0 0 0 0 0 0 1 0] 
# [0 1 0 0 0 0 0 0 0 0 1]] 
print np.tril(DF_var.as_matrix()) 
# [[1 0 0 0 0 0 0 0 0 0 0] 
# [1 1 0 0 0 0 0 0 0 0 0] 
# [0 1 1 0 0 0 0 0 0 0 0] 
# [1 1 0 1 0 0 0 0 0 0 0] 
# [1 1 0 0 1 0 0 0 0 0 0] 
# [1 0 0 0 0 1 0 0 0 0 0] 
# [0 1 0 0 0 1 1 0 0 0 0] 
# [1 0 0 0 0 0 0 1 0 0 0] 
# [0 1 0 0 0 0 0 1 1 0 0] 
# [0 1 0 0 0 0 0 0 0 1 0] 
# [0 1 0 0 0 0 0 0 0 0 1]] 

Come riconvertirlo in una matrice completa?

risposta

5

Assumendo A come array di input, alcuni metodi sono elencati di seguito.

Approccio # 1: Utilizzando np.triu su una versione trasposta di A -

np.triu(A.T,1) + A 

Approccio # 2: Evitare np.triu con sommatoria diretto tra AT e A e quindi l'indicizzazione per impostare elementi diagonali -

out = A.T + A 
idx = np.arange(A.shape[0]) 
out[idx,idx] = A[idx,idx] 

Metodo n. 3: Come previo noi uno, ma compatta utilizzando in-builts per l'indicizzazione -

out = A.T + A 
np.fill_diagonal(out,np.diag(A)) 

Approccio # 4: Uguale a quello precedente, ma con l'indicizzazione booleano di impostare elementi diagonali -

out = A.T + A 
mask = np.eye(out.shape[0],dtype=bool) 
out[mask] = A[mask] 

Approccio # 5 : Utilizzo selezione basata maschera per elementi diagonali con np.where -

np.where(np.eye(A.shape[0],dtype=bool),A,A.T+A) 

Approccio # 6: Utilizzando selezione basata maschera per tutti gli elementi con np.where -

np.where(np.triu(np.ones(A.shape[0],dtype=bool),1),A.T,A) 

Runtime mette alla prova

Funzioni -

def func1(A): 
    return np.triu(A.T,1) + A 

def func2(A): 
    out = A.T + A 
    idx = np.arange(A.shape[0]) 
    out[idx,idx] = A[idx,idx] 
    return out 

def func3(A): 
    out = A.T + A 
    np.fill_diagonal(out,np.diag(A)) 
    return out 

def func4(A): 
    out = A.T + A 
    mask = np.eye(out.shape[0],dtype=bool) 
    out[mask] = A[mask] 
    return out 

def func5(A): 
    return np.where(np.eye(A.shape[0],dtype=bool),A,A.T+A) 

def func6(A): 
    return np.where(np.triu(np.ones(A.shape[0],dtype=bool),1),A.T,A) 

Timings -

In [140]: # Input array 
    ...: N = 5000 
    ...: A = np.tril(np.random.randint(0,9,(N,N))) 
    ...: 

In [141]: %timeit func1(A) 
    ...: %timeit func2(A) 
    ...: %timeit func3(A) 
    ...: %timeit func4(A) 
    ...: %timeit func5(A) 
    ...: %timeit func6(A) 
    ...: 
1 loops, best of 3: 617 ms per loop 
1 loops, best of 3: 354 ms per loop 
1 loops, best of 3: 354 ms per loop 
1 loops, best of 3: 395 ms per loop 
1 loops, best of 3: 597 ms per loop 
1 loops, best of 3: 440 ms per loop 

Sembra che l'approccio # 2 & # 3 sia piuttosto efficiente!

+0

wow @divakar, questa è una risposta incredibile e completa. È davvero utile vedere tutti questi metodi per attaccare questo problema. Farò sicuramente riferimento a questo più e più volte. –

+0

il confronto con le esibizioni è davvero bello, grazie per la risposta! – silgon

1

Poiché la matrice è simmetrica, si può fare:

m = np.array([1,1,0,1,1,1,0,1,1]).reshape((3,3)) 

# after some computation you get x 
x = np.tril(m) 

m_recomposed = x + x.transpose() - np.diag(np.diag(x)) 

#array([[1, 1, 0], 
#  [1, 1, 1], 
#  [0, 1, 1]]) 

#In [152]: np.array_equal(m, m_recomposed) 
#Out[152]: True 
Problemi correlati