Reputation: 1274
Good afternoon!
Assume we have the following matrix m
. I'm wanting to select the k-minima values
with their associated rows/columns indices
. For this I developed the following code :
m=matrix(6:1,nrow=3)
print(" The matrix m is : ")
print(m)
k=5
paste("The" , k , "lowest values are : ")
print(order(m,decreasing = TRUE)[1:k] )
paste( "Solution 1 : we selected" , k , "minimum values with their respective positions " )
# Solution 1 :
t(sapply(1:length(order(m,decreasing = TRUE)[1:k]), function(i) {
h=order(m,decreasing = TRUE)[1:k];
which(m==h[i],arr.ind = TRUE) } ))
# solution 2 :
paste( "Another possibility : Solution 2 - We selected" , k , "minimum values with their respective positions " )
k_lowest_values=order(m,decreasing = TRUE)[1:5]
t(which(Reduce("|", lapply(k_lowest_values, function(x) m == x)), arr.ind = T))
This gives as expected :
[1] " The matrix m is : "
[,1] [,2]
[1,] 6 3
[2,] 5 2
[3,] 4 1
[1] "The 5 lowest values are : "
[1] 1 2 3 4 5
[1] "Solution 1 : we selected 5 minimum values with their respective positions "
[,1] [,2]
[1,] 3 2
[2,] 2 2
[3,] 1 2
[4,] 3 1
[5,] 2 1
[1] "Another possibility : Solution 2 - We selected 5 minimum values with their respective positions "
[,1] [,2] [,3] [,4] [,5]
row 2 3 1 2 3
col 1 1 2 2 2
However , the same code doesn't work as it should be with another matrix m
such :
m=structure(c(1, 0.996805114543033, 0.987281571590291, 0.971610767189123,
0.950088633802627, 0.996805114543033, 0.993620436379149, 0.984127320055285,
0.996805114543033, 1, 0.996805114543033, 0.987281571590291, 0.971610767189123,
0.993620436379149, 0.996805114543033, 0.993620436379149, 0.987281571590291,
0.996805114543033, 1, 0.996805114543033, 0.987281571590291, 0.984127320055285,
0.993620436379149, 0.996805114543033, 0.971610767189123, 0.987281571590291,
0.996805114543033, 1, 0.996805114543033, 0.968506582079198, 0.984127320055285,
0.993620436379149, 0.950088633802627, 0.971610767189123, 0.987281571590291,
0.996805114543033, 1, 0.947053209443661, 0.968506582079198, 0.984127320055285,
0.996805114543033, 0.993620436379149, 0.984127320055285, 0.968506582079198,
0.947053209443661, 1, 0.996805114543033, 0.987281571590291, 0.993620436379149,
0.996805114543033, 0.993620436379149, 0.984127320055285, 0.968506582079198,
0.996805114543033, 1, 0.996805114543033, 0.984127320055285, 0.993620436379149,
0.996805114543033, 0.993620436379149, 0.984127320055285, 0.987281571590291,
0.996805114543033, 1), .Dim = c(8L, 8L))
This output the following :
[1] " The matrix m is : "
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 1.0000000 0.9968051 0.9872816 0.9716108 0.9500886 0.9968051 0.9936204
[2,] 0.9968051 1.0000000 0.9968051 0.9872816 0.9716108 0.9936204 0.9968051
[3,] 0.9872816 0.9968051 1.0000000 0.9968051 0.9872816 0.9841273 0.9936204
[4,] 0.9716108 0.9872816 0.9968051 1.0000000 0.9968051 0.9685066 0.9841273
[5,] 0.9500886 0.9716108 0.9872816 0.9968051 1.0000000 0.9470532 0.9685066
[6,] 0.9968051 0.9936204 0.9841273 0.9685066 0.9470532 1.0000000 0.9968051
[7,] 0.9936204 0.9968051 0.9936204 0.9841273 0.9685066 0.9968051 1.0000000
[8,] 0.9841273 0.9936204 0.9968051 0.9936204 0.9841273 0.9872816 0.9968051
[,8]
[1,] 0.9841273
[2,] 0.9936204
[3,] 0.9968051
[4,] 0.9936204
[5,] 0.9841273
[6,] 0.9872816
[7,] 0.9968051
[8,] 1.0000000
[1] "Solution 1 : we selected 5 minimum values with their respective positions "
[,1] [,2] [,3] [,4] [,5]
[1,] Integer,16 Integer,0 Integer,0 Integer,0 Integer,0
[1] "Another possibility : Solution 2 - We selected 5 minimum values with their respective positions "
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
row 1 2 3 4 5 6 7 8
col 1 2 3 4 5 6 7 8
Problem: The second case doesn't give the expected output ( I should retrieve the k=5
lowest values with their rows/columns indices ). I had gotten the positions of the highest values instead !
Upvotes: 2
Views: 294
Reputation: 886938
For the second case, it is just that it is a list
output
lst1 <- sapply(order(m, decreasing = FALSE)[1:k], function(i) {
which(m==m[i],arr.ind = TRUE) } )
out <- do.call(rbind, lst1)
df <- t(out[!duplicated(out),])
print(df)
# output
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
#row 6 5 5 1 6 7 4 5
#col 5 6 1 5 4 5 6 7
sapply(lst1, nrow)
#[1] 8 0 0 0 0
where only the first list
element have greater than 0 rows. Probably ,we need to rbind
them before doing the t
ranspose
Or if we wrap do.call(rbind
directly on the OP's matrix
output with list
elements
out=do.call(rbind, t(sapply(order(m, decreasing = FALSE)[1:k], function(i) {
which(m==m[i],arr.ind = TRUE) } )))
df <- out[!duplicated(out),]
print(df)
row col
[1,] 6 5
[2,] 5 6
[3,] 5 1
[4,] 1 5
[5,] 6 4
[6,] 7 5
[7,] 4 6
[8,] 5 7
With sapply
, we may need to always consider that there is a chance of simplify
ication as by default it is TRUE
in its usage (?sapply
)
sapply(X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE)
In the first example, if we use simplify = FALSE
, will get a list
output with each list
element having only a single row
sapply(1:length(order(m,decreasing = FALSE)[1:k]), function(i) {
h=order(m,decreasing = TRUE)[1:k]
which(m==h[i],arr.ind = TRUE) }, simplify = FALSE)
#[[1]]
# row col
#[1,] 3 2
#[[2]]
# row col
#[1,] 2 2
#[[3]]
# row col
#[1,] 1 2
#[[4]]
# row col
#[1,] 3 1
#[[5]]
# row col
#[1,] 2 1
which with simplify = TRUE
results in
# [,1] [,2] [,3] [,4] [,5]
#[1,] 3 2 1 3 2
#[2,] 2 2 2 1 1
Upvotes: 1
Reputation: 6222
There are a couple of mistakes in the second solution; it should be decreasing = FALSE
and use m == m[x]
in lapply function.
k_lowest_values = order(m, decreasing = FALSE)[1:5]
inds <- which(Reduce("|",
lapply(k_lowest_values, function(x) m == m[x])),
arr.ind = T)
inds[order(m[inds]), ]
row col [1,] 6 5 [2,] 5 6 [3,] 5 1 [4,] 1 5 [5,] 6 4 [6,] 7 5 [7,] 4 6 [8,] 5 7
Upvotes: 2
Reputation: 101034
You can try the code below with which
+ %in%
inds <- which(`dim<-`(m %in% head(sort(c(m)), k), dim(m)), arr.ind = TRUE)
inds[order(m[inds]), ]
which gives
row col
[1,] 6 5
[2,] 5 6
[3,] 5 1
[4,] 1 5
[5,] 6 4
[6,] 7 5
[7,] 4 6
[8,] 5 7
Upvotes: 2