Вот метод R:
x <- data.frame(
geoid = c(1,1,1, 2,2, 3,3,3),
bankid = c(1,2,4, 1,3, 2,3,5),
lending = c(25,32,83, 76,22, 42,12,22)
)
myfunc <- function(x, i, j) {
geos <- x$geoid %in% c(i, j)
banks <- with(x, intersect(bankid[geoid == i], bankid[geoid == j]))
with(x, sum(lending[geos & bankid %in% banks]) / sum(lending[geos]))
}
outer(unique(x$geoid), unique(x$geoid),
function(i,j) mapply(myfunc, list(x), i, j))
# [,1] [,2] [,3]
# [1,] 1.0000000 0.4243697 0.3425926
# [2,] 0.4243697 1.0000000 0.1954023
# [3,] 0.3425926 0.1954023 1.0000000
Это не самый эффективный, но это начало.Трудно (я думаю) сделать это по-настоящему векторизованным, поскольку каждое подмножество требует пересечений, хотя я уверен, что это можно оптимизировать, чтобы не потребовать повторного вычисления intersect(bankid...)
дважды для каждой эквивалентной пары (если это фактор производительности).
Редактировать : чуть более эффективный процесс, который не пересчитывает эквивалентные пары geoid
:
Разделить данные по гео:
geox <- split(x, x$geoid)
myfunc <- function(i, j) {
if (i >= j) return(NA)
banks <- intersect(geox[[i]]$bankid, geox[[j]]$bankid)
sum(with(geox[[i]], lending[ bankid %in% banks ]),
with(geox[[j]], lending[ bankid %in% banks ])) /
sum(geox[[i]]$lending, geox[[j]]$lending)
}
o <- outer(seq_along(geox), seq_along(geox),
function(i,j) mapply(myfunc, i, j))
o
# [,1] [,2] [,3]
# [1,] NA 0.4243697 0.3425926
# [2,] NA NA 0.1954023
# [3,] NA NA NA
(Просто чтобы доказать, что мы рассчитали только минимальный набор.) Теперь переверните данные верхнего треугольника в нижний треугольник:
o[which(lower.tri(o),TRUE)] <- o[which(upper.tri(o),TRUE)]
o
# [,1] [,2] [,3]
# [1,] NA 0.4243697 0.3425926
# [2,] 0.4243697 NA 0.1954023
# [3,] 0.3425926 0.1954023 NA
И присвойте известное значение 1 диагонали:
diag(o) <- 1