11.4 Intervalos de tempo regulares e irregulares

A time series can either be irregular (unequally spaced), strictly regular (equally spaced) or have an underlying regularity, i.e., be created from a regular series by omitting some observations. Here, the latter property is called regular. Consequently, regularity follows from strict regularity but not vice versa. ?zoo::is.regular

  • Estritamente regular: dados temporais igualmente espaçados.
  • Regular: dados temporais igualmente espaçados com omissão de algumas observações.
  • Irregular: dados temporais desigualmente espaçados.

Exemplo 11.1 Adaptado da documentação de zoo::is.regular().

library(zoo)
# estritamente regular
(z <- zoo(1:10, seq(2000, 2002.25, by = 0.25), frequency = 4))
## 2000 Q1 2000 Q2 2000 Q3 2000 Q4 2001 Q1 2001 Q2 2001 Q3 2001 Q4 2002 Q1 2002 Q2 
##       1       2       3       4       5       6       7       8       9      10
is.regular(z)
## [1] TRUE
is.regular(z, strict = TRUE)
## [1] TRUE
# regular, omitindo a terceira posição
is.regular(z[-3])
## [1] TRUE
is.regular(z[-3], strict = TRUE)
## [1] FALSE
## irregular
set.seed(42); (z <- zoo(1:10, rnorm(10)))
## -0.5647 -0.1061 -0.0947 -0.0627  0.3631  0.4043  0.6329   1.371  1.5115  2.0184 
##       2       6       8      10       3       5       4       1       7       9
is.regular(z)
## [1] FALSE
is.regular(z, strict = TRUE)
## [1] FALSE

Exemplo 11.2 Em Python.

import pandas as pd
import numpy as np

# Estritamente regular
data = list(range(1, 11))
# 3 meses (aproximadamente 0.25 anos, frequência = 4)
index = pd.date_range(start='2000-01-01', periods=10, freq='3M')  
z = pd.Series(data, index=index)
print(z)
print("Regular:", z.index.is_monotonic_increasing and z.index.inferred_freq is not None)
#MS = Month Start
print("Estritamente regular:", z.index.is_monotonic_increasing and z.index.inferred_freq == '3MS') 

# Regular, omitindo a terceira posição
z_removed = z.drop(z.index[2])
print(z_removed)
print("Regular (omitindo a terceira posição):", z_removed.index.is_monotonic_increasing and z_removed.index.inferred_freq is not None)
print("Estritamente regular (omitindo a terceira posição):", z_removed.index.is_monotonic_increasing and z_removed.index.inferred_freq == '3MS')

# Irregular
np.random.seed(42)
irregular_index = np.random.rand(10)
z_irregular = pd.Series(list(range(1, 11)), index=irregular_index)
print(z_irregular)
print("Regular (irregular):", z_irregular.index.is_monotonic_increasing)
# pandas does not infer frequency of non-date index
print("Estritamente regular (irregular):", z_irregular.index.is_monotonic_increasing) 

11.4.1 ts - Time Series

O função ts() do pacote stats é utilizada para criar objetos de séries temporais estritamente regulares. Usualmente definem-se os argumentos start e end ou start e frequency.

# 10 observações anuais de 2010 a 2019
ts(1:10, start = 2010, end = 2019)
## Time Series:
## Start = 2010 
## End = 2019 
## Frequency = 1 
##  [1]  1  2  3  4  5  6  7  8  9 10
Frequência frequency
Anual 1
Semestral 2
Quadrimestral 3
Trimestral 4
Bimestral 6
Mensal 12
Semanal 365/7 ou 365.2425/7
Diária 365 ou 365.2425
# 10 observações anuais iniciando em 2010
ts(1:10, start = 2010, frequency = 1)
## Time Series:
## Start = 2010 
## End = 2019 
## Frequency = 1 
##  [1]  1  2  3  4  5  6  7  8  9 10
# 2º semestre de 2010
ts(1:10, start = c(2010,2), frequency = 2)
## Time Series:
## Start = c(2010, 2) 
## End = c(2015, 1) 
## Frequency = 2 
##  [1]  1  2  3  4  5  6  7  8  9 10
# 2º quadrimestre de 2010
ts(1:10, start = c(2010,2), frequency = 3) 
## Time Series:
## Start = c(2010, 2) 
## End = c(2013, 2) 
## Frequency = 3 
##  [1]  1  2  3  4  5  6  7  8  9 10
# 2º trimestre de 2010
(z1 <- ts(1:10, start = c(2010, 2), frequency = 4)) 
##      Qtr1 Qtr2 Qtr3 Qtr4
## 2010         1    2    3
## 2011    4    5    6    7
## 2012    8    9   10
# 2º bimestre de 2010
ts(1:10, start = c(2010, 2), frequency = 6) 
## Time Series:
## Start = c(2010, 2) 
## End = c(2011, 5) 
## Frequency = 6 
##  [1]  1  2  3  4  5  6  7  8  9 10
# 2º mês (fev) de 2010
ts(1:10, start = c(2010, 2), frequency = 12) 
##      Feb Mar Apr May Jun Jul Aug Sep Oct Nov
## 2010   1   2   3   4   5   6   7   8   9  10
# 2ª semana de 2010
ts(1:10, start = c(2010, 2), frequency = 365/7) 
## Time Series:
## Start = 2010.01917808219 
## End = 2010.19178082192 
## Frequency = 52.1428571428571 
##  [1]  1  2  3  4  5  6  7  8  9 10

Exemplo 11.3 Em Python.

import pandas as pd

data = list(range(1, 11))

# 10 observações anuais de 2010 a 2019
index_annual_1 = pd.date_range(start='2010-01-01', periods=10, freq='Y')
series_annual_1 = pd.Series(data, index=index_annual_1)
print(series_annual_1)

# 10 observações anuais iniciando em 2010
index_annual_2 = pd.date_range(start='2010-01-01', periods=10, freq='Y')
series_annual_2 = pd.Series(data, index=index_annual_2)
print(series_annual_2)

# 2º semestre de 2010
index_semi_annual = pd.date_range(start='2010-07-01', periods=10, freq='6M')
series_semi_annual = pd.Series(data, index=index_semi_annual)
print(series_semi_annual)

# 2º quadrimestre de 2010
index_quad_annual = pd.date_range(start='2010-05-01', periods=10, freq='4M')
series_quad_annual = pd.Series(data, index=index_quad_annual)
print(series_quad_annual)

# 2º trimestre de 2010, QS = Quarter Start
index_quarterly = pd.date_range(start='2010-04-01', periods=10, freq='QS')
series_quarterly = pd.Series(data, index=index_quarterly)
print(series_quarterly)

# 2º bimestre de 2010
index_bi_monthly = pd.date_range(start='2010-03-01', periods=10, freq='2M')
series_bi_monthly = pd.Series(data, index=index_bi_monthly)
print(series_bi_monthly)

# 2º mês (fev) de 2010, MS = Month Start
index_monthly = pd.date_range(start='2010-02-01', periods=10, freq='MS')
series_monthly = pd.Series(data, index=index_monthly)
print(series_monthly)

# 2ª semana de 2010, W = Weekly
# Nota: pandas não tem uma frequência direta para "semanas do ano começando em uma semana específica". 
# Usamos semanas normais e ajustamos a data inicial.
index_weekly = pd.date_range(start='2010-01-08', periods=10, freq='W')
series_weekly = pd.Series(data, index=index_weekly)
print(series_weekly)

Dados diários são pouco elegantes via ts().

# 01/fev/2010
inds <- seq(as.Date('2010-02-01'), by = 'day', length.out = 10) 
myts <- ts(1:10,
           # 32º dia do ano
           start = c(2010, as.numeric(base::format(inds[1], "%j"))), 
           frequency = 365)
myts
## Time Series:
## Start = c(2010, 32) 
## End = c(2010, 41) 
## Frequency = 365 
##  [1]  1  2  3  4  5  6  7  8  9 10

Exemplo 11.4 Em Python.

import pandas as pd
from datetime import date

# 01/fev/2010, 'D' = Daily
inds = pd.date_range(start='2010-02-01', periods=10, freq='D')

# 32º dia do ano
start_day_of_year = inds[0].timetuple().tm_yday

myts = pd.Series(range(1, 11), index=inds)
print(myts)

print(f"Dia do ano inicial: {start_day_of_year}")

Exercício 11.4 Considere dados temporais diários.

  1. Leia a discussão https://stackoverflow.com/questions/33128865/starting-a-daily-time-series-in-r, em especial a resposta de Gavin Simpson.
  2. Leia o artigo https://sciencenotes.org/how-to-convert-days-to-years/ de Anne Helmenstine.

Séries multivariadas também podem ser geradas via ts().

set.seed(99)
zm1 <- ts(matrix(rnorm(300), 100, 3), start = c(2015, 1), frequency = 12)
class(zm1)
## [1] "mts"    "ts"     "matrix" "array"
is.mts(zm1) # é uma série temporal multivariada?
## [1] TRUE
head(zm1)
##            Series 1   Series 2   Series 3
## Jan 2015  0.2139625 -1.5250694 -0.8078470
## Feb 2015  0.4796581 -0.5009917 -0.2181119
## Mar 2015  0.0878287 -1.2131812 -2.1144011
## Apr 2015  0.4438585 -0.6302768  0.4284235
## May 2015 -0.3628379 -1.4474855 -1.1417398
## Jun 2015  0.1226740 -0.1669084 -0.8368590

Exemplo 11.5 Em Python.

import pandas as pd
import numpy as np

np.random.seed(99)
# Gera 300 números aleatórios e os reorganiza em uma matriz 100x3
data = np.random.randn(300).reshape(100, 3)
# 'MS' para início do mês
index = pd.date_range(start='2015-01-01', periods=100, freq='MS')
zm1 = pd.DataFrame(data, index=index)

print(type(zm1))
print("É uma série temporal multivariada?", isinstance(zm1, pd.DataFrame))
print(zm1.head())

11.4.2 zoo - Z’s Ordered Observations

O pacote zoo (Zeileis and Grothendieck 2005b) fornece infraestrutura para séries regular e irregulamente espaçadas, desenvolvida para ser tão consistente quanto o possível com ts(). De acordo com (Zeileis and Grothendieck 2005a, 6), a classe zooreg preenche a lacuna entre séries irregulares e estritamente regulares. Objetos desta classe herdam da classe zoo, mas possuem um atributo adicional frequency, no qual a frequência da série é armazenada. Desta forma podem ser empregados para representar séries estritamente e fracamente regulares. Para criar um objeto zooreg podem-se utilizar os comandos zoo() ou zooreg(), sendo que o comando zooreg() usa basicamente os mesmos argumentos de ts().

Exemplo 11.6 Exemplo baseado nas documentações de zoo::zoo() e zoo::zooreg().

# Uso
zoo(x, order.by, frequency)
zooreg(data, start, end, frequency, deltat, ts.eps, order.by)
library(zoo)
# 10 observações anuais iniciando em 2010
zooreg(1:10, start = 2010, frequency = 1)
## 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 
##    1    2    3    4    5    6    7    8    9   10
# 2º semestre de 2010
zooreg(1:10, start = c(2010,2), frequency = 2)
## 2010(2) 2011(1) 2011(2) 2012(1) 2012(2) 2013(1) 2013(2) 2014(1) 2014(2) 2015(1) 
##       1       2       3       4       5       6       7       8       9      10
# 2º quadrimestre de 2010
zooreg(1:10, start = c(2010,2), frequency = 3) 
## 2010(2) 2010(3) 2011(1) 2011(2) 2011(3) 2012(1) 2012(2) 2012(3) 2013(1) 2013(2) 
##       1       2       3       4       5       6       7       8       9      10
# 2º trimestre de 2010
(z2 <- zooreg(1:10, start = c(2010, 2), frequency = 4)) 
## 2010 Q2 2010 Q3 2010 Q4 2011 Q1 2011 Q2 2011 Q3 2011 Q4 2012 Q1 2012 Q2 2012 Q3 
##       1       2       3       4       5       6       7       8       9      10
# equivalente à linha anterior
(z3 <- zoo(1:10, seq(2010+1/4, by = 1/4, length.out = 10), frequency = 4)) 
## 2010 Q2 2010 Q3 2010 Q4 2011 Q1 2011 Q2 2011 Q3 2011 Q4 2012 Q1 2012 Q2 2012 Q3 
##       1       2       3       4       5       6       7       8       9      10
all.equal(z2,z3)
## [1] TRUE
# 2º bimestre de 2010
zooreg(1:10, start = c(2010, 2), frequency = 6)
## 2010(2) 2010(3) 2010(4) 2010(5) 2010(6) 2011(1) 2011(2) 2011(3) 2011(4) 2011(5) 
##       1       2       3       4       5       6       7       8       9      10
# 2º mês (fev) de 2010
zooreg(1:10, start = c(2010, 2), frequency = 12)
## Feb 2010 Mar 2010 Apr 2010 May 2010 Jun 2010 Jul 2010 Aug 2010 Sep 2010 Oct 2010 Nov 2010 
##        1        2        3        4        5        6        7        8        9       10
# 2ª semana de 2010
zooreg(1:10, start = c(2010, 2), frequency = 365/7)
##  2010(2)  2010(3)  2010(4)  2010(5)  2010(6)  2010(7)  2010(8)  2010(9) 2010(10) 2010(11) 
##        1        2        3        4        5        6        7        8        9       10

Exemplo 11.7 Em Python.

import pandas as pd
import numpy as np

data = list(range(1, 11))

# 10 observações anuais iniciando em 2010
index_annual = pd.date_range(start='2010-01-01', periods=10, freq='Y')
series_annual = pd.Series(data, index=index_annual)
print(series_annual)

# 2º semestre de 2010
index_semi_annual = pd.date_range(start='2010-07-01', periods=10, freq='6M')
series_semi_annual = pd.Series(data, index=index_semi_annual)
print(series_semi_annual)

# 2º quadrimestre de 2010
index_quad_annual = pd.date_range(start='2010-05-01', periods=10, freq='4M')
series_quad_annual = pd.Series(data, index=index_quad_annual)
print(series_quad_annual)

# 2º trimestre de 2010
index_quarterly = pd.date_range(start='2010-04-01', periods=10, freq='QS')
z2 = pd.Series(data, index=index_quarterly)
print(z2)

# equivalente à linha anterior
index_quarterly_alt = pd.date_range(start='2010-04-01', periods=10, freq='QS')
z3 = pd.Series(data, index=index_quarterly_alt)
print(z3)

print("z2 e z3 são iguais?", z2.equals(z3))

# 2º bimestre de 2010
index_bi_monthly = pd.date_range(start='2010-03-01', periods=10, freq='2M')
series_bi_monthly = pd.Series(data, index=index_bi_monthly)
print(series_bi_monthly)

# 2º mês (fev) de 2010
index_monthly = pd.date_range(start='2010-02-01', periods=10, freq='MS')
series_monthly = pd.Series(data, index=index_monthly)
print(series_monthly)

# 2ª semana de 2010
index_weekly = pd.date_range(start='2010-01-08', periods=10, freq='W')
series_weekly = pd.Series(data, index=index_weekly)
print(series_weekly)

Exercício 11.5 Considerando o exemplo acima de equivalência entre zooreg() e zoo() no trimestre, replique as séries utilizando a função zoo().

A função zoo::zoo() facilita a atribuição de séries temporais através do argumento order.by. Esta abordagem é aplicada também em xts::as.xts() (veja a seguir).

set.seed(42)
x.date <- as.POSIXct(paste0("2003-", rep(1:4, 4:1), "-", 
                            sample(1:28, 10, replace = TRUE)))
(x <- zoo(matrix(rnorm(20), ncol = 2), x.date))
##                                 
## 2003-01-01  1.5548955  0.9657529
## 2003-01-05 -0.6575028  0.4822047
## 2003-01-17  0.5802063  0.8817912
## 2003-01-25 -1.1876414 -0.8145709
## 2003-02-04 -1.0861326 -0.1616986
## 2003-02-10  0.1518129  0.2839578
## 2003-02-18  1.6133728  1.9355718
## 2003-03-17  1.3149588  0.3584021
## 2003-03-26  0.0356312  1.7232308
## 2003-04-15  0.9781675  0.3024309

Exemplo 11.8 Em Python.

import pandas as pd
import numpy as np
import random
from datetime import datetime

np.random.seed(42)
random.seed(42)  # Para garantir reprodutibilidade do sample

# Criando a sequência de datas
months = np.repeat(np.arange(1, 5), np.arange(4, 0, -1))
days = random.sample(range(1, 29), 10)
date_strings = [f"2003-{month:02d}-{day:02d}" for month, day in zip(months, days)]
x_date = pd.to_datetime(date_strings)

# Criando o zoo (DataFrame pandas)
data = np.random.randn(10, 2)
x = pd.DataFrame(data, index=x_date)

print(x)

Exemplo 11.9 Considere o conjunto de dados de casos semanais de varicela na Hungria16. Consiste em uma matriz de séries temporais por condado dos casos relatados entre 2005 e 2015.

Pode-se verificar a regularidade das séries via zoo::is.regular(), na qual o argumento strict verifica a regularidade estrita. Note que séries geradas via ts() sempre indicam regularidade estrita, mesmo quando retiramos um ou mais pontos.

# gerada com ts()
zoo::is.regular(z1)
## [1] TRUE
zoo::is.regular(z1[-3], strict = TRUE)
## [1] TRUE
# gerada com zooreg()
zoo::is.regular(z2)
## [1] TRUE
zoo::is.regular(z2[-3], strict = TRUE)
## [1] FALSE
# gerada com zoo()
zoo::is.regular(z3)
## [1] TRUE
zoo::is.regular(z3[-3], strict = TRUE)
## [1] FALSE

Exemplo 11.10 Em Python.

import pandas as pd

# z1, z2, z3 são as séries temporais criadas nos exemplos anteriores

# gerada com ts()
print("z1 regular:", z1.index.is_monotonic_increasing and z1.index.inferred_freq is not None)
print("z1[-3] estritamente regular:", z1.drop(z1.index[2]).index.is_monotonic_increasing and z1.drop(z1.index[2]).index.inferred_freq == 'QS')

# gerada com zooreg()
print("z2 regular:", z2.index.is_monotonic_increasing and z2.index.inferred_freq is not None)
print("z2[-3] estritamente regular:", z2.drop(z2.index[2]).index.is_monotonic_increasing and z2.drop(z2.index[2]).index.inferred_freq == 'QS')

# gerada com zoo()
print("z3 regular:", z3.index.is_monotonic_increasing and z3.index.inferred_freq is not None)
print("z3[-3] estritamente regular:", z3.drop(z3.index[2]).index.is_monotonic_increasing and z3.drop(z3.index[2]).index.inferred_freq == 'QS')

Pode-se consultar a frequência de uma série temporal via stats::frequency(). Note que as séries geradas via ts() sofrem alteração quando retiram-se observações.

# gerada com ts()
frequency(z1)
## [1] 4
frequency(z1[-3])
## [1] 1
# gerada com zooreg()
frequency(z2)
## [1] 4
frequency(z2[-3])
## [1] 4
# gerada com zoo()
frequency(z3)
## [1] 4
frequency(z3[-3])
## [1] 4

Exemplo 11.11 Em Python.

import pandas as pd

# z1, z2, z3 são as séries temporais criadas nos exemplos anteriores

# gerada com ts()
print("Frequência de z1:", z1.index.freq)
print("Frequência de z1[-3]:", z1.drop(z1.index[2]).index.freq)

# gerada com zooreg()
print("Frequência de z2:", z2.index.freq)
print("Frequência de z2[-3]:", z2.drop(z2.index[2]).index.freq)

# gerada com zoo()
print("Frequência de z3:", z3.index.freq)
print("Frequência de z3[-3]:", z3.drop(z3.index[2]).index.freq)

A função zoo::coredata() permite extrair e substituir dados de objetos da classe zoo.

class(z2)
## [1] "zooreg" "zoo"
coredata(z2)
##  [1]  1  2  3  4  5  6  7  8  9 10
class(coredata(z2))
## [1] "integer"
coredata(z2)[5] <- 99
z2
## 2010 Q2 2010 Q3 2010 Q4 2011 Q1 2011 Q2 2011 Q3 2011 Q4 2012 Q1 2012 Q2 2012 Q3 
##       1       2       3       4      99       6       7       8       9      10

Exemplo 11.12 Em Python.

import pandas as pd
import numpy as np

# z2 é a série temporal criada nos exemplos anteriores

print(type(z2))
print(z2.values)
print(type(z2.values))

# Modificando o valor
z2.values[4] = 99  # Índices em Python começam em 0, então 5º elemento é o índice 4
print(z2)

A função zoo::index() permite extrair e substituir o índice de objetos da classe zoo.

zoo::index(z2)
##  [1] "2010 Q2" "2010 Q3" "2010 Q4" "2011 Q1" "2011 Q2" "2011 Q3" "2011 Q4" "2012 Q1" "2012 Q2" "2012 Q3"

Exemplo 11.13 Em Python.

import pandas as pd
print(z2.index)

As funções stats::start() e stats::end() fornecem o início e o fim do vetor de índice/tempo.

stats::start(z2)
## [1] "2010 Q2"
stats::end(z2)
## [1] "2012 Q3"

Exemplo 11.14 Em Python.

print("Data de início:", z2.index)
print("Data de fim:", z2.index[-1])

O tratamento de NA pode ser feito com funções específicas.

z2[6] <- NA
# omite observações NA
na.omit(z2)
## 2010 Q2 2010 Q3 2010 Q4 2011 Q1 2011 Q2 2011 Q4 2012 Q1 2012 Q2 2012 Q3 
##       1       2       3       4      99       7       8       9      10
# apresenta a série até o primeiro NA
na.contiguous(z2)
## 2010 Q2 2010 Q3 2010 Q4 2011 Q1 2011 Q2 
##       1       2       3       4      99
# substitui NA por valores interpolados linearmente, (99+7)/2=53
zoo::na.approx(z2)
## 2010 Q2 2010 Q3 2010 Q4 2011 Q1 2011 Q2 2011 Q3 2011 Q4 2012 Q1 2012 Q2 2012 Q3 
##       1       2       3       4      99      53       7       8       9      10
# substitui NA por valores interpolados linearmente
forecast::na.interp(z2)
## Time Series:
## Start = 1 
## End = 10 
## Frequency = 1 
##  [1]  1  2  3  4 99 53  7  8  9 10
# substitui NA por valores interpolados via spline, veja ?spline
zoo::na.spline(z2)
##  2010 Q2  2010 Q3  2010 Q4  2011 Q1  2011 Q2  2011 Q3  2011 Q4  2012 Q1  2012 Q2  2012 Q3 
##  1.00000  2.00000  3.00000  4.00000 99.00000 76.13273  7.00000  8.00000  9.00000 10.00000
# substitui cada NA com o mais recente não NA
zoo::na.locf(z2)
## 2010 Q2 2010 Q3 2010 Q4 2011 Q1 2011 Q2 2011 Q3 2011 Q4 2012 Q1 2012 Q2 2012 Q3 
##       1       2       3       4      99      99       7       8       9      10

Exemplo 11.15 Em Python.

import pandas as pd
import numpy as np
from scipy import interpolate

# z2 é a série temporal criada nos exemplos anteriores
z2[5] = np.nan  # Índices em Python começam em 0

# omite observações NA
print("na.omit(z2):\n", z2.dropna())

# apresenta a série até o primeiro NA
print("\nna.contiguous(z2):\n", z2.loc[:z2.index[z2.isna().idxmax() - 1]])

# substitui NA por valores interpolados linearmente, (99+7)/2=53
print("\nzoo::na.approx(z2):\n", z2.interpolate(method='linear'))

# substitui NA por valores interpolados linearmente
print("\nforecast::na.interp(z2):\n", z2.interpolate(method='linear'))

# substitui NA por valores interpolados via spline
def na_spline(series):
    valid_indices = series.dropna().index.astype(int)
    valid_values = series.dropna().values
    
    all_indices = series.index.astype(int)
    
    spline = interpolate.spline(valid_indices, valid_values, all_indices)
    return pd.Series(spline, index=series.index)

print("\nzoo::na.spline(z2):\n", na_spline(z2))

# substitui cada NA com o mais recente não NA
print("\nzoo::na.locf(z2):\n", z2.fillna(method='ffill'))

Séries multivariadas com zooreg().

set.seed(99)
zm2 <- zooreg(matrix(rnorm(300), 100, 3), start = c(2015, 1), frequency = 12)
head(zm2) # zooreg()
##                                          
## Jan 2015  0.2139625 -1.5250694 -0.8078470
## Feb 2015  0.4796581 -0.5009917 -0.2181119
## Mar 2015  0.0878287 -1.2131812 -2.1144011
## Apr 2015  0.4438585 -0.6302768  0.4284235
## May 2015 -0.3628379 -1.4474855 -1.1417398
## Jun 2015  0.1226740 -0.1669084 -0.8368590
head(zm1) # ts()
##            Series 1   Series 2   Series 3
## Jan 2015  0.2139625 -1.5250694 -0.8078470
## Feb 2015  0.4796581 -0.5009917 -0.2181119
## Mar 2015  0.0878287 -1.2131812 -2.1144011
## Apr 2015  0.4438585 -0.6302768  0.4284235
## May 2015 -0.3628379 -1.4474855 -1.1417398
## Jun 2015  0.1226740 -0.1669084 -0.8368590
all.equal(zm1,zm2)
##  [1] "Attributes: < Names: 2 string mismatches >"                                            
##  [2] "Attributes: < Component \"class\": Lengths (4, 2) differ (string compare on first 2) >"
##  [3] "Attributes: < Component \"class\": 2 string mismatches >"                              
##  [4] "Attributes: < Component 3: Modes: list, numeric >"                                     
##  [5] "Attributes: < Component 3: Length mismatch: comparison on first 1 components >"        
##  [6] "Attributes: < Component 3: Component 1: target is NULL, current is numeric >"          
##  [7] "Attributes: < Component 4: Lengths: 3, 100 >"                                          
##  [8] "Attributes: < Component 4: Attributes: < target is NULL, current is list > >"          
##  [9] "Attributes: < Component 4: target is numeric, current is yearmon >"                    
## [10] "target is mts, current is zooreg"

Exemplo 11.16 Em Python.

import pandas as pd
import numpy as np

np.random.seed(99)

# Criando zm2 com zooreg()
data_zm2 = np.random.randn(100, 3)
index_zm2 = pd.date_range(start='2015-01-01', periods=100, freq='MS')
zm2 = pd.DataFrame(data_zm2, index=index_zm2)
print("zm2 (zooreg()):\n", zm2.head())

# zm1 já foi criado anteriormente com ts()
print("\nzm1 (ts()):\n", zm1.head())

# Comparando zm1 e zm2
print("\nzm1 e zm2 são iguais?", zm1.equals(zm2))

11.4.3 xts - eXtensible Time Series

O pacote xts (Ryan and Ulrich 2024) é baseado em zoo e fornece tratamento uniforme das diferentes classes de dados temporais do R. De acordo com o xts FAQ, xts estende o zoo e tem como principal benefício a compatibilidade com outros pacotes que usam diferentes classes de séries temporais (timeSeries, zoo, etc).

library(xts)
zm3 <- as.xts(zm2)
class(zm3)
## [1] "xts" "zoo"

Exemplo 11.17 Em Python.

# zm2 é o objeto criado anteriormente

zm3 = zm2.copy()  # xts é basicamente um zoo com atributos extras, então copiamos zm2
print(type(zm3))  # A classe ainda será pandas.DataFrame

Assim como em zoo::zoo(), a função xts::as.xts() facilita a atribuição de séries temporais através do argumento order.by. Ao contrário da função zoo::zoo(), xts::as.xts() só funciona com vetores.

set.seed(42)
x.date <- as.POSIXct(paste("2003-", rep(1:4, 4:1), "-", 
                           sample(1:28, 10, replace = TRUE), sep = ""))
x <- xts::as.xts(rnorm(10), x.date)
x
##                  [,1]
## 2003-01-01  1.5548955
## 2003-01-05 -0.6575028
## 2003-01-17  0.5802063
## 2003-01-25 -1.1876414
## 2003-02-04 -1.0861326
## 2003-02-10  0.1518129
## 2003-02-18  1.6133728
## 2003-03-17  1.3149588
## 2003-03-26  0.0356312
## 2003-04-15  0.9781675

Exemplo 11.18 Em Python.

import pandas as pd
import numpy as np
import random

np.random.seed(42)
random.seed(42)

# Crie a sequência de datas
months = np.repeat(np.arange(1, 5), np.arange(4, 0, -1))
days = random.sample(range(1, 29), 10)
date_strings = [f"2003-{month:02d}-{day:02d}" for month, day in zip(months, days)]
x_date = pd.to_datetime(date_strings)

# Crie a série temporal
x = pd.Series(np.random.randn(10), index=x_date)

print(x)

Exercício 11.7 Leia as seguintes documentações.

  1. xts FAQ.
  2. xts: Extensible Time Series.

11.4.4 tsibble - Tidy Temporal Data Frames and Tools

O pacote tsibble (E. Wang, Cook, and Hyndman 2020a) estende o tidyverse (Wickham et al. 2019) para dados temporais. Construído sobre o tibble, um tsibble (ou tbl_ts) é um objeto orientado a dados e modelo.

library(tsibble)
zm4 <- as_tsibble(zm1) # não funciona com `zoo` e `xts`
class(zm4)
## [1] "tbl_ts"     "tbl_df"     "tbl"        "data.frame"
zm4
## # A tsibble: 300 x 3 [1M]
## # Key:       key [3]
##       index key        value
##       <mth> <chr>      <dbl>
##  1 2015 Jan Series 1  0.214 
##  2 2015 Feb Series 1  0.480 
##  3 2015 Mar Series 1  0.0878
##  4 2015 Apr Series 1  0.444 
##  5 2015 May Series 1 -0.363 
##  6 2015 Jun Series 1  0.123 
##  7 2015 Jul Series 1 -0.864 
##  8 2015 Aug Series 1  0.490 
##  9 2015 Sep Series 1 -0.364 
## 10 2015 Oct Series 1 -1.29  
## # ℹ 290 more rows

Exemplo 11.19 Em Python.

import pandas as pd

# zm1 é o objeto criado anteriormente com ts()

# Criando um DataFrame similar a um tsibble
zm4 = zm1.copy()  # Copiando zm1 para não modificá-lo
zm4['index'] = zm4.index  # Adicionando o índice como uma coluna 'index'
print(type(zm4))
print(zm4)

References

Ryan, Jeffrey A., and Joshua M. Ulrich. 2024. Xts: eXtensible Time Series. https://CRAN.R-project.org/package=xts.
———. 2020a. “A New Tidy Data Structure to Support Exploration and Modeling of Temporal Data.” Journal of Computational and Graphical Statistics 29 (3): 466–78. https://doi.org/10.1080/10618600.2019.1695624.
Wickham, Hadley, Mara Averick, Jennifer Bryan, Winston Chang, Lucy D’Agostino McGowan, Romain François, Garrett Grolemund, et al. 2019. “Welcome to the tidyverse.” Journal of Open Source Software 4 (43): 1686. https://doi.org/10.21105/joss.01686.
Zeileis, Achim, and Gabor Grothendieck. 2005a. “Zoo: An S3 Class and Methods for Indexed Totally Ordered Observations.” https://cran.r-project.org/web/packages/zoo/vignettes/zoo.pdf.
———. 2005b. “Zoo: S3 Infrastructure for Regular and Irregular Time Series.” Journal of Statistical Software 14 (6): 1–27. https://doi.org/10.18637/jss.v014.i06.