通过函数对data.table进行绝对降序排序?

5
我希望能够通过将排序字段传递到函数来执行绝对值降序排序(即忽略符号排序,例如 5、-2、1)。我的data.table上已经查看了降序排序,但是在我的尝试中,我遇到了错误或者变换了变量的符号,而没有正确地进行排序。
下面是可以正常工作的内容:
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

但是当传递参数时,我找不到正确的语法(数学错误,必须提供j等)。

#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

我尝试了各种不同的evals、as.name、with = F等方法。

   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

请让我解脱吧!非常感谢。

P.S. setorderv() 处理纯粹的升序和降序情况。是的,我可以添加一列,对其取绝对值,然后使用 setorderv,最后删除临时列,但我正在寻找一个更加优雅的解决方案。

编辑:其他人指出了类似于 筛选答案 的问题。该问题也涉及到数据帧,而不仅仅是数据表,并且专注于过滤数据行。它没有使用像 abs() 这样的函数进行转换排序,保留所有行并且不改变数据。同时,这个问题可能有助于其他寻找 data.table 的绝对排序类型的人,因为它在其 setorderv() 中没有涵盖。


类似的问题,在这里有相同的答案(和回答者):https://dev59.com/Vonda4cB1Zd3GeqPA5An - Frank
可能是在data.table中可变地选择/分配字段的重复问题。 - Frank
1
感谢Frank提供的答案链接。我在搜索时没有看到这些。你会发现我尝试了with = FALSE。我的错误是重新分配数据表,而不仅仅是按引用搜索 - 因此在排序时应该避免使用DT <- DT [..]。我的答案与众不同,因为我试图在列名上放置一个函数,这有点棘手,我希望这个答案能帮助其他人。 - micstr
就我所知,我认为所有这些问题都是相同的,因为它们都涉及在[.data.table调用中传递一个字符串列名(或名称向量)进行评估。无论它是在i还是j字段中;特定操作是什么;或者你是否要求将其转换为函数,都不会改变问题和答案的核心。我不介意它没有被投票为重复,但我认为有一个相当好的案例。我希望当有人询问如何对字符串列进行“大小写无关排序”时,我们至少可以将其标记为重复使用此内容。 - Frank
1
我很欣赏你的想法。对于初学者来说,由于data.table包非常复杂,因此掌握它可能会有些棘手。什么时候使用as.name(),什么时候使用with = F,难怪FAQ开头就是“为什么DT [,5]返回5!”。初学者可能还没有意识到变量选择= 通过函数= 参数化是相似的,尽管这对于全职编码人员来说可能是显而易见的。 - micstr
2个回答

3

试试这个:

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

在第一个函数定义后,你所做的是向abs函数传递了一个字符串,因此出现了ERROR get non-numeric argument to maths function as it sees string错误提示,因为它将字符串视为非数学函数的参数。

3
eval(as.name()) 会起作用。
 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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接