I would like to do an absolute descending sort (i.e. sort ignoring sign so e.g. 5, -2, 1) of my data.table
by passing a sort.field into a function.
I have looked at descending sort, but in my efforts I get errors or I am transforming the sign of my variable, and not sorting it properly.
This works:
library(data.table)
DT <- data.table(id = c("a","b","z"),
score = c(1, 5, -2))
DT1 <- copy(DT)
#doing sort direct works
DT1 <- DT1[order(-abs(score))]
# i.e. b, Z, a
But when passing a parameter I cannot find the right syntax (math errors, j must be provided, etc.)
#in function
sort.field = "score"
sortme <- function(dt, sort.field){
dt <- dt[order(-abs(sort.field))]
}
DT2 <- sortme(DT, sort.field)
# ERROR get non-numeric argument to maths function as it sees string
I have tried various evals, as.name, with = F, etc.
dt <- dt[, order(-abs(as.name(sort.field))]
# even
expr <- substitute(x := -abs(x), list(x=as.name(sort.field)))
dt<- dt[,eval(expr)]
DT3 <- DT[,eval(expr)] # changes all to negative
DT4 <- DT[order(eval(expr))] # DT not happy
Please put me out of my misery! Thanks so much.
P.S. setorderv()
handles straight Ascending and Descending cases. Yes, I could add a column, absolute it and then use setorderv, then delete the temp column, but I am looking for a more elegant solution.
Edit: Others have pointed to the similar answer for filtering. That question also covers data.frames, and not solely data tables, and is focused on filtering rows of data. It does not do a transformative ordering with a function like abs()
of the field text, keeping all the rows and not changing the data. Also this question could help others looking at this absolute sort type for data.table
which is not covered in its setorderv()
.
Try this:
sort.field = "score"
sortme <- function(dt, sort.field) dt[order(-abs(dt[[sort.field]]))]
sortme(DT, sort.field)
# id score
#1: b 5
#2: z -2
#3: a 1
What you did after the first function definition was to pass a string to the abs
function, hence the ERROR get non-numeric argument to maths function as it sees string
The eval(as.name())
would work
sort.field = "score"
sort_me <- function(dt, sort.field){
dt[order(-abs(eval(as.name(sort.field))))]
}
sort_me(DT, sort.field)
# id score
#1: b 5
#2: z -2
#3: a 1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With