I have a dataset that looks like this:
Month count
2009-01 12
2009-02 310
2009-03 2379
2009-04 234
2009-05 14
2009-08 1
2009-09 34
2009-10 2386
Try this. (Here we use text=Lines
to keep the example self contained but in reality we would replace it with the file name.)
Lines <- "2009-01 12
2009-02 310
2009-03 2379
2009-04 234
2009-05 14
2009-08 1
2009-09 34
2009-10 2386"
library(zoo)
z <- read.zoo(text = Lines, FUN = as.yearmon)
plot(z)
The X axis is not so pretty with this data but if you have more data in reality it might be ok or you can use the code for a fancy X axis shown in the examples section of ?plot.zoo
.
The zoo series, z
, that is created above has a "yearmon"
time index and looks like this:
> z
Jan 2009 Feb 2009 Mar 2009 Apr 2009 May 2009 Aug 2009 Sep 2009 Oct 2009
12 310 2379 234 14 1 34 2386
"yearmon"
can be used alone as well:
> as.yearmon("2000-03")
[1] "Mar 2000"
Note:
"yearmon"
class objects sort in calendar order.
This will plot the monthly points at equally spaced intervals which is likely what is wanted; however, if it were desired to plot the points at unequally spaced intervals spaced in proportion to the number of days in each month then convert the index of z
to "Date"
class: time(z) <- as.Date(time(z))
.
Indeed, as has been mentioned above (and elsewhere on SO), in order to convert the string to a date, you need a specific date of the month. From the as.Date()
manual page:
If the date string does not specify the date completely, the returned answer may be system-specific. The most common behaviour is to assume that a missing year, month or day is the current one. If it specifies a date incorrectly, reliable implementations will give an error and the date is reported as NA. Unfortunately some common implementations (such as
glibc
) are unreliable and guess at the intended meaning.
A simple solution would be to paste the date "01"
to each date and use strptime()
to indicate it as the first day of that month.
For those seeking a little more background on processing dates and times in R:
In R, times use POSIXct
and POSIXlt
classes and dates use the Date
class.
Dates are stored as the number of days since January 1st, 1970 and times are stored as the number of seconds since January 1st, 1970.
So, for example:
d <- as.Date("1971-01-01")
unclass(d) # one year after 1970-01-01
# [1] 365
pct <- Sys.time() # in POSIXct
unclass(pct) # number of seconds since 1970-01-01
# [1] 1450276559
plt <- as.POSIXlt(pct)
up <- unclass(plt) # up is now a list containing the components of time
names(up)
# [1] "sec" "min" "hour" "mday" "mon" "year" "wday" "yday" "isdst" "zone"
# [11] "gmtoff"
up$hour
# [1] 9
To perform operations on dates and times:
plt - as.POSIXlt(d)
# Time difference of 16420.61 days
And to process dates, you can use strptime()
(borrowing these examples from the manual page):
strptime("20/2/06 11:16:16.683", "%d/%m/%y %H:%M:%OS")
# [1] "2006-02-20 11:16:16 EST"
# And in vectorized form:
dates <- c("1jan1960", "2jan1960", "31mar1960", "30jul1960")
strptime(dates, "%d%b%Y")
# [1] "1960-01-01 EST" "1960-01-02 EST" "1960-03-31 EST" "1960-07-30 EDT"
I think @ben-rollert's solution is a good solution.
You just have to be careful if you want to use this solution in a function inside a new package.
When developping packages, it's recommended to use the syntaxe packagename::function_name()
(see http://kbroman.org/pkg_primer/pages/depends.html).
In this case, you have to use the version of as.Date()
defined by the zoo
library.
Here is an example :
> devtools::session_info()
Session info ----------------------------------------------------------------------------------------------------------------------------------------------------
setting value
version R version 3.3.1 (2016-06-21)
system x86_64, linux-gnu
ui RStudio (1.0.35)
language (EN)
collate C
tz <NA>
date 2016-11-09
Packages --------------------------------------------------------------------------------------------------------------------------------------------------------
package * version date source
devtools 1.12.0 2016-06-24 CRAN (R 3.3.1)
digest 0.6.10 2016-08-02 CRAN (R 3.2.3)
memoise 1.0.0 2016-01-29 CRAN (R 3.2.3)
withr 1.0.2 2016-06-20 CRAN (R 3.2.3)
> as.Date(zoo::as.yearmon("1989-10", "%Y-%m"))
Error in as.Date.default(zoo::as.yearmon("1989-10", "%Y-%m")) :
do not know how to convert 'zoo::as.yearmon("1989-10", "%Y-%m")' to class “Date”
> zoo::as.Date(zoo::as.yearmon("1989-10", "%Y-%m"))
[1] "1989-10-01"
So if you're developping a package, the good practice is to use :
zoo::as.Date(zoo::as.yearmon("1989-10", "%Y-%m"))
You could also achieve this with the parse_date_time
or fast_strptime
functions from the lubridate
-package:
> parse_date_time(dates1, "ym")
[1] "2009-01-01 UTC" "2009-02-01 UTC" "2009-03-01 UTC"
> fast_strptime(dates1, "%Y-%m")
[1] "2009-01-01 UTC" "2009-02-01 UTC" "2009-03-01 UTC"
The difference between those two is that parse_date_time
allows for lubridate-style format specification, while fast_strptime
requires the same format specification as strptime
.
For specifying the timezone, you can use the tz
-parameter:
> parse_date_time(dates1, "ym", tz = "CET")
[1] "2009-01-01 CET" "2009-02-01 CET" "2009-03-01 CET"
When you have irregularities in your date-time data, you can use the truncated
-parameter to specify how many irregularities are allowed:
> parse_date_time(dates2, "ymdHMS", truncated = 3)
[1] "2012-06-01 12:23:00 UTC" "2012-06-01 12:00:00 UTC" "2012-06-01 00:00:00 UTC"
Used data:
dates1 <- c("2009-01","2009-02","2009-03")
dates2 <- c("2012-06-01 12:23","2012-06-01 12",'2012-06-01")
Using anytime package:
library(anytime)
anydate("2009-01")
# [1] "2009-01-01"
Since dates correspond to a numeric value and a starting date, you indeed need the day. If you really need your data to be in Date format, you can just fix the day to the first of each month manually by pasting it to the date:
month <- "2009-03"
as.Date(paste(month,"-01",sep=""))