57

Suppose I have two vectors in R, defined as follows.

a = c(3,3,5)
b = c(2,4,6)

Is there a function that will give me the pairwise maximum between the elements of a and the elements of b, which can be run inside a formula?

I tried to do, max(a, b) but it does not get the desired output.

Desired Output:

C(3,4,6)

Actual output:

6
Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
merlin2011
  • 71,677
  • 44
  • 195
  • 329

3 Answers3

68

Pairwise maximum, pmax(a, b), will give c(3,4,6).

a <- c(3,3,5,NA,1)
b <- c(2,4,6,0,NA)

pmax(a, b)
# [1]  3  4  6 NA NA

pmax(a, b, na.rm = TRUE)
# [1] 3 4 6 0 1

There is also a pairwise minimum

pmin(a, b)
# [1]  2  3  5 NA NA

pmin(a, b, na.rm = TRUE)
# [1] 2 3 5 0 1

And a pairwise sum, which I pulled from this question/answer has been very useful to me at times:

psum(a, b) # == a + b
# [1]  5  7 11 NA NA

psum(a, b, na.rm = TRUE)
# [1]  5  7 11  0  1

psum(c(-1, NA, 4), c(0, NA, NA))
# [1] -1 NA NA

psum(c(-1, NA, 4), c(0, NA, NA), na.rm = TRUE)
# [1] -1 NA  4

psum <- function(..., na.rm = FALSE) {
  dat <- do.call(cbind, list(...))
  res <- rowSums(dat, na.rm = na.rm) 
  idx_na <- !rowSums(!is.na(dat))
  res[idx_na] <- NA
  res 
}
Community
  • 1
  • 1
rawr
  • 20,481
  • 4
  • 44
  • 78
  • 1
    One other extension is that these work for more than 2 vectors: `pmax(a, b, c)` and so on or `do.call(pmax, list(a, b, c))`. – lmo Sep 01 '17 at 15:18
2

An alternative method which sacrifices b:

# Where does b have smaller elements?
elsb <- which(a > b)
b[elsb] <- a[elsb]
b
# [1] 3 4 6
s_baldur
  • 29,441
  • 4
  • 36
  • 69
2

Actually, the alternative solution deserves some credit. Use it for short vectors.

It is a lot faster when the vectors a and b are short. Changing the variable s in the code you can try it out yourself. When vectors have a length of 100 (s=20) pmax_new is twice as fast. pmax overtakes the alternative at a vector length of 2.500 (s=500).

require(microbenchmark)

pmax_new <- function(a, b) {
  elsb <- which(a > b)
  b[elsb] <- a[elsb]
  b
}

a <- c(3,3,5,NA,1)
b <- c(2,4,6,0,NA)
s <- 20
microbenchmark( pmax(rep(a, s), rep(b, s)), times = 1E6 )
microbenchmark( pmax_new(rep(a, s), rep(b, s)), times = 1E6)
Jan
  • 4,974
  • 3
  • 26
  • 43