Skip to content Skip to sidebar Skip to footer

Deleting Diagonal Elements Of A Numpy Array

Given input A = np.array([[1,2,3],[4,5,6],[7,8,9]]) array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) Need output : array([[2, 3], [4, 6], [7, 8]]) It is easy

Solution 1:

Approach #1

One approach with masking -

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

Sample run -

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]])

Approach #2

Using the regular pattern of non-diagonal elements that could be traced with broadcasted additions with range arrays -

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

Approach #3 (Strides Strikes!)

Abusing the regular pattern of non-diagonal elements from previous approach, we can introduce np.lib.stride_tricks.as_strided and some slicing help, like so -

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)

Runtime test

Approaches as 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)

Timings -

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

Solution 2:

Just with numpy, assuming a square matrix:

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

Solution 3:

I know I'm late to this party, but I have what I believe is a simper solution. So you want to remove the diagonal? Okay cool:

  • replace it with NaN
  • filter all but NaN (this converts to one dimensional as it can't assume the result will be square)
  • reset the dimensionality

`

 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)

Solution 4:

Solution steps:

  • Flatten your array
  • Delete the location of the diagonal elements which is at the location range(0, len(x_no_diag), len(x) + 1)
  • Reshape your array to (num_rows, num_columns - 1)

The function:

import numpy as np

defremove_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

Example:

>>> 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]])

Solution 5:

Perhaps the cleanest way, based on Divakar's first solution but using len(array) instead of array.shape[0], is:

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

Post a Comment for "Deleting Diagonal Elements Of A Numpy Array"