R 在不使用apply的情况下获取与一系列向量重合的矩阵行

R 在不使用apply的情况下获取与一系列向量重合的矩阵行,r,matrix,vector,vectorization,apply,R,Matrix,Vector,Vectorization,Apply,我的问题有点像 假设我有一个矩阵和4个向量(可以考虑这另一个矩阵,因为向量的顺序很重要),并且我想得到与每个向量重合的行号。我希望解决方案避免重复向量,并且尽可能有效,因为问题是大规模的 例如 set.seed(1) M = matrix(rpois(50,5),5,10) v1 = c(3, 2, 7, 7, 4, 4, 7, 4, 5, 6) v2= c(8, 6, 4, 4, 3, 8, 3, 6, 5, 6) v3= c(4, 8, 3,

我的问题有点像

假设我有一个矩阵和4个向量(可以考虑这另一个矩阵,因为向量的顺序很重要),并且我想得到与每个向量重合的行号。我希望解决方案避免重复向量,并且尽可能有效,因为问题是大规模的

例如

 set.seed(1)

    M = matrix(rpois(50,5),5,10)
    v1 = c(3, 2, 7, 7, 4, 4, 7,  4, 5, 6)
    v2=  c(8, 6,  4, 4, 3,  8,  3, 6, 5, 6)
    v3=  c(4,  8, 3,  5, 9, 4, 5,  6, 7 ,7)
    v4=  c(4,  9, 3, 6,  3, 1, 5, 7,6, 1)

Vmat = cbind(v1,v2,v3,v4)

M
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,]    4    8    3    5    9    4    5    6    7     7
[2,]    4    9    3    6    3    1    5    7    6     1
[3,]    5    6    6   11    6    4    5    2    7     5
[4,]    8    6    4    4    3    8    3    6    5     6
[5,]    3    2    7    7    4    4    7    4    5     6

Vmat
      v1 v2 v3 v4
 [1,]  3  8  4  4
 [2,]  2  6  8  9
 [3,]  7  4  3  3
 [4,]  7  4  5  6
 [5,]  4  3  9  3
 [6,]  4  8  4  1
 [7,]  7  3  5  5
 [8,]  4  6  6  7
 [9,]  5  5  7  6
[10,]  6  6  7  1
输出应该是

5 4 1 2

如果我们将它们切换到
data.frame
s,那么我们就可以使用
merge
来实现这个技巧。此外,我们旋转
Vmat
,以便于匹配

haystack <- as.data.frame(M)
haystack$haystack_id <- rownames(haystack)
needle <- as.data.frame(t(Vmat))
needle$needle_id <- rownames(needle)

lookups <- merge(needle, haystack)
lookups <- lookups[order(lookups$needle_id), ]

haystack我认为将每个向量压缩为一个值是一种方法,如下@bunk:

m = do.call(function(...) paste(...,sep="_"), split(M, col(M)))
v = sapply(list(v1,v2,v3,v4), paste0, collapse="_")
match(v,m)
# [1] 5 4 1 2
建造
m
的更自然的方法是使用
apply
,但这是多余的。如果将
M
存储为data.frame,另一个选项是:

m = do.call(function(...) paste(...,sep="_"), as.data.frame(M))

与@user295691的答案类似,我们进行了合并,但现在在
merge.data.table
中使用了
which=TRUE
选项:

set.seed(1)
matdata  <- create_data(1e6,20,1e5) # using @user295691's example data

library(data.table)
M = as.data.table(matdata$M)
V = as.data.table(matdata$V)

r <- M[V, on=names(V), which=TRUE]

基准

OP的示例数据(在删除的答案中):

要测试的功能:

match_strings <- function(){
  m = do.call(function(...) paste(...,sep="_"), M)
  v = do.call(function(...) paste(...,sep="_"), V)
  match(v,m)
}

merge_df <- function(){ # from @user295691's answer
  M$mid = seq(nrow(M))
  V$vid = seq(nrow(V))
  with(merge(M,V), mid[order(vid)])
}

merge_dt <- function(){
  M2[V2, on=names(V2), which=TRUE]
}

“避免重复向量”是什么意思?我认为
apply
是正确的方法,即使你不喜欢它<代码>m=应用(m,1,0,折叠=“”);v=应用(Vmat,2,0,塌陷=“”);匹配(v,m)
Frank,避开rep(v1,)进行一些比较。如果你看到另一个问题,一些解决方案会重复向量,但最后一个解决方案不会,这会更有效。应用程序将不起作用,这样循环太慢了。这会使所有[1]都重新启动NA@bunk在我的回答中借用了这个。希望你不介意。无需在答案正文中写下你的编辑笔记。它们可以包含在编辑摘要(编辑时可见的小文本字段)中。最好只把你的答案写成最好的版本,而不记录它的历史。@Frank:显然是意见问题;我喜欢编辑笔记,因为在讨论问题时,我不喜欢事情发生变化,使我对答案的分析毫无预警地无效。一旦答案被接受,我可能有理由删除
EDIT
注释。这很公平。可能需要添加一个
相同的(ret$hid,matchstr)
来确认我们正在做同样的事情(可能是正确的)。相当标准的基准测试。这个速度和Frank的答案相比,对吗?理论上有什么比使用match更快的方法吗?我不太了解匹配算法的计算复杂度。我想知道OP是如何得到相反的结果的。他们的示例数据是否有本质上的不同?这比上面的合并解决方案快得多。我将发布一个答案,比较这两个答案。这是一个很好的答案,谢谢。尝试获得1.9.5:(@robertevansanders,但是很有收获!在1.9.4的例子中,你可以使用
system.time({M2[,id:=.I];setkeyv(M2,names(V2));M2[V2]$id->r})遵循
merge#df
风格。38秒对我来说是相同的(r,r#strings)#真的
我有让生活地狱般的窗口哈哈:(.
M2[,id:=.I]
在M2中创建一个行id列(与
M$mid=seq(nrow(M))
内部
merge_df
)。
setkeyv(M2,names(V2))
通过对列
V1:V20
进行排序,准备
M2
V2
合并,这在数据表1.9.4中是必需的。
M2[V2]
进行合并-结果的每一行对应于
V2
的一行,因此我们可以只取
$id
,并对其进行适当排序(与
merge_df
)不同,@robertevansanders对此表示抱歉。1.9.6现在在CRAN上。也许Jan关于“drat”的建议是正确的。。。
V[1,]
#    V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20
# 1:  7  5  3  2  5  6  3  3  5   5   3   2   4   9   4   4   3   6   4   3
M[r[1],]
#    V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 V11 V12 V13 V14 V15 V16 V17 V18 V19 V20
# 1:  7  5  3  2  5  6  3  3  5   5   3   2   4   9   4   4   3   6   4   3
set.seed(1)

NM    = 1e6
NV    = 1e5
Ncols = 20
MM = matrix(rpois(NM*Ncols,Ncols),NM,Ncols)

rows=sample(NM,NV,replace = FALSE)

Vmat=t(MM[rows,])

# converted to data.frames, because why not?
M = as.data.frame(MM)
V = as.data.frame(t(Vmat))

# converted to data.tables
M2 = setDT(copy(M))
V2 = setDT(copy(V))
match_strings <- function(){
  m = do.call(function(...) paste(...,sep="_"), M)
  v = do.call(function(...) paste(...,sep="_"), V)
  match(v,m)
}

merge_df <- function(){ # from @user295691's answer
  M$mid = seq(nrow(M))
  V$vid = seq(nrow(V))
  with(merge(M,V), mid[order(vid)])
}

merge_dt <- function(){
  M2[V2, on=names(V2), which=TRUE]
}
system.time({r_strings = match_strings()})
#    user  system elapsed 
#   10.40    0.06   10.49     
system.time({r_merge_df = merge_df()})
#    user  system elapsed 
#   14.71    0.10   14.84
system.time({r_merge_dt = merge_dt()})
#    user  system elapsed 
#    0.39    0.00    0.40 

identical(r_strings,r_merge_df) # TRUE
identical(r_strings,r_merge_dt) # TRUE