我最终决定将在互联网上浮动的sort.data.frame方法放入R包中。它只是被要求太多而无法留给临时分发方法。
但是,它使用参数编写,使其与泛型排序函数不兼容:
sort(x,decreasing,...)
sort.data.frame(form,dat)
如果我将sort.data.frame
更改为sort.data.frame(form,decreasing,dat)
中的参数减少并丢弃减少,则会失去其简单性,因为您始终必须指定dat=
而不能真的使用位置参数。如果我将其添加到sort.data.frame(form,dat,decreasing)
中的末尾,那么顺序与泛型函数不匹配。如果我希望减少被赶上点`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),]
}
示例:
library(datasets)
sort.data.frame(~len+dose,ToothGrowth)
答案 0 :(得分:6)
使用arrange
中的plyr
功能。它允许您单独选择哪些变量应按升序和降序排列:
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, ])
}
desc
只是一个普通的函数:
desc <- function (x) -xtfrm(x)
如果您正在撰写此类功能,强烈建议您阅读xtfrm
的帮助。
答案 1 :(得分:4)
那里有一些问题。 sort.data.frame
需要与泛型具有相同的参数,因此至少需要
sort.data.frame(x, decreasing = FALSE, ...) {
....
}
要进行调度工作,第一个参数需要是调度的对象。所以我会从:
开始sort.data.frame(x, decreasing = FALSE, formula = ~ ., ...) {
....
}
其中x
是您的dat
,formula
是您的form
,我们提供公式的默认值以包含所有内容。 (我没有仔细研究您的代码,以确切了解form
代表什么。)
当然,您无需在通话中指定decreasing
,因此:
sort(ToothGrowth, formula = ~ len + dose)
将是如何使用上述规范调用该函数。
否则,如果您不希望sort.data.frame
成为S3泛型,请将其称为其他内容,然后您可以自由地获得所需的任何参数。
答案 2 :(得分:2)
你能否掩盖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)
}
}
答案 3 :(得分:0)
我同意@Gavin x
必须先行。我将decreasing
参数放在formula
之后 - 因为它可能没有那么多使用,而且几乎不作为位置参数。
formula
参数将被更多地使用,因此应该是第二个参数。我也非常同意@Gavin,它应该被称为formula
,而不是form
。
sort.data.frame(x, formula = ~ ., decreasing = FALSE, ...) {
...
}
您可能希望扩展decreasing
参数以允许逻辑向量,其中每个TRUE / 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