กำลังแปลงปีและเดือน (รูปแบบ“ ปปปป - มม”) เป็นวันที่หรือไม่


93

ฉันมีชุดข้อมูลที่มีลักษณะดังนี้:

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

แต่มันไม่ได้ผล มีอะไรผิดปกติ ดูเหมือนว่าวันที่ () ต้องการวันด้วยและไม่สามารถกำหนดค่ามาตรฐานสำหรับวันได้ ฟังก์ชันใดที่ช่วยแก้ปัญหาของฉันได้

คำตอบ:


59

ลองทำตามนี้ (ที่นี่เราใช้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 แฟนซีที่แสดงในส่วนตัวอย่างของ?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" time(z) <- as.Date(time(z))


77

เนื่องจากวันที่ตรงกับค่าตัวเลขและวันที่เริ่มต้นคุณจึงต้องการวัน หากคุณต้องการให้ข้อมูลอยู่ในรูปแบบวันที่จริงๆคุณสามารถแก้ไขวันที่เป็นวันแรกของแต่ละเดือนด้วยตนเองได้โดยวางลงในวันที่:

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

รูปแบบอื่น ๆ สำหรับวันที่มีอะไรบ้าง? ฉันเห็นบางอย่างกับ POSIX และบางอย่างที่มี ISO แต่ฉันไม่แน่ใจว่าเป็นรูปแบบอื่นหรือไม่ ฉันคิดว่ามันเป็นแค่ฟังก์ชั่น ...
R_User

19
ควรสังเกตว่าคุณสามารถระบุวันที่เหมือนกันได้ในฟอร์แมตเตอร์ดังนั้นคุณจึงสามารถทำได้as.Date(month, format='%Y-%m-01')และบรรลุผลลัพธ์เดียวกัน "ความรู้สึก" นี้เป็นที่นิยมสำหรับฉันเนื่องจากการระบุวันที่เดียวกันในแต่ละเดือนเป็นเรื่องเกี่ยวกับรูปแบบของวันที่จากนั้นการปรับแต่งสตริง แต่อาจเป็นเรื่องไร้สาระ
JBecker

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 จะแก้ไขวันแรกของแต่ละเดือนเป็นปีเดือนวัตถุให้คุณ


24

นอกจากนี้คุณยังสามารถบรรลุสิ่งนี้ด้วยparse_date_timeหรือfast_strptimeฟังก์ชั่นจาก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"

ความแตกต่างระหว่างสองสิ่งนี้คือ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พารามิเตอร์เพื่อระบุจำนวนความผิดปกติที่อนุญาต:

> 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"). มีข้อเสียสำหรับสิ่งนี้: คุณจะได้รับค่าอักขระกลับมาไม่ใช่วันที่
Jaap

ขอบคุณ แต่ฉันพยายามหลีกเลี่ยงformatด้วยเหตุผลที่คุณพูดถึงฉันคิดว่าอาจมีวิธีรวมสิ่งนี้ไว้ในlubridateแพ็คเกจ แต่ดูเหมือนจะไม่มี
user63230

12

ใช้แพ็คเกจได้ตลอดเวลา :

library(anytime)

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

แปลกนิดหน่อยที่มันเลือก "01-01" มีเอกสารอะไรเกี่ยวกับตัวเลือกนี้ไหม อาจเป็นตัวอย่างที่แสดงให้เห็นanydate("2009-03")ว่าเลือกวันแรกของเดือนเสมอหรือไม่
lmo

@lmo ไม่ได้ตรวจสอบเอกสารฉันจะบอกว่านี่เป็นวิธีปฏิบัติ "ทั่วไป" เมื่อ dd ไม่มีให้เลือกวันที่ 1
zx8754

2
ที่สมเหตุสมผล ฉันจำได้ไม่ชัดจากนั้นก็พบว่าอะไรเป็นตัวกระตุ้นความคิดเห็น จากส่วนหมายเหตุของ?strptime: สตริงอินพุตไม่จำเป็นต้องระบุวันที่อย่างสมบูรณ์โดยถือว่าวินาทีนาทีหรือชั่วโมงที่ไม่ได้ระบุเป็นศูนย์และปีเดือนหรือวันที่ไม่ระบุคือวันที่ปัจจุบัน (อย่างไรก็ตามหากระบุเดือนวันของเดือนนั้นจะต้องระบุด้วย% d หรือ% e เนื่องจากวันปัจจุบันของเดือนไม่จำเป็นต้องใช้ได้กับเดือนที่ระบุ)ดูเหมือนว่าคำตอบของ megatron จะมีชิ้นส่วนที่คล้ายกัน ของเอกสารจากas.Date.
lmo

สำหรับปีก่อนปี 1900 ไม่ได้ผล ตัวอย่างเช่นฉันลองสิ่งนี้anytime('1870-01')
msh855

5

ตามที่ได้กล่าวไว้ข้างต้น (และที่อื่น ๆ ใน SO) ในการแปลงสตริงเป็นวันที่คุณต้องระบุวันที่เฉพาะของเดือน จากas.Date()หน้าคู่มือ:

หากสตริงวันที่ไม่ระบุวันที่อย่างสมบูรณ์คำตอบที่ส่งคืนอาจเป็นเฉพาะระบบ พฤติกรรมที่พบบ่อยที่สุดคือการสมมติว่าปีเดือนหรือวันที่หายไปเป็นวันปัจจุบัน หากระบุวันที่ไม่ถูกต้องการใช้งานที่เชื่อถือได้จะทำให้เกิดข้อผิดพลาดและวันที่จะรายงานเป็น NA น่าเสียดายที่การใช้งานทั่วไปบางอย่าง (เช่นglibc) ไม่น่าเชื่อถือและคาดเดาความหมายที่ตั้งใจไว้

วิธีง่ายๆคือการวางวันที่"01"ในแต่ละวันและใช้strptime()เพื่อระบุว่าเป็นวันแรกของเดือนนั้น


สำหรับผู้ที่ต้องการข้อมูลเพิ่มเติมเล็กน้อยเกี่ยวกับการประมวลผลวันที่และเวลาใน R:

ใน R ใช้เวลาPOSIXctและPOSIXltชั้นเรียนและวันที่ใช้Dateชั้นเรียน

วันที่จะถูกจัดเก็บเป็นจำนวนวันตั้งแต่วันที่ 1 มกราคม 1970 และเวลาจะถูกจัดเก็บเป็นจำนวนวินาทีตั้งแต่วันที่ 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 )

ในกรณีนี้คุณต้องใช้เวอร์ชันของ 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"))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.