Given two arrays:
a = array(1:3)
b = array(3:1)
I want to apply a function that sequentially compares the value of each element of A to each element of B, and return the result.
Something like:
compare = function(xa, xb) { if (xa < xb) { 1 } else { 0 } }
...where xa would be the an element from the a array, and xb would be an element from the b array.
Is there a derivative of apply I can use to accomplish this?
Rather than mapply
I would use R internal recycling rules for vectorised functions. If a
and b
are the same length you need only do this:
as.integer( a < b )
#[1] 1 0 0
as.integer
is just there to coerce to 1
or 0
, in reality TRUE
and FALSE
will behave as 1
and 0
in any subsequent multiplicative operations.
set.seed(1); a <- sample(10)
#[1] 3 4 5 7 2 8 9 6 10 1
set.seed(2); b <- sample(10)
#[1] 2 7 5 10 6 8 1 3 4 9
a < b
#[1] FALSE TRUE FALSE TRUE TRUE FALSE FALSE FALSE FALSE TRUE
a * ( a < b )
#[1] 0 4 0 7 2 0 0 0 0 1
a[ a < b ]
#[1] 4 7 2 1
Some people may be surprised, but <
is a function. It calls an underlying C
function called do_relop
in the files /src/main/relop.c
(all the logical comparators do - they just use a different switch for the type of comparison) which handles vector recycling. You can write <
like this:
`<`( a , b )
#[1] FALSE TRUE FALSE TRUE TRUE FALSE FALSE FALSE FALSE TRUE
Using the primitive <
operator is over 100 times quicker (on a pair of 1e6 length vectors) than using ifelse
which is also a vectorized function:
set.seed(1); a <- sample(10,1e6,repl=T)
set.seed(2); b <- sample(10,1e6,repl=T)
require( microbenchmark)
bm <- microbenchmark( comparealt(a,b) , `<`(a,b) , times = 25L )
print( bm , digits = 3 , unit = "relative" , order = "median" )
#Unit: relative
# expr min lq median uq max neval
# a < b 1 1 1 1 1.0 25
# comparealt(a, b) 131 126 122 105 48.3 25
I originally read "the value of each element of A to each element of B" meaning an outer join and suggested:
compare <- function(x, y){ outer(x, y, FUN="<")+0 }
which for example gives
> compare(array(1:6), array(5:3))
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 1
[3,] 1 1 0
[4,] 1 0 0
[5,] 0 0 0
[6,] 0 0 0
For comparing matrices of the same dimension elementwise you could use something like
comparemat <- function(mat1, mat2){ (mat1 < mat2)+0 }
or
comparealt <- function(mat1, mat2){ ifelse(mat1 < mat2, 1, 0) }
where either of
comparemat(matrix(1:12,nrow=4), matrix(12:1,nrow=4))
comparealt(matrix(1:12,nrow=4), matrix(12:1,nrow=4))
give
[,1] [,2] [,3]
[1,] 1 1 0
[2,] 1 1 0
[3,] 1 0 0
[4,] 1 0 0
I stumbled upon 'mapply', which seems to do the trick:
> gg = function(x,y){ if(x < y) { 1 } else { 0 }}
> gg(1,2)
[1] 1
> gg(2,1)
[1] 0
> mapply(gg, 1:4, 4:1)
[1] 1 1 0 0
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.