22

I have a data frame DF with one of the columns being date/Time and I would like to order the data frame in descending order of this column.

DF <- data.frame(ID=c('ID3', 'ID2','ID1'), end=c('4/1/10 12:00', '6/1/11 14:20', '1/1/09 11:10'), age=c(40,30,20));

I first converted the end column into et using et = as.POSIXct(DF$end,format='%m/%d/%Y %H:%M'), and used the following, but got the error that unary operator '-' is not accepted for the argument :

out <- DF[order(-DF$et),];

I also tried used the descending flag but again got an error about arguments not being of same length.

out <- DF[order(DF$et, descending=TRUE),];

However, the ascending order seems to work: out <- DF[order(DF$et),].

How can I order in descending order (most recent time first)? Thank you.

Fabio
  • 23,183
  • 12
  • 55
  • 64
user2327621
  • 957
  • 3
  • 11
  • 15
  • 1
    There is no argument called `descending`. It's `decreasing`. – Simon O'Hanlon May 05 '13 at 21:33
  • 1
    Since you are new here you might want to read [**the about**](http://stackoverflow.com/about) and the [**faq**](http://stackoverflow.com/faq) about how SO works. StackOverflow is made **much** more valuable to everyone if when you receive an answer that solves your problem, you accept it by clicking the little check mark. You are under absolutely **no** obligation to do so, but it is a great way to "give back" to the site if an answer did in fact solve your problem and helps to keep the site clean by removing answered question from the unanswered questions stack. – Simon O'Hanlon May 06 '13 at 12:02

3 Answers3

18

There is an easy and general solution for your issue with few code.

As you have noticed, the minus sign doesn't work with Dates because negative dates don't yet exist!

However you can have the same effect with a general purpose function: rev(). Therefore, you mix rev and order like:

#init data
DF <- data.frame(ID=c('ID3', 'ID2','ID1'), end=c('4/1/10 12:00', '6/1/11 14:20', '1/1/09 11:10')
#change order
out <- DF[rev(order(as.Date(DF$end))),]

When you use the minus sign with numbers you are classing negative numbers in one pass. I think that when you use rev() function, you are doing two passes, one to sort in ascending order and one for reversing the order. But on 3 observations, it's hard to see.

Hope it helped.

pommedeterresautee
  • 1,843
  • 1
  • 20
  • 24
11

I think this will work:

## Slightly bigger dataset with two times on same day:
DF <- data.frame(ID=c('ID3', 'ID2','ID1','ID4'), end=c('4/1/10 12:00', '6/1/11 14:20', '1/1/09 11:10' , '1/1/09 13:11'), age=c(40,30,20,20));

## Note to self - ALWAYS include a timezone.
DF$DTime <- as.POSIXct( DF$end , format = "%d/%m/%y %H:%M" , tz = "GMT")
DF[ order(DF$DTime , decreasing = TRUE ),]
#   ID          end age               DTime
#2 ID2 6/1/11 14:20  30 2011-01-06 14:20:00
#1 ID3 4/1/10 12:00  40 2010-01-04 12:00:00
#4 ID4 1/1/09 13:11  20 2009-01-01 13:11:00
#3 ID1 1/1/09 11:10  20 2009-01-01 11:10:00
Simon O'Hanlon
  • 58,647
  • 14
  • 142
  • 184
1

Using dplyr and lubridate -

library(dplyr)
library(lubridate)

DF %>% mutate(end = dmy_hm(end)) %>% arrange(desc(end))

#   ID                 end age
#1 ID2 2011-01-06 14:20:00  30
#2 ID3 2010-01-04 12:00:00  40
#3 ID1 2009-01-01 11:10:00  20

If you don't want to the change the format of end column.

DF %>% arrange(desc(dmy_hm(end)))

#   ID          end age
#1 ID2 6/1/11 14:20  30
#2 ID3 4/1/10 12:00  40
#3 ID1 1/1/09 11:10  20
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213