Smoothing and spline bases#
Scatterplot smoothing and natural cubic spline bases.
lowess() is Cleveland’s (1979) robust locally weighted regression, and
matches R’s stats::lowess. The n points are sorted by x. The fit at x_i
uses the q = max(2, min(n, floor(span * n + 1e-7))) points nearest to x_i,
which lie within h_i, the distance from x_i to its q-th nearest neighbour
(counting x_i itself). Points at distance r get the tricube weight
(1 - (r / h_i)^3)^3, which is set to 1 for r <= 0.001 h_i and to 0 for
r > 0.999 h_i; when h_i is zero, every point tied with x_i gets weight 1. The
fitted value is that of a weighted least squares line, or of a weighted mean
when the weighted standard deviation of x in the neighbourhood is at most
0.001 times the range of x. A neighbourhood whose weights are all zero keeps
the observed value. Each robustness iteration refits with every weight
multiplied by Tukey’s bisquare (1 - (e_k / s)^2)^2 of the residuals e_k of
the previous fit, with s six times the median absolute residual; the
bisquare is set to 1 for |e_k| <= 0.001 s and to 0 for |e_k| > 0.999 s. The
iterations stop early when s is below 1e-7 times the mean absolute residual.
To save time, points within delta of the last fitted point are not
fitted but interpolated linearly, and points tied with a fitted point share
its value.
choose_lowess_span() is limma’s rule for the span of a LOWESS trend
through n points (limma’s chooseLowessSpan): 1 for n up to small_n
points, and min_span + (1 - min_span) (small_n / n)^power for larger n. With
limma’s settings (small_n = 50, min_span = 0.3, power = 1/3), the
part of the span above 0.3 falls in proportion to n^(-1/3), as the width of a
histogram’s bins does in the rules of Scott (1979) and Freedman and Diaconis
(1981): the span is 1 at 50 points, 0.65 at 400 and 0.395 at 20,000.
natural_spline_basis() returns a basis of the natural cubic splines
with given interior and boundary knots: cubic between the knots, twice
continuously differentiable at simple knots, and linear beyond the boundary
knots. Its column space matches that of R’s splines::ns. The basis is
built from the cubic B-splines on the knot sequence with each boundary knot
repeated four times (de Boor 1978), restricted to the subspace with zero
second derivative at both boundary knots.
References
Cleveland WS (1979). Robust locally weighted regression and smoothing scatterplots. Journal of the American Statistical Association 74, 829-836. doi:10.1080/01621459.1979.10481038
Cleveland WS (1981). LOWESS: a program for smoothing scatterplots by robust locally weighted regression. The American Statistician 35, 54. doi:10.2307/2683591
de Boor C (1978). A Practical Guide to Splines. Springer, New York. doi:10.1007/978-1-4612-6333-3
Freedman D, Diaconis P (1981). On the histogram as a density estimator: L2 theory. Zeitschrift fuer Wahrscheinlichkeitstheorie und verwandte Gebiete 57, 453-476. doi:10.1007/BF01025868
Hastie TJ (1992). Generalized additive models. Chapter 7 of Statistical Models in S, eds Chambers JM and Hastie TJ. Wadsworth & Brooks/Cole, Pacific Grove.
Scott DW (1979). On optimal and data-based histograms. Biometrika 66, 605-610. doi:10.1093/biomet/66.3.605
- cytepool.stats.smoothing.choose_lowess_span(n, *, small_n=50, min_span=0.3, power=1 / 3)#
The span of a LOWESS trend through n points, by limma’s rule.
limma’s
chooseLowessSpan(n, small.n, min.span, power): the span is 1 for n up tosmall_n, andmin_span + (1 - min_span) (small_n / n)^power
for larger n, which falls toward
min_spanas n grows and stays above it. With the defaults, limma’s, the span is 1 up to 50 points, 0.65 at 400 and 0.395 at 20,000. limma tunes the rule for mean-variance trends, which are usually monotonic and so suit large spans;voom()chooses its span with it from the number of features, as limma’svoomdoes.limma computes its formula, capped at 1, for any arguments. This function refuses arguments outside the ranges below, where limma gives NaN for a negative n, and spans below 1 for fewer than
small_npoints for a negativepoweror amin_spanabove 1. At 0 points with amin_spanof 1 or asmall_nof 0, limma’s formula gives NaN, and this function gives 1, as limma’s documentation does.- Parameters:
n – Number of points to smooth, a non-negative integer.
small_n – Number of points up to which the span is 1, a non-negative integer.
min_span – Span that the rule approaches as n grows, in (0, 1].
power – Rate at which the span falls with n, in [0, 1]; 0 gives a span of 1 for every n.
- Returns:
The span, the fraction of the points in each local fit of
lowess(): in [min_span, 1].- Raises:
TypeError – If
norsmall_nis not an integer, ormin_spanorpoweris not a real number.ValueError – If
norsmall_nis negative,min_spanis not in (0, 1], orpoweris not in [0, 1].
Explained in: Precision weights
- cytepool.stats.smoothing.lowess(x, y, *, span=2.0 / 3.0, iterations=3, delta=None)#
Smooth a scatterplot by robust locally weighted linear regression.
Cleveland’s LOWESS, with the conventions of R’s
lowess(x, y, f=span, iter=iterations, delta=delta); the module docstring gives the method. Unlike R, which returns the fitted values sorted by x, the values are returned in the order of the input points. Every point tied in x gets the same fitted value, so the result does not depend on the order of the input points (up to rounding when x has ties).- Parameters:
x –
(n,)finite values of the predictor.y –
(n,)finite values of the response.span – Fraction of the points in each local fit. A span of 1 or more uses all points, as in R; a span below 2 / n still uses two.
iterations – Number of robustness iterations after the first fit.
delta – Distance in x within which a point is interpolated from the neighbouring fits instead of being fitted. Defaults to 1% of the range of x, as in R; 0 fits every distinct x.
- Returns:
(n,)fitted values, in the order ofx. A single point is returned unchanged.- Raises:
TypeError – If an input is not real-valued or is a numpy masked array, or
iterationsis not an integer.ValueError – If
xandyare not 1-D of the same non-zero length or are not finite,spanis not positive and finite,iterationsis negative, ordeltais negative or not finite.
Explained in: Precision weights
- cytepool.stats.smoothing.natural_spline_basis(x, df=None, *, knots=None, intercept=False, boundary_knots=None)#
Basis of natural cubic splines evaluated at x.
The columns span the same space as R’s
splines::ns(x, df=df, knots=knots, intercept=intercept, Boundary.knots=boundary_knots), so a least squares fit on either gives the same fitted values; the columns themselves differ from R’s. Without an intercept the splines are those that vanish at the lower boundary knot, as in R.With
df, thedf - 1 - interceptinterior knots are placed at quantiles of x (R’s default type 7) with probabilities k / (K + 1), k = 1, …, K, over the values of x within the boundary knots. Ties in x can make knots coincide, which lowers the smoothness there as for repeated knots. A knot that falls on a boundary knot is moved inside, as R’snsdoes, by one eighth of its distance to the nearest other knot (first at the lower boundary, then at the upper one).NaN in x gives a row of NaN, as R’s
NAdoes; knots and boundary knots are computed from the other values. Where R’snswarns and increases adfbelow1 + intercept, or accepts a knot on the lower boundary knot (returning a basis with a degenerate column), this function raises an error.- Parameters:
x –
(n,)values at which to evaluate the basis; NaN marks a missing value.df – Number of columns. Give
dforknots; given both, they must agree.knots – Interior knots (one or a sequence), strictly inside the boundary knots; repeated knots are allowed. Defaults to none, or to quantiles when
dfis given.intercept – Whether the basis spans constant functions.
boundary_knots – The two knots beyond which the splines are linear. Defaults to the range of the observed values of x; given in either order.
- Returns:
(n, df)matrix, withdf = len(knots) + 1 + intercept.- Raises:
TypeError – If an input is not real-valued or is a numpy masked array,
dfis not an integer orinterceptis not a bool.ValueError – If
xis not 1-D or has infinite values,dfis too small, knots are not finite or not strictly inside the boundary knots, the boundary knots are not two distinct finite values, or there are too few values of x to place the knots.
Explained in: Empirical Bayes moderation and TREAT