Class 为sort.data.frame创建泛型/方法一致性的最佳方法?

Class 为sort.data.frame创建泛型/方法一致性的最佳方法?,class,generics,r,methods,Class,Generics,R,Methods,我最终决定将互联网上的sort.data.frame方法放入一个R包中。它只是得到了太多的请求,不能留给一个特殊的分发方法 但是,它使用的参数与通用排序函数不兼容: sort(x,decreasing,...) sort.data.frame(form,dat) desc <- function (x) -xtfrm(x) 如果我更改sort.data.frame将递减作为参数,就像在sort.data.frame(form,discreating,dat)中一样,并放弃递减,那么它就

我最终决定将互联网上的sort.data.frame方法放入一个R包中。它只是得到了太多的请求,不能留给一个特殊的分发方法

但是,它使用的参数与通用排序函数不兼容:

sort(x,decreasing,...)
sort.data.frame(form,dat)
desc <- function (x) -xtfrm(x)
如果我更改
sort.data.frame
将递减作为参数,就像在
sort.data.frame(form,discreating,dat)
中一样,并放弃递减,那么它就失去了它的简单性,因为您总是必须指定
dat=
,并且不能真正使用位置参数。如果我像在
sort.data.frame(form,dat,discreating)
中那样将其添加到末尾,则顺序与泛型函数不匹配。如果我希望在dots`sort.data.frame(form,dat,…)中包含递减,那么当使用基于位置的匹配时,我相信通用函数会将第二个位置分配给递减,它将被丢弃。协调这两个功能的最佳方式是什么

全部功能是:

# Sort a data frame
sort.data.frame <- function(form,dat){
# Author: Kevin Wright
# http://tolstoy.newcastle.edu.au/R/help/04/09/4300.html
# Some ideas from Andy Liaw
# http://tolstoy.newcastle.edu.au/R/help/04/07/1076.html
# Use + for ascending, - for decending.
# Sorting is left to right in the formula
# Useage is either of the following:
# sort.data.frame(~Block-Variety,Oats)
# sort.data.frame(Oats,~-Variety+Block)

# If dat is the formula, then switch form and dat
  if(inherits(dat,"formula")){
    f=dat
    dat=form
    form=f
  }
  if(form[[1]] != "~") {
    stop("Formula must be one-sided.")
  }
# Make the formula into character and remove spaces
  formc <- as.character(form[2])
  formc <- gsub(" ","",formc)
# If the first character is not + or -, add +
  if(!is.element(substring(formc,1,1),c("+","-"))) {
    formc <- paste("+",formc,sep="")
  }
# Extract the variables from the formula
  vars <- unlist(strsplit(formc, "[\\+\\-]"))
  vars <- vars[vars!=""] # Remove spurious "" terms
# Build a list of arguments to pass to "order" function
  calllist <- list()
  pos=1 # Position of + or -
  for(i in 1:length(vars)){
    varsign <- substring(formc,pos,pos)
    pos <- pos+1+nchar(vars[i])
    if(is.factor(dat[,vars[i]])){
      if(varsign=="-")
        calllist[[i]] <- -rank(dat[,vars[i]])
      else
        calllist[[i]] <- rank(dat[,vars[i]])
    }
    else {
      if(varsign=="-")
        calllist[[i]] <- -dat[,vars[i]]
      else
        calllist[[i]] <- dat[,vars[i]]
    }
  }
  dat[do.call("order",calllist),]
} 

这里有一些问题
sort.data.frame
需要与泛型具有相同的参数,因此至少需要

sort.data.frame(x, decreasing = FALSE, ...) {
....
}
要进行分派工作,第一个参数必须是分派到的对象。因此,我首先要说:

sort.data.frame(x, decreasing = FALSE, formula = ~ ., ...) {
....
}
其中,
x
是您的
dat
公式
是您的
表单
,我们为公式提供了一个默认值以包含所有内容。(我还没有详细研究您的代码,以了解
表单
到底代表了什么。)

当然,您不需要在调用中指定
递减
,因此:

sort(ToothGrowth, formula = ~ len + dose)
将是如何使用上述规范调用函数


否则,如果您不想将
sort.data.frame
称为S3泛型,请将其称为其他类型,然后您可以自由使用任何参数。

我同意@Gavin的观点,即
x
必须首先出现。尽管如此,我还是将
递减
参数放在
公式
之后,因为它可能没有太多使用,而且几乎从来没有作为位置参数

formula
参数将被更多地使用,因此应该是第二个参数。我也非常同意@Gavin的观点,即它应该被称为
formula
,而不是
form

sort.data.frame(x, formula = ~ ., decreasing = FALSE, ...) {
  ...
}
您可能希望扩展
递减
参数,以允许逻辑向量,其中每个真/假值对应于公式中的一列:

d <- data.frame(A=1:10, B=10:1)
sort(d, ~ A+B, decreasing=c(A=TRUE, B=FALSE)) # sort by decreasing A, increasing B

d使用
plyr
中的
arrange
功能。它允许您单独选择哪些变量应按升序和降序排列:

arrange(ToothGrowth, len, dose)
arrange(ToothGrowth, desc(len), dose)
arrange(ToothGrowth, len, desc(dose))
arrange(ToothGrowth, desc(len), desc(dose))
它还有一个优雅的实现:

arrange <- function (df, ...) {
  ord <- eval(substitute(order(...)), df, parent.frame())
  unrowname(df[ord, ])
}

如果您正在编写此类函数,强烈建议您阅读
xtfrm
的帮助。

可能对
plyr
包中的函数
arrange
感兴趣。它是。不幸的是,它看起来不支持负(向后)排序,所以这个函数看起来仍然很有用。我很确定
arrange
确实支持负排序:
arrange(ToothGrowth,desc(dose),len)
。用plyr写了一个完整的答案-感谢@joran的例子!我希望公式参数是第二个,但我不确定我是否可以这样做,并且它仍然是一个S3类。我不希望有一个
递减
,因为公式采用了负参数,这意味着递减。@gsk3,
sort.int
只有
递减=…
作为第四个参数,所以我猜你可以将
公式=…
作为第二个参数。我怀疑您也可以使用
discreating=NULL
并在代码中忽略此参数(与
sort.int
partial=TRUE
时忽略
discreating
的方式相同)。注:所有这些都可以在
?sort
@Andrie中找到,即使您翻转顺序,因为
递减
在泛型函数中被命名为第二个,它会获取位置参数。所以很遗憾,它没有帮助。@Andrie
sort.int
不是
sort
的方法。没有类
int
。您可以看到使用
methods(sort)
实现的方法。通过部分匹配,编写
sort(ToothGrowth,f=~len+dose)
并没有那么糟糕,所以我这样做并保持了它的稳定性。谢谢你的建议。我们是否应该定义一个
sort.data.frame.formula
作为第一个参数,如果它在
Use.method
中的公式测试失败,那么它将被分派到sort.data.frame作为第一个数据参数?(与聚合的情况相同。*
)@DWin您的意思是
sort.formula
,是吗?我想我希望它返回到一个
sort.data.frame.default
方法或
sort.dataframe
,它将第一个参数作为dataframe接受。谢谢。这似乎准备成为我的替代者。但我仍然很好奇,如何让泛型和它的方法保持一致,因为我经常遇到它。此外,从语法上讲,sort()方法似乎可以保持与其他数据类型的一致性。但这是一些漂亮的代码:-)
?arrange
表示:“#注意:plyr函数不保留row.names”。如果想要保持
行.names
,这使得这个优秀的函数不是最佳的。为什么不添加一个
keep.row.names=FALSE
选项?@landroni,因为我认为它们不是一个好主意-最好将它们作为显式变量添加。我明白了。但是,至少就大多数用户而言,这是与
data.frame
相关的标准功能,让这些用户进行选择是很有用的。
desc <- function (x) -xtfrm(x)