【问题标题】:Match list to rows of matrix in R将列表与R中的矩阵行匹配
【发布时间】:2016-07-27 09:03:14
【问题描述】:

“a”是一个列表,“b”是一个矩阵。

a<-list(matrix(c(0,2,0,1,0,2,0,0,1,0,0,0,0,0,2,2),4), 
        matrix(c(0,1,0,0,0,1,1,0,0,0,0,0),3),
        matrix(c(0,0,0,0,2,0,1,0,0,0,0,0,2,0,2,1,0,1,1,0),5))
b<-matrix(c(2,2,1,1,1,2,1,2,1,1,2,1,1,1,1,1,1,2,2,2,1,2,1,1),6) 

> a
[[1]]
     [,1] [,2] [,3] [,4]
[1,]    0    0    1    0
[2,]    2    2    0    0
[3,]    0    0    0    2
[4,]    1    0    0    2

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

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

> b
     [,1] [,2] [,3] [,4]
[1,]    2    1    1    2
[2,]    2    2    1    2
[3,]    1    1    1    1
[4,]    1    1    1    2
[5,]    1    2    1    1
[6,]    2    1    2    1

列表“a”中有 3 个对象。我想测试列表“a”中每个对象中的所有 非零 元素是否与矩阵“b”中同一行的相应位置匹配。如果匹配,则输出b的匹配行号。

例如,第二个对象是

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

我们可以看到第1行的非零数是1,它位于行的第三位,可以匹配矩阵“b”的1-5行,第2行为1,位于本行首位,可匹配矩阵“b”的3-5行,第3行非零数为1,位于第2位这一行,它可以匹配矩阵“b”的3-4行。所以只有矩阵“b”的第3或第4行可以匹配这个对象中的所有行,所以输出结果是“3 4”。

我的尝试代码如下:

temp<-Map(function(y) t(y), Map(function(a) 
           apply(a,1,function(x){
                 apply(b,1, function(y) identical(x[x!=0],y[x!=0]))}),a))
lapply(temp, function(a) which(apply(a,2,prod)==1))

结果如下:

[[1]]
integer(0)

[[2]]
[1] 3 4

[[3]]
[1] 6

没错。但我想知道是否有更快速的代码来处理这个问题?

【问题讨论】:

  • 其实元素[3,4]不匹配...
  • @SerbanTanasa 为什么?它是匹配的。 “a”的第一个对象中的所有非零元素都匹配矩阵“b”第二行的对应位置,“a”的第二个对象中的所有非零元素都匹配矩阵“b”的第5行的对应位置矩阵“b”,并且“a”的第三个对象中的所有非零元素都与矩阵“b”第6行的对应位置匹配。
  • 你的实际数据有哪些维度?
  • @alexis_laz "a" 有 300 个对象(每个对象是一个矩阵(圆形 20X5)),"b" 是一个 15 行矩阵。
  • 如果在同一列中有两个非零数字会发生什么,比如a[[1]]

标签: r list matrix


【解决方案1】:

你对你想要什么以及你可能的矩阵是什么样子的解释真的不清楚。根据我的推断,您希望匹配b 中的行号,该行号与a 中矩阵的每一列中唯一的非零数匹配。如果是这样,这里有一个更简单的选择:

lapply(a, function(x){    # loop across the matrices in a
    x[x == 0] <- NA       # replace 0s with NA
    which(apply(b, 1, function(y){            # loop across the rows of b, trying to match
        all(y == colMeans(x, na.rm = TRUE))   # the rows of b with the colmeans of x
    }))
})
# [[1]]
# [1] 2
# 
# [[2]]
# [1] 5
# 
# [[3]]
# [1] 6

【讨论】:

  • 嗨,@alistaire,如果列表“a”的对象中一列的元素都是0,那么你的答案会出错,谢谢。在“a”的第二个对象中查看这种情况
  • 例如a[[2]]中的每一行都可以匹配到矩阵“b”中的第3行和第4行,因为所有非零元素都可以匹配到对应的位置(列) “b”的第 3 或第 4 行。但是,使用您的代码,结果是“integer(0)”,因为您认为所有列都包含非零元素。
  • 您需要完全布局您需要代码遵循的逻辑。更新示例很好,但您仍然没有解释它应该如何评估所需的结果,让读者猜测。
  • 是的,有点难表达,我觉得你推断的没错。
【解决方案2】:

拥有几列并尝试利用具有 > 1 个唯一值或没有非零值的列来减少计算:

ff = function(a, b)
{
    i = seq_len(nrow(b))  #starting candidate matches
    for(j in seq_len(ncol(a))) {
        aj = a[, j]
        nzaj = aj[aj != 0L]
        if(!length(nzaj)) next  #if all(a[, j] == 0) save some operations
        if(sum(tabulate(nzaj) > 0L) > 1L) return(integer())  #if no unique values in a column break looping 
        i = i[b[i, j] == nzaj[[1L]]]  #update candidate matches
    }

    return(i)
}
lapply(a, function(x) ff(x, b))
#[[1]]
#integer(0)
#
#[[2]]
#[1] 3 4
#
#[[3]]
#[1] 6

使用您实际大小的数据:

set.seed(911)
a2 = replicate(300L, matrix(sample(0:3, 20 * 5, TRUE, c(0.97, 0.01, 0.01, 0.01)), 20, 5), simplify = FALSE)
b2 = matrix(sample(1:3, 15 * 5, TRUE), 15, 5)
identical(OP(a2, b2), lapply(a2, function(x) ff(x, b2)))
#[1] TRUE
microbenchmark::microbenchmark(OP(a2, b2), lapply(a2, function(x) ff(x, b2)), times = 50)
#Unit: milliseconds
#                              expr        min         lq       mean     median         uq       max neval cld
#                        OP(a2, b2) 686.961815 730.840732 760.029859 753.790094 785.310056 863.04577    50   b
# lapply(a2, function(x) ff(x, b2))   8.110542   8.450888   9.381802   8.949924   9.872826  15.51568    50  a

OP 是:

OP = function (a, b) 
{
    temp = Map(function(y) t(y), Map(function(a) apply(a, 1, 
        function(x) {
            apply(b, 1, function(y) identical(x[x != 0], y[x != 
                0]))
        }), a))
    lapply(temp, function(x) which(apply(x, 2, prod) == 1))
}

【讨论】:

    猜你喜欢
    • 2021-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-09
    • 1970-01-01
    • 2016-07-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多