dpseg: piecewise linear segmentation by a simple dynamic programing algorithmauthors: "Rainer Machne, Peter F. Stadler"
This package performs piecewise linear segmentation of ordered data by
a dynamic programing algorithm, provided via the function dpseg. It
was developed for time series data, eg. growth curves, and for
genome-wide read-count data from next generation sequencing.
The package and its documentation are also intended to serve as a tutorial
on dynamic programing and the segmentation problem. A movie function
visualizes the progress of the algorithm through the data.
Moreover, the package features generic implementations of dynamic
programing routines, where new segmentation criteria ("scoring
functions") can be tested in base R and efficient versions
implemented in Rcpp.
See the package vignette (vignette("dpseg")) for details.
Install package from within R via cran:
install.packages("dpseg")
library(devtools)
install_gitlab("raim/dpseg")
library(dpseg)
# get example data `oddata` - bacterial growth measured as optical density OD
x <- oddata$Time
y <- log(oddata[,"A2"]) # note: exponential growth -> log(y) is linear
segs <- dpseg(x=x, y=y, jumps=FALSE, P=0.0004)
## inspect resulting segments
print(segs)
## plot results
plot(segs)
## use predict method
lines(predict(segs),lty=2, lwd=3, col="yellow")
## view the algorithm in action
movie(segs)
The problem is to find break-points in 2-dimensional data, eg. timeseries, that
split the data into linear segments. This can be formulated as an optimization
problem that can be solved by dynamic programing:
S_j = \max_{i\le j} (S_{i-\mathcal{J}} + \text{score}(i,j)) - P\;,
where the $\text{score}$ quantifies how well a segment between points
$i$ and $j$ is defined, eg. some goodness-of-fit measure such as the
negative variance of the residuals
\text{score}(i,j) = -\mathrm{Var}(r)
of a straight line fitted through data points from points $i$ to
$j$. $P$ is a penalty term and allows to fine-tune segment
lengths. At constant scores it will accumulate in $S_j$ (subtracted
for each $i$). $P>0$ forces the algorithm to "wait" until a higher
score is reached, thus yielding longer segments. $P<0$ will give
shorter segments.
Discontinuous jumps between adjacent segments can be allowed with
$\mathcal{J} =1$, while segment borders (break-points) are part of
both left and right segments with default $\mathcal{J} =0$.
The above scoring function is the default in dpseg
(type="var"). If the data does not contain horizontal segments and
only zig-zag-like trends are to be segmented, correlation-based
scoring functions may perform better: the r-squared value
(type="r2") or its square root, the Pearson correlation
(type="cor").
See the package vignette (vignette("dpseg")) for details.
Vignette better outlines the differences between variance of residuals and correlation-based scoring functions.
dpseg catches different lengths of x and y as an error.
plot.dpseg now uses equispaced points at default 10x resolution (res*length(x))
dpseg default recursion (Rcpp function recursion_linreg_c) now consistently handles Sxx=0 (vertical) and S=yy (horizontal) lines. TODO: add option to interpret Sxx=0 as perfect fit and r2=cor=1?
vlines allows to suppress the vertical lines in the dpseg plot function.