Сумма матричных элементов между диагоналями эффективно в R

У меня есть данные в виде матрицы n*n, для которой я хочу выполнить некоторые вычисления (например, sum), элементы которых размещены между диагоналями (исключая диагонали).

Например, для этой матрицы:

     [,1] [,2] [,3] [,4] [,5]
[1,]    2    0    1    4    3
[2,]    5    3    6    0    4
[3,]    3    5    2    3    1
[4,]    2    1    5    3    2
[5,]    1    4    3    4    1

Результат для sum (между диагональными элементами) будет:

# left slice 5+3+2+5 = 15
# bottom slice 4+3+4+5 = 16
# right slice 4+1+2+3 = 10
# top slice 0+1+4+6 = 11

# dput(m)
m <- structure(c(2, 5, 3, 2, 1, 0, 3, 5, 1, 4, 1, 6, 2, 5, 3, 4, 0, 
3, 3, 4, 3, 4, 1, 2, 1), .Dim = c(5L, 5L))

Как добиться этого эффективно?


person 989    schedule 24.06.2016    source источник
comment
Ваш вопрос непонятен. Пожалуйста, уточните числовым расчетом, что вы имеете в виду под левым срезом и т. Д.   -  person abhiieor    schedule 24.06.2016
comment
обновлено. теперь должно быть ясно.   -  person 989    schedule 24.06.2016
comment
пакет Matrix должен взломать это ...   -  person Colonel Beauvel    schedule 24.06.2016
comment
@ColonelBeauvel Я всегда за (возможно) выполнение моей задачи с base R.   -  person 989    schedule 24.06.2016


Ответы (2)


Вот как можно получить «верхнюю часть»:

sum(m[lower.tri(m)[nrow(m):1,] & upper.tri(m)])
#[1] 11

чтобы визуализировать это:

lower.tri(m)[nrow(m):1,] & upper.tri(m)
#      [,1]  [,2]  [,3]  [,4]  [,5]
#[1,] FALSE  TRUE  TRUE  TRUE FALSE
#[2,] FALSE FALSE  TRUE FALSE FALSE
#[3,] FALSE FALSE FALSE FALSE FALSE
#[4,] FALSE FALSE FALSE FALSE FALSE
#[5,] FALSE FALSE FALSE FALSE FALSE

Вот как можно вычислить все 4 среза:

up <- upper.tri(m)
lo <- lower.tri(m)
n <- nrow(m)

# top
sum(m[lo[n:1,] & up])
# left
sum(m[lo[n:1,] & lo])
# right
sum(m[up[n:1,] & up])
# bottom
sum(m[up[n:1,] & lo])
person talat    schedule 24.06.2016
comment
Спасибо за красивое и чистое решение. проголосовал + принял. - person 989; 24.06.2016

sum(sapply(1:dim(m)[[2L]], function(i) sum(m[c(-i,-(dim(m)[[1L]]-i+1)),i])))

Это идет столбец за столбцом, и для каждого столбца вынимаются диагональные элементы и суммируются остальные. Затем эти частичные результаты суммируются.

Я считаю, что это будет быстро, потому что мы идем столбец за столбцом, а матрицы в R сохраняются столбец за столбцом (т.е. он будет удобен для кеш-памяти ЦП). Нам также не нужно создавать большой вектор индексов, только вектор из двух индексов (взятых) для каждого столбца.

РЕДАКТИРОВАТЬ: Я прочитал вопрос еще раз более внимательно. Код можно обновить, чтобы создать список из четырех значений для каждого элемента в sapply: для каждой из областей. Идея остается той же: для большой матрицы это будет быстро, если вы будете идти столбец за столбцом, а не прыгать вперед и назад между столбцами.

person Steves    schedule 24.06.2016
comment
ну да, но по столбцам, это означает, что данные в вашем первом столбце представляют собой один фрагмент памяти, за которым следуют данные во втором столбце и т. д. Я имею в виду, что, хотя все это непрерывная память, доступ к ней локально быстрее en.wikipedia.org/wiki/Locality_of_reference - person Steves; 24.06.2016
comment
Если требуется общая сумма всех срезов, то почему бы просто не: diag(m)=0; diag(m[5:1,])=0; sum(m);, что равно 52. Но я хочу провести вычисления для каждого среза отдельно. - person 989; 24.06.2016
comment
если обнуление диагоналей в порядке, то это, вероятно, будет быстрее - person Steves; 24.06.2016
comment
даже если не все в порядке, мы могли бы просто сделать копию матрицы. - person 989; 24.06.2016
comment
но затем мы копируем потенциально большую матрицу, я не уверен, что это будет работать лучше - person Steves; 24.06.2016