Преобразование года и месяца (формат «гггг-мм») в дату?


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 () требует также день и не может установить стандартное значение для дня? Какая функция решает мою проблему?

Ответы:


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, показанный в разделе примеров ?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)).


76

Поскольку даты соответствуют числовому значению и дате начала, вам действительно нужен день. Если вам действительно нужно, чтобы ваши данные были в формате даты, вы можете просто вручную привязать день к первому числу каждого месяца, вставив его в дату:

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

Какие еще есть форматы дат? Я видел что-то с POSIX и что-то с ISO, но я не уверен, что это разные форматы. Я думал, что это просто функции, ...
— R_User 05

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 зафиксирует для вас первый день каждого месяца в объекте yearmon.


23

Вы также можете добиться этого с помощью функций 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-параметр:

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

2
Это имеет смысл. Меня смутно вспомнили, а потом я обнаружил, что вызвало этот комментарий. Из раздела «Примечание» ?strptime: во входной строке не требуется указывать дату полностью: предполагается, что неуказанные секунды, минуты или часы равны нулю, а неуказанный год, месяц или день являются текущими. (Однако, если указан месяц, день этого месяца должен быть указан% d или% e, поскольку текущий день месяца не обязательно должен быть действительным для указанного месяца.) Похоже, что ответ мегатрона содержит аналогичный фрагмент документации от 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-Roller - хорошее решение.

Вам просто нужно быть осторожным, если вы хотите использовать это решение в функции внутри нового пакета.

При разработке пакетов рекомендуется использовать синтаксис 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"))
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.