【发布时间】:2022-01-20 22:46:27
【问题描述】:
我正在创建一个函数来对 data.frames 进行排序(为什么?因为原因)。一些标准:
- 适用于 data.frames
- 针对非交互式使用
- 仅使用基础 R
- 不依赖任何非基础包
函数现在看起来像这样:
#' @title Sort a data.frame
#' @description Sort a data.frame based on one or more columns
#' @param x A data.frame class object
#' @param by A column in the data.frame. Defaults to NULL, which sorts by all columns.
#' @param decreasing A logical indicating the direction of sorting.
#' @return A data.frame.
#'
sortdf <- function(x,by=NULL,decreasing=FALSE) {
if(!is.data.frame(x)) stop("Input is not a data.frame.")
if(is.null(by)) {
ord <- do.call(order,x)
} else {
if(any(!by %in% colnames(x))) stop("One or more items in 'by' was not found.")
if(length(by) == 1) ord <- order(x[ , by])
if(length(by) > 1) ord <- do.call(order, x[ , by])
}
if(decreasing) ord <- rev(ord)
return(x[ord, , drop=FALSE])
}
例子
sortdf(iris)
sortdf(iris,"Petal.Length")
sortdf(iris,"Petal.Length",decreasing=TRUE)
sortdf(iris,c("Petal.Length","Sepal.Length"))
sortdf(iris,"Petal.Length",decreasing=TRUE)
目前有什么效果
- 按一列或多列对 data.frame 进行排序
- 调整整体排序方向
但是,我还需要一个功能:通过传递 by 中指定的每一列的方向向量,分别为每一列设置排序方向的能力。例如;
sortdf(iris,by=c("Sepal.Width","Petal.Width"),dir=c("up","down"))
关于如何实现这一点的任何想法/建议?
更新
以下答案的基准:
library(microbenchmark)
library(ggplot2)
m <- microbenchmark::microbenchmark(
"base 1u"=iris[order(iris$Petal.Length),],
"Maël 1u"=sortdf(iris,"Petal.Length"),
"Mikko 1u"=sortdf1(iris,"Petal.Length"),
"arrange 1u"=dplyr::arrange(iris,Petal.Length),
"base 1d"=iris[order(iris$Petal.Length,decreasing=TRUE),],
"Maël 1d"=sortdf(iris,"Petal.Length",dir="down"),
"Mikko 1d"=sortdf1(iris,"Petal.Length",decreasing=T),
"arrange 1d"=dplyr::arrange(iris,-Petal.Length),
"base 2d"=iris[order(iris$Petal.Length,iris$Sepal.Length,decreasing=TRUE),],
"Maël 2d"=sortdf(iris,c("Petal.Length","Sepal.Length"),dir=c("down","down")),
"Mikko 2d"=sortdf1(iris,c("Petal.Length","Sepal.Length"),decreasing=T),
"arrange 2d"=dplyr::arrange(iris,-Petal.Length,-Sepal.Length),
"base 1u1d"=iris[order(iris$Petal.Length,rev(iris$Sepal.Length)),],
"Maël 1u1d"=sortdf(iris,c("Petal.Length","Sepal.Length"),dir=c("up","down")),
"Mikko 1u1d"=sortdf1(iris,c("Petal.Length","Sepal.Length"),decreasing=c(T,F)),
"arrange 1u1d"=dplyr::arrange(iris,Petal.Length,-Sepal.Length),
times=1000
)
autoplot(m)+theme_bw()
R 4.1.0
dplyr 1.0.7
【问题讨论】:
-
dir与decreasing的区别仅在于它可以从不同的列中以不同的方式指定吗? -
我会使用 forloop。
-
@Maël 我想我们可以摆脱
decreasing一次dir工作。如果未指定任何列,则dir可以默认为rep("up",ncol(x))。也许dir不是最好的名字,听起来有点像目录。 -
你可以看看rgr package的
gx.sort.df函数。我喜欢它的语法,带有公式:gx.sort.df(dat, ~ colA + colB)。并且使用-而不是+它按降序排序 -
@Greg 正如我所提到的,这种特殊情况是用于非交互式使用(即;在其他函数中使用它),所以
desc()可能不会工作得那么好。但是,对于交互式使用,dplyr::arrange()可能是最好的选择,我完全同意你的观点,如果有一个类似的基本 R 等效项会很好。
标签: r