Converter ano e mês (formato “aaaa-mm”) em uma data?

91

Eu tenho um conjunto de dados parecido com este:

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

Quero representar graficamente os dados (meses como valores x e contagens como valores y). Como há lacunas nos dados, desejo converter as informações do mês em uma data. Eu tentei:

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

Mas não funcionou. O que há de errado? Parece que as.Date () requer também um dia e não é capaz de definir um valor padrão para o dia? Qual função resolve meu problema?

R_User
fonte

Respostas:

57

Experimente isso. (Aqui usamos text=Linespara manter o exemplo independente, mas na realidade o substituiríamos pelo nome do arquivo.)

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)

O eixo X não é tão bonito com esses dados, mas se você tiver mais dados na realidade, pode estar tudo bem ou você pode usar o código para um eixo X sofisticado mostrado na seção de exemplos de ?plot.zoo.

A série zoo,, zque é criada acima tem um "yearmon"índice de tempo e se parece com isto:

> 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" pode ser usado sozinho também:

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

Nota:

  1. "yearmon" os objetos de classe são classificados em ordem de calendário.

  2. Isso representará os pontos mensais em intervalos igualmente espaçados, o que provavelmente é o desejado; no entanto, se fosse desejado para traçar os pontos em intervalos espaçados de forma desigual espaçados em proporção com o número de dias em cada mês, em seguida, converter o índice zda "Date"classe: time(z) <- as.Date(time(z)).

G. Grothendieck
fonte
76

Como as datas correspondem a um valor numérico e a uma data de início, você realmente precisa do dia. Se você realmente precisa que seus dados estejam no formato de data, você pode apenas fixar o dia no primeiro dia de cada mês manualmente, colando-o na data:

month <- "2009-03"
as.Date(paste(month,"-01",sep=""))
Sacha Epskamp
fonte
Que outros formatos de datas existem? Vi algo com POSIX e algo com ISO, mas não tenho certeza se esses são formatos diferentes. Achei que fossem apenas funções, ...
R_Usuário de
19
É interessante notar que você pode especificar o dia como sendo o mesmo no formatador, para que possa fazer as.Date(month, format='%Y-%m-01')e obter o mesmo resultado. Isso "parece" preferível para mim, já que especificar a mesma data em cada mês tem mais a ver com o formato da data do que com a manipulação de strings, mas talvez isso seja um absurdo.
JBecker
21
@JBecker sua sugestão não funciona para mim. > as.Date("2016-01", format="%Y-%m-01") # [1] NA. Estou usando R 3.3.1
n8sty
26

A solução mais concisa se você precisa que as datas estejam no formato de data:

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

as.Date fixará o primeiro dia de cada mês como um objeto anual para você.

Ben Rollert
fonte
23

Você também pode conseguir isso com as funções parse_date_timeou fast_strptimedo lubridatepacote:

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

A diferença entre os dois é que parse_date_timepermite a especificação do formato do tipo lubrificado, enquanto fast_strptimerequer a mesma especificação de formato que strptime.

Para especificar o fuso horário, você pode usar o tzparâmetro-:

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

Quando você tem irregularidades em seus dados de data e hora, você pode usar o truncatedparâmetro -para especificar quantas irregularidades são permitidas:

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

Dados usados:

dates1 <- c("2009-01","2009-02","2009-03")
dates2 <- c("2012-06-01 12:23","2012-06-01 12",'2012-06-01")
Jaap
fonte
tendo convertido uma variável de caractere para formatar dateusando parse_date_time, há uma maneira de visualizá-lo em uma ordem diferente do que "2009-01-01 UTC"usar o lubridatepacote? Eu preferiria ver o dia primeiro no meu conjunto de dados, por exemplo 01-01-2009.
user63230
1
@ user63230 Veja ?format; por exemplo: format(your_date, "%d-%m-%Y"). Porém, há uma desvantagem nisso: você receberá um valor de caractere de volta e não um encontro.
Jaap
Obrigado, mas estava tentando evitar formatpelo motivo que você mencionou, pensei que poderia haver uma maneira de incorporar isso no lubridatepacote, mas parece que não.
user63230
12

Usando o pacote anytime :

library(anytime)

anydate("2009-01")
# [1] "2009-01-01"
zx8754
fonte
É um pouco estranho que ele escolha "01-01", há algo na documentação sobre a escolha? Talvez mais ilustrativo para mostrar também anydate("2009-03")se escolhe sempre o primeiro dia do mês.
lmo
@lmo não verificou a documentação, diria que é uma prática "comum" quando falta o dd para escolher o primeiro dia.
zx8754 01 de
2
Isso faz sentido. Fui lembrado vagamente e então descobri o que desencadeou o comentário. Na seção Nota de ?strptime: a string de entrada não precisa especificar a data completamente: assume-se que os segundos, minutos ou horas não especificados são zero e um ano, mês ou dia não especificado é o atual. (No entanto, se um mês for especificado, o dia desse mês deve ser especificado por% d ou% e, já que o dia atual do mês não precisa ser válido para o mês especificado.) Parece que a resposta do megatron contém uma parte semelhante de documentação de as.Date.
lmo
por anos antes de 1900, não funciona. Por exemplo, eu tentei issoanytime('1870-01')
msh855
5

Na verdade, como foi mencionado acima (e em outro lugar no SO), para converter a string em uma data, você precisa de uma data específica do mês. Na as.Date()página do manual:

Se a string de data não especificar a data completamente, a resposta retornada pode ser específica do sistema. O comportamento mais comum é presumir que um ano, mês ou dia ausente é o atual. Se especificar uma data incorretamente, implementações confiáveis ​​darão um erro e a data será relatada como NA. Infelizmente, algumas implementações comuns (como glibc) não são confiáveis ​​e adivinham o significado pretendido.

Uma solução simples seria colar a data "01"em cada data e usá strptime()-la para indicá-la como o primeiro dia daquele mês.


Para aqueles que procuram um pouco mais de fundo sobre datas e horários de processamento em R:

Em R, os tempos usam POSIXcte as POSIXltclasses e as datas usam a Dateclasse.

As datas são armazenadas como o número de dias desde 1º de janeiro de 1970 e as horas são armazenadas como o número de segundos desde 1º de janeiro de 1970.

Então, por exemplo:

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

Para realizar operações em datas e horas:

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

E para processar datas, você pode usar strptime()(pegando emprestado esses exemplos da página do 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
fonte
1

Eu acho que a solução de @ben-rollert é uma boa solução.

Você só precisa ter cuidado se quiser usar esta solução em uma função dentro de um novo pacote.

Ao desenvolver pacotes, é recomendado usar a sintaxe packagename::function_name()(consulte http://kbroman.org/pkg_primer/pages/depends.html ).

Neste caso, você deve usar a versão as.Date()definida pela zoobiblioteca.

Aqui está um exemplo :

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

Portanto, se você estiver desenvolvendo um pacote, a prática recomendada é usar:

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