14 #ifndef SRC_INCLUDE_SMASH_LOWESS_H_
15 #define SRC_INCLUDE_SMASH_LOWESS_H_
33 void lowest(
const T *x,
const T *y,
size_t n, T xs, T &ys,
size_t nleft,
34 size_t nright, T *w,
bool userw, T *rw,
bool &ok) {
41 const auto range = x[
n] - x[1];
42 const auto h = std::max(xs - x[nleft], x[nright] - xs);
43 const auto h9 = 0.999 * h;
44 const auto h1 = 0.001 * h;
52 const auto r = std::abs(x[j] - xs);
57 const auto d = (r / h) * (r / h) * (r / h);
58 w[j] = (1. - d) * (1. - d) * (1. - d);
63 }
else if (x[j] > xs) {
70 const auto nrt = j - 1;
76 for (j = nleft; j <= nrt; j++)
81 for (j = nleft; j <= nrt; j++)
85 for (j = nleft; j <= nrt; j++)
86 c += w[j] * (x[j] - a) * (x[j] - a);
87 if (std::sqrt(c) > 0.001 * range) {
90 for (j = nleft; j <= nrt; j++)
91 w[j] *= (b * (x[j] - a) + 1.);
95 for (j = nleft; j <= nrt; j++)
105 template <
typename T>
107 for (
size_t pL = 0, pR =
n - 1; pL < pR;) {
111 for (i = pL, j = pR; i <= j;) {
138 template <
typename T>
139 void lowess(
const T *x,
const T *y,
size_t n, T *ys, T span,
size_t iter,
140 T delta, T *rw, T *res) {
152 constexpr
size_t two = 2;
154 std::max(two, std::min(
n,
static_cast<size_t>(span *
n + 1e-7)));
158 while (iiter <= iter + 1) {
167 const auto d1 = x[i] - x[nleft];
168 const auto d2 = x[nright + 1] - x[i];
180 const bool iterg1 = iiter > 1;
182 lowest(&x[1], &y[1],
n, x[i], ys[i], nleft, nright, res, iterg1, rw, ok);
188 const auto denom = x[i] - x[last];
191 for (
auto j = last + 1; j < i; j++) {
192 const auto alpha = (x[j] - x[last]) / denom;
193 ys[j] = alpha * ys[i] + (1. - alpha) * ys[last];
201 const auto cut = x[last] + delta;
202 for (i = last + 1; i <=
n; i++) {
205 if (x[i] == x[last]) {
210 i = std::max(last + 1, i - 1);
216 for (i = 0; i <
n; i++)
217 res[i] = y[i + 1] - ys[i + 1];
222 for (i = 0; i <
n; i++)
223 rw[i] = std::abs(res[i]);
226 const auto m1 =
n / 2;
232 const auto m2 =
n - m1 - 1;
234 cmad = 3. * (rw[m1] + rw[m2]);
239 const auto c9 = 0.999 * cmad;
240 const auto c1 = 0.001 * cmad;
241 for (i = 0; i <
n; i++) {
249 const auto r = std::abs(res[i]);
254 rw[i] = (1. - (r / cmad) * (r / cmad)) * (1. - (r / cmad) * (r / cmad));
288 template <
typename T>
289 std::vector<T>
smooth(
const std::vector<T> &x,
const std::vector<T> &y,
290 T span = 2. / 3,
size_t iter = 3, T delta = 0) {
291 assert(x.size() == y.size());
292 std::vector<T> result;
293 result.resize(x.size());
297 res.resize(x.size());
298 lowess::lowess(&x.front(), &y.front(), x.size(), &result.front(), span, iter,
299 delta, &rw.front(), &res.front());
void lowest(const T *x, const T *y, size_t n, T xs, T &ys, size_t nleft, size_t nright, T *w, bool userw, T *rw, bool &ok)
Fit value at x[i] Based on R function lowest: Translated to C++ by C.
void psort(T *x, size_t n, size_t k)
Partial sort.
void lowess(const T *x, const T *y, size_t n, T *ys, T span, size_t iter, T delta, T *rw, T *res)
Lowess regression smoother.
constexpr int h1
h₁(1170).
std::vector< T > smooth(const std::vector< T > &x, const std::vector< T > &y, T span=2./3, size_t iter=3, T delta=0)
Apply the LOWESS smoother (see the reference below) to the given data (x, y).