Regression Models with Break-Points / Change-Points Estimation

Given a regression model, segmented `updates' it by adding one or more segmented (i.e., piece-wise linear) relationships. Several variables with multiple breakpoints are allowed. The estimation method is discussed in Muggeo (2003, ) and illustrated in Muggeo (2008, <>). An approach for hypothesis testing is presented in Muggeo (2016, ), and interval estimation for the breakpoint is discussed in Muggeo (2017, ).


  •   		                            *
  • Changes in segmented *
  •   		                            *

=============== version 0.5-4.0

  • confint.segmented() now computes breakpoint confidence intervals via the (smoothed) Score or Gradient statistic, see new argument 'method' in confint.segmented().
  • if segmented does not converge (since the estimated psi leaves only 1 datum on its left/right) the last psi estimate is printed as a message.
  • argument keep.class added in segmented.default()
  • argument 'rug' defaults to '!add' in plot.segmented()
  • confint.segmented now returns a matrix (rather than a list)
  • bug fixed: plot.segmented() did not handle appropriatly arguments cex.lab and cex.axis. segmented methods did not terminate appropriately when automatic selection of number of breakpoints was performed (i.e. 'stop.if.error=FALSE'). davies.test() and segmented.glm() required 'seg.Z' even if there was just one covariate in the starting model and it could be missing (thanks to Lein E. Pardo for reporting that). Some minor bug fixes (related to argument 'data' and one-sided alternative) in pscore.test (thanks to Karista Hudelson for reporting).

=============== version 0.5-3.0

  • aapc() introduced. The function computes the 'average annual percent change' to summarize piecewise linear trends (thanks to Yuchen Qin for his input).
  • plot.segmented() now accepts arguments 'cex.axis' and 'cex.lab' (thanks to Matthew Birk for his input).
  • bug fixed: segmented.Arima didn't work for arima fits including a seasonal component (thanks to Claudio Agostinelli for reportig the bug).

=============== version 0.5-2.2

  • when there is a single covariate in the starting (g)lm, seg.Z can be missing when calling the segmented methods.
  • bug fixed: plot.segmented(.., link=FALSE) did not work correctly (sometimes it returned an error) for glm fits with multiple breakpoints. Weights were not handled appropriately by segmented.lm.

=============== version 0.5-2.1

  • pscore.test() now works also for "glm" fits
  • plot.segmented() now plots the partial residuals as "component + working residuals" (rather than Pearson residuals, relevant only for glm fits).
  • segmented.default() now is expected to work for fits obtained by MASS::rlm().

=============== version 0.5-2.0

  • pscore.test() introduced. The function tests for a breakpoint using a (pseudo) score statistic which is more powerful than davies.test(), especially when the breakpoint is expected to be in the middle of the covariate range and the signal-to-noise ratio is high.
  • argument 'digits' added in seg.control() to fix the number of digits of the breakpoint estimate during the iterative estimation algorithm.
  • bug fixed: conf.level>0 in plot.segmented() did not work for objects returned by segmented.default().

=============== version 0.5-1.5 (not on CRAN)

  • arguments 'gap' and '' removed in intercept() and in plot.segmented(). (they are meaningless, as segmented() always returns joined piecewise lines, i.e. with no gaps).
  • slope() and broken.line() (and then plot.segmented() which uses them) did not work for objects returned by segmented.default() (Thanks to Marcos Krull for reporting).

=============== version 0.5-1.4

  • segmented.Arima() should be slightly faster, as starting values are passed in arima() (via 'init') throughout the iterative process.
  • plot.segmented() is expected to work for objects returned by segmented.Arima.
  • print.summary.segmented() does not print anymore the t-values for the gap coefficients (this information is meaningless as the gap coeffs are always set to zero in the returned model).
  • Bug fixed: intercept() ignored argument 'rev.sgn'; points.segmented() missed argument 'transf'.

=============== version 0.5-1.3 (not on CRAN)

  • plot.segmented() gains argument 'transf' to plot 'transf(values)' rather 'values' on the current plot.
  • print.summary.segmented() now uses round() rather than signif() when displaying the breakpoint estimate.
  • Bug fixed: psi=NA was not working in the segmented.* methods; this bug was incidentally introduced in the last version (thanks to Bertrand Sudre for first reporting that).

=============== version 0.5-1.2

  • For 1 breakpoint models, 'psi' argument can be missing (default) when calling the segmented methods.
  • Bug fixed: lines.segmented() did not plot the dots when the fit object included multiple breakpoints and the argument 'shift' was set to FALSE (thanks to Jan Bull for reporting). There were some troubles with variable names including dots (thanks to Melanie Zoelck which first reported this bug).

=============== version 0.5-1.1

  • segmented.default now accepts 'gee' fits (Thanks to John Boulanger for his input)
  • Minor change: argument 'col.dens' changed to 'dens.col' in plot.segmented() ('col.dens' made ineffective 'col')
  • Minor change: error/warning messages introduced in davies.test() if k<10; print.segmented slightly changed in displaying the estimated breakpoints.
  • Bug fixed: segmented did not terminate appropriately the algorithm with automatic selection of breakpoints concerning more than one variable (thanks to Ali Hashemi for reporting).

=============== version 0.5-1.0

  • segmented.Arima() introduced. Now it is possible to estimate segmented relationships in "Arima" fits (although the summarizing and plotting methods do not work..)
  • plot.segmented() gains arguments 'dens.rug' and 'col.dens' to display in the plot (on the x axis) also the smoothed density of the segmented covariate.
  • Bug fixed: segmented.lm did not work if it.max=0 (but segmented.glm did), thanks to Eric Nussbaumer for reporting. segmented.lm and segmented.glm did work if the starting linear model included weights (this bug was introduced incidentally since version 0.4-0.1; thanks to Michael Rutter for reporting). segmented.lm and segmented.glm did not check appropriately inadmissible breakpoints (thanks to Erica Tennenhouse for reporting). segmented.lm and segmented.glm did not handle correctly variable names equal to function names. davies.test() did not work with 'segmented' objects (to test for and additional breakpoint). points.segmented() missed the argument 'rev.sgn'.

=============== version 0.5-0.0

  • segmented.default() introduced. Now it is possible to estimate segmented relationships in arbitrary regression models (besides lm and glm) where specific methods do not exist (e.g. cox or quantile regression models).

=============== version 0.4-0.1 (not on CRAN)

  • segmented.lm() and segmented.glm() did not work if the starting model included additional "variables", such as 'threshold' in 'subset=age<threshold' (thanks to Mark Strong for reporting).

=============== version 0.4-0.0

  • points.segmented added. This function allows to add the joinpoints of the segmented lines on the current plot.
  • davies.test() now also implements the Davies test (2002) accounting for the variance estimate in linear (Gaussian) models; this results in more reliable p-values in linear models with small samples. For GLMs, argument 'type' in davies.test() allows to specify whether the Wald or the LRT (default) statistic should be used in the Davies approach.

=============== version 0.3-1.1 (not on CRAN)

  • predict.segmented() did not work in some particular conditions (for instance when there were exactly 2 terms in the model formula; thanks to Saeed Ahmadi for reporting).
  • slope() and confint() did not work appropriately when the model included segmented covariates with "overlapped" names (e.g., "x" and "xx" or ".x").
  • plot.segmented() did not account for the option 'interc=FALSE'.

=============== version 0.3-1.0

  • broken.line() now accepts arbitrary values to compute predictions for segmented relationships in the model; it also returns relevant standard errors (new argument
  • plot.segmented() now accepts also 'ylim' and 'xlim' to set limits on the new produced plot (thanks to Samantha Tyner for suggesting that).
  • the 'aic' component in the objected returned by segmented.glm() was not based on the correct number of degrees of freedom (it missed "2 times n.breaks"; this error was incidentally introduced in version 0.2-9.1) Thanks to Roland Fu? for reporting.
  • segmented.lm(), segmented.glm(), and davies.test() were not working for starting linear models having 'offset' as an argument (and not in the formula).
  • A bug fixed in davies.test() (relevant only for covariates with some inflation at the boundaries)
  • The (possible) "weights" argument in the starting model was not correctly handled (thanks to Brian Jessop for reporting)

=============== version 0.3-0.0

  • predict.segmented method added. This allows to obtain predictions from fitted segmented objects as in standard (generalized) linear models.
  • plot.segmented gains several arguments to plot pointwise confidence intervals around the fitted segmented line (e.g. 'conf.level').
  • The starting linear object to be passed on to segmented.lm and segmented.glm may include terms such as poly(), ns(), or bs().

=============== version 0.2-9.5

  • Some bugs fixed: segmented did not work if the starting linear model including an offset term was called from a dataframe; thanks to Aritz Adin Urtasun (and also to the the guy which sent me the email on 26th Sept 2013. I lost his email and I do not remember his name). segmented did not work if the starting linear model included the "weights" argument expressed via a function (something like "weights= 1/myweights"); thanks to Betty Fetscher. segmented did not work if the variable names in seg.Z included the capital "U"; thanks to Lutz Ph. Breitling.

=============== version 0.2-9.4

  • in davies.test() the evaluation points are now equally spaced values rather than quantiles (useful when the covariate has one or more mass points; thanks to Eric Goodwin for the suggestion)
  • Some minor bugs fixed: bootstrap restarting sometimes did not work when 'seed' was set. segmented.lm() and segmented.glm() did not work correctly when the input model, "lm" or "glm", included terms such such as sin(x*pi) (where x is also the segmented variable)

=============== version 0.2-9.3

  • intercept() (and plot.segmented() that uses intercept()) was not working correctly when the returned breakpoints were not ordered in the fitted segmented model. Now plot.segmented() displays the correct fitted lines in the last example of ?segmented.
  • segmented.lm() and segmented.glm() now always return ordered breakpoints.
  • segmented.lm() and segmented.glm() now return also the .Random.seed vector when bootstrap restarting is employed. Useful to replicate results.
  • draw.history() draws more meaningful convergence diagnostics when the model has ben fitted via bootstrap restarting.
  • Some bugs fixed: segmented.lm() and segmented.glm() failed with zero residuals in the iterative procedure. Argument 'linkinv' in broken.line() modified in 'link' (with oppositive meaning).

=============== version 0.2-9.2

  • Some minor bugs fixed: some corrections in segmented.glm(); in plot.segmented() the argument 'linkinv' replaced by 'link'; segmented.lm() was not working if the starting model was lm(y~0) or lm(y~1); segmented.lm() is slightly more efficient when n.boot>0.
  • The breakpoint starting values when automatic selection is performed are now specified as equally spaced values (optionally as quantiles). see argument 'quant' in seg.control()
  • added '[email protected]' entry in the DESCRIPTION file

=============== version 0.2-9.1

  • Some bugs fixed: segmented.lm() and segmented.glm() did not finish correctly when no breakpoint was found; now segmented.lm() and segmented.glm() take care of flat relationships; plot.segmented() did not compute correctly the partial residuals for segmented glm fits.

=============== version 0.2-9.0

  • Bootstrap restarting implemented to deal with problems coming from flat segmented relationships. segmented now is less sensitive to starting values supplied for 'psi'.
  • At the convergence segmented now constrains the gap coefficients to be exactly zero. This is the default and it can be altered by the 'gap' argument in seg.control().
  • plot.segmented() has been re-written. It gains argument `res' for plotting partial residuals along with the fitted piecewise lines, and now it produces nicer (and typically smaller) plots.
  • Some bugs fixed: davies.test() did not work correctly for deterministic data (thanks to Glenn Roberts for finding the error). davies.test() also returns the `process', i.e. the different values of the evaluation points and corresponding test statistic.

=============== version 0.2-8.4

  • Some bugs fixed: segmented.glm() fitted a simple "lm" (and not "glm") (the error was introduced incidentally from 0.2-8.3, thanks to Veronique Storme for finding the error); broken.line() was not working for models without intercept and a null left slope; intercept() was not working correctly with multiple segmented variables.

=============== version 0.2-8.3

  • Some minor bugs fixed: segmented.lm() and segmented.glm() did not find the offset variable in the dataframe where the initial (g)lm was called for; segmented.lm() and segmented.glm() sometimes returned an error when the automated algorithm was used (thanks to Paul Cohen for finding the error).

=============== version 0.2-8.2

  • Some minor bugs fixed (segmented.lm() and segmented.glm() alway included the left slope in the estimation process, although the number of parameters was correct in the returned final fit. confint.segmented() did not order the estimated breakpoints for the variable having rev.sgn=TRUE; intercept() missed the (currently meaningless) argument var.diff (thanks to Eric Fuchs for pointing out that). )

=============== version 0.2-8.1

  • Some minor bugs fixed (segmented.lm() and segmented.glm() were not working correctly with dataframe subset or when the starting linear model included several intercepts (e.g., see the example about data("plant"); thanks to Nicola Ferrari for finding the error). davies.test() did not work when the variable name of its argument seg.Z' included reserved words, e.g.seg.Z~dist'; thanks to Thom White for finding the error).

=============== version 0.2-8

  • intercept() added. It computes the intercepts of the regression lines for each segment of the fitted segmented relationship.
  • plot.segmented() now accepts a vector `col' argument to draw the fitted piecewise linear relationships with different colors.
  • Some minor bugs fixed (summary.segmented were not working correctly).

=============== version 0.2-7.3

  • argument APC added to the slope() function to compute the `annual percent change'.
  • Some minor bugs fixed (confint and slope were not working correctly when the estimated breakpoints were returned in non-increasing order; offset was ignored in segmented.lm and segmented.glm; broken.line() was not working correctly (and its argument gap was unimplemented), thanks to M. Rennie for pointing out that; summary.segmented() was not working for models with no linear term, i.e. fitted via segmented(lm(y~0),..)).

=============== version 0.2-7.2

  • segmented.lm and segmented.glm now accept objects with formulas y~., Thanks to G. Ferrara for finding the error.
  • Some bugs fixed (slope and confint were using the normal (rather than the t-distribution) to compute the CIs in gaussian models).

=============== version 0.2-7.1

  • segmented.lm and segmented.glm now accept objects without 'explicit' formulas, namely returned by lm(my_fo,..) (and glm(my_fo,..)) where my_fo was defined earlier. Thanks to Y. Iwasaki for finding the error.

=============== version 0.2-7

  • A sort of automatic procedure for breakpoint estimation is implemented. See argument stop.if.error in seg.control().
  • davies.test() now accepts a one-sided formula (~x) rather than character ("x") to mean the segmented variable to be tested. davies.test also gains the arguments beta0' anddispersion'.
  • Some bugs fixed.

=============== version 0.2-6

  • vcov.segmented() added.
  • option var.diff for robust covariance matrix has been added in summary.segmented(), print.summary.segmented(), slope(), and confint().
  • Some bugs fixed.

Reference manual

It appears you don't have a PDF plugin for this browser. You can click here to download the reference manual.


1.3-0 by Vito M. R. Muggeo, a month ago

Browse source code at

Authors: Vito M. R. Muggeo [aut, cre]

Documentation:   PDF Manual  

Task views: Econometrics, Analysis of Ecological and Environmental Data

GPL license

Imported by PVplr, ddiv, mixtools, netSEM, respirometry, seqinr, takos, weibulltools.

Suggested by REddyProc, nlraa.

See at CRAN