Arithmetic

Time series support basic arithmetic operations, allowing you to perform the necessary calculations. However, it is worth noting that such operations are performed in a slightly different way than on ordinary arrays, in which elements identical by index or value are compared. In our implementation, time series values ​​are matched by the last known time value.

To better understand the idea of ​​time series matching, let's look at the following simple example of adding two time series:

julia> t_array1 = TimeArray([
           TimeTick(1, 2.0),
           TimeTick(3, 4.0),
           TimeTick(7, 6.0),
       ]);

julia> t_array2 = TimeArray([
           TimeTick(3, 3.0),
           TimeTick(5, 5.0),
       ]);

Visually, these time series can be represented as follows:


 time:   - - - 1 - - - - 2 - - - - 3 - - - - 4 - - - - 5 - - - - 6 - - - - 7 - - - >
 
              2.0                 4.0                                     6.0
 t_array1:     ● - - - - - - - - - ● - - - - - - - - - - - - - - - - - - - ● - - - > 
 
 t_array2:                         ● - - - - - - - - - ● - - - - - - - - - - - - - >
                                  3.0                 5.0

Let's apply the addition operation to them.

julia> t_array1 + t_array2
4-element TimeArray{Int64, Float64}:
 TimeTick(1, NaN)
 TimeTick(3, 7.0)
 TimeTick(5, 9.0)
 TimeTick(7, 11.0)

The expected behavior will be as follows:

  • For the first timestamp 1 from the t_array1 there is no time value from the t_array2 one, so the resulting value of this timestamp will be 2.0 + NaN = NaN.
  • Then for timestamp 3 in both arrays there are values ​​(4.0 and 3.0), so as a result of addition we get 7.0.
  • At timestamp 5 in the t_array2 a new value appears 5.0 for which in the t_array1 the current value will be 4.0. As a result we get 9.0.
  • Finally, at timestamp 7 happens the opposite of the previous case.

 time:     - - - 1 - - - - 2 - - - - 3 - - - - 4 - - - - 5 - - - - 6 - - - - 7 - - - >
 
                2.0                 4.0﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉﹉⤵                   6.0
 t_array1:       ● - - - - - - - - - ● - - - - - - - - - - - - - - - - - - - ● - - - >
                 ┊                   ┊                   ┊                   ┊
    +       [2.0 + NaN]         [4.0 + 3.0]         [4.0 + 5.0]         [6.0 + 5.0]
                 ┊                   ┊                   ┊                   ┊
 t_array2:       X                   ● - - - - - - - - - ● - - - - - - - - - - - - - >
                NaN                 3.0                 5.0 ﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍﹍⤴
 
 result:         ● - - - - - - - - - ● - - - - - - - - - ● - - - - - - - - - ● - - - > 
                NaN                 7.0                 9.0                11.0

Supported mathematical operations on time series:

  • between two TimeArrays:
    • +: addition
    • -: subtraction
    • *: multiplication
    • /: division
  • between TimeArray and other values
    • +: addition
    • -: subtraction
    • *: multiplication
    • /: division
    • ^: exponentiation

For more flexible arithmetic work on TimeArrays, you can use functions ta_mergewith and ta_merge.

API

TimeArrays.ta_mergewithFunction
ta_mergewith(f, l_array::TimeArray, r_array::TimeArray; kw...) -> TimeArray

Creates a new TimeArray object by applying a binary function f on elements of left and right TimeArrays. TimeArrays uses the following rules to establish corresponding elements:

  • An element of the first array is matched to the nearest smaller or equal element of the second array.
  • If there is no such element in the second array, then the resulting element will be NaN.

Keyword arguments

  • l_merge::Bool = true: Use left timestamps in resulting TimeArray.
  • r_merge::Bool = true: Use right timestamps in resulting TimeArray.
  • padding::Bool = true: Preserve first timestamps with NaN values.

Examples

julia> using Dates

julia> t_left = TimeArray([
           TimeTick(DateTime("2024-01-02"), 0.2),
           TimeTick(DateTime("2024-01-05"), 0.5),
       ]);

julia> t_right = TimeArray([
           TimeTick(DateTime("2024-01-01"), 1.0),
           TimeTick(DateTime("2024-01-05"), 5.0),
           TimeTick(DateTime("2024-01-07"), 7.0),
       ]);

julia> ta_mergewith(+, t_left, t_right)
4-element TimeArray{DateTime, Float64}:
 TimeTick(2024-01-01T00:00:00, NaN)
 TimeTick(2024-01-02T00:00:00, 1.2)
 TimeTick(2024-01-05T00:00:00, 5.5)
 TimeTick(2024-01-07T00:00:00, 7.5)

julia> ta_mergewith(-, t_left, t_right; l_merge = false)
3-element TimeArray{DateTime, Float64}:
 TimeTick(2024-01-01T00:00:00, NaN)
 TimeTick(2024-01-05T00:00:00, -4.5)
 TimeTick(2024-01-07T00:00:00, -6.5)

julia> ta_mergewith(*, t_left, t_right, r_merge = false, padding = false)
2-element TimeArray{DateTime, Float64}:
 TimeTick(2024-01-02T00:00:00, 0.2)
 TimeTick(2024-01-05T00:00:00, 2.5)
source
TimeArrays.ta_mergeFunction
ta_merge(f::Function, t_array::TimeArray, value) -> TimeArray
ta_merge(f::Function, value, t_array::TimeArray) -> TimeArray

Creates a new TimeArray by applying a binary function f with value on elements of t_array.

Examples

julia> using Dates

julia> t_array = TimeArray([
           TimeTick(DateTime("2024-01-03"), 2.0),
           TimeTick(DateTime("2024-01-04"), 3.0),
           TimeTick(DateTime("2024-01-08"), 6.0),
       ]);

julia> ta_merge(+, t_array, 2.0)
3-element TimeArray{DateTime, Float64}:
 TimeTick(2024-01-03T00:00:00, 4.0)
 TimeTick(2024-01-04T00:00:00, 5.0)
 TimeTick(2024-01-08T00:00:00, 8.0)

julia> ta_merge(/, 18.0, t_array)
3-element TimeArray{DateTime, Float64}:
 TimeTick(2024-01-03T00:00:00, 9.0)
 TimeTick(2024-01-04T00:00:00, 6.0)
 TimeTick(2024-01-08T00:00:00, 3.0)
source