Chuyển đổi năm và tháng (định dạng “yyyy-mm”) thành một ngày?


91

Tôi có một tập dữ liệu giống như sau:

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

Tôi muốn vẽ biểu đồ dữ liệu (tháng dưới dạng giá trị x và được tính là giá trị y). Vì có khoảng trống trong dữ liệu, tôi muốn chuyển đổi Thông tin cho Tháng thành một ngày. Tôi đã thử:

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

Nhưng nó đã không hoạt động. Chuyện gì vậy? Có vẻ như as.Date () cũng yêu cầu một ngày và không thể đặt giá trị tiêu chuẩn cho ngày? Chức năng nào giải quyết vấn đề của tôi?

Câu trả lời:


57

Thử đi. (Ở đây chúng tôi sử dụng text=Linesđể giữ cho ví dụ độc lập nhưng trong thực tế, chúng tôi sẽ thay thế nó bằng tên tệp.)

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)

Trục X không quá đẹp với dữ liệu này nhưng nếu bạn có nhiều dữ liệu hơn trong thực tế thì có thể ổn hoặc bạn có thể sử dụng mã cho trục X ưa thích được hiển thị trong phần ví dụ của ?plot.zoo.

Chuỗi sở thú, zđược tạo ở trên có "yearmon"chỉ mục thời gian và trông giống như sau:

> 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" cũng có thể được sử dụng một mình:

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

Ghi chú:

  1. "yearmon" các đối tượng lớp sắp xếp theo thứ tự lịch.

  2. Điều này sẽ vẽ biểu đồ các điểm hàng tháng ở các khoảng cách đều nhau, có khả năng là những gì được mong muốn; Tuy nhiên, nếu nó được mong muốn để vẽ các điểm theo chu kỳ không đều cách nhau cách nhau tương ứng với số ngày trong mỗi tháng sau đó chuyển đổi các chỉ số zđể "Date"lớp: time(z) <- as.Date(time(z)).


76

Vì ngày tháng tương ứng với một giá trị số và ngày bắt đầu, bạn thực sự cần ngày. Nếu bạn thực sự cần dữ liệu của mình ở định dạng Ngày, bạn chỉ có thể sửa ngày thành ngày đầu tiên của mỗi tháng theo cách thủ công bằng cách dán nó vào ngày:

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

Có những định dạng nào khác cho ngày tháng? Tôi đã thấy một cái gì đó với POSIX và một cái gì đó với ISO, nhưng tôi không chắc đó có phải là các định dạng khác nhau hay không. Tôi nghĩ đó chỉ là các chức năng, ...
R_User

19
Cần lưu ý rằng bạn có thể chỉ định ngày giống nhau trong trình định dạng, vì vậy bạn có thể làm as.Date(month, format='%Y-%m-01')và đạt được kết quả tương tự. Điều này "cảm thấy" thích hợp hơn với tôi vì việc chỉ định cùng một ngày trong mỗi tháng thiên về định dạng của ngày sau đó là thao tác chuỗi, nhưng có lẽ điều đó là vô nghĩa.
JBecker

21
@JBecker đề xuất của bạn không phù hợp với tôi. > as.Date("2016-01", format="%Y-%m-01") # [1] NA. Tôi đang sử dụng R 3.3.1
n8sty

26

Giải pháp ngắn gọn nhất nếu bạn cần ngày ở định dạng Ngày:

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

as.Date sẽ cố định ngày đầu tiên của mỗi tháng thành một đối tượng yearmon cho bạn.


23

Bạn cũng có thể đạt được điều này với parse_date_timehoặc các fast_strptimechức năng từ 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"

Sự khác biệt giữa hai điều đó là parse_date_timecho phép đặc tả định dạng kiểu lubridate, trong khi fast_strptimeyêu cầu đặc tả định dạng giống như strptime.

Để chỉ định múi giờ, bạn có thể sử dụng tz-parameter:

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

Khi bạn có bất thường trong dữ liệu ngày giờ của mình, bạn có thể sử dụng truncated-parameter để chỉ định số lượng bất thường được phép:

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

Dữ liệu đã sử dụng:

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

đã chuyển đổi một biến ký tự sang định dạng datebằng cách sử dụng parse_date_time, có cách nào để xem nó theo thứ tự khác với "2009-01-01 UTC"việc sử dụng lubridategói không? Tôi muốn xem ngày đầu tiên trong tập dữ liệu của tôi, ví dụ 01-01-2009.
user63230,

1
@ user63230 Xem ?format; ví dụ: format(your_date, "%d-%m-%Y"). Tuy nhiên, có một bất lợi đối với điều này: bạn sẽ nhận được một giá trị ký tự trở lại chứ không phải ngày tháng.
Jaap

Cảm ơn nhưng tôi đã cố gắng tránh formatvì lý do bạn đề cập, tôi nghĩ có thể có một cách để kết hợp điều này trong lubridategói nhưng dường như không có.
user63230, 31-07-19

12

Sử dụng gói bất cứ lúc nào :

library(anytime)

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

Đó là một chút kỳ lạ khi nó chọn "01-01", có gì trong tài liệu về sự lựa chọn không? Có thể minh họa thêm để hiển thị anydate("2009-03")nếu nó luôn chọn ngày đầu tiên của tháng.
lmo

@lmo đã không kiểm tra tài liệu, tôi muốn nói đây là thông lệ "phổ biến" khi thiếu dd để chọn ngày đầu tiên.
zx8754

2
Điều đó có lý. Tôi mơ hồ nhớ lại và sau đó tìm thấy những gì đã kích hoạt bình luận. Từ phần Ghi chú của ?strptime: chuỗi đầu vào không cần chỉ định ngày hoàn toàn: giả định rằng giây, phút hoặc giờ không xác định bằng 0 và năm, tháng hoặc ngày không xác định là năm hiện tại. (Tuy nhiên, nếu một tháng được chỉ định, thì ngày của tháng đó phải được chỉ định bằng% d hoặc% e vì ngày hiện tại của tháng đó không hợp lệ với tháng được chỉ định.) Có vẻ như câu trả lời của megatron chứa một đoạn tương tự của tài liệu từ as.Date.
lmo

trong những năm trước 1900, nó không hoạt động. Ví dụ: tôi đã thử điều nàyanytime('1870-01')
msh855

5

Thật vậy, như đã được đề cập ở trên (và những nơi khác trên SO), để chuyển đổi chuỗi thành ngày, bạn cần một ngày cụ thể trong tháng. Từ as.Date()trang hướng dẫn sử dụng:

Nếu chuỗi ngày không chỉ định ngày hoàn toàn, câu trả lời được trả về có thể thuộc về hệ thống cụ thể. Hành vi phổ biến nhất là cho rằng một năm, tháng hoặc ngày còn thiếu là năm hiện tại. Nếu nó chỉ định ngày không chính xác, các triển khai đáng tin cậy sẽ xuất hiện lỗi và ngày được báo cáo là NA. Thật không may, một số triển khai phổ biến (chẳng hạn như glibc) không đáng tin cậy và đoán theo ý nghĩa dự định.

Một giải pháp đơn giản sẽ là dán ngày "01"vào mỗi ngày và sử dụng strptime()để chỉ ngày đó là ngày đầu tiên của tháng đó.


Đối với những người tìm kiếm thêm một chút thông tin cơ bản về ngày và giờ xử lý trong R:

Trong R, thời gian sử dụng POSIXctPOSIXltcác lớp và ngày tháng sử dụng Datelớp.

Ngày được lưu trữ dưới dạng số ngày kể từ ngày 1 tháng 1 năm 1970 và thời gian được lưu trữ dưới dạng số giây kể từ ngày 1 tháng 1 năm 1970.

Ví dụ:

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

Để thực hiện các hoạt động vào ngày và giờ:

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

Và để xử lý ngày tháng, bạn có thể sử dụng strptime()(mượn các ví dụ này từ trang hướng dẫn):

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

Tôi nghĩ giải pháp của @ ben-rollert là một giải pháp tốt.

Bạn chỉ cần cẩn thận nếu bạn muốn sử dụng giải pháp này trong một chức năng bên trong một gói mới.

Khi phát triển các gói, bạn nên sử dụng cú pháp packagename::function_name()(xem http://kbroman.org/pkg_primer/pages/depends.html ).

Trong trường hợp này, bạn phải sử dụng phiên bản as.Date()được xác định bởi zoothư viện.

Đây là một ví dụ :

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

Vì vậy, nếu bạn đang phát triển một gói, phương pháp hay là sử dụng:

zoo::as.Date(zoo::as.yearmon("1989-10", "%Y-%m"))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.