In general, xtfrm()
is the generic function to get a numeric vector that
sorts like the given input vector. Decreasing sorting can then be done by
sorting with the negated value of xtfrm()
. (This is exactly how e.g.
dplyr’s desc()
is implemented.)
For example, with the data in question:
df <- read.table(text = "
P1 P2 P3 T1 T2 T3 I1 I2
2 3 5 52 43 61 6 b
6 4 3 72 NA 59 1 a
1 5 6 55 48 60 6 f
2 4 4 65 64 58 2 b
", header = TRUE)
df[order(-xtfrm(df$I1), df$I2), ]
#> P1 P2 P3 T1 T2 T3 I1 I2
#> 1 2 3 5 52 43 61 6 b
#> 3 1 5 6 55 48 60 6 f
#> 4 2 4 4 65 64 58 2 b
#> 2 6 4 3 72 NA 59 1 a
This approach can be generalized into a base R function to sort
data frames by given columns, that also accepts a vector-valued decreasing
argument. From my answer to
this recent question:
sortdf <- function(x, by = colnames(x), decreasing = FALSE) {
x[do.call(order, Map(sortproxy, x[by], decreasing)), , drop = FALSE]
}
sortproxy <- function(x, decreasing = FALSE) {
as.integer((-1)^as.logical(decreasing)) * xtfrm(x)
}
And with the current example data, we (of course) get:
sortdf(df, by = c("I1", "I2"), decreasing = c(TRUE, FALSE))
#> P1 P2 P3 T1 T2 T3 I1 I2
#> 1 2 3 5 52 43 61 6 b
#> 3 1 5 6 55 48 60 6 f
#> 4 2 4 4 65 64 58 2 b
#> 2 6 4 3 72 NA 59 1 a