Mengonversi tahun dan bulan (format “yyyy-mm”) menjadi tanggal?

91

Saya memiliki kumpulan data yang terlihat seperti ini:

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

Saya ingin memplot data (bulan sebagai nilai x dan dihitung sebagai nilai y). Karena ada celah dalam data, saya ingin mengubah Informasi untuk Bulan ini menjadi tanggal. Saya mencoba:

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

Tapi itu tidak berhasil. Apa yang salah? Tampaknya as.Date () membutuhkan juga hari dan tidak dapat menetapkan nilai standar untuk hari itu? Fungsi mana yang memecahkan masalah saya?

R_User
sumber

Jawaban:

57

Coba ini. (Di sini kami menggunakan text=Linesuntuk menyimpan contoh itu sendiri tetapi pada kenyataannya kami akan menggantinya dengan nama file.)

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)

Sumbu X tidak begitu cantik dengan data ini tetapi jika Anda memiliki lebih banyak data pada kenyataannya itu mungkin baik-baik saja atau Anda dapat menggunakan kode untuk sumbu X mewah yang ditunjukkan pada bagian contoh ?plot.zoo.

Rangkaian kebun binatang z,, yang dibuat di atas memiliki "yearmon"indeks waktu dan terlihat seperti ini:

> 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" bisa digunakan sendiri juga:

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

catatan:

  1. "yearmon" objek kelas mengurutkan dalam urutan kalender.

  2. Ini akan memplot poin bulanan pada interval jarak yang sama yang mungkin diinginkan; Namun, jika hal itu diinginkan untuk merencanakan poin pada interval merata spasi spasi secara proporsional dengan jumlah hari dalam setiap bulan kemudian mengubah indeks dari zke "Date"kelas: time(z) <- as.Date(time(z)).

G. Grothendieck
sumber
76

Karena tanggal sesuai dengan nilai numerik dan tanggal mulai, Anda memang membutuhkan hari. Jika Anda benar-benar membutuhkan data Anda dalam format Tanggal, Anda dapat memperbaiki hari ke hari pertama setiap bulan secara manual dengan menempelkannya ke tanggal:

month <- "2009-03"
as.Date(paste(month,"-01",sep=""))
Sacha Epskamp
sumber
Apa format tanggal lain yang tersedia? Saya melihat sesuatu dengan POSIX dan sesuatu dengan ISO, tapi saya tidak yakin apakah itu format yang berbeda. Saya pikir itu hanya fungsi, ...
R_User
19
Perlu dicatat bahwa Anda dapat menentukan hari dengan formatter yang sama, sehingga Anda dapat melakukan as.Date(month, format='%Y-%m-01')dan mencapai hasil yang sama. Ini "terasa" lebih disukai bagi saya karena menentukan tanggal yang sama di setiap bulan lebih banyak tentang format tanggal kemudian manipulasi string, tapi mungkin itu tidak masuk akal.
JBecker
21
@JBecker saran Anda tidak bekerja untuk saya. > as.Date("2016-01", format="%Y-%m-01") # [1] NA. Saya menggunakan R 3.3.1
n8sty
26

Solusi paling ringkas jika Anda membutuhkan tanggal dalam format Tanggal:

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

as.Date akan memperbaiki hari pertama setiap bulan menjadi objek yearmon untuk Anda.

Ben Rollert
sumber
23

Anda juga bisa mencapai ini dengan fungsi parse_date_timeatau fast_strptimedari 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"

Perbedaan antara keduanya adalah parse_date_timememungkinkan untuk spesifikasi format gaya lubridate, sedangkan fast_strptimemembutuhkan spesifikasi format yang sama seperti strptime.

Untuk menentukan zona waktu, Anda dapat menggunakan tz-parameter:

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

Jika Anda memiliki data tanggal-waktu yang tidak teratur, Anda dapat menggunakan truncated-parameter untuk menentukan berapa banyak penyimpangan yang diperbolehkan:

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

Data yang digunakan:

dates1 <- c("2009-01","2009-02","2009-03")
dates2 <- c("2012-06-01 12:23","2012-06-01 12",'2012-06-01")
Jaap
sumber
setelah mengonversi variabel karakter ke format datemenggunakan parse_date_time, apakah ada cara untuk melihatnya dalam urutan yang berbeda daripada "2009-01-01 UTC"menggunakan lubridatepaket? Saya lebih suka melihat hari pertama di kumpulan data saya misalnya 01-01-2009.
pengguna63230
1
@ user63230 Lihat ?format; mis format(your_date, "%d-%m-%Y"). : . Ada kerugian untuk ini: Anda akan mendapatkan nilai karakter kembali dan bukan tanggal.
Jaap
Terima kasih tetapi saya mencoba untuk menghindari formatalasan yang Anda sebutkan, saya pikir mungkin ada cara untuk memasukkan ini ke dalam lubridatepaket tetapi sepertinya tidak ada.
pengguna63230
12

Menggunakan paket kapan saja :

library(anytime)

anydate("2009-01")
# [1] "2009-01-01"
zx8754
sumber
Agak aneh karena memilih "01-01", apakah ada sesuatu di dokumentasi tentang pilihan tersebut? Mungkin lebih ilustratif juga untuk ditampilkan anydate("2009-03")jika selalu memilih hari pertama setiap bulan.
lmo
@lmo tidak memeriksa dokumennya, menurut saya ini adalah praktik "umum" ketika dd tidak ada untuk memilih hari pertama.
zx8754
2
Itu masuk akal. Saya samar-samar diingat dan kemudian menemukan apa yang memicu komentar tersebut. Dari bagian Catatan di ?strptime: string input tidak perlu menentukan tanggal sepenuhnya: diasumsikan bahwa detik, menit, atau jam yang tidak ditentukan adalah nol, dan tahun, bulan, atau hari yang tidak ditentukan adalah yang sekarang. (Namun, jika satu bulan ditentukan, hari dalam bulan itu harus ditentukan oleh% d atau% e karena hari saat ini pada bulan tersebut tidak perlu valid untuk bulan yang ditentukan.) Sepertinya jawaban megatron berisi bagian yang serupa dokumentasi dari as.Date.
lmo
selama bertahun-tahun sebelum tahun 1900, itu tidak berhasil. Misalnya, saya mencoba inianytime('1870-01')
msh855
5

Memang, seperti yang telah disebutkan di atas (dan di tempat lain di SO), untuk mengubah string menjadi tanggal, Anda memerlukan tanggal tertentu dalam sebulan. Dari as.Date()halaman manual:

Jika string tanggal tidak menentukan tanggal secara lengkap, jawaban yang dikembalikan mungkin khusus untuk sistem. Perilaku yang paling umum adalah berasumsi bahwa tahun, bulan, atau hari yang hilang adalah yang sekarang. Jika itu menentukan tanggal secara tidak benar, implementasi yang andal akan memberikan kesalahan dan tanggal dilaporkan sebagai NA. Sayangnya beberapa implementasi umum (seperti glibc) tidak dapat diandalkan dan menebak arti yang dimaksudkan.

Solusi sederhana adalah menempelkan tanggal "01"ke setiap tanggal dan digunakan strptime()untuk menunjukkannya sebagai hari pertama bulan itu.


Bagi mereka yang mencari sedikit lebih banyak latar belakang tentang pemrosesan tanggal dan waktu di R:

Di R, waktu penggunaan POSIXctdan POSIXltkelas serta tanggal menggunakan Datekelas.

Tanggal disimpan sebagai jumlah hari sejak 1 Januari 1970 dan waktu disimpan sebagai jumlah detik sejak 1 Januari 1970.

Jadi, misalnya:

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

Untuk melakukan operasi pada tanggal dan waktu:

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

Dan untuk memproses tanggal, Anda dapat menggunakan strptime()(meminjam contoh ini dari halaman manual):

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

Saya pikir solusi @ ben-rollert adalah solusi yang baik.

Anda hanya perlu berhati-hati jika ingin menggunakan solusi ini dalam fungsi di dalam paket baru.

Saat mengembangkan paket, disarankan untuk menggunakan sintaks packagename::function_name()(lihat http://kbroman.org/pkg_primer/pages/depends.html ).

Dalam kasus ini, Anda harus menggunakan versi yang as.Date()ditentukan oleh zoopustaka.

Berikut ini contohnya:

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

Jadi jika Anda mengembangkan sebuah paket, praktik yang baik adalah menggunakan:

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