# How would you improve this code in R?

I'm trying to implement a function that given a data frame returns the same data frame with four columns added. These new four columns are: for each row, I get the maximun element and its index and put them as two new columns. I do the same with the second maximum element. Don't care if they are repeated. This is my code for this task:

``````add_2max <- function(x)
{
max1 = max(x, na.rm=TRUE)
indmax1 = which.max(x)
y=x[-c(indmax1)]
max2 = max(y, na.rm=TRUE)
indmax2 = which(x==max2)
indmax2 = ifelse(max1==max2, indmax2[2], indmax2[1])
x=c(x, max1, max2, indmax1, indmax2)
return (x)
}

{
return(NewDF)
}
``````

I'm sure this code can be improved! What do you recommend in order to do that? Is it fast enough?

-
`ifelse` is notoriously slow, but since its working on a single row it shouldn't be an issue. As far as you last question... is it fast enough for you? –  Justin Apr 11 '12 at 15:41
Thanks for your advice @Dason –  Nestorghh Apr 11 '12 at 15:42
That's the line I'd like to avoid @Justin, but it seems not being an issue due to the fact that it's working on a single row as you've said. Thank you! –  Nestorghh Apr 11 '12 at 15:48
Just goes to show we all could use a modified `which.max(x,nth_biggest)` function. –  Carl Witthoft Apr 11 '12 at 16:39

## migrated from stackoverflow.comApr 11 '12 at 15:57

This question came from our site for professional and enthusiast programmers.

Here is a more compact version:

``````add_2maxBrian <- function(x) {
r <- order(x, decreasing=TRUE)
c(x, x[r[1:2]], r[1:2])
}
``````

With some sample data (different than Tommy's because I want the chance of ties):

``````set.seed(123)
DF <- as.data.frame(matrix(sample(1:20, 10000, replace=TRUE), 2500, 4))
``````

It's not as fast a Tommy's solution, but still faster than the original.

``````library("rbenchmark")

order = "relative")
#                                   test replications elapsed relative user.self
#2 a2 <- t(apply(DF, 1, add_2maxFaster))          100   6.537 1.000000     6.441
#3  a3 <- t(apply(DF, 1, add_2maxBrian))          100   8.259 1.263424     8.073
#1       a1 <- t(apply(DF, 1, add_2max))          100  12.168 1.861404    12.038
#  sys.self user.child sys.child
#2    0.067          0         0
#3    0.082          0         0
#1    0.089          0         0
identical(a1, a2) #TRUE
identical(a1, a3) #TRUE
``````
-
Great @Brian Diggs. Pretty compact and simple. I like a lot. –  Nestorghh Apr 11 '12 at 17:34

Here's a faster way:

``````add_2maxFaster <- function(x)
{
imax1 <- which.max(x)
imax2 <- which.max(x[-imax1])
if (imax2 >= imax1) imax2 <- imax2 + 1L
c(x, x[imax1], x[imax2], imax1, imax2)
}

set.seed(42)
m <- matrix(runif(1e6), 1e4)

# Compare speed:
system.time( a1<-apply(m, 1, add_2max) )        # 0.38 secs
system.time( a2<-apply(m, 1, add_2maxFaster) )  # 0.15 secs

# ...And compare results
all.equal(a1,a2) # TRUE
``````
-