class generics r methods

class - ¿La mejor forma de crear una coherencia genérica/de método para sort.data.frame?



generics methods (4)

¿Puedes enmascarar la definición básica de sort , es decir, algo como esto?

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

Finalmente he decidido poner el método sort.data.frame que está flotando en Internet en un paquete R. Simplemente se solicita demasiado como para dejarlo en un método ad hoc de distribución.

Sin embargo, está escrito con argumentos que lo hacen incompatible con la función de ordenación genérica:

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

Si cambio sort.data.frame para que tome la disminución como un argumento como en sort.data.frame(form,decreasing,dat) y descarte disminuyendo, entonces pierde su simplicidad porque siempre tendrá que especificar dat= y can '' Realmente uso argumentos posicionales. Si lo agrego al final como en sort.data.frame(form,dat,decreasing) , entonces el orden no coincide con la función genérica. Si espero que la disminución quede atrapada en los puntos `sort.data.frame (form, dat, ...), entonces cuando use la coincidencia basada en posición, creo que la función genérica asignará la segunda posición a la disminución y se obtendrá descartado. ¿Cuál es la mejor manera de armonizar estas dos funciones?

La función completa es:

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

Ejemplo:

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


Estoy de acuerdo con @Gavin en que x debe ser lo primero. Sin embargo, pondría el parámetro decreasing después de la formula , ya que probablemente no se use tanto y casi nunca como argumento posicional.

El argumento de formula se usaría mucho más y, por lo tanto, debería ser el segundo argumento. También estoy totalmente de acuerdo con @Gavin en que debería llamarse formula , y no form .

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

Es posible que desee extender el argumento decreasing para permitir un vector lógico donde cada valor VERDADERO / FALSO corresponde a una columna en la fórmula:

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


Hay algunos problemas allí. sort.data.frame necesita tener los mismos argumentos que el genérico, por lo que, como mínimo, debe ser

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

Para que el despacho funcione, el primer argumento debe ser el objeto enviado. Entonces comenzaría con:

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

donde x es su dat , la formula es su form , y proporcionamos un valor predeterminado para la fórmula para incluir todo. (No he estudiado su código en detalle para ver exactamente qué form representa).

Por supuesto, no necesita especificar la decreasing en la llamada, entonces:

sort(ToothGrowth, formula = ~ len + dose)

sería cómo llamar a la función utilizando las especificaciones anteriores.

De lo contrario, si no desea que sort.data.frame sea ​​un S3 genérico, sort.data.frame de otra forma y podrá tener los argumentos que desee.


Use la función de arrange en plyr . Le permite elegir individualmente qué variables deben estar en orden ascendente y descendente:

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

También tiene una implementación elegante:

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

Y desc es solo una función ordinaria:

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

Leer la ayuda para xtfrm es muy recomendable si está escribiendo este tipo de función.