![](/img/trans.png)
[英]Finding maximum value and their indices in a sparse lil_matrix (Scipy/Python)
[英]SciPy/numpy: Only keep maximum value of a sparse matrix block
我正在嘗試在大型稀疏矩陣上操作(當前為12000 x 12000)。 我想要做的是將其塊設置為零,但將最大值保留在該塊內。 我已經有一個適用於密集矩陣的運行解決方案:
import numpy as np
from scipy.sparse import random
np.set_printoptions(precision=2)
#x = random(10,10,density=0.5)
x = np.random.random((10,10))
x = x.T * x
print(x)
def keep_only_max(a,b,c,d):
sub = x[a:b,c:d]
z = np.max(sub)
sub[sub < z] = 0
sizes = np.asarray([0,1,5,4])
sizes_sum = np.cumsum(sizes)
for i in range(1,len(sizes)):
current_i_min = sizes_sum[i-1]
current_i_max = sizes_sum[i]
for j in range(1,len(sizes)):
if i >= j:
continue
current_j_min = sizes_sum[j-1]
current_j_max = sizes_sum[j]
keep_only_max(current_i_min, current_i_max, current_j_min, current_j_max)
keep_only_max(current_j_min, current_j_max, current_i_min, current_i_max)
print(x)
但是,這不適用於稀疏矩陣(嘗試取消注釋頂部的行)。 有什么想法可以在不調用todense()的情況下有效實現嗎?
def keep_only_max(a,b,c,d):
sub = x[a:b,c:d]
z = np.max(sub)
sub[sub < z] = 0
對於稀疏的x
, sub
切片適用於csr
格式。 它不會像等效的密集切片那樣快,但是會創建x
的該部分的副本。
我必須檢查稀疏的max
函數。 但是我可以想象將sub
轉換為coo
格式,在.data
屬性上使用np.argmax
,並具有相應的row
和col
值,構造一個形狀相同但只有一個非零值的新矩陣。
如果您的塊以常規,不重疊的方式覆蓋x
,則建議您使用sparse.bmat
構造一個新矩陣。 這基本上收集了所有組件的coo
屬性,將它們連接到具有適當偏移量的一組數組中,並創建了一個新的coo
矩陣。
如果塊散落或重疊,則可能必須生成,然后將它們一個接一個地插入x
。 csr
格式應該可以解決此問題,但是會發出稀疏效率警告。 lil
應該可以更快地更改值。 我認為它將接受障礙。
我可以想象使用稀疏矩陣來執行此操作,但是設置測試用例和調試過程將花費一些時間。
多虧了hpaulj,我得以使用scipy.sparse.bmat
實現了一個解決方案:
from scipy.sparse import coo_matrix
from scipy.sparse import csr_matrix
from scipy.sparse import rand
from scipy.sparse import bmat
import numpy as np
np.set_printoptions(precision=2)
# my matrices are symmetric, so generate random symmetric matrix
x = rand(10,10,density=0.4)
x = x.T * x
x = x
def keep_only_max(a,b,c,d):
sub = x[a:b,c:d]
z = np.unravel_index(sub.argmax(),sub.shape)
i1 = z[0]
j1 = z[1]
new = csr_matrix(([sub[i1,j1]],([i1],[j1])),shape=(b-a,d-c))
return new
def keep_all(a,b,c,d):
return x[a:b,c:d].copy()
# we want to create a chessboard pattern where the first central block is 1x1, the second 5x5 and the last 4x4
sizes = np.asarray([0,1,5,4])
sizes_sum = np.cumsum(sizes)
# acquire 2D array to store our chessboard blocks
r = range(len(sizes)-1)
blocks = [[0 for x in r] for y in r]
for i in range(1,len(sizes)):
current_i_min = sizes_sum[i-1]
current_i_max = sizes_sum[i]
for j in range(i,len(sizes)):
current_j_min = sizes_sum[j-1]
current_j_max = sizes_sum[j]
if i == j:
# keep the blocks at the diagonal completely
sub = keep_all(current_i_min, current_i_max, current_j_min, current_j_max)
blocks[i-1][j-1] = sub
else:
# the blocks not on the digonal only keep their maximum value
current_j_min = sizes_sum[j-1]
current_j_max = sizes_sum[j]
# we can leverage the matrix symmetry and only calculate one new matrix.
m1 = keep_only_max(current_i_min, current_i_max, current_j_min, current_j_max)
m2 = m1.T
blocks[i-1][j-1] = m1
blocks[j-1][i-1] = m2
z = bmat(blocks)
print(z.todense())
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.