我有以下格式的矩阵:
set.seed(1)
m = matrix(sample(c(0,0,0,1),25,rep=T), nrow=5)
m[13] = 4
print(m)
[,1] [,2] [,3] [,4] [,5]
[1,] 0 1 0 0 1
[2,] 0 1 0 0 0
[3,] 0 0 4 1 0
[4,] 1 0 0 0 0
[5,] 0 0 1 1 0
考虑[3,3]
是我们想要“压扁”的一些热点。通过在最近的相邻/附近的零值单元上传播它的值。在这种情况下,这意味着为单元格[2,3]
,[3,2]
和[4,3]
分配1,以便[3,3]
也可以减少为1:
[,1] [,2] [,3] [,4] [,5]
[1,] 0 1 0 0 1
[2,] 0 1 1 0 0
[3,] 0 1 1 1 0
[4,] 1 0 1 0 0
[5,] 0 0 1 1 0
是否有人知道矩阵/光栅操作可以有效地实现这一目标,同时保留所有单元格的总和?
答案 0 :(得分:2)
我对这个问题很感兴趣,所以我试了一下。可能存在一个“rastery”工具,用于你正在尝试的但我不知道。
首先,一个辅助函数,用于查找矩阵中特定元素周围的正方形元素的索引:
find_neighbors = function(i, j, n)
{
tmp = expand.grid(replicate(2, -n:n, simplify = F))
tmp2 = tmp[rowSums(abs(tmp) < n) < 2, ]
inds = cbind(tmp2[, 1] + i, tmp2[, 2] + j)
inds[order(rowSums(abs(cbind(inds[, 1] - i, ##so that up/down/right/left are filled before diagonal neighbors
inds[, 2] - j)))), ]
}
E.g:
m1 = matrix(0, 7, 8)
m1
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
#[1,] 0 0 0 0 0 0 0 0
#[2,] 0 0 0 0 0 0 0 0
#[3,] 0 0 0 0 0 0 0 0
#[4,] 0 0 0 0 0 0 0 0
#[5,] 0 0 0 0 0 0 0 0
#[6,] 0 0 0 0 0 0 0 0
#[7,] 0 0 0 0 0 0 0 0
m1[find_neighbors(3, 4, 1)] = 1
m1[find_neighbors(3, 4, 2)] = 2
m1[find_neighbors(3, 4, 3)] = 3
m1
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
#[1,] 3 2 2 2 2 2 3 0
#[2,] 3 2 1 1 1 2 3 0
#[3,] 3 2 1 0 1 2 3 0
#[4,] 3 2 1 1 1 2 3 0
#[5,] 3 2 2 2 2 2 3 0
#[6,] 3 3 3 3 3 3 3 0
#[7,] 0 0 0 0 0 0 0 0
以及使热点变平的功能。有一个嵌套循环。第一个“for”循环遍布热点,第二个迭代地将热点扁平化为邻居。然而,一旦斑点变平,就会退出环。
ff = function(mat, thres = 1)
{
wh = which(mat > thres, T)
for(r in seq_len(nrow(wh))) {
for(n in seq_len(max(c(dim(mat) - wh[r, ], wh[r, ] - 1)))) {
if(mat[wh[r, , drop = F]] <= thres) break #stop flattening if we are done
inds = find_neighbors(wh[r, 1], wh[r, 2], n) #get indices of neighbours
inds = inds[!((rowSums(inds <= 0) > 0) | #use valid indices..
inds[, 1] > nrow(mat) |
inds[, 2] > ncol(mat)), ]
inds = inds[mat[inds] < thres, , drop = F] #use indices that are allowed to take values
tofill = nrow(inds) * thres #how many 'units' need to be taken from the hotspot?
mat[wh[r, , drop = F]] = mat[wh[r, , drop = F]] + sum(mat[inds]) #in case the neighbors
#of the hotspot are > 0,
#the, just, increase the
#value of the hotspot
if(mat[wh[r, , drop = F]] <= tofill) tofill = mat[wh[r, , drop = F]] - thres #do we have enough
#'units' in the hotspot?
if(tofill > 0) {
if(tofill < thres) {
mat[inds[1, , drop = F]] = tofill
mat[wh[r, , drop = F]] = mat[wh[r, , drop = F]] - tofill
next
}
nr = tofill %/% thres
mat[inds[seq_len(nr), , drop = F]] = thres
if((tofill %% thres) > 0) mat[inds[nr + 1, , drop = F]] = tofill %% thres
mat[wh[r, , drop = F]] = mat[wh[r, , drop = F]] - tofill
}
}
}
mat
}
一个例子:
mm = matrix(0, 11, 9); mm[8, 2] = 12; mm[6, 7] = 4
mm
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
# [1,] 0 0 0 0 0 0 0 0 0
# [2,] 0 0 0 0 0 0 0 0 0
# [3,] 0 0 0 0 0 0 0 0 0
# [4,] 0 0 0 0 0 0 0 0 0
# [5,] 0 0 0 0 0 0 0 0 0
# [6,] 0 0 0 0 0 0 4 0 0
# [7,] 0 0 0 0 0 0 0 0 0
# [8,] 0 12 0 0 0 0 0 0 0
# [9,] 0 0 0 0 0 0 0 0 0
#[10,] 0 0 0 0 0 0 0 0 0
#[11,] 0 0 0 0 0 0 0 0 0
ff(mm)
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
# [1,] 0 0 0 0 0 0 0 0 0
# [2,] 0 0 0 0 0 0 0 0 0
# [3,] 0 0 0 0 0 0 0 0 0
# [4,] 0 0 0 0 0 0 0 0 0
# [5,] 0 0 0 0 0 0 1 0 0
# [6,] 0 1 0 0 0 1 1 0 0
# [7,] 1 1 1 0 0 0 1 0 0
# [8,] 1 1 1 1 0 0 0 0 0
# [9,] 1 1 1 0 0 0 0 0 0
#[10,] 0 1 0 0 0 0 0 0 0
#[11,] 0 0 0 0 0 0 0 0 0
ff(mm, 3)
ff(mm, 5)
ff(mm, 1500)
希望其中任何一个都有用。
答案 1 :(得分:1)
攻击的可能概要。
1)找到热点:
hotind <- which (m > 1, arr.ind=TRUE)
2)循环遍历hotind行以传播:
for (j in 1: nrow(hotind) {
hotpoint <- hotind[j,]
# for example, divvy up the hot value into four nearest neighbors
m[hotpoint[1]-1,hotpoint[2]-1] <- m[hotpoint[1],hotpoint[2]]/4
# do_same_for m[hotpoint[1]+1,hotpoint[2]-1] and_so_on
m[hotpoint[1],hotpoint[2]] <- 1 # or your choice of final value
}
对我来说肯定“感觉”就像有一种方法可以通过平滑卷积核方法来做到这一点,所以这里希望有人发布一个更流畅的方法。