【问题标题】:determine which row a vector in a matrix using R function使用 R 函数确定矩阵中向量的哪一行
【发布时间】:2018-01-01 12:23:15
【问题描述】:

例如

a1 <- rbind(c(1,3), c(1,2))
A1 <- rbind(c(1, 2), c(1, 4), c(1,3), c(2, 4))

我想检查 a1 在 A1 的哪一行。 在这个例子中,返回值应该是 c(3, 1)。

【问题讨论】:

  • 一个非常快速的数据表答案是here。也是一个重复的问题,但由于这是唯一好的答案,我不会将其标记为重复。也许这个问题应该被标记为这个问题的欺骗。
  • which(duplicated(rbind(A1, a1), fromLast=TRUE)) 不错。

标签: r matrix


【解决方案1】:

我很抱歉没有测试早期的解决方案,我希望这对你有用:

options(stringsAsFactors =F)

a11 <- do.call("paste0",data.frame(a1))
A11 <- do.call("paste0", data.frame(A1))
which(A11 %in% a11)

输出

> a11
[1] "13" "12"
> A11
[1] "12" "14" "13" "24"
> which(A11 %in% a11)
[1] 1 3

【讨论】:

  • @PoGibas,它不适用于不同的场景,我发现一些总和没有达到 2 但匹配的值,我现在感觉很糟糕。
【解决方案2】:

使用applyduplicated 的解决方案。这个想法是使用apply 循环遍历A1 中的每一行,并使用函数rbind 每行到a1,并使用duplicatedany 检查是否有任何重复项。

which(apply(A1, 1, function(x) any(duplicated(rbind(x, a1)))))
# [1] 1 3

或者我们可以将所有数字组合成字符串并匹配来自A1a1 的字符串。该解决方案的灵感来自 Pkumar 的解决方案。

which(apply(A1, 1, toString) %in% apply(a1, 1, toString))
# [1] 1 3

测试方法

在 Dror Bogin 的答案的评论部分,OP 提出了一个解决方案,即which(duplicated(rbind(a1 ,A1))) - nrow(a1)。此解决方案仅在大矩阵中没有重复项时才有效,例如A1

例如,考虑以下矩阵,A2,它与 A1 相同,除了三个额外的行,其中两个是重复的。

A2 <- rbind(c(1, 2), c(1, 4), c(1, 3), c(2, 4), c(5, 8), c(4, 3), c(5, 8))

A2 的预期输出也应该是c(1, 3)。但是,当我们使用 OP 的解决方案时,我们会在 7 处获得一个额外的索引。

which(duplicated(rbind(a1 ,A2)))-nrow(a1) 
# [1] 1 3 7

但我的解决方案仍会返回 c(1, 3)

which(apply(A2, 1, function(x) any(duplicated(rbind(x, a1)))))
# [1] 1 3

最后,如果 OP 确定没有任何重复项。我们可以使用下面的代码来进一步简化代码。

which(duplicated(rbind(A1, a1), fromLast = TRUE))
# [1] 1 3

绩效评估

由于 OP 提到现实世界的矩阵是巨大的,因此值得在这里对所有提出的方法进行性能评估。

到目前为止,我们一共有五种方法。

方法一:我提出的“apply-duplicate”方法。

方法2:受PKumar启发的“apply-toString-match”方法

方法 3:PKumar 提出的“do.call-dataframe-match”方法

方法四:Dror Bogin 提出的“for-loop”方法

方法5:tophcito提出的“data.table”方法

下面我使用microbenchmark包进行性能评估。

library(microbenchmark)
library(data.table)

microbenchmark(m1 = {which(apply(A1, 1, function(x) any(duplicated(rbind(x, a1)))))},
               m2 = {which(apply(A1, 1, toString) %in% apply(a1, 1, toString))},
               m3 = {which(do.call("paste0",data.frame(A1)) %in% do.call("paste0",data.frame(a1)))},
               m4 = {v1 = vector()
               for(i in 1:nrow(A1)){
                 b = ifelse(all(a1[1,] == A1[i,]),i,NA)
                 d = ifelse(all(a1[2,] == A1[i,]),i,NA)
                 v1 = c(v1,b,d)
               }
               v1[!is.na(v1)]},
               m5 = {a1_dt <- as.data.table(as.data.frame(a1))
               A1_dt <- as.data.table(as.data.frame(A1))
               setnames(a1_dt, c("x", "y"))
               setnames(A1_dt, c("x", "y"))
               A1_dt[, id := 1:nrow(A1_dt)]
               result <- merge(A1_dt, a1_dt, by = c("x", "y"))
               result[, id]})

# Unit: microseconds
# expr      min        lq      mean    median       uq      max neval
#   m1  164.498  191.7435  235.6025  215.1320  237.751 1777.094   100
#   m2   71.968   82.2490  101.0790   99.2130  112.064  202.024   100
#   m3  140.851  165.5265  197.3618  185.3175  206.908  395.824   100
#   m4 4734.462 5107.4095 5450.1260 5348.2450 5535.876 8807.847   100
#   m5 1286.684 1394.6360 1591.3651 1508.7560 1674.283 4361.256   100

结果显示方法 2 最快,方法 3 次之。方法 2 应该比方法 3 更快是有道理的,因为将对象从矩阵转换为数据框需要一些时间。方法1排在第三位,在我看来仍然是一种性能不错的方法。方法5比上述三种方法要慢,说明虽然data.table是为处理大数据帧而设计的,但是这种情况下不需要使用data.table进行操作。最后,方法 4 是最慢的,表明这种情况下 for 循环是低效的。

【讨论】:

    【解决方案3】:

    您必须为要检查的每一行添加一个变量a1

    a1 <- rbind(c(1,3), c(1,2))
    A1 <- rbind(c(1, 2), c(1, 4), c(1,3), c(2, 4))
    v1 = vector()
    for(i in 1:nrow(A1)){
      b = ifelse(all(a1[1,] == A1[i,]),i,NA)
      d = ifelse(all(a1[2,] == A1[i,]),i,NA)
      v1 = c(v1,b,d)
    }
    v1 = v1[!is.na(v1)]
    

    【讨论】:

    • 非常感谢。由于我的矩阵很大,因此使用循环方法有点费时。
    • 哪个矩阵太大了?
    • A1 矩阵非常大。
    • 如果您要搜索的矩阵非常大,应该没问题。为什么不直接运行代码并让它运行多久?如果您希望它运行得更快,请使用应用变体。
    • 非常感谢。我已经使用 which(duplicated(rbind(a1 ,A1)))-nrow(a1) 解决了这个问题
    【解决方案4】:

    使用%in%rowSums 的解决方案(应该是一种改进方法):

    apply(a1, 1, 
          function(x) which(rowSums(matrix(A1 %in% x, ncol = 2)) == 2))
    

    另一种可能性是使用rowMeans== 1

    【讨论】:

      【解决方案5】:

      一种可能的解决方案是添加行号并将两个矩阵合并为数据表。优点是数据表针对速度和大数据进行了优化。

      首先,将您的两个矩阵转换为数据表:

      library(data.table)
      a1 <- as.data.table(as.data.frame(a1))
      A1 <- as.data.table(as.data.frame(A1))
      setnames(a1, c("x", "y"))
      setnames(A1, c("x", "y"))
      

      让我们添加一个带有行号的附加列:

      A1[, id := 1:nrow(A1)]
      

      最后,我们合并两个表(这将返回 A1 的行,其中出现了来自 a1 的值):

      result <- merge(A1, a1, by = c("x", "y"))
      

      由于您只对行号感兴趣,所以我们只选择它:

      result[, id]
      

      【讨论】:

        猜你喜欢
        • 2015-04-23
        • 2020-08-09
        • 1970-01-01
        • 1970-01-01
        • 2013-04-07
        • 2019-08-25
        • 1970-01-01
        • 2018-08-07
        相关资源
        最近更新 更多