簡體   English   中英

刪除numpy數組的對角線元素

[英]Deleting diagonal elements of a numpy array

給定輸入

A = np.array([[1,2,3],[4,5,6],[7,8,9]])
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

需要輸出:

array([[2, 3],
       [4, 6],
       [7, 8]])

使用迭代或循環很容易做到這一點,但應該有一種不使用循環的簡潔方法來做到這一點。 謝謝

方法#1

一種masking方法 -

A[~np.eye(A.shape[0],dtype=bool)].reshape(A.shape[0],-1)

樣品運行 -

In [395]: A
Out[395]: 
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])

In [396]: A[~np.eye(A.shape[0],dtype=bool)].reshape(A.shape[0],-1)
Out[396]: 
array([[2, 3],
       [4, 6],
       [7, 8]])

方法#2

使用非對角元素的規則模式,可以通過范圍數組的廣播添加進行跟蹤 -

m = A.shape[0]
idx = (np.arange(1,m+1) + (m+1)*np.arange(m-1)[:,None]).reshape(m,-1)
out = A.ravel()[idx]

方法#3 (Strides Strikes!)

濫用先前方法中非對角元素的常規模式,我們可以引入np.lib.stride_tricks.as_strided和一些slicing幫助,如下所示 -

m = A.shape[0]
strided = np.lib.stride_tricks.as_strided
s0,s1 = A.strides
out = strided(A.ravel()[1:], shape=(m-1,m), strides=(s0+s1,s1)).reshape(m,-1)

運行時測試

作為 funcs 的方法:

def skip_diag_masking(A):
    return A[~np.eye(A.shape[0],dtype=bool)].reshape(A.shape[0],-1)

def skip_diag_broadcasting(A):
    m = A.shape[0]
    idx = (np.arange(1,m+1) + (m+1)*np.arange(m-1)[:,None]).reshape(m,-1)
    return A.ravel()[idx]

def skip_diag_strided(A):
    m = A.shape[0]
    strided = np.lib.stride_tricks.as_strided
    s0,s1 = A.strides
    return strided(A.ravel()[1:], shape=(m-1,m), strides=(s0+s1,s1)).reshape(m,-1)

時間——

In [528]: A = np.random.randint(11,99,(5000,5000))

In [529]: %timeit skip_diag_masking(A)
     ...: %timeit skip_diag_broadcasting(A)
     ...: %timeit skip_diag_strided(A)
     ...: 
10 loops, best of 3: 56.1 ms per loop
10 loops, best of 3: 82.1 ms per loop
10 loops, best of 3: 32.6 ms per loop

就用 numpy,假設一個方陣:

new_A = numpy.delete(A,range(0,A.shape[0]**2,(A.shape[0]+1))).reshape(A.shape[0],(A.shape[1]-1))

我知道我參加這個聚會遲到了,但我認為這是一個更簡單的解決方案。 所以你想刪除對角線? 好酷:

  • 用 NaN 替換它
  • 過濾除 NaN 之外的所有內容(這將轉換為一維,因為它不能假設結果是方形的)
  • 重置維度

`

 arr = np.array([[1,2,3],[4,5,6],[7,8,9]]).astype(np.float)
 np.fill_diagonal(arr, np.nan)
 arr[~np.isnan(arr)].reshape(arr.shape[0], arr.shape[1] - 1)

解決步驟:

  • 展平你的陣列
  • 刪除位於位置range(0, len(x_no_diag), len(x) + 1)的對角線元素的位置
  • 將數組重塑為 (num_rows, num_columns - 1)

功能:

import numpy as np

def remove_diag(x):
    x_no_diag = np.ndarray.flatten(x)
    x_no_diag = np.delete(x_no_diag, range(0, len(x_no_diag), len(x) + 1), 0)
    x_no_diag = x_no_diag.reshape(len(x), len(x) - 1)
    return x_no_diag

示例:

>>> x = np.random.randint(5, size=(3,3))
array([[0, 2, 3],
       [3, 4, 1],
       [2, 4, 0]])
>>> remove_diag(x)
array([[2, 3],
       [3, 1],
       [2, 4]])

如果您不介意創建一個新數組,那么您可以使用列表理解。

A = np.array([A[i][A[i] != A[i][i]] for i in range(len(A))])

重新運行與@Divakar 相同的方法,

A = np.random.randint(11,99,(5000,5000))

skip_diag_masking
85.7 ms ± 1.55 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
skip_diag_broadcasting
163 ms ± 1.77 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
skip_diag_strided
52.5 ms ± 2.54 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
skip_diag_list_comp
101 ms ± 347 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

也許最干凈的方法,基於Divakar 的第一個解決方案,但使用len(array)而不是array.shape[0] ,是:

array_without_diagonal = array[~np.eye(len(array), dtype=bool)].reshape(len(array), -1)

我喜歡這里的所有答案,但我想添加一個,以防您的 numpy 對象具有超過 2 個維度。 在這種情況下,您可以使用 Divakar 方法 #1 的以下調整:

def remove_diag(A):
    removed = A[~np.eye(A.shape[0], dtype=bool)].reshape(A.shape[0], int(A.shape[0])-1, -1)
    return np.squeeze(removed)

另一種方法是使用 numpy.delete()。 假設方陣,你可以使用:

numpy.delete(A,range(0,A.shape[0]**2,A.shape[0])).reshape(A.shape[0],A.shape[1]-1)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM