2

スパース行列でゼロ以外の隣人までの距離を計算するスマートな方法を誰か教えてもらえますか? これを行う理由は、大規模な多次元マトリックスの「穴」を特定したいからです。

例として: 多くのゼロといくつかの 1 で満たされた 10x10 マトリックスがあると仮定しましょう:

f<-ceiling((runif(100,0,1))-.6)
a <- matrix(f, ncol=10L, nrow=10L)
rownames(a) = seq(1,10,1)
colnames(a) = seq(1,10,1)

可能性があります

> a
   1 2 3 4 5 6 7 8 9 10
1  0 0 0 0 1 0 0 1 1  0
2  1 0 0 0 1 0 0 0 0  0
3  0 1 1 0 1 1 0 0 1  1
4  0 0 1 1 0 1 0 1 0  0
5  0 0 0 1 0 1 0 0 0  1
6  1 0 0 0*0*1 0 1 0  0
7  0 1 1 1 1 1 1 0 1  0
8  1 0 1 0 1 0 0 0 1  1
9  1 1 1 0 0 0 0 0 0  0
10 1 1 1 1 1 0 1 0 1  0

結果として必要なのは、すべてのゼロ点の 4 つの方向すべて (各次元に 2 つ) の平均距離を持つ 10x10 マトリックスです。

たとえば、ポイントa[6,5]はゼロで、4 つの近傍があります。左の距離は 5、右の距離は 1、上は 3、下は 1 です。したがって、平均は 2.5 になります。近隣が存在しない場合は、残りの近隣の平均を計算する必要があります。

いつものように、私の最初のアイデアは一連の for ループで、すべての方向の各行列値を探して距離を返します。しかし、これはそれを行うための最もばかげた方法でなければなりません...

4

2 に答える 2

1

I liked that problem a lot! Here is a solution, not necessarily fast but it does the job.

First let's recreate your data:

a <- matrix(scan(textConnection("
  0 0 0 0 1 0 0 1 1  0
  1 0 0 0 1 0 0 0 0  0
  0 1 1 0 1 1 0 0 1  1
  0 0 1 1 0 1 0 1 0  0
  0 0 0 1 0 1 0 0 0  1
  1 0 0 0 0 1 0 1 0  0
  0 1 1 1 1 1 1 0 1  0
  1 0 1 0 1 0 0 0 1  1
  1 1 1 0 0 0 0 0 0  0
  1 1 1 1 1 0 1 0 1  0
")), 10, 10, byrow = TRUE)

Here, let's split your rows and columns into four oriented lists of vectors:

rev.list <- function(l) lapply(l, rev)

v1 <- split(a, row(a))  # rows left to right
v2 <- rev.list(v1)      # rows right to left
v3 <- split(a, col(a))  # cols up to down
v4 <- rev.list(v3)      # cols down to up

Here we create and apply a function (inspired from https://stackoverflow.com/a/17929557/1201032) for computing one-directional distances:

dir.dist <- function(v) {
  out <- seq_along(v) - cummax(seq_along(v) * v)
  out[seq_len(match(1, v) - 1)] <- NA
  out
}

dist1.list <- lapply(v1, dir.dist) # dist to closest on left
dist2.list <- lapply(v2, dir.dist) # dist to closest on right
dist3.list <- lapply(v3, dir.dist) # dist to closest up
dist4.list <- lapply(v4, dir.dist) # dist to closest dn

Now let's put everything back into four matrices:

nr <- nrow(a)
nc <- ncol(a)

list.to.mat <- function(l, revert = FALSE, byrow = FALSE,
                           nrow = nr, ncol = nc) {
  x <- unlist(if (revert) rev.list(l) else l)
  matrix(x, nrow, ncol, byrow)
}

m1 <- list.to.mat(dist1.list, revert = FALSE, byrow = TRUE)
m2 <- list.to.mat(dist2.list, revert = TRUE,  byrow = TRUE)
m3 <- list.to.mat(dist3.list, revert = FALSE, byrow = FALSE)
m4 <- list.to.mat(dist4.list, revert = TRUE,  byrow = FALSE)

Finally, let's compute the means using a pmean function inspired from https://stackoverflow.com/a/13123779/1201032:

pmean <- function(..., na.rm = FALSE) { 
  dat <- do.call(cbind, list(...))
  res <- rowMeans(dat, na.rm = na.rm) 
  idx_na <- !rowSums(!is.na(dat))
  res[idx_na] <- NA
  res 
}

final <- matrix(pmean(as.vector(m1),
                      as.vector(m2),
                      as.vector(m3),
                      as.vector(m4), na.rm = TRUE), nr, nc)

final
#       [,1] [,2] [,3] [,4]  [,5]  [,6] [,7] [,8] [,9] [,10]
#  [1,] 2.50 2.50 2.00 2.00  0.00  1.67 3.00  0.0 0.00 1.50
#  [2,] 0.00 1.67 1.67 2.00  0.00  1.00 3.50  2.0 2.00 3.00
#  [3,] 1.67 0.00 0.00 1.00  0.00  0.00 2.33  1.5 0.00 0.00
#  [4,] 2.00 1.67 0.00 0.00  1.50  0.00 1.67  0.0 1.67 1.33
#  [5,] 2.33 2.00 1.33 0.00  1.50  0.00 2.00  1.5 2.00 0.00
#  [6,] 0.00 2.25 2.00 1.75 *2.25* 0.00 1.00  0.0 1.67 1.67
#  [7,] 1.00 0.00 0.00 0.00  0.00  0.00 0.00  1.0 0.00 1.33
#  [8,] 0.00 1.00 0.00 1.25  0.00  1.67 1.75  2.0 0.00 0.00
#  [9,] 0.00 0.00 0.00 1.33  1.33  2.50 2.33  4.0 2.67 4.00
# [10,] 0.00 0.00 0.00 0.00  0.00  1.67 0.00  2.0 0.00 1.50
于 2013-08-02T01:00:00.817 に答える
0

行列の場合、次を使用してスパース rxc 形式に変換できますwhich

rc <- which(a>0, arr.ind=TRUE)
rc[rc[,1] == 6, 2]   # 1, 6,8   candidates for "row-neighbors"
rc[rc[,2] == 5, 1]   # 1,2,3, 7,8,10  col-neighbors
于 2013-08-01T23:04:46.957 に答える