【问题标题】:Simple matching similarity matrix for continuous, non-binary data?连续非二进制数据的简单匹配相似度矩阵?
【发布时间】:2012-05-24 03:49:09
【问题描述】:

给定矩阵

structure(list(X1 = c(1L, 2L, 3L, 4L, 2L, 5L), X2 = c(2L, 3L, 
4L, 5L, 3L, 6L), X3 = c(3L, 4L, 4L, 5L, 3L, 2L), X4 = c(2L, 4L, 
6L, 5L, 3L, 8L), X5 = c(1L, 3L, 2L, 4L, 6L, 4L)), .Names = c("X1", 
"X2", "X3", "X4", "X5"), class = "data.frame", row.names = c(NA, 
-6L))

我想创建一个 5 x 5 距离矩阵,其中包含匹配比率和所有列之间的总行数。例如,X4 和 X3 之间的距离应该是 0.5,因为两列匹配 6 次中的 3 次。

我曾尝试使用包“proxy”中的dist(test, method="simple matching"),但此方法仅适用于二进制数据。

【问题讨论】:

    标签: r distance matching similarity metric


    【解决方案1】:

    使用outer(再次:-)

    my.dist <- function(x) {
     n <- nrow(x)
     d <- outer(seq.int(ncol(x)), seq.int(ncol(x)),
                Vectorize(function(i,j)sum(x[[i]] == x[[j]]) / n))
     rownames(d) <- names(x)
     colnames(d) <- names(x)
     return(d)
    }
    
    my.dist(x)
    #           X1        X2  X3  X4        X5
    # X1 1.0000000 0.0000000 0.0 0.0 0.3333333
    # X2 0.0000000 1.0000000 0.5 0.5 0.1666667
    # X3 0.0000000 0.5000000 1.0 0.5 0.0000000
    # X4 0.0000000 0.5000000 0.5 1.0 0.0000000
    # X5 0.3333333 0.1666667 0.0 0.0 1.0000000
    

    【讨论】:

      【解决方案2】:

      这是一个镜头(dt 是你的矩阵):

      library(reshape)
      df = expand.grid(names(dt),names(dt))
      df$val=apply(df,1,function(x) mean(dt[x[1]]==dt[x[2]]))
      cast(df,Var2~Var1)
      

      【讨论】:

      • 效果很好!非常感谢你。只有一个错误:第 3 行的 df2 = df。
      【解决方案3】:

      这是一个比其他两个更快的解决方案,虽然有点难看。我假设减速带来自不使用mean(),因为与sum() 相比它可能会很慢,并且只计算输出矩阵的一半,然后手动填充下三角形。该函数目前将NA 留在对角线上,但您可以轻松地将它们设置为一个,以与diag(out) &lt;- 1 完全匹配其他答案

      FUN <- function(m) {
        #compute all the combinations of columns pairs
        combos <- t(combn(ncol(m),2))
        #compute the similarity index based on the criteria defined
        sim <- apply(combos, 1, function(x) sum(m[, x[1]] - m[, x[2]] == 0) / nrow(m))
        combos <- cbind(combos, sim)
        #dimensions of output matrix
        out <- matrix(NA, ncol = ncol(m), nrow = ncol(m))
      
        for (i in 1:nrow(combos)){
          #upper tri
          out[combos[i, 1], combos[i, 2]] <- combos[i,3]
          #lower tri
          out[combos[i, 2], combos[i, 1]] <- combos[i,3]
        }
        return(out)
      }
      

      我把另外两个答案,做成函数,做了一些基准测试:

      library(rbenchmark)
      benchmark(chase(m), flodel(m), blindJessie(m), 
                replications = 1000,
                order = "elapsed", 
                columns = c("test", "elapsed", "relative"))
      #-----
             test elapsed relative
      1  chase(m)   1.217 1.000000
      2 flodel(m)   1.306 1.073131
      3 blindJessie(m)  17.691 14.548520
      

      【讨论】:

      • Chase,你的代码中有一个错误:你不能使用 combos 之后你做了 transform(combos, ...) 因为 ... 将在 combos 内部评估。我怀疑您的全球环境中有另一个combos 副本,所以它对您有用。不过,在调用transform 之前制作一个连击副本应该很容易解决。
      • @flodel - 很好,谢谢。进行了适当的调整并重新制定了时间安排。坚持使用矩阵和 cbind 也加快了函数的运行速度。
      • 那么你可以再次运行它们,因为我也提高了我的回答速度。在我的机器上,我的版本仍然比你的慢一点,但不是很多:比率下降到 1.07。
      • @flodel - 干得好,我得到了同等的测试。我喜欢你的回答,因为它更规范。我认为您可以通过将outer(names(x), names(x) 位更改为outer(seq.int(ncol(x)), seq.int(ncol(x)) 来(轻松地)获得更多性能,因为它是一个原语。我还认为如果矩阵没有名称,names() 将失败。当我进行更改时,您在我的 hack 工作的 1.02 内进行了测试……这可能足以维持一晚的微优化 :)。
      • 好点大通,我已经做出了你建议的改变。谢谢!
      【解决方案4】:

      我得到的答案如下: 第一,我对行数据做了一些修改:

      X1 = c(1L, 2L, 3L, 4L, 2L, 5L)
      X2 = c(2L, 3L, 4L, 5L, 3L, 6L)
      X3 = c(3L, 4L, 4L, 5L, 3L, 2L)
      X4 = c(2L, 4L, 6L, 5L, 3L, 8L)
      X5 = c(1L, 3L, 2L, 4L, 6L, 4L)
      matrix_cor=rbind(x1,x2,x3,x4,x5)
      matrix_cor
      
         [,1] [,2] [,3] [,4] [,5] [,6]
      X1    1    2    3    4    2    5
      X2    2    3    4    5    3    6
      X3    3    4    4    5    3    2
      X4    2    4    6    5    3    8
      X5    1    3    2    4    6    4
      

      然后:

      dist(matrix_cor)
      
           X1       X2       X3       X4
      X2 2.449490                           
      X3 4.472136 4.242641                  
      X4 5.000000 3.000000 6.403124         
      X5 4.358899 4.358899 4.795832 6.633250
      

      【讨论】:

      【解决方案5】:

      感谢大家的建议。根据您的回答,我详细阐述了一个三行解决方案(“test”是数据集的名称)。

      require(proxy)
      ff <- function(x,y) sum(x == y) / NROW(x)
      dist(t(test), ff, upper=TRUE)
      

      这是输出:

                X1        X2        X3        X4        X5
      X1           0.0000000 0.0000000 0.0000000 0.3333333
      X2 0.0000000           0.5000000 0.5000000 0.1666667
      X3 0.0000000 0.5000000           0.5000000 0.0000000
      X4 0.0000000 0.5000000 0.5000000           0.0000000
      X5 0.3333333 0.1666667 0.0000000 0.0000000          
      

      【讨论】:

      • 我无法让它工作,ff 未定义...即使我将其更改为 f,它也以 Error in as.character(x) : cannot coerce type 'closure' to vector of type 'character' 失败
      • 我认为这是因为我正在使用的“dist”功能是来自包代理的功能。我将在代码中添加“require(proxy)”。
      猜你喜欢
      • 1970-01-01
      • 2021-01-11
      • 2022-11-22
      • 2020-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多