type - r s3 class




La meilleure façon de créer une cohérence générique/méthode pour sort.data.frame? (3)

J'ai finalement décidé de mettre la méthode sort.data.frame qui circule sur Internet dans un paquet R. On demande juste trop à laisser à une méthode de distribution ad hoc.

Cependant, il est écrit avec des arguments qui le rendent incompatible avec la fonction de tri générique:

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

Si je change sort.data.frame pour prendre décroissant en argument comme sort.data.frame(form,decreasing,dat) et rejette décroissant, alors il perd sa simplicité car il faudra toujours spécifier dat= et can ' t utilise vraiment des arguments positionnels. Si je l'ajoute à la fin comme dans sort.data.frame(form,dat,decreasing) , alors l'ordre ne correspond pas à la fonction générique. Si j'espère que décroissant sera pris dans les points `sort.data.frame (form, dat, ...), alors en utilisant la correspondance basée sur la position, je crois que la fonction générique assignera la seconde position à décroissante et elle obtiendra mis au rebut. Quelle est la meilleure façon d'harmoniser ces deux fonctions?

La fonction complète est:

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

Exemple:

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

Pouvez-vous juste masquer la définition de base de sort , c'est à dire quelque chose comme ça?

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

Il y a quelques problèmes là-bas. sort.data.frame doit avoir les mêmes arguments que le générique, donc au minimum il doit être

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

Pour que le dispatch fonctionne, le premier argument doit être l'objet envoyé. Donc je commencerais par:

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

x est votre dat , la formula est votre form , et nous fournissons par défaut à la formule d'inclure tout. (Je n'ai pas étudié votre code en détail pour voir exactement quelle form représente.)

Bien sûr, vous n'avez pas besoin de spécifier decreasing dans l'appel, donc:

sort(ToothGrowth, formula = ~ len + dose)

serait comment appeler la fonction en utilisant les spécifications ci-dessus.

Sinon, si vous ne voulez pas que sort.data.frame soit un générique S3, appelez-le quelque chose d'autre et vous êtes libre d'avoir les arguments que vous voulez.


Utilisez la fonction d' arrange dans plyr . Il vous permet de choisir individuellement quelles variables doivent être dans l'ordre croissant et décroissant:

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

Il a également une implémentation élégante:

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

Et desc est juste une fonction ordinaire:

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

La lecture de l'aide pour xtfrm est fortement recommandée si vous écrivez ce genre de fonction.





methods