Soothsayer.Trend (Soothsayer v0.6.1)

View Source

Trend component with optional piecewise linear changepoints.

Handles network building, feature engineering, and weight extraction for the trend.

The trend function with changepoints is:

trend(t) = k * t + m + sum(delta_j * max(0, t - s_j))

Where:

  • k = base growth rate (learned)
  • m = offset (learned)
  • s_j = changepoint positions (computed from data, fixed)
  • delta_j = rate adjustments at each changepoint (learned)

Summary

Functions

Builds changepoint feature tensor computing max(0, t - s_j) for each changepoint.

Builds the trend component layer.

Builds trend features tensor and metadata from dates.

Creates the Axon input node for the trend component.

Builds the complete trend input by concatenating t with changepoint features.

Computes evenly spaced changepoint indices within the first portion of data.

Computes changepoint positions as dates from the data.

Converts dates to numeric values (days since first date).

Extracts learned trend weights from a fitted model.

Converts numeric values back to dates.

Functions

build_changepoint_features(t, changepoint_positions)

@spec build_changepoint_features(Nx.Tensor.t(), [number()]) :: Nx.Tensor.t() | nil

Builds changepoint feature tensor computing max(0, t - s_j) for each changepoint.

Parameters

  • t - Tensor of time values with shape {n_samples, 1}.
  • changepoint_positions - List of numeric changepoint positions.

Returns

A tensor of shape {n_samples, changepoints} with changepoint features.

Examples

iex> t = Nx.tensor([[1.0], [2.0], [3.0]])
iex> Soothsayer.Trend.build_changepoint_features(t, [1.5])
#Nx.Tensor<f32[3][1] [[0.0], [0.5], [1.5]]>

build_component(input, arg2)

@spec build_component(Axon.t(), map()) :: Axon.t()

Builds the trend component layer.

Parameters

  • input - Axon input node from build_input/1.
  • config - Model configuration map.

Returns

An Axon dense layer when enabled, or Axon.constant(0) when disabled.

build_features(dates, config)

@spec build_features([Date.t()], map()) :: {Nx.Tensor.t(), map()}

Builds trend features tensor and metadata from dates.

Parameters

  • dates - List of dates.
  • config - Model configuration map with :trend key.

Returns

A tuple {tensor, metadata} where:

  • tensor has shape {n_dates, 1 + changepoints}
  • metadata contains :first_date and :changepoint_positions

Examples

iex> dates = [~D[2023-01-01], ~D[2023-01-02], ~D[2023-01-03]]
iex> config = %{trend: %{changepoints: 0, changepoints_range: 0.8}}
iex> {tensor, metadata} = Soothsayer.Trend.build_features(dates, config)
iex> Nx.shape(tensor)
{3, 1}
iex> metadata.first_date
~D[2023-01-01]

build_input(config)

@spec build_input(map()) :: Axon.t()

Creates the Axon input node for the trend component.

Parameters

  • config - Model configuration map with :trend key.

Returns

An Axon input node with shape {nil, 1 + changepoints}.

build_trend_input(t, changepoint_features)

@spec build_trend_input(Nx.Tensor.t(), Nx.Tensor.t() | nil) :: Nx.Tensor.t()

Builds the complete trend input by concatenating t with changepoint features.

Parameters

  • t - Tensor of time values with shape {n_samples, 1}.
  • changepoint_features - Tensor of changepoint features with shape {n_samples, changepoints}.

Returns

A tensor of shape {n_samples, 1 + changepoints}.

Examples

iex> t = Nx.tensor([[1.0], [2.0]])
iex> cp_features = Nx.tensor([[0.0, 0.0], [0.5, 0.0]])
iex> Soothsayer.Trend.build_trend_input(t, cp_features)
#Nx.Tensor<f32[2][3] [[1.0, 0.0, 0.0], [2.0, 0.5, 0.0]]>

compute_changepoint_indices(n_samples, changepoints, changepoints_range)

@spec compute_changepoint_indices(non_neg_integer(), non_neg_integer(), float()) :: [
  non_neg_integer()
]

Computes evenly spaced changepoint indices within the first portion of data.

Parameters

  • n_samples - Total number of samples in the dataset.
  • changepoints - Number of changepoints to create.
  • changepoints_range - Fraction of data to place changepoints in (0-1).

Returns

A list of indices where changepoints will be placed.

Examples

iex> Soothsayer.Trend.compute_changepoint_indices(100, 5, 0.8)
[16, 32, 48, 64, 80]

compute_changepoint_positions(dates, changepoints, changepoints_range)

@spec compute_changepoint_positions([Date.t()], non_neg_integer(), float()) :: [
  Date.t()
]

Computes changepoint positions as dates from the data.

Parameters

  • dates - List of dates in the dataset.
  • changepoints - Number of changepoints to create.
  • changepoints_range - Fraction of data to place changepoints in (0-1).

Returns

A list of dates where changepoints are positioned.

Examples

iex> dates = Enum.map(0..99, fn i -> Date.add(~D[2023-01-01], i) end)
iex> Soothsayer.Trend.compute_changepoint_positions(dates, 5, 0.8)
[~D[2023-01-17], ~D[2023-02-02], ~D[2023-02-18], ~D[2023-03-06], ~D[2023-03-22]]

date_to_numeric(dates, first_date)

@spec date_to_numeric([Date.t()], Date.t()) :: Nx.Tensor.t()

Converts dates to numeric values (days since first date).

Parameters

  • dates - List of dates.
  • first_date - Reference date (typically first date in dataset).

Returns

A tensor of numeric values representing days since first_date.

Examples

iex> Soothsayer.Trend.date_to_numeric([~D[2023-01-01], ~D[2023-01-02]], ~D[2023-01-01])
#Nx.Tensor<f32[2] [0.0, 1.0]>

get_weights(model)

@spec get_weights(Soothsayer.Model.t()) :: %{
  kernel: Nx.Tensor.t(),
  bias: Nx.Tensor.t()
}

Extracts learned trend weights from a fitted model.

Parameters

Returns

A map with :kernel and :bias tensors.

numeric_to_date(numeric, first_date)

@spec numeric_to_date([number()], Date.t()) :: [Date.t()]

Converts numeric values back to dates.

Parameters

  • numeric - List of numeric values (days since first_date).
  • first_date - Reference date.

Returns

A list of dates.

Examples

iex> Soothsayer.Trend.numeric_to_date([0.0, 1.0], ~D[2023-01-01])
[~D[2023-01-01], ~D[2023-01-02]]