Best way to create generic/method consistency for sort.data.frame?

I've finally decided to put the sort.data.frame method that's floating around the internet into an R package. It just gets requested too much to be left to an ad hoc method of distribution.

However, it's written with arguments that make it incompatible with the generic sort function:

sort(x,decreasing,...)
sort.data.frame(form,dat)

If I change sort.data.frame to take decreasing as an argument as in sort.data.frame(form,decreasing,dat) and discard decreasing, then it loses its simplicity because you'll always have to specify dat= and can't really use positional arguments. If I add it to the end as in sort.data.frame(form,dat,decreasing) , then the order doesn't match with the generic function. If I hope that decreasing gets caught up in the dots `sort.data.frame(form,dat,...), then when using position-based matching I believe the generic function will assign the second position to decreasing and it will get discarded. What's the best way to harmonize these two functions?

The full function is:

# 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),]
} 

Example:

library(datasets)
sort.data.frame(~len+dose,ToothGrowth)

There are a few problems there. sort.data.frame needs to have the same arguments as the generic, so at a minimum it needs to be

sort.data.frame(x, decreasing = FALSE, ...) {
....
}

To have dispatch work, the first argument needs to be the object dispatched on. So I would start with:

sort.data.frame(x, decreasing = FALSE, formula = ~ ., ...) {
....
}

where x is your dat , formula is your form , and we provide a default for formula to include everything. (I haven't studied your code in detail to see exactly what form represents.)

Of course, you don't need to specify decreasing in the call, so:

sort(ToothGrowth, formula = ~ len + dose)

would be how to call the function using the above specifications.

Otherwise, if you don't want sort.data.frame to be an S3 generic, call it something else and then you are free to have whatever arguments you want.


Use the arrange function in plyr . It allows you to individually pick which variables should be in ascending and descending order:

arrange(ToothGrowth, len, dose)
arrange(ToothGrowth, desc(len), dose)
arrange(ToothGrowth, len, desc(dose))
arrange(ToothGrowth, desc(len), desc(dose))

It also has an elegant implementation:

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

And desc is just an ordinary function:

desc <- function (x) -xtfrm(x)

Reading the help for xtfrm is highly recommended if you're writing this sort of function.


你能否掩饰sort的基本定义,即类似的东西?

sort <- function(x,...) {
  if (inherits(x,"data.frame")) {
    sort.data.frame(x,...)
  } else {
    L <- list(...)
    if (!is.null(names(L))) {
      if ("decreasing" %in% names(L)) {
        decreasing <- L[["decreasing"]]
        L <- L[names(L)!="decreasing"]
      }
    } else {
      if (any(names(L)=="")) {
        dpos <- which.min(names(L)=="")
        decreasing <- L[[dpos]]
        L <- L[-dpos]
      } else decreasing <- FALSE      
    }
    arglist <- c(list(x=x,decreasing=decreasing),L)
    do.call(base::sort,arglist)
  }
}
链接地址: http://www.djcxy.com/p/12222.html

上一篇: 将data.frame列从因素转换为字符

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