foundryts.functions.time_weighted

foundryts.functions.time_weighted(aggregate, method='linear', bounds_interpolation=None)

Returns a time-weighted aggregation specification that can be passed as the aggregate argument to aggregate functions such as cumulative_aggregate(), rolling_aggregate(), and periodic_aggregate().

Unlike standard aggregations, which weight every point equally, time-weighted aggregations weight each point by the duration it is in effect by integrating the line segments between adjacent points. This is the appropriate choice for series sampled at irregular intervals, such as a sensor reading or a status value held until the next update.

Time-weighted aggregates supported:

AggregateDescription
averageAverage value of the series across the range, weighted by the duration each value is in effect. Equivalent to the area under the curve divided by the range duration.
integralArea under the curve across the range, computed using the specified integration method.

Integration methods supported (method):

MethodDescription
lhs (left-hand sum)Holds the earlier point's value constant until the next point arrives. Use this option when each point represents the value that started at its timestamp.
linear (trapezoidal rule)Connects adjacent points with a straight line and integrates the resulting trapezoid. Use this option when the underlying value changes smoothly between samples. This is the default.
rhs (right-hand sum)Holds the later point's value constant back to the previous point. Use this option when each point represents the value that ended at its timestamp.

Bounds interpolation options (bounds_interpolation):

By default (None), only the area between data points that fall inside the range contributes to the aggregate. Any gap between a range boundary and the nearest interior point is ignored, which can understate aggregates for ranges that do not align with the sampling timestamps of the series.

Specifying a bounds_interpolation extends the curve to the range boundaries using the chosen strategy. See Interpolation in time series for more on how each strategy infers values between known points.

ValueDescription
defaultUse the default interpolation strategy: linear for numeric series, previous for enum series.
linearLinearly interpolate between the point outside the range and the nearest point inside the range to derive a value at the boundary.
nearestUse the value of the nearest point on either side of the boundary.
nextUse the value of the next point, holding it constant back to the boundary.
noneDo not extrapolate. Equivalent to passing None (the default).
previousUse the value of the previous point, holding it constant up to the boundary.
  • Parameters:
    • aggregate (str) – Time-weighted aggregate to compute. Either average or integral.
    • method (str , optional) – Integration method used to compute the area between adjacent points. One of lhs, linear, or rhs (default is linear).
    • bounds_interpolation (str , optional) – Interpolation strategy used to extend the curve to the range bounds when computing the aggregate. One of default, linear, nearest, next, none, or previous. When None (the default), no extrapolation is performed.
  • Returns: A TimeWeightedSpec aggregation specification that can be passed as the aggregate argument to aggregate functions such as cumulative_aggregate(), rolling_aggregate(), and periodic_aggregate().
Note

This function is only applicable to numeric series.

Examples

Copied!
1 2 3 4 5 6 7 8 >>> series = F.points( ... (1, 5.0), (3, 15.0), (6, 30.0), name="series" ... ) >>> series.to_pandas() timestamp value 0 1970-01-01 00:00:00.000000001 5.0 1 1970-01-01 00:00:00.000000003 15.0 2 1970-01-01 00:00:00.000000006 30.0

Cumulative time-weighted average using the default linear integration method. At t=1 the result is just the first point's value; at t=3 the running average weights the values at t=1 and t=3 equally because the gap between them is 2ns; at t=6 the longer 3ns gap to the value 30.0 pulls the average up:

Copied!
1 2 3 4 5 6 >>> twa = F.cumulative_aggregate(F.time_weighted("average"))(series) >>> twa.to_pandas() timestamp value 0 1970-01-01 00:00:00.000000001 5.0 1 1970-01-01 00:00:00.000000003 10.0 2 1970-01-01 00:00:00.000000006 17.5

Rolling integral computed with the right-hand-sum integration method over a 5ns window. Output values are in value × seconds, hence the scientific notation. At t=1 the window contains only one point so there is nothing to integrate; at t=3 the window covers (1, 5.0) and (3, 15.0) and the RHS method holds the later value 15.0 constant across the 2ns gap, giving 15 × 2ns = 3e-08; at t=6 the point at t=1 has dropped out of the window, leaving (3, 15.0) and (6, 30.0), and RHS holds 30.0 constant across the 3ns gap, giving 30 × 3ns = 9e-08:

Copied!
1 2 3 4 5 6 7 8 >>> rolling_integral = F.rolling_aggregate( ... F.time_weighted("integral", method="rhs"), "5ns" ... )(series) >>> rolling_integral.to_pandas() timestamp value 0 1970-01-01 00:00:00.000000001 0.000000e+00 1 1970-01-01 00:00:00.000000003 3.000000e-08 2 1970-01-01 00:00:00.000000006 9.000000e-08

Periodic time-weighted average in 2ns windows, with the value at each window boundary linearly interpolated from the surrounding points. In the window ending at t=2, only the point (1, 5.0) is inside; the boundary value at t=2 is interpolated to 10.0 between (1, 5.0) and (3, 15.0), giving a trapezoidal average of 7.5. In the window ending at t=4, both boundaries are interpolated — t=2 to 10.0 and t=4 to 20.0 — averaging the linear curve across the full 2ns window to 15.0. In the window ending at t=6, the left boundary at t=4 is interpolated to 20.0 and the right boundary is the actual point (6, 30.0), averaging to 25.0:

Copied!
1 2 3 4 5 6 7 8 >>> periodic_twa = F.periodic_aggregate( ... F.time_weighted("average", bounds_interpolation="linear"), "2ns" ... )(series) >>> periodic_twa.to_pandas() timestamp value 0 1970-01-01 00:00:00.000000002 7.5 1 1970-01-01 00:00:00.000000004 15.0 2 1970-01-01 00:00:00.000000006 25.0