将年月(“ yyyy-mm”格式)转换为日期?


91

我有一个看起来像这样的数据集:

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()也需要一天,并且无法为该天设置标准值吗?哪个功能可以解决我的问题?

Answers:


57

试试这个。(在这里,我们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轴的数据并不是很漂亮,但是如果您实际上有更多的数据可能没关系,或者您可以使用代码来制作X轴的示例部分所示的花式X轴?plot.zoo

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"class time(z) <- as.Date(time(z))


76

由于日期与数字值和开始日期相对应,因此您确实需要一天。如果您确实需要将数据设置为日期格式,则可以通过将日期粘贴到日期来手动将日期固定为每个月的第一天:

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

日期还有哪些其他格式?我看到了POSIX和ISO的内容,但是不确定这些格式是否不同。我以为那只是函数,...
R_User 2011年

19
值得一提的是,您可以在格式化程序中将日期指定为相同的日期,因此可以as.Date(month, format='%Y-%m-01')实现相同的结果。我觉得这种“感觉”更好,因为在每个月中指定相同的日期比字符串操作更多地涉及日期的格式,但这也许是胡说八道。
JBecker 2013年

21
@JBecker您的建议对我不起作用。> as.Date("2016-01", format="%Y-%m-01") # [1] NA。我正在使用R 3.3.1
n8sty

26

最简洁的解决方案,如果您需要将日期设置为日期格式:

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

as.Date 将为您修复每个月的第一天为yearmon对象。


23

您也可以使用-package中的parse_date_timeor fast_strptime函数来实现lubridate

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

具有转换后的字符变量来格式化date使用parse_date_time,是有办法在不同的顺序,以查看它"2009-01-01 UTC"使用lubridate包?我希望首先在数据集中查看这一天,例如01-01-2009
user63230

1
@ user63230请参见?format;例如:format(your_date, "%d-%m-%Y")。但是,这样做有一个缺点:您将获得字符值而不是日期。
哈普

谢谢,但是format由于您提到的原因,我试图避免这种情况,我认为可能有一种将其合并到lubridate软件包中的方法,但似乎没有。
user63230 '19

12

使用随时打包:

library(anytime)

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

选择“ 01-01”有点奇怪,文档中是否有关于该选择的内容?也许更具说明性,以显示anydate("2009-03")它是否始终选择每月的第一天。
lmo

@lmo没有检查文档,我会说这是dd缺少选择第一天的“惯例”做法。
zx8754

2
这就说得通了。隐约记得了我,然后发现了引起评论的原因。在的“注释”部分中?strptime输入字符串不必完全指定日期:假定未指定的秒,分钟或小时为零,而未指定的年,月或日为当前时间。(但是,如果指定了一个月,则必须由%d或%e指定该月的日期,因为该月的当前日期对于指定的月份不必是有效的。)看来megatron的答案包含类似的内容来自的文档as.Date
lmo

在1900年之前的几年中,它不起作用。例如,我尝试了此操作anytime('1870-01')
msh855 '19

5

实际上,正如上面(以及SO的其他地方)所提到的那样,为了将字符串转换为日期,您需要一个月的特定日期。从as.Date()手册页:

如果日期字符串未完全指定日期,则返回的答案可能是系统特定的。最常见的行为是假设缺少的年份,月份或日期是当前年份。如果错误地指定了日期,则可靠的实现将给出错误,并且日期将报告为NA。不幸的是,一些常见的实现(例如glibc)不可靠,无法猜测预期的含义。

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


对于那些希望在R中处理日期和时间有更多背景的人:

在R中,时间使用POSIXctPOSIXlt类别和日期使用Date类别。

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

因此,例如:

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

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

这是一个例子:

> 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"))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.