Search code examples
rmultiple-columnsranking

How can I select the top 2 values in a column per column and report this with both values and row names?


I have columns of a matrix with the names of users' unique ID's. Each row in the column represents a risk factor score based on a regression model that predicted risk. I want to report each individual's top 2 risk factors (both the row name representing the factors and the actual values) along with their ID.

I've searched for solutions and found a lot of near misses. For instance, max would work if I only wanted the top 1 value without a row name, and it I didn't have individuals as columns then I think that I could use some variation of sort(x,partial=n-1)[n-1].

My data looks like this:

        ID.H00034222 ID.H00034305
a.score  0.040093810   0.04009381
b.score -0.038265220  -0.03826522
c.score  0.044418130   0.04441813
d.score -0.418624640  -0.05656504
e.score -0.005192439   0.10851938
f.score  0.005026030   0.02174170

df <- structure(c(0.04009381, -0.03826522, 0.04441813, -0.41862464, 
-0.005192439, 0.00502603, 0.04009381, -0.03826522, 0.04441813, 
-0.05656504, 0.10851938, 0.0217417), .Dim = c(6L, 2L), .Dimnames = list(
    c("a.score", "b.score", "c.score", "d.score", "e.score", 
    "f.score"), c("ID.H00034222", "ID.H00034305")))

My output should give a user ID, and highest 2 row names and values for each ID.


Solution

  • Some toy data:

    > foo <- matrix(rnorm(80),nrow=20,dimnames=list(letters[1:20],LETTERS[23:26]))
    > foo
               W           X           Y          Z
    a  1.3550138  1.35438637  0.43150124 -0.7087100
    b -1.3200136 -0.82764303 -0.01480796  2.2399561
    c -1.0018050 -0.04941702 -2.46454058  0.2516673
    d  0.7877259  0.08713982  1.25948179  1.1901716
    e  1.5834800  0.06905996  0.37453295  0.5343909
    f  0.3607650  0.22815776 -0.24688689 -0.7784353
    g  0.2071689 -0.21987249 -0.38334840 -0.0568370
    h  0.7502296  0.61355174 -0.38836131  1.8772838
    i -1.1608980  0.75128093 -0.13562930 -1.3183407
    j -0.5419957 -0.43251911 -1.91773334  0.8227418
    k  1.1222314 -0.52768270  1.13687919  0.2458857
    l -0.2158528 -0.43057554 -0.93613664  0.7861322
    m  0.2933530 -1.22532466  0.98192839  0.6581522
    n -0.6324390 -0.90072134 -1.89817529 -1.4419014
    o  0.6956912  1.28457179  0.65234730  0.6524573
    p -1.4979845 -0.23898356  1.82825548 -0.1819744
    q  1.5459565  0.38683197 -1.23645565  1.0340520
    r -1.3844880  0.05111238 -0.51715069 -0.1702139
    s -2.1096706  0.46527795 -1.13718323  0.8133859
    t -1.5700089  0.09305299  2.33807078  0.8382010
    

    Extract the top two values per column:

    > apply(foo,2,function(xx)tail(sort(xx),2))
                W        X        Y        Z
    [1,] 1.545957 1.284572 1.828255 1.877284
    [2,] 1.583480 1.354386 2.338071 2.239956
    

    Extract the names of the top two values per column:

    > apply(foo,2,function(xx)tail(names(sort(xx)),2))
         W   X   Y   Z  
    [1,] "q" "o" "p" "h"
    [2,] "e" "a" "t" "b"
    >