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?

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


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

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ê.


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

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"

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

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"))
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.