2011-07-26 82 views
8

我终于决定把在Internet上浮动的sort.data.frame方法放到R包中。它只是被请求太多而不能用于临时分配方法。为sort.data.frame创建泛型/方法一致性的最佳方法?

但是,它是写带参数,使其与通用排序功能不兼容:

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) 
+3

'plyr'包中的函数'arrange'可能会引起一些兴趣。 – joran

+0

是的。不幸的是,它看起来不像支持负面(向后)排序,所以这个功能似乎仍然有用。 –

+0

我很确定'arrange'确实支持负面排序:'排列(ToothGrowth,desc(dose),len)'。 – joran

回答

4

有存在一些问题。 sort.data.frame需要有相同的参数通用的,所以它至少需要是

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

要有调度工作,第一个参数必须是对象出动。因此,我将开始:

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

其中x是你datformula是你form,我们提供一个默认式,包括一切。 (我没有研究过你的代码来详细看看到底是什么form代表。)

当然,你不需要在调用指定decreasing,所以:

sort(ToothGrowth, formula = ~ len + dose) 

会如何使用上述规格调用函数。否则,如果您不希望sort.data.frame成为S3通用类型,请将其称为其他类型,然后您可以随意获得所需的任何参数。

+0

通过部分匹配,编写'sort(ToothGrowth,f =〜len + dose)'就不那么糟糕了,所以我就这样做了,并保持了它的S3性。感谢您的建议。 –

+1

我们不应该定义一个'sort.data.frame.formula',它将公式作为第一个参数,如果它失败了'Use.method'中的公式测试,然后将调度到sort.data.frame,第一个数据参数? (与'aggregate。*'相同) –

+0

@DWin你的意思是'sort.formula',是吗? –

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 
+1

我想*公式的参数是第二,但我不确定我可以这样做,仍然是一个S3类。我根本不想减少,因为这个公式带有负面的论据,这意味着减少。 –

+0

@ gsk3,'sort.int'只有'decrease = ...'作为第四个参数,所以我的猜测是你可以有'formula = ...'作为第二个参数。我怀疑你也可以使用'decrease = NULL'并忽略你的代码中的这个参数(与'sort.int'在'partial = TRUE'时忽略'递减'的方式一样)。 PS。所有这些都可以在'sort'中找到。 – Andrie

+0

@Andrie,即使您翻转订单,因为'在递归函数中名为第二个“,它会抓取位置参数。所以,不幸的是,这并没有帮助。 –

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) 
    } 
} 
+1

我很喜欢这种方法,但它被认为是“适当的”?我担心的是我会用自己的,功能相似的替代方法在不同的包中重写'sort'。 –

6

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

而且desc只是一个普通的功能:

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

如果您正在编写这种功能,强烈建议您阅读xtfrm的帮助。

+2

谢谢。这似乎有望成为我的替代品。但是我仍然很好奇如何去做一个通用的方法,并且它的方法是一致的,因为它对我来说经常出现。而且,在语法上,sort()方法似乎可以使事物与其他数据类型保持一致。但是,这是一些漂亮的代码:-) –

+1

'?arrange'表示:“#注意:plyr函数不保留row.names”。如果想保留'row.names',这使得这个优秀的函数不是最理想的。为什么不添加'keep.row.names = FALSE'选项? – landroni

+0

@landroni,因为我不认为他们是一个好主意 - 这是更好地将其添加为一个明确的变量。 – hadley