由於您使用的是矩陣與其轉置的乘積,因此[m, n]
的值基本上將會是原始矩陣中的列m
和n
的點積。
我將使用下面的矩陣作爲一個玩具示例
a = np.array([[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1]])
>>> np.dot(a.T, a)
array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0],
[0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 2]])
它是形狀(3, 12)
,並具有7個非零項。其轉置產品當然是(12, 12)
的形狀,並有16個非零項,其中6個在對角線,因此它只需要存儲11個元素。
你能得到你的輸出矩陣的大小將是在以下兩種方式之一的一個好主意:
CSR FORMAT
如果你原來的矩陣具有C
非零列,您的新矩陣將至多有C**2
非零條目,其中C
在對角線中,並且確保不爲零,其餘條目中您只需保留一半,這樣至多是(C**2 + C)/2
非零值,零元素。當然,其中很多也是零,所以這可能是一個高估。
如果矩陣被存儲在csr
格式,則相應的scipy
對象的indices
屬性具有與所有非零元素的列索引的陣列,所以可以很容易地計算上述估計爲:
>>> a_csr = scipy.sparse.csr_matrix(a)
>>> a_csr.indices
array([ 2, 11, 1, 7, 10, 4, 11])
>>> np.unique(a_csr.indices).shape[0]
6
因此,有6列非零項,因此估計將是至多36個非零項,比真正的16
CSC數據的方式更
如果不是非零元素的列索引我們有行索引,我們實際上可以做一個更好的估計。對於兩列的點積是非零的,它們必須在同一行中有一個非零元素。如果給定行中有非零元素,則它們將爲產品貢獻R**2
非零元素。當你對所有行進行總結時,你必然會多次計算一些元素,所以這也是一個上限。
你的矩陣的非零元素的行索引是稀疏CSC矩陣indices
屬性,所以這個估計可以計算如下:
>>> a_csc = scipy.sparse.csc_matrix(a)
>>> a_csc.indices
array([1, 0, 2, 1, 1, 0, 2])
>>> rows, where = np.unique(a_csc.indices, return_inverse=True)
>>> where = np.bincount(where)
>>> rows
array([0, 1, 2])
>>> where
array([2, 3, 2])
>>> np.sum(where**2)
17
這是混賬接近真實16!它其實並不是一個巧合,這個估計實際上是一樣的:
>>> np.sum(np.dot(a.T,a),axis=None)
17
在任何情況下,下面的代碼應該讓你看到,估計是相當不錯的:
def estimate(a) :
a_csc = scipy.sparse.csc_matrix(a)
_, where = np.unique(a_csc.indices, return_inverse=True)
where = np.bincount(where)
return np.sum(where**2)
def test(shape=(10,1000), count=100) :
a = np.zeros(np.prod(shape), dtype=int)
a[np.random.randint(np.prod(shape), size=count)] = 1
print 'a non-zero = {0}'.format(np.sum(a))
a = a.reshape(shape)
print 'a.T * a non-zero = {0}'.format(np.flatnonzero(np.dot(a.T,
a)).shape[0])
print 'csc estimate = {0}'.format(estimate(a))
>>> test(count=100)
a non-zero = 100
a.T * a non-zero = 1065
csc estimate = 1072
>>> test(count=200)
a non-zero = 199
a.T * a non-zero = 4056
csc estimate = 4079
>>> test(count=50)
a non-zero = 50
a.T * a non-zero = 293
csc estimate = 294
道歉延時。感謝您的幫助!我擔心「存儲要求」這個短語含糊不清。您發送的估算代碼完全是*我希望學習的內容。你的方法是否受到sedgewick和flajolet一直在做的分析組合/漸近性工作(關於近似計數)的啓發?參考文獻: https://en.wikipedia.org/wiki/Analytic_combinatorics http://algo.inria.fr/flajolet/Publications/AnaCombi/ https://en.wikipedia.org/wiki/Asymptotic_theory https: //en.wikipedia.org/wiki/Approximate_counting_algorithm –
@ct。不幸的是,我住在遠離學術界的遙遠的土地上,所以我從來沒有聽說過任何你們聯繫過的東西。我的靈感只是對[CSR]的描述(http://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_.28CSR_or_CRS.29)和[CSC](http://en.wikipedia.org/wiki/Sparse_matrix #Compressed_sparse_column_.28CSC_or_CCS.29)格式。 – Jaime