将列表匹配到R中的矩阵行
“a”是一个列表,“b”是一个矩阵将列表匹配到R中的矩阵行,r,list,matrix,R,List,Matrix,“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<-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
我们可以看到第一行的非零数字是1,它位于第三行,它可以匹配矩阵“b”的1-5行,第二行的非零数字是1,它位于这一行的第一行,它可以匹配矩阵“b”的3-5行,第三行的非零数字是1,它位于该行的第二位,可以匹配矩阵“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
是的。但我想知道是否有更快捷的代码来处理这个问题 你对你想要什么以及你可能的矩阵是什么样子的解释真的不清楚。根据我的推断,您希望匹配
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
lappy(a,函数(x){#在a中的矩阵上循环
x[x==0]有几个列,并试图利用具有>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))
}
实际上元素[3,4]不匹配…@为什么?它是匹配的。“a”的第一个对象中的所有非零元素匹配矩阵“b”第二行的对应位置,“a”的第二个对象中的所有非零元素匹配矩阵“b”第五行的对应位置,并且“a”的第三个对象中的所有非零元素与矩阵“b”的第六行的相应位置匹配。您的实际数据的维度是什么?@alexis_laz“a”有300个对象(每个对象是一个矩阵(第20X5轮)),“b”是一个15行的矩阵。如果你在同一列中有两个非零的数字,比如在a[[1]]
?嗨,@alistaire,如果一列中的元素在列表“a”的对象中都是0,那么你的答案会出错,谢谢。看看“a”的第二个对象中的这种情况,例如,a[[2]]中的每一行可以与矩阵“b”中的第3行和第4行匹配,因为所有非零元素都可以与“b”的第3行或第4行中的相应位置(列)匹配。但是,使用您的代码,结果是“整数(0)”因为你认为所有的列都包含非零元素。你需要完全排列你需要遵循的逻辑。更新例子是好的,但是你仍然没有解释它应该如何评估到期望的结果,让读者猜测。是的,有点难以表达,我认为你推断的是正确的。
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))
}