https://github.com/cran/IDPmisc
Raw File
Tip revision: f5c0af4bb057bde4d584a4ae0cf32bfd5c76df60 authored by Christoph Hofer on 08 February 2024, 23:50:10 UTC
version 1.1.21
Tip revision: f5c0af4
lwreg.c
/*
 * This is a C-program called by R. It is the core piece in a lowess-like
 * smoothing procedure. The idea is borrowed from Cleveland's FORTRAN
 * implementaion (see lowess.f on STATLIB).
 *
 * ARu, April 1999; modified April 2004
 *
 * Compiled by R CMD SHLIB locreg.c (2004)
 */

/* -----------------------  Some definitions  --------------------------- */

#include <R.h>     /* R header  */

#define	min(a, b)	( ((a) < (b)) ? (a) : (b) )
#define	max(a, b)	( ((a) > (b)) ? (a) : (b) )
#define	sign(a)		( ((a) == 0) ? 0 : (((a) > 0) ? 1 : -1) )

/* -------------------- lowreg is called by R ---------------------- */

/*       Purpose
 *
 *       LWREG computes the smooth of a scatterplot of Y  against X  using
 *       locally  weighted regression, where the weights may include robust
 *       weights.  Fitted values, yfit, are computed at each of the  values
 *       of  the  horizontal axis in x.

 *   Parameter - passing:
 *       x = Input; abscissas of the points on the scatterplot;
 *           the values in X must be ordered from smallest to largest.
 *       y = Input; ordinates of the points on the scatterplot.
 *       n = Input; dimension of x, y, ow, and yfit.
 *       f = Input; specifies the amount of smoothing; f is the number of
 *           points used to compute each fitted value.
 *   delta = Input; nonnegative parameter which may be used to save
 *           computations.
 *      ow = Input; Weights; ow(i) is the weight given to the point
 *           (x(i), y(i)); if neither robustness nor heteroscedasticy is
 *           considered, these weights are all 1.
 *    yfit = Output; fitted values; yfit(i) is the fitted value at x(i).
 *
 */

void lwreg(double x[], double y[], int *n, int *f, double *delta,
	   double ow[], double yfit[])

{
  int nleft, nright, nrt, last, icp, j;
  double range, d1, d2, denom, sow, a, b, c, r, cut, h, h9, h1, *w;

  /* w = Salloc(*n, double); */
  w = (double *) R_alloc(*n, sizeof(double));

/* ------------------------------ body ---------------------------------- */

  if (*n < 2){ yfit[0] = y[0]; return; };  /* Just in case ... */

  range = x[*n-1]-x[0];
  nleft = 0; nright = *f-1;
  last = -1;       /* index of prev estimated point */
  icp = 0;        /* index of current point */
  do { /* beginning of repeat-until loop */
    while(nright < *n-1){
      /*  move nleft, nright to right if radius decreases */
      d1 = x[icp] - x[nleft];
      d2 = x[nright+1] - x[icp];
      /* if d1<=d2 with x(nright+1)==x(nright), lowest fixes */
      if (d1 <= d2) break;
      /* radius will not decrease by move right */
      nleft = nleft+1;
      nright = nright+1;
    }

    /* The  fitted  value, yfit[i], is computed  at  the  value,  x[i],
     * of  the   horizontal   axis.                                   */
    h = max(x[icp] - x[nleft],x[nright] - x[icp]);
    h9 = .999*h;
    h1 = .001*h;
    sow = 0.0;        /* sum of weights  */
    for(j=nleft; j<*n; j++){
      /* compute kernel weights (pick up all ties on right) */
      w[j] = 0.0;
      r = fabs(x[j]-x[icp]);
      if (r<=h9) {    /* small enough for non-zero weight */
	if (r>h1) w[j] = pow((1.0-pow((r/h),3)),3);
	else      w[j] = 1.0;
	w[j] = ow[j]*w[j];
	sow = sow + w[j];
      }
      else{
	if(x[j] > x[icp]) break;   /* get out at first zero wt on right */
      }
    }
    nrt=j-1;     /* rightmost pt (may be greater than nright because of ties*/
  if (sow <= 0.0) yfit[icp] = y[icp];
  else { /* weighted least squares   */
    for(j = nleft; j <= nrt; j++) w[j] = w[j]/sow; /* make sum of w[j] == 1 */
    if (h > 0.0) { /* use linear fit */
      a = 0.0;
      for(j = nleft; j <= nrt; j++)
	a = a+w[j]*x[j];   /* weighted center of x values */
      b = x[icp] - a;
      c = 0.0;
      for(j = nleft; j <= nrt; j++) c = c + w[j]*(x[j]-a)*(x[j]-a);
      if(sqrt(c)>.001*range) {
	/*  points are spread out enough to compute slope  */
	b = b/c;
	for(j = nleft; j <= nrt; j++) w[j] = w[j]*(1.0+b*(x[j]-a));
      }
    }
    yfit[icp] = 0.0;
    for(j = nleft; j <= nrt; j++) yfit[icp] = yfit[icp]+w[j]*y[j];
  }

    /* Move forward */
    if (last < icp-1) { /* skipped points -- interpolate */
      denom = x[icp] - x[last];    /* non-zero - proof? */
      for(j=last+1; j<icp; j++){
	a = (x[j] - x[last])/denom;
	yfit[j] = a * yfit[icp] + (1.0 - a) * yfit[last];
      }
    }
    last = icp;                        /* last point actually estimated      */
    cut = x[last] + *delta;            /* x coord of close points            */
    for(icp = last+1; icp < *n; icp++){/* find close points                  */
      if(x[icp] > cut) break;          /* i one beyond last point within cut */
      if(x[icp] == x[last]){           /* exact match in x                   */
	yfit[icp] = yfit[last];
	last = icp;
      }
    }
    icp = max(last+1,icp-1);  /* back 1 point so interpolation within delta,
                                 but always go forward                      */
  } while(last < (*n - 1));   /* end of repeat-until loop */

  return;
}

back to top