Sum of antidiagonal of a matrix
Using
m <- matrix(c(2, 3, 1, 4, 2, 5, 1, 3, 7), 3)
1) Reverse the rows as shown (or the columns - not shown), take the diagonal and sum:
sum(diag(m[nrow(m):1, ]))
## [1] 4
2) or use row
and col
like this:
sum(m[c(row(m) + col(m) - nrow(m) == 1)])
## [1] 4
This generalizes to other anti-diagonals since row(m) + col(m) - nrow(m)
is constant along all anti-diagonals. For such a generalization it might be more convenient to write the part within c(...)
as row(m) + col(m) - nrow(m) - 1 == 0
since then replacing 0 with -1 uses the superdiagonal and with +1 uses the subdiagonal. -2 and 2 use the second superdiagonal and subdiagonal respectively and so on.
3) or use this sequence of indexes:
n <- nrow(m)
sum(m[seq(n, by = n-1, length = n)])
## [1] 4
4) or use outer
like this:
n <- nrow(m)
sum(m[!c(outer(1:n, n:1, "-"))])
## [1] 4
This one generalizes nicely to other anti-diagonals too as outer(1:n, n:1, "-")
is constant along anti-diagonals. We can write m[outer(1:n, n:1) == 0]
and if we replace 0 with -1 we get the super anti-diagonal and with +1 we get the sub anti-diagonal. -2 and 2 give the super super and sub sub antidiagonals. For example sum(m[c(outer(1:n, n:1, "-") == 1)])
is the sum of the sub anti-diagonal.
get the sum of diagonals and anti diagonals 2D N*N matrix using numpy
Use np.diag
. Suppose you select element a[i, j]
. Then,
>>> diagonal = np.diag(a, j-i)
>>> antidiagonal = np.diag(a[:, ::-1], N-j-1-i)
>>> np.sum(diagonal) + np.sum(antidiagonal)
This works, because j-i
is the number of columns above the diagonal entry (i, i)
. So np.diag(a, j-i)
correctly picks the diagonal corresponding to 8.
For the antidiagonal, I simply flip the array horizontally (by reversing the columns), and then run np.diag
again. But now, the new column index is N-j-1
, while the row index remains i
.
If you find a[:, ::-1]
unreadable, you could use np.fliplr(a)
or np.flipud(a)
instead, as Eric suggests.
Sum along diagonal and anti-diagonal lines in 2D array - NumPy / Python
you can use .diag
like this:
import numpy as np
arr = np.array([[1, 0, 0], [1, 0, 0], [0, 1, 0]])
left_diag = [np.sum(np.diag(np.fliplr(arr), d)) for d in range(len(arr) - 1, -len(arr), -1)]
right_diag = [np.sum(np.diag(arr, d)) for d in range(len(arr) - 1, -len(arr), -1)]
print("left:", left_diag)
print("right:", right_diag)
Output:
left: [1, 1, 0, 1, 0]
right: [0, 0, 1, 2, 0]
it returns all the element in a diagonal of a given offset. to get all the offsets in the order you mentioned, we go from +2 to -2, then for each diagonal get the sum of elements.
to get the left diagonal we first flip arr using .fliplr
numpy sum antidiagonals of array
There is a trace
function that gives the sum of a diagonal. You can specify the offset and 2 axes (0 and 1 are the defaults). And to get the antidiagonal, you just need to flip one dimension. np.flipud
does that, though it's just [::-1,...]
indexing.
Putting those together,
np.array([np.trace(np.flipud(array),offset=k) for k in range(-1,3)])
matches your new_array
.
It still loops over the possible values of l
(4 in this case). trace
itself is compiled.
In this small case, it's actually slower than your double loop (2x3 steps). Even if I move the flipud
out of the inner loop, it is still slower. I don't know how this scales for larger arrays.
Part of the problem with vectorizing this even further is that fact that each diagonal has a different length.
In [331]: %%timeit
array1 = array[::-1]
np.array([np.trace(array1,offset=k) for k in range(-1,3)])
.....:
10000 loops, best of 3: 87.4 µs per loop
In [332]: %%timeit
new_array = np.zeros([array.shape[0] + array.shape[1] - 1] + list(array.shape[2:]))
for i in range(2):
for j in range(3):
new_array[i+j] += array[i,j]
.....:
10000 loops, best of 3: 43.5 µs per loop
scipy.sparse
has a dia
format, which stores the values of nonzero diagonals. It stores a padded array of values, along with the offsets.
array([[12, 0, 0, 0],
[ 8, 13, 0, 0],
[ 4, 9, 14, 0],
[ 0, 5, 10, 15],
[ 0, 1, 6, 11],
[ 0, 0, 2, 7],
[ 0, 0, 0, 3]])
array([-3, -2, -1, 0, 1, 2, 3])
While that's a way of getting around the issue of variable diagonal lengths, I don't think it helps in this case where you just need their sums.
How to check if the terms on the anti diagonal of a matrix are the same?
Array indices in C are 0-based; thus, if your matrix is NxN, the indices for any element on the anti-diagonal will sum to N-1, not N.
Sum of diagonal elements in a matrix
Try this for summing your second diagonal:
sum(a[i][n-i-1] for i in range(n))
The inner loop accesses these entries:
>>> n = 3
>>> [(i, n-i-1) for i in range(n)]
[(0, 2), (1, 1), (2, 0)]
And the summed value of this diagonal for your sample matrix is:
>>> n = 3
>>> sum(a[i][n-i-1] for i in range(n))
19
The mistake in your code is to use the same expression for both dimensions:
a[n-i-1][n-i-1]
which will process the first diagonal again in reverse order [(2, 2), (1, 1), (0, 0)]
giving you the same sum twice.
R Shiny - Extracting Anti-Diagonal elements in matrix using for-loops
Solved the issue by changing the codes to below:
for(i in 1:3) {
for(j in 3:1) {
my_table[,1] <- rev(my_input_matrix[i+(j-1)*3])[i]
my_table[,2] <- my_input_matrix[i+(j-1)*3][i]
}
}
Java add matrix antidiagonal elements
In your first example the loop ends as soon as j != 0
, if t > 1
this means that it will end immediately, making no iterations at all.
How to find the sum of all anti-diagonals?
First note that outer
can produce the matrix d
without explicitly listing its elements.
matrix(c(0, 1, 2, 1, 2, 3, 2, 3, 4), 3)
#> [,1] [,2] [,3]
#> [1,] 0 1 2
#> [2,] 1 2 3
#> [3,] 2 3 4
outer(0:2, 0:2, `+`)
#> [,1] [,2] [,3]
#> [1,] 0 1 2
#> [2,] 1 2 3
#> [3,] 2 3 4
Created on 2022-03-24 by the reprex package (v2.0.1)
And use it in a function.
sumAntiDiag <- function(M){
nr <- nrow(M)
nc <- ncol(M)
d <- outer(seq.int(nr), seq.int(nc), `+`)
tapply(M, d, sum)
}
n <- 3
x <- c(0.85, 0.1, 0.05)
M <- matrix(NA, n, n);
for(i in 1:n){
for(j in 1:n){
M[i,j] = x[i] * x[j]
}}
sumAntiDiag(M)
#> 2 3 4 5 6
#> 0.7225 0.1700 0.0950 0.0100 0.0025
Created on 2022-03-24 by the reprex package (v2.0.1)
Related Topics
How to Attach a Simple Data.Frame to a Spatialpolygondataframe in R
Saving Plot as PDF and Simultaneously Display It in the Window (X11)
How to Check the Existence of a Downloaded File
Rolling Window Over Irregular Time Series
Keeping Zero Count Combinations When Aggregating with Data.Table
Sendmailr (Part2): Sending Files as Mail Attachments
Increase Plot Size (Width) in Ggplot2
Delete Columns Where All Values Are 0
Cannot Coerce Type 'Closure' to Vector of Type 'Character'
How to Generate Bin Frequency Table in R
How to Create a New Column Based on Multiple Conditions from Multiple Columns
K-Means Clustering in R on Very Large, Sparse Matrix
Error When Using Dplyr Inside of a Function
Add Vline to Existing Plot and Have It Appear in Ggplot2 Legend
R - Store a Matrix into a Single Dataframe Cell
R:Ggplot2:Facet_Grid:How Include Math Expressions in Few (Not All) Labels