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列从因素转换为字符