leo.blog();

Partial moments and NNS for financial ML

Partial moments and NNS for financial ML

Explored after seeing a CrowdCent participant use ovvo-nns. Their competition performance alone doesn't establish whether the method is useful.

What NNS is

In this context, Nonlinear Nonparametric Statistics (NNS) is a specific framework built around partial moments, associated with Fred Viole and the book by Viole and David Nawrocki, Nonlinear Nonparametric Statistics: Using Partial Moments.

ovvo-nns is a native Python port of the R NNS package, imported as nns. It includes descriptive statistics, dependence measures, regression, classification, forecasting, and stochastic dominance tools. It is more than a feature-engineering library.

Partial moments

For observations \(x_i\), threshold \(t\), and degree \(p>0\):

\[ \operatorname{LPM}_p(t)=\frac{1}{N}\sum_i \max(t-x_i,0)^p \]
\[ \operatorname{UPM}_p(t)=\frac{1}{N}\sum_i \max(x_i-t,0)^p \]

Divide by all observations, not just those on the relevant side. These measure frequency and magnitude together, rather than the conditional average loss or gain.

The threshold is sometimes called a target, but this is not the prediction label! For returns, zero is a useful threshold; the sample mean is useful for decomposing variance. Other thresholds could represent a benchmark or minimum acceptable return.

Python implementation

import numpy as np

def partial_moments(x, degree=2, target=0.0):
    """Return (LPM, UPM), normalized by the total observation count."""
    x = np.asarray(x, dtype=float)
    if x.ndim != 1 or x.size == 0 or not np.isfinite(x).all():
        raise ValueError("x must be a nonempty, finite, 1-D array")
    if not np.isfinite(degree) or degree < 0:
        raise ValueError("degree must be finite and nonnegative")
    if not np.isfinite(target):
        raise ValueError("target must be finite")

    # Explicit degree-zero convention: assign ties to the lower side.
    # Avoid raising clipped zeros to power zero, which would count both sides.
    if degree == 0:
        return np.mean(x <= target), np.mean(x > target)

    lower = np.maximum(target - x, 0)
    upper = np.maximum(x - target, 0)
    return np.mean(lower ** degree), np.mean(upper ** degree)

Recovering variance

x = np.array([-2.0, -1.0, 0.0, 3.0])
mu = x.mean()
lower, upper = partial_moments(x, degree=2, target=mu)

variance = lower + upper                  # 3.5 == np.var(x)
sample_variance = variance * len(x) / (len(x) - 1)
assert np.isclose(variance, np.var(x))
assert np.isclose(sample_variance, np.var(x, ddof=1))

Here the downside contribution is 1.25 and the upside contribution is 2.25. Variance hides that split.

For any threshold \(t\):

\[ \operatorname{LPM}_2(t)+\operatorname{UPM}_2(t) =\operatorname{Var}_{ddof=0}(x)+(\bar{x}-t)^2. \]

The sum is variance only when centered at the mean.

Higher and fractional degrees

Fractional degrees work too. For example, a deviation four times larger receives \(4^{0.5}=2\) times the weight at degree 0.5, versus 16 times at degree 2.

For every \(p>0\):

\[ \operatorname{LPM}_p(t)+\operatorname{UPM}_p(t) =\frac{1}{N}\sum_i |x_i-t|^p. \]

These are absolute moments about the threshold, including at fractional degrees. Degrees below one reduce the relative emphasis on large deviations, but are not immune to outliers: their contribution still grows without bound.

Taking a partial moment to the power \(1/p\) restores the units of the original data. This rooted measure scales linearly with positive changes of scale for every \(p>0\); degree 0.5 is not uniquely more scale-sensitive.

Potential ML features

For Machine learning or Algorithmic trading, compute over trailing windows per asset:

These add representations, not new information. Explicit aggregation may help a neural network learn with less data, particularly when the target signal is weak. But there is no established reason to expect larger gains for an NN than a GBM: ReLU represents the positive-part function exactly, and either model's benefit depends on its inputs and training.

Neighboring degrees may be highly redundant. Heavy-tailed features may benefit from scaling, clipping, or per-date cross-sectional ranks. Choose preprocessing using training data and the actual prediction setup. No degree is known in advance to be best.

Does NNS use prediction targets?

Partial-moment features can still leak information if their windows include unavailable observations or if thresholds/preprocessing are estimated from future data. Use only information available at prediction time; shift rolling windows when the timing requires it.

How to evaluate

  1. Start with the existing model and feature baseline.
  2. Add a small set of partial-moment features over a few meaningful windows.
  3. Compare on time-based validation, accounting for overlapping label horizons.
  4. Inspect consistency across periods and, for NNs, multiple seeds.
  5. Keep features based on held-out improvement, not appealing formulas or in-sample dependence.

Avoid interpreting the package's breadth as evidence of predictive advantage. We reviewed its PyPI documentation, not its implementation or independent benchmarks; precise algorithmic and parity claims need source verification.

References

Leave a Comment