问题
I would like to vectorize (apply
) a which
operation on matrix X
as illustrated by the following for
loop having as result the vector ind
:
X = matrix( 1:20, 4, 5 )
V = sample( 1:20, 4 )
ind = numeric()
for( i in 1:nrow(X) ) ind[i] = max( c(0, which(X[i,] < V[i]) ))
The operation returns in ind
for each row in X
the index of the element with the highest value smaller than the value indicated by the X
-row-corresponding element of V
.
The operation max
maps the vector of all eligible indices to a scalar. Alternatively I would by happy with an operation returning e.g. a list
of all indices (to which I can lapply
max
).
回答1:
If your matrix has increasing values like the example you shared (which of course I doubt), but If it does you can simply do,
rowSums(X < V)
#[1] 4 3 4 0
However, If this is not the case, then a simple apply
will suffice, i.e.
apply(X < V, 1, function(i)max(which(i)))
#[1] 4 3 4 -Inf
Remember that all mathematical operations are vectorized, so <
is vectorized
You can replace -Inf
as per usual
回答2:
apply(
(X < V) * X
, 1
, which.max
)
回答3:
Here's a simple lapply example
X = matrix( 1:20, 4, 5 )
V = sample( 1:20, 4 )
ind = numeric()
for( i in 1:nrow(X) ) ind[i] = max( c(0, which(X[i,] < V[i]) ))
mymax = function(matrix, sample) {
whichlist = which(matrix < sample)
max(0, whichlist)
}
ind2 = unlist(lapply(1:nrow(X), function(r) mymax(X[r,], V[r])))
identical(ind, ind2)
# [1] TRUE
回答4:
Here is another answer where you first sweep
the vector V
across each row of X
and then you use apply to determine the maximum TRUE
element of each row.
set.seed(14)
X = matrix( 1:20, 4, 5 )
V = sample( 1:20, 4 )
ind1 = numeric()
for( i in 1:nrow(X) ) ind1[i] = max(c(0, which(X[i,] < V[i]) ))
ind2 <- apply(
sweep(X, 1, V, "<"),
1,
function(x){
max(
which(
x,
arr.ind = TRUE)
)
}
)
> ind1
[1] 2 5 2 4
> ind2
[1] 2 5 2 4
来源:https://stackoverflow.com/questions/60097628/vectorizing-which-operation-across-the-rows-of-a-matrix