我正在尋找一種簡潔的方式來提取大小爲2x2的對角塊,它位於(2N)x(2N)numpy數組的主對角線上(也就是說,將會有N這樣的塊)。這概括了numpy.diag,它返回沿着主對角線的元素,人們可能認爲它是1x1塊(儘管當然numpy並不代表它們)。爲了更廣泛地描述這一點,人們可能希望從(MN)x(MN)陣列中提取N個M×M個塊。這似乎是scipy.linalg.block_diag的補充,在How can I transform blocks into a blockdiagonal matrix (NumPy)中進行了巧妙的討論,將塊放在block_diag放置它們的地方之外。從the solution to that question從一個numpy數組中提取對角塊
借款代碼,這裏是如何可以這樣設置:
>>> a1 = np.array([[1,1,1],[1,1,1],[1,1,1]])
>>> a2 = np.array([[2,2,2],[2,2,2],[2,2,2]])
>>> a3 = np.array([[3,3,3],[3,3,3],[3,3,3]])
>>> import scipy.linalg
>>> scipy.linalg.block_diag(a1, a2, a3)
array([[1, 1, 1, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 2, 2, 2, 0, 0, 0],
[0, 0, 0, 2, 2, 2, 0, 0, 0],
[0, 0, 0, 2, 2, 2, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 3, 3, 3],
[0, 0, 0, 0, 0, 0, 3, 3, 3],
[0, 0, 0, 0, 0, 0, 3, 3, 3]])
然後,我們希望有一個像
>>> A = scipy.linalg.block_diag(a1, a2, a3)
>>> extract_block_diag(A, M=3)
array([[[1, 1, 1],
[1, 1, 1],
[1, 1, 1]],
[[2, 2, 2],
[2, 2, 2],
[2, 2, 2]],
[[3, 3, 3],
[3, 3, 3],
[3, 3, 3]]])
功能繼續上面的類比與numpy.diag,人們也可能希望提取非對角塊:在第k個塊對角線上它們的N-k個。 (順便說一下,block_diag的擴展允許將block放置在主對角線上肯定會有用,但這不是這個問題的範圍。)在上述陣列的情況下,這可能會產生:
>>> extract_block_diag(A, M=3, k=1)
array([[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]],
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]])
我看到使用this question中涉及的stride_tricks旨在產生類似於此功能的東西,但我知道striding在字節級操作,這聽起來不太合適。
通過動機的方式,這是由於我希望提取協方差矩陣(即方差)的對角元素的情況,其中元素本身不是標量而是2×2矩陣。
編輯:基於the suggestion from Chris,我已經做了以下嘗試:
def extract_block_diag(A,M,k=0):
"""Extracts blocks of size M from the kth diagonal
of square matrix A, whose size must be a multiple of M."""
# Check that the matrix can be block divided
if A.shape[0] != A.shape[1] or A.shape[0] % M != 0:
raise StandardError('Matrix must be square and a multiple of block size')
# Assign indices for offset from main diagonal
if abs(k) > M - 1:
raise StandardError('kth diagonal does not exist in matrix')
elif k > 0:
ro = 0
co = abs(k)*M
elif k < 0:
ro = abs(k)*M
co = 0
else:
ro = 0
co = 0
blocks = np.array([A[i+ro:i+ro+M,i+co:i+co+M]
for i in range(0,len(A)-abs(k)*M,M)])
return blocks
在下面的結果將上面的數據返回:
D = extract_block_diag(A,3)
[[[1 1 1]
[1 1 1]
[1 1 1]]
[[2 2 2]
[2 2 2]
[2 2 2]]
[[3 3 3]
[3 3 3]
[3 3 3]]]
D = extract_block_diag(A,3,-1)
[[[0 0 0]
[0 0 0]
[0 0 0]]
[[0 0 0]
[0 0 0]
[0 0 0]]]
這看起來對我非常好。我認爲用一個包含列表理解的'numpy.array()'調用,輸出將是一個(a.shape [0]/M,M,M)數組。索引算法可以推廣到非對角塊。大! – berian
很高興我能幫到你。但是,請注意,我沒有真正考慮過當'M'不整齊地分成矩陣形狀時會發生什麼。如果您將其封裝在'extract_block_diag'函數中,您很可能需要進行一些輸入檢查。 – Chris