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

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

R_User
источник

Ответы:

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"
zx8754
источник
Немного странно, что он выбирает «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"))
PAC
источник