2011-06-05 270 views
61

我有一个数据集,看起来像这样:将年份和月份(“yyyy-mm”格式)转换为日期?

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 

我要绘制的数据(个月x值和计为y值)。由于数据中存在空白,我想将本月的信息转换为日期。我试过:

as.Date("2009-03", "%Y-%m") 

但它没有奏效。怎么了?看起来as.Date()也需要一天,并且无法为当天设置标准值?哪个功能解决了我的问题?

回答

40

试试这个。 (这里我们使用text=Lines保持示例自包含,但在现实中,我们将与文件名替换它。)

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) 

X轴是与这个数据很漂亮,但如果你在现实中的数据越多可能没问题,或者您可以使用?plot.zoo示例部分中显示的花式X轴代码。

动物园系列,z,即上面创建具有"yearmon"时间指数,看起来像这样:

> 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"可以单独使用,也:

> as.yearmon("2000-03") 
[1] "Mar 2000" 

注:

  1. "yearmon"类对象按日历顺序排序。

  2. 这将绘出等间隔的月点,这可能是想要的;然而,如果希望以不同的间隔时间间隔绘制点,则间距与每月的天数成比例,然后将z的索引转换为"Date"类:time(z) <- as.Date(time(z))

50

由于日期与数值和开始日期相对应,所以确实需要一天。如果你真的需要你的数据在日期格式,你可以解决白天到每个月的第一天通过手动将其粘贴到日期:

month <- "2009-03" 
as.Date(paste(month,"-01",sep="")) 
+0

日期还有其他什么格式?我看到了POSIX和ISO的东西,但我不确定这些是不同的格式。我认为这些只是功能,... – 2011-06-05 12:57:51

+14

值得注意的是,你可以指定一天在格式化程序中相同,所以你可以做'as.Date(month,format ='%Y-%m-01') '并取得相同的结果。这种“感觉”比我更喜欢,因为指定每个月的同一日期更多地是日期和字符串操作的格式,但也许这是无稽之谈。 – JBecker 2013-05-24 16:57:56

+7

@JBecker你的建议对我不起作用。 '> as.Date(“2016-01”,format =“%Y-%m-01”) #[1] NA'。 我正在使用R 3.3.1 – n8sty 2017-01-20 20:43:57

21

,如果你需要的日期是在日期格式最简洁的解决方案:

library(zoo) 
month <- "2000-03" 
as.Date(as.yearmon(month)) 
[1] "2000-03-01" 

as.Date将每个月的第一天定为你一个yearmon对象。

2

事实上,正如上面已经提到的(以及SO中的其他地方),为了将字符串转换为日期,您需要特定的月份日期。从as.Date()使用手册页面:

如果日期字符串没有完全指定日期,则返回的答案可能是系统特定的。最常见的行为是假设失去的一年,一月或一天是当前的一个。如果它错误地指定了日期,那么可靠的实现会给出错误,并且日期被报告为NA。不幸的是,一些常见的实现(如glibc)是不可靠的,并猜测其意图。

一个简单的解决方案是将日期"01"粘贴到每个日期并使用strptime()来表明它是该月的第一天。


对于那些寻求加工日期和时间多一点背景R:

在R,次使用POSIXctPOSIXlt类和日期使用Date类。

日期存储为自1970年以来和时间1月1日,被存储为自1月1日的秒数的天数,1970年

因此,举例来说:

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 

要执行

plt - as.POSIXlt(d) 
# Time difference of 16420.61 days 

,并处理日期,您可以使用strptime()(从手册页借用这些例子):关于日期和时间的操作

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" 
-1

我认为@ ben-rollert的解决方案是一个很好的解决方案。

如果您想在新软件包中的函数中使用此解决方案,您只需要小心。

开发包时,建议使用语法packagename::function_name()(请参阅http://kbroman.org/pkg_primer/pages/depends.html)。

在这种情况下,您必须使用由zoo库定义的as.Date()版本。

下面是一个例子:

> 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" 

所以,如果你是深化发展一个包,好做法是使用:

zoo::as.Date(zoo::as.yearmon("1989-10", "%Y-%m")) 
3

使用anytime包:

library(anytime) 

anydate("2009-01") 
# [1] "2009-01-01" 
+0

这有点奇怪,它选择了“01-01”,关于选择的文档中是否有任何内容?如果它总是选择每月的第一天,也许更具说明性,以显示“anydate(”2009-03“)”。 – lmo 2017-09-01 18:01:35

+0

@lmo没有检查文档,我认为这是“常见”的做法,当dd缺少选择第一天。 – zx8754 2017-09-01 18:47:17

+2

这很有道理。我隐约记得,然后发现是什么引发了评论。从'?strptime'的Note部分:*输入字符串不需要完全指定日期:假定未指定的秒,分钟或小时为零,并且未指定的年,月或日是当前日期。 (但是,如果指定了一个月份,则该月份的日期必须由%d或%e指定,因为该月份的当前日期不需要在指定的月份有效。)*看起来像威震天的答案包含类似来自'as.Date'的一段文档。 – lmo 2017-09-01 18:52:37

4

您也可以通过parse_date_timefast_strptime函数来实现此目的从lubridate -package NS:

> 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" 

这两个之间的区别在于,parse_date_time允许lubridate风格的格式规范,而fast_strptime需要相同的格式规范作为strptime

用于指定时区,你可以使用tz -parameter:

> parse_date_time(dates1, "ym", tz = "CET") 
[1] "2009-01-01 CET" "2009-02-01 CET" "2009-03-01 CET" 

当你在你的日期时间数据的不规则性,可以使用truncated -parameter指定多少违规行为被允许:

> 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" 

使用的数据

dates1 <- c("2009-01","2009-02","2009-03") 
dates2 <- c("2012-06-01 12:23","2012-06-01 12",'2012-06-01") 
相关问题