在矩阵中展平(重新分配值)热点

时间:2015-01-24 10:42:55

标签: r

我有以下格式的矩阵:

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

是否有人知道矩阵/光栅操作可以有效地实现这一目标,同时保留所有单元格的总和?

2 个答案:

答案 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
}

对我来说肯定“感觉”就像有一种方法可以通过平滑卷积核方法来做到这一点,所以这里希望有人发布一个更流畅的方法。

相关问题