## [R] translation of lowess_module.f90 ## Dan Gavin; Mar 1, 2008 ## Fortran code is commented out ## module lowess ## contains ## subroutine lowess_curve(nctrl,xin,yin,ntarg,xt,wintype="w",order=0, nrobust=0,width=300,yfit) ## manages computation of a lowess "curve" lowess_curve<-function(xin,yin,xt,width=300,wintype="w",order=0,nrobust=0){ ## xin=array of x values ## yin=array of y values ## xt=array of target x values to fit loess. Use seq(low,high,step). ## wintype= "s" to use obs in width proportion of data ## wintype= "w" to use obs within plus or minus window half-width (width) ## order=0,1,2 (median, linear, quadratic) ## nrobust=number of robustifying iterations ## implicit none ## integer :: nctrl,ntarg ## real(8) :: xin(nctrl),yin(nctrl),xt(ntarg),width,yfit(ntarg),y0 ## real(8) :: xs(nctrl),ys(nctrl),targ,fitval,lwmean1,lwmean2,newwidth ## integer :: order,nrobust ## integer :: np ## character(1) :: wintype ## logical :: monotonic,yfitnan ## integer :: i,ii,iii,j,k y0 <- 0.0 xs<-xin ys<-yin ntarg<-length(xt) nctrl<-length(xin) yfit<-array(NA,ntarg) stderr<-array(NA,ntarg) #!write (*,*) nctrl,ntarg #!write (*,'(8f10.2)') xs #!write (*,'(8f10.4)') ys #!write (*,'(8f10.2)') xt #!pause #! sort the input data by x-values if necessary # monotonic=.true. # do i=2,nctrl # if (xs(i).lt.xs(i-1)) then # monotonic=.false. # ! write (*,'("xs(i),xs(i-1) non-monotonic: ",i6,2f14.6)') i,xs(i),xs(i-1) # end if #end do #if (.not. monotonic) then # ! write (*,'(a)') "Note: input x's were not monotonic" # ! write (10,'(a)') "Note: input x's were not monotonic" # call sortxy(nctrl,xin,yin,xs,ys) !sortxy replaced by R command 'order' #end if yin<-yin[order(xin)] xs<-xs[order(xin)] ys<-ys[order(xin)] xin<-xin[order(xin)] # ! loop over target points, calling localfit for each target point for(ii in 1:ntarg){ # do ii=1,ntarg targ<-xt[ii] # targ=xt(ii) # call localfit(nctrl,xs,ys,targ,wintype,width,order,nrobust,fitval,lwmean1) # yfit(ii)=fitval fitted<-localfit(nctrl,xs,ys,targ,wintype,width,order,nrobust) yfit[ii]<-fitted[1] stderr[ii]<-fitted[2] } #end do # !write (*,*) ii,targ,yfit(ii),lwmean1 return(data.frame(xt,yfit,stderr)) } #end subroutine lowess_curve # subroutine localfit(nctrl,xs,ys,targval,wintype,width,order,nrobust,fitval) # ! gets a lowess-type fitted value at a particular target point localfit <- function(nctrl,xs,ys,targval,wintype,width,order,nrobust){ #implicit none #integer :: nctrl #real(8) :: targval,width,fitval,lwmean #real(8) :: xs(nctrl),ys(nctrl),x(nctrl),y(nctrl) #real(8) :: w(nctrl),wsum,ywm,ym,ystd #real(8) :: b0,b1,b2,yhat(nctrl),resid(nctrl),mse,stderr,rsq #real(8) :: dmax,diff,u,ul,ll #real(8) :: r(nctrl),median,rmedx6,ru,rw(nctrl) #integer :: order,nrobust #integer :: np,np2,npts,low,high,nonzero #character(1) :: wintype #integer :: i,ii,iii,j #!write (*,*) nctrl #!write (*,'(8f10.2)') xs #!write (*,'(8f10.4)') ys #!write (*,'(8f10.2)') targval x<-array(NA,nctrl) y<-array(NA,nctrl) r<-array(NA,nctrl) rw<-array(NA,nctrl) #! select data to use for a specific fitted value if(wintype=="s"){ #if (wintype.eq.'s') then #! find observations in width proportion of data npts<-floor(width*nctrl) #npts=int(width*nctrl) np2<-npts/2 #np2=npts/2 low<-ii-np2 #low=ii-np2 high<-ii+np2 #high=ii+np2 if(low<1){ #if (low.lt.1) then low<-1 #low=1 high<-low+npts #high=low+npts } # end if if(high>nctrl){ #if (high.gt.nctrl) then high<-nctrl #high=nctrl low<-nctrl-npts #low=nctrl-npts } #end if np<-high-low+1 #np=high-low+1 i<-0 #i=0 for(iii in low:high){ #do iii=low,high i<-i+1 #i=i+1 x[i]<-xs[iii] #x(i)=xs(iii) y[i]<-ys[iii] #y(i)=ys(iii) } #end do # ! get distance weights dmax<-0 #dmax=0.0d0 for(i in 1:np){ #do i=1,np diff<-x[i]-targval #diff=x(i)-targval if(abs(diff)>dmax) dmax<-abs(diff) #if (dabs(diff).gt.dmax) dmax=dabs(diff) } #end do w<-array(NA,np) for(i in 1:np){ #do i=1,np u<-abs(x[i]-targval)/dmax #u=dabs(x(i)-targval)/dmax if(u>1) u<-1.0 #if (u.gt.1.0d0) u=1.0d0 w[i]<-(1-u^3)^3 #w(i)=(1.0d0-u**3.0d0)**3.0d0 } #end do } else { #else if (wintype.eq.'w') then #assume 'w' #! find observations within plus or minus window half-width (width) ul<-targval+width #ul=targval+width ll<-targval-width #ll=targval-width i<-0 #i=0 for(iii in 1:nctrl){ #do iii=1,nctrl if(!is.na(xs[iii])){ if(xs[iii]>ll && xs[iii]1) u<-1.0 #if (u.gt.1.0d0) u=1.0d0 w[i]<-(1-u^3)^3 #w(i)=(1.0d0-u**3.0d0)**3.0d0 } #end do } #end if # ! get a locally weighted mean # call wm(np,y,w,lwmean,resid) resid<-wm_resid(np,y,w) fitval<-NA # fitval=0.0d0/0.0d0 ! set to NaN initially seval<-NA # ! set initial robustness weights equal to distance weights nonzero<-0 #nonzero=0 for(i in 1:np){ #do i=1,np rw[i]<-w[i] #rw(i)=w(i) if(rw[i] != 0.0) nonzero <- nonzero+1 #if (rw(i).ne.0.0d0) nonzero=nonzero+1 #!write (*,*) i,w(i),rw(i) } #end do #! robustness iterations for(j in 0:nrobust){ #do j=0,nrobust #! lowess regressions #select case (order) if(order==0){ #case (0) #! (distance) weighted mean fitval <- wm(np,y,rw) ## call wm(np,y,rw,ywm,resid) seval <- wm_resid(np,y,w) # fitval=ywm } #end if if(order==1){ #case (1) #! distance-weighted linear regression if(nonzero>3){ #if (nonzero.gt.3) then #call fitline(np,x,y,rw,b0,b1,yhat,resid,mse,stderr,rsq) fitout <- fitline(np,x,y,rw) fitval <- fitout$b0+fitout$b1*targval seval <- fitout$stderr } #end if } #end if if(order==2){ #case (2) #! distance-weighted quadratic regression if(nonzero>8){ #if (nonzero.gt.8) then #call fitquad(np,x,y,rw,b0,b1,b2,yhat,resid,mse,stderr,rsq) fitout <- fitquad(np,x,y,rw) #fitval=b0+b1*targval+b2*targval*targval fitval<-fitout$b0+fitout$b1*targval+fitout$b2*targval*targval seval<-fitout$stderr } #end if } #end if #case default # write (*,*) "Polynomial order not supported...." # stop if(order>2){ print("Polynomial order not supported....") break } #end select #! robustness weights if(nrobust!=0 && j1) ru<-1.0 #if (ru.gt.1.0d0) ru=1.0d0 r[i]<-(1-ru^2)^2 #r(i)=(1.0d0-ru**2.0d0)**2.0d0 rw[i]<-w[i]*r[i] #rw(i)=w(i)*r(i) if(rw[i] != 0) nonzero <- nonzero+1 #if (rw(i).ne.0.0d0) nonzero=nonzero+1 } #end do } #end if } #end do (next j , robust step) #!write (*,*) lwmean,fitval #!pause return(c(fitval,seval)) } #end subroutine localfit # subroutine wm(npts,y,w,ywm,dev) wm <- function(npts,y,w){ #! weighted mean --this function returns the weighted mean #implicit none #integer :: npts #real(8) :: y(npts),w(npts),dev(npts) #real(8) :: wsum,ywm,ym #integer :: i dev<-array(NA,npts) ym<-0.0 #ym=0.0d0 ywm<-0.0 #ywm=0.0d0 wsum<-0.0 #wsum=0.0d0 for(i in 1:npts){ #do i=1,npts ym<-ym+y[i] #ym=ym+y(i) ywm<-ywm+y[i]*w[i] #ywm=ywm+y(i)*w(i) wsum<-wsum+w[i] #wsum=wsum+w(i) } #end do if(wsum>0.0){ #if (wsum.gt.0.0) then ywm<-ywm/wsum } else { ywm<-ym/npts #ywm=ym/dble(npts) } #end if return(ywm) } #end subroutine wm wm_resid <- function(npts,y,w){ #! weighted mean --this function returns the deviations #implicit none #integer :: npts #real(8) :: y(npts),w(npts),dev(npts) #real(8) :: wsum,ywm,ym #integer :: i dev<-array(NA,npts) ym<-0.0 #ym=0.0d0 ywm<-0.0 #ywm=0.0d0 wsum<-0.0 #wsum=0.0d0 for(i in 1:npts){ #do i=1,npts ym<-ym+y[i] #ym=ym+y(i) ywm<-ywm+y[i]*w[i] #ywm=ywm+y(i)*w(i) wsum<-wsum+w[i] #wsum=wsum+w(i) } #end do if(wsum>0.0){ #if (wsum.gt.0.0) then ywm<-ywm/wsum } else { ywm<-ym/npts #ywm=ym/dble(npts) } #end if for(i in 1:npts){ #do i=1,npts dev[i]<-y[i]-ywm #dev(i)=y(i)-ywm } #end do return(dev) } #end subroutine wm #subroutine fitline(npts,x,y,w,b0,b1,yhat,resid,mse,stderr,rsq) fitline <- function(npts,x,y,w){ #! simple weighted linear regression #implicit none #integer :: npts #real(8) :: x(npts),y(npts),w(npts),b0,b1,yhat(npts),resid(npts) #real(8) :: xm,ym,wsum,sxx,sxy,sse,sst,mse,stderr,sratio,rsq #integer :: i yhat<-array(NA,npts) resid<-array(NA,npts) #xm=0.0d0; ym=0.0d0; wsum=0.0d0; sxx=0.0d0; sxy=0.0d0 xm<-0 ym<-0 wsum<-0 sxx<-0 sxy<-0 for(i in 1:npts){ #do i=1,npts wsum<-wsum+w[i] #wsum=wsum+w(i) xm<-xm+x[i]*w[i] #xm=xm+x(i)*w(i) ym<-ym+y[i]*w[i] #ym=ym+y(i)*w(i) #!write (*,*) i,x(i),y(i),w(i) } #end do xm<-xm/wsum #xm=xm/wsum ym<-ym/wsum #ym=ym/wsum #!write (*,*) xm,ym,wsum for(i in 1:npts){ #do i=1,npts sxx<-sxx+((x[i]-xm)^2.0)*w[i] #sxx=sxx+((x(i)-xm)**2.0d0)*w(i) sxy<-sxy+(x[i]-xm)*(y[i]-ym)*w[i] #sxy=sxy+(x(i)-xm)*(y(i)-ym)*w(i) } #end do b1<-sxy/sxx #b1=sxy/sxx b0<-ym-(b1*xm) #b0=ym-(b1*xm) sse<-0.0 sst<-0.0 #sse=0.0d0; sst=0.0d0 for(i in 1:npts){ #do i=1,npts yhat[i]<-b0+b1*x[i] #yhat(i)=b0+b1*x(i) resid[i]<-y[i]-yhat[i] #resid(i)=y(i)-yhat(i) sse<-sse+(resid[i]*sqrt(w[i]))^2.0 #sse=sse+(resid(i)*dsqrt(w(i)))**2.0d0 sst<-sst+((y[i]-ym)*sqrt(w[i]))^2.0 #sst=sst+((y(i)-ym)*dsqrt(w(i)))**2.0d0 } #end do mse<-sse/(npts-2) #mse=sse/dble(npts-2) stderr<-sqrt(mse) #stderr=dsqrt(mse) rsq <- -1.0 #rsq=-1.0d0 sratio<-sse/sst #sratio=sse/sst #if (sratio.le.1.0d0 .and. sratio.ge.0.0d0) rsq=1.0d0-sratio if(sratio<1.0 && sratio>0.0) rsq<-1.0-sratio return(data.frame(b0,b1,mse,stderr,rsq)) } #end subroutine fitline #subroutine fitquad(npts,x1,y,w,b0,b1,b2,yhat,resid,mse,stderr,rsq) #! simple weighted quadratic regression fitquad <- function(npts,x1,y,w){ #implicit none #integer :: npts #real(8) :: x1(npts),x2(npts),y(npts),w(npts),b0,b1,b2,yhat(npts),resid(npts) #real(8) :: x1m,x2m,ym,wsum,sx1x1,sx2x2,sx1x2,sx1y,sx2y,sse,sst,mse,stderr,sratio,rsq #real(8) :: bx1y,bx2y,bx2x1,bx1x2 #integer :: i x2<-array(NA,npts) yhat<-array(NA,npts) resid<-array(NA,npts) #x1m=0.0d0; x2m=0.0d0; ym=0.0d0; wsum=0.0d0 x1m<-0.0 x2m<-0.0 ym<-0.0 wsum<-0.0 sx1x1<-0.0 sx2x2<-0.0 sx1x2<-0.0 sx1y<-0.0 sx2y<-0.0 for(i in 1:npts){ #do i=1,npts x2[i]<-x1[i]^2 #x2(i)=x1(i)**2.0d0 wsum<-wsum+w[i] #wsum=wsum+w(i) x1m<-x1m+x1[i]*w[i] #x1m=x1m+x1(i)*w(i) x2m<-x2m+x2[i]*w[i] #x2m=x2m+x2(i)*w(i) ym<-ym+y[i]*w[i] #ym=ym+y(i)*w(i) } #end do x1m<-x1m/wsum #x1m=x1m/wsum x2m<-x2m/wsum #x2m=x2m/wsum ym<-ym/wsum #ym=ym/wsum for(i in 1:npts){ #do i=1,npts sx1x1<-sx1x1+((x1[i]-x1m)^2)*w[i] #sx1x1=sx1x1+((x1(i)-x1m)**2.0d0)*w(i) sx2x2<-sx2x2+((x2[i]-x2m)^2)*w[i] #sx2x2=sx2x2+((x2(i)-x2m)**2.0d0)*w(i) sx1x2<-sx1x2+(x1[i]-x1m)*(x2[i]-x2m)*w[i] #sx1x2=sx1x2+(x1(i)-x1m)*(x2(i)-x2m)*w(i) sx1y<-sx1y+(x1[i]-x1m)*(y[i]-ym)*w[i] #sx1y=sx1y+(x1(i)-x1m)*(y(i)-ym)*w(i) sx2y<-sx2y+(x2[i]-x2m)*(y[i]-ym)*w[i] #sx2y=sx2y+(x2(i)-x2m)*(y(i)-ym)*w(i) } #end do bx1y<-sx1y/sx1x1 #bx1y=sx1y/sx1x1 ! b12 bx2y<-sx2y/sx2x2 #bx2y=sx2y/sx2x2 ! b13 bx2x1<-sx1x2/sx2x2 #bx2x1=sx1x2/sx2x2 ! b32 bx1x2<-sx1x2/sx1x1 #bx1x2=sx1x2/sx1x1 ! b23 b1<-(bx1y-bx2y*bx1x2)/(1.0-bx1x2*bx2x1) #b1=(bx1y-bx2y*bx1x2)/(1.0d0-bx1x2*bx2x1) b2<-(bx2y-bx1y*bx2x1)/(1.0-bx1x2*bx2x1) #b2=(bx2y-bx1y*bx2x1)/(1.0d0-bx1x2*bx2x1) b0<-ym-(b1*x1m)-(b2*x2m) #b0=ym-(b1*x1m)-(b2*x2m) sse<-0.0 #sse=0.0d0; sst=0.0d0 sst<-0.0 for(i in 1:npts){ #do i=1,npts yhat[i]<-b0+b1*x1[i]+b2*x2[i] #yhat(i)=b0+b1*x1(i)+b2*x2(i) resid[i]<-y[i]-yhat[i] #resid(i)=y(i)-yhat(i) sse<-sse+(resid[i]*sqrt(w[i]))^2 #sse=sse+(resid(i)*dsqrt(w(i)))**2.0d0 sst<-sst+((y[i]-ym)*sqrt(w[i]))^2 #sst=sst+((y(i)-ym)*dsqrt(w(i)))**2.0d0 } #end do mse<-sse/(npts-2) #mse=sse/dble(npts-2) stderr<-sqrt(mse) #stderr=dsqrt(mse) rsq<- -1.0 #rsq=-1.0d0 sratio<-sse/sst #sratio=sse/sst if(sratio<1 && sratio>0) rsq <- 1-sratio #if (sratio.le.1.0d0 .and. sratio.ge.0.0d0) rsq=1.0d0-sratio return(data.frame(b0,b1,b2,yhat,mse,stderr,rsq)) } #end subroutine fitquad # end module lowess