creating a triangular matrix

后端 未结 4 664
有刺的猬
有刺的猬 2020-12-15 08:04

There must an elegant way to do this but I can\'t figure out so:

Columns are probabilities from 1 to 0 going right

Rows are probabilities from 0 to 1 going d

相关标签:
4条回答
  • 2020-12-15 08:38

    A slightly different solution, close in style to @DWin's:

    Create a matrix with the appropriate lower triangle (I don't think the rounding is strictly necessary, but otherwise the floating point error makes it look awful):

    mat <- round(outer(seq(-0.5, 0.5, 0.1), seq(-0.5, 0.5, 0.1), `+`), 1)
    mat
    
          [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11]
     [1,] -1.0 -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2  -0.1   0.0
     [2,] -0.9 -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1   0.0   0.1
     [3,] -0.8 -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1  0.0   0.1   0.2
     [4,] -0.7 -0.6 -0.5 -0.4 -0.3 -0.2 -0.1  0.0  0.1   0.2   0.3
     [5,] -0.6 -0.5 -0.4 -0.3 -0.2 -0.1  0.0  0.1  0.2   0.3   0.4
     [6,] -0.5 -0.4 -0.3 -0.2 -0.1  0.0  0.1  0.2  0.3   0.4   0.5
     [7,] -0.4 -0.3 -0.2 -0.1  0.0  0.1  0.2  0.3  0.4   0.5   0.6
     [8,] -0.3 -0.2 -0.1  0.0  0.1  0.2  0.3  0.4  0.5   0.6   0.7
     [9,] -0.2 -0.1  0.0  0.1  0.2  0.3  0.4  0.5  0.6   0.7   0.8
    [10,] -0.1  0.0  0.1  0.2  0.3  0.4  0.5  0.6  0.7   0.8   0.9
    [11,]  0.0  0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8   0.9   1.0
    

    Reverse the columns

    mat <- mat[,rev(seq.int(ncol(mat)))]
    

    Remove the upper triangle:

    mat[upper.tri(mat)] <- NA
    

    Re-reverse the columns:

    mat <- mat[,rev(seq_len(ncol(mat)))]
    mat
    
          [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11]
     [1,]   NA   NA   NA   NA   NA   NA   NA   NA   NA    NA   0.0
     [2,]   NA   NA   NA   NA   NA   NA   NA   NA   NA   0.0   0.1
     [3,]   NA   NA   NA   NA   NA   NA   NA   NA  0.0   0.1   0.2
     [4,]   NA   NA   NA   NA   NA   NA   NA  0.0  0.1   0.2   0.3
     [5,]   NA   NA   NA   NA   NA   NA  0.0  0.1  0.2   0.3   0.4
     [6,]   NA   NA   NA   NA   NA  0.0  0.1  0.2  0.3   0.4   0.5
     [7,]   NA   NA   NA   NA  0.0  0.1  0.2  0.3  0.4   0.5   0.6
     [8,]   NA   NA   NA  0.0  0.1  0.2  0.3  0.4  0.5   0.6   0.7
     [9,]   NA   NA  0.0  0.1  0.2  0.3  0.4  0.5  0.6   0.7   0.8
    [10,]   NA  0.0  0.1  0.2  0.3  0.4  0.5  0.6  0.7   0.8   0.9
    [11,]    0  0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8   0.9   1.0
    

    You can change the rownames from there.

    EDIT: Given there are so many solutions, you may be interested to see how they benchmark. Using microbenchmark:

    Unit: microseconds
       expr       min         lq     median         uq       max
    1 AGS()   682.491   738.9370   838.0955   892.8815  4518.740
    2  DW()    23.244    27.1680    31.3930    34.8650    70.937
    3 MvG() 15469.664 15920.4820 17352.3215 17827.4380 18989.270
    4  SC()   118.629   131.4575   144.1360   157.7190   631.779
    

    @DWin's solution appears to be the fastest by quite a margin.

    0 讨论(0)
  • 2020-12-15 08:39
     mat <- matrix(NA, 10,10)
     mat[row(mat)+col(mat) >=11] <- (row(mat)+col(mat) -11)[row(mat)+col(mat)>=11]/10
     mat
          [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
     [1,]   NA   NA   NA   NA   NA   NA   NA   NA   NA   0.0
     [2,]   NA   NA   NA   NA   NA   NA   NA   NA  0.0   0.1
     [3,]   NA   NA   NA   NA   NA   NA   NA  0.0  0.1   0.2
     [4,]   NA   NA   NA   NA   NA   NA  0.0  0.1  0.2   0.3
     [5,]   NA   NA   NA   NA   NA  0.0  0.1  0.2  0.3   0.4
     [6,]   NA   NA   NA   NA  0.0  0.1  0.2  0.3  0.4   0.5
     [7,]   NA   NA   NA  0.0  0.1  0.2  0.3  0.4  0.5   0.6
     [8,]   NA   NA  0.0  0.1  0.2  0.3  0.4  0.5  0.6   0.7
     [9,]   NA  0.0  0.1  0.2  0.3  0.4  0.5  0.6  0.7   0.8
    [10,]    0  0.1  0.2  0.3  0.4  0.5  0.6  0.7  0.8   0.9
    

    I think this will be much faster than a plyr solution and I happen to think it is easier to comprehend. It basically sets up a test for the entries that are in the lower right hand "triangle" and then divides the results of that "test" matrix bu 10. You can look at the test matrix with this code:

    row(mat)+col(mat) -11
    

    Edit: I thought it possible that making the matrix once as sebastian-c illustrated and then doing a single test to do the NA setting might be faster ( with one third the number of calls to row and col) but it appears to be only one third as fast. It looks like the two seq calls take more time than the extra :

    mat <- round(outer(seq(-0.5, 0.5, 0.1), seq(-0.5, 0.5, 0.1), `+`), 1)
    is.na(mat) <- row(mat)+col(mat) <= 11
    mat
    

    I did find another solution based on the little known embed function:

    mat <- embed(seq(-1,1, by=0.1), 11 )[,11:1]
    is.na(mat) <- row(mat)+col(mat) <= 11
    

    Although it is 50% faster than the new solution, it is still slower than the original.

    0 讨论(0)
  • 2020-12-15 08:39

    One possible way, using my current favorite library:

    library(plyr)
    daply(expand.grid(x=seq(1,0,-.1), y=seq(0,1,.1)),
          .(y, x), with,
          if (x+y >= 1) x+y-1 else NA)
    

    This gives the following result:

         x
    y      0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9   1
      0   NA  NA  NA  NA  NA  NA  NA  NA  NA  NA 0.0
      0.1 NA  NA  NA  NA  NA  NA  NA  NA  NA 0.0 0.1
      0.2 NA  NA  NA  NA  NA  NA  NA  NA 0.0 0.1 0.2
      0.3 NA  NA  NA  NA  NA  NA  NA 0.0 0.1 0.2 0.3
      0.4 NA  NA  NA  NA  NA  NA 0.0 0.1 0.2 0.3 0.4
      0.5 NA  NA  NA  NA  NA 0.0 0.1 0.2 0.3 0.4 0.5
      0.6 NA  NA  NA  NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6
      0.7 NA  NA  NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7
      0.8 NA  NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8
      0.9 NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
      1    0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
    

    The idea is that the expand.grid creates a data frame of all possible cell values. You could just as well use merge for this. Then you apply a function to each of these values to compute the cell content. And have daply turn this into a nice matrix for you, including names.

    EDIT:
    OK, you wanted the columns labeled in reverse order. ddply will sort them ascending. So try this:

    daply(expand.grid(x=seq(0,1,.1), y=seq(0,1,.1)),
          .(y, x), with,
          if (y-x >= 0) y-x else NA)[,11:1]
    
         x
    y      1 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1   0
      0   NA  NA  NA  NA  NA  NA  NA  NA  NA  NA 0.0
      0.1 NA  NA  NA  NA  NA  NA  NA  NA  NA 0.0 0.1
      0.2 NA  NA  NA  NA  NA  NA  NA  NA 0.0 0.1 0.2
      0.3 NA  NA  NA  NA  NA  NA  NA 0.0 0.1 0.2 0.3
      0.4 NA  NA  NA  NA  NA  NA 0.0 0.1 0.2 0.3 0.4
      0.5 NA  NA  NA  NA  NA 0.0 0.1 0.2 0.3 0.4 0.5
      0.6 NA  NA  NA  NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6
      0.7 NA  NA  NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7
      0.8 NA  NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8
      0.9 NA 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9
      1    0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
    
    0 讨论(0)
  • 2020-12-15 08:52
    require(matlab)
    x=matrix(seq(0,1,.1),1)
    X=x[rep(1,c(11)),]
    X[upper.tri(X)]=NA
    X=t(X)
    for(a in 1:11){
      X[1:a,a]=rev(X[1:a,a])
    }
    X=flipud(X)
    colnames(X) <- seq(1,0,by=-.1)
    rownames(X) <- seq(0,1,by=.1)
    
    0 讨论(0)
提交回复
热议问题