2011-06-05 293 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") 
相關問題