> ## Documentation Index
> Fetch the complete documentation index at: https://nixtla.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Find predictive signals in history

> Rank the features that have been most useful for predicting your target over time.

Use `NixtlaClient.explain()` when someone asks:

> Which signals in my historical data deserve attention?

The result ranks your features using their past relationship with the target.
You do not need to make a forecast or provide future feature values.

> [!NOTE]
>
> The analysis runs as an asynchronous job on the server. `NixtlaClient.explain()`
> submits the job and polls its status until the weights are ready, so the call
> blocks like any other client method. By default the client polls on an
> adaptive cadence -- first after half a second, then doubling up to one check
> every 15 seconds -- and waits up to an hour; pass `poll_interval` for a fixed
> cadence or `poll_timeout` for a different ceiling, or use `NixtlaClient.jobs.explain()` to get a
> `Job` handle back immediately and wait on it yourself. A job that fails
> on the server raises `nixtla.JobError` with the server's original error. Server-side cancellation raises
> `nixtla.JobCancelledError`; exceeding the client wait timeout raises
> `nixtla.JobTimeoutError` and requests cancellation.

> [!WARNING]
>
> These weights are **not** causal. They measure whether a feature's past values
> help predict the target, which is a statement about correlation over time, not
> about cause and effect. A high weight does not mean that changing the feature
> will change the target: both may be driven by something absent from your data,
> or the direction of influence may run the other way. To ask what a forecast is
> sensitive to, use [intervention
> analysis](https://nixtla.io/docs/forecasting/explanation/intervention.md) instead.

## Retail-demand example

The store in our example has one year of daily demand, price, promotion, and
temperature data.

> [accordion] Create the example data
>
> ```python theme={null}
> import numpy as np
> import pandas as pd
>
> from nixtla import NixtlaClient
>
> nixtla_client = NixtlaClient(
>     # Defaults to os.environ["NIXTLA_API_KEY"]
>     api_key="my_api_key_provided_by_nixtla"
> )
>
> rng = np.random.default_rng(7)
> n = 365
> h = 14
> t = np.arange(n + h)
>
> price = 20 + 1.8 * np.sin(2 * np.pi * t / 90) + rng.normal(0, 0.35, n + h)
> promotion = ((t % 42) >= 35).astype(int)
> temperature = (
>     18
>     + 9 * np.sin(2 * np.pi * (t - 30) / 365)
>     + rng.normal(0, 0.8, n + h)
> )
> weekly = 6 * np.sin(2 * np.pi * t / 7)
> demand = (
>     118
>     - 2.4 * price[:n]
>     + 16 * promotion[:n]
>     + 0.55 * temperature[:n]
>     + weekly[:n]
>     + rng.normal(0, 2.0, n)
> )
>
> df = pd.DataFrame(
>     {
>         "unique_id": "store-a",
>         "ds": pd.date_range("2024-01-01", periods=n, freq="D"),
>         "y": demand,
>         "price": price[:n],
>         "promotion": promotion[:n],
>         "temperature": temperature[:n],
>     }
> )
> ```

## Rank the historical signals

Call `explain()` with the features you want to review:

```python theme={null}
signals = nixtla_client.explain(
    df=df,
    features=["price", "promotion", "temperature"],
)

signals
```

| feature | weight | method |
| - | -: | - |
| price | 0.000 | granger |
| promotion | 0.863 | granger |
| temperature | 0.137 | granger |

The weights add up to one. In this historical window, promotion has the
strongest measured signal, followed by temperature. Price does not add a
measurable linear lagged signal in this particular run.

![A horizontal bar chart ranking promotion, temperature, and price as historical predictive signals](https://mintcdn.com/nixtla-enterprise/Z27JIqRDnQ0rRCKY/images/forecasting/explain-retail-historical-signals.png?fit=max\&auto=format\&n=Z27JIqRDnQ0rRCKY\&q=85\&s=206729d60c66f3561f85b650dd63497e)

Promotion is the strongest historical signal in the default analysis. Results were generated with TimeGPT 2.1.

## Use the ranking

This result can help you:

* Decide which data sources deserve closer monitoring.
* Prioritize features for a forecasting experiment.
* Check whether important business signals are present in the data.
* Compare feature rankings across stores, products, or time periods.

It cannot tell you what to change. "Promotion ranks first, so running more
promotions will raise demand" does not follow from this ranking; it is a causal
claim the analysis does not support.

Weights are relative scores. A weight of `0.863` means promotion is the
strongest signal among these three features; it is not a percentage of the
forecast.

## Use your own data

By default, `explain()` analyzes every column except the series ID, timestamp,
and target. Passing `features` makes the scope explicit:

```python theme={null}
signals = nixtla_client.explain(
    df=df,
    features=["price", "promotion", "temperature"],
)
```

For multiple time series, stack the series in the same dataframe and identify
them with `unique_id`. TimeGPT respects the boundary between each series and
returns one combined ranking.

Non-numeric features must be declared as categorical. Any feature that is not
numeric and not listed in `categorical_exog_list` is rejected, naming the
column:

```python theme={null}
df_with_campaign = df.assign(
    campaign=np.where(df["promotion"] == 1, "email", "none")
)

signals = nixtla_client.explain(
    df=df_with_campaign,
    features=["price", "promotion", "temperature", "campaign"],
    categorical_exog_list=["campaign"],
)
```

Both methods are lag-based, so every series must be complete and regularly
spaced. `explain()` infers the frequency from `df`; pass `freq` explicitly for
polars input, or to be strict about which spacing you expect:

```python theme={null}
signals = nixtla_client.explain(df=df, freq="D")
```

> [!NOTE]
>
> Historical signals are especially useful for exploration and feature
> prioritization. Re-run an important analysis on another time period to see
> whether the same signals remain useful.

## Next

* [Explain a forecast with
  SHAP](https://nixtla.io/docs/forecasting/exogenous-variables/interpretability_with_shap.md)
* [Test forecast sensitivity](https://nixtla.io/docs/forecasting/explanation/intervention.md)
* [Compare analyses and check
  stability](https://nixtla.io/docs/forecasting/explanation/advanced-explanations.md)
