Sistema de referência de tempo
O sistema de referência de tempo (TRS) é um sistema local, regional ou global usado para identificar o tempo.
Um sistema de referência de tempo define uma projeção específica para mapeamento direto e reverso entre um registro de data e hora e sua representação numérica. Um exemplo comum com o qual a maioria dos usuários está familiarizada é o horário UTC, que mapeia um registro de data e hora, por exemplo, 1 de janeiro de 2019, meia-noite (Horário de Greenwich) para um valor inteiro de 64 bits (1546300800000), que captura o número de milissegundos decorridos desde 1 de janeiro de 1970, meia-noite (Horário de Greenwich). Em linhas gerais, o valor de registro de data e hora é mais adequado para capacidade de leitura humana, enquanto a representação numérica é mais adequada para o processamento de máquina.
Na biblioteca de séries temporais, uma série temporal pode ser associada a um TRS. Um TRS é composto por:
- Uma marcação de tempo que captura a granularidade do tempo, por exemplo 1 minuto
- A data e hora zoneadas que capturam um horário de início, por exemplo
1 Jan 2019, 12 midnight US Eastern Daylight Savings time (EDT). Um registro de data e hora é mapeado em uma representação numérica por meio do cálculo do número de marcações de tempo decorrido desde o horário de início. Uma representação numérica é escalonada pela granularidade e deslocada pela hora de início quando é mapeada de volta para um timestamp.
Observe que essa projeção direta + reversa pode levar à perda de tempo. Por exemplo, se a granularidade de tempo real de uma série temporal for em segundos, então encaminhação e mapeamento reverso dos estampas do tempo 09:00:01 e 09:00:02 (para ser lido como hh:mm:ss) a uma granularidade de um minuto resultaria em estampas de tempo 09:00:00 e 09:00:00 , respectivamente. Neste exemplo, uma série temporal, cuja granularidade está em segundos, está sendo mapeada para minutos e, assim, o mapeamento reverso perde informações. No entanto, se a granularidade mapeada for maior do que a granularidade da série temporal de entrada (mais especificamente, se a granularidade da série temporal for um múltiplo integral da granularidade mapeada), certamente a projeção direta + reversa não sofrerá perdas. Por exemplo, mapear uma série temporal, cuja granularidade está em minutos, para segundos e fazer a projeção reversa para minutos resultaria na reconstrução sem perdas dos registros de data e hora.
Configurando o TRS
Quando uma série temporal é criada, ela é associada a um TRS (ou Nenhum se nenhum TRS for especificado). Se o TRS for Nenhum, então os valores numéricos não poderão ser mapeados para registros de data e hora. Observe que o TRS só pode ser configurado em uma série temporal no momento da construção. O motivo é que uma série temporal por design é um objeto imutável. A imutabilidade vem a calhar quando a biblioteca é usada em ambientes multiencadeados ou em ambientes de computação distribuída, como o Apache Spark. Embora um TRS possa ser configurado somente no momento da construção, ele pode ser alterado usando o método with_trs, conforme descrito na próxima seção. O with_trs produz uma nova série temporal e, assim, não tem impacto na imutabilidade.
Consideremos uma série temporal simples criada a partir de uma lista na memória:
values = [1.0, 2.0, 4.0]
x = tspy.time_series(values)
x
Isso retorna:
TimeStamp: 0 Value: 1.0
TimeStamp: 1 Value: 2.0
TimeStamp: 2 Value: 4.0
No momento da construção, a série temporal pode ser associada a um TRS. Associar um TRS com uma série temporal permite que seus registros de data e hora numéricos fiquem em conformidade com a marcação de tempo e o deslocamento/fuso horário. O exemplo a seguir mostra 1 minute and 1 Jan 2019, 12 midnight (GMT):
zdt = datetime.datetime(2019,1,1,0,0,0,0,tzinfo=datetime.timezone.utc)
x_trs = tspy.time_series(data, granularity=datetime.timedelta(minutes=1), start_time=zdt)
x_trs
Isso retorna:
TimeStamp: 2019-01-01T00:00Z Value: 1.0
TimeStamp: 2019-01-01T00:01Z Value: 2.0
TimeStamp: 2019-01-01T00:02Z Value: 4.0
Aqui está outro exemplo em que os registros de data e hora numéricos são reinterpretados com uma marcação de tempo de uma hora e deslocamento/fuso horário como 1 Jan 2019, 12 midnight US Eastern Daylight Savings time (EDT).
tz_edt = datetime.timezone.edt
zdt = datetime.datetime(2019,1,1,0,0,0,0,tzinfo=tz_edt)
x_trs = tspy.time_series(data, granularity=datetime.timedelta(hours=1), start_time=zdt)
x_trs
Isso retorna:
TimeStamp: 2019-01-01T00:00-04:00 Value: 1.0
TimeStamp: 2019-01-01T00:01-04:00 Value: 2.0
TimeStamp: 2019-01-01T00:02-04:00 Value: 4.0
Observe que agora os registros de data e hora indicam um deslocamento de -4 horas do Horário de Greenwich (fuso horário do Horário Padrão do Leste dos EUA) e capturam a marcação de tempo de uma hora. Observe também que a configuração de um TRS NÃO altera os registros de data e hora numéricos - ela apenas especifica uma maneira de interpretar registros de data e hora numéricos.
x_trs.print(human_readable=False)
Isso retorna:
TimeStamp: 0 Value: 1.0
TimeStamp: 1 Value: 2.0
TimeStamp: 2 Value: 4.0
Alterando o TRS
É possível mudar o TRS associado a uma série temporal usando a função with_trs. Observe que essa função lançará uma exceção se a série temporal de entrada não estiver associada a um TRS (se o TRS for Nenhum). O uso de with_trs muda os registros de data e hora numéricos.
A amostra de código a seguir mostra o TRS configurado no horário das construções sem usar with_trs:
# 1546300800 is the epoch time in seconds for 1 Jan 2019, 12 midnight GMT
zdt1 = datetime.datetime(1970,1,1,0,0,0,0,tzinfo=datetime.timezone.utc)
y = tspy.observations.of(tspy.observation(1546300800, 1.0),tspy.observation(1546300860, 2.0), tspy.observation(1546300920,
4.0)).to_time_series(granularity=datetime.timedelta(seconds=1), start_time=zdt1)
y.print()
y.print(human_readable=False)
Isso retorna:
TimeStamp: 2019-01-01T00:00Z Value: 1.0
TimeStamp: 2019-01-01T00:01Z Value: 2.0
TimeStamp: 2019-01-01T00:02Z Value: 4.0
# TRS has been set during construction time - no changes to numeric timestamps
TimeStamp: 1546300800 Value: 1.0
TimeStamp: 1546300860 Value: 2.0
TimeStamp: 1546300920 Value: 4.0
O exemplo a seguir mostra como aplicar with_trs para mudar granularity para um minuto e reter o deslocamento de tempo original (1º de janeiro de 1970, meia-noite GMT):
y_minutely_1970 = y.with_trs(granularity=datetime.timedelta(minutes=1), start_time=zdt1)
y_minutely_1970.print()
y_minutely_1970.print(human_readable=False)
Isso retorna:
TimeStamp: 2019-01-01T00:00Z Value: 1.0
TimeStamp: 2019-01-01T00:01Z Value: 2.0
TimeStamp: 2019-01-01T00:02Z Value: 4.0
# numeric timestamps have changed to number of elapsed minutes since 1 Jan 1970, 12 midnight GMT
TimeStamp: 25771680 Value: 1.0
TimeStamp: 25771681 Value: 2.0
TimeStamp: 25771682 Value: 4.0
Agora aplique with_trs para mudar granularity para um minuto e o deslocamento para 1º de janeiro de 2019, meia-noite GMT:
zdt2 = datetime.datetime(2019,1,1,0,0,0,0,tzinfo=datetime.timezone.utc)
y_minutely = y.with_trs(granularity=datetime.timedelta(minutes=1), start_time=zdt2)
y_minutely.print()
y_minutely.print(human_readable=False)
Isso retorna:
TimeStamp: 2019-01-01T00:00Z Value: 1.0
TimeStamp: 2019-01-01T00:01Z Value: 2.0
TimeStamp: 2019-01-01T00:02Z Value: 4.0
# numeric timestamps are now minutes elapsed since 1 Jan 2019, 12 midnight GMT
TimeStamp: 0 Value: 1.0
TimeStamp: 1 Value: 2.0
TimeStamp: 2 Value: 4.0
Para entender melhor como isso impacta o pós-processamento, vamos examinar o seguinte. Note que materialize em registros de data e hora numéricos opera sobre os registros de data e hora numéricos subjacentes associados à série temporal.
print(y.materialize(0,2))
print(y_minutely_1970.materialize(0,2))
print(y_minutely.materialize(0,2))
Isso retorna:
# numeric timestamps in y are in the range 1546300800, 1546300920 and thus y.materialize(0,2) is empty
[]
# numeric timestamps in y_minutely_1970 are in the range 25771680, 25771682 and thus y_minutely_1970.materialize(0,2) is empty
[]
# numeric timestamps in y_minutely are in the range 0, 2
[(0,1.0),(1,2.0),(2,4.0)]
O método materialize também pode ser aplicado a objetos datetime. Isso resulta em uma exceção, caso a série temporal subjacente não esteja associada a um TRS (se o TRS for Nenhum). Supondo que a série temporal subjacente tenha um TRS, os objetos de data/hora serão mapeados para um intervalo numérico usando o TRS.
# Jan 1 2019, 12 midnight GMT
dt_beg = datetime.datetime(2019,1,1,0,0,0,0,tzinfo=datetime.timezone.utc)
# Jan 1 2019, 12:02 AM GMT
dt_end = datetime.datetime(2019,1,1,0,2,0,0,tzinfo=datetime.timezone.utc)
print(y.materialize(dt_beg, dt_end))
print(y_minutely_1970.materialize(dt_beg, dt_end))
print(y_minutely.materialize(dt_beg, dt_end))
# materialize on y in UTC millis
[(1546300800,1.0),(1546300860,2.0), (1546300920,4.0)]
# materialize on y_minutely_1970 in UTC minutes
[(25771680,1.0),(25771681,2.0),(25771682,4.0)]
# materialize on y_minutely in minutes offset by 1 Jan 2019, 12 midnight
[(0,1.0),(1,2.0),(2,4.0)]
Registros de data e hora duplicados
A mudança do TRS pode resultar em registros de data e hora duplicados. O exemplo a seguir altera a granularidade para uma hora o que resulta em timestamps duplicados. A biblioteca de séries temporais manipula perfeitamente os registros de data e hora duplicados e fornece combinadores de conveniência para reduzir valores associados a registros de data e hora duplicados a um único valor, por exemplo, calculando uma média dos valores agrupados por registros de data e hora duplicados.
y_hourly = y_minutely.with_trs(granularity=datetime.timedelta(hours=1), start_time=zdt2)
print(y_minutely)
print(y_minutely.materialize(0,2))
print(y_hourly)
print(y_hourly.materialize(0,0))
Isso retorna:
# y_minutely - minutely time series
TimeStamp: 2019-01-01T00:00Z Value: 1.0
TimeStamp: 2019-01-01T00:01Z Value: 2.0
TimeStamp: 2019-01-01T00:02Z Value: 4.0
# y_minutely has numeric timestamps 0, 1 and 2
[(0,1.0),(1,2.0),(2,4.0)]
# y_hourly - hourly time series has duplicate timestamps
TimeStamp: 2019-01-01T00:00Z Value: 1.0
TimeStamp: 2019-01-01T00:00Z Value: 2.0
TimeStamp: 2019-01-01T00:00Z Value: 4.0
# y_hourly has numeric timestamps of all 0
[(0,1.0),(0,2.0),(0,4.0)]
Opcionalmente, os registros de data e hora duplicados podem ser combinados da seguinte forma:
y_hourly_averaged = y_hourly.transform(transformers.combine_duplicate_granularity(lambda x: sum(x)/len(x))
print(y_hourly_averaged.materialize(0,0))
Isso retorna:
# values corresponding to the duplicate numeric timestamp 0 have been combined using average
# average = (1+2+4)/3 = 2.33
[(0,2.33)]
Saiba Mais
Para usar o tspy Python SDK, consulte a Documentação do tspy Python SDK.