knitr::opts_chunk$set(echo = TRUE)
library(dSTEM) library(latex2exp) set.seed(2021)
A new generic and low-computational approach for multiple change points detection in linear models. The method is designed for the data sequence modeled as piecewise linear signal plus correlated random noise (a stationary Gaussian process). See the related papers: "Multiple testing of local extrema for detection of change points" and "Multiple testing of local extrema for detection of structural breaks in piecewise linear models".
The core idea of our method is to transform the change points into local maxima/minima of the differential smoothed data. By performing multiple testing on the local maxima/minima, the significant ones are detected as change points.
For example, a continuous change point will be transformed into a local maximum/minimum in the second derivative of the smoothed data, while a noncontinuous change point will be transformed into a local maximum/minimum in the first derivative of the smoothed data. A toy example is illustrated as follows
k1 = 0.08 k2 = 0.15 gamma=8 v = 100 # change point location c = 4 # bandwidth of smoothing kernel d1mu = function(x) a/gamma*dnorm((v-x)/gamma)+(k1-k2)*pnorm((v-x)/gamma)+k2 d2mu = function(x) (a*(v-x)+(k2-k1)*gamma^2)/gamma^3*dnorm((v-x)/gamma) #par(mfrow=c(3,3),mar=c(2,2.5,2,0.5)) par(mfrow=c(3,3),mar=c(4,4,2,1)) #### Type I change Point a = 0 b = a - (k2-k1)*v xmax = 200 ymax = k2*xmax+b x = 1:xmax curve(k1*x,0,floor(xmax/2),xlim = c(0,xmax),ylim=c(0,ymax+1),lwd=2,xlab="(a)",ylab="Scenario 1",main=TeX("$\\mu(t)$")) curve(k2*x+b,floor(xmax/2),xmax,add=TRUE,lwd=2,xlab="",ylab="") points(x=v,y=k1*v,pch=16) points(x=v,y=k2*v+b,pch=1) abline(v=v,col="red",lty=2) y = d1mu(x) plot(loess(y~x,span=0.6),type="l",lwd=2,xlab="(b)",ylab="",main=TeX("$\\mu_{\\gamma}^{\\prime}(t)$")) abline(v=v,col="red",lty=2,lwd=1) points(x = c(v-c*gamma,v+c*gamma),y=y[c(v-c*gamma,v+c*gamma)],pch =16 ,col="blue") y = d2mu(x) plot(loess(y~x,span=0.6),type="l",lwd=2,xlab="(c)",ylab="",main=TeX("$\\mu_{\\gamma}^{\\prime\\prime}(t)$")) abline(v=v,col="red",lty=2,lwd=1) points(x = c(v-c*gamma,v+c*gamma),y=y[c(v-c*gamma,v+c*gamma)],pch =16 ,col="blue") #### Type II Change Point a = 3 b = a - (k2-k1)*v xmax = 200 ymax = k2*xmax+b x = 1:xmax curve(k1*x,0,floor(xmax/2),xlim = c(0,xmax),ylim=c(0,ymax+1),lwd=2,xlab="(d)",ylab="Scenario 2") curve(k2*x+b,floor(xmax/2),xmax,add=TRUE,lwd=2,xlab="",ylab="") points(x=v,y=k1*v,pch=16) points(x=v,y=k2*v+b,pch=1) abline(v=v,col="red",lty=2) y = d1mu(x) plot(loess(y~x,span=0.6),type="l",lwd=2,xlab="(e)",ylab="") abline(v=v,col="red",lty=2,lwd=1) points(x = c(v-c*gamma,v+c*gamma),y=y[c(v-c*gamma,v+c*gamma)],pch =16 ,col="blue") y = d2mu(x) plot(loess(y~x,span=0.6),type="l",lwd=2,xlab="(f)",ylab="") abline(v=v,col="red",lty=2,lwd=1) points(x = c(v-c*gamma,v+c*gamma),y=y[c(v-c*gamma,v+c*gamma)],pch =16 ,col="blue") #### Mixture of Type I and Type II Change Points a = 0 b = a - (k2-k1)*v xmax1 = 200 ; xmax2 = 300 ymax = k2*xmax1+b x = 1:xmax2 a3 = -3 ; k3 = 0 ; v3 = xmax1 b3 = a3 - (k3-k2)*v3 +b curve(k1*x,0,floor(xmax1/2),xlim = c(0,xmax2),ylim=c(0,ymax+1),lwd=2,xlab="(g)",ylab="Scenario 3") curve(k2*x+b,floor(xmax1/2),xmax1,add=TRUE,lwd=2,xlab="",ylab="") points(x=v,y=k1*v,pch=16) abline(v=v,col="red",lty=2) curve(k3*x+b3,xmax1,xmax2,add=TRUE,lwd=2,xlab="",ylab="") abline(v=v3,col="red",lty=2) points(x=v3,y=k2*v3+b,pch=16) points(x=v3,y=k3*v3+b3,pch=1) # y1 = d1mu(x[1:floor(xmax2/2)]) plot(loess(y1~x[1:floor(xmax2/2)],span=0.6),type="l",lwd=2,xlab="(h)",ylab="",xlim=c(0,xmax2),ylim=c(-0.10,0.15)) abline(v=v,col="red",lty=2,lwd=1) points(x = c(v-c*gamma,v+c*gamma),y=y1[c(v-c*gamma,v+c*gamma)],pch =16 ,col="blue") k1=k2;k2=k3;a=a3;v=v3 y2 = d1mu(x[floor(xmax2/2):xmax2]) lines(loess(y2~x[floor(xmax2/2):xmax2],span=0.6),lwd=2,xlab="",ylab="") abline(v=v3,col="red",lty=2,lwd=1) points(x = c(v3-c*gamma,v3+c*gamma),y=y2[c(v3-c*gamma,v3+c*gamma)-floor(xmax2/2)],pch =16 ,col="blue") # k1 = 0.08;k2 = 0.15;v = 100;a = 0 y1 = d2mu(x[1:floor(xmax2/2)]) plot(loess(y1~x[1:floor(xmax2/2)],span=0.6),type="l",lwd=2,xlab="(i)",ylab="",xlim=c(0,xmax2),ylim=c(-0.016,0.007)) abline(v=v,col="red",lty=2,lwd=1) points(x = c(v-c*gamma,v+c*gamma),y=y1[c(v-c*gamma,v+c*gamma)],pch =16 ,col="blue") k1=k2;k2=k3;a=a3;v=v3 y2 = d2mu(x[floor(xmax2/2):xmax2]) lines(loess(y2~x[floor(xmax2/2):xmax2],span=0.6),lwd=2,xlab="",ylab="") abline(v=v3,col="red",lty=2,lwd=1) points(x = c(v3-c*gamma,v3+c*gamma),y=y2[c(v3-c*gamma,v3+c*gamma)-floor(xmax2/2)],pch =16 ,col="blue")
The main function is 'dstem()', which detect the change points in piecewise constant and piecewise linear signals.
l = 1200 h = seq(150,by=150,length.out=6) jump = rep(0,7) beta1 = c(2,-1,2.5,-3,-0.2,2.5)/50 beta1 = c(beta1,-sum(beta1*(c(h[1],diff(h))))/(l-tail(h,1))) signal = gen.signal(l,h,jump,beta1) noise = rnorm(length(signal),0,1) gamma = 25 unlist(dstem(signal + noise,"I",gamma=gamma,alpha=0.05)) ## piecewise constant l = 1200 h = seq(150,by=150,length.out=6) jump = c(0,1.5,2,2.2,1.8,2,1.5) beta1 = rep(0,length(h)+1) signal = gen.signal(l,h,jump,beta1) noise = rnorm(length(signal),0,1) gamma = 25 unlist(dstem(signal + noise, "II-step",gamma,alpha=0.05)) ## piecewise linear with jump l = 1200 h = seq(150,by=150,length.out=6) jump = c(0,1.5,2,2.2,1.8,2,1.5)*3 beta1 = c(2,-1,2.5,-3,-0.2,2.5,-0.5)/50 signal = gen.signal(l=l,h=h,jump=jump,b1=beta1) noise = rnorm(length(signal),0,1) gamma = 25 unlist(dstem(signal + noise, "II-linear",gamma,alpha=0.05))
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.