2011-07-26 10 views
8

W końcu zdecydowałem się umieścić metodę sort.data.frame, która pływa w Internecie w pakiecie R. Za bardzo żąda się, aby zostawić ją na ad hoc.Najlepszy sposób tworzenia spójności ogólnej/metody dla sort.data.frame?

Jednak on napisany z argumentami, które sprawiają, że jest niezgodna z ogólną funkcję sortowania:

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

jeśli zmienię sort.data.frame wziąć maleje jako argument jak w sort.data.frame(form,decreasing,dat) i wyrzucić maleje, wówczas traci swoją prostotą, ponieważ zawsze będziesz musiał podać dat= i nie możesz naprawdę używać argumentów pozycyjnych. Jeśli dodaję go do końca, jak w przypadku sort.data.frame(form,dat,decreasing), kolejność nie jest zgodna z funkcją ogólną. Jeśli mam nadzieję, że zmniejszenie zostanie uwikłane w kropki `sort.data.frame (forma, dat, ...), to podczas używania dopasowania opartego na pozycji uważam, że funkcja ogólna przypisuje drugiemu położeniu obniżenie i otrzyma odrzucona. Jaki jest najlepszy sposób na zharmonizowanie tych dwóch funkcji?

Pełne funkcja:

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

przykład:

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

Funkcja 'arran' w pakiecie' plyr' może być przedmiotem zainteresowania. – joran

+0

To jest. Niestety nie wygląda na to, że obsługuje sortowanie negatywne (do tyłu), więc ta funkcja wciąż wydaje się przydatna. –

+0

Jestem dość pewny, że 'zorganizuj' obsługuje typy negatywne:' aranżuj (ToothGrowth, desc (dose), len) '. – joran

Odpowiedz

4

Istnieje kilka problemów istnieją. sort.data.frame musi mieć te same argumenty co rodzajową, więc przynajmniej to musi być

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

mieć pracę wysyłki, pierwszy argument musi być przedmiotem wysyłane dalej. Więc chciałbym zacząć:

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

gdzie x jest twój dat, formula jest twój form i zapewniamy domyślne formuła obejmuje wszystko. (I nie badali szczegółowo swój kod, aby zobaczyć dokładnie to, co form reprezentuje.)

Oczywiście, nie trzeba określać decreasing w wezwaniu, więc:

sort(ToothGrowth, formula = ~ len + dose) 

byłoby jak wywołaj funkcję przy użyciu powyższych specyfikacji.

W przeciwnym razie, jeśli nie chcesz, aby sort.data.frame był generycznym S3, możesz to nazwać czymś innym, a następnie możesz mieć dowolne argumenty.

+0

Przy częściowym dopasowaniu, nie jest tak źle napisać 'sort (ToothGrowth, f = ~ len + dose)', dlatego to zrobiłem i zachowałem S3ness tego. Dzieki za sugestie. –

+1

Nie powinniśmy zdefiniować 'sort.data.frame.formula', który wziąłby formułę jako pierwszy argument, a jeśli to się nie powiedzie, test formuły w' Use.method' będzie następnie wysłany do sort.data.frame, który zajmuje pierwszy argument danych? (Tak samo, jak w przypadku 'aggregate. *') –

+0

@DWin Masz na myśli 'sort.formula', yes? –

0

Zgadzam się z @Gavin, że x musi być na pierwszym miejscu. Dodałbym jednak parametr decreasing po formula - ponieważ prawdopodobnie nie jest używany tak często, a rzadko jako argument pozycyjny.

Argument formula zostanie użyty znacznie więcej i dlatego powinien być drugim argumentem. Również mocno zgadzam się z @Gavin, że powinien on być nazwany formula, a nie form.

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

Możesz chcieć przedłużyć decreasing argumentu, aby umożliwić logiczny wektor gdzie każdy PRAWDA/wartość FAŁSZ odpowiada jednej kolumnie w formule:

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

Chciałbym * lubię * argument formuły być drugi, ale nie jestem pewien, czy mogę mieć to w ten sposób i nadal mam klasę S3. Nie chciałbym w ogóle "zmniejszać", ponieważ formuła przyjmuje negatywne argumenty, co implikuje zmniejszenie. –

+0

@ gsk3, 'sort.int' ma' malejący = ... 'tylko jako czwarty parametr, więc zgaduję, że możesz mieć' formułę = ... 'jako drugą. Podejrzewam, że możesz również użyć 'malejącej = NULL' i zignorować ten parametr w swoim kodzie (w ten sam sposób, w jaki' sort.int' ignoruje 'malejące' gdy 'partial = TRUE'). PS. Wszystko to można znaleźć w '? Sort'. – Andrie

+0

@Andrie, nawet jeśli zmienisz kolejność, ponieważ 'malejący' jest nazywany drugim w funkcji ogólnej, pobiera argument pozycyjny. Więc to nie pomaga, niestety. –

2

można po prostu maskować definicji podstawy sort , czyli coś takiego?

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

Jestem zaintrygowany tym podejściem, ale czy jest ono uważane za "właściwe"? Obawiam się, że nadpisuję "sort" w innym pakiecie z moją własną, funkcjonalnie podobną alternatywą. –

6

Użyj funkcji arrange w plyr. To pozwala indywidualnie wybrać, które zmienne powinny być w kolejności rosnącej i malejącej:

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

Posiada również elegancką realizacji:

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

I desc jest tylko zwykłym funkcja:

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

Zaleca się czytanie pomocy dla xtfrm, jeśli piszesz tego rodzaju funkcję.

+2

Dzięki. To wydaje się być zamiennikiem. Ale nadal jestem ciekawy, jak można by było zrobić rodzajowy i jego metody spójne, ponieważ pojawia się dość często dla mnie. Również syntaktycznie wydaje się, że metoda sort() zachowuje zgodność z innymi typami danych. Ale to ładny kod :-) –

+1

'? Aranżacja' oznacza, że:" # UWAGA: funkcje plyr NIE przechowują row.names ". To sprawia, że ​​ta doskonała funkcja jest nieoptymalna, jeśli chce się zachować 'row.names'. Dlaczego nie dodać opcji 'keep.row.names = FALSE'? – landroni

+0

@landroni, ponieważ nie sądzę, że są dobrym pomysłem - lepiej dodać je jako zmienną jawną. – hadley

Powiązane problemy