问题
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