[
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: pwlf ci\n\non:\n  push:\n\njobs:\n  build:\n\n    runs-on: ubuntu-22.04\n    strategy:\n      matrix:\n        python-version: ['3.10', '3.11', '3.12', '3.13']\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v2\n      with:\n        python-version: ${{ matrix.python-version }}\n    - name: Install dependencies\n      run: |\n        python -m pip install flake8 coverage pytest pytest-cov\n    - name: Install pwlf\n      run: |\n        python -m pip install . --no-cache-dir\n    - name: Lint with flake8\n      run: |\n        flake8 pwlf\n        flake8 tests/tests.py\n    - name: Test with pytest\n      run: |\n        pytest --cov=pwlf --cov-report=xml -p no:warnings tests/tests.py\n    - name: Upload coverage to Codecov\n      uses: codecov/codecov-action@v1\n      with:\n        token: ${{ secrets.CODECOV_TOKEN }}\n        file: ./coverage.xml\n        directory: ./coverage/reports/\n        flags: unittests\n        env_vars: OS,PYTHON\n        name: codecov-umbrella\n        fail_ci_if_error: false\n        verbose: false\n"
  },
  {
    "path": ".github/workflows/cron.yml",
    "content": "name: pwlf cron\n\non:\n  schedule:\n    # Also run every 24 hours\n    - cron:  '* */24 * * *'\n\njobs:\n  build:\n\n    runs-on: ubuntu-22.04\n    strategy:\n      matrix:\n        python-version: ['3.10', '3.11', '3.12', '3.13']\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v2\n      with:\n        python-version: ${{ matrix.python-version }}\n    - name: Install dependencies\n      run: |\n        python -m pip install flake8 coverage pytest pytest-cov\n    - name: Install pwlf\n      run: |\n        python -m pip install . --no-cache-dir\n    - name: Lint with flake8\n      run: |\n        flake8 pwlf\n    - name: Test with pytest\n      run: |\n        pytest --cov=pwlf --cov-report=xml -p no:warnings tests/tests.py\n"
  },
  {
    "path": ".gitignore",
    "content": "*.pyc\n.coverage\nMANIFEST\n/build/\nsetup.cfg\n# Setuptools distribution folder.\n/dist/\n\n# Python egg metadata, regenerated from source files by setuptools.\n/*.egg-info\n\n# pip stuff\n/temp/\n\n# vscode folder\n.vscode*\n\n# vim temp file\n*~\n*.swp\n*.un~\n\n# temporary documentation folder\ntempdocs\ntempdocs/*\nsphinxdocs/build\nsphinxdocs/build/*\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [2.5.2] - 2025-07-26\n### Changed\n- Minor typo in documentation. Thanks to [Berend-ASML](https://github.com/Berend-ASML) for the fix!\n\n## [2.5.1] - 2025-02-23\n### Changed\n- Only test float128 support if numpy allows you to create float128 numbers. This should fix issues on aarch64 builds that do not support float128 or longdouble.\n\n## [2.5.0] - 2025-02-19\n### Changed\n- remove pyDOE as a dependency in favor of scipy's own latin hypercube sampling. This change will effect results of the `fitfast` method, where previous versions of the `fitfast` results will no longer be reproducible with this version.\n\n## [2.4.0] - 2024-12-31\n### Added\n- Added support for mixing degree fits. You may now specify `degree=[0,1,0]` to fit a constant, then linear, then constant line. These are discontinuous piecewise linear.  Currently this only supports mixing degrees of 0 and 1. Thanks to [wonch002](https://github.com/wonch002) for resurrecting an old branch.\n### Changed\n- fixed a bug where `seed=0` would net get set. Thanks to [filippobistaffa](https://github.com/filippobistaffa) from https://github.com/cjekel/piecewise_linear_fit_py/pull/118 .\n\n## [2.3.0] - 2024-10-26\n### Changed\n- You can now force fits of one line segment to go through a particular point `mypwlf.fit(1, x_c, y_c)`. Thanks to [fredrikhellman](https://github.com/fredrikhellman).\n- Update docs to sphinx 8 (from 4)\n- Update ci version to `python==3.9`, `python==3.10`, `python==3.11`, and `python==3.12`\n\n## [2.2.1] - 2022-05-07\n### Added\n- You can now perform `fit` and `fitfast` for one line segment!\n\n## [2.2.0] - 2022-05-01\n### Added\n- Now you can specify a numpy.random.seed to use on init to get reproducible results from the `fit` and `fitfast` methods. Simply specify an integer seed number like so `pwlf.PiecewiseLinFit(x, y, seed=123)`. Note this hijacks your current random seed. By default, not random seed is specified.\n- Python 3.9 is now part of the ci\n### Changed\n- Add flake8 checks to tests\n- Two tests were not being checked because the method did not start with `test`\n\n## [2.1.0] - 2022-03-31\n### Changed\n- All instances of `linalg.inv` now use `linalg.pinv`. All APIs are still the same, but this is potentially a backwards breaking change as previous results may be different from new results. This will mainly affect standard error calculations.\n- Previously `calc_slopes` was called after every least squares fit in optimization routines trying to find breakpoints. This would occasionally raise a numpy `RuntimeWarning` if two breakpoints were the same, or if a breakpoint was on the boundary. Now `calc_slopes` is not called during experimental breakpoint calculation, which should no longer raise this warning for most users. Slopes will still be calculated once optimal breakpoints are found!\n\n## [2.0.5] - 2021-12-04\n### Added\n- conda forge installs are now officially mentioned on readme and in documentation\n\n## [2.0.4] - 2020-08-27\n### Deprecated\n- Python 2.7 will not be supported in future releases\n- Python 3.5 reaches [end-of-life](https://devguide.python.org/#status-of-python-branches) on 2020-09-13, and will not be supported in future releases\n### Added\n- ```python_requires``` in setup.py\n\n## [2.0.3] - 2020-06-26\n### Changed\n- version handling does not require any dependencies \n### Removed\n- importlib requirement\n\n## [2.0.2] - 2020-05-25\n### Changed\n- Fixed an encoding bug that would not let pwlf install on windows. Thanks to h-vetinari for the [PR](https://github.com/cjekel/piecewise_linear_fit_py/pull/71)!\n\n## [2.0.1] - 2020-05-24\n### Changed\n- Removed setuptools for importlib single source versioning\n### Added\n- Requirement for importlib-metadata if Python version is less than 3.8\n### Removed\n- Requriement for setuptools\n\n## [2.0.0] - 2020-04-02\n### Added\n- Added supports for pwlf to fit to weighted data sets! Check out [this example](https://github.com/cjekel/piecewise_linear_fit_py/tree/master/examples#weighted-least-squares-fit).\n### Changed\n- Setup.py now grabs markdown file for long description\n### Removed\n- Tensorflow support has been removed. It hasn't been updated in a long time. If you still require this object, check out [pwlftf](https://github.com/cjekel/piecewise_linear_fit_py_tf)\n\n\n## [1.1.7] - 2020-02-05\n### Changed\n- Minimum SciPy version is now 1.2.0 because of issues with MacOS and the old SciPy versions. See issue https://github.com/cjekel/piecewise_linear_fit_py/issues/40 and thanks to bezineb5 !\n\n## [1.1.6] - 2020-01-22\n### Changed\n- Single source version now found in setup.py instead of pwlf/VERSION see issue https://github.com/cjekel/piecewise_linear_fit_py/issues/53\n- New setuptools requirement to handle new version file\n- Fix bug where forcing pwlf through points didn't work with higher degrees. See issue https://github.com/cjekel/piecewise_linear_fit_py/issues/54\n\n## [1.1.5] - 2019-11-21\n### Changed\n- Fix minor typo in docstring of ```calc_slopes```\n- Initialized all attributes in the ```__init__``` funciton\n- All attributes are now documented in the ```__init__``` function. To view this docstring, use ```pwlf.PiecewiseLinFit?```.\n\n## [1.1.4] - 2019-10-24\n### Changed\n- TensorFlow 2.0.0 is not (and most probably will not) be supported. DepreciationWarning is displayed when using the ```PiecewiseLinFitTF``` object. Setup.py checks for this optional requirement. Tests are run on Tensorflow<2.0.0.\n- TravisCi now checks Python version 3.7 in addition to 3.6, 3.5, 2.7.\n- TravisCi tests should now be run daily.\n\n## [1.1.3] - 2019-09-14\n### Changed\n- Make .ssr stored with fit_with_break* functions\n\n## [1.1.2] - 2019-08-19\n### Changed \n- Bug fix in non-linear standard error, predict was calling y instead of x. https://github.com/cjekel/piecewise_linear_fit_py/pull/46 Thanks to @tcanders\n\n## [1.1.1] - 2019-08-18\n### Changed\n- Raise the correct AttributeError when a fit has not yet been performed\n\n## [1.1.0] - 2019-06-16\n### Added\n- Now you can calculate standard errors for non-linear regression using the Delta method! Check out this [example](https://github.com/cjekel/piecewise_linear_fit_py/tree/master/examples#non-linear-standard-errors-and-p-values). \n\n## [1.0.1] - 2019-06-15\n### Added\n- Now you can fit constants and continuous polynomials with pwlf! Just specify the keyword ```degree=``` when initializing the ```PiecewiseLinFit``` object. Note that ```degree=0``` for constants, ```degree==1``` for linear (default), ```degree==2``` for quadratics, etc.\n- You can manually specify the optimization bounds for each breakpoint when calling the ```fit``` functions by using the ```bounds=``` keyword. Check out the related example.\n### Changed\n- n_parameters is now calculated based on the shape of the regression matrix\n- assembly of the regression matrix now considers which degree polynomial\n- n_segments calculated from break points...\n- Greatly reduce teststf.py run time\n\n## [1.0.0] - 2019-05-16\n### Changed\n- Numpy matrix assembly is now ~100x times faster, which will translate to much faster fits! See this [comment](https://github.com/cjekel/piecewise_linear_fit_py/issues/20#issuecomment-492860953) about the speed up. There should no longer be any performance benefits with using the ```PiecewiseLinFitTF``` (TensorFlow) object, so the only reason to use ```PiecewiseLinFitTF``` is if you want access to TensorFlow's optimizers.\n### Removed\n- There are no sort or order optional parameters in ```PiecewiseLinFit```. The new matrix assembly method doesn't need sorted data. This may break backwards compatibility with your code. \n\n## [0.5.1] - 2019-05-05\n### Changed\n- Fixed ```PiecewiseLinFitTF``` for Python 2.\n\n## [0.5.0] - 2019-04-15\n### Added\n- New ```PiecewiseLinFitTF``` class which uses TensorFlow to accelerate pwlf. This class is nearly identical to ```PiecewiseLinFit```, with the exception of the removed ```sorted_data``` options. If you have TensorFlow installed you'll be able to use ```PiecewiseLinFitTF```. If you do not have TensorFlow installed, importing pwlf will issue a warning that ```PiecewiseLinFitTF``` is not available. See this blog [post](https://jekel.me/2019/Adding-tensorflow-to-pwlf/) for more information and benchmarks. The new class includes an option to use float32 or float64 data types. \n- ```lapack_driver``` option to choose between the least squares backend. For more see https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.lstsq.html and http://www.netlib.org/lapack/lug/node27.html\n### Changed\n- Now use scipy.linalg instead of numpy.linalg because scipy is always compiled with lapack\n- least squares fit now defaults to scipy instead of numpy\n### Removed\n- ```rcond``` optional parameter; was not necessary with scipy.linalg\n\n## [0.4.3] - 2019-04-02\n### Changed\n- You can now manually specify ```rcond``` for the numpy least squares solver. For more see https://github.com/cjekel/piecewise_linear_fit_py/issues/21 . \n\n## [0.4.2] - 2019-03-22\n### Changed\n- ```assemble_regression_matrix()``` now checks if breaks is a numpy array\n\n## [0.4.1] - 2019-03-18\n### Changed\n- p_values() now uses the correct degrees of freedom (Thanks to Tong Qiu for pointing this out!)\n- p_values() now returns a value that can be compared to alpha; previous values would have been compared to alpha/2\n\n## [0.4.0] - 2019-03-14\n### Added\n- new ```assemble_regression_matrix()``` function that returns the linear regression matrix ```A``` which can allow you to do some more complicated [fits](https://jekel.me/2019/detect-number-of-line-segments-in-pwlf/)\n- test function for the linear regression matrix\n- new ```fit_guess()``` function to perform a fit when you have an estimate of the breakpoint locations\n### Changed\n- consolidated the assembly of the linear regression matrix to a single function (and removed the duplicate code)\n\n## [0.3.5] - 2019-02-25\n### Changed\n- minor correction to r_squared docstring example\n\n## [0.3.4] - 2019-02-06\n### Added\n- Uploaded paper and citation information\n- Added example of what happens when you have more unknowns than data\n### Changed\n- Examples now include figures\n\n## [0.3.3] - 2019-01-32\n### Added\n- Documentation and link to documentation\n### Changed\n- Minor changes to docstrings (spelling, formatting, attribute fixes)\n\n## [0.3.2] - 2019-01-24\n### Added\n- y-intercepts are now calculated when running the calc_slopes() function. The Y-intercept for each line is stored in self.intercepts. \n\n## [0.3.1] - 2018-12-09\n### Added\n- p_values() function to calculate the p-value of each beta parameter (WARNING! you may only want to use this if you specify the break point locations, as this does not account for uncertainty in break point locations)\n\n### Changed\n- Now changes stored in CHANGELOG.md\n\n## [0.3.0] - 2018-12-05\n### Added\n- r_squared() function to calculate the coefficent of determination after a fit has been performed\n\n### Changed\n- complete docstring overhaul to match the numpydoc style\n- fix issues where sum-of-squares of residuals returned array_like, now should always return float\n\n### Removed\n- legacy piecewise_lin_fit object has been removed\n\n## [0.2.10] - 2018-12-04\n### Changed\n- Minor docstring changes\n- Fix spelling mistakes throughout\n- Fix README.rst format for PyPI\n\n## [0.0.X - 0.2.9] - from 2017-04-01 to 2018-10-03\n- 2018/10/03 Add example of bare minimum model persistance to predict for new data (see examples/model_persistence_prediction.py). Bug fix in predict function for custom parameters. Add new test function to check that predict works with custom parameters.\n- 2018/08/11 New function which calculates the predication variance for given array of x locations. The predication variance is the squared version of the standard error (not to be confused with the standard errors of the previous change). New example prediction_variance.py shows how to use the new function.\n- 2018/06/16 New function which calculates the standard error for each of the model parameters (Remember model parameters are stored as my_pwlf.beta). Standard errors are calculated by calling se = my_pwlf.standard_errors() after you have performed a fit. For more information about standard errors see [this](https://en.wikipedia.org/wiki/Standard_error). Fix docstrings for all functions.\n- 2018/05/11 New sorted_data key which can be used to avoided sorting already ordered data. If your data is already ordered as x[0] < x[1] < ... < x[n-1], you may consider using sorted_data=True for a slight performance increase. Additionally the predict function can take the sorted_data key if the data you want to predict at is already sorted. Thanks to [V-Kh](https://github.com/V-Kh) for the idea and PR. \n- 2018/04/15 Now you can find piecewise linear fits that go through specified data points! Read [this post](http://jekel.me/2018/Force-piecwise-linear-fit-through-data/) for the details.\n- 2018/04/09 Intelligently converts your x, y, or breaks to be numpy array.\n- 2018/04/06 Speed! pwlf just got better and faster! A vast majority of this library has been entirely rewritten! New naming convention. The class piecewise_lin_fit() is being depreciated, now use the class PiecewiseLinFit(). See [this post](http://jekel.me/2018/Continous-piecewise-linear-regression/) for details on the new formulation. New test function that tests predict().\n- 2018/03/25 Default now hides optimization results. Use disp_res=True when initializing piecewise_lin_fit to change. The multi-start fitfast() function now defaults to the minimum population of 2.\n- 2018/03/11 Added try/except behavior for fitWithBreaks function such that the function could be used in an optimization routine. In general when you have a singular matrix, the function will now return np.inf.\n- 2018/02/16 Added new fitfast() function which uses multi-start gradient optimization instead of Differential Evolution. It may be substantially faster for your application. Also it would be a good candidate if you don't need the best solution, but just a reasonable fit. Fixed bug in tests function where assert was checking bound, not SSr. New requirement, pyDOE library. New 0.1.0 Version.\n- 2017/11/03 add setup.py, new tests folder and test scripts, new version tracking, initialize break0 breakN in the beginning\n- 2017/10/31 bug fix related to the case where break points exactly equal to x data points ( as per issue https://github.com/cjekel/piecewise_linear_fit_py/issues/1 ) and added attributes .sep_data_x, .sep_data_y, .sep_predict_data_x for troubleshooting issues related to the separation of data points to their respective regions\n- 2017/10/20 remove determinant calculation and use try-except instead, this will offer a larger performance boost for big problems. Change library name to something more Pythonic. Add version attribute.\n- 2017/08/03 gradients (slopes of the line segments) now stored as piecewise_lin_fit.slopes (or myPWLF.slopes) after they have been calculated by performing a fit or predicting\n- 2017/04/01 initial release\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017-2022 Charles Jekel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include LICENSE\ninclude README.rst\n"
  },
  {
    "path": "README.md",
    "content": "# About\nA library for fitting continuous piecewise linear functions to data. Just specify the number of line segments you desire and provide the data.\n\n![Downloads a month](https://img.shields.io/pypi/dm/pwlf.svg) ![pwlf ci](https://github.com/cjekel/piecewise_linear_fit_py/workflows/pwlf%20ci/badge.svg) [![codecov](https://codecov.io/gh/cjekel/piecewise_linear_fit_py/branch/master/graph/badge.svg?token=AgeDFEQXed)](https://codecov.io/gh/cjekel/piecewise_linear_fit_py) ![PyPI version](https://img.shields.io/pypi/v/pwlf) [![Conda](https://img.shields.io/conda/vn/conda-forge/pwlf)](https://anaconda.org/conda-forge/pwlf)\n\nCheck out the [documentation](https://jekel.me/piecewise_linear_fit_py)!\n\nRead the [blog post](http://jekel.me/2017/Fit-a-piecewise-linear-function-to-data/).\n\n![Example of a continuous piecewise linear fit to data.](https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/examplePiecewiseFit.png)\n\n![Example of a continuous piecewise linear fit to a sine wave.](https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/sinWaveFit.png)\n\nNow you can perform segmented constant fitting and piecewise polynomials!\n![Example of multiple degree fits to a sine wave.](https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/multi_degree.png)\n\n# Features\nFor a specified number of line segments, you can determine (and predict from) the optimal continuous piecewise linear function f(x). See [this example](https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/fitForSpecifiedNumberOfLineSegments.py).\n\nYou can fit and predict a continuous piecewise linear function f(x) if you know the specific x locations where the line segments terminate. See [this example](https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/fitWithKnownLineSegmentLocations.py).\n\nIf you want to pass different keywords for the SciPy differential evolution algorithm see [this example](https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/fitForSpecifiedNumberOfLineSegments_passDiffEvoKeywords.py).\n\nYou can use a different optimization algorithm to find the optimal location for line segments by using the objective function that minimizes the sum of square of residuals. See [this example](https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/useCustomOptimizationRoutine.py).\n\nInstead of using differential evolution, you can now use a multi-start gradient optimization with fitfast() function. You can specify the number of starting points to use. The default is 2. This means that a latin hyper cube sampling (space filling DOE) of 2 is used to run 2 L-BFGS-B optimizations. See [this example](https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/sineWave_time_compare.py) which runs fit() function, then runs the fitfast() to compare the runtime differences!\n\n# Installation\n\n## Python Package Index (PyPI)\n\nYou can now install with pip.\n```\npython -m pip install pwlf\n```\n\n## Conda\n\nIf you have conda, you can also install from conda-forge.\n```\nconda install -c conda-forge pwlf\n```\n\n## From source\n\nOr clone the repo\n```\ngit clone https://github.com/cjekel/piecewise_linear_fit_py.git\n```\n\nthen install with pip\n```\npython -m pip install ./piecewise_linear_fit_py\n```\n\n# How it works\nThis [paper](https://github.com/cjekel/piecewise_linear_fit_py/raw/master/paper/pwlf_Jekel_Venter_v2.pdf) explains how this library works in detail.\n\nThis is based on a formulation of a piecewise linear least squares fit, where the user must specify the location of break points. See [this post](http://jekel.me/2018/Continous-piecewise-linear-regression/) which goes through the derivation of a least squares regression problem if the break point locations are known. Alternatively check out [Golovchenko (2004)](http://golovchenko.org/docs/ContinuousPiecewiseLinearFit.pdf).\n\nGlobal optimization is used to find the best location for the user defined number of line segments. I specifically use the [differential evolution](https://docs.scipy.org/doc/scipy-0.17.0/reference/generated/scipy.optimize.differential_evolution.html) algorithm in SciPy. I default the differential evolution algorithm to be aggressive, and it is probably overkill for your problem. So feel free to pass your own differential evolution keywords to the library. See [this example](https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/fitForSpecifiedNumberOfLineSegments_passDiffEvoKeywords.py).\n\n# Changelog\nAll changes now stored in [CHANGELOG.md](https://github.com/cjekel/piecewise_linear_fit_py/blob/master/CHANGELOG.md)\n\nNew ```weights=``` keyword allows you to perform weighted pwlf fits! Removed TensorFlow code which can now be found [here](https://github.com/cjekel/piecewise_linear_fit_py_tf). \n\n# Requirements\n\nNumPy >= 1.14.0\n\nSciPy >= 1.8.0\n\n\n# License\nMIT License\n\n# Citation\n\n```bibtex\n@Manual{pwlf,\nauthor = {Jekel, Charles F. and Venter, Gerhard},\ntitle = {{pwlf:} A Python Library for Fitting 1D Continuous Piecewise Linear Functions},\nyear = {2019},\nurl = {https://github.com/cjekel/piecewise_linear_fit_py}\n}\n```"
  },
  {
    "path": "README.rst",
    "content": "About\n=====\n\nA library for fitting continuous piecewise linear functions to data.\nJust specify the number of line segments you desire and provide the\ndata.\n\n|Downloads a month| |pwlf ci| |codecov| |PyPI version| |Conda|\n\nCheck out the\n`documentation <https://jekel.me/piecewise_linear_fit_py>`__!\n\nRead the `blog\npost <http://jekel.me/2017/Fit-a-piecewise-linear-function-to-data/>`__.\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/examplePiecewiseFit.png\n   :alt: Example of a continuous piecewise linear fit to data.\n\n   Example of a continuous piecewise linear fit to data.\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/sinWaveFit.png\n   :alt: Example of a continuous piecewise linear fit to a sine wave.\n\n   Example of a continuous piecewise linear fit to a sine wave.\n\nNow you can perform segmented constant fitting and piecewise\npolynomials! |Example of multiple degree fits to a sine wave.|\n\nFeatures\n========\n\nFor a specified number of line segments, you can determine (and predict\nfrom) the optimal continuous piecewise linear function f(x). See `this\nexample <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/fitForSpecifiedNumberOfLineSegments.py>`__.\n\nYou can fit and predict a continuous piecewise linear function f(x) if\nyou know the specific x locations where the line segments terminate. See\n`this\nexample <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/fitWithKnownLineSegmentLocations.py>`__.\n\nIf you want to pass different keywords for the SciPy differential\nevolution algorithm see `this\nexample <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/fitForSpecifiedNumberOfLineSegments_passDiffEvoKeywords.py>`__.\n\nYou can use a different optimization algorithm to find the optimal\nlocation for line segments by using the objective function that\nminimizes the sum of square of residuals. See `this\nexample <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/useCustomOptimizationRoutine.py>`__.\n\nInstead of using differential evolution, you can now use a multi-start\ngradient optimization with fitfast() function. You can specify the\nnumber of starting points to use. The default is 2. This means that a\nlatin hyper cube sampling (space filling DOE) of 2 is used to run 2\nL-BFGS-B optimizations. See `this\nexample <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/sineWave_time_compare.py>`__\nwhich runs fit() function, then runs the fitfast() to compare the\nruntime differences!\n\nInstallation\n============\n\nPython Package Index (PyPI)\n---------------------------\n\nYou can now install with pip.\n\n::\n\n   python -m pip install pwlf\n\nConda\n-----\n\nIf you have conda, you can also install from conda-forge.\n\n::\n\n   conda install -c conda-forge pwlf\n\nFrom source\n-----------\n\nOr clone the repo\n\n::\n\n   git clone https://github.com/cjekel/piecewise_linear_fit_py.git\n\nthen install with pip\n\n::\n\n   python -m pip install ./piecewise_linear_fit_py\n\nHow it works\n============\n\nThis\n`paper <https://github.com/cjekel/piecewise_linear_fit_py/raw/master/paper/pwlf_Jekel_Venter_v2.pdf>`__\nexplains how this library works in detail.\n\nThis is based on a formulation of a piecewise linear least squares fit,\nwhere the user must specify the location of break points. See `this\npost <http://jekel.me/2018/Continous-piecewise-linear-regression/>`__\nwhich goes through the derivation of a least squares regression problem\nif the break point locations are known. Alternatively check out\n`Golovchenko\n(2004) <http://golovchenko.org/docs/ContinuousPiecewiseLinearFit.pdf>`__.\n\nGlobal optimization is used to find the best location for the user\ndefined number of line segments. I specifically use the `differential\nevolution <https://docs.scipy.org/doc/scipy-0.17.0/reference/generated/scipy.optimize.differential_evolution.html>`__\nalgorithm in SciPy. I default the differential evolution algorithm to be\naggressive, and it is probably overkill for your problem. So feel free\nto pass your own differential evolution keywords to the library. See\n`this\nexample <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/fitForSpecifiedNumberOfLineSegments_passDiffEvoKeywords.py>`__.\n\nChangelog\n=========\n\nAll changes now stored in\n`CHANGELOG.md <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/CHANGELOG.md>`__\n\nNew ``weights=`` keyword allows you to perform weighted pwlf fits!\nRemoved TensorFlow code which can now be found\n`here <https://github.com/cjekel/piecewise_linear_fit_py_tf>`__.\n\nRequirements\n============\n\nNumPy >= 1.14.0\n\nSciPy >= 1.8.0\n\n\nLicense\n=======\n\nMIT License\n\nCitation\n========\n\n.. code:: bibtex\n\n   @Manual{pwlf,\n   author = {Jekel, Charles F. and Venter, Gerhard},\n   title = {{pwlf:} A Python Library for Fitting 1D Continuous Piecewise Linear Functions},\n   year = {2019},\n   url = {https://github.com/cjekel/piecewise_linear_fit_py}\n   }\n\n.. |Downloads a month| image:: https://img.shields.io/pypi/dm/pwlf.svg\n.. |pwlf ci| image:: https://github.com/cjekel/piecewise_linear_fit_py/workflows/pwlf%20ci/badge.svg\n.. |codecov| image:: https://codecov.io/gh/cjekel/piecewise_linear_fit_py/branch/master/graph/badge.svg?token=AgeDFEQXed\n   :target: https://codecov.io/gh/cjekel/piecewise_linear_fit_py\n.. |PyPI version| image:: https://img.shields.io/pypi/v/pwlf\n.. |Conda| image:: https://img.shields.io/conda/vn/conda-forge/pwlf\n   :target: https://anaconda.org/conda-forge/pwlf\n.. |Example of multiple degree fits to a sine wave.| image:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/multi_degree.png\n"
  },
  {
    "path": "convert_README_to_RST.sh",
    "content": "#!/usr/bin/env bash\npandoc --from=markdown --to=rst --output=README.rst README.md\n"
  },
  {
    "path": "docs/.buildinfo",
    "content": "# Sphinx build info version 1\n# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.\nconfig: 24f4d9dbb6c120d783c7146d16a6ffbd\ntags: 645f666f9bcd5a90fca523b33c5a78b7\n"
  },
  {
    "path": "docs/.nojekyll",
    "content": ""
  },
  {
    "path": "docs/_sources/about.rst.txt",
    "content": "About\n============\n\nA library for fitting continuous piecewise linear functions to data. Just specify the number of line segments you desire and provide the data.\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/examplePiecewiseFit.png\n   :alt: Example of a continuous piecewise linear fit to data.\n\nExample of a continuous piecewise linear fit to data.\n\nAll changes now stored in\n`CHANGELOG.md <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/CHANGELOG.md>`__\n\nPlease cite pwlf in your publications if it helps your research.\n\n.. code:: bibtex\n\n    @Manual{pwlf,\n        author = {Jekel, Charles F. and Venter, Gerhard},\n        title = {{pwlf:} A Python Library for Fitting 1D Continuous Piecewise Linear Functions},\n        year = {2019},\n        url = {https://github.com/cjekel/piecewise_linear_fit_py}\n    }\n"
  },
  {
    "path": "docs/_sources/examples.rst.txt",
    "content": "Examples\n========\n\nAll of these examples will use the following data and imports.\n\n.. code:: python\n\n   import numpy as np\n   import matplotlib.pyplot as plt\n   import pwlf\n\n   # your data\n   y = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n                 4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n                 8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n                 1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n                 8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n                 4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n                 5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n                 7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n                 1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n                 1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n                 3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n                 6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n                 1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n                 1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n                 5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n                 9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n                 0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n                 4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n                 8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n                 1.41881288e-01, 1.62618058e-01])\n   x = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n                 5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n                 1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n                 1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n                 7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n                 4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n                 7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n                 1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n                 1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n                 1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n                 3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n                 1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n                 1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n                 1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n                 7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n                 1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n                 0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n                 6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n                 1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n                 1.65299640e-01, 1.79942720e-01])\n\n1.  `fit with known breakpoint\n    locations <#fit-with-known-breakpoint-locations>`__\n2.  `fit for specified number of line\n    segments <#fit-for-specified-number-of-line-segments>`__\n3.  `fitfast for specified number of line\n    segments <#fitfast-for-specified-number-of-line-segments>`__\n4.  `force a fit through data\n    points <#force-a-fit-through-data-points>`__\n5.  `use custom optimization\n    routine <#use-custom-optimization-routine>`__\n6.  `pass differential evolution\n    keywords <#pass-differential-evolution-keywords>`__\n7.  `find the best number of line\n    segments <#find-the-best-number-of-line-segments>`__\n8.  `model persistence <#model-persistence>`__\n9.  `bad fits when you have more unknowns than\n    data <#bad-fits-when-you-have-more-unknowns-than-data>`__\n10. `fit with a breakpoint guess <#fit-with-a-breakpoint-guess>`__\n11. `get the linear regression\n    matrix <#get-the-linear-regression-matrix>`__\n12. `use of TensorFlow <#use-of-tensorflow>`__\n13. `fit constants or polynomials <#fit-constants-or-polynomials>`__\n14. `specify breakpoint bounds <#specify-breakpoint-bounds>`__\n15. `non-linear standard errors and\n    p-values <#non-linear-standard-errors-and-p-values>`__\n16. `obtain the equations of fitted\n    pwlf <#obtain-the-equations-of-fitted-pwlf>`__\n17. `weighted least squares fit <#weighted-least-squares-fit>`__\n18. `reproducible results <#reproducible results>`__\n\nfit with known breakpoint locations\n-----------------------------------\n\nYou can perform a least squares fit if you know the breakpoint\nlocations.\n\n.. code:: python\n\n   # your desired line segment end locations\n   x0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data with the specified break points\n   # (ie the x locations of where the line segments\n   # will terminate)\n   my_pwlf.fit_with_breaks(x0)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/fit_breaks.png\n   :alt: fit with known breakpoint locations\n\n   fit with known breakpoint locations\n\nfit for specified number of line segments\n-----------------------------------------\n\nUse a global optimization to find the breakpoint locations that minimize\nthe sum of squares error. This uses `Differential\nEvolution <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html>`__\nfrom scipy.\n\n.. code:: python\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data for four line segments\n   res = my_pwlf.fit(4)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/numberoflines.png\n   :alt: fit for specified number of line segments\n\n   fit for specified number of line segments\n\nfitfast for specified number of line segments\n---------------------------------------------\n\nThis performs a fit for a specified number of line segments with a\nmulti-start gradient based optimization. This should be faster than\n`Differential\nEvolution <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html>`__\nfor a small number of starting points.\n\n.. code:: python\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data for four line segments\n   # this performs 3 multi-start optimizations\n   res = my_pwlf.fitfast(4, pop=3)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/fitfast.png\n   :alt: fitfast for specified number of line segments\n\n   fitfast for specified number of line segments\n\nforce a fit through data points\n-------------------------------\n\nSometimes it’s necessary to force the piecewise continuous model through\na particular data point, or a set of data points. The following example\nfinds the best 4 line segments that go through two data points.\n\n.. code:: python\n\n   # initialize piecewise linear fit with your x and y data\n   myPWLF = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the function with four line segments\n   # force the function to go through the data points\n   # (0.0, 0.0) and (0.19, 0.16) \n   # where the data points are of the form (x, y)\n   x_c = [0.0, 0.19]\n   y_c = [0.0, 0.2]\n   res = myPWLF.fit(4, x_c, y_c)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), 0.19, num=10000)\n   yHat = myPWLF.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/force.png\n   :alt: force a fit through data points\n\n   force a fit through data points\n\nuse custom optimization routine\n-------------------------------\n\nYou can use your favorite optimization routine to find the breakpoint\nlocations. The following example uses scipy’s\n`minimize <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html>`__\nfunction.\n\n.. code:: python\n\n   from scipy.optimize import minimize\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # initialize custom optimization\n   number_of_line_segments = 3\n   my_pwlf.use_custom_opt(number_of_line_segments)\n\n   # i have number_of_line_segments - 1 number of variables\n   # let's guess the correct location of the two unknown variables\n   # (the program defaults to have end segments at x0= min(x)\n   # and xn=max(x)\n   xGuess = np.zeros(number_of_line_segments - 1)\n   xGuess[0] = 0.02\n   xGuess[1] = 0.10\n\n   res = minimize(my_pwlf.fit_with_breaks_opt, xGuess)\n\n   # set up the break point locations\n   x0 = np.zeros(number_of_line_segments + 1)\n   x0[0] = np.min(x)\n   x0[-1] = np.max(x)\n   x0[1:-1] = res.x\n\n   # calculate the parameters based on the optimal break point locations\n   my_pwlf.fit_with_breaks(x0)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\npass differential evolution keywords\n------------------------------------\n\nYou can pass keyword arguments from the ``fit`` function into scipy’s\n`Differential\nEvolution <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html>`__.\n\n.. code:: python\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data for four line segments\n   # this sets DE to have an absolute tolerance of 0.1\n   res = my_pwlf.fit(4, atol=0.1)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\nfind the best number of line segments\n-------------------------------------\n\nThis example uses EGO (bayesian optimization) and a penalty function to\nfind the best number of line segments. This will require careful use of\nthe penalty parameter ``l``. Use this template to automatically find the\nbest number of line segments.\n\n.. code:: python\n\n   from GPyOpt.methods import BayesianOptimization\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # define your objective function\n\n\n   def my_obj(x):\n       # define some penalty parameter l\n       # you'll have to arbitrarily pick this\n       # it depends upon the noise in your data,\n       # and the value of your sum of square of residuals\n       l = y.mean()*0.001\n       f = np.zeros(x.shape[0])\n       for i, j in enumerate(x):\n           my_pwlf.fit(j[0])\n           f[i] = my_pwlf.ssr + (l*j[0])\n       return f\n\n\n   # define the lower and upper bound for the number of line segments\n   bounds = [{'name': 'var_1', 'type': 'discrete',\n              'domain': np.arange(2, 40)}]\n\n   np.random.seed(12121)\n\n   myBopt = BayesianOptimization(my_obj, domain=bounds, model_type='GP',\n                                 initial_design_numdata=10,\n                                 initial_design_type='latin',\n                                 exact_feval=True, verbosity=True,\n                                 verbosity_model=False)\n   max_iter = 30\n\n   # perform the bayesian optimization to find the optimum number\n   # of line segments\n   myBopt.run_optimization(max_iter=max_iter, verbosity=True)\n\n   print('\\n \\n Opt found \\n')\n   print('Optimum number of line segments:', myBopt.x_opt)\n   print('Function value:', myBopt.fx_opt)\n   myBopt.plot_acquisition()\n   myBopt.plot_convergence()\n\n   # perform the fit for the optimum\n   my_pwlf.fit(myBopt.x_opt)\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\nmodel persistence\n-----------------\n\nYou can save fitted models with pickle. Alternatively see\n`joblib <https://joblib.readthedocs.io/en/latest/>`__.\n\n.. code:: python\n\n   # if you use Python 2.x you should import cPickle\n   # import cPickle as pickle\n   # if you use Python 3.x you can just use pickle\n   import pickle\n\n   # your desired line segment end locations\n   x0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data with the specified break points\n   my_pwlf.fit_with_breaks(x0)\n\n   # save the fitted model\n   with open('my_fit.pkl', 'wb') as f:\n       pickle.dump(my_pwlf, f, pickle.HIGHEST_PROTOCOL)\n\n   # load the fitted model\n   with open('my_fit.pkl', 'rb') as f:\n       my_pwlf = pickle.load(f)\n\nbad fits when you have more unknowns than data\n----------------------------------------------\n\nYou can get very bad fits with pwlf when you have more unknowns than\ndata points. The following example will fit 99 line segments to the 59\ndata points. While this will result in an error of zero, the model will\nhave very weird predictions within the data. You should not fit more\nunknowns than you have data with pwlf!\n\n.. code:: python\n\n   break_locations = np.linspace(min(x), max(x), num=100)\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n   my_pwlf.fit_with_breaks(break_locations)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/badfit.png\n   :alt: bad fits when you have more unknowns than data\n\n   bad fits when you have more unknowns than data\n\nfit with a breakpoint guess\n---------------------------\n\nIn this example we see two distinct linear regions, and we believe a\nbreakpoint occurs at 6.0. We’ll use the fit_guess() function to find the\nbest breakpoint location starting with this guess. These fits should be\nmuch faster than the ``fit`` or ``fitfast`` function when you have a\nreasonable idea where the breakpoints occur.\n\n.. code:: python\n\n   import numpy as np\n   import pwlf\n   x = np.array([4., 5., 6., 7., 8.])\n   y = np.array([11., 13., 16., 28.92, 42.81])\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n   breaks = my_pwlf.fit_guess([6.0])\n\nNote specifying one breakpoint will result in two line segments. If we\nwanted three line segments, we’ll have to specify two breakpoints.\n\n.. code:: python\n\n   breaks = my_pwlf.fit_guess([5.5, 6.0])\n\nget the linear regression matrix\n--------------------------------\n\nIn some cases it may be desirable to work with the linear regression\nmatrix directly. The following example grabs the linear regression\nmatrix ``A`` for a specific set of breakpoints. In this case we assume\nthat the breakpoints occur at each of the data points. Please see the\n`paper <https://github.com/cjekel/piecewise_linear_fit_py/tree/master/paper>`__\nfor details about the regression matrix ``A``.\n\n.. code:: python\n\n   import numpy as np\n   import pwlf\n   # select random seed for reproducibility\n   np.random.seed(123)\n   # generate sin wave data\n   x = np.linspace(0, 10, num=100)\n   y = np.sin(x * np.pi / 2)\n   ytrue = y.copy()\n   # add noise to the data\n   y = np.random.normal(0, 0.05, 100) + ytrue\n\n   my_pwlf_en = pwlf.PiecewiseLinFit(x, y)\n   # copy the x data to use as break points\n   breaks = my_pwlf_en.x_data.copy()\n   # create the linear regression matrix A \n   A = my_pwlf_en.assemble_regression_matrix(breaks, my_pwlf_en.x_data)\n\nWe can perform fits that are more complicated than a least squares fit\nwhen we have the regression matrix. The following uses the Elastic Net\nregularizer to perform an interesting fit with the regression matrix.\n\n.. code:: python\n\n   from sklearn.linear_model import ElasticNetCV\n   # set up the elastic net\n   en_model = ElasticNetCV(cv=5,\n                           l1_ratio=[.1, .5, .7, .9,\n                                     .95, .99, 1],\n                           fit_intercept=False,\n                           max_iter=1000000, n_jobs=-1)\n   # fit the model using the elastic net\n   en_model.fit(A, my_pwlf_en.y_data)\n\n   # predict from the elastic net parameters\n   xhat = np.linspace(x.min(), x.max(), 1000)\n   yhat_en = my_pwlf_en.predict(xhat, breaks=breaks,\n                                beta=en_model.coef_)\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/sin_en_net_fit.png\n   :alt: interesting elastic net fit\n\n   interesting elastic net fit\n\nuse of tensorflow\n-----------------\n\nYou need to install\n`pwlftf <https://github.com/cjekel/piecewise_linear_fit_py_tf>`__ which\nwill have the ``PiecewiseLinFitTF`` class. For performance benchmarks\n(these benchmarks are outdated! and the regular pwlf may be faster in\nmany applications) see this blog\n`post <https://jekel.me/2019/Adding-tensorflow-to-pwlf/>`__.\n\nThe use of the TF class is nearly identical to the original class,\nhowever note the following exceptions. ``PiecewiseLinFitTF`` does:\n\n-  not have a ``lapack_driver`` option\n-  have an optional parameter ``dtype``, so you can choose between the\n   float64 and float32 data types\n-  have an optional parameter ``fast`` to switch between Cholesky\n   decomposition (default ``fast=True``), and orthogonal decomposition\n   (``fast=False``)\n\n.. code:: python\n\n   import pwlftf as pwlf\n   # your desired line segment end locations\n   x0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n   # initialize TF piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFitTF(x, y, dtype='float32)\n\n   # fit the data with the specified break points\n   # (ie the x locations of where the line segments\n   # will terminate)\n   my_pwlf.fit_with_breaks(x0)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\nfit constants or polynomials\n----------------------------\n\nYou can use pwlf to fit segmented constant models, or piecewise\npolynomials. The following example fits a segmented constant model,\npiecewise linear, and a piecewise quadratic model to a sine wave.\n\n.. code:: python\n\n   # generate sin wave data\n   x = np.linspace(0, 10, num=100)\n   y = np.sin(x * np.pi / 2)\n   # add noise to the data\n   y = np.random.normal(0, 0.05, 100) + y\n\n   # initialize piecewise linear fit with your x and y data\n   # pwlf lets you fit continuous model for many degree polynomials\n   # degree=0 constant\n   # degree=1 linear (default)\n   # degree=2 quadratic\n   my_pwlf_0 = pwlf.PiecewiseLinFit(x, y, degree=0)\n   my_pwlf_1 = pwlf.PiecewiseLinFit(x, y, degree=1)  # default\n   my_pwlf_2 = pwlf.PiecewiseLinFit(x, y, degree=2)\n\n   # fit the data for four line segments\n   res0 = my_pwlf_0.fitfast(5, pop=50)\n   res1 = my_pwlf_1.fitfast(5, pop=50)\n   res2 = my_pwlf_2.fitfast(5, pop=50)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat0 = my_pwlf_0.predict(xHat)\n   yHat1 = my_pwlf_1.predict(xHat)\n   yHat2 = my_pwlf_2.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o', label='Data')\n   plt.plot(xHat, yHat0, '-', label='degree=0')\n   plt.plot(xHat, yHat1, '--', label='degree=1')\n   plt.plot(xHat, yHat2, ':', label='degree=2')\n   plt.legend()\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/multi_degree.png\n   :alt: Example of multiple degree fits to a sine wave.\n\n   Example of multiple degree fits to a sine wave.\n\nspecify breakpoint bounds\n-------------------------\n\nYou may want extra control over the search space for feasible\nbreakpoints. One way to do this is to specify the bounds for each\nbreakpoint location.\n\n.. code:: python\n\n   # generate sin wave data\n   x = np.linspace(0, 10, num=100)\n   y = np.sin(x * np.pi / 2)\n   # add noise to the data\n   y = np.random.normal(0, 0.05, 100) + y\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # define custom bounds for the interior break points\n   n_segments = 4\n   bounds = np.zeros((n_segments-1, 2))\n   # first breakpoint\n   bounds[0, 0] = 0.0  # lower bound\n   bounds[0, 1] = 3.5  # upper bound\n   # second breakpoint\n   bounds[1, 0] = 3.0  # lower bound\n   bounds[1, 1] = 7.0  # upper bound\n   # third breakpoint\n   bounds[2, 0] = 6.0  # lower bound\n   bounds[2, 1] = 10.0  # upper bound\n   res = my_pwlf.fit(n_segments, bounds=bounds)\n\nnon-linear standard errors and p-values\n---------------------------------------\n\nYou can calculate non-linear standard errors using the Delta method.\nThis will calculate the standard errors of the piecewise linear\nparameters (intercept + slopes) and the breakpoint locations!\n\nFirst let us generate true piecewise linear data.\n\n.. code:: python\n\n   from __future__ import print_function\n   # generate a true piecewise linear data\n   np.random.seed(5)\n   n_data = 100\n   x = np.linspace(0, 1, num=n_data)\n   y = np.random.random(n_data)\n   my_pwlf_gen = pwlf.PiecewiseLinFit(x, y)\n   true_beta = np.random.normal(size=5)\n   true_breaks = np.array([0.0, 0.2, 0.5, 0.75, 1.0])\n   y = my_pwlf_gen.predict(x, beta=true_beta, breaks=true_breaks)\n\n   plt.figure()\n   plt.title('True piecewise linear data')\n   plt.plot(x, y)\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/true_pwlf.png\n   :alt: True piecewise linear data.\n\n   True piecewise linear data.\n\nNow we can perform a fit, calculate the standard errors, and p-values.\nThe non-linear method uses a first order taylor series expansion to\nlinearize the non-linear regression problem. A positive step_size\nperforms a forward difference, and a negative step_size would perform a\nbackwards difference.\n\n.. code:: python\n\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n   res = my_pwlf.fitfast(4, pop=100)\n\n   p = my_pwlf.p_values(method='non-linear', step_size=1e-4)\n   se = my_pwlf.se  # standard errors\n\nThe standard errors and p-values correspond to each model parameter.\nFirst the beta parameters (intercept + slopes) and then the breakpoints.\nWe can assemble the parameters, and print a table of the result with the\nfollowing code.\n\n.. code:: python\n\n   parameters = np.concatenate((my_pwlf.beta,\n                                my_pwlf.fit_breaks[1:-1]))\n\n   header = ['Parameter type', 'Parameter value', 'Standard error', 't',\n             'P > np.abs(t) (p-value)']\n   print(*header, sep=' | ')\n   values = np.zeros((parameters.size, 5), dtype=np.object_)\n   values[:, 1] = np.around(parameters, decimals=3)\n   values[:, 2] = np.around(se, decimals=3)\n   values[:, 3] = np.around(parameters / se, decimals=3)\n   values[:, 4] = np.around(p, decimals=3)\n\n   for i, row in enumerate(values):\n       if i < my_pwlf.beta.size:\n           row[0] = 'Beta'\n           print(*row, sep=' | ')\n       else:\n           row[0] = 'Breakpoint'\n           print(*row, sep=' | ')\n\n============== =============== ============== ============== =======================\nParameter type Parameter value Standard error t              P > np.abs(t) (p-value)\n============== =============== ============== ============== =======================\nBeta           1.821           0.0            1763191476.046 0.0\nBeta           -0.427          0.0            -46404554.493  0.0\nBeta           -1.165          0.0            -111181494.162 0.0\nBeta           -1.397          0.0            -168954500.421 0.0\nBeta           0.873           0.0            93753841.242   0.0\nBreakpoint     0.2             0.0            166901856.885  0.0\nBreakpoint     0.5             0.0            537785803.646  0.0\nBreakpoint     0.75            0.0            482311769.159  0.0\n============== =============== ============== ============== =======================\n\nobtain the equations of fitted pwlf\n-----------------------------------\n\nSometimes you may want the mathematical equations that represent your\nfitted model. This is easy to perform if you don’t mind using sympy.\n\nThe following code will fit 5 line segments of degree=2 to a sin wave.\n\n.. code:: python\n\n   import numpy as np\n   import pwlf\n   # generate sin wave data\n   x = np.linspace(0, 10, num=100)\n   y = np.sin(x * np.pi / 2)\n   # add noise to the data\n   y = np.random.normal(0, 0.05, 100) + y\n   my_pwlf_2 = pwlf.PiecewiseLinFit(x, y, degree=2)\n   res2 = my_pwlf_2.fitfast(5, pop=50)\n\nGiven this fit, the following code will print the mathematical equation\nfor each line segment.\n\n.. code:: python\n\n   from sympy import Symbol\n   from sympy.utilities import lambdify\n   x = Symbol('x')\n\n\n   def get_symbolic_eqn(pwlf_, segment_number):\n       if pwlf_.degree < 1:\n           raise ValueError('Degree must be at least 1')\n       if segment_number < 1 or segment_number > pwlf_.n_segments:\n           raise ValueError('segment_number not possible')\n       # assemble degree = 1 first\n       for line in range(segment_number):\n           if line == 0:\n               my_eqn = pwlf_.beta[0] + (pwlf_.beta[1])*(x-pwlf_.fit_breaks[0])\n           else:\n               my_eqn += (pwlf_.beta[line+1])*(x-pwlf_.fit_breaks[line])\n       # assemble all other degrees\n       if pwlf_.degree > 1:\n           for k in range(2, pwlf_.degree + 1):\n               for line in range(segment_number):\n                   beta_index = pwlf_.n_segments*(k-1) + line + 1 \n                   my_eqn += (pwlf_.beta[beta_index])*(x-pwlf_.fit_breaks[line])**k\n       return my_eqn.simplify()\n\n\n   eqn_list = []\n   f_list = []\n   for i in range(my_pwlf_2.n_segments):\n       eqn_list.append(get_symbolic_eqn(my_pwlf_2, i + 1))\n       print('Equation number: ', i + 1)\n       print(eqn_list[-1])\n       f_list.append(lambdify(x, eqn_list[-1]))\n\nwhich should print out something like the following:\n\n.. code:: python\n\n   Equation number:  1\n   -0.953964059782599*x**2 + 1.89945177490653*x + 0.00538634182565454\n   Equation number:  2\n   0.951561315686298*x**2 - 5.69747505830914*x + 7.5772216545711\n   Equation number:  3\n   -0.949735350431857*x**2 + 9.48218236957122*x - 22.720785454735\n   Equation number:  4\n   0.926850298824217*x**2 - 12.9824424358344*x + 44.5102742956827\n   Equation number:  5\n   -1.03016230425747*x**2 + 18.5306546317065*x - 82.3508513333073\n\nFor more information on how this works, see\n`this <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/understanding_higher_degrees/polynomials_in_pwlf.ipynb>`__\njupyter notebook.\n\nweighted least squares fit\n--------------------------\n\nSometimes your data will not have a constant variance\n(heteroscedasticity), and you need to perform a weighted least squares\nfit. The following example will perform a standard and weighted fit so\nyou can compare the differences. First we need to generate a data set\nwhich will be a good candidate to use for weighted least squares fits.\n\n.. code:: python\n\n   # generate data with heteroscedasticity\n   n = 100\n   n_data_sets = 100\n   n_segments = 6\n   # generate sine data\n   x = np.linspace(0, 10, n)\n   y = np.zeros((n_data_sets, n))\n   sigma_change = np.linspace(0.001, 0.05, 100)\n   for i in range(n_data_sets):\n       y[i] = np.sin(x * np.pi / 2)\n       # add noise to the data\n       y[i] = np.random.normal(0, sigma_change, 100) + y[i]\n   X = np.tile(x, n_data_sets)\n\nThe individual weights in pwlf are the reciprocal of the standard\ndeviation for each data point. Here weights[i] corresponds to one over\nthe standard deviation of the ith data point. The result of this is that\ndata points with higher variance are less important to the overall pwlf\nthan data point with small variance. Let’s perform a standard pwlf fit\nand a weighted fit.\n\n.. code:: python\n\n   # perform an ordinary pwlf fit to the entire data\n   my_pwlf = pwlf.PiecewiseLinFit(X.flatten(), y.flatten())\n   my_pwlf.fit(n_segments)\n\n   # compute the standard deviation in y\n   y_std = np.std(y, axis=0)\n   # set the weights to be one over the standard deviation\n   weights = 1.0 / y_std\n\n   # perform a weighted least squares to the data\n   my_pwlf_w = pwlf.PiecewiseLinFit(x, y.mean(axis=0), weights=weights)\n   my_pwlf_w.fit(n_segments)\n\n   # compare the fits\n   xhat = np.linspace(0, 10, 1000)\n   yhat = my_pwlf.predict(xhat)\n   yhat_w = my_pwlf_w.predict(xhat)\n\n   plt.figure()\n   plt.plot(X.flatten(), y.flatten(), '.')\n   plt.plot(xhat, yhat, '-', label='Ordinary LS')\n   plt.plot(xhat, yhat_w, '-', label='Weighted LS')\n   plt.legend()\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/weighted_least_squares_example.png\n   :alt: Weighted pwlf fit.\n\n   Weighted pwlf fit.\n\nWe can see that the weighted pwlf fit tries fit data with low variance\nbetter than data with high variance, however the ordinary pwlf fits the\ndata assuming a uniform variance.\n\nreproducible results\n--------------------\n\nThe `fit` and `fitfast` methods are stochastic and may not give the same\nresult every time the program is run. To have reproducible results you can\nmanually specify a numpy.random.seed on init. Now everytime the following\nprogram is run, the results of the fit(2) should be the same.\n\n.. code:: python\n\n   # initialize piecewise linear fit with a random seed\n   my_pwlf = pwlf.PiecewiseLinFit(x, y, seed=123)\n\n   # Now the fit() method will be reproducible\n   my_pwlf.fit(2)\n\n"
  },
  {
    "path": "docs/_sources/how_it_works.rst.txt",
    "content": "How it works\n============\n\nThis\n`paper <https://github.com/cjekel/piecewise_linear_fit_py/raw/master/paper/pwlf_Jekel_Venter_v2.pdf>`__\nexplains how this library works in detail.\n\nThis is based on a formulation of a piecewise linear least squares fit,\nwhere the user must specify the location of break points. See `this\npost <http://jekel.me/2018/Continous-piecewise-linear-regression/>`__\nwhich goes through the derivation of a least squares regression problem\nif the break point locations are known. Alternatively check out\n`Golovchenko\n(2004) <http://golovchenko.org/docs/ContinuousPiecewiseLinearFit.pdf>`__.\n\nGlobal optimization is used to find the best location for the user\ndefined number of line segments. I specifically use the `differential\nevolution <https://docs.scipy.org/doc/scipy-0.17.0/reference/generated/scipy.optimize.differential_evolution.html>`__\nalgorithm in SciPy. I default the differential evolution algorithm to be\naggressive, and it is probably overkill for your problem. So feel free\nto pass your own differential evolution keywords to the library. See\n`this\nexample <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/fitForSpecifiedNumberOfLineSegments_passDiffEvoKeywords.py>`__.\n"
  },
  {
    "path": "docs/_sources/index.rst.txt",
    "content": "pwlf: piecewise linear fitting\n================================\n\nFit piecewise linear functions to data!\n\n.. toctree::\n   :maxdepth: 2\n\n   installation\n   how_it_works\n   examples\n   pwlf\n   about\n   requirements\n   license\n\nIndices and tables\n==================\n\n* :ref:`genindex`\n* :ref:`search`\n"
  },
  {
    "path": "docs/_sources/installation.rst.txt",
    "content": "Installation\n============\n\nPython Package Index (PyPI)\n---------------------------\n\nYou can now install with pip.\n\n::\n\n   python -m pip install pwlf\n\nConda\n-----\n\nIf you have conda, you can also install from conda-forge.\n\n::\n\n   conda install -c conda-forge pwlf\n\nFrom source\n-----------\n\nOr clone the repo\n\n::\n\n   git clone https://github.com/cjekel/piecewise_linear_fit_py.git\n\nthen install with pip\n\n::\n\n   python -m pip install ./piecewise_linear_fit_py\n\n"
  },
  {
    "path": "docs/_sources/license.rst.txt",
    "content": "License\n=======\n\nMIT License\n\nCopyright (c) 2017-2020 Charles Jekel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "docs/_sources/modules.rst.txt",
    "content": "pwlf\n====\n\n.. toctree::\n   :maxdepth: 4\n\n   pwlf\n"
  },
  {
    "path": "docs/_sources/pwlf.rst.txt",
    "content": "pwlf package contents\n============\n\n.. autosummary::\n     :toctree: stubs\n\n     pwlf.PiecewiseLinFit\n\n.. autoclass:: pwlf.PiecewiseLinFit\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "docs/_sources/requirements.rst.txt",
    "content": "Requirements\n============\n\n`NumPy <https://pypi.org/project/numpy/>`__ (>= 1.14.0)\n\n`SciPy <https://pypi.org/project/scipy/>`__ (>= 1.2.0)\n\n`pyDOE <https://pypi.org/project/pyDOE/>`__ ( >= 0.3.8)\n"
  },
  {
    "path": "docs/_sources/stubs/pwlf.PiecewiseLinFit.rst.txt",
    "content": "﻿pwlf.PiecewiseLinFit\n====================\n\n.. currentmodule:: pwlf\n\n.. autoclass:: PiecewiseLinFit\n\n   \n   .. automethod:: __init__\n\n   \n   .. rubric:: Methods\n\n   .. autosummary::\n   \n      ~PiecewiseLinFit.__init__\n      ~PiecewiseLinFit.assemble_regression_matrix\n      ~PiecewiseLinFit.calc_slopes\n      ~PiecewiseLinFit.conlstsq\n      ~PiecewiseLinFit.fit\n      ~PiecewiseLinFit.fit_force_points_opt\n      ~PiecewiseLinFit.fit_guess\n      ~PiecewiseLinFit.fit_with_breaks\n      ~PiecewiseLinFit.fit_with_breaks_force_points\n      ~PiecewiseLinFit.fit_with_breaks_opt\n      ~PiecewiseLinFit.fitfast\n      ~PiecewiseLinFit.lstsq\n      ~PiecewiseLinFit.p_values\n      ~PiecewiseLinFit.predict\n      ~PiecewiseLinFit.prediction_variance\n      ~PiecewiseLinFit.r_squared\n      ~PiecewiseLinFit.standard_errors\n      ~PiecewiseLinFit.use_custom_opt\n   \n   \n\n   \n   \n   "
  },
  {
    "path": "docs/_static/alabaster.css",
    "content": "/* -- page layout ----------------------------------------------------------- */\n\nbody {\n    font-family: Georgia, serif;\n    font-size: 17px;\n    background-color: #fff;\n    color: #000;\n    margin: 0;\n    padding: 0;\n}\n\n\ndiv.document {\n    width: 940px;\n    margin: 30px auto 0 auto;\n}\n\ndiv.documentwrapper {\n    float: left;\n    width: 100%;\n}\n\ndiv.bodywrapper {\n    margin: 0 0 0 220px;\n}\n\ndiv.sphinxsidebar {\n    width: 220px;\n    font-size: 14px;\n    line-height: 1.5;\n}\n\nhr {\n    border: 1px solid #B1B4B6;\n}\n\ndiv.body {\n    background-color: #fff;\n    color: #3E4349;\n    padding: 0 30px 0 30px;\n}\n\ndiv.body > .section {\n    text-align: left;\n}\n\ndiv.footer {\n    width: 940px;\n    margin: 20px auto 30px auto;\n    font-size: 14px;\n    color: #888;\n    text-align: right;\n}\n\ndiv.footer a {\n    color: #888;\n}\n\np.caption {\n    font-family: inherit;\n    font-size: inherit;\n}\n\n\ndiv.relations {\n    display: none;\n}\n\n\ndiv.sphinxsidebar {\n    max-height: 100%;\n    overflow-y: auto;\n}\n\ndiv.sphinxsidebar a {\n    color: #444;\n    text-decoration: none;\n    border-bottom: 1px dotted #999;\n}\n\ndiv.sphinxsidebar a:hover {\n    border-bottom: 1px solid #999;\n}\n\ndiv.sphinxsidebarwrapper {\n    padding: 18px 10px;\n}\n\ndiv.sphinxsidebarwrapper p.logo {\n    padding: 0;\n    margin: -10px 0 0 0px;\n    text-align: center;\n}\n\ndiv.sphinxsidebarwrapper h1.logo {\n    margin-top: -10px;\n    text-align: center;\n    margin-bottom: 5px;\n    text-align: left;\n}\n\ndiv.sphinxsidebarwrapper h1.logo-name {\n    margin-top: 0px;\n}\n\ndiv.sphinxsidebarwrapper p.blurb {\n    margin-top: 0;\n    font-style: normal;\n}\n\ndiv.sphinxsidebar h3,\ndiv.sphinxsidebar h4 {\n    font-family: Georgia, serif;\n    color: #444;\n    font-size: 24px;\n    font-weight: normal;\n    margin: 0 0 5px 0;\n    padding: 0;\n}\n\ndiv.sphinxsidebar h4 {\n    font-size: 20px;\n}\n\ndiv.sphinxsidebar h3 a {\n    color: #444;\n}\n\ndiv.sphinxsidebar p.logo a,\ndiv.sphinxsidebar h3 a,\ndiv.sphinxsidebar p.logo a:hover,\ndiv.sphinxsidebar h3 a:hover {\n    border: none;\n}\n\ndiv.sphinxsidebar p {\n    color: #555;\n    margin: 10px 0;\n}\n\ndiv.sphinxsidebar ul {\n    margin: 10px 0;\n    padding: 0;\n    color: #000;\n}\n\ndiv.sphinxsidebar ul li.toctree-l1 > a {\n    font-size: 120%;\n}\n\ndiv.sphinxsidebar ul li.toctree-l2 > a {\n    font-size: 110%;\n}\n\ndiv.sphinxsidebar input {\n    border: 1px solid #CCC;\n    font-family: Georgia, serif;\n    font-size: 1em;\n}\n\ndiv.sphinxsidebar #searchbox {\n    margin: 1em 0;\n}\n\ndiv.sphinxsidebar .search > div {\n    display: table-cell;\n}\n\ndiv.sphinxsidebar hr {\n    border: none;\n    height: 1px;\n    color: #AAA;\n    background: #AAA;\n\n    text-align: left;\n    margin-left: 0;\n    width: 50%;\n}\n\ndiv.sphinxsidebar .badge {\n    border-bottom: none;\n}\n\ndiv.sphinxsidebar .badge:hover {\n    border-bottom: none;\n}\n\n/* To address an issue with donation coming after search */\ndiv.sphinxsidebar h3.donation {\n    margin-top: 10px;\n}\n\n/* -- body styles ----------------------------------------------------------- */\n\na {\n    color: #004B6B;\n    text-decoration: underline;\n}\n\na:hover {\n    color: #6D4100;\n    text-decoration: underline;\n}\n\ndiv.body h1,\ndiv.body h2,\ndiv.body h3,\ndiv.body h4,\ndiv.body h5,\ndiv.body h6 {\n    font-family: Georgia, serif;\n    font-weight: normal;\n    margin: 30px 0px 10px 0px;\n    padding: 0;\n}\n\ndiv.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; }\ndiv.body h2 { font-size: 180%; }\ndiv.body h3 { font-size: 150%; }\ndiv.body h4 { font-size: 130%; }\ndiv.body h5 { font-size: 100%; }\ndiv.body h6 { font-size: 100%; }\n\na.headerlink {\n    color: #DDD;\n    padding: 0 4px;\n    text-decoration: none;\n}\n\na.headerlink:hover {\n    color: #444;\n    background: #EAEAEA;\n}\n\ndiv.body p, div.body dd, div.body li {\n    line-height: 1.4em;\n}\n\ndiv.admonition {\n    margin: 20px 0px;\n    padding: 10px 30px;\n    background-color: #EEE;\n    border: 1px solid #CCC;\n}\n\ndiv.admonition tt.xref, div.admonition code.xref, div.admonition a tt {\n    background-color: #FBFBFB;\n    border-bottom: 1px solid #fafafa;\n}\n\ndiv.admonition p.admonition-title {\n    font-family: Georgia, serif;\n    font-weight: normal;\n    font-size: 24px;\n    margin: 0 0 10px 0;\n    padding: 0;\n    line-height: 1;\n}\n\ndiv.admonition p.last {\n    margin-bottom: 0;\n}\n\ndt:target, .highlight {\n    background: #FAF3E8;\n}\n\ndiv.warning {\n    background-color: #FCC;\n    border: 1px solid #FAA;\n}\n\ndiv.danger {\n    background-color: #FCC;\n    border: 1px solid #FAA;\n    -moz-box-shadow: 2px 2px 4px #D52C2C;\n    -webkit-box-shadow: 2px 2px 4px #D52C2C;\n    box-shadow: 2px 2px 4px #D52C2C;\n}\n\ndiv.error {\n    background-color: #FCC;\n    border: 1px solid #FAA;\n    -moz-box-shadow: 2px 2px 4px #D52C2C;\n    -webkit-box-shadow: 2px 2px 4px #D52C2C;\n    box-shadow: 2px 2px 4px #D52C2C;\n}\n\ndiv.caution {\n    background-color: #FCC;\n    border: 1px solid #FAA;\n}\n\ndiv.attention {\n    background-color: #FCC;\n    border: 1px solid #FAA;\n}\n\ndiv.important {\n    background-color: #EEE;\n    border: 1px solid #CCC;\n}\n\ndiv.note {\n    background-color: #EEE;\n    border: 1px solid #CCC;\n}\n\ndiv.tip {\n    background-color: #EEE;\n    border: 1px solid #CCC;\n}\n\ndiv.hint {\n    background-color: #EEE;\n    border: 1px solid #CCC;\n}\n\ndiv.seealso {\n    background-color: #EEE;\n    border: 1px solid #CCC;\n}\n\ndiv.topic {\n    background-color: #EEE;\n}\n\np.admonition-title {\n    display: inline;\n}\n\np.admonition-title:after {\n    content: \":\";\n}\n\npre, tt, code {\n    font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;\n    font-size: 0.9em;\n}\n\n.hll {\n    background-color: #FFC;\n    margin: 0 -12px;\n    padding: 0 12px;\n    display: block;\n}\n\nimg.screenshot {\n}\n\ntt.descname, tt.descclassname, code.descname, code.descclassname {\n    font-size: 0.95em;\n}\n\ntt.descname, code.descname {\n    padding-right: 0.08em;\n}\n\nimg.screenshot {\n    -moz-box-shadow: 2px 2px 4px #EEE;\n    -webkit-box-shadow: 2px 2px 4px #EEE;\n    box-shadow: 2px 2px 4px #EEE;\n}\n\ntable.docutils {\n    border: 1px solid #888;\n    -moz-box-shadow: 2px 2px 4px #EEE;\n    -webkit-box-shadow: 2px 2px 4px #EEE;\n    box-shadow: 2px 2px 4px #EEE;\n}\n\ntable.docutils td, table.docutils th {\n    border: 1px solid #888;\n    padding: 0.25em 0.7em;\n}\n\ntable.field-list, table.footnote {\n    border: none;\n    -moz-box-shadow: none;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n}\n\ntable.footnote {\n    margin: 15px 0;\n    width: 100%;\n    border: 1px solid #EEE;\n    background: #FDFDFD;\n    font-size: 0.9em;\n}\n\ntable.footnote + table.footnote {\n    margin-top: -15px;\n    border-top: none;\n}\n\ntable.field-list th {\n    padding: 0 0.8em 0 0;\n}\n\ntable.field-list td {\n    padding: 0;\n}\n\ntable.field-list p {\n    margin-bottom: 0.8em;\n}\n\n/* Cloned from\n * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68\n */\n.field-name {\n    -moz-hyphens: manual;\n    -ms-hyphens: manual;\n    -webkit-hyphens: manual;\n    hyphens: manual;\n}\n\ntable.footnote td.label {\n    width: .1px;\n    padding: 0.3em 0 0.3em 0.5em;\n}\n\ntable.footnote td {\n    padding: 0.3em 0.5em;\n}\n\ndl {\n    margin-left: 0;\n    margin-right: 0;\n    margin-top: 0;\n    padding: 0;\n}\n\ndl dd {\n    margin-left: 30px;\n}\n\nblockquote {\n    margin: 0 0 0 30px;\n    padding: 0;\n}\n\nul, ol {\n    /* Matches the 30px from the narrow-screen \"li > ul\" selector below */\n    margin: 10px 0 10px 30px;\n    padding: 0;\n}\n\npre {\n    background: unset;\n    padding: 7px 30px;\n    margin: 15px 0px;\n    line-height: 1.3em;\n}\n\ndiv.viewcode-block:target {\n    background: #ffd;\n}\n\ndl pre, blockquote pre, li pre {\n    margin-left: 0;\n    padding-left: 30px;\n}\n\ntt, code {\n    background-color: #ecf0f3;\n    color: #222;\n    /* padding: 1px 2px; */\n}\n\ntt.xref, code.xref, a tt {\n    background-color: #FBFBFB;\n    border-bottom: 1px solid #fff;\n}\n\na.reference {\n    text-decoration: none;\n    border-bottom: 1px dotted #004B6B;\n}\n\na.reference:hover {\n    border-bottom: 1px solid #6D4100;\n}\n\n/* Don't put an underline on images */\na.image-reference, a.image-reference:hover {\n    border-bottom: none;\n}\n\na.footnote-reference {\n    text-decoration: none;\n    font-size: 0.7em;\n    vertical-align: top;\n    border-bottom: 1px dotted #004B6B;\n}\n\na.footnote-reference:hover {\n    border-bottom: 1px solid #6D4100;\n}\n\na:hover tt, a:hover code {\n    background: #EEE;\n}\n\n@media screen and (max-width: 940px) {\n\n    body {\n        margin: 0;\n        padding: 20px 30px;\n    }\n\n    div.documentwrapper {\n        float: none;\n        background: #fff;\n        margin-left: 0;\n        margin-top: 0;\n        margin-right: 0;\n        margin-bottom: 0;\n    }\n\n    div.sphinxsidebar {\n        display: block;\n        float: none;\n        width: unset;\n        margin: 50px -30px -20px -30px;\n        padding: 10px 20px;\n        background: #333;\n        color: #FFF;\n    }\n\n    div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p,\n    div.sphinxsidebar h3 a {\n        color: #fff;\n    }\n\n    div.sphinxsidebar a {\n        color: #AAA;\n    }\n\n    div.sphinxsidebar p.logo {\n        display: none;\n    }\n\n    div.document {\n        width: 100%;\n        margin: 0;\n    }\n\n    div.footer {\n        display: none;\n    }\n\n    div.bodywrapper {\n        margin: 0;\n    }\n\n    div.body {\n        min-height: 0;\n        min-width: auto; /* fixes width on small screens, breaks .hll */\n        padding: 0;\n    }\n    \n    .hll {\n        /* \"fixes\" the breakage */\n        width: max-content;\n    }\n\n    .rtd_doc_footer {\n        display: none;\n    }\n\n    .document {\n        width: auto;\n    }\n\n    .footer {\n        width: auto;\n    }\n\n    .github {\n        display: none;\n    }\n\n    ul {\n        margin-left: 0;\n    }\n\n    li > ul {\n       /* Matches the 30px from the \"ul, ol\" selector above */\n        margin-left: 30px;\n    }\n}\n\n\n/* misc. */\n\n.revsys-inline {\n    display: none!important;\n}\n\n/* Hide ugly table cell borders in ..bibliography:: directive output */\ntable.docutils.citation, table.docutils.citation td, table.docutils.citation th {\n  border: none;\n  /* Below needed in some edge cases; if not applied, bottom shadows appear */\n  -moz-box-shadow: none;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n\n\n/* relbar */\n\n.related {\n    line-height: 30px;\n    width: 100%;\n    font-size: 0.9rem;\n}\n\n.related.top {\n    border-bottom: 1px solid #EEE;\n    margin-bottom: 20px;\n}\n\n.related.bottom {\n    border-top: 1px solid #EEE;\n}\n\n.related ul {\n    padding: 0;\n    margin: 0;\n    list-style: none;\n}\n\n.related li {\n    display: inline;\n}\n\nnav#rellinks {\n    float: right;\n}\n\nnav#rellinks li+li:before {\n    content: \"|\";\n}\n\nnav#breadcrumbs li+li:before {\n    content: \"\\00BB\";\n}\n\n/* Hide certain items when printing */\n@media print {\n    div.related {\n        display: none;\n    }\n}\n\nimg.github  {\n    position: absolute;\n    top: 0;\n    border: 0;\n    right: 0;\n}"
  },
  {
    "path": "docs/_static/basic.css",
    "content": "/*\n * Sphinx stylesheet -- basic theme.\n */\n\n/* -- main layout ----------------------------------------------------------- */\n\ndiv.clearer {\n    clear: both;\n}\n\ndiv.section::after {\n    display: block;\n    content: '';\n    clear: left;\n}\n\n/* -- relbar ---------------------------------------------------------------- */\n\ndiv.related {\n    width: 100%;\n    font-size: 90%;\n}\n\ndiv.related h3 {\n    display: none;\n}\n\ndiv.related ul {\n    margin: 0;\n    padding: 0 0 0 10px;\n    list-style: none;\n}\n\ndiv.related li {\n    display: inline;\n}\n\ndiv.related li.right {\n    float: right;\n    margin-right: 5px;\n}\n\n/* -- sidebar --------------------------------------------------------------- */\n\ndiv.sphinxsidebarwrapper {\n    padding: 10px 5px 0 10px;\n}\n\ndiv.sphinxsidebar {\n    float: left;\n    width: 230px;\n    margin-left: -100%;\n    font-size: 90%;\n    word-wrap: break-word;\n    overflow-wrap : break-word;\n}\n\ndiv.sphinxsidebar ul {\n    list-style: none;\n}\n\ndiv.sphinxsidebar ul ul,\ndiv.sphinxsidebar ul.want-points {\n    margin-left: 20px;\n    list-style: square;\n}\n\ndiv.sphinxsidebar ul ul {\n    margin-top: 0;\n    margin-bottom: 0;\n}\n\ndiv.sphinxsidebar form {\n    margin-top: 10px;\n}\n\ndiv.sphinxsidebar input {\n    border: 1px solid #98dbcc;\n    font-family: sans-serif;\n    font-size: 1em;\n}\n\ndiv.sphinxsidebar #searchbox form.search {\n    overflow: hidden;\n}\n\ndiv.sphinxsidebar #searchbox input[type=\"text\"] {\n    float: left;\n    width: 80%;\n    padding: 0.25em;\n    box-sizing: border-box;\n}\n\ndiv.sphinxsidebar #searchbox input[type=\"submit\"] {\n    float: left;\n    width: 20%;\n    border-left: none;\n    padding: 0.25em;\n    box-sizing: border-box;\n}\n\n\nimg {\n    border: 0;\n    max-width: 100%;\n}\n\n/* -- search page ----------------------------------------------------------- */\n\nul.search {\n    margin-top: 10px;\n}\n\nul.search li {\n    padding: 5px 0;\n}\n\nul.search li a {\n    font-weight: bold;\n}\n\nul.search li p.context {\n    color: #888;\n    margin: 2px 0 0 30px;\n    text-align: left;\n}\n\nul.keywordmatches li.goodmatch a {\n    font-weight: bold;\n}\n\n/* -- index page ------------------------------------------------------------ */\n\ntable.contentstable {\n    width: 90%;\n    margin-left: auto;\n    margin-right: auto;\n}\n\ntable.contentstable p.biglink {\n    line-height: 150%;\n}\n\na.biglink {\n    font-size: 1.3em;\n}\n\nspan.linkdescr {\n    font-style: italic;\n    padding-top: 5px;\n    font-size: 90%;\n}\n\n/* -- general index --------------------------------------------------------- */\n\ntable.indextable {\n    width: 100%;\n}\n\ntable.indextable td {\n    text-align: left;\n    vertical-align: top;\n}\n\ntable.indextable ul {\n    margin-top: 0;\n    margin-bottom: 0;\n    list-style-type: none;\n}\n\ntable.indextable > tbody > tr > td > ul {\n    padding-left: 0em;\n}\n\ntable.indextable tr.pcap {\n    height: 10px;\n}\n\ntable.indextable tr.cap {\n    margin-top: 10px;\n    background-color: #f2f2f2;\n}\n\nimg.toggler {\n    margin-right: 3px;\n    margin-top: 3px;\n    cursor: pointer;\n}\n\ndiv.modindex-jumpbox {\n    border-top: 1px solid #ddd;\n    border-bottom: 1px solid #ddd;\n    margin: 1em 0 1em 0;\n    padding: 0.4em;\n}\n\ndiv.genindex-jumpbox {\n    border-top: 1px solid #ddd;\n    border-bottom: 1px solid #ddd;\n    margin: 1em 0 1em 0;\n    padding: 0.4em;\n}\n\n/* -- domain module index --------------------------------------------------- */\n\ntable.modindextable td {\n    padding: 2px;\n    border-collapse: collapse;\n}\n\n/* -- general body styles --------------------------------------------------- */\n\ndiv.body {\n    min-width: inherit;\n    max-width: 800px;\n}\n\ndiv.body p, div.body dd, div.body li, div.body blockquote {\n    -moz-hyphens: auto;\n    -ms-hyphens: auto;\n    -webkit-hyphens: auto;\n    hyphens: auto;\n}\n\na.headerlink {\n    visibility: hidden;\n}\n\na:visited {\n    color: #551A8B;\n}\n\nh1:hover > a.headerlink,\nh2:hover > a.headerlink,\nh3:hover > a.headerlink,\nh4:hover > a.headerlink,\nh5:hover > a.headerlink,\nh6:hover > a.headerlink,\ndt:hover > a.headerlink,\ncaption:hover > a.headerlink,\np.caption:hover > a.headerlink,\ndiv.code-block-caption:hover > a.headerlink {\n    visibility: visible;\n}\n\ndiv.body p.caption {\n    text-align: inherit;\n}\n\ndiv.body td {\n    text-align: left;\n}\n\n.first {\n    margin-top: 0 !important;\n}\n\np.rubric {\n    margin-top: 30px;\n    font-weight: bold;\n}\n\nimg.align-left, figure.align-left, .figure.align-left, object.align-left {\n    clear: left;\n    float: left;\n    margin-right: 1em;\n}\n\nimg.align-right, figure.align-right, .figure.align-right, object.align-right {\n    clear: right;\n    float: right;\n    margin-left: 1em;\n}\n\nimg.align-center, figure.align-center, .figure.align-center, object.align-center {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n\nimg.align-default, figure.align-default, .figure.align-default {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n\n.align-left {\n    text-align: left;\n}\n\n.align-center {\n    text-align: center;\n}\n\n.align-default {\n    text-align: center;\n}\n\n.align-right {\n    text-align: right;\n}\n\n/* -- sidebars -------------------------------------------------------------- */\n\ndiv.sidebar,\naside.sidebar {\n    margin: 0 0 0.5em 1em;\n    border: 1px solid #ddb;\n    padding: 7px;\n    background-color: #ffe;\n    width: 40%;\n    float: right;\n    clear: right;\n    overflow-x: auto;\n}\n\np.sidebar-title {\n    font-weight: bold;\n}\n\nnav.contents,\naside.topic,\ndiv.admonition, div.topic, blockquote {\n    clear: left;\n}\n\n/* -- topics ---------------------------------------------------------------- */\n\nnav.contents,\naside.topic,\ndiv.topic {\n    border: 1px solid #ccc;\n    padding: 7px;\n    margin: 10px 0 10px 0;\n}\n\np.topic-title {\n    font-size: 1.1em;\n    font-weight: bold;\n    margin-top: 10px;\n}\n\n/* -- admonitions ----------------------------------------------------------- */\n\ndiv.admonition {\n    margin-top: 10px;\n    margin-bottom: 10px;\n    padding: 7px;\n}\n\ndiv.admonition dt {\n    font-weight: bold;\n}\n\np.admonition-title {\n    margin: 0px 10px 5px 0px;\n    font-weight: bold;\n}\n\ndiv.body p.centered {\n    text-align: center;\n    margin-top: 25px;\n}\n\n/* -- content of sidebars/topics/admonitions -------------------------------- */\n\ndiv.sidebar > :last-child,\naside.sidebar > :last-child,\nnav.contents > :last-child,\naside.topic > :last-child,\ndiv.topic > :last-child,\ndiv.admonition > :last-child {\n    margin-bottom: 0;\n}\n\ndiv.sidebar::after,\naside.sidebar::after,\nnav.contents::after,\naside.topic::after,\ndiv.topic::after,\ndiv.admonition::after,\nblockquote::after {\n    display: block;\n    content: '';\n    clear: both;\n}\n\n/* -- tables ---------------------------------------------------------------- */\n\ntable.docutils {\n    margin-top: 10px;\n    margin-bottom: 10px;\n    border: 0;\n    border-collapse: collapse;\n}\n\ntable.align-center {\n    margin-left: auto;\n    margin-right: auto;\n}\n\ntable.align-default {\n    margin-left: auto;\n    margin-right: auto;\n}\n\ntable caption span.caption-number {\n    font-style: italic;\n}\n\ntable caption span.caption-text {\n}\n\ntable.docutils td, table.docutils th {\n    padding: 1px 8px 1px 5px;\n    border-top: 0;\n    border-left: 0;\n    border-right: 0;\n    border-bottom: 1px solid #aaa;\n}\n\nth {\n    text-align: left;\n    padding-right: 5px;\n}\n\ntable.citation {\n    border-left: solid 1px gray;\n    margin-left: 1px;\n}\n\ntable.citation td {\n    border-bottom: none;\n}\n\nth > :first-child,\ntd > :first-child {\n    margin-top: 0px;\n}\n\nth > :last-child,\ntd > :last-child {\n    margin-bottom: 0px;\n}\n\n/* -- figures --------------------------------------------------------------- */\n\ndiv.figure, figure {\n    margin: 0.5em;\n    padding: 0.5em;\n}\n\ndiv.figure p.caption, figcaption {\n    padding: 0.3em;\n}\n\ndiv.figure p.caption span.caption-number,\nfigcaption span.caption-number {\n    font-style: italic;\n}\n\ndiv.figure p.caption span.caption-text,\nfigcaption span.caption-text {\n}\n\n/* -- field list styles ----------------------------------------------------- */\n\ntable.field-list td, table.field-list th {\n    border: 0 !important;\n}\n\n.field-list ul {\n    margin: 0;\n    padding-left: 1em;\n}\n\n.field-list p {\n    margin: 0;\n}\n\n.field-name {\n    -moz-hyphens: manual;\n    -ms-hyphens: manual;\n    -webkit-hyphens: manual;\n    hyphens: manual;\n}\n\n/* -- hlist styles ---------------------------------------------------------- */\n\ntable.hlist {\n    margin: 1em 0;\n}\n\ntable.hlist td {\n    vertical-align: top;\n}\n\n/* -- object description styles --------------------------------------------- */\n\n.sig {\n\tfont-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;\n}\n\n.sig-name, code.descname {\n    background-color: transparent;\n    font-weight: bold;\n}\n\n.sig-name {\n\tfont-size: 1.1em;\n}\n\ncode.descname {\n    font-size: 1.2em;\n}\n\n.sig-prename, code.descclassname {\n    background-color: transparent;\n}\n\n.optional {\n    font-size: 1.3em;\n}\n\n.sig-paren {\n    font-size: larger;\n}\n\n.sig-param.n {\n\tfont-style: italic;\n}\n\n/* C++ specific styling */\n\n.sig-inline.c-texpr,\n.sig-inline.cpp-texpr {\n\tfont-family: unset;\n}\n\n.sig.c   .k, .sig.c   .kt,\n.sig.cpp .k, .sig.cpp .kt {\n\tcolor: #0033B3;\n}\n\n.sig.c   .m,\n.sig.cpp .m {\n\tcolor: #1750EB;\n}\n\n.sig.c   .s, .sig.c   .sc,\n.sig.cpp .s, .sig.cpp .sc {\n\tcolor: #067D17;\n}\n\n\n/* -- other body styles ----------------------------------------------------- */\n\nol.arabic {\n    list-style: decimal;\n}\n\nol.loweralpha {\n    list-style: lower-alpha;\n}\n\nol.upperalpha {\n    list-style: upper-alpha;\n}\n\nol.lowerroman {\n    list-style: lower-roman;\n}\n\nol.upperroman {\n    list-style: upper-roman;\n}\n\n:not(li) > ol > li:first-child > :first-child,\n:not(li) > ul > li:first-child > :first-child {\n    margin-top: 0px;\n}\n\n:not(li) > ol > li:last-child > :last-child,\n:not(li) > ul > li:last-child > :last-child {\n    margin-bottom: 0px;\n}\n\nol.simple ol p,\nol.simple ul p,\nul.simple ol p,\nul.simple ul p {\n    margin-top: 0;\n}\n\nol.simple > li:not(:first-child) > p,\nul.simple > li:not(:first-child) > p {\n    margin-top: 0;\n}\n\nol.simple p,\nul.simple p {\n    margin-bottom: 0;\n}\n\naside.footnote > span,\ndiv.citation > span {\n    float: left;\n}\naside.footnote > span:last-of-type,\ndiv.citation > span:last-of-type {\n  padding-right: 0.5em;\n}\naside.footnote > p {\n  margin-left: 2em;\n}\ndiv.citation > p {\n  margin-left: 4em;\n}\naside.footnote > p:last-of-type,\ndiv.citation > p:last-of-type {\n    margin-bottom: 0em;\n}\naside.footnote > p:last-of-type:after,\ndiv.citation > p:last-of-type:after {\n    content: \"\";\n    clear: both;\n}\n\ndl.field-list {\n    display: grid;\n    grid-template-columns: fit-content(30%) auto;\n}\n\ndl.field-list > dt {\n    font-weight: bold;\n    word-break: break-word;\n    padding-left: 0.5em;\n    padding-right: 5px;\n}\n\ndl.field-list > dd {\n    padding-left: 0.5em;\n    margin-top: 0em;\n    margin-left: 0em;\n    margin-bottom: 0em;\n}\n\ndl {\n    margin-bottom: 15px;\n}\n\ndd > :first-child {\n    margin-top: 0px;\n}\n\ndd ul, dd table {\n    margin-bottom: 10px;\n}\n\ndd {\n    margin-top: 3px;\n    margin-bottom: 10px;\n    margin-left: 30px;\n}\n\n.sig dd {\n    margin-top: 0px;\n    margin-bottom: 0px;\n}\n\n.sig dl {\n    margin-top: 0px;\n    margin-bottom: 0px;\n}\n\ndl > dd:last-child,\ndl > dd:last-child > :last-child {\n    margin-bottom: 0;\n}\n\ndt:target, span.highlighted {\n    background-color: #fbe54e;\n}\n\nrect.highlighted {\n    fill: #fbe54e;\n}\n\ndl.glossary dt {\n    font-weight: bold;\n    font-size: 1.1em;\n}\n\n.versionmodified {\n    font-style: italic;\n}\n\n.system-message {\n    background-color: #fda;\n    padding: 5px;\n    border: 3px solid red;\n}\n\n.footnote:target  {\n    background-color: #ffa;\n}\n\n.line-block {\n    display: block;\n    margin-top: 1em;\n    margin-bottom: 1em;\n}\n\n.line-block .line-block {\n    margin-top: 0;\n    margin-bottom: 0;\n    margin-left: 1.5em;\n}\n\n.guilabel, .menuselection {\n    font-family: sans-serif;\n}\n\n.accelerator {\n    text-decoration: underline;\n}\n\n.classifier {\n    font-style: oblique;\n}\n\n.classifier:before {\n    font-style: normal;\n    margin: 0 0.5em;\n    content: \":\";\n    display: inline-block;\n}\n\nabbr, acronym {\n    border-bottom: dotted 1px;\n    cursor: help;\n}\n\n.translated {\n    background-color: rgba(207, 255, 207, 0.2)\n}\n\n.untranslated {\n    background-color: rgba(255, 207, 207, 0.2)\n}\n\n/* -- code displays --------------------------------------------------------- */\n\npre {\n    overflow: auto;\n    overflow-y: hidden;  /* fixes display issues on Chrome browsers */\n}\n\npre, div[class*=\"highlight-\"] {\n    clear: both;\n}\n\nspan.pre {\n    -moz-hyphens: none;\n    -ms-hyphens: none;\n    -webkit-hyphens: none;\n    hyphens: none;\n    white-space: nowrap;\n}\n\ndiv[class*=\"highlight-\"] {\n    margin: 1em 0;\n}\n\ntd.linenos pre {\n    border: 0;\n    background-color: transparent;\n    color: #aaa;\n}\n\ntable.highlighttable {\n    display: block;\n}\n\ntable.highlighttable tbody {\n    display: block;\n}\n\ntable.highlighttable tr {\n    display: flex;\n}\n\ntable.highlighttable td {\n    margin: 0;\n    padding: 0;\n}\n\ntable.highlighttable td.linenos {\n    padding-right: 0.5em;\n}\n\ntable.highlighttable td.code {\n    flex: 1;\n    overflow: hidden;\n}\n\n.highlight .hll {\n    display: block;\n}\n\ndiv.highlight pre,\ntable.highlighttable pre {\n    margin: 0;\n}\n\ndiv.code-block-caption + div {\n    margin-top: 0;\n}\n\ndiv.code-block-caption {\n    margin-top: 1em;\n    padding: 2px 5px;\n    font-size: small;\n}\n\ndiv.code-block-caption code {\n    background-color: transparent;\n}\n\ntable.highlighttable td.linenos,\nspan.linenos,\ndiv.highlight span.gp {  /* gp: Generic.Prompt */\n  user-select: none;\n  -webkit-user-select: text; /* Safari fallback only */\n  -webkit-user-select: none; /* Chrome/Safari */\n  -moz-user-select: none; /* Firefox */\n  -ms-user-select: none; /* IE10+ */\n}\n\ndiv.code-block-caption span.caption-number {\n    padding: 0.1em 0.3em;\n    font-style: italic;\n}\n\ndiv.code-block-caption span.caption-text {\n}\n\ndiv.literal-block-wrapper {\n    margin: 1em 0;\n}\n\ncode.xref, a code {\n    background-color: transparent;\n    font-weight: bold;\n}\n\nh1 code, h2 code, h3 code, h4 code, h5 code, h6 code {\n    background-color: transparent;\n}\n\n.viewcode-link {\n    float: right;\n}\n\n.viewcode-back {\n    float: right;\n    font-family: sans-serif;\n}\n\ndiv.viewcode-block:target {\n    margin: -1px -10px;\n    padding: 0 10px;\n}\n\n/* -- math display ---------------------------------------------------------- */\n\nimg.math {\n    vertical-align: middle;\n}\n\ndiv.body div.math p {\n    text-align: center;\n}\n\nspan.eqno {\n    float: right;\n}\n\nspan.eqno a.headerlink {\n    position: absolute;\n    z-index: 1;\n}\n\ndiv.math:hover a.headerlink {\n    visibility: visible;\n}\n\n/* -- printout stylesheet --------------------------------------------------- */\n\n@media print {\n    div.document,\n    div.documentwrapper,\n    div.bodywrapper {\n        margin: 0 !important;\n        width: 100%;\n    }\n\n    div.sphinxsidebar,\n    div.related,\n    div.footer,\n    #top-link {\n        display: none;\n    }\n}"
  },
  {
    "path": "docs/_static/custom.css",
    "content": "/* This file intentionally left blank. */\n"
  },
  {
    "path": "docs/_static/doctools.js",
    "content": "/*\n * Base JavaScript utilities for all Sphinx HTML documentation.\n */\n\"use strict\";\n\nconst BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([\n  \"TEXTAREA\",\n  \"INPUT\",\n  \"SELECT\",\n  \"BUTTON\",\n]);\n\nconst _ready = (callback) => {\n  if (document.readyState !== \"loading\") {\n    callback();\n  } else {\n    document.addEventListener(\"DOMContentLoaded\", callback);\n  }\n};\n\n/**\n * Small JavaScript module for the documentation.\n */\nconst Documentation = {\n  init: () => {\n    Documentation.initDomainIndexTable();\n    Documentation.initOnKeyListeners();\n  },\n\n  /**\n   * i18n support\n   */\n  TRANSLATIONS: {},\n  PLURAL_EXPR: (n) => (n === 1 ? 0 : 1),\n  LOCALE: \"unknown\",\n\n  // gettext and ngettext don't access this so that the functions\n  // can safely bound to a different name (_ = Documentation.gettext)\n  gettext: (string) => {\n    const translated = Documentation.TRANSLATIONS[string];\n    switch (typeof translated) {\n      case \"undefined\":\n        return string; // no translation\n      case \"string\":\n        return translated; // translation exists\n      default:\n        return translated[0]; // (singular, plural) translation tuple exists\n    }\n  },\n\n  ngettext: (singular, plural, n) => {\n    const translated = Documentation.TRANSLATIONS[singular];\n    if (typeof translated !== \"undefined\")\n      return translated[Documentation.PLURAL_EXPR(n)];\n    return n === 1 ? singular : plural;\n  },\n\n  addTranslations: (catalog) => {\n    Object.assign(Documentation.TRANSLATIONS, catalog.messages);\n    Documentation.PLURAL_EXPR = new Function(\n      \"n\",\n      `return (${catalog.plural_expr})`\n    );\n    Documentation.LOCALE = catalog.locale;\n  },\n\n  /**\n   * helper function to focus on search bar\n   */\n  focusSearchBar: () => {\n    document.querySelectorAll(\"input[name=q]\")[0]?.focus();\n  },\n\n  /**\n   * Initialise the domain index toggle buttons\n   */\n  initDomainIndexTable: () => {\n    const toggler = (el) => {\n      const idNumber = el.id.substr(7);\n      const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`);\n      if (el.src.substr(-9) === \"minus.png\") {\n        el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`;\n        toggledRows.forEach((el) => (el.style.display = \"none\"));\n      } else {\n        el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`;\n        toggledRows.forEach((el) => (el.style.display = \"\"));\n      }\n    };\n\n    const togglerElements = document.querySelectorAll(\"img.toggler\");\n    togglerElements.forEach((el) =>\n      el.addEventListener(\"click\", (event) => toggler(event.currentTarget))\n    );\n    togglerElements.forEach((el) => (el.style.display = \"\"));\n    if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler);\n  },\n\n  initOnKeyListeners: () => {\n    // only install a listener if it is really needed\n    if (\n      !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS &&\n      !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS\n    )\n      return;\n\n    document.addEventListener(\"keydown\", (event) => {\n      // bail for input elements\n      if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;\n      // bail with special keys\n      if (event.altKey || event.ctrlKey || event.metaKey) return;\n\n      if (!event.shiftKey) {\n        switch (event.key) {\n          case \"ArrowLeft\":\n            if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;\n\n            const prevLink = document.querySelector('link[rel=\"prev\"]');\n            if (prevLink && prevLink.href) {\n              window.location.href = prevLink.href;\n              event.preventDefault();\n            }\n            break;\n          case \"ArrowRight\":\n            if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break;\n\n            const nextLink = document.querySelector('link[rel=\"next\"]');\n            if (nextLink && nextLink.href) {\n              window.location.href = nextLink.href;\n              event.preventDefault();\n            }\n            break;\n        }\n      }\n\n      // some keyboard layouts may need Shift to get /\n      switch (event.key) {\n        case \"/\":\n          if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break;\n          Documentation.focusSearchBar();\n          event.preventDefault();\n      }\n    });\n  },\n};\n\n// quick alias for translations\nconst _ = Documentation.gettext;\n\n_ready(Documentation.init);\n"
  },
  {
    "path": "docs/_static/documentation_options.js",
    "content": "const DOCUMENTATION_OPTIONS = {\n    VERSION: '2.5.2',\n    LANGUAGE: 'en',\n    COLLAPSE_INDEX: false,\n    BUILDER: 'html',\n    FILE_SUFFIX: '.html',\n    LINK_SUFFIX: '.html',\n    HAS_SOURCE: true,\n    SOURCELINK_SUFFIX: '.txt',\n    NAVIGATION_WITH_KEYS: false,\n    SHOW_SEARCH_SUMMARY: true,\n    ENABLE_SEARCH_SHORTCUTS: true,\n};"
  },
  {
    "path": "docs/_static/language_data.js",
    "content": "/*\n * This script contains the language-specific data used by searchtools.js,\n * namely the list of stopwords, stemmer, scorer and splitter.\n */\n\nvar stopwords = [\"a\", \"and\", \"are\", \"as\", \"at\", \"be\", \"but\", \"by\", \"for\", \"if\", \"in\", \"into\", \"is\", \"it\", \"near\", \"no\", \"not\", \"of\", \"on\", \"or\", \"such\", \"that\", \"the\", \"their\", \"then\", \"there\", \"these\", \"they\", \"this\", \"to\", \"was\", \"will\", \"with\"];\n\n\n/* Non-minified version is copied as a separate JS file, if available */\n\n/**\n * Porter Stemmer\n */\nvar Stemmer = function() {\n\n  var step2list = {\n    ational: 'ate',\n    tional: 'tion',\n    enci: 'ence',\n    anci: 'ance',\n    izer: 'ize',\n    bli: 'ble',\n    alli: 'al',\n    entli: 'ent',\n    eli: 'e',\n    ousli: 'ous',\n    ization: 'ize',\n    ation: 'ate',\n    ator: 'ate',\n    alism: 'al',\n    iveness: 'ive',\n    fulness: 'ful',\n    ousness: 'ous',\n    aliti: 'al',\n    iviti: 'ive',\n    biliti: 'ble',\n    logi: 'log'\n  };\n\n  var step3list = {\n    icate: 'ic',\n    ative: '',\n    alize: 'al',\n    iciti: 'ic',\n    ical: 'ic',\n    ful: '',\n    ness: ''\n  };\n\n  var c = \"[^aeiou]\";          // consonant\n  var v = \"[aeiouy]\";          // vowel\n  var C = c + \"[^aeiouy]*\";    // consonant sequence\n  var V = v + \"[aeiou]*\";      // vowel sequence\n\n  var mgr0 = \"^(\" + C + \")?\" + V + C;                      // [C]VC... is m>0\n  var meq1 = \"^(\" + C + \")?\" + V + C + \"(\" + V + \")?$\";    // [C]VC[V] is m=1\n  var mgr1 = \"^(\" + C + \")?\" + V + C + V + C;              // [C]VCVC... is m>1\n  var s_v   = \"^(\" + C + \")?\" + v;                         // vowel in stem\n\n  this.stemWord = function (w) {\n    var stem;\n    var suffix;\n    var firstch;\n    var origword = w;\n\n    if (w.length < 3)\n      return w;\n\n    var re;\n    var re2;\n    var re3;\n    var re4;\n\n    firstch = w.substr(0,1);\n    if (firstch == \"y\")\n      w = firstch.toUpperCase() + w.substr(1);\n\n    // Step 1a\n    re = /^(.+?)(ss|i)es$/;\n    re2 = /^(.+?)([^s])s$/;\n\n    if (re.test(w))\n      w = w.replace(re,\"$1$2\");\n    else if (re2.test(w))\n      w = w.replace(re2,\"$1$2\");\n\n    // Step 1b\n    re = /^(.+?)eed$/;\n    re2 = /^(.+?)(ed|ing)$/;\n    if (re.test(w)) {\n      var fp = re.exec(w);\n      re = new RegExp(mgr0);\n      if (re.test(fp[1])) {\n        re = /.$/;\n        w = w.replace(re,\"\");\n      }\n    }\n    else if (re2.test(w)) {\n      var fp = re2.exec(w);\n      stem = fp[1];\n      re2 = new RegExp(s_v);\n      if (re2.test(stem)) {\n        w = stem;\n        re2 = /(at|bl|iz)$/;\n        re3 = new RegExp(\"([^aeiouylsz])\\\\1$\");\n        re4 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n        if (re2.test(w))\n          w = w + \"e\";\n        else if (re3.test(w)) {\n          re = /.$/;\n          w = w.replace(re,\"\");\n        }\n        else if (re4.test(w))\n          w = w + \"e\";\n      }\n    }\n\n    // Step 1c\n    re = /^(.+?)y$/;\n    if (re.test(w)) {\n      var fp = re.exec(w);\n      stem = fp[1];\n      re = new RegExp(s_v);\n      if (re.test(stem))\n        w = stem + \"i\";\n    }\n\n    // Step 2\n    re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;\n    if (re.test(w)) {\n      var fp = re.exec(w);\n      stem = fp[1];\n      suffix = fp[2];\n      re = new RegExp(mgr0);\n      if (re.test(stem))\n        w = stem + step2list[suffix];\n    }\n\n    // Step 3\n    re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;\n    if (re.test(w)) {\n      var fp = re.exec(w);\n      stem = fp[1];\n      suffix = fp[2];\n      re = new RegExp(mgr0);\n      if (re.test(stem))\n        w = stem + step3list[suffix];\n    }\n\n    // Step 4\n    re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;\n    re2 = /^(.+?)(s|t)(ion)$/;\n    if (re.test(w)) {\n      var fp = re.exec(w);\n      stem = fp[1];\n      re = new RegExp(mgr1);\n      if (re.test(stem))\n        w = stem;\n    }\n    else if (re2.test(w)) {\n      var fp = re2.exec(w);\n      stem = fp[1] + fp[2];\n      re2 = new RegExp(mgr1);\n      if (re2.test(stem))\n        w = stem;\n    }\n\n    // Step 5\n    re = /^(.+?)e$/;\n    if (re.test(w)) {\n      var fp = re.exec(w);\n      stem = fp[1];\n      re = new RegExp(mgr1);\n      re2 = new RegExp(meq1);\n      re3 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n      if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))\n        w = stem;\n    }\n    re = /ll$/;\n    re2 = new RegExp(mgr1);\n    if (re.test(w) && re2.test(w)) {\n      re = /.$/;\n      w = w.replace(re,\"\");\n    }\n\n    // and turn initial Y back to y\n    if (firstch == \"y\")\n      w = firstch.toLowerCase() + w.substr(1);\n    return w;\n  }\n}\n\n"
  },
  {
    "path": "docs/_static/pygments.css",
    "content": "pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.highlight .hll { background-color: #ffffcc }\n.highlight { background: #f8f8f8; }\n.highlight .c { color: #8f5902; font-style: italic } /* Comment */\n.highlight .err { color: #a40000; border: 1px solid #ef2929 } /* Error */\n.highlight .g { color: #000000 } /* Generic */\n.highlight .k { color: #004461; font-weight: bold } /* Keyword */\n.highlight .l { color: #000000 } /* Literal */\n.highlight .n { color: #000000 } /* Name */\n.highlight .o { color: #582800 } /* Operator */\n.highlight .x { color: #000000 } /* Other */\n.highlight .p { color: #000000; font-weight: bold } /* Punctuation */\n.highlight .ch { color: #8f5902; font-style: italic } /* Comment.Hashbang */\n.highlight .cm { color: #8f5902; font-style: italic } /* Comment.Multiline */\n.highlight .cp { color: #8f5902 } /* Comment.Preproc */\n.highlight .cpf { color: #8f5902; font-style: italic } /* Comment.PreprocFile */\n.highlight .c1 { color: #8f5902; font-style: italic } /* Comment.Single */\n.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */\n.highlight .gd { color: #a40000 } /* Generic.Deleted */\n.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */\n.highlight .ges { color: #000000 } /* Generic.EmphStrong */\n.highlight .gr { color: #ef2929 } /* Generic.Error */\n.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n.highlight .gi { color: #00A000 } /* Generic.Inserted */\n.highlight .go { color: #888888 } /* Generic.Output */\n.highlight .gp { color: #745334 } /* Generic.Prompt */\n.highlight .gs { color: #000000; font-weight: bold } /* Generic.Strong */\n.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n.highlight .gt { color: #a40000; font-weight: bold } /* Generic.Traceback */\n.highlight .kc { color: #004461; font-weight: bold } /* Keyword.Constant */\n.highlight .kd { color: #004461; font-weight: bold } /* Keyword.Declaration */\n.highlight .kn { color: #004461; font-weight: bold } /* Keyword.Namespace */\n.highlight .kp { color: #004461; font-weight: bold } /* Keyword.Pseudo */\n.highlight .kr { color: #004461; font-weight: bold } /* Keyword.Reserved */\n.highlight .kt { color: #004461; font-weight: bold } /* Keyword.Type */\n.highlight .ld { color: #000000 } /* Literal.Date */\n.highlight .m { color: #990000 } /* Literal.Number */\n.highlight .s { color: #4e9a06 } /* Literal.String */\n.highlight .na { color: #c4a000 } /* Name.Attribute */\n.highlight .nb { color: #004461 } /* Name.Builtin */\n.highlight .nc { color: #000000 } /* Name.Class */\n.highlight .no { color: #000000 } /* Name.Constant */\n.highlight .nd { color: #888888 } /* Name.Decorator */\n.highlight .ni { color: #ce5c00 } /* Name.Entity */\n.highlight .ne { color: #cc0000; font-weight: bold } /* Name.Exception */\n.highlight .nf { color: #000000 } /* Name.Function */\n.highlight .nl { color: #f57900 } /* Name.Label */\n.highlight .nn { color: #000000 } /* Name.Namespace */\n.highlight .nx { color: #000000 } /* Name.Other */\n.highlight .py { color: #000000 } /* Name.Property */\n.highlight .nt { color: #004461; font-weight: bold } /* Name.Tag */\n.highlight .nv { color: #000000 } /* Name.Variable */\n.highlight .ow { color: #004461; font-weight: bold } /* Operator.Word */\n.highlight .pm { color: #000000; font-weight: bold } /* Punctuation.Marker */\n.highlight .w { color: #f8f8f8 } /* Text.Whitespace */\n.highlight .mb { color: #990000 } /* Literal.Number.Bin */\n.highlight .mf { color: #990000 } /* Literal.Number.Float */\n.highlight .mh { color: #990000 } /* Literal.Number.Hex */\n.highlight .mi { color: #990000 } /* Literal.Number.Integer */\n.highlight .mo { color: #990000 } /* Literal.Number.Oct */\n.highlight .sa { color: #4e9a06 } /* Literal.String.Affix */\n.highlight .sb { color: #4e9a06 } /* Literal.String.Backtick */\n.highlight .sc { color: #4e9a06 } /* Literal.String.Char */\n.highlight .dl { color: #4e9a06 } /* Literal.String.Delimiter */\n.highlight .sd { color: #8f5902; font-style: italic } /* Literal.String.Doc */\n.highlight .s2 { color: #4e9a06 } /* Literal.String.Double */\n.highlight .se { color: #4e9a06 } /* Literal.String.Escape */\n.highlight .sh { color: #4e9a06 } /* Literal.String.Heredoc */\n.highlight .si { color: #4e9a06 } /* Literal.String.Interpol */\n.highlight .sx { color: #4e9a06 } /* Literal.String.Other */\n.highlight .sr { color: #4e9a06 } /* Literal.String.Regex */\n.highlight .s1 { color: #4e9a06 } /* Literal.String.Single */\n.highlight .ss { color: #4e9a06 } /* Literal.String.Symbol */\n.highlight .bp { color: #3465a4 } /* Name.Builtin.Pseudo */\n.highlight .fm { color: #000000 } /* Name.Function.Magic */\n.highlight .vc { color: #000000 } /* Name.Variable.Class */\n.highlight .vg { color: #000000 } /* Name.Variable.Global */\n.highlight .vi { color: #000000 } /* Name.Variable.Instance */\n.highlight .vm { color: #000000 } /* Name.Variable.Magic */\n.highlight .il { color: #990000 } /* Literal.Number.Integer.Long */"
  },
  {
    "path": "docs/_static/searchtools.js",
    "content": "/*\n * Sphinx JavaScript utilities for the full-text search.\n */\n\"use strict\";\n\n/**\n * Simple result scoring code.\n */\nif (typeof Scorer === \"undefined\") {\n  var Scorer = {\n    // Implement the following function to further tweak the score for each result\n    // The function takes a result array [docname, title, anchor, descr, score, filename]\n    // and returns the new score.\n    /*\n    score: result => {\n      const [docname, title, anchor, descr, score, filename, kind] = result\n      return score\n    },\n    */\n\n    // query matches the full name of an object\n    objNameMatch: 11,\n    // or matches in the last dotted part of the object name\n    objPartialMatch: 6,\n    // Additive scores depending on the priority of the object\n    objPrio: {\n      0: 15, // used to be importantResults\n      1: 5, // used to be objectResults\n      2: -5, // used to be unimportantResults\n    },\n    //  Used when the priority is not in the mapping.\n    objPrioDefault: 0,\n\n    // query found in title\n    title: 15,\n    partialTitle: 7,\n    // query found in terms\n    term: 5,\n    partialTerm: 2,\n  };\n}\n\n// Global search result kind enum, used by themes to style search results.\nclass SearchResultKind {\n    static get index() { return  \"index\"; }\n    static get object() { return \"object\"; }\n    static get text() { return \"text\"; }\n    static get title() { return \"title\"; }\n}\n\nconst _removeChildren = (element) => {\n  while (element && element.lastChild) element.removeChild(element.lastChild);\n};\n\n/**\n * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping\n */\nconst _escapeRegExp = (string) =>\n  string.replace(/[.*+\\-?^${}()|[\\]\\\\]/g, \"\\\\$&\"); // $& means the whole matched string\n\nconst _displayItem = (item, searchTerms, highlightTerms) => {\n  const docBuilder = DOCUMENTATION_OPTIONS.BUILDER;\n  const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX;\n  const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX;\n  const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY;\n  const contentRoot = document.documentElement.dataset.content_root;\n\n  const [docName, title, anchor, descr, score, _filename, kind] = item;\n\n  let listItem = document.createElement(\"li\");\n  // Add a class representing the item's type:\n  // can be used by a theme's CSS selector for styling\n  // See SearchResultKind for the class names.\n  listItem.classList.add(`kind-${kind}`);\n  let requestUrl;\n  let linkUrl;\n  if (docBuilder === \"dirhtml\") {\n    // dirhtml builder\n    let dirname = docName + \"/\";\n    if (dirname.match(/\\/index\\/$/))\n      dirname = dirname.substring(0, dirname.length - 6);\n    else if (dirname === \"index/\") dirname = \"\";\n    requestUrl = contentRoot + dirname;\n    linkUrl = requestUrl;\n  } else {\n    // normal html builders\n    requestUrl = contentRoot + docName + docFileSuffix;\n    linkUrl = docName + docLinkSuffix;\n  }\n  let linkEl = listItem.appendChild(document.createElement(\"a\"));\n  linkEl.href = linkUrl + anchor;\n  linkEl.dataset.score = score;\n  linkEl.innerHTML = title;\n  if (descr) {\n    listItem.appendChild(document.createElement(\"span\")).innerHTML =\n      \" (\" + descr + \")\";\n    // highlight search terms in the description\n    if (SPHINX_HIGHLIGHT_ENABLED)  // set in sphinx_highlight.js\n      highlightTerms.forEach((term) => _highlightText(listItem, term, \"highlighted\"));\n  }\n  else if (showSearchSummary)\n    fetch(requestUrl)\n      .then((responseData) => responseData.text())\n      .then((data) => {\n        if (data)\n          listItem.appendChild(\n            Search.makeSearchSummary(data, searchTerms, anchor)\n          );\n        // highlight search terms in the summary\n        if (SPHINX_HIGHLIGHT_ENABLED)  // set in sphinx_highlight.js\n          highlightTerms.forEach((term) => _highlightText(listItem, term, \"highlighted\"));\n      });\n  Search.output.appendChild(listItem);\n};\nconst _finishSearch = (resultCount) => {\n  Search.stopPulse();\n  Search.title.innerText = _(\"Search Results\");\n  if (!resultCount)\n    Search.status.innerText = Documentation.gettext(\n      \"Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories.\"\n    );\n  else\n    Search.status.innerText = Documentation.ngettext(\n      \"Search finished, found one page matching the search query.\",\n      \"Search finished, found ${resultCount} pages matching the search query.\",\n      resultCount,\n    ).replace('${resultCount}', resultCount);\n};\nconst _displayNextItem = (\n  results,\n  resultCount,\n  searchTerms,\n  highlightTerms,\n) => {\n  // results left, load the summary and display it\n  // this is intended to be dynamic (don't sub resultsCount)\n  if (results.length) {\n    _displayItem(results.pop(), searchTerms, highlightTerms);\n    setTimeout(\n      () => _displayNextItem(results, resultCount, searchTerms, highlightTerms),\n      5\n    );\n  }\n  // search finished, update title and status message\n  else _finishSearch(resultCount);\n};\n// Helper function used by query() to order search results.\n// Each input is an array of [docname, title, anchor, descr, score, filename, kind].\n// Order the results by score (in opposite order of appearance, since the\n// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically.\nconst _orderResultsByScoreThenName = (a, b) => {\n  const leftScore = a[4];\n  const rightScore = b[4];\n  if (leftScore === rightScore) {\n    // same score: sort alphabetically\n    const leftTitle = a[1].toLowerCase();\n    const rightTitle = b[1].toLowerCase();\n    if (leftTitle === rightTitle) return 0;\n    return leftTitle > rightTitle ? -1 : 1; // inverted is intentional\n  }\n  return leftScore > rightScore ? 1 : -1;\n};\n\n/**\n * Default splitQuery function. Can be overridden in ``sphinx.search`` with a\n * custom function per language.\n *\n * The regular expression works by splitting the string on consecutive characters\n * that are not Unicode letters, numbers, underscores, or emoji characters.\n * This is the same as ``\\W+`` in Python, preserving the surrogate pair area.\n */\nif (typeof splitQuery === \"undefined\") {\n  var splitQuery = (query) => query\n      .split(/[^\\p{Letter}\\p{Number}_\\p{Emoji_Presentation}]+/gu)\n      .filter(term => term)  // remove remaining empty strings\n}\n\n/**\n * Search Module\n */\nconst Search = {\n  _index: null,\n  _queued_query: null,\n  _pulse_status: -1,\n\n  htmlToText: (htmlString, anchor) => {\n    const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html');\n    for (const removalQuery of [\".headerlink\", \"script\", \"style\"]) {\n      htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() });\n    }\n    if (anchor) {\n      const anchorContent = htmlElement.querySelector(`[role=\"main\"] ${anchor}`);\n      if (anchorContent) return anchorContent.textContent;\n\n      console.warn(\n        `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.`\n      );\n    }\n\n    // if anchor not specified or not found, fall back to main content\n    const docContent = htmlElement.querySelector('[role=\"main\"]');\n    if (docContent) return docContent.textContent;\n\n    console.warn(\n      \"Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template.\"\n    );\n    return \"\";\n  },\n\n  init: () => {\n    const query = new URLSearchParams(window.location.search).get(\"q\");\n    document\n      .querySelectorAll('input[name=\"q\"]')\n      .forEach((el) => (el.value = query));\n    if (query) Search.performSearch(query);\n  },\n\n  loadIndex: (url) =>\n    (document.body.appendChild(document.createElement(\"script\")).src = url),\n\n  setIndex: (index) => {\n    Search._index = index;\n    if (Search._queued_query !== null) {\n      const query = Search._queued_query;\n      Search._queued_query = null;\n      Search.query(query);\n    }\n  },\n\n  hasIndex: () => Search._index !== null,\n\n  deferQuery: (query) => (Search._queued_query = query),\n\n  stopPulse: () => (Search._pulse_status = -1),\n\n  startPulse: () => {\n    if (Search._pulse_status >= 0) return;\n\n    const pulse = () => {\n      Search._pulse_status = (Search._pulse_status + 1) % 4;\n      Search.dots.innerText = \".\".repeat(Search._pulse_status);\n      if (Search._pulse_status >= 0) window.setTimeout(pulse, 500);\n    };\n    pulse();\n  },\n\n  /**\n   * perform a search for something (or wait until index is loaded)\n   */\n  performSearch: (query) => {\n    // create the required interface elements\n    const searchText = document.createElement(\"h2\");\n    searchText.textContent = _(\"Searching\");\n    const searchSummary = document.createElement(\"p\");\n    searchSummary.classList.add(\"search-summary\");\n    searchSummary.innerText = \"\";\n    const searchList = document.createElement(\"ul\");\n    searchList.setAttribute(\"role\", \"list\");\n    searchList.classList.add(\"search\");\n\n    const out = document.getElementById(\"search-results\");\n    Search.title = out.appendChild(searchText);\n    Search.dots = Search.title.appendChild(document.createElement(\"span\"));\n    Search.status = out.appendChild(searchSummary);\n    Search.output = out.appendChild(searchList);\n\n    const searchProgress = document.getElementById(\"search-progress\");\n    // Some themes don't use the search progress node\n    if (searchProgress) {\n      searchProgress.innerText = _(\"Preparing search...\");\n    }\n    Search.startPulse();\n\n    // index already loaded, the browser was quick!\n    if (Search.hasIndex()) Search.query(query);\n    else Search.deferQuery(query);\n  },\n\n  _parseQuery: (query) => {\n    // stem the search terms and add them to the correct list\n    const stemmer = new Stemmer();\n    const searchTerms = new Set();\n    const excludedTerms = new Set();\n    const highlightTerms = new Set();\n    const objectTerms = new Set(splitQuery(query.toLowerCase().trim()));\n    splitQuery(query.trim()).forEach((queryTerm) => {\n      const queryTermLower = queryTerm.toLowerCase();\n\n      // maybe skip this \"word\"\n      // stopwords array is from language_data.js\n      if (\n        stopwords.indexOf(queryTermLower) !== -1 ||\n        queryTerm.match(/^\\d+$/)\n      )\n        return;\n\n      // stem the word\n      let word = stemmer.stemWord(queryTermLower);\n      // select the correct list\n      if (word[0] === \"-\") excludedTerms.add(word.substr(1));\n      else {\n        searchTerms.add(word);\n        highlightTerms.add(queryTermLower);\n      }\n    });\n\n    if (SPHINX_HIGHLIGHT_ENABLED) {  // set in sphinx_highlight.js\n      localStorage.setItem(\"sphinx_highlight_terms\", [...highlightTerms].join(\" \"))\n    }\n\n    // console.debug(\"SEARCH: searching for:\");\n    // console.info(\"required: \", [...searchTerms]);\n    // console.info(\"excluded: \", [...excludedTerms]);\n\n    return [query, searchTerms, excludedTerms, highlightTerms, objectTerms];\n  },\n\n  /**\n   * execute search (requires search index to be loaded)\n   */\n  _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => {\n    const filenames = Search._index.filenames;\n    const docNames = Search._index.docnames;\n    const titles = Search._index.titles;\n    const allTitles = Search._index.alltitles;\n    const indexEntries = Search._index.indexentries;\n\n    // Collect multiple result groups to be sorted separately and then ordered.\n    // Each is an array of [docname, title, anchor, descr, score, filename, kind].\n    const normalResults = [];\n    const nonMainIndexResults = [];\n\n    _removeChildren(document.getElementById(\"search-progress\"));\n\n    const queryLower = query.toLowerCase().trim();\n    for (const [title, foundTitles] of Object.entries(allTitles)) {\n      if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) {\n        for (const [file, id] of foundTitles) {\n          const score = Math.round(Scorer.title * queryLower.length / title.length);\n          const boost = titles[file] === title ? 1 : 0;  // add a boost for document titles\n          normalResults.push([\n            docNames[file],\n            titles[file] !== title ? `${titles[file]} > ${title}` : title,\n            id !== null ? \"#\" + id : \"\",\n            null,\n            score + boost,\n            filenames[file],\n            SearchResultKind.title,\n          ]);\n        }\n      }\n    }\n\n    // search for explicit entries in index directives\n    for (const [entry, foundEntries] of Object.entries(indexEntries)) {\n      if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) {\n        for (const [file, id, isMain] of foundEntries) {\n          const score = Math.round(100 * queryLower.length / entry.length);\n          const result = [\n            docNames[file],\n            titles[file],\n            id ? \"#\" + id : \"\",\n            null,\n            score,\n            filenames[file],\n            SearchResultKind.index,\n          ];\n          if (isMain) {\n            normalResults.push(result);\n          } else {\n            nonMainIndexResults.push(result);\n          }\n        }\n      }\n    }\n\n    // lookup as object\n    objectTerms.forEach((term) =>\n      normalResults.push(...Search.performObjectSearch(term, objectTerms))\n    );\n\n    // lookup as search terms in fulltext\n    normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms));\n\n    // let the scorer override scores with a custom scoring function\n    if (Scorer.score) {\n      normalResults.forEach((item) => (item[4] = Scorer.score(item)));\n      nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item)));\n    }\n\n    // Sort each group of results by score and then alphabetically by name.\n    normalResults.sort(_orderResultsByScoreThenName);\n    nonMainIndexResults.sort(_orderResultsByScoreThenName);\n\n    // Combine the result groups in (reverse) order.\n    // Non-main index entries are typically arbitrary cross-references,\n    // so display them after other results.\n    let results = [...nonMainIndexResults, ...normalResults];\n\n    // remove duplicate search results\n    // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept\n    let seen = new Set();\n    results = results.reverse().reduce((acc, result) => {\n      let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(',');\n      if (!seen.has(resultStr)) {\n        acc.push(result);\n        seen.add(resultStr);\n      }\n      return acc;\n    }, []);\n\n    return results.reverse();\n  },\n\n  query: (query) => {\n    const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query);\n    const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms);\n\n    // for debugging\n    //Search.lastresults = results.slice();  // a copy\n    // console.info(\"search results:\", Search.lastresults);\n\n    // print the results\n    _displayNextItem(results, results.length, searchTerms, highlightTerms);\n  },\n\n  /**\n   * search for object names\n   */\n  performObjectSearch: (object, objectTerms) => {\n    const filenames = Search._index.filenames;\n    const docNames = Search._index.docnames;\n    const objects = Search._index.objects;\n    const objNames = Search._index.objnames;\n    const titles = Search._index.titles;\n\n    const results = [];\n\n    const objectSearchCallback = (prefix, match) => {\n      const name = match[4]\n      const fullname = (prefix ? prefix + \".\" : \"\") + name;\n      const fullnameLower = fullname.toLowerCase();\n      if (fullnameLower.indexOf(object) < 0) return;\n\n      let score = 0;\n      const parts = fullnameLower.split(\".\");\n\n      // check for different match types: exact matches of full name or\n      // \"last name\" (i.e. last dotted part)\n      if (fullnameLower === object || parts.slice(-1)[0] === object)\n        score += Scorer.objNameMatch;\n      else if (parts.slice(-1)[0].indexOf(object) > -1)\n        score += Scorer.objPartialMatch; // matches in last name\n\n      const objName = objNames[match[1]][2];\n      const title = titles[match[0]];\n\n      // If more than one term searched for, we require other words to be\n      // found in the name/title/description\n      const otherTerms = new Set(objectTerms);\n      otherTerms.delete(object);\n      if (otherTerms.size > 0) {\n        const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase();\n        if (\n          [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0)\n        )\n          return;\n      }\n\n      let anchor = match[3];\n      if (anchor === \"\") anchor = fullname;\n      else if (anchor === \"-\") anchor = objNames[match[1]][1] + \"-\" + fullname;\n\n      const descr = objName + _(\", in \") + title;\n\n      // add custom score for some objects according to scorer\n      if (Scorer.objPrio.hasOwnProperty(match[2]))\n        score += Scorer.objPrio[match[2]];\n      else score += Scorer.objPrioDefault;\n\n      results.push([\n        docNames[match[0]],\n        fullname,\n        \"#\" + anchor,\n        descr,\n        score,\n        filenames[match[0]],\n        SearchResultKind.object,\n      ]);\n    };\n    Object.keys(objects).forEach((prefix) =>\n      objects[prefix].forEach((array) =>\n        objectSearchCallback(prefix, array)\n      )\n    );\n    return results;\n  },\n\n  /**\n   * search for full-text terms in the index\n   */\n  performTermsSearch: (searchTerms, excludedTerms) => {\n    // prepare search\n    const terms = Search._index.terms;\n    const titleTerms = Search._index.titleterms;\n    const filenames = Search._index.filenames;\n    const docNames = Search._index.docnames;\n    const titles = Search._index.titles;\n\n    const scoreMap = new Map();\n    const fileMap = new Map();\n\n    // perform the search on the required terms\n    searchTerms.forEach((word) => {\n      const files = [];\n      const arr = [\n        { files: terms[word], score: Scorer.term },\n        { files: titleTerms[word], score: Scorer.title },\n      ];\n      // add support for partial matches\n      if (word.length > 2) {\n        const escapedWord = _escapeRegExp(word);\n        if (!terms.hasOwnProperty(word)) {\n          Object.keys(terms).forEach((term) => {\n            if (term.match(escapedWord))\n              arr.push({ files: terms[term], score: Scorer.partialTerm });\n          });\n        }\n        if (!titleTerms.hasOwnProperty(word)) {\n          Object.keys(titleTerms).forEach((term) => {\n            if (term.match(escapedWord))\n              arr.push({ files: titleTerms[term], score: Scorer.partialTitle });\n          });\n        }\n      }\n\n      // no match but word was a required one\n      if (arr.every((record) => record.files === undefined)) return;\n\n      // found search word in contents\n      arr.forEach((record) => {\n        if (record.files === undefined) return;\n\n        let recordFiles = record.files;\n        if (recordFiles.length === undefined) recordFiles = [recordFiles];\n        files.push(...recordFiles);\n\n        // set score for the word in each file\n        recordFiles.forEach((file) => {\n          if (!scoreMap.has(file)) scoreMap.set(file, {});\n          scoreMap.get(file)[word] = record.score;\n        });\n      });\n\n      // create the mapping\n      files.forEach((file) => {\n        if (!fileMap.has(file)) fileMap.set(file, [word]);\n        else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word);\n      });\n    });\n\n    // now check if the files don't contain excluded terms\n    const results = [];\n    for (const [file, wordList] of fileMap) {\n      // check if all requirements are matched\n\n      // as search terms with length < 3 are discarded\n      const filteredTermCount = [...searchTerms].filter(\n        (term) => term.length > 2\n      ).length;\n      if (\n        wordList.length !== searchTerms.size &&\n        wordList.length !== filteredTermCount\n      )\n        continue;\n\n      // ensure that none of the excluded terms is in the search result\n      if (\n        [...excludedTerms].some(\n          (term) =>\n            terms[term] === file ||\n            titleTerms[term] === file ||\n            (terms[term] || []).includes(file) ||\n            (titleTerms[term] || []).includes(file)\n        )\n      )\n        break;\n\n      // select one (max) score for the file.\n      const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w]));\n      // add result to the result list\n      results.push([\n        docNames[file],\n        titles[file],\n        \"\",\n        null,\n        score,\n        filenames[file],\n        SearchResultKind.text,\n      ]);\n    }\n    return results;\n  },\n\n  /**\n   * helper function to return a node containing the\n   * search summary for a given text. keywords is a list\n   * of stemmed words.\n   */\n  makeSearchSummary: (htmlText, keywords, anchor) => {\n    const text = Search.htmlToText(htmlText, anchor);\n    if (text === \"\") return null;\n\n    const textLower = text.toLowerCase();\n    const actualStartPosition = [...keywords]\n      .map((k) => textLower.indexOf(k.toLowerCase()))\n      .filter((i) => i > -1)\n      .slice(-1)[0];\n    const startWithContext = Math.max(actualStartPosition - 120, 0);\n\n    const top = startWithContext === 0 ? \"\" : \"...\";\n    const tail = startWithContext + 240 < text.length ? \"...\" : \"\";\n\n    let summary = document.createElement(\"p\");\n    summary.classList.add(\"context\");\n    summary.textContent = top + text.substr(startWithContext, 240).trim() + tail;\n\n    return summary;\n  },\n};\n\n_ready(Search.init);\n"
  },
  {
    "path": "docs/_static/sphinx_highlight.js",
    "content": "/* Highlighting utilities for Sphinx HTML documentation. */\n\"use strict\";\n\nconst SPHINX_HIGHLIGHT_ENABLED = true\n\n/**\n * highlight a given string on a node by wrapping it in\n * span elements with the given class name.\n */\nconst _highlight = (node, addItems, text, className) => {\n  if (node.nodeType === Node.TEXT_NODE) {\n    const val = node.nodeValue;\n    const parent = node.parentNode;\n    const pos = val.toLowerCase().indexOf(text);\n    if (\n      pos >= 0 &&\n      !parent.classList.contains(className) &&\n      !parent.classList.contains(\"nohighlight\")\n    ) {\n      let span;\n\n      const closestNode = parent.closest(\"body, svg, foreignObject\");\n      const isInSVG = closestNode && closestNode.matches(\"svg\");\n      if (isInSVG) {\n        span = document.createElementNS(\"http://www.w3.org/2000/svg\", \"tspan\");\n      } else {\n        span = document.createElement(\"span\");\n        span.classList.add(className);\n      }\n\n      span.appendChild(document.createTextNode(val.substr(pos, text.length)));\n      const rest = document.createTextNode(val.substr(pos + text.length));\n      parent.insertBefore(\n        span,\n        parent.insertBefore(\n          rest,\n          node.nextSibling\n        )\n      );\n      node.nodeValue = val.substr(0, pos);\n      /* There may be more occurrences of search term in this node. So call this\n       * function recursively on the remaining fragment.\n       */\n      _highlight(rest, addItems, text, className);\n\n      if (isInSVG) {\n        const rect = document.createElementNS(\n          \"http://www.w3.org/2000/svg\",\n          \"rect\"\n        );\n        const bbox = parent.getBBox();\n        rect.x.baseVal.value = bbox.x;\n        rect.y.baseVal.value = bbox.y;\n        rect.width.baseVal.value = bbox.width;\n        rect.height.baseVal.value = bbox.height;\n        rect.setAttribute(\"class\", className);\n        addItems.push({ parent: parent, target: rect });\n      }\n    }\n  } else if (node.matches && !node.matches(\"button, select, textarea\")) {\n    node.childNodes.forEach((el) => _highlight(el, addItems, text, className));\n  }\n};\nconst _highlightText = (thisNode, text, className) => {\n  let addItems = [];\n  _highlight(thisNode, addItems, text, className);\n  addItems.forEach((obj) =>\n    obj.parent.insertAdjacentElement(\"beforebegin\", obj.target)\n  );\n};\n\n/**\n * Small JavaScript module for the documentation.\n */\nconst SphinxHighlight = {\n\n  /**\n   * highlight the search words provided in localstorage in the text\n   */\n  highlightSearchWords: () => {\n    if (!SPHINX_HIGHLIGHT_ENABLED) return;  // bail if no highlight\n\n    // get and clear terms from localstorage\n    const url = new URL(window.location);\n    const highlight =\n        localStorage.getItem(\"sphinx_highlight_terms\")\n        || url.searchParams.get(\"highlight\")\n        || \"\";\n    localStorage.removeItem(\"sphinx_highlight_terms\")\n    url.searchParams.delete(\"highlight\");\n    window.history.replaceState({}, \"\", url);\n\n    // get individual terms from highlight string\n    const terms = highlight.toLowerCase().split(/\\s+/).filter(x => x);\n    if (terms.length === 0) return; // nothing to do\n\n    // There should never be more than one element matching \"div.body\"\n    const divBody = document.querySelectorAll(\"div.body\");\n    const body = divBody.length ? divBody[0] : document.querySelector(\"body\");\n    window.setTimeout(() => {\n      terms.forEach((term) => _highlightText(body, term, \"highlighted\"));\n    }, 10);\n\n    const searchBox = document.getElementById(\"searchbox\");\n    if (searchBox === null) return;\n    searchBox.appendChild(\n      document\n        .createRange()\n        .createContextualFragment(\n          '<p class=\"highlight-link\">' +\n            '<a href=\"javascript:SphinxHighlight.hideSearchWords()\">' +\n            _(\"Hide Search Matches\") +\n            \"</a></p>\"\n        )\n    );\n  },\n\n  /**\n   * helper function to hide the search marks again\n   */\n  hideSearchWords: () => {\n    document\n      .querySelectorAll(\"#searchbox .highlight-link\")\n      .forEach((el) => el.remove());\n    document\n      .querySelectorAll(\"span.highlighted\")\n      .forEach((el) => el.classList.remove(\"highlighted\"));\n    localStorage.removeItem(\"sphinx_highlight_terms\")\n  },\n\n  initEscapeListener: () => {\n    // only install a listener if it is really needed\n    if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return;\n\n    document.addEventListener(\"keydown\", (event) => {\n      // bail for input elements\n      if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return;\n      // bail with special keys\n      if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return;\n      if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === \"Escape\")) {\n        SphinxHighlight.hideSearchWords();\n        event.preventDefault();\n      }\n    });\n  },\n};\n\n_ready(() => {\n  /* Do not call highlightSearchWords() when we are on the search page.\n   * It will highlight words from the *previous* search query.\n   */\n  if (typeof Search === \"undefined\") SphinxHighlight.highlightSearchWords();\n  SphinxHighlight.initEscapeListener();\n});\n"
  },
  {
    "path": "docs/about.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\" data-content_root=\"./\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>About &#8212; pwlf 2.5.2 documentation</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/pygments.css?v=d1102ebc\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/basic.css?v=686e5160\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/alabaster.css?v=27fed22d\" />\n    <script src=\"_static/documentation_options.js?v=afc61bbc\"></script>\n    <script src=\"_static/doctools.js?v=9bcbadda\"></script>\n    <script src=\"_static/sphinx_highlight.js?v=dc90522c\"></script>\n    <link rel=\"icon\" href=\"_static/favicon.ico\"/>\n    <link rel=\"author\" title=\"About these documents\" href=\"#\" />\n    <link rel=\"index\" title=\"Index\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"Search\" href=\"search.html\" />\n    <link rel=\"next\" title=\"Requirements\" href=\"requirements.html\" />\n    <link rel=\"prev\" title=\"pwlf.PiecewiseLinFit\" href=\"stubs/pwlf.PiecewiseLinFit.html\" />\n   \n  <link rel=\"stylesheet\" href=\"_static/custom.css\" type=\"text/css\" />\n  \n\n  \n  \n\n  </head><body>\n  \n\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n        <div class=\"bodywrapper\">\n          \n\n          <div class=\"body\" role=\"main\">\n            \n  <section id=\"about\">\n<h1>About<a class=\"headerlink\" href=\"#about\" title=\"Link to this heading\">¶</a></h1>\n<p>A library for fitting continuous piecewise linear functions to data. Just specify the number of line segments you desire and provide the data.</p>\n<figure class=\"align-default\">\n<img alt=\"Example of a continuous piecewise linear fit to data.\" src=\"https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/examplePiecewiseFit.png\" />\n</figure>\n<p>Example of a continuous piecewise linear fit to data.</p>\n<p>All changes now stored in\n<a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py/blob/master/CHANGELOG.md\">CHANGELOG.md</a></p>\n<p>Please cite pwlf in your publications if it helps your research.</p>\n<div class=\"highlight-bibtex notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"nc\">@Manual</span><span class=\"p\">{</span><span class=\"nl\">pwlf</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"na\">author</span><span class=\"w\"> </span><span class=\"p\">=</span><span class=\"w\"> </span><span class=\"s\">{Jekel, Charles F. and Venter, Gerhard}</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"na\">title</span><span class=\"w\"> </span><span class=\"p\">=</span><span class=\"w\"> </span><span class=\"s\">{{pwlf:} A Python Library for Fitting 1D Continuous Piecewise Linear Functions}</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"na\">year</span><span class=\"w\"> </span><span class=\"p\">=</span><span class=\"w\"> </span><span class=\"s\">{2019}</span><span class=\"p\">,</span>\n<span class=\"w\">    </span><span class=\"na\">url</span><span class=\"w\"> </span><span class=\"p\">=</span><span class=\"w\"> </span><span class=\"s\">{https://github.com/cjekel/piecewise_linear_fit_py}</span>\n<span class=\"p\">}</span>\n</pre></div>\n</div>\n</section>\n\n\n          </div>\n          \n        </div>\n      </div>\n      <div class=\"sphinxsidebar\" role=\"navigation\" aria-label=\"Main\">\n        <div class=\"sphinxsidebarwrapper\">\n<h1 class=\"logo\"><a href=\"index.html\">pwlf</a></h1>\n\n\n\n\n\n\n\n\n\n<search id=\"searchbox\" style=\"display: none\" role=\"search\">\n    <div class=\"searchformwrapper\">\n    <form class=\"search\" action=\"search.html\" method=\"get\">\n      <input type=\"text\" name=\"q\" aria-labelledby=\"searchlabel\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" placeholder=\"Search\"/>\n      <input type=\"submit\" value=\"Go\" />\n    </form>\n    </div>\n</search>\n<script>document.getElementById('searchbox').style.display = \"block\"</script><h3>Navigation</h3>\n<ul class=\"current\">\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"installation.html\">Installation</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"how_it_works.html\">How it works</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"examples.html\">Examples</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"pwlf.html\">pwlf package contents</a></li>\n<li class=\"toctree-l1 current\"><a class=\"current reference internal\" href=\"#\">About</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"requirements.html\">Requirements</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"license.html\">License</a></li>\n</ul>\n\n<div class=\"relations\">\n<h3>Related Topics</h3>\n<ul>\n  <li><a href=\"index.html\">Documentation overview</a><ul>\n      <li>Previous: <a href=\"stubs/pwlf.PiecewiseLinFit.html\" title=\"previous chapter\">pwlf.PiecewiseLinFit</a></li>\n      <li>Next: <a href=\"requirements.html\" title=\"next chapter\">Requirements</a></li>\n  </ul></li>\n</ul>\n</div>\n\n\n\n\n\n\n\n\n        </div>\n      </div>\n      <div class=\"clearer\"></div>\n    </div>\n    <div class=\"footer\">\n      &#169;2024, Charles Jekel.\n      \n      |\n      Powered by <a href=\"https://www.sphinx-doc.org/\">Sphinx 8.1.3</a>\n      &amp; <a href=\"https://alabaster.readthedocs.io\">Alabaster 1.0.0</a>\n      \n      |\n      <a href=\"_sources/about.rst.txt\"\n          rel=\"nofollow\">Page source</a>\n    </div>\n\n    \n\n    \n    <script>\n\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'G-QKPGZSZ8CD']);\n      _gaq.push(['_setDomainName', 'none']);\n      _gaq.push(['_setAllowLinker', true]);\n      _gaq.push(['_trackPageview']);\n\n      (function() {\n        var ga = document.createElement('script'); ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n\n    </script>\n    \n  </body>\n</html>"
  },
  {
    "path": "docs/examples.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\" data-content_root=\"./\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>Examples &#8212; pwlf 2.5.2 documentation</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/pygments.css?v=d1102ebc\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/basic.css?v=686e5160\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/alabaster.css?v=27fed22d\" />\n    <script src=\"_static/documentation_options.js?v=afc61bbc\"></script>\n    <script src=\"_static/doctools.js?v=9bcbadda\"></script>\n    <script src=\"_static/sphinx_highlight.js?v=dc90522c\"></script>\n    <link rel=\"icon\" href=\"_static/favicon.ico\"/>\n    <link rel=\"author\" title=\"About these documents\" href=\"about.html\" />\n    <link rel=\"index\" title=\"Index\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"Search\" href=\"search.html\" />\n    <link rel=\"next\" title=\"pwlf package contents\" href=\"pwlf.html\" />\n    <link rel=\"prev\" title=\"How it works\" href=\"how_it_works.html\" />\n   \n  <link rel=\"stylesheet\" href=\"_static/custom.css\" type=\"text/css\" />\n  \n\n  \n  \n\n  </head><body>\n  \n\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n        <div class=\"bodywrapper\">\n          \n\n          <div class=\"body\" role=\"main\">\n            \n  <section id=\"examples\">\n<h1>Examples<a class=\"headerlink\" href=\"#examples\" title=\"Link to this heading\">¶</a></h1>\n<p>All of these examples will use the following data and imports.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"nn\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">matplotlib.pyplot</span> <span class=\"k\">as</span> <span class=\"nn\">plt</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n\n<span class=\"c1\"># your data</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">0.00000000e+00</span><span class=\"p\">,</span> <span class=\"mf\">9.69801700e-03</span><span class=\"p\">,</span> <span class=\"mf\">2.94350340e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">4.39052750e-02</span><span class=\"p\">,</span> <span class=\"mf\">5.45343950e-02</span><span class=\"p\">,</span> <span class=\"mf\">6.74104940e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">8.34831790e-02</span><span class=\"p\">,</span> <span class=\"mf\">1.02580042e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.22767939e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.42172312e-01</span><span class=\"p\">,</span> <span class=\"mf\">0.00000000e+00</span><span class=\"p\">,</span> <span class=\"mf\">8.58600000e-06</span><span class=\"p\">,</span>\n              <span class=\"mf\">8.31543400e-03</span><span class=\"p\">,</span> <span class=\"mf\">2.34184100e-02</span><span class=\"p\">,</span> <span class=\"mf\">3.39709150e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">4.03581990e-02</span><span class=\"p\">,</span> <span class=\"mf\">4.53545600e-02</span><span class=\"p\">,</span> <span class=\"mf\">5.02345260e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">5.55253360e-02</span><span class=\"p\">,</span> <span class=\"mf\">6.14750770e-02</span><span class=\"p\">,</span> <span class=\"mf\">6.82125120e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">7.55892510e-02</span><span class=\"p\">,</span> <span class=\"mf\">8.38356810e-02</span><span class=\"p\">,</span> <span class=\"mf\">9.26413070e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.02039790e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.11688258e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.21390666e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.31196948e-01</span><span class=\"p\">,</span> <span class=\"mf\">0.00000000e+00</span><span class=\"p\">,</span> <span class=\"mf\">1.56706510e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">3.54628780e-02</span><span class=\"p\">,</span> <span class=\"mf\">4.63739040e-02</span><span class=\"p\">,</span> <span class=\"mf\">5.61442590e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">6.78542550e-02</span><span class=\"p\">,</span> <span class=\"mf\">8.16388310e-02</span><span class=\"p\">,</span> <span class=\"mf\">9.77756110e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.16531753e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.37038283e-01</span><span class=\"p\">,</span> <span class=\"mf\">0.00000000e+00</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.16951050e-02</span><span class=\"p\">,</span> <span class=\"mf\">3.12089850e-02</span><span class=\"p\">,</span> <span class=\"mf\">4.41776550e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">5.42877590e-02</span><span class=\"p\">,</span> <span class=\"mf\">6.63321350e-02</span><span class=\"p\">,</span> <span class=\"mf\">8.07655920e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">9.70363280e-02</span><span class=\"p\">,</span> <span class=\"mf\">1.15706975e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.36687642e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">0.00000000e+00</span><span class=\"p\">,</span> <span class=\"mf\">1.50144640e-02</span><span class=\"p\">,</span> <span class=\"mf\">3.44519970e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">4.55907760e-02</span><span class=\"p\">,</span> <span class=\"mf\">5.59556700e-02</span><span class=\"p\">,</span> <span class=\"mf\">6.88450940e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">8.41374060e-02</span><span class=\"p\">,</span> <span class=\"mf\">1.01254006e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.20605073e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.41881288e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.62618058e-01</span><span class=\"p\">])</span>\n<span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">0.00000000e+00</span><span class=\"p\">,</span> <span class=\"mf\">8.82678000e-03</span><span class=\"p\">,</span> <span class=\"mf\">3.25615100e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">5.66106800e-02</span><span class=\"p\">,</span> <span class=\"mf\">7.95549800e-02</span><span class=\"p\">,</span> <span class=\"mf\">1.00936330e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.20351520e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.37442010e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.51858250e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.64433570e-01</span><span class=\"p\">,</span> <span class=\"mf\">0.00000000e+00</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mf\">2.12600000e-05</span><span class=\"p\">,</span>\n              <span class=\"mf\">7.03872000e-03</span><span class=\"p\">,</span> <span class=\"mf\">1.85494500e-02</span><span class=\"p\">,</span> <span class=\"mf\">3.00926700e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">4.17617000e-02</span><span class=\"p\">,</span> <span class=\"mf\">5.37279600e-02</span><span class=\"p\">,</span> <span class=\"mf\">6.54941000e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">7.68092100e-02</span><span class=\"p\">,</span> <span class=\"mf\">8.76596300e-02</span><span class=\"p\">,</span> <span class=\"mf\">9.80525800e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.07961810e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.17305210e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.26063930e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.34180360e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.41725010e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.48629710e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.55374770e-01</span><span class=\"p\">,</span> <span class=\"mf\">0.00000000e+00</span><span class=\"p\">,</span> <span class=\"mf\">1.65610200e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">3.91016100e-02</span><span class=\"p\">,</span> <span class=\"mf\">6.18679400e-02</span><span class=\"p\">,</span> <span class=\"mf\">8.30997400e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.02132890e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.19011260e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.34620080e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.49429370e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.63539960e-01</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mf\">0.00000000e+00</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.01980300e-02</span><span class=\"p\">,</span> <span class=\"mf\">3.28642800e-02</span><span class=\"p\">,</span> <span class=\"mf\">5.59461900e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">7.81388400e-02</span><span class=\"p\">,</span> <span class=\"mf\">9.84458400e-02</span><span class=\"p\">,</span> <span class=\"mf\">1.16270210e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.31279040e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.45437090e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.59627540e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">0.00000000e+00</span><span class=\"p\">,</span> <span class=\"mf\">1.63404300e-02</span><span class=\"p\">,</span> <span class=\"mf\">4.00086000e-02</span><span class=\"p\">,</span>\n              <span class=\"mf\">6.34390200e-02</span><span class=\"p\">,</span> <span class=\"mf\">8.51085900e-02</span><span class=\"p\">,</span> <span class=\"mf\">1.04787860e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.22120350e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.36931660e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.50958760e-01</span><span class=\"p\">,</span>\n              <span class=\"mf\">1.65299640e-01</span><span class=\"p\">,</span> <span class=\"mf\">1.79942720e-01</span><span class=\"p\">])</span>\n</pre></div>\n</div>\n<ol class=\"arabic simple\">\n<li><p><a class=\"reference external\" href=\"#fit-with-known-breakpoint-locations\">fit with known breakpoint\nlocations</a></p></li>\n<li><p><a class=\"reference external\" href=\"#fit-for-specified-number-of-line-segments\">fit for specified number of line\nsegments</a></p></li>\n<li><p><a class=\"reference external\" href=\"#fitfast-for-specified-number-of-line-segments\">fitfast for specified number of line\nsegments</a></p></li>\n<li><p><a class=\"reference external\" href=\"#force-a-fit-through-data-points\">force a fit through data\npoints</a></p></li>\n<li><p><a class=\"reference external\" href=\"#use-custom-optimization-routine\">use custom optimization\nroutine</a></p></li>\n<li><p><a class=\"reference external\" href=\"#pass-differential-evolution-keywords\">pass differential evolution\nkeywords</a></p></li>\n<li><p><a class=\"reference external\" href=\"#find-the-best-number-of-line-segments\">find the best number of line\nsegments</a></p></li>\n<li><p><a class=\"reference external\" href=\"#model-persistence\">model persistence</a></p></li>\n<li><p><a class=\"reference external\" href=\"#bad-fits-when-you-have-more-unknowns-than-data\">bad fits when you have more unknowns than\ndata</a></p></li>\n<li><p><a class=\"reference external\" href=\"#fit-with-a-breakpoint-guess\">fit with a breakpoint guess</a></p></li>\n<li><p><a class=\"reference external\" href=\"#get-the-linear-regression-matrix\">get the linear regression\nmatrix</a></p></li>\n<li><p><a class=\"reference external\" href=\"#use-of-tensorflow\">use of TensorFlow</a></p></li>\n<li><p><a class=\"reference external\" href=\"#fit-constants-or-polynomials\">fit constants or polynomials</a></p></li>\n<li><p><a class=\"reference external\" href=\"#specify-breakpoint-bounds\">specify breakpoint bounds</a></p></li>\n<li><p><a class=\"reference external\" href=\"#non-linear-standard-errors-and-p-values\">non-linear standard errors and\np-values</a></p></li>\n<li><p><a class=\"reference external\" href=\"#obtain-the-equations-of-fitted-pwlf\">obtain the equations of fitted\npwlf</a></p></li>\n<li><p><a class=\"reference external\" href=\"#weighted-least-squares-fit\">weighted least squares fit</a></p></li>\n<li><p><a class=\"reference external\" href=\"#reproducibleresults\">reproducible results</a></p></li>\n</ol>\n<section id=\"fit-with-known-breakpoint-locations\">\n<h2>fit with known breakpoint locations<a class=\"headerlink\" href=\"#fit-with-known-breakpoint-locations\" title=\"Link to this heading\">¶</a></h2>\n<p>You can perform a least squares fit if you know the breakpoint\nlocations.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"c1\"># your desired line segment end locations</span>\n<span class=\"n\">x0</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"mf\">0.039</span><span class=\"p\">,</span> <span class=\"mf\">0.10</span><span class=\"p\">,</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">)])</span>\n\n<span class=\"c1\"># initialize piecewise linear fit with your x and y data</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># fit the data with the specified break points</span>\n<span class=\"c1\"># (ie the x locations of where the line segments</span>\n<span class=\"c1\"># will terminate)</span>\n<span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_with_breaks</span><span class=\"p\">(</span><span class=\"n\">x0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># predict for the determined points</span>\n<span class=\"n\">xHat</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n<span class=\"n\">yHat</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># plot the results</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">figure</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"s1\">&#39;o&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">,</span> <span class=\"n\">yHat</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n<figure class=\"align-default\" id=\"id1\">\n<img alt=\"fit with known breakpoint locations\" src=\"https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/fit_breaks.png\" />\n<figcaption>\n<p><span class=\"caption-text\">fit with known breakpoint locations</span><a class=\"headerlink\" href=\"#id1\" title=\"Link to this image\">¶</a></p>\n</figcaption>\n</figure>\n</section>\n<section id=\"fit-for-specified-number-of-line-segments\">\n<h2>fit for specified number of line segments<a class=\"headerlink\" href=\"#fit-for-specified-number-of-line-segments\" title=\"Link to this heading\">¶</a></h2>\n<p>Use a global optimization to find the breakpoint locations that minimize\nthe sum of squares error. This uses <a class=\"reference external\" href=\"https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html\">Differential\nEvolution</a>\nfrom scipy.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"c1\"># initialize piecewise linear fit with your x and y data</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># fit the data for four line segments</span>\n<span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"mi\">4</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># predict for the determined points</span>\n<span class=\"n\">xHat</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n<span class=\"n\">yHat</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># plot the results</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">figure</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"s1\">&#39;o&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">,</span> <span class=\"n\">yHat</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n<figure class=\"align-default\" id=\"id2\">\n<img alt=\"fit for specified number of line segments\" src=\"https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/numberoflines.png\" />\n<figcaption>\n<p><span class=\"caption-text\">fit for specified number of line segments</span><a class=\"headerlink\" href=\"#id2\" title=\"Link to this image\">¶</a></p>\n</figcaption>\n</figure>\n</section>\n<section id=\"fitfast-for-specified-number-of-line-segments\">\n<h2>fitfast for specified number of line segments<a class=\"headerlink\" href=\"#fitfast-for-specified-number-of-line-segments\" title=\"Link to this heading\">¶</a></h2>\n<p>This performs a fit for a specified number of line segments with a\nmulti-start gradient based optimization. This should be faster than\n<a class=\"reference external\" href=\"https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html\">Differential\nEvolution</a>\nfor a small number of starting points.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"c1\"># initialize piecewise linear fit with your x and y data</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># fit the data for four line segments</span>\n<span class=\"c1\"># this performs 3 multi-start optimizations</span>\n<span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fitfast</span><span class=\"p\">(</span><span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"n\">pop</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># predict for the determined points</span>\n<span class=\"n\">xHat</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n<span class=\"n\">yHat</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># plot the results</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">figure</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"s1\">&#39;o&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">,</span> <span class=\"n\">yHat</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n<figure class=\"align-default\" id=\"id3\">\n<img alt=\"fitfast for specified number of line segments\" src=\"https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/fitfast.png\" />\n<figcaption>\n<p><span class=\"caption-text\">fitfast for specified number of line segments</span><a class=\"headerlink\" href=\"#id3\" title=\"Link to this image\">¶</a></p>\n</figcaption>\n</figure>\n</section>\n<section id=\"force-a-fit-through-data-points\">\n<h2>force a fit through data points<a class=\"headerlink\" href=\"#force-a-fit-through-data-points\" title=\"Link to this heading\">¶</a></h2>\n<p>Sometimes it’s necessary to force the piecewise continuous model through\na particular data point, or a set of data points. The following example\nfinds the best 4 line segments that go through two data points.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"c1\"># initialize piecewise linear fit with your x and y data</span>\n<span class=\"n\">myPWLF</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># fit the function with four line segments</span>\n<span class=\"c1\"># force the function to go through the data points</span>\n<span class=\"c1\"># (0.0, 0.0) and (0.19, 0.16)</span>\n<span class=\"c1\"># where the data points are of the form (x, y)</span>\n<span class=\"n\">x_c</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">0.19</span><span class=\"p\">]</span>\n<span class=\"n\">y_c</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">]</span>\n<span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">myPWLF</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"n\">x_c</span><span class=\"p\">,</span> <span class=\"n\">y_c</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># predict for the determined points</span>\n<span class=\"n\">xHat</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"mf\">0.19</span><span class=\"p\">,</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n<span class=\"n\">yHat</span> <span class=\"o\">=</span> <span class=\"n\">myPWLF</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># plot the results</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">figure</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"s1\">&#39;o&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">,</span> <span class=\"n\">yHat</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n<figure class=\"align-default\" id=\"id4\">\n<img alt=\"force a fit through data points\" src=\"https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/force.png\" />\n<figcaption>\n<p><span class=\"caption-text\">force a fit through data points</span><a class=\"headerlink\" href=\"#id4\" title=\"Link to this image\">¶</a></p>\n</figcaption>\n</figure>\n</section>\n<section id=\"use-custom-optimization-routine\">\n<h2>use custom optimization routine<a class=\"headerlink\" href=\"#use-custom-optimization-routine\" title=\"Link to this heading\">¶</a></h2>\n<p>You can use your favorite optimization routine to find the breakpoint\nlocations. The following example uses scipy’s\n<a class=\"reference external\" href=\"https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html\">minimize</a>\nfunction.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">scipy.optimize</span> <span class=\"kn\">import</span> <span class=\"n\">minimize</span>\n<span class=\"c1\"># initialize piecewise linear fit with your x and y data</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># initialize custom optimization</span>\n<span class=\"n\">number_of_line_segments</span> <span class=\"o\">=</span> <span class=\"mi\">3</span>\n<span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">use_custom_opt</span><span class=\"p\">(</span><span class=\"n\">number_of_line_segments</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># i have number_of_line_segments - 1 number of variables</span>\n<span class=\"c1\"># let&#39;s guess the correct location of the two unknown variables</span>\n<span class=\"c1\"># (the program defaults to have end segments at x0= min(x)</span>\n<span class=\"c1\"># and xn=max(x)</span>\n<span class=\"n\">xGuess</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">zeros</span><span class=\"p\">(</span><span class=\"n\">number_of_line_segments</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"n\">xGuess</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.02</span>\n<span class=\"n\">xGuess</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.10</span>\n\n<span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">minimize</span><span class=\"p\">(</span><span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_with_breaks_opt</span><span class=\"p\">,</span> <span class=\"n\">xGuess</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># set up the break point locations</span>\n<span class=\"n\">x0</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">zeros</span><span class=\"p\">(</span><span class=\"n\">number_of_line_segments</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"n\">x0</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">)</span>\n<span class=\"n\">x0</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">)</span>\n<span class=\"n\">x0</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">res</span><span class=\"o\">.</span><span class=\"n\">x</span>\n\n<span class=\"c1\"># calculate the parameters based on the optimal break point locations</span>\n<span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_with_breaks</span><span class=\"p\">(</span><span class=\"n\">x0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># predict for the determined points</span>\n<span class=\"n\">xHat</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n<span class=\"n\">yHat</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">)</span>\n\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">figure</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"s1\">&#39;o&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">,</span> <span class=\"n\">yHat</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n</section>\n<section id=\"pass-differential-evolution-keywords\">\n<h2>pass differential evolution keywords<a class=\"headerlink\" href=\"#pass-differential-evolution-keywords\" title=\"Link to this heading\">¶</a></h2>\n<p>You can pass keyword arguments from the <code class=\"docutils literal notranslate\"><span class=\"pre\">fit</span></code> function into scipy’s\n<a class=\"reference external\" href=\"https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html\">Differential\nEvolution</a>.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"c1\"># initialize piecewise linear fit with your x and y data</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># fit the data for four line segments</span>\n<span class=\"c1\"># this sets DE to have an absolute tolerance of 0.1</span>\n<span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"n\">atol</span><span class=\"o\">=</span><span class=\"mf\">0.1</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># predict for the determined points</span>\n<span class=\"n\">xHat</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n<span class=\"n\">yHat</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># plot the results</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">figure</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"s1\">&#39;o&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">,</span> <span class=\"n\">yHat</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n</section>\n<section id=\"find-the-best-number-of-line-segments\">\n<h2>find the best number of line segments<a class=\"headerlink\" href=\"#find-the-best-number-of-line-segments\" title=\"Link to this heading\">¶</a></h2>\n<p>This example uses EGO (bayesian optimization) and a penalty function to\nfind the best number of line segments. This will require careful use of\nthe penalty parameter <code class=\"docutils literal notranslate\"><span class=\"pre\">l</span></code>. Use this template to automatically find the\nbest number of line segments.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">GPyOpt.methods</span> <span class=\"kn\">import</span> <span class=\"n\">BayesianOptimization</span>\n<span class=\"c1\"># initialize piecewise linear fit with your x and y data</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># define your objective function</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">my_obj</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">):</span>\n    <span class=\"c1\"># define some penalty parameter l</span>\n    <span class=\"c1\"># you&#39;ll have to arbitrarily pick this</span>\n    <span class=\"c1\"># it depends upon the noise in your data,</span>\n    <span class=\"c1\"># and the value of your sum of square of residuals</span>\n    <span class=\"n\">l</span> <span class=\"o\">=</span> <span class=\"n\">y</span><span class=\"o\">.</span><span class=\"n\">mean</span><span class=\"p\">()</span><span class=\"o\">*</span><span class=\"mf\">0.001</span>\n    <span class=\"n\">f</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">zeros</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">.</span><span class=\"n\">shape</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"k\">for</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">j</span> <span class=\"ow\">in</span> <span class=\"nb\">enumerate</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">):</span>\n        <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"n\">j</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n        <span class=\"n\">f</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">ssr</span> <span class=\"o\">+</span> <span class=\"p\">(</span><span class=\"n\">l</span><span class=\"o\">*</span><span class=\"n\">j</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n    <span class=\"k\">return</span> <span class=\"n\">f</span>\n\n\n<span class=\"c1\"># define the lower and upper bound for the number of line segments</span>\n<span class=\"n\">bounds</span> <span class=\"o\">=</span> <span class=\"p\">[{</span><span class=\"s1\">&#39;name&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;var_1&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;type&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;discrete&#39;</span><span class=\"p\">,</span>\n           <span class=\"s1\">&#39;domain&#39;</span><span class=\"p\">:</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">arange</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">40</span><span class=\"p\">)}]</span>\n\n<span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">seed</span><span class=\"p\">(</span><span class=\"mi\">12121</span><span class=\"p\">)</span>\n\n<span class=\"n\">myBopt</span> <span class=\"o\">=</span> <span class=\"n\">BayesianOptimization</span><span class=\"p\">(</span><span class=\"n\">my_obj</span><span class=\"p\">,</span> <span class=\"n\">domain</span><span class=\"o\">=</span><span class=\"n\">bounds</span><span class=\"p\">,</span> <span class=\"n\">model_type</span><span class=\"o\">=</span><span class=\"s1\">&#39;GP&#39;</span><span class=\"p\">,</span>\n                              <span class=\"n\">initial_design_numdata</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">,</span>\n                              <span class=\"n\">initial_design_type</span><span class=\"o\">=</span><span class=\"s1\">&#39;latin&#39;</span><span class=\"p\">,</span>\n                              <span class=\"n\">exact_feval</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span> <span class=\"n\">verbosity</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span>\n                              <span class=\"n\">verbosity_model</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">)</span>\n<span class=\"n\">max_iter</span> <span class=\"o\">=</span> <span class=\"mi\">30</span>\n\n<span class=\"c1\"># perform the bayesian optimization to find the optimum number</span>\n<span class=\"c1\"># of line segments</span>\n<span class=\"n\">myBopt</span><span class=\"o\">.</span><span class=\"n\">run_optimization</span><span class=\"p\">(</span><span class=\"n\">max_iter</span><span class=\"o\">=</span><span class=\"n\">max_iter</span><span class=\"p\">,</span> <span class=\"n\">verbosity</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n\n<span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;</span><span class=\"se\">\\n</span><span class=\"s1\"> </span><span class=\"se\">\\n</span><span class=\"s1\"> Opt found </span><span class=\"se\">\\n</span><span class=\"s1\">&#39;</span><span class=\"p\">)</span>\n<span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;Optimum number of line segments:&#39;</span><span class=\"p\">,</span> <span class=\"n\">myBopt</span><span class=\"o\">.</span><span class=\"n\">x_opt</span><span class=\"p\">)</span>\n<span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;Function value:&#39;</span><span class=\"p\">,</span> <span class=\"n\">myBopt</span><span class=\"o\">.</span><span class=\"n\">fx_opt</span><span class=\"p\">)</span>\n<span class=\"n\">myBopt</span><span class=\"o\">.</span><span class=\"n\">plot_acquisition</span><span class=\"p\">()</span>\n<span class=\"n\">myBopt</span><span class=\"o\">.</span><span class=\"n\">plot_convergence</span><span class=\"p\">()</span>\n\n<span class=\"c1\"># perform the fit for the optimum</span>\n<span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"n\">myBopt</span><span class=\"o\">.</span><span class=\"n\">x_opt</span><span class=\"p\">)</span>\n<span class=\"c1\"># predict for the determined points</span>\n<span class=\"n\">xHat</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n<span class=\"n\">yHat</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># plot the results</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">figure</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"s1\">&#39;o&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">,</span> <span class=\"n\">yHat</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n</section>\n<section id=\"model-persistence\">\n<h2>model persistence<a class=\"headerlink\" href=\"#model-persistence\" title=\"Link to this heading\">¶</a></h2>\n<p>You can save fitted models with pickle. Alternatively see\n<a class=\"reference external\" href=\"https://joblib.readthedocs.io/en/latest/\">joblib</a>.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"c1\"># if you use Python 2.x you should import cPickle</span>\n<span class=\"c1\"># import cPickle as pickle</span>\n<span class=\"c1\"># if you use Python 3.x you can just use pickle</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pickle</span>\n\n<span class=\"c1\"># your desired line segment end locations</span>\n<span class=\"n\">x0</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"mf\">0.039</span><span class=\"p\">,</span> <span class=\"mf\">0.10</span><span class=\"p\">,</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">)])</span>\n\n<span class=\"c1\"># initialize piecewise linear fit with your x and y data</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># fit the data with the specified break points</span>\n<span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_with_breaks</span><span class=\"p\">(</span><span class=\"n\">x0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># save the fitted model</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">&#39;my_fit.pkl&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;wb&#39;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n    <span class=\"n\">pickle</span><span class=\"o\">.</span><span class=\"n\">dump</span><span class=\"p\">(</span><span class=\"n\">my_pwlf</span><span class=\"p\">,</span> <span class=\"n\">f</span><span class=\"p\">,</span> <span class=\"n\">pickle</span><span class=\"o\">.</span><span class=\"n\">HIGHEST_PROTOCOL</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># load the fitted model</span>\n<span class=\"k\">with</span> <span class=\"nb\">open</span><span class=\"p\">(</span><span class=\"s1\">&#39;my_fit.pkl&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;rb&#39;</span><span class=\"p\">)</span> <span class=\"k\">as</span> <span class=\"n\">f</span><span class=\"p\">:</span>\n    <span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pickle</span><span class=\"o\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">f</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n</section>\n<section id=\"bad-fits-when-you-have-more-unknowns-than-data\">\n<h2>bad fits when you have more unknowns than data<a class=\"headerlink\" href=\"#bad-fits-when-you-have-more-unknowns-than-data\" title=\"Link to this heading\">¶</a></h2>\n<p>You can get very bad fits with pwlf when you have more unknowns than\ndata points. The following example will fit 99 line segments to the 59\ndata points. While this will result in an error of zero, the model will\nhave very weird predictions within the data. You should not fit more\nunknowns than you have data with pwlf!</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"n\">break_locations</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n<span class=\"c1\"># initialize piecewise linear fit with your x and y data</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_with_breaks</span><span class=\"p\">(</span><span class=\"n\">break_locations</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># predict for the determined points</span>\n<span class=\"n\">xHat</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n<span class=\"n\">yHat</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># plot the results</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">figure</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"s1\">&#39;o&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">,</span> <span class=\"n\">yHat</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n<figure class=\"align-default\" id=\"id5\">\n<img alt=\"bad fits when you have more unknowns than data\" src=\"https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/badfit.png\" />\n<figcaption>\n<p><span class=\"caption-text\">bad fits when you have more unknowns than data</span><a class=\"headerlink\" href=\"#id5\" title=\"Link to this image\">¶</a></p>\n</figcaption>\n</figure>\n</section>\n<section id=\"fit-with-a-breakpoint-guess\">\n<h2>fit with a breakpoint guess<a class=\"headerlink\" href=\"#fit-with-a-breakpoint-guess\" title=\"Link to this heading\">¶</a></h2>\n<p>In this example we see two distinct linear regions, and we believe a\nbreakpoint occurs at 6.0. We’ll use the fit_guess() function to find the\nbest breakpoint location starting with this guess. These fits should be\nmuch faster than the <code class=\"docutils literal notranslate\"><span class=\"pre\">fit</span></code> or <code class=\"docutils literal notranslate\"><span class=\"pre\">fitfast</span></code> function when you have a\nreasonable idea where the breakpoints occur.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"nn\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">4.</span><span class=\"p\">,</span> <span class=\"mf\">5.</span><span class=\"p\">,</span> <span class=\"mf\">6.</span><span class=\"p\">,</span> <span class=\"mf\">7.</span><span class=\"p\">,</span> <span class=\"mf\">8.</span><span class=\"p\">])</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">11.</span><span class=\"p\">,</span> <span class=\"mf\">13.</span><span class=\"p\">,</span> <span class=\"mf\">16.</span><span class=\"p\">,</span> <span class=\"mf\">28.92</span><span class=\"p\">,</span> <span class=\"mf\">42.81</span><span class=\"p\">])</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_guess</span><span class=\"p\">([</span><span class=\"mf\">6.0</span><span class=\"p\">])</span>\n</pre></div>\n</div>\n<p>Note specifying one breakpoint will result in two line segments. If we\nwanted three line segments, we’ll have to specify two breakpoints.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_guess</span><span class=\"p\">([</span><span class=\"mf\">5.5</span><span class=\"p\">,</span> <span class=\"mf\">6.0</span><span class=\"p\">])</span>\n</pre></div>\n</div>\n</section>\n<section id=\"get-the-linear-regression-matrix\">\n<h2>get the linear regression matrix<a class=\"headerlink\" href=\"#get-the-linear-regression-matrix\" title=\"Link to this heading\">¶</a></h2>\n<p>In some cases it may be desirable to work with the linear regression\nmatrix directly. The following example grabs the linear regression\nmatrix <code class=\"docutils literal notranslate\"><span class=\"pre\">A</span></code> for a specific set of breakpoints. In this case we assume\nthat the breakpoints occur at each of the data points. Please see the\n<a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py/tree/master/paper\">paper</a>\nfor details about the regression matrix <code class=\"docutils literal notranslate\"><span class=\"pre\">A</span></code>.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"nn\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"c1\"># select random seed for reproducibility</span>\n<span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">seed</span><span class=\"p\">(</span><span class=\"mi\">123</span><span class=\"p\">)</span>\n<span class=\"c1\"># generate sin wave data</span>\n<span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">sin</span><span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">pi</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n<span class=\"n\">ytrue</span> <span class=\"o\">=</span> <span class=\"n\">y</span><span class=\"o\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n<span class=\"c1\"># add noise to the data</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">normal</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mf\">0.05</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">ytrue</span>\n\n<span class=\"n\">my_pwlf_en</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"c1\"># copy the x data to use as break points</span>\n<span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf_en</span><span class=\"o\">.</span><span class=\"n\">x_data</span><span class=\"o\">.</span><span class=\"n\">copy</span><span class=\"p\">()</span>\n<span class=\"c1\"># create the linear regression matrix A</span>\n<span class=\"n\">A</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf_en</span><span class=\"o\">.</span><span class=\"n\">assemble_regression_matrix</span><span class=\"p\">(</span><span class=\"n\">breaks</span><span class=\"p\">,</span> <span class=\"n\">my_pwlf_en</span><span class=\"o\">.</span><span class=\"n\">x_data</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n<p>We can perform fits that are more complicated than a least squares fit\nwhen we have the regression matrix. The following uses the Elastic Net\nregularizer to perform an interesting fit with the regression matrix.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">sklearn.linear_model</span> <span class=\"kn\">import</span> <span class=\"n\">ElasticNetCV</span>\n<span class=\"c1\"># set up the elastic net</span>\n<span class=\"n\">en_model</span> <span class=\"o\">=</span> <span class=\"n\">ElasticNetCV</span><span class=\"p\">(</span><span class=\"n\">cv</span><span class=\"o\">=</span><span class=\"mi\">5</span><span class=\"p\">,</span>\n                        <span class=\"n\">l1_ratio</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"mf\">.1</span><span class=\"p\">,</span> <span class=\"mf\">.5</span><span class=\"p\">,</span> <span class=\"mf\">.7</span><span class=\"p\">,</span> <span class=\"mf\">.9</span><span class=\"p\">,</span>\n                                  <span class=\"mf\">.95</span><span class=\"p\">,</span> <span class=\"mf\">.99</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">],</span>\n                        <span class=\"n\">fit_intercept</span><span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span>\n                        <span class=\"n\">max_iter</span><span class=\"o\">=</span><span class=\"mi\">1000000</span><span class=\"p\">,</span> <span class=\"n\">n_jobs</span><span class=\"o\">=-</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"c1\"># fit the model using the elastic net</span>\n<span class=\"n\">en_model</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"n\">A</span><span class=\"p\">,</span> <span class=\"n\">my_pwlf_en</span><span class=\"o\">.</span><span class=\"n\">y_data</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># predict from the elastic net parameters</span>\n<span class=\"n\">xhat</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">.</span><span class=\"n\">min</span><span class=\"p\">(),</span> <span class=\"n\">x</span><span class=\"o\">.</span><span class=\"n\">max</span><span class=\"p\">(),</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n<span class=\"n\">yhat_en</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf_en</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xhat</span><span class=\"p\">,</span> <span class=\"n\">breaks</span><span class=\"o\">=</span><span class=\"n\">breaks</span><span class=\"p\">,</span>\n                             <span class=\"n\">beta</span><span class=\"o\">=</span><span class=\"n\">en_model</span><span class=\"o\">.</span><span class=\"n\">coef_</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n<figure class=\"align-default\" id=\"id6\">\n<img alt=\"interesting elastic net fit\" src=\"https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/sin_en_net_fit.png\" />\n<figcaption>\n<p><span class=\"caption-text\">interesting elastic net fit</span><a class=\"headerlink\" href=\"#id6\" title=\"Link to this image\">¶</a></p>\n</figcaption>\n</figure>\n</section>\n<section id=\"use-of-tensorflow\">\n<h2>use of tensorflow<a class=\"headerlink\" href=\"#use-of-tensorflow\" title=\"Link to this heading\">¶</a></h2>\n<p>You need to install\n<a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py_tf\">pwlftf</a> which\nwill have the <code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFitTF</span></code> class. For performance benchmarks\n(these benchmarks are outdated! and the regular pwlf may be faster in\nmany applications) see this blog\n<a class=\"reference external\" href=\"https://jekel.me/2019/Adding-tensorflow-to-pwlf/\">post</a>.</p>\n<p>The use of the TF class is nearly identical to the original class,\nhowever note the following exceptions. <code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFitTF</span></code> does:</p>\n<ul class=\"simple\">\n<li><p>not have a <code class=\"docutils literal notranslate\"><span class=\"pre\">lapack_driver</span></code> option</p></li>\n<li><p>have an optional parameter <code class=\"docutils literal notranslate\"><span class=\"pre\">dtype</span></code>, so you can choose between the\nfloat64 and float32 data types</p></li>\n<li><p>have an optional parameter <code class=\"docutils literal notranslate\"><span class=\"pre\">fast</span></code> to switch between Cholesky\ndecomposition (default <code class=\"docutils literal notranslate\"><span class=\"pre\">fast=True</span></code>), and orthogonal decomposition\n(<code class=\"docutils literal notranslate\"><span class=\"pre\">fast=False</span></code>)</p></li>\n</ul>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">pwlftf</span> <span class=\"k\">as</span> <span class=\"nn\">pwlf</span>\n<span class=\"c1\"># your desired line segment end locations</span>\n<span class=\"n\">x0</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"mf\">0.039</span><span class=\"p\">,</span> <span class=\"mf\">0.10</span><span class=\"p\">,</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">)])</span>\n\n<span class=\"c1\"># initialize TF piecewise linear fit with your x and y data</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFitTF</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"s1\">&#39;float32)</span>\n\n<span class=\"c1\"># fit the data with the specified break points</span>\n<span class=\"c1\"># (ie the x locations of where the line segments</span>\n<span class=\"c1\"># will terminate)</span>\n<span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_with_breaks</span><span class=\"p\">(</span><span class=\"n\">x0</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># predict for the determined points</span>\n<span class=\"n\">xHat</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n<span class=\"n\">yHat</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n</section>\n<section id=\"fit-constants-or-polynomials\">\n<h2>fit constants or polynomials<a class=\"headerlink\" href=\"#fit-constants-or-polynomials\" title=\"Link to this heading\">¶</a></h2>\n<p>You can use pwlf to fit segmented constant models, or piecewise\npolynomials. The following example fits a segmented constant model,\npiecewise linear, and a piecewise quadratic model to a sine wave.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"c1\"># generate sin wave data</span>\n<span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">sin</span><span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">pi</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n<span class=\"c1\"># add noise to the data</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">normal</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mf\">0.05</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">y</span>\n\n<span class=\"c1\"># initialize piecewise linear fit with your x and y data</span>\n<span class=\"c1\"># pwlf lets you fit continuous model for many degree polynomials</span>\n<span class=\"c1\"># degree=0 constant</span>\n<span class=\"c1\"># degree=1 linear (default)</span>\n<span class=\"c1\"># degree=2 quadratic</span>\n<span class=\"n\">my_pwlf_0</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">degree</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"n\">my_pwlf_1</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">degree</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>  <span class=\"c1\"># default</span>\n<span class=\"n\">my_pwlf_2</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">degree</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># fit the data for four line segments</span>\n<span class=\"n\">res0</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf_0</span><span class=\"o\">.</span><span class=\"n\">fitfast</span><span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"n\">pop</span><span class=\"o\">=</span><span class=\"mi\">50</span><span class=\"p\">)</span>\n<span class=\"n\">res1</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf_1</span><span class=\"o\">.</span><span class=\"n\">fitfast</span><span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"n\">pop</span><span class=\"o\">=</span><span class=\"mi\">50</span><span class=\"p\">)</span>\n<span class=\"n\">res2</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf_2</span><span class=\"o\">.</span><span class=\"n\">fitfast</span><span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"n\">pop</span><span class=\"o\">=</span><span class=\"mi\">50</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># predict for the determined points</span>\n<span class=\"n\">xHat</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"nb\">min</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"nb\">max</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">),</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">10000</span><span class=\"p\">)</span>\n<span class=\"n\">yHat0</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf_0</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">)</span>\n<span class=\"n\">yHat1</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf_1</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">)</span>\n<span class=\"n\">yHat2</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf_2</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># plot the results</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">figure</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"s1\">&#39;o&#39;</span><span class=\"p\">,</span> <span class=\"n\">label</span><span class=\"o\">=</span><span class=\"s1\">&#39;Data&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">,</span> <span class=\"n\">yHat0</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-&#39;</span><span class=\"p\">,</span> <span class=\"n\">label</span><span class=\"o\">=</span><span class=\"s1\">&#39;degree=0&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">,</span> <span class=\"n\">yHat1</span><span class=\"p\">,</span> <span class=\"s1\">&#39;--&#39;</span><span class=\"p\">,</span> <span class=\"n\">label</span><span class=\"o\">=</span><span class=\"s1\">&#39;degree=1&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xHat</span><span class=\"p\">,</span> <span class=\"n\">yHat2</span><span class=\"p\">,</span> <span class=\"s1\">&#39;:&#39;</span><span class=\"p\">,</span> <span class=\"n\">label</span><span class=\"o\">=</span><span class=\"s1\">&#39;degree=2&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">legend</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n<figure class=\"align-default\" id=\"id7\">\n<img alt=\"Example of multiple degree fits to a sine wave.\" src=\"https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/multi_degree.png\" />\n<figcaption>\n<p><span class=\"caption-text\">Example of multiple degree fits to a sine wave.</span><a class=\"headerlink\" href=\"#id7\" title=\"Link to this image\">¶</a></p>\n</figcaption>\n</figure>\n</section>\n<section id=\"specify-breakpoint-bounds\">\n<h2>specify breakpoint bounds<a class=\"headerlink\" href=\"#specify-breakpoint-bounds\" title=\"Link to this heading\">¶</a></h2>\n<p>You may want extra control over the search space for feasible\nbreakpoints. One way to do this is to specify the bounds for each\nbreakpoint location.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"c1\"># generate sin wave data</span>\n<span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">sin</span><span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">pi</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n<span class=\"c1\"># add noise to the data</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">normal</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mf\">0.05</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">y</span>\n\n<span class=\"c1\"># initialize piecewise linear fit with your x and y data</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># define custom bounds for the interior break points</span>\n<span class=\"n\">n_segments</span> <span class=\"o\">=</span> <span class=\"mi\">4</span>\n<span class=\"n\">bounds</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">n_segments</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">))</span>\n<span class=\"c1\"># first breakpoint</span>\n<span class=\"n\">bounds</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">0.0</span>  <span class=\"c1\"># lower bound</span>\n<span class=\"n\">bounds</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">3.5</span>  <span class=\"c1\"># upper bound</span>\n<span class=\"c1\"># second breakpoint</span>\n<span class=\"n\">bounds</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">3.0</span>  <span class=\"c1\"># lower bound</span>\n<span class=\"n\">bounds</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">7.0</span>  <span class=\"c1\"># upper bound</span>\n<span class=\"c1\"># third breakpoint</span>\n<span class=\"n\">bounds</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">6.0</span>  <span class=\"c1\"># lower bound</span>\n<span class=\"n\">bounds</span><span class=\"p\">[</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"mf\">10.0</span>  <span class=\"c1\"># upper bound</span>\n<span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"n\">n_segments</span><span class=\"p\">,</span> <span class=\"n\">bounds</span><span class=\"o\">=</span><span class=\"n\">bounds</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n</section>\n<section id=\"non-linear-standard-errors-and-p-values\">\n<h2>non-linear standard errors and p-values<a class=\"headerlink\" href=\"#non-linear-standard-errors-and-p-values\" title=\"Link to this heading\">¶</a></h2>\n<p>You can calculate non-linear standard errors using the Delta method.\nThis will calculate the standard errors of the piecewise linear\nparameters (intercept + slopes) and the breakpoint locations!</p>\n<p>First let us generate true piecewise linear data.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">__future__</span> <span class=\"kn\">import</span> <span class=\"n\">print_function</span>\n<span class=\"c1\"># generate a true piecewise linear data</span>\n<span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">seed</span><span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">)</span>\n<span class=\"n\">n_data</span> <span class=\"o\">=</span> <span class=\"mi\">100</span>\n<span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"n\">n_data</span><span class=\"p\">)</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">(</span><span class=\"n\">n_data</span><span class=\"p\">)</span>\n<span class=\"n\">my_pwlf_gen</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"n\">true_beta</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">normal</span><span class=\"p\">(</span><span class=\"n\">size</span><span class=\"o\">=</span><span class=\"mi\">5</span><span class=\"p\">)</span>\n<span class=\"n\">true_breaks</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">0.2</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">0.75</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">])</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf_gen</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">beta</span><span class=\"o\">=</span><span class=\"n\">true_beta</span><span class=\"p\">,</span> <span class=\"n\">breaks</span><span class=\"o\">=</span><span class=\"n\">true_breaks</span><span class=\"p\">)</span>\n\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">figure</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">title</span><span class=\"p\">(</span><span class=\"s1\">&#39;True piecewise linear data&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n<figure class=\"align-default\" id=\"id8\">\n<img alt=\"True piecewise linear data.\" src=\"https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/true_pwlf.png\" />\n<figcaption>\n<p><span class=\"caption-text\">True piecewise linear data.</span><a class=\"headerlink\" href=\"#id8\" title=\"Link to this image\">¶</a></p>\n</figcaption>\n</figure>\n<p>Now we can perform a fit, calculate the standard errors, and p-values.\nThe non-linear method uses a first order taylor series expansion to\nlinearize the non-linear regression problem. A positive step_size\nperforms a forward difference, and a negative step_size would perform a\nbackwards difference.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"n\">res</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fitfast</span><span class=\"p\">(</span><span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"n\">pop</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n\n<span class=\"n\">p</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">p_values</span><span class=\"p\">(</span><span class=\"n\">method</span><span class=\"o\">=</span><span class=\"s1\">&#39;non-linear&#39;</span><span class=\"p\">,</span> <span class=\"n\">step_size</span><span class=\"o\">=</span><span class=\"mf\">1e-4</span><span class=\"p\">)</span>\n<span class=\"n\">se</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">se</span>  <span class=\"c1\"># standard errors</span>\n</pre></div>\n</div>\n<p>The standard errors and p-values correspond to each model parameter.\nFirst the beta parameters (intercept + slopes) and then the breakpoints.\nWe can assemble the parameters, and print a table of the result with the\nfollowing code.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"n\">parameters</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">concatenate</span><span class=\"p\">((</span><span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">beta</span><span class=\"p\">,</span>\n                             <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_breaks</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">:</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]))</span>\n\n<span class=\"n\">header</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;Parameter type&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Parameter value&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;Standard error&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;t&#39;</span><span class=\"p\">,</span>\n          <span class=\"s1\">&#39;P &gt; np.abs(t) (p-value)&#39;</span><span class=\"p\">]</span>\n<span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">header</span><span class=\"p\">,</span> <span class=\"n\">sep</span><span class=\"o\">=</span><span class=\"s1\">&#39; | &#39;</span><span class=\"p\">)</span>\n<span class=\"n\">values</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">parameters</span><span class=\"o\">.</span><span class=\"n\">size</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">object_</span><span class=\"p\">)</span>\n<span class=\"n\">values</span><span class=\"p\">[:,</span> <span class=\"mi\">1</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">around</span><span class=\"p\">(</span><span class=\"n\">parameters</span><span class=\"p\">,</span> <span class=\"n\">decimals</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n<span class=\"n\">values</span><span class=\"p\">[:,</span> <span class=\"mi\">2</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">around</span><span class=\"p\">(</span><span class=\"n\">se</span><span class=\"p\">,</span> <span class=\"n\">decimals</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n<span class=\"n\">values</span><span class=\"p\">[:,</span> <span class=\"mi\">3</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">around</span><span class=\"p\">(</span><span class=\"n\">parameters</span> <span class=\"o\">/</span> <span class=\"n\">se</span><span class=\"p\">,</span> <span class=\"n\">decimals</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n<span class=\"n\">values</span><span class=\"p\">[:,</span> <span class=\"mi\">4</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">around</span><span class=\"p\">(</span><span class=\"n\">p</span><span class=\"p\">,</span> <span class=\"n\">decimals</span><span class=\"o\">=</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n\n<span class=\"k\">for</span> <span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">row</span> <span class=\"ow\">in</span> <span class=\"nb\">enumerate</span><span class=\"p\">(</span><span class=\"n\">values</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">i</span> <span class=\"o\">&lt;</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">beta</span><span class=\"o\">.</span><span class=\"n\">size</span><span class=\"p\">:</span>\n        <span class=\"n\">row</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;Beta&#39;</span>\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">row</span><span class=\"p\">,</span> <span class=\"n\">sep</span><span class=\"o\">=</span><span class=\"s1\">&#39; | &#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"n\">row</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;Breakpoint&#39;</span>\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">row</span><span class=\"p\">,</span> <span class=\"n\">sep</span><span class=\"o\">=</span><span class=\"s1\">&#39; | &#39;</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n<table class=\"docutils align-default\">\n<thead>\n<tr class=\"row-odd\"><th class=\"head\"><p>Parameter type</p></th>\n<th class=\"head\"><p>Parameter value</p></th>\n<th class=\"head\"><p>Standard error</p></th>\n<th class=\"head\"><p>t</p></th>\n<th class=\"head\"><p>P &gt; np.abs(t) (p-value)</p></th>\n</tr>\n</thead>\n<tbody>\n<tr class=\"row-even\"><td><p>Beta</p></td>\n<td><p>1.821</p></td>\n<td><p>0.0</p></td>\n<td><p>1763191476.046</p></td>\n<td><p>0.0</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p>Beta</p></td>\n<td><p>-0.427</p></td>\n<td><p>0.0</p></td>\n<td><p>-46404554.493</p></td>\n<td><p>0.0</p></td>\n</tr>\n<tr class=\"row-even\"><td><p>Beta</p></td>\n<td><p>-1.165</p></td>\n<td><p>0.0</p></td>\n<td><p>-111181494.162</p></td>\n<td><p>0.0</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p>Beta</p></td>\n<td><p>-1.397</p></td>\n<td><p>0.0</p></td>\n<td><p>-168954500.421</p></td>\n<td><p>0.0</p></td>\n</tr>\n<tr class=\"row-even\"><td><p>Beta</p></td>\n<td><p>0.873</p></td>\n<td><p>0.0</p></td>\n<td><p>93753841.242</p></td>\n<td><p>0.0</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p>Breakpoint</p></td>\n<td><p>0.2</p></td>\n<td><p>0.0</p></td>\n<td><p>166901856.885</p></td>\n<td><p>0.0</p></td>\n</tr>\n<tr class=\"row-even\"><td><p>Breakpoint</p></td>\n<td><p>0.5</p></td>\n<td><p>0.0</p></td>\n<td><p>537785803.646</p></td>\n<td><p>0.0</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p>Breakpoint</p></td>\n<td><p>0.75</p></td>\n<td><p>0.0</p></td>\n<td><p>482311769.159</p></td>\n<td><p>0.0</p></td>\n</tr>\n</tbody>\n</table>\n</section>\n<section id=\"obtain-the-equations-of-fitted-pwlf\">\n<h2>obtain the equations of fitted pwlf<a class=\"headerlink\" href=\"#obtain-the-equations-of-fitted-pwlf\" title=\"Link to this heading\">¶</a></h2>\n<p>Sometimes you may want the mathematical equations that represent your\nfitted model. This is easy to perform if you don’t mind using sympy.</p>\n<p>The following code will fit 5 line segments of degree=2 to a sin wave.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"nn\">np</span>\n<span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"c1\"># generate sin wave data</span>\n<span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">num</span><span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">)</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">sin</span><span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">pi</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n<span class=\"c1\"># add noise to the data</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">normal</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mf\">0.05</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">y</span>\n<span class=\"n\">my_pwlf_2</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">degree</span><span class=\"o\">=</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n<span class=\"n\">res2</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf_2</span><span class=\"o\">.</span><span class=\"n\">fitfast</span><span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"n\">pop</span><span class=\"o\">=</span><span class=\"mi\">50</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n<p>Given this fit, the following code will print the mathematical equation\nfor each line segment.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">sympy</span> <span class=\"kn\">import</span> <span class=\"n\">Symbol</span>\n<span class=\"kn\">from</span> <span class=\"nn\">sympy.utilities</span> <span class=\"kn\">import</span> <span class=\"n\">lambdify</span>\n<span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">Symbol</span><span class=\"p\">(</span><span class=\"s1\">&#39;x&#39;</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">get_symbolic_eqn</span><span class=\"p\">(</span><span class=\"n\">pwlf_</span><span class=\"p\">,</span> <span class=\"n\">segment_number</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">pwlf_</span><span class=\"o\">.</span><span class=\"n\">degree</span> <span class=\"o\">&lt;</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;Degree must be at least 1&#39;</span><span class=\"p\">)</span>\n    <span class=\"k\">if</span> <span class=\"n\">segment_number</span> <span class=\"o\">&lt;</span> <span class=\"mi\">1</span> <span class=\"ow\">or</span> <span class=\"n\">segment_number</span> <span class=\"o\">&gt;</span> <span class=\"n\">pwlf_</span><span class=\"o\">.</span><span class=\"n\">n_segments</span><span class=\"p\">:</span>\n        <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span><span class=\"p\">(</span><span class=\"s1\">&#39;segment_number not possible&#39;</span><span class=\"p\">)</span>\n    <span class=\"c1\"># assemble degree = 1 first</span>\n    <span class=\"k\">for</span> <span class=\"n\">line</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">segment_number</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"n\">line</span> <span class=\"o\">==</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">my_eqn</span> <span class=\"o\">=</span> <span class=\"n\">pwlf_</span><span class=\"o\">.</span><span class=\"n\">beta</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"p\">(</span><span class=\"n\">pwlf_</span><span class=\"o\">.</span><span class=\"n\">beta</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">])</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">-</span><span class=\"n\">pwlf_</span><span class=\"o\">.</span><span class=\"n\">fit_breaks</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">])</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"n\">my_eqn</span> <span class=\"o\">+=</span> <span class=\"p\">(</span><span class=\"n\">pwlf_</span><span class=\"o\">.</span><span class=\"n\">beta</span><span class=\"p\">[</span><span class=\"n\">line</span><span class=\"o\">+</span><span class=\"mi\">1</span><span class=\"p\">])</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">-</span><span class=\"n\">pwlf_</span><span class=\"o\">.</span><span class=\"n\">fit_breaks</span><span class=\"p\">[</span><span class=\"n\">line</span><span class=\"p\">])</span>\n    <span class=\"c1\"># assemble all other degrees</span>\n    <span class=\"k\">if</span> <span class=\"n\">pwlf_</span><span class=\"o\">.</span><span class=\"n\">degree</span> <span class=\"o\">&gt;</span> <span class=\"mi\">1</span><span class=\"p\">:</span>\n        <span class=\"k\">for</span> <span class=\"n\">k</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"n\">pwlf_</span><span class=\"o\">.</span><span class=\"n\">degree</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">):</span>\n            <span class=\"k\">for</span> <span class=\"n\">line</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">segment_number</span><span class=\"p\">):</span>\n                <span class=\"n\">beta_index</span> <span class=\"o\">=</span> <span class=\"n\">pwlf_</span><span class=\"o\">.</span><span class=\"n\">n_segments</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">k</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">line</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n                <span class=\"n\">my_eqn</span> <span class=\"o\">+=</span> <span class=\"p\">(</span><span class=\"n\">pwlf_</span><span class=\"o\">.</span><span class=\"n\">beta</span><span class=\"p\">[</span><span class=\"n\">beta_index</span><span class=\"p\">])</span><span class=\"o\">*</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"o\">-</span><span class=\"n\">pwlf_</span><span class=\"o\">.</span><span class=\"n\">fit_breaks</span><span class=\"p\">[</span><span class=\"n\">line</span><span class=\"p\">])</span><span class=\"o\">**</span><span class=\"n\">k</span>\n    <span class=\"k\">return</span> <span class=\"n\">my_eqn</span><span class=\"o\">.</span><span class=\"n\">simplify</span><span class=\"p\">()</span>\n\n\n<span class=\"n\">eqn_list</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n<span class=\"n\">f_list</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">my_pwlf_2</span><span class=\"o\">.</span><span class=\"n\">n_segments</span><span class=\"p\">):</span>\n    <span class=\"n\">eqn_list</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">get_symbolic_eqn</span><span class=\"p\">(</span><span class=\"n\">my_pwlf_2</span><span class=\"p\">,</span> <span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">))</span>\n    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s1\">&#39;Equation number: &#39;</span><span class=\"p\">,</span> <span class=\"n\">i</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">eqn_list</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">])</span>\n    <span class=\"n\">f_list</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">lambdify</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">eqn_list</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]))</span>\n</pre></div>\n</div>\n<p>which should print out something like the following:</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"n\">Equation</span> <span class=\"n\">number</span><span class=\"p\">:</span>  <span class=\"mi\">1</span>\n<span class=\"o\">-</span><span class=\"mf\">0.953964059782599</span><span class=\"o\">*</span><span class=\"n\">x</span><span class=\"o\">**</span><span class=\"mi\">2</span> <span class=\"o\">+</span> <span class=\"mf\">1.89945177490653</span><span class=\"o\">*</span><span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"mf\">0.00538634182565454</span>\n<span class=\"n\">Equation</span> <span class=\"n\">number</span><span class=\"p\">:</span>  <span class=\"mi\">2</span>\n<span class=\"mf\">0.951561315686298</span><span class=\"o\">*</span><span class=\"n\">x</span><span class=\"o\">**</span><span class=\"mi\">2</span> <span class=\"o\">-</span> <span class=\"mf\">5.69747505830914</span><span class=\"o\">*</span><span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"mf\">7.5772216545711</span>\n<span class=\"n\">Equation</span> <span class=\"n\">number</span><span class=\"p\">:</span>  <span class=\"mi\">3</span>\n<span class=\"o\">-</span><span class=\"mf\">0.949735350431857</span><span class=\"o\">*</span><span class=\"n\">x</span><span class=\"o\">**</span><span class=\"mi\">2</span> <span class=\"o\">+</span> <span class=\"mf\">9.48218236957122</span><span class=\"o\">*</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"mf\">22.720785454735</span>\n<span class=\"n\">Equation</span> <span class=\"n\">number</span><span class=\"p\">:</span>  <span class=\"mi\">4</span>\n<span class=\"mf\">0.926850298824217</span><span class=\"o\">*</span><span class=\"n\">x</span><span class=\"o\">**</span><span class=\"mi\">2</span> <span class=\"o\">-</span> <span class=\"mf\">12.9824424358344</span><span class=\"o\">*</span><span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"mf\">44.5102742956827</span>\n<span class=\"n\">Equation</span> <span class=\"n\">number</span><span class=\"p\">:</span>  <span class=\"mi\">5</span>\n<span class=\"o\">-</span><span class=\"mf\">1.03016230425747</span><span class=\"o\">*</span><span class=\"n\">x</span><span class=\"o\">**</span><span class=\"mi\">2</span> <span class=\"o\">+</span> <span class=\"mf\">18.5306546317065</span><span class=\"o\">*</span><span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"mf\">82.3508513333073</span>\n</pre></div>\n</div>\n<p>For more information on how this works, see\n<a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/understanding_higher_degrees/polynomials_in_pwlf.ipynb\">this</a>\njupyter notebook.</p>\n</section>\n<section id=\"weighted-least-squares-fit\">\n<h2>weighted least squares fit<a class=\"headerlink\" href=\"#weighted-least-squares-fit\" title=\"Link to this heading\">¶</a></h2>\n<p>Sometimes your data will not have a constant variance\n(heteroscedasticity), and you need to perform a weighted least squares\nfit. The following example will perform a standard and weighted fit so\nyou can compare the differences. First we need to generate a data set\nwhich will be a good candidate to use for weighted least squares fits.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"c1\"># generate data with heteroscedasticity</span>\n<span class=\"n\">n</span> <span class=\"o\">=</span> <span class=\"mi\">100</span>\n<span class=\"n\">n_data_sets</span> <span class=\"o\">=</span> <span class=\"mi\">100</span>\n<span class=\"n\">n_segments</span> <span class=\"o\">=</span> <span class=\"mi\">6</span>\n<span class=\"c1\"># generate sine data</span>\n<span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"n\">n</span><span class=\"p\">)</span>\n<span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">n_data_sets</span><span class=\"p\">,</span> <span class=\"n\">n</span><span class=\"p\">))</span>\n<span class=\"n\">sigma_change</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.001</span><span class=\"p\">,</span> <span class=\"mf\">0.05</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">)</span>\n<span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">n_data_sets</span><span class=\"p\">):</span>\n    <span class=\"n\">y</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">sin</span><span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">pi</span> <span class=\"o\">/</span> <span class=\"mi\">2</span><span class=\"p\">)</span>\n    <span class=\"c1\"># add noise to the data</span>\n    <span class=\"n\">y</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">normal</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">sigma_change</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">)</span> <span class=\"o\">+</span> <span class=\"n\">y</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">]</span>\n<span class=\"n\">X</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">tile</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">n_data_sets</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n<p>The individual weights in pwlf are the reciprocal of the standard\ndeviation for each data point. Here weights[i] corresponds to one over\nthe standard deviation of the ith data point. The result of this is that\ndata points with higher variance are less important to the overall pwlf\nthan data point with small variance. Let’s perform a standard pwlf fit\nand a weighted fit.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"c1\"># perform an ordinary pwlf fit to the entire data</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">X</span><span class=\"o\">.</span><span class=\"n\">flatten</span><span class=\"p\">(),</span> <span class=\"n\">y</span><span class=\"o\">.</span><span class=\"n\">flatten</span><span class=\"p\">())</span>\n<span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"n\">n_segments</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># compute the standard deviation in y</span>\n<span class=\"n\">y_std</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">std</span><span class=\"p\">(</span><span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">)</span>\n<span class=\"c1\"># set the weights to be one over the standard deviation</span>\n<span class=\"n\">weights</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span> <span class=\"o\">/</span> <span class=\"n\">y_std</span>\n\n<span class=\"c1\"># perform a weighted least squares to the data</span>\n<span class=\"n\">my_pwlf_w</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"o\">.</span><span class=\"n\">mean</span><span class=\"p\">(</span><span class=\"n\">axis</span><span class=\"o\">=</span><span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"n\">weights</span><span class=\"o\">=</span><span class=\"n\">weights</span><span class=\"p\">)</span>\n<span class=\"n\">my_pwlf_w</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"n\">n_segments</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># compare the fits</span>\n<span class=\"n\">xhat</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"mi\">1000</span><span class=\"p\">)</span>\n<span class=\"n\">yhat</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xhat</span><span class=\"p\">)</span>\n<span class=\"n\">yhat_w</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf_w</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">xhat</span><span class=\"p\">)</span>\n\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">figure</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">X</span><span class=\"o\">.</span><span class=\"n\">flatten</span><span class=\"p\">(),</span> <span class=\"n\">y</span><span class=\"o\">.</span><span class=\"n\">flatten</span><span class=\"p\">(),</span> <span class=\"s1\">&#39;.&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xhat</span><span class=\"p\">,</span> <span class=\"n\">yhat</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-&#39;</span><span class=\"p\">,</span> <span class=\"n\">label</span><span class=\"o\">=</span><span class=\"s1\">&#39;Ordinary LS&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">plot</span><span class=\"p\">(</span><span class=\"n\">xhat</span><span class=\"p\">,</span> <span class=\"n\">yhat_w</span><span class=\"p\">,</span> <span class=\"s1\">&#39;-&#39;</span><span class=\"p\">,</span> <span class=\"n\">label</span><span class=\"o\">=</span><span class=\"s1\">&#39;Weighted LS&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">legend</span><span class=\"p\">()</span>\n<span class=\"n\">plt</span><span class=\"o\">.</span><span class=\"n\">show</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n<figure class=\"align-default\" id=\"id9\">\n<img alt=\"Weighted pwlf fit.\" src=\"https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/weighted_least_squares_example.png\" />\n<figcaption>\n<p><span class=\"caption-text\">Weighted pwlf fit.</span><a class=\"headerlink\" href=\"#id9\" title=\"Link to this image\">¶</a></p>\n</figcaption>\n</figure>\n<p>We can see that the weighted pwlf fit tries fit data with low variance\nbetter than data with high variance, however the ordinary pwlf fits the\ndata assuming a uniform variance.</p>\n</section>\n<section id=\"reproducible-results\">\n<h2>reproducible results<a class=\"headerlink\" href=\"#reproducible-results\" title=\"Link to this heading\">¶</a></h2>\n<p>The <cite>fit</cite> and <cite>fitfast</cite> methods are stochastic and may not give the same\nresult every time the program is run. To have reproducible results you can\nmanually specify a numpy.random.seed on init. Now everytime the following\nprogram is run, the results of the fit(2) should be the same.</p>\n<div class=\"highlight-python notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"c1\"># initialize piecewise linear fit with a random seed</span>\n<span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">seed</span><span class=\"o\">=</span><span class=\"mi\">123</span><span class=\"p\">)</span>\n\n<span class=\"c1\"># Now the fit() method will be reproducible</span>\n<span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n</section>\n</section>\n\n\n          </div>\n          \n        </div>\n      </div>\n      <div class=\"sphinxsidebar\" role=\"navigation\" aria-label=\"Main\">\n        <div class=\"sphinxsidebarwrapper\">\n<h1 class=\"logo\"><a href=\"index.html\">pwlf</a></h1>\n\n\n\n\n\n\n\n\n\n<search id=\"searchbox\" style=\"display: none\" role=\"search\">\n    <div class=\"searchformwrapper\">\n    <form class=\"search\" action=\"search.html\" method=\"get\">\n      <input type=\"text\" name=\"q\" aria-labelledby=\"searchlabel\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" placeholder=\"Search\"/>\n      <input type=\"submit\" value=\"Go\" />\n    </form>\n    </div>\n</search>\n<script>document.getElementById('searchbox').style.display = \"block\"</script><h3>Navigation</h3>\n<ul class=\"current\">\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"installation.html\">Installation</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"how_it_works.html\">How it works</a></li>\n<li class=\"toctree-l1 current\"><a class=\"current reference internal\" href=\"#\">Examples</a><ul>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#fit-with-known-breakpoint-locations\">fit with known breakpoint locations</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#fit-for-specified-number-of-line-segments\">fit for specified number of line segments</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#fitfast-for-specified-number-of-line-segments\">fitfast for specified number of line segments</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#force-a-fit-through-data-points\">force a fit through data points</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#use-custom-optimization-routine\">use custom optimization routine</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#pass-differential-evolution-keywords\">pass differential evolution keywords</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#find-the-best-number-of-line-segments\">find the best number of line segments</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#model-persistence\">model persistence</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#bad-fits-when-you-have-more-unknowns-than-data\">bad fits when you have more unknowns than data</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#fit-with-a-breakpoint-guess\">fit with a breakpoint guess</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#get-the-linear-regression-matrix\">get the linear regression matrix</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#use-of-tensorflow\">use of tensorflow</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#fit-constants-or-polynomials\">fit constants or polynomials</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#specify-breakpoint-bounds\">specify breakpoint bounds</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#non-linear-standard-errors-and-p-values\">non-linear standard errors and p-values</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#obtain-the-equations-of-fitted-pwlf\">obtain the equations of fitted pwlf</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#weighted-least-squares-fit\">weighted least squares fit</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#reproducible-results\">reproducible results</a></li>\n</ul>\n</li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"pwlf.html\">pwlf package contents</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"about.html\">About</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"requirements.html\">Requirements</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"license.html\">License</a></li>\n</ul>\n\n<div class=\"relations\">\n<h3>Related Topics</h3>\n<ul>\n  <li><a href=\"index.html\">Documentation overview</a><ul>\n      <li>Previous: <a href=\"how_it_works.html\" title=\"previous chapter\">How it works</a></li>\n      <li>Next: <a href=\"pwlf.html\" title=\"next chapter\">pwlf package contents</a></li>\n  </ul></li>\n</ul>\n</div>\n\n\n\n\n\n\n\n\n        </div>\n      </div>\n      <div class=\"clearer\"></div>\n    </div>\n    <div class=\"footer\">\n      &#169;2024, Charles Jekel.\n      \n      |\n      Powered by <a href=\"https://www.sphinx-doc.org/\">Sphinx 8.1.3</a>\n      &amp; <a href=\"https://alabaster.readthedocs.io\">Alabaster 1.0.0</a>\n      \n      |\n      <a href=\"_sources/examples.rst.txt\"\n          rel=\"nofollow\">Page source</a>\n    </div>\n\n    \n\n    \n    <script>\n\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'G-QKPGZSZ8CD']);\n      _gaq.push(['_setDomainName', 'none']);\n      _gaq.push(['_setAllowLinker', true]);\n      _gaq.push(['_trackPageview']);\n\n      (function() {\n        var ga = document.createElement('script'); ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n\n    </script>\n    \n  </body>\n</html>"
  },
  {
    "path": "docs/genindex.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\" data-content_root=\"./\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Index &#8212; pwlf 2.5.2 documentation</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/pygments.css?v=d1102ebc\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/basic.css?v=686e5160\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/alabaster.css?v=27fed22d\" />\n    <script src=\"_static/documentation_options.js?v=afc61bbc\"></script>\n    <script src=\"_static/doctools.js?v=9bcbadda\"></script>\n    <script src=\"_static/sphinx_highlight.js?v=dc90522c\"></script>\n    <link rel=\"icon\" href=\"_static/favicon.ico\"/>\n    <link rel=\"author\" title=\"About these documents\" href=\"about.html\" />\n    <link rel=\"index\" title=\"Index\" href=\"#\" />\n    <link rel=\"search\" title=\"Search\" href=\"search.html\" />\n   \n  <link rel=\"stylesheet\" href=\"_static/custom.css\" type=\"text/css\" />\n  \n\n  \n  \n\n  </head><body>\n  \n\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n        <div class=\"bodywrapper\">\n          \n\n          <div class=\"body\" role=\"main\">\n            \n\n<h1 id=\"index\">Index</h1>\n\n<div class=\"genindex-jumpbox\">\n <a href=\"#_\"><strong>_</strong></a>\n | <a href=\"#A\"><strong>A</strong></a>\n | <a href=\"#C\"><strong>C</strong></a>\n | <a href=\"#F\"><strong>F</strong></a>\n | <a href=\"#L\"><strong>L</strong></a>\n | <a href=\"#P\"><strong>P</strong></a>\n | <a href=\"#R\"><strong>R</strong></a>\n | <a href=\"#S\"><strong>S</strong></a>\n | <a href=\"#U\"><strong>U</strong></a>\n \n</div>\n<h2 id=\"_\">_</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"stubs/pwlf.PiecewiseLinFit.html#pwlf.PiecewiseLinFit.__init__\">__init__() (pwlf.PiecewiseLinFit method)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"A\">A</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.assemble_regression_matrix\">assemble_regression_matrix() (pwlf.PiecewiseLinFit method)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"C\">C</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.calc_slopes\">calc_slopes() (pwlf.PiecewiseLinFit method)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.conlstsq\">conlstsq() (pwlf.PiecewiseLinFit method)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"F\">F</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.fit\">fit() (pwlf.PiecewiseLinFit method)</a>\n</li>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.fit_force_points_opt\">fit_force_points_opt() (pwlf.PiecewiseLinFit method)</a>\n</li>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.fit_guess\">fit_guess() (pwlf.PiecewiseLinFit method)</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.fit_with_breaks\">fit_with_breaks() (pwlf.PiecewiseLinFit method)</a>\n</li>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.fit_with_breaks_force_points\">fit_with_breaks_force_points() (pwlf.PiecewiseLinFit method)</a>\n</li>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.fit_with_breaks_opt\">fit_with_breaks_opt() (pwlf.PiecewiseLinFit method)</a>\n</li>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.fitfast\">fitfast() (pwlf.PiecewiseLinFit method)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"L\">L</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.lstsq\">lstsq() (pwlf.PiecewiseLinFit method)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"P\">P</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.p_values\">p_values() (pwlf.PiecewiseLinFit method)</a>\n</li>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit\">PiecewiseLinFit (class in pwlf)</a>, <a href=\"stubs/pwlf.PiecewiseLinFit.html#pwlf.PiecewiseLinFit\">[1]</a>\n</li>\n  </ul></td>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.predict\">predict() (pwlf.PiecewiseLinFit method)</a>\n</li>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.prediction_variance\">prediction_variance() (pwlf.PiecewiseLinFit method)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"R\">R</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.r_squared\">r_squared() (pwlf.PiecewiseLinFit method)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"S\">S</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.standard_errors\">standard_errors() (pwlf.PiecewiseLinFit method)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n<h2 id=\"U\">U</h2>\n<table style=\"width: 100%\" class=\"indextable genindextable\"><tr>\n  <td style=\"width: 33%; vertical-align: top;\"><ul>\n      <li><a href=\"pwlf.html#pwlf.PiecewiseLinFit.use_custom_opt\">use_custom_opt() (pwlf.PiecewiseLinFit method)</a>\n</li>\n  </ul></td>\n</tr></table>\n\n\n\n          </div>\n          \n        </div>\n      </div>\n      <div class=\"sphinxsidebar\" role=\"navigation\" aria-label=\"Main\">\n        <div class=\"sphinxsidebarwrapper\">\n<h1 class=\"logo\"><a href=\"index.html\">pwlf</a></h1>\n\n\n\n\n\n\n\n\n\n<search id=\"searchbox\" style=\"display: none\" role=\"search\">\n    <div class=\"searchformwrapper\">\n    <form class=\"search\" action=\"search.html\" method=\"get\">\n      <input type=\"text\" name=\"q\" aria-labelledby=\"searchlabel\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" placeholder=\"Search\"/>\n      <input type=\"submit\" value=\"Go\" />\n    </form>\n    </div>\n</search>\n<script>document.getElementById('searchbox').style.display = \"block\"</script><h3>Navigation</h3>\n<ul>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"installation.html\">Installation</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"how_it_works.html\">How it works</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"examples.html\">Examples</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"pwlf.html\">pwlf package contents</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"about.html\">About</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"requirements.html\">Requirements</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"license.html\">License</a></li>\n</ul>\n\n<div class=\"relations\">\n<h3>Related Topics</h3>\n<ul>\n  <li><a href=\"index.html\">Documentation overview</a><ul>\n  </ul></li>\n</ul>\n</div>\n\n\n\n\n\n\n\n\n        </div>\n      </div>\n      <div class=\"clearer\"></div>\n    </div>\n    <div class=\"footer\">\n      &#169;2024, Charles Jekel.\n      \n      |\n      Powered by <a href=\"https://www.sphinx-doc.org/\">Sphinx 8.1.3</a>\n      &amp; <a href=\"https://alabaster.readthedocs.io\">Alabaster 1.0.0</a>\n      \n    </div>\n\n    \n\n    \n    <script>\n\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'G-QKPGZSZ8CD']);\n      _gaq.push(['_setDomainName', 'none']);\n      _gaq.push(['_setAllowLinker', true]);\n      _gaq.push(['_trackPageview']);\n\n      (function() {\n        var ga = document.createElement('script'); ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n\n    </script>\n    \n  </body>\n</html>"
  },
  {
    "path": "docs/how_it_works.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\" data-content_root=\"./\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>How it works &#8212; pwlf 2.5.2 documentation</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/pygments.css?v=d1102ebc\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/basic.css?v=686e5160\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/alabaster.css?v=27fed22d\" />\n    <script src=\"_static/documentation_options.js?v=afc61bbc\"></script>\n    <script src=\"_static/doctools.js?v=9bcbadda\"></script>\n    <script src=\"_static/sphinx_highlight.js?v=dc90522c\"></script>\n    <link rel=\"icon\" href=\"_static/favicon.ico\"/>\n    <link rel=\"author\" title=\"About these documents\" href=\"about.html\" />\n    <link rel=\"index\" title=\"Index\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"Search\" href=\"search.html\" />\n    <link rel=\"next\" title=\"Examples\" href=\"examples.html\" />\n    <link rel=\"prev\" title=\"Installation\" href=\"installation.html\" />\n   \n  <link rel=\"stylesheet\" href=\"_static/custom.css\" type=\"text/css\" />\n  \n\n  \n  \n\n  </head><body>\n  \n\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n        <div class=\"bodywrapper\">\n          \n\n          <div class=\"body\" role=\"main\">\n            \n  <section id=\"how-it-works\">\n<h1>How it works<a class=\"headerlink\" href=\"#how-it-works\" title=\"Link to this heading\">¶</a></h1>\n<p>This\n<a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py/raw/master/paper/pwlf_Jekel_Venter_v2.pdf\">paper</a>\nexplains how this library works in detail.</p>\n<p>This is based on a formulation of a piecewise linear least squares fit,\nwhere the user must specify the location of break points. See <a class=\"reference external\" href=\"http://jekel.me/2018/Continous-piecewise-linear-regression/\">this\npost</a>\nwhich goes through the derivation of a least squares regression problem\nif the break point locations are known. Alternatively check out\n<a class=\"reference external\" href=\"http://golovchenko.org/docs/ContinuousPiecewiseLinearFit.pdf\">Golovchenko\n(2004)</a>.</p>\n<p>Global optimization is used to find the best location for the user\ndefined number of line segments. I specifically use the <a class=\"reference external\" href=\"https://docs.scipy.org/doc/scipy-0.17.0/reference/generated/scipy.optimize.differential_evolution.html\">differential\nevolution</a>\nalgorithm in SciPy. I default the differential evolution algorithm to be\naggressive, and it is probably overkill for your problem. So feel free\nto pass your own differential evolution keywords to the library. See\n<a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/fitForSpecifiedNumberOfLineSegments_passDiffEvoKeywords.py\">this\nexample</a>.</p>\n</section>\n\n\n          </div>\n          \n        </div>\n      </div>\n      <div class=\"sphinxsidebar\" role=\"navigation\" aria-label=\"Main\">\n        <div class=\"sphinxsidebarwrapper\">\n<h1 class=\"logo\"><a href=\"index.html\">pwlf</a></h1>\n\n\n\n\n\n\n\n\n\n<search id=\"searchbox\" style=\"display: none\" role=\"search\">\n    <div class=\"searchformwrapper\">\n    <form class=\"search\" action=\"search.html\" method=\"get\">\n      <input type=\"text\" name=\"q\" aria-labelledby=\"searchlabel\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" placeholder=\"Search\"/>\n      <input type=\"submit\" value=\"Go\" />\n    </form>\n    </div>\n</search>\n<script>document.getElementById('searchbox').style.display = \"block\"</script><h3>Navigation</h3>\n<ul class=\"current\">\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"installation.html\">Installation</a></li>\n<li class=\"toctree-l1 current\"><a class=\"current reference internal\" href=\"#\">How it works</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"examples.html\">Examples</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"pwlf.html\">pwlf package contents</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"about.html\">About</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"requirements.html\">Requirements</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"license.html\">License</a></li>\n</ul>\n\n<div class=\"relations\">\n<h3>Related Topics</h3>\n<ul>\n  <li><a href=\"index.html\">Documentation overview</a><ul>\n      <li>Previous: <a href=\"installation.html\" title=\"previous chapter\">Installation</a></li>\n      <li>Next: <a href=\"examples.html\" title=\"next chapter\">Examples</a></li>\n  </ul></li>\n</ul>\n</div>\n\n\n\n\n\n\n\n\n        </div>\n      </div>\n      <div class=\"clearer\"></div>\n    </div>\n    <div class=\"footer\">\n      &#169;2024, Charles Jekel.\n      \n      |\n      Powered by <a href=\"https://www.sphinx-doc.org/\">Sphinx 8.1.3</a>\n      &amp; <a href=\"https://alabaster.readthedocs.io\">Alabaster 1.0.0</a>\n      \n      |\n      <a href=\"_sources/how_it_works.rst.txt\"\n          rel=\"nofollow\">Page source</a>\n    </div>\n\n    \n\n    \n    <script>\n\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'G-QKPGZSZ8CD']);\n      _gaq.push(['_setDomainName', 'none']);\n      _gaq.push(['_setAllowLinker', true]);\n      _gaq.push(['_trackPageview']);\n\n      (function() {\n        var ga = document.createElement('script'); ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n\n    </script>\n    \n  </body>\n</html>"
  },
  {
    "path": "docs/index.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\" data-content_root=\"./\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>pwlf: piecewise linear fitting &#8212; pwlf 2.5.2 documentation</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/pygments.css?v=d1102ebc\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/basic.css?v=686e5160\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/alabaster.css?v=27fed22d\" />\n    <script src=\"_static/documentation_options.js?v=afc61bbc\"></script>\n    <script src=\"_static/doctools.js?v=9bcbadda\"></script>\n    <script src=\"_static/sphinx_highlight.js?v=dc90522c\"></script>\n    <link rel=\"icon\" href=\"_static/favicon.ico\"/>\n    <link rel=\"author\" title=\"About these documents\" href=\"about.html\" />\n    <link rel=\"index\" title=\"Index\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"Search\" href=\"search.html\" />\n    <link rel=\"next\" title=\"Installation\" href=\"installation.html\" />\n   \n  <link rel=\"stylesheet\" href=\"_static/custom.css\" type=\"text/css\" />\n  \n\n  \n  \n\n  </head><body>\n  \n\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n        <div class=\"bodywrapper\">\n          \n\n          <div class=\"body\" role=\"main\">\n            \n  <section id=\"pwlf-piecewise-linear-fitting\">\n<h1>pwlf: piecewise linear fitting<a class=\"headerlink\" href=\"#pwlf-piecewise-linear-fitting\" title=\"Link to this heading\">¶</a></h1>\n<p>Fit piecewise linear functions to data!</p>\n<div class=\"toctree-wrapper compound\">\n<ul>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"installation.html\">Installation</a><ul>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"installation.html#python-package-index-pypi\">Python Package Index (PyPI)</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"installation.html#conda\">Conda</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"installation.html#from-source\">From source</a></li>\n</ul>\n</li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"how_it_works.html\">How it works</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"examples.html\">Examples</a><ul>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#fit-with-known-breakpoint-locations\">fit with known breakpoint locations</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#fit-for-specified-number-of-line-segments\">fit for specified number of line segments</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#fitfast-for-specified-number-of-line-segments\">fitfast for specified number of line segments</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#force-a-fit-through-data-points\">force a fit through data points</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#use-custom-optimization-routine\">use custom optimization routine</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#pass-differential-evolution-keywords\">pass differential evolution keywords</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#find-the-best-number-of-line-segments\">find the best number of line segments</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#model-persistence\">model persistence</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#bad-fits-when-you-have-more-unknowns-than-data\">bad fits when you have more unknowns than data</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#fit-with-a-breakpoint-guess\">fit with a breakpoint guess</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#get-the-linear-regression-matrix\">get the linear regression matrix</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#use-of-tensorflow\">use of tensorflow</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#fit-constants-or-polynomials\">fit constants or polynomials</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#specify-breakpoint-bounds\">specify breakpoint bounds</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#non-linear-standard-errors-and-p-values\">non-linear standard errors and p-values</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#obtain-the-equations-of-fitted-pwlf\">obtain the equations of fitted pwlf</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#weighted-least-squares-fit\">weighted least squares fit</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"examples.html#reproducible-results\">reproducible results</a></li>\n</ul>\n</li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"pwlf.html\">pwlf package contents</a><ul>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"stubs/pwlf.PiecewiseLinFit.html\">pwlf.PiecewiseLinFit</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit</span></code></a></li>\n</ul>\n</li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"about.html\">About</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"requirements.html\">Requirements</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"license.html\">License</a></li>\n</ul>\n</div>\n</section>\n<section id=\"indices-and-tables\">\n<h1>Indices and tables<a class=\"headerlink\" href=\"#indices-and-tables\" title=\"Link to this heading\">¶</a></h1>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"genindex.html\"><span class=\"std std-ref\">Index</span></a></p></li>\n<li><p><a class=\"reference internal\" href=\"search.html\"><span class=\"std std-ref\">Search Page</span></a></p></li>\n</ul>\n</section>\n\n\n          </div>\n          \n        </div>\n      </div>\n      <div class=\"sphinxsidebar\" role=\"navigation\" aria-label=\"Main\">\n        <div class=\"sphinxsidebarwrapper\">\n<h1 class=\"logo\"><a href=\"#\">pwlf</a></h1>\n\n\n\n\n\n\n\n\n\n<search id=\"searchbox\" style=\"display: none\" role=\"search\">\n    <div class=\"searchformwrapper\">\n    <form class=\"search\" action=\"search.html\" method=\"get\">\n      <input type=\"text\" name=\"q\" aria-labelledby=\"searchlabel\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" placeholder=\"Search\"/>\n      <input type=\"submit\" value=\"Go\" />\n    </form>\n    </div>\n</search>\n<script>document.getElementById('searchbox').style.display = \"block\"</script><h3>Navigation</h3>\n<ul>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"installation.html\">Installation</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"how_it_works.html\">How it works</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"examples.html\">Examples</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"pwlf.html\">pwlf package contents</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"about.html\">About</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"requirements.html\">Requirements</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"license.html\">License</a></li>\n</ul>\n\n<div class=\"relations\">\n<h3>Related Topics</h3>\n<ul>\n  <li><a href=\"#\">Documentation overview</a><ul>\n      <li>Next: <a href=\"installation.html\" title=\"next chapter\">Installation</a></li>\n  </ul></li>\n</ul>\n</div>\n\n\n\n\n\n\n\n\n        </div>\n      </div>\n      <div class=\"clearer\"></div>\n    </div>\n    <div class=\"footer\">\n      &#169;2024, Charles Jekel.\n      \n      |\n      Powered by <a href=\"https://www.sphinx-doc.org/\">Sphinx 8.1.3</a>\n      &amp; <a href=\"https://alabaster.readthedocs.io\">Alabaster 1.0.0</a>\n      \n      |\n      <a href=\"_sources/index.rst.txt\"\n          rel=\"nofollow\">Page source</a>\n    </div>\n\n    \n\n    \n    <script>\n\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'G-QKPGZSZ8CD']);\n      _gaq.push(['_setDomainName', 'none']);\n      _gaq.push(['_setAllowLinker', true]);\n      _gaq.push(['_trackPageview']);\n\n      (function() {\n        var ga = document.createElement('script'); ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n\n    </script>\n    \n  </body>\n</html>"
  },
  {
    "path": "docs/installation.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\" data-content_root=\"./\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>Installation &#8212; pwlf 2.5.2 documentation</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/pygments.css?v=d1102ebc\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/basic.css?v=686e5160\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/alabaster.css?v=27fed22d\" />\n    <script src=\"_static/documentation_options.js?v=afc61bbc\"></script>\n    <script src=\"_static/doctools.js?v=9bcbadda\"></script>\n    <script src=\"_static/sphinx_highlight.js?v=dc90522c\"></script>\n    <link rel=\"icon\" href=\"_static/favicon.ico\"/>\n    <link rel=\"author\" title=\"About these documents\" href=\"about.html\" />\n    <link rel=\"index\" title=\"Index\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"Search\" href=\"search.html\" />\n    <link rel=\"next\" title=\"How it works\" href=\"how_it_works.html\" />\n    <link rel=\"prev\" title=\"pwlf: piecewise linear fitting\" href=\"index.html\" />\n   \n  <link rel=\"stylesheet\" href=\"_static/custom.css\" type=\"text/css\" />\n  \n\n  \n  \n\n  </head><body>\n  \n\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n        <div class=\"bodywrapper\">\n          \n\n          <div class=\"body\" role=\"main\">\n            \n  <section id=\"installation\">\n<h1>Installation<a class=\"headerlink\" href=\"#installation\" title=\"Link to this heading\">¶</a></h1>\n<section id=\"python-package-index-pypi\">\n<h2>Python Package Index (PyPI)<a class=\"headerlink\" href=\"#python-package-index-pypi\" title=\"Link to this heading\">¶</a></h2>\n<p>You can now install with pip.</p>\n<div class=\"highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"n\">python</span> <span class=\"o\">-</span><span class=\"n\">m</span> <span class=\"n\">pip</span> <span class=\"n\">install</span> <span class=\"n\">pwlf</span>\n</pre></div>\n</div>\n</section>\n<section id=\"conda\">\n<h2>Conda<a class=\"headerlink\" href=\"#conda\" title=\"Link to this heading\">¶</a></h2>\n<p>If you have conda, you can also install from conda-forge.</p>\n<div class=\"highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"n\">conda</span> <span class=\"n\">install</span> <span class=\"o\">-</span><span class=\"n\">c</span> <span class=\"n\">conda</span><span class=\"o\">-</span><span class=\"n\">forge</span> <span class=\"n\">pwlf</span>\n</pre></div>\n</div>\n</section>\n<section id=\"from-source\">\n<h2>From source<a class=\"headerlink\" href=\"#from-source\" title=\"Link to this heading\">¶</a></h2>\n<p>Or clone the repo</p>\n<div class=\"highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"n\">git</span> <span class=\"n\">clone</span> <span class=\"n\">https</span><span class=\"p\">:</span><span class=\"o\">//</span><span class=\"n\">github</span><span class=\"o\">.</span><span class=\"n\">com</span><span class=\"o\">/</span><span class=\"n\">cjekel</span><span class=\"o\">/</span><span class=\"n\">piecewise_linear_fit_py</span><span class=\"o\">.</span><span class=\"n\">git</span>\n</pre></div>\n</div>\n<p>then install with pip</p>\n<div class=\"highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"n\">python</span> <span class=\"o\">-</span><span class=\"n\">m</span> <span class=\"n\">pip</span> <span class=\"n\">install</span> <span class=\"o\">./</span><span class=\"n\">piecewise_linear_fit_py</span>\n</pre></div>\n</div>\n</section>\n</section>\n\n\n          </div>\n          \n        </div>\n      </div>\n      <div class=\"sphinxsidebar\" role=\"navigation\" aria-label=\"Main\">\n        <div class=\"sphinxsidebarwrapper\">\n<h1 class=\"logo\"><a href=\"index.html\">pwlf</a></h1>\n\n\n\n\n\n\n\n\n\n<search id=\"searchbox\" style=\"display: none\" role=\"search\">\n    <div class=\"searchformwrapper\">\n    <form class=\"search\" action=\"search.html\" method=\"get\">\n      <input type=\"text\" name=\"q\" aria-labelledby=\"searchlabel\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" placeholder=\"Search\"/>\n      <input type=\"submit\" value=\"Go\" />\n    </form>\n    </div>\n</search>\n<script>document.getElementById('searchbox').style.display = \"block\"</script><h3>Navigation</h3>\n<ul class=\"current\">\n<li class=\"toctree-l1 current\"><a class=\"current reference internal\" href=\"#\">Installation</a><ul>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#python-package-index-pypi\">Python Package Index (PyPI)</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#conda\">Conda</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#from-source\">From source</a></li>\n</ul>\n</li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"how_it_works.html\">How it works</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"examples.html\">Examples</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"pwlf.html\">pwlf package contents</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"about.html\">About</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"requirements.html\">Requirements</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"license.html\">License</a></li>\n</ul>\n\n<div class=\"relations\">\n<h3>Related Topics</h3>\n<ul>\n  <li><a href=\"index.html\">Documentation overview</a><ul>\n      <li>Previous: <a href=\"index.html\" title=\"previous chapter\">pwlf: piecewise linear fitting</a></li>\n      <li>Next: <a href=\"how_it_works.html\" title=\"next chapter\">How it works</a></li>\n  </ul></li>\n</ul>\n</div>\n\n\n\n\n\n\n\n\n        </div>\n      </div>\n      <div class=\"clearer\"></div>\n    </div>\n    <div class=\"footer\">\n      &#169;2024, Charles Jekel.\n      \n      |\n      Powered by <a href=\"https://www.sphinx-doc.org/\">Sphinx 8.1.3</a>\n      &amp; <a href=\"https://alabaster.readthedocs.io\">Alabaster 1.0.0</a>\n      \n      |\n      <a href=\"_sources/installation.rst.txt\"\n          rel=\"nofollow\">Page source</a>\n    </div>\n\n    \n\n    \n    <script>\n\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'G-QKPGZSZ8CD']);\n      _gaq.push(['_setDomainName', 'none']);\n      _gaq.push(['_setAllowLinker', true]);\n      _gaq.push(['_trackPageview']);\n\n      (function() {\n        var ga = document.createElement('script'); ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n\n    </script>\n    \n  </body>\n</html>"
  },
  {
    "path": "docs/license.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\" data-content_root=\"./\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>License &#8212; pwlf 2.5.2 documentation</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/pygments.css?v=d1102ebc\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/basic.css?v=686e5160\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/alabaster.css?v=27fed22d\" />\n    <script src=\"_static/documentation_options.js?v=afc61bbc\"></script>\n    <script src=\"_static/doctools.js?v=9bcbadda\"></script>\n    <script src=\"_static/sphinx_highlight.js?v=dc90522c\"></script>\n    <link rel=\"icon\" href=\"_static/favicon.ico\"/>\n    <link rel=\"author\" title=\"About these documents\" href=\"about.html\" />\n    <link rel=\"index\" title=\"Index\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"Search\" href=\"search.html\" />\n    <link rel=\"prev\" title=\"Requirements\" href=\"requirements.html\" />\n   \n  <link rel=\"stylesheet\" href=\"_static/custom.css\" type=\"text/css\" />\n  \n\n  \n  \n\n  </head><body>\n  \n\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n        <div class=\"bodywrapper\">\n          \n\n          <div class=\"body\" role=\"main\">\n            \n  <section id=\"license\">\n<h1>License<a class=\"headerlink\" href=\"#license\" title=\"Link to this heading\">¶</a></h1>\n<p>MIT License</p>\n<p>Copyright (c) 2017-2020 Charles Jekel</p>\n<p>Permission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the “Software”), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:</p>\n<p>The above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.</p>\n<p>THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.</p>\n</section>\n\n\n          </div>\n          \n        </div>\n      </div>\n      <div class=\"sphinxsidebar\" role=\"navigation\" aria-label=\"Main\">\n        <div class=\"sphinxsidebarwrapper\">\n<h1 class=\"logo\"><a href=\"index.html\">pwlf</a></h1>\n\n\n\n\n\n\n\n\n\n<search id=\"searchbox\" style=\"display: none\" role=\"search\">\n    <div class=\"searchformwrapper\">\n    <form class=\"search\" action=\"search.html\" method=\"get\">\n      <input type=\"text\" name=\"q\" aria-labelledby=\"searchlabel\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" placeholder=\"Search\"/>\n      <input type=\"submit\" value=\"Go\" />\n    </form>\n    </div>\n</search>\n<script>document.getElementById('searchbox').style.display = \"block\"</script><h3>Navigation</h3>\n<ul class=\"current\">\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"installation.html\">Installation</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"how_it_works.html\">How it works</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"examples.html\">Examples</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"pwlf.html\">pwlf package contents</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"about.html\">About</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"requirements.html\">Requirements</a></li>\n<li class=\"toctree-l1 current\"><a class=\"current reference internal\" href=\"#\">License</a></li>\n</ul>\n\n<div class=\"relations\">\n<h3>Related Topics</h3>\n<ul>\n  <li><a href=\"index.html\">Documentation overview</a><ul>\n      <li>Previous: <a href=\"requirements.html\" title=\"previous chapter\">Requirements</a></li>\n  </ul></li>\n</ul>\n</div>\n\n\n\n\n\n\n\n\n        </div>\n      </div>\n      <div class=\"clearer\"></div>\n    </div>\n    <div class=\"footer\">\n      &#169;2024, Charles Jekel.\n      \n      |\n      Powered by <a href=\"https://www.sphinx-doc.org/\">Sphinx 8.1.3</a>\n      &amp; <a href=\"https://alabaster.readthedocs.io\">Alabaster 1.0.0</a>\n      \n      |\n      <a href=\"_sources/license.rst.txt\"\n          rel=\"nofollow\">Page source</a>\n    </div>\n\n    \n\n    \n    <script>\n\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'G-QKPGZSZ8CD']);\n      _gaq.push(['_setDomainName', 'none']);\n      _gaq.push(['_setAllowLinker', true]);\n      _gaq.push(['_trackPageview']);\n\n      (function() {\n        var ga = document.createElement('script'); ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n\n    </script>\n    \n  </body>\n</html>"
  },
  {
    "path": "docs/modules.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\" data-content_root=\"./\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>pwlf &#8212; pwlf 2.5.2 documentation</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/pygments.css?v=d1102ebc\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/basic.css?v=686e5160\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/alabaster.css?v=27fed22d\" />\n    <script src=\"_static/documentation_options.js?v=afc61bbc\"></script>\n    <script src=\"_static/doctools.js?v=9bcbadda\"></script>\n    <script src=\"_static/sphinx_highlight.js?v=dc90522c\"></script>\n    <link rel=\"icon\" href=\"_static/favicon.ico\"/>\n    <link rel=\"author\" title=\"About these documents\" href=\"about.html\" />\n    <link rel=\"index\" title=\"Index\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"Search\" href=\"search.html\" />\n   \n  <link rel=\"stylesheet\" href=\"_static/custom.css\" type=\"text/css\" />\n  \n\n  \n  \n\n  </head><body>\n  \n\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n        <div class=\"bodywrapper\">\n          \n\n          <div class=\"body\" role=\"main\">\n            \n  <section id=\"pwlf\">\n<h1>pwlf<a class=\"headerlink\" href=\"#pwlf\" title=\"Link to this heading\">¶</a></h1>\n<div class=\"toctree-wrapper compound\">\n<ul>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"pwlf.html\">pwlf package contents</a><ul>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"stubs/pwlf.PiecewiseLinFit.html\">pwlf.PiecewiseLinFit</a><ul>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"stubs/pwlf.PiecewiseLinFit.html#pwlf.PiecewiseLinFit\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit</span></code></a><ul>\n<li class=\"toctree-l4\"><a class=\"reference internal\" href=\"stubs/pwlf.PiecewiseLinFit.html#pwlf.PiecewiseLinFit.__init__\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.__init__()</span></code></a></li>\n</ul>\n</li>\n</ul>\n</li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit</span></code></a><ul>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.assemble_regression_matrix\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.assemble_regression_matrix()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.calc_slopes\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.calc_slopes()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.conlstsq\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.conlstsq()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.fit\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.fit()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.fit_force_points_opt\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.fit_force_points_opt()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.fit_guess\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.fit_guess()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.fit_with_breaks\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.fit_with_breaks()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.fit_with_breaks_force_points\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.fit_with_breaks_force_points()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.fit_with_breaks_opt\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.fit_with_breaks_opt()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.fitfast\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.fitfast()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.lstsq\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.lstsq()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.p_values\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.p_values()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.predict\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.predict()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.prediction_variance\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.prediction_variance()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.r_squared\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.r_squared()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.standard_errors\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.standard_errors()</span></code></a></li>\n<li class=\"toctree-l3\"><a class=\"reference internal\" href=\"pwlf.html#pwlf.PiecewiseLinFit.use_custom_opt\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit.use_custom_opt()</span></code></a></li>\n</ul>\n</li>\n</ul>\n</li>\n</ul>\n</div>\n</section>\n\n\n          </div>\n          \n        </div>\n      </div>\n      <div class=\"sphinxsidebar\" role=\"navigation\" aria-label=\"Main\">\n        <div class=\"sphinxsidebarwrapper\">\n<h1 class=\"logo\"><a href=\"index.html\">pwlf</a></h1>\n\n\n\n\n\n\n\n\n\n<search id=\"searchbox\" style=\"display: none\" role=\"search\">\n    <div class=\"searchformwrapper\">\n    <form class=\"search\" action=\"search.html\" method=\"get\">\n      <input type=\"text\" name=\"q\" aria-labelledby=\"searchlabel\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" placeholder=\"Search\"/>\n      <input type=\"submit\" value=\"Go\" />\n    </form>\n    </div>\n</search>\n<script>document.getElementById('searchbox').style.display = \"block\"</script><h3>Navigation</h3>\n<ul>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"installation.html\">Installation</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"how_it_works.html\">How it works</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"examples.html\">Examples</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"pwlf.html\">pwlf package contents</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"about.html\">About</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"requirements.html\">Requirements</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"license.html\">License</a></li>\n</ul>\n\n<div class=\"relations\">\n<h3>Related Topics</h3>\n<ul>\n  <li><a href=\"index.html\">Documentation overview</a><ul>\n  </ul></li>\n</ul>\n</div>\n\n\n\n\n\n\n\n\n        </div>\n      </div>\n      <div class=\"clearer\"></div>\n    </div>\n    <div class=\"footer\">\n      &#169;2024, Charles Jekel.\n      \n      |\n      Powered by <a href=\"https://www.sphinx-doc.org/\">Sphinx 8.1.3</a>\n      &amp; <a href=\"https://alabaster.readthedocs.io\">Alabaster 1.0.0</a>\n      \n      |\n      <a href=\"_sources/modules.rst.txt\"\n          rel=\"nofollow\">Page source</a>\n    </div>\n\n    \n\n    \n    <script>\n\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'G-QKPGZSZ8CD']);\n      _gaq.push(['_setDomainName', 'none']);\n      _gaq.push(['_setAllowLinker', true]);\n      _gaq.push(['_trackPageview']);\n\n      (function() {\n        var ga = document.createElement('script'); ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n\n    </script>\n    \n  </body>\n</html>"
  },
  {
    "path": "docs/pwlf.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\" data-content_root=\"./\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>pwlf package contents &#8212; pwlf 2.5.2 documentation</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/pygments.css?v=d1102ebc\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/basic.css?v=686e5160\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/alabaster.css?v=27fed22d\" />\n    <script src=\"_static/documentation_options.js?v=afc61bbc\"></script>\n    <script src=\"_static/doctools.js?v=9bcbadda\"></script>\n    <script src=\"_static/sphinx_highlight.js?v=dc90522c\"></script>\n    <link rel=\"icon\" href=\"_static/favicon.ico\"/>\n    <link rel=\"author\" title=\"About these documents\" href=\"about.html\" />\n    <link rel=\"index\" title=\"Index\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"Search\" href=\"search.html\" />\n    <link rel=\"next\" title=\"pwlf.PiecewiseLinFit\" href=\"stubs/pwlf.PiecewiseLinFit.html\" />\n    <link rel=\"prev\" title=\"Examples\" href=\"examples.html\" />\n   \n  <link rel=\"stylesheet\" href=\"_static/custom.css\" type=\"text/css\" />\n  \n\n  \n  \n\n  </head><body>\n  \n\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n        <div class=\"bodywrapper\">\n          \n\n          <div class=\"body\" role=\"main\">\n            \n  <section id=\"pwlf-package-contents\">\n<h1>pwlf package contents<a class=\"headerlink\" href=\"#pwlf-package-contents\" title=\"Link to this heading\">¶</a></h1>\n<table class=\"autosummary longtable docutils align-default\">\n<tbody>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"stubs/pwlf.PiecewiseLinFit.html#pwlf.PiecewiseLinFit\" title=\"pwlf.PiecewiseLinFit\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">pwlf.PiecewiseLinFit</span></code></a>(x, y[, disp_res, ...])</p></td>\n<td><p></p></td>\n</tr>\n</tbody>\n</table>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit\">\n<em class=\"property\"><span class=\"pre\">class</span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">pwlf.</span></span><span class=\"sig-name descname\"><span class=\"pre\">PiecewiseLinFit</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">x</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">y</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">disp_res</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">False</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">lapack_driver</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'gelsd'</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">degree</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">1</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">weights</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">seed</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Bases: <a class=\"reference external\" href=\"https://docs.python.org/3/library/functions.html#object\" title=\"(in Python v3.13)\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">object</span></code></a></p>\n<p class=\"rubric\">Methods</p>\n<table class=\"autosummary longtable docutils align-default\">\n<tbody>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.assemble_regression_matrix\" title=\"pwlf.PiecewiseLinFit.assemble_regression_matrix\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">assemble_regression_matrix</span></code></a>(breaks, x)</p></td>\n<td><p>Assemble the linear regression matrix A</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.calc_slopes\" title=\"pwlf.PiecewiseLinFit.calc_slopes\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">calc_slopes</span></code></a>()</p></td>\n<td><p>Calculate the slopes of the lines after a piecewise linear function has been fitted.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.conlstsq\" title=\"pwlf.PiecewiseLinFit.conlstsq\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">conlstsq</span></code></a>(A[, calc_slopes])</p></td>\n<td><p>Perform a constrained least squares fit for A matrix.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.fit\" title=\"pwlf.PiecewiseLinFit.fit\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit</span></code></a>(n_segments[, x_c, y_c, bounds])</p></td>\n<td><p>Fit a continuous piecewise linear function for a specified number of line segments.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.fit_force_points_opt\" title=\"pwlf.PiecewiseLinFit.fit_force_points_opt\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_force_points_opt</span></code></a>(var)</p></td>\n<td><p>The objective function to perform a continuous piecewise linear fit for a specified number of breakpoints.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.fit_guess\" title=\"pwlf.PiecewiseLinFit.fit_guess\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_guess</span></code></a>(guess_breakpoints[, bounds])</p></td>\n<td><p>Uses L-BFGS-B optimization to find the location of breakpoints from a guess of where breakpoint locations should be.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.fit_with_breaks\" title=\"pwlf.PiecewiseLinFit.fit_with_breaks\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_with_breaks</span></code></a>(breaks)</p></td>\n<td><p>A function which fits a continuous piecewise linear function for specified breakpoint locations.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.fit_with_breaks_force_points\" title=\"pwlf.PiecewiseLinFit.fit_with_breaks_force_points\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_with_breaks_force_points</span></code></a>(breaks, x_c, y_c)</p></td>\n<td><p>A function which fits a continuous piecewise linear function for specified breakpoint locations, where you force the fit to go through the data points at x_c and y_c.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.fit_with_breaks_opt\" title=\"pwlf.PiecewiseLinFit.fit_with_breaks_opt\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_with_breaks_opt</span></code></a>(var)</p></td>\n<td><p>The objective function to perform a continuous piecewise linear fit for a specified number of breakpoints.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.fitfast\" title=\"pwlf.PiecewiseLinFit.fitfast\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fitfast</span></code></a>(n_segments[, pop, bounds])</p></td>\n<td><p>Uses multi start LBFGSB optimization to find the location of breakpoints for a given number of line segments by minimizing the sum of the square of the errors.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.lstsq\" title=\"pwlf.PiecewiseLinFit.lstsq\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">lstsq</span></code></a>(A[, calc_slopes])</p></td>\n<td><p>Perform the least squares fit for A matrix.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.p_values\" title=\"pwlf.PiecewiseLinFit.p_values\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">p_values</span></code></a>([method, step_size])</p></td>\n<td><p>Calculate the p-values for each beta parameter.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.predict\" title=\"pwlf.PiecewiseLinFit.predict\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">predict</span></code></a>(x[, beta, breaks])</p></td>\n<td><p>Evaluate the fitted continuous piecewise linear function at untested points.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.prediction_variance\" title=\"pwlf.PiecewiseLinFit.prediction_variance\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">prediction_variance</span></code></a>(x)</p></td>\n<td><p>Calculate the prediction variance for each specified x location.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.r_squared\" title=\"pwlf.PiecewiseLinFit.r_squared\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">r_squared</span></code></a>()</p></td>\n<td><p>Calculate the coefficient of determination (&quot;R squared&quot;, R^2) value after a fit has been performed.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.standard_errors\" title=\"pwlf.PiecewiseLinFit.standard_errors\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">standard_errors</span></code></a>([method, step_size])</p></td>\n<td><p>Calculate the standard errors for each beta parameter determined from the piecewise linear fit.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.use_custom_opt\" title=\"pwlf.PiecewiseLinFit.use_custom_opt\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">use_custom_opt</span></code></a>(n_segments[, x_c, y_c])</p></td>\n<td><p>Provide the number of line segments you want to use with your custom optimization routine.</p></td>\n</tr>\n</tbody>\n</table>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.assemble_regression_matrix\">\n<span class=\"sig-name descname\"><span class=\"pre\">assemble_regression_matrix</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">breaks</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">x</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.assemble_regression_matrix\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Assemble the linear regression matrix A</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>breaks</strong><span class=\"classifier\">array_like</span></dt><dd><p>The x locations where each line segment terminates. These are\nreferred to as breakpoints for each line segment. This should be\nstructured as a 1-D numpy array.</p>\n</dd>\n<dt><strong>x</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>The x locations which the linear regression matrix is assembled on.\nThis must be a numpy array!</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>A</strong><span class=\"classifier\">ndarray (2-D)</span></dt><dd><p>The assembled linear regression matrix.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Examples</p>\n<p>Assemble the linear regression matrix on the x data for some set of\nbreakpoints.</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">0.5</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">A</span> <span class=\"o\">=</span> <span class=\"n\">assemble_regression_matrix</span><span class=\"p\">(</span><span class=\"n\">breaks</span><span class=\"p\">,</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">x_data</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.calc_slopes\">\n<span class=\"sig-name descname\"><span class=\"pre\">calc_slopes</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.calc_slopes\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Calculate the slopes of the lines after a piecewise linear\nfunction has been fitted.</p>\n<p>This will also calculate the y-intercept from each line in the form\ny = mx + b. The intercepts are stored at self.intercepts.</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>slopes</strong><span class=\"classifier\">ndarray(1-D)</span></dt><dd><p>The slope of each ling segment as a 1-D numpy array. This assumes\nthat x[0] &lt;= x[1] &lt;= … &lt;= x[n]. Thus, slopes[0] is the slope\nof the first line segment.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Examples</p>\n<p>Calculate the slopes after performing a simple fit</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">slopes</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">calc_slopes</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.conlstsq\">\n<span class=\"sig-name descname\"><span class=\"pre\">conlstsq</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">A</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">calc_slopes</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">True</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.conlstsq\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Perform a constrained least squares fit for A matrix.</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>A</strong><span class=\"classifier\">ndarray (2-D)</span></dt><dd><p>The regression matrix you want to fit in the linear system of\nequations Ab=y.</p>\n</dd>\n<dt><strong>calc_slopes</strong><span class=\"classifier\">boolean, optional</span></dt><dd><p>Whether to calculate slopes after performing a fit. Default is\ncalc_slopes=True.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.fit\">\n<span class=\"sig-name descname\"><span class=\"pre\">fit</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">n_segments</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">x_c</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">y_c</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">bounds</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"o\"><span class=\"pre\">**</span></span><span class=\"n\"><span class=\"pre\">kwargs</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.fit\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Fit a continuous piecewise linear function for a specified number\nof line segments. Uses differential evolution to finds the optimum\nlocation of breakpoints for a given number of line segments by\nminimizing the sum of the square error.</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>n_segments</strong><span class=\"classifier\">int</span></dt><dd><p>The desired number of line segments.</p>\n</dd>\n<dt><strong>x_c</strong><span class=\"classifier\">array_like, optional</span></dt><dd><p>The x locations of the data points that the piecewise linear\nfunction will be forced to go through.</p>\n</dd>\n<dt><strong>y_c</strong><span class=\"classifier\">array_like, optional</span></dt><dd><p>The x locations of the data points that the piecewise linear\nfunction will be forced to go through.</p>\n</dd>\n<dt><strong>bounds</strong><span class=\"classifier\">array_like, optional</span></dt><dd><p>Bounds for each breakpoint location within the optimization. This\nshould have the shape of (n_segments, 2).</p>\n</dd>\n<dt><strong>**kwargs</strong><span class=\"classifier\">optional</span></dt><dd><p>Directly passed into scipy.optimize.differential_evolution(). This\nwill override any pwlf defaults when provided. See Note for more\ninformation.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>fit_breaks</strong><span class=\"classifier\">float</span></dt><dd><p>breakpoint locations stored as a 1-D numpy array.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-odd\">Raises<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt>ValueError</dt><dd><p>You probably provided x_c without y_c (or vice versa).\nYou must provide both x_c and y_c if you plan to force\nthe model through data point(s).</p>\n</dd>\n<dt>ValueError</dt><dd><p>You can’t specify weights with x_c and y_c.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Notes</p>\n<p>All <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">**</span></a>kwargs are passed into sicpy.optimize.differential_evolution.\nIf any <a href=\"#id3\"><span class=\"problematic\" id=\"id4\">**</span></a>kwargs is used, it will override my differential_evolution,\ndefaults. This allows advanced users to tweak their own optimization.\nFor me information see:\n<a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py/issues/15#issuecomment-434717232\">https://github.com/cjekel/piecewise_linear_fit_py/issues/15#issuecomment-434717232</a></p>\n<p class=\"rubric\">Examples</p>\n<p>This example shows you how to fit three continuous piecewise lines to\na dataset. This assumes that x is linearly spaced from [0, 1), and y is\nrandom.</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n<p>Additionally you desired that the piecewise linear function go\nthrough the point (0.0, 0.0).</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x_c</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">0.0</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y_c</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">0.0</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"n\">x_c</span><span class=\"o\">=</span><span class=\"n\">x_c</span><span class=\"p\">,</span> <span class=\"n\">y_c</span><span class=\"o\">=</span><span class=\"n\">y_c</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n<p>Additionally you desired that the piecewise linear function go\nthrough the points (0.0, 0.0) and (1.0, 1.0).</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x_c</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y_c</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"n\">x_c</span><span class=\"o\">=</span><span class=\"n\">x_c</span><span class=\"p\">,</span> <span class=\"n\">y_c</span><span class=\"o\">=</span><span class=\"n\">y_c</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.fit_force_points_opt\">\n<span class=\"sig-name descname\"><span class=\"pre\">fit_force_points_opt</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">var</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.fit_force_points_opt\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>The objective function to perform a continuous piecewise linear\nfit for a specified number of breakpoints. This is to be used\nwith a custom optimization routine, and after use_custom_opt has\nbeen called.</p>\n<p>Use this function if you intend to be force the model through\nx_c and y_c, while performing a custom optimization.</p>\n<p>This was intended for advanced users only.\nSee the following example\n<a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/useCustomOptimizationRoutine.py\">https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/useCustomOptimizationRoutine.py</a></p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>var</strong><span class=\"classifier\">array_like</span></dt><dd><p>The breakpoint locations, or variable, in a custom\noptimization routine.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>ssr</strong><span class=\"classifier\">float</span></dt><dd><p>The sum of square of the residuals.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-odd\">Raises<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt>LinAlgError</dt><dd><p>This typically means your regression problem is ill-conditioned.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Notes</p>\n<p>You should run use_custom_opt to initialize necessary object\nattributes first.</p>\n<p>Unlike fit_with_breaks_force_points, fit_force_points_opt\nautomatically assumes that the first and last breakpoints occur\nat the min and max values of x.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.fit_guess\">\n<span class=\"sig-name descname\"><span class=\"pre\">fit_guess</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">guess_breakpoints</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">bounds</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"o\"><span class=\"pre\">**</span></span><span class=\"n\"><span class=\"pre\">kwargs</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.fit_guess\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Uses L-BFGS-B optimization to find the location of breakpoints\nfrom a guess of where breakpoint locations should be.</p>\n<p>In some cases you may have a good idea where the breakpoint locations\noccur. It generally won’t be necessary to run a full global\noptimization to search the entire domain for the breakpoints when you\nhave a good idea where the breakpoints occur. Here a local optimization\nis run from a guess of the breakpoint locations.</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>guess_breakpoints</strong><span class=\"classifier\">array_like</span></dt><dd><p>Guess where the breakpoints occur. This should be a list or numpy\narray containing the locations where it appears breakpoints occur.</p>\n</dd>\n<dt><strong>bounds</strong><span class=\"classifier\">array_like, optional</span></dt><dd><p>Bounds for each breakpoint location within the optimization. This\nshould have the shape of (n_segments, 2).</p>\n</dd>\n<dt><strong>**kwargs</strong><span class=\"classifier\">optional</span></dt><dd><p>Directly passed into scipy.optimize.fmin_l_bfgs_b(). This\nwill override any pwlf defaults when provided. See Note for more\ninformation.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>fit_breaks</strong><span class=\"classifier\">float</span></dt><dd><p>breakpoint locations stored as a 1-D numpy array.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Notes</p>\n<p>All <a href=\"#id5\"><span class=\"problematic\" id=\"id6\">**</span></a>kwargs are passed into sicpy.optimize.fmin_l_bfgs_b. If any\n<a href=\"#id7\"><span class=\"problematic\" id=\"id8\">**</span></a>kwargs is used, it will override my defaults. This allows\nadvanced users to tweak their own optimization. For me information see:\n<a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py/issues/15#issuecomment-434717232\">https://github.com/cjekel/piecewise_linear_fit_py/issues/15#issuecomment-434717232</a></p>\n<p>You do not need to specify the x.min() or x.max() in geuss_breakpoints!</p>\n<p class=\"rubric\">Examples</p>\n<p>In this example we see two distinct linear regions, and we believe a\nbreakpoint occurs at 6.0. We’ll use the fit_guess() function to find\nthe best breakpoint location starting with this guess.</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">4.</span><span class=\"p\">,</span> <span class=\"mf\">5.</span><span class=\"p\">,</span> <span class=\"mf\">6.</span><span class=\"p\">,</span> <span class=\"mf\">7.</span><span class=\"p\">,</span> <span class=\"mf\">8.</span><span class=\"p\">])</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">([</span><span class=\"mf\">11.</span><span class=\"p\">,</span> <span class=\"mf\">13.</span><span class=\"p\">,</span> <span class=\"mf\">16.</span><span class=\"p\">,</span> <span class=\"mf\">28.92</span><span class=\"p\">,</span> <span class=\"mf\">42.81</span><span class=\"p\">])</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_guess</span><span class=\"p\">([</span><span class=\"mf\">6.0</span><span class=\"p\">])</span>\n</pre></div>\n</div>\n<p>Note specifying one breakpoint will result in two line segments.\nIf we wanted three line segments, we’ll have to specify two\nbreakpoints.</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_guess</span><span class=\"p\">([</span><span class=\"mf\">5.5</span><span class=\"p\">,</span> <span class=\"mf\">6.0</span><span class=\"p\">])</span>\n</pre></div>\n</div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.fit_with_breaks\">\n<span class=\"sig-name descname\"><span class=\"pre\">fit_with_breaks</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">breaks</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.fit_with_breaks\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>A function which fits a continuous piecewise linear function\nfor specified breakpoint locations.</p>\n<p>The function minimizes the sum of the square of the residuals for the\nx y data.</p>\n<p>If you want to understand the math behind this read\n<a class=\"reference external\" href=\"https://jekel.me/2018/Continous-piecewise-linear-regression/\">https://jekel.me/2018/Continous-piecewise-linear-regression/</a></p>\n<p>Other useful resources:\n<a class=\"reference external\" href=\"http://golovchenko.org/docs/ContinuousPiecewiseLinearFit.pdf\">http://golovchenko.org/docs/ContinuousPiecewiseLinearFit.pdf</a>\n<a class=\"reference external\" href=\"https://www.mathworks.com/matlabcentral/fileexchange/40913-piecewise-linear-least-square-fittic\">https://www.mathworks.com/matlabcentral/fileexchange/40913-piecewise-linear-least-square-fittic</a>\n<a class=\"reference external\" href=\"http://www.regressionist.com/2018/02/07/continuous-piecewise-linear-fitting/\">http://www.regressionist.com/2018/02/07/continuous-piecewise-linear-fitting/</a></p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>breaks</strong><span class=\"classifier\">array_like</span></dt><dd><p>The x locations where each line segment terminates. These are\nreferred to as breakpoints for each line segment. This should be\nstructured as a 1-D numpy array.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>ssr</strong><span class=\"classifier\">float</span></dt><dd><p>Returns the sum of squares of the residuals.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-odd\">Raises<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt>LinAlgError</dt><dd><p>This typically means your regression problem is ill-conditioned.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Examples</p>\n<p>If your x data exists from 0 &lt;= x &lt;= 1 and you want three\npiecewise linear lines where the lines terminate at x = 0.0, 0.3, 0.6,\nand 1.0. This assumes that x is linearly spaced from [0, 1), and y is\nrandom.</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">0.3</span><span class=\"p\">,</span> <span class=\"mf\">0.6</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">ssr</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_with_breaks</span><span class=\"p\">(</span><span class=\"n\">breaks</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.fit_with_breaks_force_points\">\n<span class=\"sig-name descname\"><span class=\"pre\">fit_with_breaks_force_points</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">breaks</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">x_c</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">y_c</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.fit_with_breaks_force_points\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>A function which fits a continuous piecewise linear function\nfor specified breakpoint locations, where you force the\nfit to go through the data points at x_c and y_c.</p>\n<p>The function minimizes the sum of the square of the residuals for the\npair of x, y data points. If you want to understand the math behind\nthis read <a class=\"reference external\" href=\"https://jekel.me/2018/Force-piecwise-linear-fit-through-data/\">https://jekel.me/2018/Force-piecwise-linear-fit-through-data/</a></p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>breaks</strong><span class=\"classifier\">array_like</span></dt><dd><p>The x locations where each line segment terminates. These are\nreferred to as breakpoints for each line segment. This should be\nstructured as a 1-D numpy array.</p>\n</dd>\n<dt><strong>x_c</strong><span class=\"classifier\">array_like</span></dt><dd><p>The x locations of the data points that the piecewise linear\nfunction will be forced to go through.</p>\n</dd>\n<dt><strong>y_c</strong><span class=\"classifier\">array_like</span></dt><dd><p>The x locations of the data points that the piecewise linear\nfunction will be forced to go through.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>L</strong><span class=\"classifier\">float</span></dt><dd><p>Returns the Lagrangian function value. This is the sum of squares\nof the residuals plus the constraint penalty.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-odd\">Raises<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt>LinAlgError</dt><dd><p>This typically means your regression problem is ill-conditioned.</p>\n</dd>\n<dt>ValueError</dt><dd><p>You can’t specify weights with x_c and y_c.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Examples</p>\n<p>If your x data exists from 0 &lt;= x &lt;= 1 and you want three\npiecewise linear lines where the lines terminate at x = 0.0, 0.3, 0.6,\nand 1.0. This assumes that x is linearly spaced from [0, 1), and y is\nrandom. Additionally you desired that the piecewise linear function go\nthrough the point (0.0, 0.0)</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x_c</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">0.0</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y_c</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">0.0</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">0.3</span><span class=\"p\">,</span> <span class=\"mf\">0.6</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">L</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_with_breaks_force_points</span><span class=\"p\">(</span><span class=\"n\">breaks</span><span class=\"p\">,</span> <span class=\"n\">x_c</span><span class=\"p\">,</span> <span class=\"n\">y_c</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.fit_with_breaks_opt\">\n<span class=\"sig-name descname\"><span class=\"pre\">fit_with_breaks_opt</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">var</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.fit_with_breaks_opt\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>The objective function to perform a continuous piecewise linear\nfit for a specified number of breakpoints. This is to be used\nwith a custom optimization routine, and after use_custom_opt has\nbeen called.</p>\n<p>This was intended for advanced users only.</p>\n<p>See the following example\n<a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/useCustomOptimizationRoutine.py\">https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/useCustomOptimizationRoutine.py</a></p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>var</strong><span class=\"classifier\">array_like</span></dt><dd><p>The breakpoint locations, or variable, in a custom\noptimization routine.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>ssr</strong><span class=\"classifier\">float</span></dt><dd><p>The sum of square of the residuals.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-odd\">Raises<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt>LinAlgError</dt><dd><p>This typically means your regression problem is ill-conditioned.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Notes</p>\n<p>You should run use_custom_opt to initialize necessary object\nattributes first.</p>\n<p>Unlike fit_with_breaks, fit_with_breaks_opt automatically\nassumes that the first and last breakpoints occur at the min and max\nvalues of x.</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.fitfast\">\n<span class=\"sig-name descname\"><span class=\"pre\">fitfast</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">n_segments</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">pop</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">2</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">bounds</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"o\"><span class=\"pre\">**</span></span><span class=\"n\"><span class=\"pre\">kwargs</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.fitfast\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Uses multi start LBFGSB optimization to find the location of\nbreakpoints for a given number of line segments by minimizing the sum\nof the square of the errors.</p>\n<p>The idea is that we generate n random latin hypercube samples\nand run LBFGSB optimization on each one. This isn’t guaranteed to\nfind the global optimum. It’s suppose to be a reasonable compromise\nbetween speed and quality of fit. Let me know how it works.</p>\n<p>Since this is based on random sampling, you might want to run it\nmultiple times and save the best version… The best version will\nhave the lowest self.ssr (sum of square of residuals).</p>\n<p>There is no guarantee that this will be faster than fit(), however\nyou may find it much faster sometimes.</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>n_segments</strong><span class=\"classifier\">int</span></dt><dd><p>The desired number of line segments.</p>\n</dd>\n<dt><strong>pop</strong><span class=\"classifier\">int, optional</span></dt><dd><p>The number of latin hypercube samples to generate. Default pop=2.</p>\n</dd>\n<dt><strong>bounds</strong><span class=\"classifier\">array_like, optional</span></dt><dd><p>Bounds for each breakpoint location within the optimization. This\nshould have the shape of (n_segments, 2).</p>\n</dd>\n<dt><strong>**kwargs</strong><span class=\"classifier\">optional</span></dt><dd><p>Directly passed into scipy.optimize.fmin_l_bfgs_b(). This\nwill override any pwlf defaults when provided. See Note for more\ninformation.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>fit_breaks</strong><span class=\"classifier\">float</span></dt><dd><p>breakpoint locations stored as a 1-D numpy array.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Notes</p>\n<dl class=\"simple\">\n<dt>The default number of multi start optimizations is 2.</dt><dd><ul class=\"simple\">\n<li><p>Decreasing this number will result in a faster run time.</p></li>\n<li><dl class=\"simple\">\n<dt>Increasing this number will improve the likelihood of finding</dt><dd><p>good results</p>\n</dd>\n</dl>\n</li>\n<li><p>You can specify the number of starts using the following call</p></li>\n<li><p>Minimum value of pop is 2</p></li>\n</ul>\n</dd>\n</dl>\n<p>All <a href=\"#id9\"><span class=\"problematic\" id=\"id10\">**</span></a>kwargs are passed into sicpy.optimize.fmin_l_bfgs_b. If any\n<a href=\"#id11\"><span class=\"problematic\" id=\"id12\">**</span></a>kwargs is used, it will override my defaults. This allows\nadvanced users to tweak their own optimization. For me information see:\n<a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py/issues/15#issuecomment-434717232\">https://github.com/cjekel/piecewise_linear_fit_py/issues/15#issuecomment-434717232</a></p>\n<p class=\"rubric\">Examples</p>\n<p>This example shows you how to fit three continuous piecewise lines to\na dataset. This assumes that x is linearly spaced from [0, 1), and y is\nrandom.</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fitfast</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n<p>You can change the number of latin hypercube samples (or starting\npoint, locations) to use with pop. The following example will use 50\nsamples.</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fitfast</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"n\">pop</span><span class=\"o\">=</span><span class=\"mi\">50</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.lstsq\">\n<span class=\"sig-name descname\"><span class=\"pre\">lstsq</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">A</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">calc_slopes</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">True</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.lstsq\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Perform the least squares fit for A matrix.</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>A</strong><span class=\"classifier\">ndarray (2-D)</span></dt><dd><p>The regression matrix you want to fit in the linear system of\nequations Ab=y.</p>\n</dd>\n<dt><strong>calc_slopes</strong><span class=\"classifier\">boolean, optional</span></dt><dd><p>Whether to calculate slopes after performing a fit. Default is\ncalc_slopes=True.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.p_values\">\n<span class=\"sig-name descname\"><span class=\"pre\">p_values</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">method</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'linear'</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">step_size</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">0.0001</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.p_values\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Calculate the p-values for each beta parameter.</p>\n<p>This calculates the p-values for the beta parameters under the\nassumption that your breakpoint locations are known. Section 2.4.2 of\n<a class=\"reference internal\" href=\"#r665247553e58-2\" id=\"id13\">[2]</a> defines how to calculate the p-value of individual parameters.\nThis is really a marginal test since each parameter is dependent upon\nthe other parameters.</p>\n<p>These values are typically compared to some confidence level alpha for\nsignificance. A 95% confidence level would have alpha = 0.05.</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>method</strong><span class=\"classifier\">string, optional</span></dt><dd><p>Calculate the standard errors for a linear or non-linear\nregression problem. The default is method=’linear’. A taylor-\nseries expansion is performed when method=’non-linear’ (which is\ncommonly referred to as the Delta method).</p>\n</dd>\n<dt><strong>step_size</strong><span class=\"classifier\">float, optional</span></dt><dd><p>The step size to perform forward differences for the taylor-\nseries expansion when method=’non-linear’. Default is\nstep_size=1e-4.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>p</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>p-values for each beta parameter where p-value[0] corresponds to\nbeta[0] and so forth</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-odd\">Raises<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt>AttributeError</dt><dd><p>You have probably not performed a fit yet.</p>\n</dd>\n<dt>ValueError</dt><dd><p>You supplied an unsupported method.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Notes</p>\n<p>The linear regression problem is when you know the breakpoint\nlocations (e.g. when using the fit_with_breaks function).</p>\n<p>The non-linear regression problem is when you don’t know the\nbreakpoint locations (e.g. when using the fit, fitfast, and fit_guess\nfunctions).</p>\n<p>See <a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py/issues/14\">https://github.com/cjekel/piecewise_linear_fit_py/issues/14</a></p>\n<p class=\"rubric\">References</p>\n<div role=\"list\" class=\"citation-list\">\n<div class=\"citation\" id=\"r665247553e58-2\" role=\"doc-biblioentry\">\n<span class=\"label\"><span class=\"fn-bracket\">[</span><a role=\"doc-backlink\" href=\"#id13\">2</a><span class=\"fn-bracket\">]</span></span>\n<p>Myers RH, Montgomery DC, Anderson-Cook CM. Response surface\nmethodology . Hoboken. New Jersey: John Wiley &amp; Sons, Inc.\n2009;20:38-44.</p>\n</div>\n</div>\n<p class=\"rubric\">Examples</p>\n<p>After performing a fit, one can calculate the p-value for each beta\nparameter</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fitfast</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x_new</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">p</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">p_values</span><span class=\"p\">(</span><span class=\"n\">x_new</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n<p>see also examples/standard_errrors_and_p-values.py</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.predict\">\n<span class=\"sig-name descname\"><span class=\"pre\">predict</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">x</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">beta</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">breaks</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.predict\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Evaluate the fitted continuous piecewise linear function at untested\npoints.</p>\n<p>You can manfully specify the breakpoints and calculated\nvalues for beta if you want to quickly predict from different models\nand the same data set.</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>x</strong><span class=\"classifier\">array_like</span></dt><dd><p>The x locations where you want to predict the output of the fitted\ncontinuous piecewise linear function.</p>\n</dd>\n<dt><strong>beta</strong><span class=\"classifier\">none or ndarray (1-D), optional</span></dt><dd><p>The model parameters for the continuous piecewise linear fit.\nDefault is None.</p>\n</dd>\n<dt><strong>breaks</strong><span class=\"classifier\">none or array_like, optional</span></dt><dd><p>The x locations where each line segment terminates. These are\nreferred to as breakpoints for each line segment. This should be\nstructured as a 1-D numpy array. Default is None.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>y_hat</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>The predicted values at x.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Examples</p>\n<p>Fits a simple model, then predict at x_new locations which are\nlinearly spaced.</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">0.3</span><span class=\"p\">,</span> <span class=\"mf\">0.6</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">]</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">ssr</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fit_with_breaks</span><span class=\"p\">(</span><span class=\"n\">breaks</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x_new</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">yhat</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">predict</span><span class=\"p\">(</span><span class=\"n\">x_new</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.prediction_variance\">\n<span class=\"sig-name descname\"><span class=\"pre\">prediction_variance</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">x</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.prediction_variance\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Calculate the prediction variance for each specified x location. The\nprediction variance is the uncertainty of the model due to the lack of\ndata. This can be used to find a 95% confidence interval of possible\npiecewise linear models based on the current data. This would be\ndone typically as y_hat +- 1.96*np.sqrt(pre_var). The\nprediction_variance needs to be calculated at various x locations.\nFor more information see:\nwww2.mae.ufl.edu/haftka/vvuq/lectures/Regression-accuracy.pptx</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>x</strong><span class=\"classifier\">array_like</span></dt><dd><p>The x locations where you want the prediction variance from the\nfitted continuous piecewise linear function.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>pre_var</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>Numpy array (floats) of prediction variance at each x location.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-odd\">Raises<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt>AttributeError</dt><dd><p>You have probably not performed a fit yet.</p>\n</dd>\n<dt>LinAlgError</dt><dd><p>This typically means your regression problem is ill-conditioned.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Notes</p>\n<p>This assumes that your breakpoint locations are exact! and does\nnot consider the uncertainty with your breakpoint locations.</p>\n<p class=\"rubric\">Examples</p>\n<p>Calculate the prediction variance at x_new after performing a simple\nfit.</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fitfast</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x_new</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">100</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">pre_var</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">prediction_variance</span><span class=\"p\">(</span><span class=\"n\">x_new</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n<p>see also examples/prediction_variance.py</p>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.r_squared\">\n<span class=\"sig-name descname\"><span class=\"pre\">r_squared</span></span><span class=\"sig-paren\">(</span><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.r_squared\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Calculate the coefficient of determination (“R squared”, R^2) value\nafter a fit has been performed.\nFor more information see:\n<a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Coefficient_of_determination\">https://en.wikipedia.org/wiki/Coefficient_of_determination</a></p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>rsq</strong><span class=\"classifier\">float</span></dt><dd><p>Coefficient of determination, or ‘R squared’ value.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Raises<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt>AttributeError</dt><dd><p>You have probably not performed a fit yet.</p>\n</dd>\n<dt>LinAlgError</dt><dd><p>This typically means your regression problem is ill-conditioned.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Examples</p>\n<p>Calculate the R squared value after performing a simple fit.</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fitfast</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">rsq</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">r_squared</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.standard_errors\">\n<span class=\"sig-name descname\"><span class=\"pre\">standard_errors</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">method</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'linear'</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">step_size</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">0.0001</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.standard_errors\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Calculate the standard errors for each beta parameter determined\nfrom the piecewise linear fit. Typically +- 1.96*se will yield the\ncenter of a 95% confidence region around your parameters. This\nassumes the parmaters follow a normal distribution. For more\ninformation see:\n<a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Standard_error\">https://en.wikipedia.org/wiki/Standard_error</a></p>\n<p>This calculation follows the derivation provided in <a class=\"reference internal\" href=\"#rb5b41547ab31-1\" id=\"id15\">[1]</a>.</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>method</strong><span class=\"classifier\">string, optional</span></dt><dd><p>Calculate the standard errors for a linear or non-linear\nregression problem. The default is method=’linear’. A taylor-\nseries expansion is performed when method=’non-linear’ (which is\ncommonly referred to as the Delta method).</p>\n</dd>\n<dt><strong>step_size</strong><span class=\"classifier\">float, optional</span></dt><dd><p>The step size to perform forward differences for the taylor-\nseries expansion when method=’non-linear’. Default is\nstep_size=1e-4.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Returns<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>se</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>Standard errors associated with each beta parameter. Specifically\nse[0] correspounds to the standard error for beta[0], and so forth.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-odd\">Raises<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt>AttributeError</dt><dd><p>You have probably not performed a fit yet.</p>\n</dd>\n<dt>ValueError</dt><dd><p>You supplied an unsupported method.</p>\n</dd>\n<dt>LinAlgError</dt><dd><p>This typically means your regression problem is ill-conditioned.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Notes</p>\n<p>The linear regression problem is when you know the breakpoint\nlocations (e.g. when using the fit_with_breaks function).</p>\n<p>The non-linear regression problem is when you don’t know the\nbreakpoint locations (e.g. when using the fit, fitfast, and fit_guess\nfunctions).</p>\n<p class=\"rubric\">References</p>\n<div role=\"list\" class=\"citation-list\">\n<div class=\"citation\" id=\"rb5b41547ab31-1\" role=\"doc-biblioentry\">\n<span class=\"label\"><span class=\"fn-bracket\">[</span><a role=\"doc-backlink\" href=\"#id15\">1</a><span class=\"fn-bracket\">]</span></span>\n<p>Coppe, A., Haftka, R. T., and Kim, N. H., “Uncertainty\nIdentification of Damage Growth Parameters Using Nonlinear\nRegression,” AIAA Journal, Vol. 49, No. 12, dec 2011, pp.\n2818–2821.</p>\n</div>\n</div>\n<p class=\"rubric\">Examples</p>\n<p>Calculate the standard errors after performing a simple fit.</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">linspace</span><span class=\"p\">(</span><span class=\"mf\">0.0</span><span class=\"p\">,</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">breaks</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">fitfast</span><span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">se</span> <span class=\"o\">=</span> <span class=\"n\">my_pwlf</span><span class=\"o\">.</span><span class=\"n\">standard_errors</span><span class=\"p\">()</span>\n</pre></div>\n</div>\n</dd></dl>\n\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.use_custom_opt\">\n<span class=\"sig-name descname\"><span class=\"pre\">use_custom_opt</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">n_segments</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">x_c</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">y_c</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.use_custom_opt\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>Provide the number of line segments you want to use with your\ncustom optimization routine.</p>\n<p>Run this function first to initialize necessary attributes!!!</p>\n<p>This was intended for advanced users only.</p>\n<p>See the following example\n<a class=\"reference external\" href=\"https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/useCustomOptimizationRoutine.py\">https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/useCustomOptimizationRoutine.py</a></p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>n_segments</strong><span class=\"classifier\">int</span></dt><dd><p>The x locations where each line segment terminates. These are\nreferred to as breakpoints for each line segment. This should be\nstructured as a 1-D numpy array.</p>\n</dd>\n<dt><strong>x_c</strong><span class=\"classifier\">none or array_like, optional</span></dt><dd><p>The x locations of the data points that the piecewise linear\nfunction will be forced to go through.</p>\n</dd>\n<dt><strong>y_c</strong><span class=\"classifier\">none or array_like, optional</span></dt><dd><p>The x locations of the data points that the piecewise linear\nfunction will be forced to go through.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Raises<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt>ValueError</dt><dd><p>You can’t specify weights with x_c and y_c.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Notes</p>\n<p>Optimize fit_with_breaks_opt(var) where var is a 1D array\ncontaining the x locations of your variables\nvar has length n_segments - 1, because the two breakpoints\nare always defined (1. the min of x, 2. the max of x).</p>\n<p>fit_with_breaks_opt(var) will return the sum of the square of the\nresiduals which you’ll want to minimize with your optimization\nroutine.</p>\n</dd></dl>\n\n</dd></dl>\n\n</section>\n\n\n          </div>\n          \n        </div>\n      </div>\n      <div class=\"sphinxsidebar\" role=\"navigation\" aria-label=\"Main\">\n        <div class=\"sphinxsidebarwrapper\">\n<h1 class=\"logo\"><a href=\"index.html\">pwlf</a></h1>\n\n\n\n\n\n\n\n\n\n<search id=\"searchbox\" style=\"display: none\" role=\"search\">\n    <div class=\"searchformwrapper\">\n    <form class=\"search\" action=\"search.html\" method=\"get\">\n      <input type=\"text\" name=\"q\" aria-labelledby=\"searchlabel\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" placeholder=\"Search\"/>\n      <input type=\"submit\" value=\"Go\" />\n    </form>\n    </div>\n</search>\n<script>document.getElementById('searchbox').style.display = \"block\"</script><h3>Navigation</h3>\n<ul class=\"current\">\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"installation.html\">Installation</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"how_it_works.html\">How it works</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"examples.html\">Examples</a></li>\n<li class=\"toctree-l1 current\"><a class=\"current reference internal\" href=\"#\">pwlf package contents</a><ul>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"stubs/pwlf.PiecewiseLinFit.html\">pwlf.PiecewiseLinFit</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit</span></code></a></li>\n</ul>\n</li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"about.html\">About</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"requirements.html\">Requirements</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"license.html\">License</a></li>\n</ul>\n\n<div class=\"relations\">\n<h3>Related Topics</h3>\n<ul>\n  <li><a href=\"index.html\">Documentation overview</a><ul>\n      <li>Previous: <a href=\"examples.html\" title=\"previous chapter\">Examples</a></li>\n      <li>Next: <a href=\"stubs/pwlf.PiecewiseLinFit.html\" title=\"next chapter\">pwlf.PiecewiseLinFit</a></li>\n  </ul></li>\n</ul>\n</div>\n\n\n\n\n\n\n\n\n        </div>\n      </div>\n      <div class=\"clearer\"></div>\n    </div>\n    <div class=\"footer\">\n      &#169;2024, Charles Jekel.\n      \n      |\n      Powered by <a href=\"https://www.sphinx-doc.org/\">Sphinx 8.1.3</a>\n      &amp; <a href=\"https://alabaster.readthedocs.io\">Alabaster 1.0.0</a>\n      \n      |\n      <a href=\"_sources/pwlf.rst.txt\"\n          rel=\"nofollow\">Page source</a>\n    </div>\n\n    \n\n    \n    <script>\n\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'G-QKPGZSZ8CD']);\n      _gaq.push(['_setDomainName', 'none']);\n      _gaq.push(['_setAllowLinker', true]);\n      _gaq.push(['_trackPageview']);\n\n      (function() {\n        var ga = document.createElement('script'); ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n\n    </script>\n    \n  </body>\n</html>"
  },
  {
    "path": "docs/requirements.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\" data-content_root=\"./\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>Requirements &#8212; pwlf 2.5.2 documentation</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/pygments.css?v=d1102ebc\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/basic.css?v=686e5160\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/alabaster.css?v=27fed22d\" />\n    <script src=\"_static/documentation_options.js?v=afc61bbc\"></script>\n    <script src=\"_static/doctools.js?v=9bcbadda\"></script>\n    <script src=\"_static/sphinx_highlight.js?v=dc90522c\"></script>\n    <link rel=\"icon\" href=\"_static/favicon.ico\"/>\n    <link rel=\"author\" title=\"About these documents\" href=\"about.html\" />\n    <link rel=\"index\" title=\"Index\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"Search\" href=\"search.html\" />\n    <link rel=\"next\" title=\"License\" href=\"license.html\" />\n    <link rel=\"prev\" title=\"About\" href=\"about.html\" />\n   \n  <link rel=\"stylesheet\" href=\"_static/custom.css\" type=\"text/css\" />\n  \n\n  \n  \n\n  </head><body>\n  \n\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n        <div class=\"bodywrapper\">\n          \n\n          <div class=\"body\" role=\"main\">\n            \n  <section id=\"requirements\">\n<h1>Requirements<a class=\"headerlink\" href=\"#requirements\" title=\"Link to this heading\">¶</a></h1>\n<p><a class=\"reference external\" href=\"https://pypi.org/project/numpy/\">NumPy</a> (&gt;= 1.14.0)</p>\n<p><a class=\"reference external\" href=\"https://pypi.org/project/scipy/\">SciPy</a> (&gt;= 1.2.0)</p>\n<p><a class=\"reference external\" href=\"https://pypi.org/project/pyDOE/\">pyDOE</a> ( &gt;= 0.3.8)</p>\n</section>\n\n\n          </div>\n          \n        </div>\n      </div>\n      <div class=\"sphinxsidebar\" role=\"navigation\" aria-label=\"Main\">\n        <div class=\"sphinxsidebarwrapper\">\n<h1 class=\"logo\"><a href=\"index.html\">pwlf</a></h1>\n\n\n\n\n\n\n\n\n\n<search id=\"searchbox\" style=\"display: none\" role=\"search\">\n    <div class=\"searchformwrapper\">\n    <form class=\"search\" action=\"search.html\" method=\"get\">\n      <input type=\"text\" name=\"q\" aria-labelledby=\"searchlabel\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" placeholder=\"Search\"/>\n      <input type=\"submit\" value=\"Go\" />\n    </form>\n    </div>\n</search>\n<script>document.getElementById('searchbox').style.display = \"block\"</script><h3>Navigation</h3>\n<ul class=\"current\">\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"installation.html\">Installation</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"how_it_works.html\">How it works</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"examples.html\">Examples</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"pwlf.html\">pwlf package contents</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"about.html\">About</a></li>\n<li class=\"toctree-l1 current\"><a class=\"current reference internal\" href=\"#\">Requirements</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"license.html\">License</a></li>\n</ul>\n\n<div class=\"relations\">\n<h3>Related Topics</h3>\n<ul>\n  <li><a href=\"index.html\">Documentation overview</a><ul>\n      <li>Previous: <a href=\"about.html\" title=\"previous chapter\">About</a></li>\n      <li>Next: <a href=\"license.html\" title=\"next chapter\">License</a></li>\n  </ul></li>\n</ul>\n</div>\n\n\n\n\n\n\n\n\n        </div>\n      </div>\n      <div class=\"clearer\"></div>\n    </div>\n    <div class=\"footer\">\n      &#169;2024, Charles Jekel.\n      \n      |\n      Powered by <a href=\"https://www.sphinx-doc.org/\">Sphinx 8.1.3</a>\n      &amp; <a href=\"https://alabaster.readthedocs.io\">Alabaster 1.0.0</a>\n      \n      |\n      <a href=\"_sources/requirements.rst.txt\"\n          rel=\"nofollow\">Page source</a>\n    </div>\n\n    \n\n    \n    <script>\n\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'G-QKPGZSZ8CD']);\n      _gaq.push(['_setDomainName', 'none']);\n      _gaq.push(['_setAllowLinker', true]);\n      _gaq.push(['_trackPageview']);\n\n      (function() {\n        var ga = document.createElement('script'); ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n\n    </script>\n    \n  </body>\n</html>"
  },
  {
    "path": "docs/search.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\" data-content_root=\"./\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Search &#8212; pwlf 2.5.2 documentation</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/pygments.css?v=d1102ebc\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/basic.css?v=686e5160\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"_static/alabaster.css?v=27fed22d\" />\n    \n    <script src=\"_static/documentation_options.js?v=afc61bbc\"></script>\n    <script src=\"_static/doctools.js?v=9bcbadda\"></script>\n    <script src=\"_static/sphinx_highlight.js?v=dc90522c\"></script>\n    <script src=\"_static/searchtools.js\"></script>\n    <script src=\"_static/language_data.js\"></script>\n    <link rel=\"icon\" href=\"_static/favicon.ico\"/>\n    <link rel=\"author\" title=\"About these documents\" href=\"about.html\" />\n    <link rel=\"index\" title=\"Index\" href=\"genindex.html\" />\n    <link rel=\"search\" title=\"Search\" href=\"#\" />\n    <script src=\"searchindex.js\" defer=\"defer\"></script>\n    <meta name=\"robots\" content=\"noindex\" />\n    \n   \n  <link rel=\"stylesheet\" href=\"_static/custom.css\" type=\"text/css\" />\n  \n\n  \n  \n\n\n  </head><body>\n  \n\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n        <div class=\"bodywrapper\">\n          \n\n          <div class=\"body\" role=\"main\">\n            \n  <h1 id=\"search-documentation\">Search</h1>\n  \n  <noscript>\n  <div class=\"admonition warning\">\n  <p>\n    Please activate JavaScript to enable the search\n    functionality.\n  </p>\n  </div>\n  </noscript>\n  \n  \n  <p>\n    Searching for multiple words only shows matches that contain\n    all words.\n  </p>\n  \n  \n  <form action=\"\" method=\"get\">\n    <input type=\"text\" name=\"q\" aria-labelledby=\"search-documentation\" value=\"\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\"/>\n    <input type=\"submit\" value=\"search\" />\n    <span id=\"search-progress\" style=\"padding-left: 10px\"></span>\n  </form>\n  \n  \n  <div id=\"search-results\"></div>\n  \n\n          </div>\n          \n        </div>\n      </div>\n      <div class=\"sphinxsidebar\" role=\"navigation\" aria-label=\"Main\">\n        <div class=\"sphinxsidebarwrapper\">\n<h1 class=\"logo\"><a href=\"index.html\">pwlf</a></h1>\n\n\n\n\n\n\n\n\n<h3>Navigation</h3>\n<ul>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"installation.html\">Installation</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"how_it_works.html\">How it works</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"examples.html\">Examples</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"pwlf.html\">pwlf package contents</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"about.html\">About</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"requirements.html\">Requirements</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"license.html\">License</a></li>\n</ul>\n\n<div class=\"relations\">\n<h3>Related Topics</h3>\n<ul>\n  <li><a href=\"index.html\">Documentation overview</a><ul>\n  </ul></li>\n</ul>\n</div>\n\n\n\n\n\n\n\n\n        </div>\n      </div>\n      <div class=\"clearer\"></div>\n    </div>\n    <div class=\"footer\">\n      &#169;2024, Charles Jekel.\n      \n      |\n      Powered by <a href=\"https://www.sphinx-doc.org/\">Sphinx 8.1.3</a>\n      &amp; <a href=\"https://alabaster.readthedocs.io\">Alabaster 1.0.0</a>\n      \n    </div>\n\n    \n\n    \n    <script>\n\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'G-QKPGZSZ8CD']);\n      _gaq.push(['_setDomainName', 'none']);\n      _gaq.push(['_setAllowLinker', true]);\n      _gaq.push(['_trackPageview']);\n\n      (function() {\n        var ga = document.createElement('script'); ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n\n    </script>\n    \n  </body>\n</html>"
  },
  {
    "path": "docs/searchindex.js",
    "content": "Search.setIndex({\"alltitles\": {\"About\": [[0, null]], \"Conda\": [[4, \"conda\"]], \"Examples\": [[1, null]], \"From source\": [[4, \"from-source\"]], \"How it works\": [[2, null]], \"Indices and tables\": [[3, \"indices-and-tables\"]], \"Installation\": [[4, null]], \"License\": [[5, null]], \"Python Package Index (PyPI)\": [[4, \"python-package-index-pypi\"]], \"Requirements\": [[8, null]], \"bad fits when you have more unknowns than data\": [[1, \"bad-fits-when-you-have-more-unknowns-than-data\"]], \"find the best number of line segments\": [[1, \"find-the-best-number-of-line-segments\"]], \"fit constants or polynomials\": [[1, \"fit-constants-or-polynomials\"]], \"fit for specified number of line segments\": [[1, \"fit-for-specified-number-of-line-segments\"]], \"fit with a breakpoint guess\": [[1, \"fit-with-a-breakpoint-guess\"]], \"fit with known breakpoint locations\": [[1, \"fit-with-known-breakpoint-locations\"]], \"fitfast for specified number of line segments\": [[1, \"fitfast-for-specified-number-of-line-segments\"]], \"force a fit through data points\": [[1, \"force-a-fit-through-data-points\"]], \"get the linear regression matrix\": [[1, \"get-the-linear-regression-matrix\"]], \"model persistence\": [[1, \"model-persistence\"]], \"non-linear standard errors and p-values\": [[1, \"non-linear-standard-errors-and-p-values\"]], \"obtain the equations of fitted pwlf\": [[1, \"obtain-the-equations-of-fitted-pwlf\"]], \"pass differential evolution keywords\": [[1, \"pass-differential-evolution-keywords\"]], \"pwlf\": [[6, null]], \"pwlf package contents\": [[7, null]], \"pwlf.PiecewiseLinFit\": [[9, null]], \"pwlf: piecewise linear fitting\": [[3, null]], \"reproducible results\": [[1, \"reproducible-results\"]], \"specify breakpoint bounds\": [[1, \"specify-breakpoint-bounds\"]], \"use custom optimization routine\": [[1, \"use-custom-optimization-routine\"]], \"use of tensorflow\": [[1, \"use-of-tensorflow\"]], \"weighted least squares fit\": [[1, \"weighted-least-squares-fit\"]]}, \"docnames\": [\"about\", \"examples\", \"how_it_works\", \"index\", \"installation\", \"license\", \"modules\", \"pwlf\", \"requirements\", \"stubs/pwlf.PiecewiseLinFit\"], \"envversion\": {\"sphinx\": 64, \"sphinx.domains.c\": 3, \"sphinx.domains.changeset\": 1, \"sphinx.domains.citation\": 1, \"sphinx.domains.cpp\": 9, \"sphinx.domains.index\": 1, \"sphinx.domains.javascript\": 3, \"sphinx.domains.math\": 2, \"sphinx.domains.python\": 4, \"sphinx.domains.rst\": 2, \"sphinx.domains.std\": 2, \"sphinx.ext.intersphinx\": 1}, \"filenames\": [\"about.rst\", \"examples.rst\", \"how_it_works.rst\", \"index.rst\", \"installation.rst\", \"license.rst\", \"modules.rst\", \"pwlf.rst\", \"requirements.rst\", \"stubs/pwlf.PiecewiseLinFit.rst\"], \"indexentries\": {\"__init__() (pwlf.piecewiselinfit method)\": [[9, \"pwlf.PiecewiseLinFit.__init__\", false]], \"assemble_regression_matrix() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.assemble_regression_matrix\", false]], \"calc_slopes() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.calc_slopes\", false]], \"conlstsq() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.conlstsq\", false]], \"fit() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.fit\", false]], \"fit_force_points_opt() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.fit_force_points_opt\", false]], \"fit_guess() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.fit_guess\", false]], \"fit_with_breaks() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.fit_with_breaks\", false]], \"fit_with_breaks_force_points() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.fit_with_breaks_force_points\", false]], \"fit_with_breaks_opt() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.fit_with_breaks_opt\", false]], \"fitfast() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.fitfast\", false]], \"lstsq() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.lstsq\", false]], \"p_values() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.p_values\", false]], \"piecewiselinfit (class in pwlf)\": [[7, \"pwlf.PiecewiseLinFit\", false], [9, \"pwlf.PiecewiseLinFit\", false]], \"predict() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.predict\", false]], \"prediction_variance() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.prediction_variance\", false]], \"r_squared() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.r_squared\", false]], \"standard_errors() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.standard_errors\", false]], \"use_custom_opt() (pwlf.piecewiselinfit method)\": [[7, \"pwlf.PiecewiseLinFit.use_custom_opt\", false]]}, \"objects\": {\"pwlf\": [[9, 0, 1, \"\", \"PiecewiseLinFit\"]], \"pwlf.PiecewiseLinFit\": [[9, 1, 1, \"\", \"__init__\"], [7, 1, 1, \"\", \"assemble_regression_matrix\"], [7, 1, 1, \"\", \"calc_slopes\"], [7, 1, 1, \"\", \"conlstsq\"], [7, 1, 1, \"\", \"fit\"], [7, 1, 1, \"\", \"fit_force_points_opt\"], [7, 1, 1, \"\", \"fit_guess\"], [7, 1, 1, \"\", \"fit_with_breaks\"], [7, 1, 1, \"\", \"fit_with_breaks_force_points\"], [7, 1, 1, \"\", \"fit_with_breaks_opt\"], [7, 1, 1, \"\", \"fitfast\"], [7, 1, 1, \"\", \"lstsq\"], [7, 1, 1, \"\", \"p_values\"], [7, 1, 1, \"\", \"predict\"], [7, 1, 1, \"\", \"prediction_variance\"], [7, 1, 1, \"\", \"r_squared\"], [7, 1, 1, \"\", \"standard_errors\"], [7, 1, 1, \"\", \"use_custom_opt\"]]}, \"objnames\": {\"0\": [\"py\", \"class\", \"Python class\"], \"1\": [\"py\", \"method\", \"Python method\"]}, \"objtypes\": {\"0\": \"py:class\", \"1\": \"py:method\"}, \"terms\": {\"\": [1, 7], \"0\": [1, 7, 8, 9], \"00\": 1, \"00000000e\": 1, \"0001\": 7, \"00086000e\": 1, \"001\": 1, \"00538634182565454\": 1, \"00926700e\": 1, \"00936330e\": 1, \"01\": 1, \"01254006e\": 1, \"01980300e\": 1, \"02\": [1, 7], \"02039790e\": 1, \"02132890e\": 1, \"02345260e\": 1, \"02580042e\": 1, \"03\": 1, \"03016230425747\": 1, \"03581990e\": 1, \"03872000e\": 1, \"039\": 1, \"046\": 1, \"04787860e\": 1, \"05\": [1, 7], \"06\": 1, \"07\": 7, \"07655920e\": 1, \"07961810e\": 1, \"1\": [1, 7, 8, 9], \"10\": [1, 7], \"100\": [1, 7], \"1000\": 1, \"10000\": 1, \"1000000\": 1, \"11\": [1, 7], \"111181494\": 1, \"11688258e\": 1, \"12\": [1, 7], \"12089850e\": 1, \"12121\": 1, \"123\": 1, \"12600000e\": 1, \"13\": [1, 7], \"14\": [7, 8], \"14750770e\": 1, \"15\": 7, \"15706975e\": 1, \"159\": 1, \"16\": [1, 7], \"162\": 1, \"16270210e\": 1, \"16388310e\": 1, \"165\": 1, \"16531753e\": 1, \"166901856\": 1, \"168954500\": 1, \"16951050e\": 1, \"17305210e\": 1, \"17617000e\": 1, \"1763191476\": 1, \"18\": 1, \"18679400e\": 1, \"19\": 1, \"19011260e\": 1, \"1d\": [0, 7], \"1e\": [1, 7], \"2\": [1, 7, 8, 9], \"20\": 7, \"2004\": 2, \"2009\": 7, \"2011\": 7, \"2017\": 5, \"2018\": 7, \"2019\": 0, \"2020\": 5, \"20351520e\": 1, \"20605073e\": 1, \"21390666e\": 1, \"22\": 1, \"22120350e\": 1, \"22767939e\": 1, \"242\": 1, \"25615100e\": 1, \"26063930e\": 1, \"26413070e\": 1, \"28\": [1, 7], \"2818\": 7, \"2821\": 7, \"28642800e\": 1, \"3\": [1, 7, 8], \"30\": 1, \"30997400e\": 1, \"31196948e\": 1, \"31279040e\": 1, \"31543400e\": 1, \"34180360e\": 1, \"34184100e\": 1, \"34390200e\": 1, \"34620080e\": 1, \"34831790e\": 1, \"3508513333073\": 1, \"36687642e\": 1, \"36931660e\": 1, \"37038283e\": 1, \"37279600e\": 1, \"37442010e\": 1, \"38\": 7, \"38356810e\": 1, \"39052750e\": 1, \"397\": 1, \"39709150e\": 1, \"4\": [1, 7], \"40\": 1, \"40913\": 7, \"41374060e\": 1, \"41725010e\": 1, \"41776550e\": 1, \"41881288e\": 1, \"42\": [1, 7], \"421\": 1, \"42172312e\": 1, \"427\": 1, \"42877590e\": 1, \"434717232\": 7, \"44\": [1, 7], \"44519970e\": 1, \"45343950e\": 1, \"45437090e\": 1, \"46404554\": 1, \"48218236957122\": 1, \"482311769\": 1, \"48629710e\": 1, \"49\": 7, \"493\": 1, \"49429370e\": 1, \"5\": [1, 7], \"50\": [1, 7], \"50144640e\": 1, \"50958760e\": 1, \"5102742956827\": 1, \"51085900e\": 1, \"51858250e\": 1, \"5306546317065\": 1, \"53545600e\": 1, \"537785803\": 1, \"54628780e\": 1, \"54941000e\": 1, \"55253360e\": 1, \"55374770e\": 1, \"55892510e\": 1, \"55907760e\": 1, \"56706510e\": 1, \"5772216545711\": 1, \"58600000e\": 1, \"59\": 1, \"59461900e\": 1, \"59556700e\": 1, \"59627540e\": 1, \"6\": [1, 7], \"61442590e\": 1, \"62618058e\": 1, \"63321350e\": 1, \"63404300e\": 1, \"63539960e\": 1, \"63739040e\": 1, \"64433570e\": 1, \"646\": 1, \"65299640e\": 1, \"65610200e\": 1, \"66106800e\": 1, \"68092100e\": 1, \"69747505830914\": 1, \"69801700e\": 1, \"7\": [1, 7], \"70363280e\": 1, \"720785454735\": 1, \"74104940e\": 1, \"75\": 1, \"76596300e\": 1, \"77756110e\": 1, \"78542550e\": 1, \"79942720e\": 1, \"8\": [1, 7, 8], \"80525800e\": 1, \"81\": [1, 7], \"81388400e\": 1, \"82\": 1, \"821\": 1, \"82125120e\": 1, \"82678000e\": 1, \"84458400e\": 1, \"85494500e\": 1, \"873\": 1, \"88450940e\": 1, \"885\": 1, \"89945177490653\": 1, \"9\": 1, \"91016100e\": 1, \"92\": [1, 7], \"926850298824217\": 1, \"93753841\": 1, \"94350340e\": 1, \"949735350431857\": 1, \"95\": [1, 7], \"951561315686298\": 1, \"953964059782599\": 1, \"95549800e\": 1, \"96\": 7, \"9824424358344\": 1, \"99\": 1, \"A\": [0, 1, 5, 7], \"AND\": 5, \"AS\": 5, \"BE\": 5, \"BUT\": 5, \"FOR\": 5, \"For\": [1, 7, 9], \"IN\": 5, \"If\": [1, 4, 7], \"In\": [1, 7], \"It\": 7, \"NO\": 5, \"NOT\": 5, \"No\": 7, \"OF\": 5, \"OR\": 5, \"One\": 1, \"Or\": 4, \"THE\": 5, \"TO\": 5, \"The\": [1, 5, 7, 9], \"There\": 7, \"These\": [1, 7], \"To\": 1, \"WITH\": 5, \"__future__\": 1, \"__init__\": [6, 9], \"ab\": [1, 7], \"about\": [1, 3], \"abov\": 5, \"absolut\": 1, \"accuraci\": 7, \"action\": 5, \"add\": 1, \"addition\": 7, \"advanc\": 7, \"after\": [7, 9], \"aggress\": 2, \"aiaa\": 7, \"algorithm\": 2, \"all\": [0, 1, 5, 7], \"allow\": [7, 9], \"alpha\": 7, \"also\": [4, 7], \"altern\": [1, 2], \"alwai\": 7, \"an\": [1, 5, 7, 9], \"anderson\": 7, \"ani\": [5, 7], \"appear\": 7, \"append\": 1, \"applic\": 1, \"ar\": [1, 2, 7, 9], \"arang\": 1, \"arbitrarili\": 1, \"argument\": 1, \"aris\": 5, \"around\": [1, 7], \"arrai\": [1, 7, 9], \"array_lik\": [7, 9], \"assembl\": [1, 7], \"assemble_regression_matrix\": [1, 6, 7], \"associ\": [5, 7, 9], \"assum\": [1, 7, 9], \"assumpt\": 7, \"atol\": 1, \"attribut\": [7, 9], \"attributeerror\": 7, \"author\": [0, 5], \"automat\": [1, 7], \"axi\": 1, \"b\": 7, \"backward\": 1, \"bad\": 3, \"base\": [1, 2, 7], \"bayesian\": 1, \"bayesianoptim\": 1, \"becaus\": 7, \"been\": [7, 9], \"behavior\": 9, \"behind\": 7, \"believ\": [1, 7], \"benchmark\": 1, \"best\": [2, 3, 7], \"beta\": [1, 7, 9], \"beta_index\": 1, \"better\": 1, \"between\": [1, 7], \"bfg\": 7, \"blob\": 7, \"blog\": 1, \"bool\": 9, \"boolean\": 7, \"both\": 7, \"bound\": [3, 7], \"break\": [1, 2, 7, 9], \"break_0\": 9, \"break_loc\": 1, \"break_n\": 9, \"breakpoint\": [3, 7, 9], \"c\": [4, 5], \"c_n\": 9, \"calc_slop\": [6, 7, 9], \"calcul\": [1, 7, 9], \"call\": [7, 9], \"can\": [1, 4, 7], \"candid\": 1, \"care\": 1, \"case\": [1, 7], \"center\": 7, \"chang\": [0, 7], \"changelog\": 0, \"charg\": 5, \"charl\": [0, 5], \"check\": 2, \"choleski\": 1, \"choos\": 1, \"cite\": 0, \"cjekel\": [0, 4, 7], \"claim\": 5, \"class\": [1, 7, 9], \"clone\": 4, \"cm\": 7, \"code\": 1, \"coef_\": 1, \"coeffici\": [7, 9], \"coefficient_of_determin\": 7, \"com\": [0, 4, 7], \"commonli\": 7, \"compar\": [1, 7], \"complic\": 1, \"compromis\": 7, \"comput\": 1, \"concaten\": 1, \"conda\": 3, \"condit\": [5, 7], \"confid\": 7, \"conlstsq\": [6, 7], \"connect\": 5, \"consid\": 7, \"constant\": [3, 9], \"constrain\": 7, \"constraint\": [7, 9], \"contain\": 7, \"content\": [3, 6], \"contin\": 7, \"continu\": [0, 1, 7, 9], \"continuouspiecewiselinearfit\": 7, \"contract\": 5, \"control\": 1, \"cook\": 7, \"copi\": [1, 5], \"copp\": 7, \"copyright\": 5, \"correct\": 1, \"correspond\": [1, 7, 9], \"correspound\": [7, 9], \"cpickl\": 1, \"creat\": 1, \"current\": 7, \"custom\": [3, 7, 9], \"cv\": 1, \"d\": [7, 9], \"damag\": [5, 7], \"data\": [0, 3, 7, 9], \"dataset\": 7, \"dc\": 7, \"de\": 1, \"deal\": 5, \"dec\": 7, \"decim\": 1, \"decomposit\": 1, \"decreas\": 7, \"def\": 1, \"default\": [1, 2, 7, 9], \"defin\": [1, 2, 7], \"degre\": [1, 7, 9], \"delta\": [1, 7], \"depend\": [1, 7, 9], \"deriv\": [2, 7], \"desir\": [0, 1, 7], \"detail\": [1, 2], \"determin\": [1, 7, 9], \"deviat\": [1, 9], \"differ\": [1, 7], \"differenti\": [2, 3, 7], \"differential_evolut\": 7, \"dimension\": 9, \"directli\": [1, 7], \"discret\": 1, \"disp_r\": [7, 9], \"distinct\": [1, 7], \"distribut\": [5, 7], \"do\": [1, 5, 7], \"doc\": [7, 9], \"document\": 5, \"doe\": [1, 7], \"domain\": [1, 7], \"don\": [1, 7], \"done\": 7, \"driver\": 9, \"dtype\": 1, \"due\": 7, \"dump\": 1, \"e\": 7, \"each\": [1, 7, 9], \"easi\": 1, \"edu\": 7, \"ego\": 1, \"elast\": 1, \"elasticnetcv\": 1, \"els\": 1, \"en\": 7, \"en_model\": 1, \"end\": 1, \"entir\": [1, 7], \"enumer\": 1, \"eqn_list\": 1, \"equat\": [3, 7], \"equival\": 9, \"error\": [3, 7, 9], \"evalu\": [7, 9], \"event\": 5, \"everi\": 1, \"everytim\": 1, \"evolut\": [2, 3, 7], \"exact\": 7, \"exact_fev\": 1, \"exampl\": [0, 2, 3, 7, 9], \"except\": [1, 9], \"exist\": 7, \"expans\": [1, 7], \"explain\": 2, \"express\": 5, \"extra\": 1, \"f\": [0, 1], \"f_list\": 1, \"fals\": [1, 7, 9], \"fast\": 1, \"faster\": [1, 7, 9], \"favorit\": 1, \"feasibl\": 1, \"feel\": 2, \"figur\": 1, \"file\": 5, \"fileexchang\": 7, \"find\": [2, 3, 7], \"first\": [1, 7, 9], \"fit\": [0, 2, 5, 6, 7, 9], \"fit_break\": [1, 7, 9], \"fit_force_points_opt\": [6, 7, 9], \"fit_guess\": [1, 6, 7], \"fit_intercept\": 1, \"fit_with_break\": [1, 6, 7, 9], \"fit_with_breaks_force_point\": [6, 7, 9], \"fit_with_breaks_opt\": [1, 6, 7, 9], \"fitfast\": [3, 6, 7, 9], \"fittic\": 7, \"flatten\": 1, \"float\": [7, 9], \"float32\": 1, \"float64\": 1, \"fmin_l_bfgs_b\": 7, \"follow\": [1, 5, 7], \"forc\": [3, 7, 9], \"forg\": 4, \"form\": [1, 7], \"formul\": 2, \"forth\": [7, 9], \"forward\": [1, 7], \"found\": 1, \"four\": 1, \"free\": [2, 5], \"from\": [1, 3, 5, 7, 9], \"full\": 7, \"function\": [0, 1, 3, 7, 9], \"furnish\": 5, \"fx_opt\": 1, \"g\": 7, \"gelsd\": [7, 9], \"gelsi\": 9, \"gelss\": 9, \"gener\": [1, 7, 9], \"gerhard\": 0, \"get\": 3, \"get_symbolic_eqn\": 1, \"geuss_breakpoint\": 7, \"git\": 4, \"github\": [0, 4, 7], \"give\": 1, \"given\": [1, 7], \"global\": [1, 2, 7, 9], \"go\": [1, 7, 9], \"goe\": 2, \"golovchenko\": [2, 7], \"good\": [1, 7], \"gp\": 1, \"gpyopt\": 1, \"grab\": 1, \"gradient\": 1, \"grant\": 5, \"growth\": 7, \"guarante\": 7, \"guess\": [3, 7], \"guess_breakpoint\": 7, \"h\": 7, \"ha\": [7, 9], \"haftka\": 7, \"have\": [3, 4, 7], \"header\": 1, \"help\": 0, \"here\": [1, 7], \"herebi\": 5, \"heteroscedast\": 1, \"high\": 1, \"higher\": 1, \"highest_protocol\": 1, \"hoboken\": 7, \"holder\": 5, \"how\": [1, 3, 7], \"howev\": [1, 7], \"html\": 9, \"http\": [0, 4, 7, 9], \"hypercub\": 7, \"i\": [1, 2, 5, 7, 9], \"idea\": [1, 7], \"ident\": 1, \"identif\": 7, \"ie\": 1, \"ill\": 7, \"impli\": 5, \"import\": [1, 7, 9], \"improv\": 7, \"inc\": 7, \"includ\": 5, \"increas\": 7, \"independ\": 9, \"index\": 3, \"individu\": [1, 7, 9], \"inform\": [1, 7], \"init\": [1, 9], \"initi\": [1, 7, 9], \"initial_design_numdata\": 1, \"initial_design_typ\": 1, \"input\": 9, \"instal\": [1, 3], \"int\": [7, 9], \"integ\": 9, \"intend\": 7, \"intercept\": [1, 7, 9], \"interest\": 1, \"interior\": 1, \"interv\": 7, \"isn\": 7, \"issu\": 7, \"issuecom\": 7, \"ith\": [1, 9], \"j\": 1, \"jekel\": [0, 5, 7], \"jersei\": 7, \"joblib\": 1, \"john\": 7, \"journal\": 7, \"jupyt\": 1, \"just\": [0, 1], \"k\": 1, \"keyword\": [2, 3], \"kim\": 7, \"kind\": 5, \"know\": [1, 7], \"known\": [2, 3, 7, 9], \"kwarg\": [7, 9], \"l\": [1, 7], \"l1_ratio\": 1, \"label\": 1, \"lack\": 7, \"lagrangian\": 7, \"lambdifi\": 1, \"lapack\": 9, \"lapack_driv\": [1, 7, 9], \"larg\": 9, \"largest\": 9, \"last\": 7, \"latin\": [1, 7], \"lbfgsb\": 7, \"least\": [2, 3, 7, 9], \"lectur\": 7, \"left\": 9, \"legend\": 1, \"len\": 9, \"length\": 7, \"less\": 1, \"let\": [1, 7], \"level\": 7, \"liabil\": 5, \"liabl\": 5, \"librari\": [0, 2, 9], \"licens\": 3, \"like\": 1, \"likelihood\": 7, \"limit\": 5, \"linalg\": 9, \"linalgerror\": 7, \"line\": [0, 2, 3, 7, 9], \"linear\": [0, 2, 7, 9], \"linear_model\": 1, \"linearli\": 7, \"ling\": [7, 9], \"linspac\": [1, 7], \"list\": [7, 9], \"ll\": [1, 7, 9], \"load\": 1, \"local\": 7, \"locat\": [2, 3, 7, 9], \"low\": 1, \"lower\": [1, 9], \"lowest\": 7, \"lstsq\": [6, 7, 9], \"lug\": 9, \"m\": 4, \"mae\": 7, \"mai\": [1, 7, 9], \"make\": 9, \"manfulli\": 7, \"mani\": 1, \"manual\": [0, 1], \"margin\": 7, \"master\": 7, \"math\": 7, \"mathemat\": 1, \"mathwork\": 7, \"matlabcentr\": 7, \"matplotlib\": 1, \"matrix\": [3, 7], \"max\": [1, 7], \"max_it\": 1, \"md\": 0, \"me\": 7, \"mean\": [1, 7], \"merchant\": 5, \"merg\": 5, \"method\": [1, 7, 9], \"methodologi\": 7, \"middl\": 9, \"might\": 7, \"min\": [1, 7], \"mind\": 1, \"minim\": [1, 7], \"minimum\": 7, \"mit\": 5, \"mix\": 9, \"model\": [3, 7, 9], \"model_typ\": 1, \"modifi\": 5, \"montgomeri\": 7, \"more\": [3, 7, 9], \"most\": 9, \"much\": [1, 7], \"multi\": [1, 7], \"multipl\": [1, 7], \"must\": [1, 2, 7, 9], \"mx\": 7, \"my\": 7, \"my_eqn\": 1, \"my_fit\": 1, \"my_obj\": 1, \"my_pwlf\": [1, 7, 9], \"my_pwlf_0\": 1, \"my_pwlf_1\": 1, \"my_pwlf_2\": 1, \"my_pwlf_en\": 1, \"my_pwlf_gen\": 1, \"my_pwlf_w\": 1, \"mybopt\": 1, \"myer\": 7, \"mypwlf\": 1, \"n\": [1, 7, 9], \"n_data\": [1, 9], \"n_data_set\": 1, \"n_job\": 1, \"n_paramet\": 9, \"n_segment\": [1, 7, 9], \"name\": 1, \"ndarrai\": [7, 9], \"nearli\": 1, \"necessari\": [1, 7, 9], \"need\": [1, 7], \"neg\": 1, \"net\": 1, \"netlib\": 9, \"new\": [7, 9], \"node27\": 9, \"nois\": 1, \"non\": [3, 7], \"none\": [7, 9], \"noninfring\": 5, \"nonlinear\": 7, \"normal\": [1, 7], \"note\": [1, 7, 9], \"notebook\": 1, \"notic\": 5, \"now\": [0, 1, 4], \"np\": [1, 7], \"num\": 1, \"number\": [0, 2, 3, 7, 9], \"number_of_line_seg\": 1, \"numpi\": [1, 7, 8, 9], \"nvar\": 9, \"o\": 1, \"object\": [1, 7, 9], \"object_\": 1, \"obtain\": [3, 5], \"occur\": [1, 7], \"one\": [1, 7, 9], \"onli\": [7, 9], \"open\": 1, \"opt\": 1, \"optim\": [2, 3, 7, 9], \"optimum\": [1, 7], \"option\": [1, 7, 9], \"order\": 1, \"ordinari\": 1, \"org\": [7, 9], \"origin\": 1, \"orthogon\": 1, \"other\": [1, 5, 7], \"otherwis\": 5, \"out\": [1, 2, 5], \"outdat\": 1, \"output\": 7, \"over\": [1, 9], \"overal\": 1, \"overkil\": 2, \"overrid\": 7, \"own\": [2, 7], \"p\": [3, 7], \"p_valu\": [1, 6, 7], \"packag\": [3, 6], \"page\": 3, \"pair\": 7, \"paper\": [1, 2], \"paramet\": [1, 7, 9], \"parmat\": 7, \"particular\": [1, 5], \"pass\": [2, 3, 7], \"pdf\": 7, \"penalti\": [1, 7], \"perform\": [1, 7, 9], \"permiss\": 5, \"permit\": 5, \"persist\": 3, \"person\": 5, \"pi\": 1, \"pick\": [1, 9], \"pickl\": 1, \"piecewis\": [0, 1, 2, 7, 9], \"piecewise_linear_fit_pi\": [0, 4, 7], \"piecewiselinfit\": [1, 3, 6, 7], \"piecewiselinfittf\": 1, \"piecwis\": 7, \"pip\": 4, \"pkl\": 1, \"plan\": 7, \"pleas\": [0, 1], \"plot\": 1, \"plot_acquisit\": 1, \"plot_converg\": 1, \"plt\": 1, \"plu\": 7, \"point\": [2, 3, 7, 9], \"polynomi\": [3, 9], \"pop\": [1, 7, 9], \"portion\": 5, \"posit\": 1, \"possibl\": [1, 7], \"post\": [1, 2], \"pp\": 7, \"pptx\": 7, \"pre_var\": 7, \"predict\": [1, 6, 7, 9], \"prediction_vari\": [6, 7, 9], \"print\": [1, 9], \"print_funct\": 1, \"prior\": 9, \"probabl\": [2, 7], \"problem\": [1, 2, 7, 9], \"program\": 1, \"provid\": [0, 5, 7, 9], \"public\": 0, \"publish\": 5, \"purpos\": 5, \"pwlf\": [0, 4], \"pwlf_\": 1, \"pwlftf\": 1, \"py\": 7, \"pydo\": 8, \"pypi\": 3, \"pyplot\": 1, \"python\": [0, 1, 3], \"quadrat\": 1, \"qualiti\": [7, 9], \"quickli\": 7, \"r\": [7, 9], \"r_squar\": [6, 7, 9], \"rais\": [1, 7], \"random\": [1, 7, 9], \"rang\": 1, \"rb\": 1, \"re\": 1, \"read\": [7, 9], \"realli\": 7, \"reason\": [1, 7], \"reciproc\": [1, 9], \"refer\": [7, 9], \"region\": [1, 7], \"regress\": [2, 3, 7], \"regressionist\": 7, \"regular\": 1, \"reli\": 9, \"repo\": 4, \"repres\": 1, \"reproduc\": [3, 9], \"requir\": [1, 3], \"res0\": 1, \"res1\": 1, \"res2\": 1, \"research\": 0, \"residu\": [1, 7], \"resourc\": 7, \"respons\": 7, \"restrict\": 5, \"result\": [3, 7, 9], \"return\": [1, 7], \"rh\": 7, \"right\": [5, 9], \"routin\": [3, 7, 9], \"row\": 1, \"rsq\": 7, \"run\": [1, 7], \"run_optim\": 1, \"same\": [1, 7, 9], \"sampl\": 7, \"save\": [1, 7], \"scipi\": [1, 2, 7, 8, 9], \"se\": [1, 7, 9], \"search\": [1, 3, 7], \"second\": 1, \"section\": 7, \"see\": [1, 2, 7, 9], \"seed\": [1, 7, 9], \"segment\": [0, 2, 3, 7, 9], \"segment_numb\": 1, \"select\": 1, \"self\": 7, \"sell\": 5, \"sep\": 1, \"seri\": [1, 7], \"set\": [1, 7, 9], \"shall\": 5, \"shape\": [1, 7], \"should\": [1, 7, 9], \"show\": [1, 7], \"sicpi\": 7, \"sigma_chang\": 1, \"signific\": 7, \"simpl\": 7, \"simplifi\": 1, \"sin\": 1, \"sinc\": 7, \"sine\": 1, \"size\": [1, 7], \"sklearn\": 1, \"slope\": [1, 7, 9], \"small\": 1, \"smallest\": 9, \"so\": [1, 2, 5, 7, 9], \"softwar\": 5, \"solv\": 9, \"some\": [1, 7], \"someth\": 1, \"sometim\": [1, 7], \"son\": 7, \"sourc\": 3, \"space\": [1, 7], \"special\": 9, \"specif\": [1, 2, 7, 9], \"specifi\": [0, 2, 3, 7, 9], \"speed\": 7, \"sqrt\": 7, \"squar\": [2, 3, 7, 9], \"ssr\": [1, 7, 9], \"standard\": [3, 7, 9], \"standard_error\": [6, 7, 9], \"standard_errrors_and_p\": 7, \"start\": [1, 7], \"std\": 1, \"step\": 7, \"step_siz\": [1, 7], \"stochast\": [1, 9], \"store\": [0, 7, 9], \"str\": 9, \"string\": 7, \"structur\": 7, \"subject\": 5, \"sublicens\": 5, \"substanti\": 5, \"sum\": [1, 7, 9], \"suppli\": [7, 9], \"support\": 9, \"suppos\": 7, \"surfac\": 7, \"switch\": 1, \"symbol\": 1, \"sympi\": 1, \"system\": 7, \"t\": [1, 7, 9], \"tabl\": 1, \"taylor\": [1, 7], \"templat\": 1, \"tensorflow\": 3, \"termin\": [1, 7], \"test\": 7, \"tf\": 1, \"than\": [3, 7, 9], \"thi\": [1, 2, 5, 7, 9], \"third\": 1, \"three\": [1, 7], \"through\": [2, 3, 7, 9], \"thu\": [7, 9], \"tile\": 1, \"time\": [1, 7], \"titl\": [0, 1], \"toler\": 1, \"tort\": 5, \"tradeoff\": 9, \"tri\": 1, \"true\": [1, 7, 9], \"true_beta\": 1, \"true_break\": 1, \"tweak\": 7, \"two\": [1, 7], \"type\": 1, \"typic\": [7, 9], \"u\": 1, \"ufl\": 7, \"uncertainti\": [7, 9], \"under\": 7, \"understand\": 7, \"uniform\": 1, \"unknown\": 3, \"unlik\": 7, \"unsupport\": 7, \"untest\": [7, 9], \"up\": 1, \"upon\": [1, 7], \"upper\": 1, \"url\": 0, \"us\": [2, 3, 5, 7, 9], \"use_custom_opt\": [1, 6, 7, 9], \"usecustomoptimizationroutin\": 7, \"user\": [2, 7, 9], \"util\": 1, \"valu\": [3, 7, 9], \"valueerror\": [1, 7], \"var\": [7, 9], \"var_1\": 1, \"variabl\": [1, 7, 9], \"varianc\": [1, 7, 9], \"variou\": 7, \"vector\": 9, \"venter\": 0, \"verbos\": 1, \"verbosity_model\": 1, \"veri\": 1, \"versa\": 7, \"version\": 7, \"vice\": 7, \"vol\": 7, \"vvuq\": 7, \"wa\": 7, \"wai\": 1, \"want\": [1, 7], \"warranti\": 5, \"wave\": 1, \"wb\": 1, \"we\": [1, 7], \"weight\": [3, 7, 9], \"weird\": 1, \"when\": [3, 7], \"where\": [1, 2, 7, 9], \"whether\": [5, 7, 9], \"which\": [1, 2, 7, 9], \"while\": [1, 7], \"whom\": 5, \"wiki\": 7, \"wikipedia\": 7, \"wilei\": 7, \"within\": [1, 7], \"without\": [5, 7], \"won\": [7, 9], \"work\": [1, 3, 7], \"would\": [1, 7], \"www\": [7, 9], \"www2\": 7, \"x\": [1, 7, 9], \"x0\": 1, \"x_c\": [1, 7, 9], \"x_data\": [1, 7, 9], \"x_new\": 7, \"x_opt\": 1, \"xguess\": 1, \"xhat\": 1, \"xn\": 1, \"y\": [1, 7, 9], \"y_c\": [1, 7, 9], \"y_data\": [1, 9], \"y_hat\": 7, \"y_std\": 1, \"y_w\": 9, \"year\": 0, \"yet\": 7, \"yhat\": [1, 7], \"yhat0\": 1, \"yhat1\": 1, \"yhat2\": 1, \"yhat_en\": 1, \"yhat_w\": 1, \"yield\": 7, \"you\": [0, 3, 4, 7, 9], \"your\": [0, 1, 2, 7], \"ytrue\": 1, \"zero\": 1, \"zeta\": 9}, \"titles\": [\"About\", \"Examples\", \"How it works\", \"pwlf: piecewise linear fitting\", \"Installation\", \"License\", \"pwlf\", \"pwlf package contents\", \"Requirements\", \"pwlf.PiecewiseLinFit\"], \"titleterms\": {\"about\": 0, \"bad\": 1, \"best\": 1, \"bound\": 1, \"breakpoint\": 1, \"conda\": 4, \"constant\": 1, \"content\": 7, \"custom\": 1, \"data\": 1, \"differenti\": 1, \"equat\": 1, \"error\": 1, \"evolut\": 1, \"exampl\": 1, \"find\": 1, \"fit\": [1, 3], \"fitfast\": 1, \"forc\": 1, \"from\": 4, \"get\": 1, \"guess\": 1, \"have\": 1, \"how\": 2, \"index\": 4, \"indic\": 3, \"instal\": 4, \"keyword\": 1, \"known\": 1, \"least\": 1, \"licens\": 5, \"line\": 1, \"linear\": [1, 3], \"locat\": 1, \"matrix\": 1, \"model\": 1, \"more\": 1, \"non\": 1, \"number\": 1, \"obtain\": 1, \"optim\": 1, \"p\": 1, \"packag\": [4, 7], \"pass\": 1, \"persist\": 1, \"piecewis\": 3, \"piecewiselinfit\": 9, \"point\": 1, \"polynomi\": 1, \"pwlf\": [1, 3, 6, 7, 9], \"pypi\": 4, \"python\": 4, \"regress\": 1, \"reproduc\": 1, \"requir\": 8, \"result\": 1, \"routin\": 1, \"segment\": 1, \"sourc\": 4, \"specifi\": 1, \"squar\": 1, \"standard\": 1, \"tabl\": 3, \"tensorflow\": 1, \"than\": 1, \"through\": 1, \"unknown\": 1, \"us\": 1, \"valu\": 1, \"weight\": 1, \"when\": 1, \"work\": 2, \"you\": 1}})"
  },
  {
    "path": "docs/stubs/pwlf.PiecewiseLinFit.html",
    "content": "<!DOCTYPE html>\n\n<html lang=\"en\" data-content_root=\"../\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\n    <title>pwlf.PiecewiseLinFit &#8212; pwlf 2.5.2 documentation</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../_static/pygments.css?v=d1102ebc\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../_static/basic.css?v=686e5160\" />\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../_static/alabaster.css?v=27fed22d\" />\n    <script src=\"../_static/documentation_options.js?v=afc61bbc\"></script>\n    <script src=\"../_static/doctools.js?v=9bcbadda\"></script>\n    <script src=\"../_static/sphinx_highlight.js?v=dc90522c\"></script>\n    <link rel=\"icon\" href=\"../_static/favicon.ico\"/>\n    <link rel=\"author\" title=\"About these documents\" href=\"../about.html\" />\n    <link rel=\"index\" title=\"Index\" href=\"../genindex.html\" />\n    <link rel=\"search\" title=\"Search\" href=\"../search.html\" />\n    <link rel=\"next\" title=\"About\" href=\"../about.html\" />\n    <link rel=\"prev\" title=\"pwlf package contents\" href=\"../pwlf.html\" />\n   \n  <link rel=\"stylesheet\" href=\"../_static/custom.css\" type=\"text/css\" />\n  \n\n  \n  \n\n  </head><body>\n  \n\n    <div class=\"document\">\n      <div class=\"documentwrapper\">\n        <div class=\"bodywrapper\">\n          \n\n          <div class=\"body\" role=\"main\">\n            \n  <section id=\"pwlf-piecewiselinfit\">\n<h1>pwlf.PiecewiseLinFit<a class=\"headerlink\" href=\"#pwlf-piecewiselinfit\" title=\"Link to this heading\">¶</a></h1>\n<dl class=\"py class\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit\">\n<em class=\"property\"><span class=\"pre\">class</span><span class=\"w\"> </span></em><span class=\"sig-prename descclassname\"><span class=\"pre\">pwlf.</span></span><span class=\"sig-name descname\"><span class=\"pre\">PiecewiseLinFit</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">x</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">y</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">disp_res</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">False</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">lapack_driver</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'gelsd'</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">degree</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">1</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">weights</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">seed</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit\" title=\"Link to this definition\">¶</a></dt>\n<dd><p class=\"rubric\">Methods</p>\n<table class=\"autosummary longtable docutils align-default\">\n<tbody>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.assemble_regression_matrix\" title=\"pwlf.PiecewiseLinFit.assemble_regression_matrix\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">assemble_regression_matrix</span></code></a>(breaks, x)</p></td>\n<td><p>Assemble the linear regression matrix A</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.calc_slopes\" title=\"pwlf.PiecewiseLinFit.calc_slopes\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">calc_slopes</span></code></a>()</p></td>\n<td><p>Calculate the slopes of the lines after a piecewise linear function has been fitted.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.conlstsq\" title=\"pwlf.PiecewiseLinFit.conlstsq\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">conlstsq</span></code></a>(A[, calc_slopes])</p></td>\n<td><p>Perform a constrained least squares fit for A matrix.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fit\" title=\"pwlf.PiecewiseLinFit.fit\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit</span></code></a>(n_segments[, x_c, y_c, bounds])</p></td>\n<td><p>Fit a continuous piecewise linear function for a specified number of line segments.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fit_force_points_opt\" title=\"pwlf.PiecewiseLinFit.fit_force_points_opt\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_force_points_opt</span></code></a>(var)</p></td>\n<td><p>The objective function to perform a continuous piecewise linear fit for a specified number of breakpoints.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fit_guess\" title=\"pwlf.PiecewiseLinFit.fit_guess\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_guess</span></code></a>(guess_breakpoints[, bounds])</p></td>\n<td><p>Uses L-BFGS-B optimization to find the location of breakpoints from a guess of where breakpoint locations should be.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fit_with_breaks\" title=\"pwlf.PiecewiseLinFit.fit_with_breaks\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_with_breaks</span></code></a>(breaks)</p></td>\n<td><p>A function which fits a continuous piecewise linear function for specified breakpoint locations.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fit_with_breaks_force_points\" title=\"pwlf.PiecewiseLinFit.fit_with_breaks_force_points\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_with_breaks_force_points</span></code></a>(breaks, x_c, y_c)</p></td>\n<td><p>A function which fits a continuous piecewise linear function for specified breakpoint locations, where you force the fit to go through the data points at x_c and y_c.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fit_with_breaks_opt\" title=\"pwlf.PiecewiseLinFit.fit_with_breaks_opt\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_with_breaks_opt</span></code></a>(var)</p></td>\n<td><p>The objective function to perform a continuous piecewise linear fit for a specified number of breakpoints.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fitfast\" title=\"pwlf.PiecewiseLinFit.fitfast\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fitfast</span></code></a>(n_segments[, pop, bounds])</p></td>\n<td><p>Uses multi start LBFGSB optimization to find the location of breakpoints for a given number of line segments by minimizing the sum of the square of the errors.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.lstsq\" title=\"pwlf.PiecewiseLinFit.lstsq\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">lstsq</span></code></a>(A[, calc_slopes])</p></td>\n<td><p>Perform the least squares fit for A matrix.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.p_values\" title=\"pwlf.PiecewiseLinFit.p_values\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">p_values</span></code></a>([method, step_size])</p></td>\n<td><p>Calculate the p-values for each beta parameter.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.predict\" title=\"pwlf.PiecewiseLinFit.predict\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">predict</span></code></a>(x[, beta, breaks])</p></td>\n<td><p>Evaluate the fitted continuous piecewise linear function at untested points.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.prediction_variance\" title=\"pwlf.PiecewiseLinFit.prediction_variance\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">prediction_variance</span></code></a>(x)</p></td>\n<td><p>Calculate the prediction variance for each specified x location.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.r_squared\" title=\"pwlf.PiecewiseLinFit.r_squared\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">r_squared</span></code></a>()</p></td>\n<td><p>Calculate the coefficient of determination (&quot;R squared&quot;, R^2) value after a fit has been performed.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.standard_errors\" title=\"pwlf.PiecewiseLinFit.standard_errors\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">standard_errors</span></code></a>([method, step_size])</p></td>\n<td><p>Calculate the standard errors for each beta parameter determined from the piecewise linear fit.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.use_custom_opt\" title=\"pwlf.PiecewiseLinFit.use_custom_opt\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">use_custom_opt</span></code></a>(n_segments[, x_c, y_c])</p></td>\n<td><p>Provide the number of line segments you want to use with your custom optimization routine.</p></td>\n</tr>\n</tbody>\n</table>\n<dl class=\"py method\">\n<dt class=\"sig sig-object py\" id=\"pwlf.PiecewiseLinFit.__init__\">\n<span class=\"sig-name descname\"><span class=\"pre\">__init__</span></span><span class=\"sig-paren\">(</span><em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">x</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">y</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">disp_res</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">False</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">lapack_driver</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">'gelsd'</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">degree</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">1</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">weights</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em>, <em class=\"sig-param\"><span class=\"n\"><span class=\"pre\">seed</span></span><span class=\"o\"><span class=\"pre\">=</span></span><span class=\"default_value\"><span class=\"pre\">None</span></span></em><span class=\"sig-paren\">)</span><a class=\"headerlink\" href=\"#pwlf.PiecewiseLinFit.__init__\" title=\"Link to this definition\">¶</a></dt>\n<dd><p>An object to fit a continuous piecewise linear function\nto data.</p>\n<p>Initiate the library with the supplied x and y data.\nSupply the x and y data of which you’ll be fitting\na continuous piecewise linear model to where y(x).\nby default pwlf won’t print the optimization results.;</p>\n<dl class=\"field-list simple\">\n<dt class=\"field-odd\">Parameters<span class=\"colon\">:</span></dt>\n<dd class=\"field-odd\"><dl class=\"simple\">\n<dt><strong>x</strong><span class=\"classifier\">array_like</span></dt><dd><p>The x or independent data point locations as list or 1 dimensional\nnumpy array.</p>\n</dd>\n<dt><strong>y</strong><span class=\"classifier\">array_like</span></dt><dd><p>The y or dependent data point locations as list or 1 dimensional\nnumpy array.</p>\n</dd>\n<dt><strong>disp_res</strong><span class=\"classifier\">bool, optional</span></dt><dd><p>Whether the optimization results should be printed. Default is\nFalse.</p>\n</dd>\n<dt><strong>lapack_driver</strong><span class=\"classifier\">str, optional</span></dt><dd><p>Which LAPACK driver is used to solve the least-squares problem.\nDefault lapack_driver=’gelsd’. Options are ‘gelsd’, ‘gelsy’,\n‘gelss’. For more see\n<a class=\"reference external\" href=\"https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.lstsq.html\">https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.lstsq.html</a>\n<a class=\"reference external\" href=\"http://www.netlib.org/lapack/lug/node27.html\">http://www.netlib.org/lapack/lug/node27.html</a></p>\n</dd>\n<dt><strong>degree</strong><span class=\"classifier\">int, list, optional</span></dt><dd><p>The degree of polynomial to use. The default is degree=1 for\nlinear models. Use degree=0 for constant models. Use a list for\nmixed degrees (only supports degrees 1 or 0). List should be read\nfrom left to right, degree=[1,0,1] corresponds to a mixed degree\nmodel, where the left most segment has degree 1, the middle\nsegment degree 0, and the right most segment degree 1.</p>\n</dd>\n<dt><strong>weights</strong><span class=\"classifier\">None, or array_like</span></dt><dd><p>The individual weights are typically the reciprocal of the\nstandard deviation for each data point, where weights[i]\ncorresponds to one over the standard deviation of the ith data\npoint. Default weights=None.</p>\n</dd>\n<dt><strong>seed</strong><span class=\"classifier\">None, or int</span></dt><dd><p>Pick an integer which will set the numpy.random.seed on init.\nThe fit and fitfast methods rely on stochastic methods and setting\nthis value will make the results reproducible. The default\nbehavior is to not specify a seed.</p>\n</dd>\n</dl>\n</dd>\n<dt class=\"field-even\">Attributes<span class=\"colon\">:</span></dt>\n<dd class=\"field-even\"><dl class=\"simple\">\n<dt><strong>beta</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>The model parameters for the continuous piecewise linear fit.</p>\n</dd>\n<dt><strong>break_0</strong><span class=\"classifier\">float</span></dt><dd><p>The smallest x value.</p>\n</dd>\n<dt><strong>break_n</strong><span class=\"classifier\">float</span></dt><dd><p>The largest x value.</p>\n</dd>\n<dt><strong>c_n</strong><span class=\"classifier\">int</span></dt><dd><p>The number of constraint points. This is the same as len(x_c).</p>\n</dd>\n<dt><strong>degree: int, list</strong></dt><dd><p>The degree of polynomial to use. The default is degree=1 for\nlinear models. Use degree=0 for constant models. This will be a\nlist if the user provided a list.</p>\n</dd>\n<dt><strong>fit_breaks</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>breakpoint locations stored as a 1-D numpy array.</p>\n</dd>\n<dt><strong>intercepts</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>The y-intercept of each line segment as a 1-D numpy array.</p>\n</dd>\n<dt><strong>lapack_driver</strong><span class=\"classifier\">str</span></dt><dd><p>Which LAPACK driver is used to solve the least-squares problem.</p>\n</dd>\n<dt><strong>print</strong><span class=\"classifier\">bool</span></dt><dd><p>Whether the optimization results should be printed. Default is\nFalse.</p>\n</dd>\n<dt><strong>n_data</strong><span class=\"classifier\">int</span></dt><dd><p>The number of data points.</p>\n</dd>\n<dt><strong>n_parameters</strong><span class=\"classifier\">int</span></dt><dd><p>The number of model parameters. This is equivalent to the\nlen(beta).</p>\n</dd>\n<dt><strong>n_segments</strong><span class=\"classifier\">int</span></dt><dd><p>The number of line segments.</p>\n</dd>\n<dt><strong>nVar</strong><span class=\"classifier\">int</span></dt><dd><p>The number of variables in the global optimization problem.</p>\n</dd>\n<dt><strong>se</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>Standard errors associated with each beta parameter. Specifically\nse[0] correspounds to the standard error for beta[0], and so forth.</p>\n</dd>\n<dt><strong>seed</strong><span class=\"classifier\">int</span></dt><dd><p>Numpy random seed number set on init.</p>\n</dd>\n<dt><strong>slopes</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>The slope of each ling segment as a 1-D numpy array. This assumes\nthat x[0] &lt;= x[1] &lt;= … &lt;= x[n]. Thus, slopes[0] is the slope\nof the first line segment.</p>\n</dd>\n<dt><strong>ssr</strong><span class=\"classifier\">float</span></dt><dd><p>Optimal sum of square error.</p>\n</dd>\n<dt><strong>x_c</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>The x locations of the data points that the piecewise linear\nfunction will be forced to go through.</p>\n</dd>\n<dt><strong>y_c</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>The y locations of the data points that the piecewise linear\nfunction will be forced to go through.</p>\n</dd>\n<dt><strong>x_data</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>The inputted parameter x from the 1-D data set.</p>\n</dd>\n<dt><strong>y_data</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>The inputted parameter y from the 1-D data set.</p>\n</dd>\n<dt><strong>y_w</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>The weighted y data vector.</p>\n</dd>\n<dt><strong>zeta</strong><span class=\"classifier\">ndarray (1-D)</span></dt><dd><p>The model parameters associated with the constraint function.</p>\n</dd>\n</dl>\n</dd>\n</dl>\n<p class=\"rubric\">Methods</p>\n<table class=\"docutils align-default\">\n<tbody>\n<tr class=\"row-odd\"><td><p><strong>fit(n_segments, x_c=None, y_c=None, **kwargs)</strong></p></td>\n<td><p>Fit a continuous piecewise linear function for a specified number of line segments.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><strong>fitfast(n_segments, pop=2, **kwargs)</strong></p></td>\n<td><p>Fit a continuous piecewise linear function for a specified number of line segments using a specialized optimization routine that should be faster than fit() for large problems. The tradeoff may be that fitfast() results in a lower quality model.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><strong>fit_with_breaks(breaks)</strong></p></td>\n<td><p>Fit a continuous piecewise linear function where the breakpoint locations are known.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><strong>fit_with_breaks_force_points(breaks, x_c, y_c)</strong></p></td>\n<td><p>Fit a continuous piecewise linear function where the breakpoint locations are known, and force the fit to go through points at x_c and y_c.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><strong>predict(x, beta=None, breaks=None)</strong></p></td>\n<td><p>Evaluate the continuous piecewise linear function at new untested points.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><strong>fit_with_breaks_opt(var)</strong></p></td>\n<td><p>The objective function to perform a continuous piecewise linear fit for a specified number of breakpoints. This is to be used with a custom optimization routine, and after use_custom_opt has been called.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><strong>fit_force_points_opt(var)’</strong></p></td>\n<td><p>Same as fit_with_breaks_opt(var), except this allows for points to be forced through x_c and y_c.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><strong>use_custom_opt(n_segments, x_c=None, y_c=None)</strong></p></td>\n<td><p>Function to initialize the attributes necessary to use a custom optimization routine. Must be used prior to calling fit_with_breaks_opt() or fit_force_points_opt().</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><strong>calc_slopes()</strong></p></td>\n<td><p>Calculate the slopes of the lines after a piecewise linear function has been fitted.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><strong>standard_errors()</strong></p></td>\n<td><p>Calculate the standard error of each model parameter in the fitted piecewise linear function. Note, this assumes no uncertainty in breakpoint locations.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><strong>prediction_variance(x)</strong></p></td>\n<td><p>Calculate the prediction variance at x locations for the fitted piecewise linear function. Note, assumes no uncertainty in break point locations.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><strong>r_squared()</strong></p></td>\n<td><p>Calculate the coefficient of determination, or ‘R-squared’ value for a fitted piecewise linear function.</p></td>\n</tr>\n</tbody>\n</table>\n<p class=\"rubric\">Examples</p>\n<p>Initialize for x, y data</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span> <span class=\"nn\">pwlf</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n<p>Initialize for x,y data and print optimization results</p>\n<div class=\"doctest highlight-default notranslate\"><div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">my_pwlf</span> <span class=\"o\">=</span> <span class=\"n\">pwlf</span><span class=\"o\">.</span><span class=\"n\">PiecewiseLinFit</span><span class=\"p\">(</span><span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">,</span> <span class=\"n\">disp_res</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n</pre></div>\n</div>\n</dd></dl>\n\n<p class=\"rubric\">Methods</p>\n<table class=\"autosummary longtable docutils align-default\">\n<tbody>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"#pwlf.PiecewiseLinFit.__init__\" title=\"pwlf.PiecewiseLinFit.__init__\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">__init__</span></code></a>(x, y[, disp_res, lapack_driver, ...])</p></td>\n<td><p>An object to fit a continuous piecewise linear function to data.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.assemble_regression_matrix\" title=\"pwlf.PiecewiseLinFit.assemble_regression_matrix\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">assemble_regression_matrix</span></code></a>(breaks, x)</p></td>\n<td><p>Assemble the linear regression matrix A</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.calc_slopes\" title=\"pwlf.PiecewiseLinFit.calc_slopes\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">calc_slopes</span></code></a>()</p></td>\n<td><p>Calculate the slopes of the lines after a piecewise linear function has been fitted.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.conlstsq\" title=\"pwlf.PiecewiseLinFit.conlstsq\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">conlstsq</span></code></a>(A[, calc_slopes])</p></td>\n<td><p>Perform a constrained least squares fit for A matrix.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fit\" title=\"pwlf.PiecewiseLinFit.fit\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit</span></code></a>(n_segments[, x_c, y_c, bounds])</p></td>\n<td><p>Fit a continuous piecewise linear function for a specified number of line segments.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fit_force_points_opt\" title=\"pwlf.PiecewiseLinFit.fit_force_points_opt\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_force_points_opt</span></code></a>(var)</p></td>\n<td><p>The objective function to perform a continuous piecewise linear fit for a specified number of breakpoints.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fit_guess\" title=\"pwlf.PiecewiseLinFit.fit_guess\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_guess</span></code></a>(guess_breakpoints[, bounds])</p></td>\n<td><p>Uses L-BFGS-B optimization to find the location of breakpoints from a guess of where breakpoint locations should be.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fit_with_breaks\" title=\"pwlf.PiecewiseLinFit.fit_with_breaks\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_with_breaks</span></code></a>(breaks)</p></td>\n<td><p>A function which fits a continuous piecewise linear function for specified breakpoint locations.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fit_with_breaks_force_points\" title=\"pwlf.PiecewiseLinFit.fit_with_breaks_force_points\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_with_breaks_force_points</span></code></a>(breaks, x_c, y_c)</p></td>\n<td><p>A function which fits a continuous piecewise linear function for specified breakpoint locations, where you force the fit to go through the data points at x_c and y_c.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fit_with_breaks_opt\" title=\"pwlf.PiecewiseLinFit.fit_with_breaks_opt\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fit_with_breaks_opt</span></code></a>(var)</p></td>\n<td><p>The objective function to perform a continuous piecewise linear fit for a specified number of breakpoints.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.fitfast\" title=\"pwlf.PiecewiseLinFit.fitfast\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">fitfast</span></code></a>(n_segments[, pop, bounds])</p></td>\n<td><p>Uses multi start LBFGSB optimization to find the location of breakpoints for a given number of line segments by minimizing the sum of the square of the errors.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.lstsq\" title=\"pwlf.PiecewiseLinFit.lstsq\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">lstsq</span></code></a>(A[, calc_slopes])</p></td>\n<td><p>Perform the least squares fit for A matrix.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.p_values\" title=\"pwlf.PiecewiseLinFit.p_values\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">p_values</span></code></a>([method, step_size])</p></td>\n<td><p>Calculate the p-values for each beta parameter.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.predict\" title=\"pwlf.PiecewiseLinFit.predict\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">predict</span></code></a>(x[, beta, breaks])</p></td>\n<td><p>Evaluate the fitted continuous piecewise linear function at untested points.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.prediction_variance\" title=\"pwlf.PiecewiseLinFit.prediction_variance\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">prediction_variance</span></code></a>(x)</p></td>\n<td><p>Calculate the prediction variance for each specified x location.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.r_squared\" title=\"pwlf.PiecewiseLinFit.r_squared\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">r_squared</span></code></a>()</p></td>\n<td><p>Calculate the coefficient of determination (&quot;R squared&quot;, R^2) value after a fit has been performed.</p></td>\n</tr>\n<tr class=\"row-odd\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.standard_errors\" title=\"pwlf.PiecewiseLinFit.standard_errors\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">standard_errors</span></code></a>([method, step_size])</p></td>\n<td><p>Calculate the standard errors for each beta parameter determined from the piecewise linear fit.</p></td>\n</tr>\n<tr class=\"row-even\"><td><p><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit.use_custom_opt\" title=\"pwlf.PiecewiseLinFit.use_custom_opt\"><code class=\"xref py py-obj docutils literal notranslate\"><span class=\"pre\">use_custom_opt</span></code></a>(n_segments[, x_c, y_c])</p></td>\n<td><p>Provide the number of line segments you want to use with your custom optimization routine.</p></td>\n</tr>\n</tbody>\n</table>\n</dd></dl>\n\n</section>\n\n\n          </div>\n          \n        </div>\n      </div>\n      <div class=\"sphinxsidebar\" role=\"navigation\" aria-label=\"Main\">\n        <div class=\"sphinxsidebarwrapper\">\n<h1 class=\"logo\"><a href=\"../index.html\">pwlf</a></h1>\n\n\n\n\n\n\n\n\n\n<search id=\"searchbox\" style=\"display: none\" role=\"search\">\n    <div class=\"searchformwrapper\">\n    <form class=\"search\" action=\"../search.html\" method=\"get\">\n      <input type=\"text\" name=\"q\" aria-labelledby=\"searchlabel\" autocomplete=\"off\" autocorrect=\"off\" autocapitalize=\"off\" spellcheck=\"false\" placeholder=\"Search\"/>\n      <input type=\"submit\" value=\"Go\" />\n    </form>\n    </div>\n</search>\n<script>document.getElementById('searchbox').style.display = \"block\"</script><h3>Navigation</h3>\n<ul class=\"current\">\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"../installation.html\">Installation</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"../how_it_works.html\">How it works</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"../examples.html\">Examples</a></li>\n<li class=\"toctree-l1 current\"><a class=\"reference internal\" href=\"../pwlf.html\">pwlf package contents</a><ul class=\"current\">\n<li class=\"toctree-l2 current\"><a class=\"current reference internal\" href=\"#\">pwlf.PiecewiseLinFit</a></li>\n<li class=\"toctree-l2\"><a class=\"reference internal\" href=\"../pwlf.html#pwlf.PiecewiseLinFit\"><code class=\"docutils literal notranslate\"><span class=\"pre\">PiecewiseLinFit</span></code></a></li>\n</ul>\n</li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"../about.html\">About</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"../requirements.html\">Requirements</a></li>\n<li class=\"toctree-l1\"><a class=\"reference internal\" href=\"../license.html\">License</a></li>\n</ul>\n\n<div class=\"relations\">\n<h3>Related Topics</h3>\n<ul>\n  <li><a href=\"../index.html\">Documentation overview</a><ul>\n  <li><a href=\"../pwlf.html\">pwlf package contents</a><ul>\n      <li>Previous: <a href=\"../pwlf.html\" title=\"previous chapter\">pwlf package contents</a></li>\n      <li>Next: <a href=\"../about.html\" title=\"next chapter\">About</a></li>\n  </ul></li>\n  </ul></li>\n</ul>\n</div>\n\n\n\n\n\n\n\n\n        </div>\n      </div>\n      <div class=\"clearer\"></div>\n    </div>\n    <div class=\"footer\">\n      &#169;2024, Charles Jekel.\n      \n      |\n      Powered by <a href=\"https://www.sphinx-doc.org/\">Sphinx 8.1.3</a>\n      &amp; <a href=\"https://alabaster.readthedocs.io\">Alabaster 1.0.0</a>\n      \n      |\n      <a href=\"../_sources/stubs/pwlf.PiecewiseLinFit.rst.txt\"\n          rel=\"nofollow\">Page source</a>\n    </div>\n\n    \n\n    \n    <script>\n\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'G-QKPGZSZ8CD']);\n      _gaq.push(['_setDomainName', 'none']);\n      _gaq.push(['_setAllowLinker', true]);\n      _gaq.push(['_trackPageview']);\n\n      (function() {\n        var ga = document.createElement('script'); ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n\n    </script>\n    \n  </body>\n</html>"
  },
  {
    "path": "examples/EGO_integer_only.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"import numpy as np\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"import pwlf\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"[<matplotlib.lines.Line2D at 0x24d81ae6f28>]\"\n      ]\n     },\n     \"execution_count\": 2,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    },\n    {\n     \"data\": {\n      \"image/png\": \"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\\n\",\n      \"text/plain\": [\n       \"<Figure size 432x288 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"x = np.linspace(0, 1024, 100)\\n\",\n    \"y = np.sin(.01*x)\\n\",\n    \"plt.figure()\\n\",\n    \"plt.plot(x, y)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from GPyOpt.methods import BayesianOptimization\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 4,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"my_pwlf = pwlf.PiecewiseLinFit(x, y, degree=2)\\n\",\n    \"number_of_line_segments = 4\\n\",\n    \"my_pwlf.use_custom_opt(number_of_line_segments)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 5,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# define domain for possible breakpoints\\n\",\n    \"bounds = [{'name': 'break_1', 'type': 'discrete',\\n\",\n    \"           'domain': np.arange(1, 1023)},\\n\",\n    \"          {'name': 'break_2', 'type': 'discrete',\\n\",\n    \"           'domain': np.arange(1, 1023)},\\n\",\n    \"          {'name': 'break_3', 'type': 'discrete',\\n\",\n    \"           'domain': np.arange(1, 1023)}]\\n\",\n    \"max_iter = 120\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 6,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"def my_obj(x):\\n\",\n    \"    f = np.zeros(x.shape[0])\\n\",\n    \"    for i, j in enumerate(x):\\n\",\n    \"        f[i] = my_pwlf.fit_with_breaks_opt(j)\\n\",\n    \"    return f\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 7,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"myBopt = BayesianOptimization(my_obj,\\n\",\n    \"                              domain=bounds, model_type='GP',\\n\",\n    \"                              initial_design_numdata=20,\\n\",\n    \"                              initial_design_type='latin',\\n\",\n    \"                              exact_feval=True, verbosity=True,\\n\",\n    \"                              verbosity_model=False)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 8,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"num acquisition: 1, time elapsed: 0.20s\\n\",\n      \"num acquisition: 2, time elapsed: 0.40s\\n\",\n      \"num acquisition: 3, time elapsed: 0.60s\\n\",\n      \"num acquisition: 4, time elapsed: 0.79s\\n\",\n      \"num acquisition: 5, time elapsed: 0.97s\\n\",\n      \"num acquisition: 6, time elapsed: 1.15s\\n\",\n      \"num acquisition: 7, time elapsed: 1.35s\\n\",\n      \"num acquisition: 8, time elapsed: 1.53s\\n\",\n      \"num acquisition: 9, time elapsed: 1.73s\\n\",\n      \"num acquisition: 10, time elapsed: 1.93s\\n\",\n      \"num acquisition: 11, time elapsed: 2.11s\\n\",\n      \"num acquisition: 12, time elapsed: 2.30s\\n\",\n      \"num acquisition: 13, time elapsed: 2.49s\\n\",\n      \"num acquisition: 14, time elapsed: 2.76s\\n\",\n      \"num acquisition: 15, time elapsed: 3.01s\\n\",\n      \"num acquisition: 16, time elapsed: 3.28s\\n\",\n      \"num acquisition: 17, time elapsed: 3.51s\\n\",\n      \"num acquisition: 18, time elapsed: 3.79s\\n\",\n      \"num acquisition: 19, time elapsed: 4.08s\\n\",\n      \"num acquisition: 20, time elapsed: 4.32s\\n\",\n      \"num acquisition: 21, time elapsed: 4.57s\\n\",\n      \"num acquisition: 22, time elapsed: 4.83s\\n\",\n      \"num acquisition: 23, time elapsed: 5.08s\\n\",\n      \"num acquisition: 24, time elapsed: 5.34s\\n\",\n      \"num acquisition: 25, time elapsed: 5.66s\\n\",\n      \"num acquisition: 26, time elapsed: 5.95s\\n\",\n      \"num acquisition: 27, time elapsed: 6.20s\\n\",\n      \"num acquisition: 28, time elapsed: 6.49s\\n\",\n      \"num acquisition: 29, time elapsed: 6.74s\\n\",\n      \"num acquisition: 30, time elapsed: 6.99s\\n\",\n      \"num acquisition: 31, time elapsed: 7.21s\\n\",\n      \"num acquisition: 32, time elapsed: 7.47s\\n\",\n      \"num acquisition: 33, time elapsed: 7.70s\\n\",\n      \"num acquisition: 34, time elapsed: 7.96s\\n\",\n      \"num acquisition: 35, time elapsed: 8.18s\\n\",\n      \"num acquisition: 36, time elapsed: 8.44s\\n\",\n      \"num acquisition: 37, time elapsed: 8.70s\\n\",\n      \"num acquisition: 38, time elapsed: 8.94s\\n\",\n      \"num acquisition: 39, time elapsed: 9.21s\\n\",\n      \"num acquisition: 40, time elapsed: 9.49s\\n\",\n      \"num acquisition: 41, time elapsed: 9.77s\\n\",\n      \"num acquisition: 42, time elapsed: 10.02s\\n\",\n      \"num acquisition: 43, time elapsed: 10.31s\\n\",\n      \"num acquisition: 44, time elapsed: 10.56s\\n\",\n      \"num acquisition: 45, time elapsed: 10.80s\\n\",\n      \"num acquisition: 46, time elapsed: 11.07s\\n\",\n      \"num acquisition: 47, time elapsed: 11.34s\\n\",\n      \"num acquisition: 48, time elapsed: 11.61s\\n\",\n      \"num acquisition: 49, time elapsed: 11.91s\\n\",\n      \"num acquisition: 50, time elapsed: 12.18s\\n\",\n      \"num acquisition: 51, time elapsed: 12.47s\\n\",\n      \"num acquisition: 52, time elapsed: 12.74s\\n\",\n      \"num acquisition: 53, time elapsed: 13.04s\\n\",\n      \"num acquisition: 54, time elapsed: 13.39s\\n\",\n      \"num acquisition: 55, time elapsed: 13.70s\\n\",\n      \"num acquisition: 56, time elapsed: 13.96s\\n\",\n      \"num acquisition: 57, time elapsed: 14.25s\\n\",\n      \"num acquisition: 58, time elapsed: 14.52s\\n\",\n      \"num acquisition: 59, time elapsed: 14.80s\\n\",\n      \"num acquisition: 60, time elapsed: 15.10s\\n\",\n      \"num acquisition: 61, time elapsed: 15.38s\\n\",\n      \"num acquisition: 62, time elapsed: 15.65s\\n\",\n      \"num acquisition: 63, time elapsed: 15.93s\\n\",\n      \"num acquisition: 64, time elapsed: 16.23s\\n\",\n      \"num acquisition: 65, time elapsed: 16.54s\\n\",\n      \"num acquisition: 66, time elapsed: 16.82s\\n\",\n      \"num acquisition: 67, time elapsed: 17.16s\\n\",\n      \"num acquisition: 68, time elapsed: 17.45s\\n\",\n      \"num acquisition: 69, time elapsed: 17.73s\\n\",\n      \"num acquisition: 70, time elapsed: 18.02s\\n\",\n      \"num acquisition: 71, time elapsed: 18.33s\\n\",\n      \"num acquisition: 72, time elapsed: 18.61s\\n\",\n      \"num acquisition: 73, time elapsed: 18.88s\\n\",\n      \"num acquisition: 74, time elapsed: 19.17s\\n\",\n      \"num acquisition: 75, time elapsed: 19.46s\\n\",\n      \"num acquisition: 76, time elapsed: 19.76s\\n\",\n      \"num acquisition: 77, time elapsed: 20.07s\\n\",\n      \"num acquisition: 78, time elapsed: 20.38s\\n\",\n      \"num acquisition: 79, time elapsed: 20.67s\\n\",\n      \"num acquisition: 80, time elapsed: 20.95s\\n\",\n      \"num acquisition: 81, time elapsed: 21.30s\\n\",\n      \"num acquisition: 82, time elapsed: 21.58s\\n\",\n      \"num acquisition: 83, time elapsed: 21.88s\\n\",\n      \"num acquisition: 84, time elapsed: 22.17s\\n\",\n      \"num acquisition: 85, time elapsed: 22.46s\\n\",\n      \"num acquisition: 86, time elapsed: 22.75s\\n\",\n      \"num acquisition: 87, time elapsed: 23.07s\\n\",\n      \"num acquisition: 88, time elapsed: 23.40s\\n\",\n      \"num acquisition: 89, time elapsed: 23.72s\\n\",\n      \"num acquisition: 90, time elapsed: 24.02s\\n\",\n      \"num acquisition: 91, time elapsed: 24.34s\\n\",\n      \"num acquisition: 92, time elapsed: 24.67s\\n\",\n      \"num acquisition: 93, time elapsed: 24.99s\\n\",\n      \"num acquisition: 94, time elapsed: 25.34s\\n\",\n      \"num acquisition: 95, time elapsed: 25.69s\\n\",\n      \"num acquisition: 96, time elapsed: 26.03s\\n\",\n      \"num acquisition: 97, time elapsed: 26.32s\\n\",\n      \"num acquisition: 98, time elapsed: 26.65s\\n\",\n      \"num acquisition: 99, time elapsed: 27.02s\\n\",\n      \"num acquisition: 100, time elapsed: 27.36s\\n\",\n      \"num acquisition: 101, time elapsed: 27.78s\\n\",\n      \"num acquisition: 102, time elapsed: 28.11s\\n\",\n      \"num acquisition: 103, time elapsed: 28.47s\\n\",\n      \"num acquisition: 104, time elapsed: 28.80s\\n\",\n      \"num acquisition: 105, time elapsed: 29.13s\\n\",\n      \"num acquisition: 106, time elapsed: 29.48s\\n\",\n      \"num acquisition: 107, time elapsed: 29.80s\\n\",\n      \"num acquisition: 108, time elapsed: 30.19s\\n\",\n      \"num acquisition: 109, time elapsed: 30.55s\\n\",\n      \"num acquisition: 110, time elapsed: 30.84s\\n\",\n      \"num acquisition: 111, time elapsed: 31.25s\\n\",\n      \"num acquisition: 112, time elapsed: 31.58s\\n\",\n      \"num acquisition: 113, time elapsed: 31.91s\\n\",\n      \"num acquisition: 114, time elapsed: 32.26s\\n\",\n      \"num acquisition: 115, time elapsed: 32.65s\\n\",\n      \"num acquisition: 116, time elapsed: 33.02s\\n\",\n      \"num acquisition: 117, time elapsed: 33.36s\\n\",\n      \"num acquisition: 118, time elapsed: 33.72s\\n\",\n      \"num acquisition: 119, time elapsed: 34.06s\\n\",\n      \"num acquisition: 120, time elapsed: 34.47s\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"myBopt.run_optimization(max_iter=max_iter, verbosity=True)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 9,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"\\n\",\n      \" \\n\",\n      \" Opt found \\n\",\n      \"\\n\",\n      \"Optimum number of line segments: [612. 310. 842.]\\n\",\n      \"Function value: 0.058342840166060575\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"print('\\\\n \\\\n Opt found \\\\n')\\n\",\n    \"print('Optimum number of line segments:', myBopt.x_opt)\\n\",\n    \"print('Function value:', myBopt.fx_opt)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 10,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\\n\",\n      \"text/plain\": [\n       \"<Figure size 720x360 with 2 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"myBopt.plot_convergence()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 11,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\\n\",\n      \"text/plain\": [\n       \"<Figure size 432x288 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# perform the fit for the optimum\\n\",\n    \"x_opt = list(myBopt.x_opt)\\n\",\n    \"x_opt.append(x.min())\\n\",\n    \"x_opt.append(x.max())\\n\",\n    \"ssr = my_pwlf.fit_with_breaks(x_opt)\\n\",\n    \"# predict for the determined points\\n\",\n    \"xHat = np.linspace(min(x), max(x), num=10000)\\n\",\n    \"yHat = my_pwlf.predict(xHat)\\n\",\n    \"\\n\",\n    \"# plot the results\\n\",\n    \"plt.figure()\\n\",\n    \"plt.plot(x, y, 'o')\\n\",\n    \"plt.plot(xHat, yHat, '-')\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 12,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"0.058342840166060575\"\n      ]\n     },\n     \"execution_count\": 12,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"ssr\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": []\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"Python 3\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.6.8\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"
  },
  {
    "path": "examples/README.md",
    "content": "# Examples\nAll of these examples will use the following data and imports.\n```python\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n```\n\n1. [fit with known breakpoint locations](#fit-with-known-breakpoint-locations)\n2. [fit for specified number of line segments](#fit-for-specified-number-of-line-segments)\n3. [fitfast for specified number of line segments](#fitfast-for-specified-number-of-line-segments)\n4. [force a fit through data points](#force-a-fit-through-data-points)\n5. [use custom optimization routine](#use-custom-optimization-routine)\n6. [pass differential evolution keywords](#pass-differential-evolution-keywords)\n7. [find the best number of line segments](#find-the-best-number-of-line-segments)\n8. [model persistence](#model-persistence)\n9. [bad fits when you have more unknowns than data](#bad-fits-when-you-have-more-unknowns-than-data)\n10. [fit with a breakpoint guess](#fit-with-a-breakpoint-guess)\n11. [get the linear regression matrix](#get-the-linear-regression-matrix)\n12. [use of TensorFlow](#use-of-tensorflow)\n13. [fit constants or polynomials](#fit-constants-or-polynomials)\n14. [specify breakpoint bounds](#specify-breakpoint-bounds)\n15. [non-linear standard errors and p-values](#non-linear-standard-errors-and-p-values)\n16. [obtain the equations of fitted pwlf](#obtain-the-equations-of-fitted-pwlf)\n17. [weighted least squares fit](#weighted-least-squares-fit)\n18. [reproducible results](#reproducible-resultss)\n\n\n## fit with known breakpoint locations\n\nYou can perform a least squares fit if you know the breakpoint locations.\n\n```python\n# your desired line segment end locations\nx0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data with the specified break points\n# (ie the x locations of where the line segments\n# will terminate)\nmy_pwlf.fit_with_breaks(x0)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n```\n\n![fit with known breakpoint locations](https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/fit_breaks.png)\n\n\n## fit for specified number of line segments\n\nUse a global optimization to find the breakpoint locations that minimize the sum of squares error. This uses [Differential Evolution](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html) from scipy.\n\n```python\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data for four line segments\nres = my_pwlf.fit(4)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n```\n\n![fit for specified number of line segments](https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/numberoflines.png)\n\n\n## fitfast for specified number of line segments\n\nThis performs a fit for a specified number of line segments with a multi-start gradient based optimization. This should be faster than [Differential Evolution](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html) for a small number of starting points.\n\n```python\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data for four line segments\n# this performs 3 multi-start optimizations\nres = my_pwlf.fitfast(4, pop=3)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n```\n\n![fitfast for specified number of line segments](https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/fitfast.png)\n\n\n## force a fit through data points\n\nSometimes it's necessary to force the piecewise continuous model through a particular data point, or a set of data points. The following example finds the best 4 line segments that go through two data points.\n\n```python\n# initialize piecewise linear fit with your x and y data\nmyPWLF = pwlf.PiecewiseLinFit(x, y)\n\n# fit the function with four line segments\n# force the function to go through the data points\n# (0.0, 0.0) and (0.19, 0.16) \n# where the data points are of the form (x, y)\nx_c = [0.0, 0.19]\ny_c = [0.0, 0.2]\nres = myPWLF.fit(4, x_c, y_c)\n\n# predict for the determined points\nxHat = np.linspace(min(x), 0.19, num=10000)\nyHat = myPWLF.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n```\n\n![force a fit through data points](https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/force.png)\n\n\n## use custom optimization routine\n\nYou can use your favorite optimization routine to find the breakpoint locations. The following example uses scipy's [minimize](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html) function.\n\n```python\nfrom scipy.optimize import minimize\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# initialize custom optimization\nnumber_of_line_segments = 3\nmy_pwlf.use_custom_opt(number_of_line_segments)\n\n# i have number_of_line_segments - 1 number of variables\n# let's guess the correct location of the two unknown variables\n# (the program defaults to have end segments at x0= min(x)\n# and xn=max(x)\nxGuess = np.zeros(number_of_line_segments - 1)\nxGuess[0] = 0.02\nxGuess[1] = 0.10\n\nres = minimize(my_pwlf.fit_with_breaks_opt, xGuess)\n\n# set up the break point locations\nx0 = np.zeros(number_of_line_segments + 1)\nx0[0] = np.min(x)\nx0[-1] = np.max(x)\nx0[1:-1] = res.x\n\n# calculate the parameters based on the optimal break point locations\nmy_pwlf.fit_with_breaks(x0)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n```\n\n\n## pass differential evolution keywords\n\nYou can pass keyword arguments from the ```fit``` function into scipy's  [Differential Evolution](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html).\n\n```python\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data for four line segments\n# this sets DE to have an absolute tolerance of 0.1\nres = my_pwlf.fit(4, atol=0.1)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n```\n\n## find the best number of line segments\n\nThis example uses EGO (bayesian optimization) and a penalty function to find the best number of line segments. This will require careful use of the penalty parameter ```l```. Use this template to automatically find the best number of line segments.\n\n```python\nfrom GPyOpt.methods import BayesianOptimization\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# define your objective function\n\n\ndef my_obj(x):\n    # define some penalty parameter l\n    # you'll have to arbitrarily pick this\n    # it depends upon the noise in your data,\n    # and the value of your sum of square of residuals\n    l = y.mean()*0.001\n    f = np.zeros(x.shape[0])\n    for i, j in enumerate(x):\n        my_pwlf.fit(j[0])\n        f[i] = my_pwlf.ssr + (l*j[0])\n    return f\n\n\n# define the lower and upper bound for the number of line segments\nbounds = [{'name': 'var_1', 'type': 'discrete',\n           'domain': np.arange(2, 40)}]\n\nnp.random.seed(12121)\n\nmyBopt = BayesianOptimization(my_obj, domain=bounds, model_type='GP',\n                              initial_design_numdata=10,\n                              initial_design_type='latin',\n                              exact_feval=True, verbosity=True,\n                              verbosity_model=False)\nmax_iter = 30\n\n# perform the bayesian optimization to find the optimum number\n# of line segments\nmyBopt.run_optimization(max_iter=max_iter, verbosity=True)\n\nprint('\\n \\n Opt found \\n')\nprint('Optimum number of line segments:', myBopt.x_opt)\nprint('Function value:', myBopt.fx_opt)\nmyBopt.plot_acquisition()\nmyBopt.plot_convergence()\n\n# perform the fit for the optimum\nmy_pwlf.fit(myBopt.x_opt)\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n```\n\n## model persistence\n\nYou can save fitted models with pickle. Alternatively see [joblib](https://joblib.readthedocs.io/en/latest/). \n\n```python\n# if you use Python 2.x you should import cPickle\n# import cPickle as pickle\n# if you use Python 3.x you can just use pickle\nimport pickle\n\n# your desired line segment end locations\nx0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data with the specified break points\nmy_pwlf.fit_with_breaks(x0)\n\n# save the fitted model\nwith open('my_fit.pkl', 'wb') as f:\n    pickle.dump(my_pwlf, f, pickle.HIGHEST_PROTOCOL)\n\n# load the fitted model\nwith open('my_fit.pkl', 'rb') as f:\n    my_pwlf = pickle.load(f)\n```\n\n## bad fits when you have more unknowns than data\n\nYou can get very bad fits with pwlf when you have more unknowns than data points. The following example will fit 99 line segments to the 59 data points. While this will result in an error of zero, the model will have very weird predictions within the data. You should not fit more unknowns than you have data with pwlf!\n\n```python\nbreak_locations = np.linspace(min(x), max(x), num=100)\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\nmy_pwlf.fit_with_breaks(break_locations)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n```\n\n![bad fits when you have more unknowns than data](https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/badfit.png)\n\n## fit with a breakpoint guess\n\nIn this example we see two distinct linear regions, and we believe a breakpoint occurs at 6.0. We'll use the fit_guess() function to find the best breakpoint location starting with this guess. These fits should be much faster than the ```fit``` or ```fitfast``` function when you have a reasonable idea where the breakpoints occur.\n\n```python\nimport numpy as np\nimport pwlf\nx = np.array([4., 5., 6., 7., 8.])\ny = np.array([11., 13., 16., 28.92, 42.81])\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\nbreaks = my_pwlf.fit_guess([6.0])\n```\n\nNote specifying one breakpoint will result in two line segments. If we wanted three line segments, we'll have to specify two breakpoints.\n\n```python\nbreaks = my_pwlf.fit_guess([5.5, 6.0])\n```\n\n## get the linear regression matrix\n\nIn some cases it may be desirable to work with the linear regression matrix directly. The following example grabs the linear regression matrix ```A``` for a specific set of breakpoints. In this case we assume that the breakpoints occur at each of the data points. Please see the [paper](https://github.com/cjekel/piecewise_linear_fit_py/tree/master/paper) for details about the regression matrix ```A```.\n\n```python\nimport numpy as np\nimport pwlf\n# select random seed for reproducibility\nnp.random.seed(123)\n# generate sin wave data\nx = np.linspace(0, 10, num=100)\ny = np.sin(x * np.pi / 2)\nytrue = y.copy()\n# add noise to the data\ny = np.random.normal(0, 0.05, 100) + ytrue\n\nmy_pwlf_en = pwlf.PiecewiseLinFit(x, y)\n# copy the x data to use as break points\nbreaks = my_pwlf_en.x_data.copy()\n# create the linear regression matrix A \nA = my_pwlf_en.assemble_regression_matrix(breaks, my_pwlf_en.x_data)\n```\n\nWe can perform fits that are more complicated than a least squares fit when we have the regression matrix. The following uses the Elastic Net regularizer to perform an interesting fit with the regression matrix.\n\n```python\nfrom sklearn.linear_model import ElasticNetCV\n# set up the elastic net\nen_model = ElasticNetCV(cv=5,\n                        l1_ratio=[.1, .5, .7, .9,\n                                  .95, .99, 1],\n                        fit_intercept=False,\n                        max_iter=1000000, n_jobs=-1)\n# fit the model using the elastic net\nen_model.fit(A, my_pwlf_en.y_data)\n\n# predict from the elastic net parameters\nxhat = np.linspace(x.min(), x.max(), 1000)\nyhat_en = my_pwlf_en.predict(xhat, breaks=breaks,\n                             beta=en_model.coef_)\n```\n\n![interesting elastic net fit](https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/sin_en_net_fit.png)\n\n## use of tensorflow\n\nYou need to install [pwlftf](https://github.com/cjekel/piecewise_linear_fit_py_tf) which will have the ```PiecewiseLinFitTF``` class. For performance benchmarks (these benchmarks are outdated! and the regular pwlf may be faster in many applications) see this blog [post](https://jekel.me/2019/Adding-tensorflow-to-pwlf/).\n\nThe use of the TF class is nearly identical to the original class, however note the following exceptions.\n```PiecewiseLinFitTF``` does:\n\n- not have a ```lapack_driver``` option\n- have an optional parameter ```dtype```, so you can choose between the float64 and float32 data types\n- have an optional parameter ```fast``` to switch between Cholesky decomposition (default ```fast=True```), and orthogonal decomposition (```fast=False```)\n\n\n\n```python\nimport pwlftf as pwlf\n# your desired line segment end locations\nx0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n# initialize TF piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFitTF(x, y, dtype='float32)\n\n# fit the data with the specified break points\n# (ie the x locations of where the line segments\n# will terminate)\nmy_pwlf.fit_with_breaks(x0)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n```\n\n## fit constants or polynomials\n\nYou can use pwlf to fit segmented constant models, or piecewise polynomials. The following example fits a segmented constant model, piecewise linear, and a piecewise quadratic model to a sine wave.\n\n```python\n# generate sin wave data\nx = np.linspace(0, 10, num=100)\ny = np.sin(x * np.pi / 2)\n# add noise to the data\ny = np.random.normal(0, 0.05, 100) + y\n\n# initialize piecewise linear fit with your x and y data\n# pwlf lets you fit continuous model for many degree polynomials\n# degree=0 constant\n# degree=1 linear (default)\n# degree=2 quadratic\nmy_pwlf_0 = pwlf.PiecewiseLinFit(x, y, degree=0)\nmy_pwlf_1 = pwlf.PiecewiseLinFit(x, y, degree=1)  # default\nmy_pwlf_2 = pwlf.PiecewiseLinFit(x, y, degree=2)\n\n# fit the data for four line segments\nres0 = my_pwlf_0.fitfast(5, pop=50)\nres1 = my_pwlf_1.fitfast(5, pop=50)\nres2 = my_pwlf_2.fitfast(5, pop=50)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat0 = my_pwlf_0.predict(xHat)\nyHat1 = my_pwlf_1.predict(xHat)\nyHat2 = my_pwlf_2.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o', label='Data')\nplt.plot(xHat, yHat0, '-', label='degree=0')\nplt.plot(xHat, yHat1, '--', label='degree=1')\nplt.plot(xHat, yHat2, ':', label='degree=2')\nplt.legend()\nplt.show()\n```\n\n![Example of multiple degree fits to a sine wave.](https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/multi_degree.png)\n\n## specify breakpoint bounds\n\nYou may want extra control over the search space for feasible breakpoints. One way to do this is to specify the bounds for each breakpoint location.\n\n```python\n# generate sin wave data\nx = np.linspace(0, 10, num=100)\ny = np.sin(x * np.pi / 2)\n# add noise to the data\ny = np.random.normal(0, 0.05, 100) + y\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# define custom bounds for the interior break points\nn_segments = 4\nbounds = np.zeros((n_segments-1, 2))\n# first breakpoint\nbounds[0, 0] = 0.0  # lower bound\nbounds[0, 1] = 3.5  # upper bound\n# second breakpoint\nbounds[1, 0] = 3.0  # lower bound\nbounds[1, 1] = 7.0  # upper bound\n# third breakpoint\nbounds[2, 0] = 6.0  # lower bound\nbounds[2, 1] = 10.0  # upper bound\nres = my_pwlf.fit(n_segments, bounds=bounds)\n```\n\n## non-linear standard errors and p-values\n\nYou can calculate non-linear standard errors using the Delta method. This will calculate the standard errors of the piecewise linear parameters (intercept + slopes) and the breakpoint locations!\n\nFirst let us generate true piecewise linear data.\n\n```python\nfrom __future__ import print_function\n# generate a true piecewise linear data\nnp.random.seed(5)\nn_data = 100\nx = np.linspace(0, 1, num=n_data)\ny = np.random.random(n_data)\nmy_pwlf_gen = pwlf.PiecewiseLinFit(x, y)\ntrue_beta = np.random.normal(size=5)\ntrue_breaks = np.array([0.0, 0.2, 0.5, 0.75, 1.0])\ny = my_pwlf_gen.predict(x, beta=true_beta, breaks=true_breaks)\n\nplt.figure()\nplt.title('True piecewise linear data')\nplt.plot(x, y)\nplt.show()\n```\n\n![True piecewise linear data.](https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/true_pwlf.png)\n\nNow we can perform a fit, calculate the standard errors, and p-values. The non-linear method uses a first order taylor series expansion to linearize the non-linear regression problem. A positive step_size performs a forward difference, and a negative step_size would perform a backwards difference.\n\n```python\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\nres = my_pwlf.fitfast(4, pop=100)\n\np = my_pwlf.p_values(method='non-linear', step_size=1e-4)\nse = my_pwlf.se  # standard errors\n```\n\nThe standard errors and p-values correspond to each model parameter. First the beta parameters (intercept + slopes) and then the breakpoints. We can assemble the parameters, and print a table of the result with the following code. \n\n```python\nparameters = np.concatenate((my_pwlf.beta,\n                             my_pwlf.fit_breaks[1:-1]))\n\nheader = ['Parameter type', 'Parameter value', 'Standard error', 't',\n          'P > np.abs(t) (p-value)']\nprint(*header, sep=' | ')\nvalues = np.zeros((parameters.size, 5), dtype=np.object_)\nvalues[:, 1] = np.around(parameters, decimals=3)\nvalues[:, 2] = np.around(se, decimals=3)\nvalues[:, 3] = np.around(parameters / se, decimals=3)\nvalues[:, 4] = np.around(p, decimals=3)\n\nfor i, row in enumerate(values):\n    if i < my_pwlf.beta.size:\n        row[0] = 'Beta'\n        print(*row, sep=' | ')\n    else:\n        row[0] = 'Breakpoint'\n        print(*row, sep=' | ')\n```\n\n| Parameter type | Parameter value | Standard error | t | P > np.abs(t) (p-value) |\n| ------------- | --------------- | -------------- |---| ----------------------- |\n| Beta | 1.821 | 0.0 | 1763191476.046 | 0.0 |\n| Beta | -0.427 | 0.0 | -46404554.493 | 0.0 |\n| Beta | -1.165 | 0.0 | -111181494.162 | 0.0 |\n| Beta | -1.397 | 0.0 | -168954500.421 | 0.0 |\n| Beta | 0.873 | 0.0 | 93753841.242 | 0.0 |\n| Breakpoint | 0.2 | 0.0 | 166901856.885 | 0.0 |\n| Breakpoint | 0.5 | 0.0 | 537785803.646 | 0.0 |\n| Breakpoint | 0.75 | 0.0 | 482311769.159 | 0.0 |\n\n## obtain the equations of fitted pwlf\n\nSometimes you may want the mathematical equations that represent your fitted model. This is easy to perform if you don't mind using sympy.\n\nThe following code will fit 5 line segments of degree=2 to a sin wave.\n```python\nimport numpy as np\nimport pwlf\n# generate sin wave data\nx = np.linspace(0, 10, num=100)\ny = np.sin(x * np.pi / 2)\n# add noise to the data\ny = np.random.normal(0, 0.05, 100) + y\nmy_pwlf_2 = pwlf.PiecewiseLinFit(x, y, degree=2)\nres2 = my_pwlf_2.fitfast(5, pop=50)\n```\n\nGiven this fit, the following code will print the mathematical equation for each line segment.\n```python\nfrom sympy import Symbol\nfrom sympy.utilities import lambdify\nx = Symbol('x')\n\n\ndef get_symbolic_eqn(pwlf_, segment_number):\n    if pwlf_.degree < 1:\n        raise ValueError('Degree must be at least 1')\n    if segment_number < 1 or segment_number > pwlf_.n_segments:\n        raise ValueError('segment_number not possible')\n    # assemble degree = 1 first\n    for line in range(segment_number):\n        if line == 0:\n            my_eqn = pwlf_.beta[0] + (pwlf_.beta[1])*(x-pwlf_.fit_breaks[0])\n        else:\n            my_eqn += (pwlf_.beta[line+1])*(x-pwlf_.fit_breaks[line])\n    # assemble all other degrees\n    if pwlf_.degree > 1:\n        for k in range(2, pwlf_.degree + 1):\n            for line in range(segment_number):\n                beta_index = pwlf_.n_segments*(k-1) + line + 1 \n                my_eqn += (pwlf_.beta[beta_index])*(x-pwlf_.fit_breaks[line])**k\n    return my_eqn.simplify()\n\n\neqn_list = []\nf_list = []\nfor i in range(my_pwlf_2.n_segments):\n    eqn_list.append(get_symbolic_eqn(my_pwlf_2, i + 1))\n    print('Equation number: ', i + 1)\n    print(eqn_list[-1])\n    f_list.append(lambdify(x, eqn_list[-1]))\n```\n\nwhich should print out something like the following:\n```python\nEquation number:  1\n-0.953964059782599*x**2 + 1.89945177490653*x + 0.00538634182565454\nEquation number:  2\n0.951561315686298*x**2 - 5.69747505830914*x + 7.5772216545711\nEquation number:  3\n-0.949735350431857*x**2 + 9.48218236957122*x - 22.720785454735\nEquation number:  4\n0.926850298824217*x**2 - 12.9824424358344*x + 44.5102742956827\nEquation number:  5\n-1.03016230425747*x**2 + 18.5306546317065*x - 82.3508513333073\n```\n\nFor more information on how this works, see [this](https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/understanding_higher_degrees/polynomials_in_pwlf.ipynb) jupyter notebook.\n\n## weighted least squares fit\n\nSometimes your data will not have a constant variance (heteroscedasticity), and you need to perform a weighted least squares fit. The following example will perform a standard and weighted fit so you can compare the differences. First we need to generate a data set which will be a good candidate to use for weighted least squares fits.\n\n```python\n# generate data with heteroscedasticity\nn = 100\nn_data_sets = 100\nn_segments = 6\n# generate sine data\nx = np.linspace(0, 10, n)\ny = np.zeros((n_data_sets, n))\nsigma_change = np.linspace(0.001, 0.05, 100)\nfor i in range(n_data_sets):\n    y[i] = np.sin(x * np.pi / 2)\n    # add noise to the data\n    y[i] = np.random.normal(0, sigma_change, 100) + y[i]\nX = np.tile(x, n_data_sets)\n```\n\nThe individual weights in pwlf are the reciprocal of the standard deviation for each data point. Here weights[i] corresponds to one over the standard deviation of the ith data point. The result of this is that data points with higher variance are less important to the overall pwlf than data point with small variance. Let's perform a standard pwlf fit and a weighted fit.\n\n```python\n# perform an ordinary pwlf fit to the entire data\nmy_pwlf = pwlf.PiecewiseLinFit(X.flatten(), y.flatten())\nmy_pwlf.fit(n_segments)\n\n# compute the standard deviation in y\ny_std = np.std(y, axis=0)\n# set the weights to be one over the standard deviation\nweights = 1.0 / y_std\n\n# perform a weighted least squares to the data\nmy_pwlf_w = pwlf.PiecewiseLinFit(x, y.mean(axis=0), weights=weights)\nmy_pwlf_w.fit(n_segments)\n\n# compare the fits\nxhat = np.linspace(0, 10, 1000)\nyhat = my_pwlf.predict(xhat)\nyhat_w = my_pwlf_w.predict(xhat)\n\nplt.figure()\nplt.plot(X.flatten(), y.flatten(), '.')\nplt.plot(xhat, yhat, '-', label='Ordinary LS')\nplt.plot(xhat, yhat_w, '-', label='Weighted LS')\nplt.legend()\nplt.show()\n```\n\n![Weighted pwlf fit.](https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/weighted_least_squares_example.png)\n\nWe can see that the weighted pwlf fit tries fit data with low variance better than data with high variance, however the ordinary pwlf fits the data assuming a uniform variance.\n\n## reproducible results\n\nThe `fit` and `fitfast` methods are stochastic and may not give the same\nresult every time the program is run. To have reproducible results you can\nmanually specify a numpy.random.seed on init. Now everytime the following\nprogram is run, the results of the fit(2) should be the same.\n\n```python\n\n# initialize piecewise linear fit with a random seed\nmy_pwlf = pwlf.PiecewiseLinFit(x, y, seed=123)\n\n# Now the fit() method will be reproducible\nmy_pwlf.fit(2)\n```\n"
  },
  {
    "path": "examples/README.rst",
    "content": "Examples\n========\n\nAll of these examples will use the following data and imports.\n\n.. code:: python\n\n   import numpy as np\n   import matplotlib.pyplot as plt\n   import pwlf\n\n   # your data\n   y = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n                 4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n                 8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n                 1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n                 8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n                 4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n                 5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n                 7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n                 1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n                 1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n                 3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n                 6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n                 1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n                 1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n                 5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n                 9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n                 0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n                 4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n                 8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n                 1.41881288e-01, 1.62618058e-01])\n   x = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n                 5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n                 1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n                 1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n                 7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n                 4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n                 7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n                 1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n                 1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n                 1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n                 3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n                 1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n                 1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n                 1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n                 7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n                 1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n                 0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n                 6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n                 1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n                 1.65299640e-01, 1.79942720e-01])\n\n1.  `fit with known breakpoint\n    locations <#fit-with-known-breakpoint-locations>`__\n2.  `fit for specified number of line\n    segments <#fit-for-specified-number-of-line-segments>`__\n3.  `fitfast for specified number of line\n    segments <#fitfast-for-specified-number-of-line-segments>`__\n4.  `force a fit through data\n    points <#force-a-fit-through-data-points>`__\n5.  `use custom optimization\n    routine <#use-custom-optimization-routine>`__\n6.  `pass differential evolution\n    keywords <#pass-differential-evolution-keywords>`__\n7.  `find the best number of line\n    segments <#find-the-best-number-of-line-segments>`__\n8.  `model persistence <#model-persistence>`__\n9.  `bad fits when you have more unknowns than\n    data <#bad-fits-when-you-have-more-unknowns-than-data>`__\n10. `fit with a breakpoint guess <#fit-with-a-breakpoint-guess>`__\n11. `get the linear regression\n    matrix <#get-the-linear-regression-matrix>`__\n12. `use of TensorFlow <#use-of-tensorflow>`__\n13. `fit constants or polynomials <#fit-constants-or-polynomials>`__\n14. `specify breakpoint bounds <#specify-breakpoint-bounds>`__\n15. `non-linear standard errors and\n    p-values <#non-linear-standard-errors-and-p-values>`__\n16. `obtain the equations of fitted\n    pwlf <#obtain-the-equations-of-fitted-pwlf>`__\n17. `weighted least squares fit <#weighted-least-squares-fit>`__\n18. `reproducible results <#reproducible results>`__\n\nfit with known breakpoint locations\n-----------------------------------\n\nYou can perform a least squares fit if you know the breakpoint\nlocations.\n\n.. code:: python\n\n   # your desired line segment end locations\n   x0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data with the specified break points\n   # (ie the x locations of where the line segments\n   # will terminate)\n   my_pwlf.fit_with_breaks(x0)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/fit_breaks.png\n   :alt: fit with known breakpoint locations\n\n   fit with known breakpoint locations\n\nfit for specified number of line segments\n-----------------------------------------\n\nUse a global optimization to find the breakpoint locations that minimize\nthe sum of squares error. This uses `Differential\nEvolution <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html>`__\nfrom scipy.\n\n.. code:: python\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data for four line segments\n   res = my_pwlf.fit(4)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/numberoflines.png\n   :alt: fit for specified number of line segments\n\n   fit for specified number of line segments\n\nfitfast for specified number of line segments\n---------------------------------------------\n\nThis performs a fit for a specified number of line segments with a\nmulti-start gradient based optimization. This should be faster than\n`Differential\nEvolution <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html>`__\nfor a small number of starting points.\n\n.. code:: python\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data for four line segments\n   # this performs 3 multi-start optimizations\n   res = my_pwlf.fitfast(4, pop=3)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/fitfast.png\n   :alt: fitfast for specified number of line segments\n\n   fitfast for specified number of line segments\n\nforce a fit through data points\n-------------------------------\n\nSometimes it’s necessary to force the piecewise continuous model through\na particular data point, or a set of data points. The following example\nfinds the best 4 line segments that go through two data points.\n\n.. code:: python\n\n   # initialize piecewise linear fit with your x and y data\n   myPWLF = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the function with four line segments\n   # force the function to go through the data points\n   # (0.0, 0.0) and (0.19, 0.16) \n   # where the data points are of the form (x, y)\n   x_c = [0.0, 0.19]\n   y_c = [0.0, 0.2]\n   res = myPWLF.fit(4, x_c, y_c)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), 0.19, num=10000)\n   yHat = myPWLF.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/force.png\n   :alt: force a fit through data points\n\n   force a fit through data points\n\nuse custom optimization routine\n-------------------------------\n\nYou can use your favorite optimization routine to find the breakpoint\nlocations. The following example uses scipy’s\n`minimize <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html>`__\nfunction.\n\n.. code:: python\n\n   from scipy.optimize import minimize\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # initialize custom optimization\n   number_of_line_segments = 3\n   my_pwlf.use_custom_opt(number_of_line_segments)\n\n   # i have number_of_line_segments - 1 number of variables\n   # let's guess the correct location of the two unknown variables\n   # (the program defaults to have end segments at x0= min(x)\n   # and xn=max(x)\n   xGuess = np.zeros(number_of_line_segments - 1)\n   xGuess[0] = 0.02\n   xGuess[1] = 0.10\n\n   res = minimize(my_pwlf.fit_with_breaks_opt, xGuess)\n\n   # set up the break point locations\n   x0 = np.zeros(number_of_line_segments + 1)\n   x0[0] = np.min(x)\n   x0[-1] = np.max(x)\n   x0[1:-1] = res.x\n\n   # calculate the parameters based on the optimal break point locations\n   my_pwlf.fit_with_breaks(x0)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\npass differential evolution keywords\n------------------------------------\n\nYou can pass keyword arguments from the ``fit`` function into scipy’s\n`Differential\nEvolution <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html>`__.\n\n.. code:: python\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data for four line segments\n   # this sets DE to have an absolute tolerance of 0.1\n   res = my_pwlf.fit(4, atol=0.1)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\nfind the best number of line segments\n-------------------------------------\n\nThis example uses EGO (bayesian optimization) and a penalty function to\nfind the best number of line segments. This will require careful use of\nthe penalty parameter ``l``. Use this template to automatically find the\nbest number of line segments.\n\n.. code:: python\n\n   from GPyOpt.methods import BayesianOptimization\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # define your objective function\n\n\n   def my_obj(x):\n       # define some penalty parameter l\n       # you'll have to arbitrarily pick this\n       # it depends upon the noise in your data,\n       # and the value of your sum of square of residuals\n       l = y.mean()*0.001\n       f = np.zeros(x.shape[0])\n       for i, j in enumerate(x):\n           my_pwlf.fit(j[0])\n           f[i] = my_pwlf.ssr + (l*j[0])\n       return f\n\n\n   # define the lower and upper bound for the number of line segments\n   bounds = [{'name': 'var_1', 'type': 'discrete',\n              'domain': np.arange(2, 40)}]\n\n   np.random.seed(12121)\n\n   myBopt = BayesianOptimization(my_obj, domain=bounds, model_type='GP',\n                                 initial_design_numdata=10,\n                                 initial_design_type='latin',\n                                 exact_feval=True, verbosity=True,\n                                 verbosity_model=False)\n   max_iter = 30\n\n   # perform the bayesian optimization to find the optimum number\n   # of line segments\n   myBopt.run_optimization(max_iter=max_iter, verbosity=True)\n\n   print('\\n \\n Opt found \\n')\n   print('Optimum number of line segments:', myBopt.x_opt)\n   print('Function value:', myBopt.fx_opt)\n   myBopt.plot_acquisition()\n   myBopt.plot_convergence()\n\n   # perform the fit for the optimum\n   my_pwlf.fit(myBopt.x_opt)\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\nmodel persistence\n-----------------\n\nYou can save fitted models with pickle. Alternatively see\n`joblib <https://joblib.readthedocs.io/en/latest/>`__.\n\n.. code:: python\n\n   # if you use Python 2.x you should import cPickle\n   # import cPickle as pickle\n   # if you use Python 3.x you can just use pickle\n   import pickle\n\n   # your desired line segment end locations\n   x0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data with the specified break points\n   my_pwlf.fit_with_breaks(x0)\n\n   # save the fitted model\n   with open('my_fit.pkl', 'wb') as f:\n       pickle.dump(my_pwlf, f, pickle.HIGHEST_PROTOCOL)\n\n   # load the fitted model\n   with open('my_fit.pkl', 'rb') as f:\n       my_pwlf = pickle.load(f)\n\nbad fits when you have more unknowns than data\n----------------------------------------------\n\nYou can get very bad fits with pwlf when you have more unknowns than\ndata points. The following example will fit 99 line segments to the 59\ndata points. While this will result in an error of zero, the model will\nhave very weird predictions within the data. You should not fit more\nunknowns than you have data with pwlf!\n\n.. code:: python\n\n   break_locations = np.linspace(min(x), max(x), num=100)\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n   my_pwlf.fit_with_breaks(break_locations)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/badfit.png\n   :alt: bad fits when you have more unknowns than data\n\n   bad fits when you have more unknowns than data\n\nfit with a breakpoint guess\n---------------------------\n\nIn this example we see two distinct linear regions, and we believe a\nbreakpoint occurs at 6.0. We’ll use the fit_guess() function to find the\nbest breakpoint location starting with this guess. These fits should be\nmuch faster than the ``fit`` or ``fitfast`` function when you have a\nreasonable idea where the breakpoints occur.\n\n.. code:: python\n\n   import numpy as np\n   import pwlf\n   x = np.array([4., 5., 6., 7., 8.])\n   y = np.array([11., 13., 16., 28.92, 42.81])\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n   breaks = my_pwlf.fit_guess([6.0])\n\nNote specifying one breakpoint will result in two line segments. If we\nwanted three line segments, we’ll have to specify two breakpoints.\n\n.. code:: python\n\n   breaks = my_pwlf.fit_guess([5.5, 6.0])\n\nget the linear regression matrix\n--------------------------------\n\nIn some cases it may be desirable to work with the linear regression\nmatrix directly. The following example grabs the linear regression\nmatrix ``A`` for a specific set of breakpoints. In this case we assume\nthat the breakpoints occur at each of the data points. Please see the\n`paper <https://github.com/cjekel/piecewise_linear_fit_py/tree/master/paper>`__\nfor details about the regression matrix ``A``.\n\n.. code:: python\n\n   import numpy as np\n   import pwlf\n   # select random seed for reproducibility\n   np.random.seed(123)\n   # generate sin wave data\n   x = np.linspace(0, 10, num=100)\n   y = np.sin(x * np.pi / 2)\n   ytrue = y.copy()\n   # add noise to the data\n   y = np.random.normal(0, 0.05, 100) + ytrue\n\n   my_pwlf_en = pwlf.PiecewiseLinFit(x, y)\n   # copy the x data to use as break points\n   breaks = my_pwlf_en.x_data.copy()\n   # create the linear regression matrix A \n   A = my_pwlf_en.assemble_regression_matrix(breaks, my_pwlf_en.x_data)\n\nWe can perform fits that are more complicated than a least squares fit\nwhen we have the regression matrix. The following uses the Elastic Net\nregularizer to perform an interesting fit with the regression matrix.\n\n.. code:: python\n\n   from sklearn.linear_model import ElasticNetCV\n   # set up the elastic net\n   en_model = ElasticNetCV(cv=5,\n                           l1_ratio=[.1, .5, .7, .9,\n                                     .95, .99, 1],\n                           fit_intercept=False,\n                           max_iter=1000000, n_jobs=-1)\n   # fit the model using the elastic net\n   en_model.fit(A, my_pwlf_en.y_data)\n\n   # predict from the elastic net parameters\n   xhat = np.linspace(x.min(), x.max(), 1000)\n   yhat_en = my_pwlf_en.predict(xhat, breaks=breaks,\n                                beta=en_model.coef_)\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/sin_en_net_fit.png\n   :alt: interesting elastic net fit\n\n   interesting elastic net fit\n\nuse of tensorflow\n-----------------\n\nYou need to install\n`pwlftf <https://github.com/cjekel/piecewise_linear_fit_py_tf>`__ which\nwill have the ``PiecewiseLinFitTF`` class. For performance benchmarks\n(these benchmarks are outdated! and the regular pwlf may be faster in\nmany applications) see this blog\n`post <https://jekel.me/2019/Adding-tensorflow-to-pwlf/>`__.\n\nThe use of the TF class is nearly identical to the original class,\nhowever note the following exceptions. ``PiecewiseLinFitTF`` does:\n\n-  not have a ``lapack_driver`` option\n-  have an optional parameter ``dtype``, so you can choose between the\n   float64 and float32 data types\n-  have an optional parameter ``fast`` to switch between Cholesky\n   decomposition (default ``fast=True``), and orthogonal decomposition\n   (``fast=False``)\n\n.. code:: python\n\n   import pwlftf as pwlf\n   # your desired line segment end locations\n   x0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n   # initialize TF piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFitTF(x, y, dtype='float32)\n\n   # fit the data with the specified break points\n   # (ie the x locations of where the line segments\n   # will terminate)\n   my_pwlf.fit_with_breaks(x0)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\nfit constants or polynomials\n----------------------------\n\nYou can use pwlf to fit segmented constant models, or piecewise\npolynomials. The following example fits a segmented constant model,\npiecewise linear, and a piecewise quadratic model to a sine wave.\n\n.. code:: python\n\n   # generate sin wave data\n   x = np.linspace(0, 10, num=100)\n   y = np.sin(x * np.pi / 2)\n   # add noise to the data\n   y = np.random.normal(0, 0.05, 100) + y\n\n   # initialize piecewise linear fit with your x and y data\n   # pwlf lets you fit continuous model for many degree polynomials\n   # degree=0 constant\n   # degree=1 linear (default)\n   # degree=2 quadratic\n   my_pwlf_0 = pwlf.PiecewiseLinFit(x, y, degree=0)\n   my_pwlf_1 = pwlf.PiecewiseLinFit(x, y, degree=1)  # default\n   my_pwlf_2 = pwlf.PiecewiseLinFit(x, y, degree=2)\n\n   # fit the data for four line segments\n   res0 = my_pwlf_0.fitfast(5, pop=50)\n   res1 = my_pwlf_1.fitfast(5, pop=50)\n   res2 = my_pwlf_2.fitfast(5, pop=50)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat0 = my_pwlf_0.predict(xHat)\n   yHat1 = my_pwlf_1.predict(xHat)\n   yHat2 = my_pwlf_2.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o', label='Data')\n   plt.plot(xHat, yHat0, '-', label='degree=0')\n   plt.plot(xHat, yHat1, '--', label='degree=1')\n   plt.plot(xHat, yHat2, ':', label='degree=2')\n   plt.legend()\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/multi_degree.png\n   :alt: Example of multiple degree fits to a sine wave.\n\n   Example of multiple degree fits to a sine wave.\n\nspecify breakpoint bounds\n-------------------------\n\nYou may want extra control over the search space for feasible\nbreakpoints. One way to do this is to specify the bounds for each\nbreakpoint location.\n\n.. code:: python\n\n   # generate sin wave data\n   x = np.linspace(0, 10, num=100)\n   y = np.sin(x * np.pi / 2)\n   # add noise to the data\n   y = np.random.normal(0, 0.05, 100) + y\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # define custom bounds for the interior break points\n   n_segments = 4\n   bounds = np.zeros((n_segments-1, 2))\n   # first breakpoint\n   bounds[0, 0] = 0.0  # lower bound\n   bounds[0, 1] = 3.5  # upper bound\n   # second breakpoint\n   bounds[1, 0] = 3.0  # lower bound\n   bounds[1, 1] = 7.0  # upper bound\n   # third breakpoint\n   bounds[2, 0] = 6.0  # lower bound\n   bounds[2, 1] = 10.0  # upper bound\n   res = my_pwlf.fit(n_segments, bounds=bounds)\n\nnon-linear standard errors and p-values\n---------------------------------------\n\nYou can calculate non-linear standard errors using the Delta method.\nThis will calculate the standard errors of the piecewise linear\nparameters (intercept + slopes) and the breakpoint locations!\n\nFirst let us generate true piecewise linear data.\n\n.. code:: python\n\n   from __future__ import print_function\n   # generate a true piecewise linear data\n   np.random.seed(5)\n   n_data = 100\n   x = np.linspace(0, 1, num=n_data)\n   y = np.random.random(n_data)\n   my_pwlf_gen = pwlf.PiecewiseLinFit(x, y)\n   true_beta = np.random.normal(size=5)\n   true_breaks = np.array([0.0, 0.2, 0.5, 0.75, 1.0])\n   y = my_pwlf_gen.predict(x, beta=true_beta, breaks=true_breaks)\n\n   plt.figure()\n   plt.title('True piecewise linear data')\n   plt.plot(x, y)\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/true_pwlf.png\n   :alt: True piecewise linear data.\n\n   True piecewise linear data.\n\nNow we can perform a fit, calculate the standard errors, and p-values.\nThe non-linear method uses a first order taylor series expansion to\nlinearize the non-linear regression problem. A positive step_size\nperforms a forward difference, and a negative step_size would perform a\nbackwards difference.\n\n.. code:: python\n\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n   res = my_pwlf.fitfast(4, pop=100)\n\n   p = my_pwlf.p_values(method='non-linear', step_size=1e-4)\n   se = my_pwlf.se  # standard errors\n\nThe standard errors and p-values correspond to each model parameter.\nFirst the beta parameters (intercept + slopes) and then the breakpoints.\nWe can assemble the parameters, and print a table of the result with the\nfollowing code.\n\n.. code:: python\n\n   parameters = np.concatenate((my_pwlf.beta,\n                                my_pwlf.fit_breaks[1:-1]))\n\n   header = ['Parameter type', 'Parameter value', 'Standard error', 't',\n             'P > np.abs(t) (p-value)']\n   print(*header, sep=' | ')\n   values = np.zeros((parameters.size, 5), dtype=np.object_)\n   values[:, 1] = np.around(parameters, decimals=3)\n   values[:, 2] = np.around(se, decimals=3)\n   values[:, 3] = np.around(parameters / se, decimals=3)\n   values[:, 4] = np.around(p, decimals=3)\n\n   for i, row in enumerate(values):\n       if i < my_pwlf.beta.size:\n           row[0] = 'Beta'\n           print(*row, sep=' | ')\n       else:\n           row[0] = 'Breakpoint'\n           print(*row, sep=' | ')\n\n============== =============== ============== ============== =======================\nParameter type Parameter value Standard error t              P > np.abs(t) (p-value)\n============== =============== ============== ============== =======================\nBeta           1.821           0.0            1763191476.046 0.0\nBeta           -0.427          0.0            -46404554.493  0.0\nBeta           -1.165          0.0            -111181494.162 0.0\nBeta           -1.397          0.0            -168954500.421 0.0\nBeta           0.873           0.0            93753841.242   0.0\nBreakpoint     0.2             0.0            166901856.885  0.0\nBreakpoint     0.5             0.0            537785803.646  0.0\nBreakpoint     0.75            0.0            482311769.159  0.0\n============== =============== ============== ============== =======================\n\nobtain the equations of fitted pwlf\n-----------------------------------\n\nSometimes you may want the mathematical equations that represent your\nfitted model. This is easy to perform if you don’t mind using sympy.\n\nThe following code will fit 5 line segments of degree=2 to a sin wave.\n\n.. code:: python\n\n   import numpy as np\n   import pwlf\n   # generate sin wave data\n   x = np.linspace(0, 10, num=100)\n   y = np.sin(x * np.pi / 2)\n   # add noise to the data\n   y = np.random.normal(0, 0.05, 100) + y\n   my_pwlf_2 = pwlf.PiecewiseLinFit(x, y, degree=2)\n   res2 = my_pwlf_2.fitfast(5, pop=50)\n\nGiven this fit, the following code will print the mathematical equation\nfor each line segment.\n\n.. code:: python\n\n   from sympy import Symbol\n   from sympy.utilities import lambdify\n   x = Symbol('x')\n\n\n   def get_symbolic_eqn(pwlf_, segment_number):\n       if pwlf_.degree < 1:\n           raise ValueError('Degree must be at least 1')\n       if segment_number < 1 or segment_number > pwlf_.n_segments:\n           raise ValueError('segment_number not possible')\n       # assemble degree = 1 first\n       for line in range(segment_number):\n           if line == 0:\n               my_eqn = pwlf_.beta[0] + (pwlf_.beta[1])*(x-pwlf_.fit_breaks[0])\n           else:\n               my_eqn += (pwlf_.beta[line+1])*(x-pwlf_.fit_breaks[line])\n       # assemble all other degrees\n       if pwlf_.degree > 1:\n           for k in range(2, pwlf_.degree + 1):\n               for line in range(segment_number):\n                   beta_index = pwlf_.n_segments*(k-1) + line + 1 \n                   my_eqn += (pwlf_.beta[beta_index])*(x-pwlf_.fit_breaks[line])**k\n       return my_eqn.simplify()\n\n\n   eqn_list = []\n   f_list = []\n   for i in range(my_pwlf_2.n_segments):\n       eqn_list.append(get_symbolic_eqn(my_pwlf_2, i + 1))\n       print('Equation number: ', i + 1)\n       print(eqn_list[-1])\n       f_list.append(lambdify(x, eqn_list[-1]))\n\nwhich should print out something like the following:\n\n.. code:: python\n\n   Equation number:  1\n   -0.953964059782599*x**2 + 1.89945177490653*x + 0.00538634182565454\n   Equation number:  2\n   0.951561315686298*x**2 - 5.69747505830914*x + 7.5772216545711\n   Equation number:  3\n   -0.949735350431857*x**2 + 9.48218236957122*x - 22.720785454735\n   Equation number:  4\n   0.926850298824217*x**2 - 12.9824424358344*x + 44.5102742956827\n   Equation number:  5\n   -1.03016230425747*x**2 + 18.5306546317065*x - 82.3508513333073\n\nFor more information on how this works, see\n`this <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/understanding_higher_degrees/polynomials_in_pwlf.ipynb>`__\njupyter notebook.\n\nweighted least squares fit\n--------------------------\n\nSometimes your data will not have a constant variance\n(heteroscedasticity), and you need to perform a weighted least squares\nfit. The following example will perform a standard and weighted fit so\nyou can compare the differences. First we need to generate a data set\nwhich will be a good candidate to use for weighted least squares fits.\n\n.. code:: python\n\n   # generate data with heteroscedasticity\n   n = 100\n   n_data_sets = 100\n   n_segments = 6\n   # generate sine data\n   x = np.linspace(0, 10, n)\n   y = np.zeros((n_data_sets, n))\n   sigma_change = np.linspace(0.001, 0.05, 100)\n   for i in range(n_data_sets):\n       y[i] = np.sin(x * np.pi / 2)\n       # add noise to the data\n       y[i] = np.random.normal(0, sigma_change, 100) + y[i]\n   X = np.tile(x, n_data_sets)\n\nThe individual weights in pwlf are the reciprocal of the standard\ndeviation for each data point. Here weights[i] corresponds to one over\nthe standard deviation of the ith data point. The result of this is that\ndata points with higher variance are less important to the overall pwlf\nthan data point with small variance. Let’s perform a standard pwlf fit\nand a weighted fit.\n\n.. code:: python\n\n   # perform an ordinary pwlf fit to the entire data\n   my_pwlf = pwlf.PiecewiseLinFit(X.flatten(), y.flatten())\n   my_pwlf.fit(n_segments)\n\n   # compute the standard deviation in y\n   y_std = np.std(y, axis=0)\n   # set the weights to be one over the standard deviation\n   weights = 1.0 / y_std\n\n   # perform a weighted least squares to the data\n   my_pwlf_w = pwlf.PiecewiseLinFit(x, y.mean(axis=0), weights=weights)\n   my_pwlf_w.fit(n_segments)\n\n   # compare the fits\n   xhat = np.linspace(0, 10, 1000)\n   yhat = my_pwlf.predict(xhat)\n   yhat_w = my_pwlf_w.predict(xhat)\n\n   plt.figure()\n   plt.plot(X.flatten(), y.flatten(), '.')\n   plt.plot(xhat, yhat, '-', label='Ordinary LS')\n   plt.plot(xhat, yhat_w, '-', label='Weighted LS')\n   plt.legend()\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/weighted_least_squares_example.png\n   :alt: Weighted pwlf fit.\n\n   Weighted pwlf fit.\n\nWe can see that the weighted pwlf fit tries fit data with low variance\nbetter than data with high variance, however the ordinary pwlf fits the\ndata assuming a uniform variance.\n\nreproducible results\n--------------------\n\nThe `fit` and `fitfast` methods are stochastic and may not give the same\nresult every time the program is run. To have reproducible results you can\nmanually specify a numpy.random.seed on init. Now everytime the following\nprogram is run, the results of the fit(2) should be the same.\n\n.. code:: python\n\n   # initialize piecewise linear fit with a random seed\n   my_pwlf = pwlf.PiecewiseLinFit(x, y, seed=123)\n\n   # Now the fit() method will be reproducible\n   my_pwlf.fit(2)\n\n"
  },
  {
    "path": "examples/experiment_with_batch_process.py.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"import numpy as np\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"import pwlf\\n\",\n    \"%matplotlib inline\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"np.random.seed(123)\\n\",\n    \"n = 100\\n\",\n    \"n_data_sets = 100\\n\",\n    \"n_segments = 6\\n\",\n    \"# generate sine data\\n\",\n    \"x = np.linspace(0, 10, n)\\n\",\n    \"y = np.zeros((n_data_sets, n))\\n\",\n    \"for i in range(n_data_sets):\\n\",\n    \"    y[i] = np.sin(x * np.pi / 2)\\n\",\n    \"    # add noise to the data\\n\",\n    \"    y[i] = np.random.normal(0, 0.05, 100) + y[i]\\n\",\n    \"X = np.tile(x, n_data_sets)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\\n\",\n      \"text/plain\": [\n       \"<Figure size 432x288 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# plot all of the data\\n\",\n    \"plt.figure()\\n\",\n    \"plt.plot(X.flatten(), y.flatten(), '.')\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 4,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"array([ 0.        ,  1.05164435,  2.98570544,  5.00010778,  7.01335991,\\n\",\n       \"        8.94940776, 10.        ])\"\n      ]\n     },\n     \"execution_count\": 4,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"# perform a single fit to all of the data\\n\",\n    \"my_pwlf_global = pwlf.PiecewiseLinFit(X.flatten(), y.flatten())\\n\",\n    \"my_pwlf_global.fit(n_segments)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 5,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\\n\",\n      \"text/plain\": [\n       \"<Figure size 432x288 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# plot all of the data with global fit\\n\",\n    \"yhat = my_pwlf_global.predict(x)\\n\",\n    \"plt.figure()\\n\",\n    \"plt.plot(X.flatten(), y.flatten(), '.')\\n\",\n    \"plt.plot(x, yhat, '-')\\n\",\n    \"plt.plot()\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 6,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# for each data set, fit a pwlf model using the global breaks\\n\",\n    \"my_pwlf_models = []\\n\",\n    \"slopes = []\\n\",\n    \"for i in range(n_data_sets):\\n\",\n    \"    temp_pwlf = pwlf.PiecewiseLinFit(x, y[i])\\n\",\n    \"    temp_pwlf.fit_with_breaks(my_pwlf_global.fit_breaks)\\n\",\n    \"    my_pwlf_models.append(temp_pwlf)\\n\",\n    \"    slopes.append(temp_pwlf.slopes)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 7,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"[ 1.01504066 -1.24340053  1.2084571  -1.21045573  1.24507127 -1.02114751]\\n\",\n      \"[ 1.01504066 -1.24340053  1.2084571  -1.21045573  1.24507127 -1.02114751]\\n\",\n      \"[0.03299628 0.01432216 0.01273798 0.01173331 0.01313007 0.03130695]\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"slopes = np.array(slopes)\\n\",\n    \"print(my_pwlf_global.slopes)\\n\",\n    \"print(slopes.mean(axis=0))\\n\",\n    \"print(slopes.std(axis=0))\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": []\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"Python 3\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.6.10\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 4\n}\n"
  },
  {
    "path": "examples/fitForSpecifiedNumberOfLineSegments.py",
    "content": "# fit for a specified number of line segments\n# you specify the number of line segments you want, the library does the rest\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data for four line segments\nres = my_pwlf.fit(4)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# Get the slopes\nmy_slopes = my_pwlf.slopes\n\n# Get my model parameters\nbeta = my_pwlf.beta\n\n# calculate the standard errors associated with each beta parameter\nse = my_pwlf.standard_errors()\n\n# calcualte the R^2 value\nRsquared = my_pwlf.r_squared()\n\n# calculate the piecewise R^2 value\nR2values = np.zeros(my_pwlf.n_segments)\nfor i in range(my_pwlf.n_segments):\n    # segregate the data based on break point locations\n    xmin = my_pwlf.fit_breaks[i]\n    xmax = my_pwlf.fit_breaks[i+1]\n    xtemp = my_pwlf.x_data\n    ytemp = my_pwlf.y_data\n    indtemp = np.where(xtemp >= xmin)\n    xtemp = my_pwlf.x_data[indtemp]\n    ytemp = my_pwlf.y_data[indtemp]\n    indtemp = np.where(xtemp <= xmax)\n    xtemp = xtemp[indtemp]\n    ytemp = ytemp[indtemp]\n\n    # predict for the new data\n    yhattemp = my_pwlf.predict(xtemp)\n\n    # calcualte ssr\n    e = yhattemp - ytemp\n    ssr = np.dot(e, e)\n\n    # calculate sst\n    ybar = np.ones(ytemp.size) * np.mean(ytemp)\n    ydiff = ytemp - ybar\n    sst = np.dot(ydiff, ydiff)\n\n    R2values[i] = 1.0 - (ssr/sst)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n"
  },
  {
    "path": "examples/fitForSpecifiedNumberOfLineSegments_passDiffEvoKeywords.py",
    "content": "# fit for a specified number of line segments\n# you specify the number of line segments you want, the library does the rest\n# same as fitForSpecifiedNumberOfLineSegments.py, with the exception of\n# passing custom keywords directly to the scipy differential evolution algo\n# see\n# https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data for four line segments\n# My differential evolutions keywords are tuned to be very aggressive\n# it's probably overkill for your application\n# so you can pass your custom keywords here\n# for example I'll pass the only keyword that I want differential evolution\n# to print the iterations with disp=True\n# if any keyword is passed, all of my aggressively tuned differential evolution\n# keywords reset to the default\nres = my_pwlf.fit(4, disp=True)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n"
  },
  {
    "path": "examples/fitForSpecifiedNumberOfLineSegments_standard_deviation.py",
    "content": "# fit for a specified number of line segments\n# you specify the number of line segments you want, the library does the rest\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data for four line segments\nres = my_pwlf.fit(4)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# Get the slopes\nmy_slopes = my_pwlf.slopes\n\n# Get my model parameters\nbeta = my_pwlf.beta\n\n# calculate the standard errors associated with each beta parameter\nse = my_pwlf.standard_errors()\n\n# calculate the sum of the square of the residuals\nssr = my_pwlf.fit_with_breaks(my_pwlf.fit_breaks)\n\n# calculate the unbiased standard deviation\nsigma = np.sqrt(ssr / (my_pwlf.n_data - my_pwlf.n_parameters))\n# sigma can be used as a prediction variance\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.fill_between(xHat, yHat - (sigma*1.96), yHat + (sigma*1.96), alpha=0.1,\n                 color=\"r\")\nplt.show()\n"
  },
  {
    "path": "examples/fitWithKnownLineSegmentLocations.py",
    "content": "# fit and predict with known line segment x locations\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# your desired line segment end locations\nx0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data with the specified break points (ie the x locations of where\n# the line segments should end\nmy_pwlf.fit_with_breaks(x0)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n"
  },
  {
    "path": "examples/fit_begin_and_end.py",
    "content": "# fit and predict between a known begging and known ending\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\nfrom scipy.optimize import differential_evolution\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# initialize piecewise linear fit with your x and y data\nmyPWLF = pwlf.PiecewiseLinFit(x, y, disp_res=True)\n\n# fit the function with four line segments\n# force the function to go through the data points\n# (0.0, 0.0) and (0.19, 0.16) \n# where the data points are of the form (x, y)\nx_c = [0.0, 0.19]\ny_c = [0.0, 0.2]\nres = myPWLF.fit(4, x_c, y_c)\n\n# predict for the determined points\nxHat = np.linspace(min(x), 0.19, num=10000)\nyHat = myPWLF.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n"
  },
  {
    "path": "examples/min_length_demo.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"import numpy as np\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"import pwlf\\n\",\n    \"pwlf.__version__\\n\",\n    \"%matplotlib inline\"\n   ]\n  },\n  {\n   \"cell_type\": \"markdown\",\n   \"metadata\": {},\n   \"source\": [\n    \"## Force minimum length of segments to be greater than x\\n\",\n    \"\\n\",\n    \"[Issue 66](https://github.com/cjekel/piecewise_linear_fit_py/issues/66)\\n\",\n    \"\\n\",\n    \"This jupyter notebook uses SLSQP to apply a constraint function to force a minimum line segment length. You'll need to supply a starting point (or guess) to start the optimization. If you don't know what is a good starting point, check out how I use Latin Hypercube random sampling to run multiple optimizations in the ```fitfast``` function. \\n\",\n    \"\\n\",\n    \"\\n\",\n    \"A constraint function could look like:\\n\",\n    \"```python\\n\",\n    \"def my_con(var):\\n\",\n    \"    var = np.sort(var)\\n\",\n    \"    distances = np.zeros(number_of_line_segments)\\n\",\n    \"    distances[0] = var[0] - my_pwlf.break_0\\n\",\n    \"    distances[-1] = my_pwlf.break_n - var[-1]\\n\",\n    \"    for i in range(number_of_line_segments - 2):\\n\",\n    \"        distances[i+1] = var[i+1] - var[i]\\n\",\n    \"    # element must be greater or equal to 0.0\\n\",\n    \"    # in a successfully optimized problem\\n\",\n    \"    return np.array((distances.min() - min_length))\\n\",\n    \"```\\n\",\n    \"\\n\",\n    \"This is a single constraint for the minimum length of all segments. It's possible that the ```min()``` in this function will create issues with the gradient of the constraint. If you run into issues with this, you may want to investigate using a separate constraint for each line segment. That could be done by changing:\\n\",\n    \"```python\\n\",\n    \"    return np.array((distances.min() - min_length))\\n\",\n    \"```\\n\",\n    \"to\\n\",\n    \"```python\\n\",\n    \"    return distances - min_length\\n\",\n    \"```\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# your data\\n\",\n    \"y = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\\n\",\n    \"              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\\n\",\n    \"              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\\n\",\n    \"              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\\n\",\n    \"              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\\n\",\n    \"              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\\n\",\n    \"              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\\n\",\n    \"              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\\n\",\n    \"              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\\n\",\n    \"              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\\n\",\n    \"              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\\n\",\n    \"              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\\n\",\n    \"              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\\n\",\n    \"              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\\n\",\n    \"              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\\n\",\n    \"              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\\n\",\n    \"              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\\n\",\n    \"              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\\n\",\n    \"              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\\n\",\n    \"              1.41881288e-01, 1.62618058e-01])\\n\",\n    \"x = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\\n\",\n    \"              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\\n\",\n    \"              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\\n\",\n    \"              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\\n\",\n    \"              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\\n\",\n    \"              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\\n\",\n    \"              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\\n\",\n    \"              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\\n\",\n    \"              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\\n\",\n    \"              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\\n\",\n    \"              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\\n\",\n    \"              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\\n\",\n    \"              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\\n\",\n    \"              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\\n\",\n    \"              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\\n\",\n    \"              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\\n\",\n    \"              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\\n\",\n    \"              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\\n\",\n    \"              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\\n\",\n    \"              1.65299640e-01, 1.79942720e-01])\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# initialize piecewise linear fit with your x and y data\\n\",\n    \"my_pwlf = pwlf.PiecewiseLinFit(x, y)\\n\",\n    \"\\n\",\n    \"# initialize custom optimization\\n\",\n    \"number_of_line_segments = 3\\n\",\n    \"my_pwlf.use_custom_opt(number_of_line_segments)\\n\",\n    \"\\n\",\n    \"# minium length of a segment\\n\",\n    \"min_length = 0.05\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 4,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"def my_con(var):\\n\",\n    \"    var = np.sort(var)\\n\",\n    \"    distances = np.zeros(number_of_line_segments)\\n\",\n    \"    distances[0] = var[0] - my_pwlf.break_0\\n\",\n    \"    distances[-1] = my_pwlf.break_n - var[-1]\\n\",\n    \"    for i in range(number_of_line_segments - 2):\\n\",\n    \"        distances[i+1] = var[i+1] - var[i]\\n\",\n    \"    # element must be greater or equal to 0.0\\n\",\n    \"    # in a successfully optimized problem\\n\",\n    \"    return np.array((distances.min() - min_length))\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 5,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Optimization terminated successfully.    (Exit mode 0)\\n\",\n      \"            Current function value: 0.00035834090548162784\\n\",\n      \"            Iterations: 4\\n\",\n      \"            Function evaluations: 18\\n\",\n      \"            Gradient evaluations: 4\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"from scipy.optimize import fmin_slsqp\\n\",\n    \"# i have number_of_line_segments - 1 number of variables\\n\",\n    \"# let's guess the correct location of the two unknown variables\\n\",\n    \"# (the program defaults to have end segments at x0= min(x)\\n\",\n    \"# and xn=max(x)\\n\",\n    \"xGuess = np.zeros(number_of_line_segments - 1)\\n\",\n    \"xGuess[0] = 0.06\\n\",\n    \"xGuess[1] = 0.13\\n\",\n    \"bounds = np.zeros((number_of_line_segments - 1, 2))\\n\",\n    \"bounds[:, 0] = my_pwlf.break_0\\n\",\n    \"bounds[:, 1] = my_pwlf.break_n\\n\",\n    \"\\n\",\n    \"res = fmin_slsqp(my_pwlf.fit_with_breaks_opt, xGuess, f_ieqcons=my_con,\\n\",\n    \"                 bounds=bounds, iter=100, acc=1e-06, iprint=1,\\n\",\n    \"                 epsilon=1.4901161193847656e-08)\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 6,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\\n\",\n      \"text/plain\": [\n       \"<Figure size 432x288 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# set up the break point locations\\n\",\n    \"x0 = np.zeros(number_of_line_segments + 1)\\n\",\n    \"x0[0] = np.min(x)\\n\",\n    \"x0[-1] = np.max(x)\\n\",\n    \"x0[1:-1] = res\\n\",\n    \"\\n\",\n    \"# calculate the parameters based on the optimal break point locations\\n\",\n    \"my_pwlf.fit_with_breaks(x0)\\n\",\n    \"\\n\",\n    \"# predict for the determined points\\n\",\n    \"xHat = np.linspace(min(x), max(x), num=10000)\\n\",\n    \"yHat = my_pwlf.predict(xHat)\\n\",\n    \"\\n\",\n    \"plt.figure()\\n\",\n    \"plt.plot(x, y, 'o')\\n\",\n    \"plt.plot(xHat, yHat, '-')\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": []\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"Python 3\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.6.10\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 4\n}\n"
  },
  {
    "path": "examples/mixed_degree.py",
    "content": "import numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\nx = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\ny = [1, 2, 3, 4, 4.25, 3.75, 4, 5, 6, 7]\n\ndegree_list = [1, 0, 1]\n\nmy_pwlf = pwlf.PiecewiseLinFit(x, y, degree=degree_list)\n\nbreaks = my_pwlf.fit(3)\n\n# generate predictions\nx_hat = np.linspace(min(x), max(x), 1000)\ny_hat = my_pwlf.predict(x_hat)\n\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(x_hat, y_hat)\nplt.show()\n"
  },
  {
    "path": "examples/mixed_degree_forcing_slope.py",
    "content": "import numpy as np\nfrom scipy.optimize import differential_evolution\nimport matplotlib.pyplot as plt\nimport pwlf\n\nx = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\ny = [1, 2, 3, 4, 4.25, 3.75, 4, 5, 6, 7]\n\nmy_pwlf = pwlf.PiecewiseLinFit(x, y, degree=1)\n\n# perform initial fit\nbreaks = my_pwlf.fit(2)\n\n\ndef my_fun(beta):\n    # assing variables to the pwlf object\n    my_pwlf.beta[0] = beta[0]  # first line offset\n    my_pwlf.beta[1] = beta[1]  # first line slope\n    my_pwlf.beta[2] = -1*beta[1]\n    my_pwlf.fit_breaks[1] = beta[2]  # breakpoint\n    # generate predictions\n    y_temp = my_pwlf.predict(my_pwlf.x_data)\n    # compute ssr\n    e = y_temp - my_pwlf.y_data\n    return np.dot(e, e)\n\n\nbounds = np.zeros((3, 2))\n# first line offset\nbounds[0, 0] = -100.0  # lower bound\nbounds[0, 1] = 100.0  # upper bound\n# first line slope\nbounds[1, 0] = -100.0  # lower bound\nbounds[1, 1] = 100.0  # upper bound\n# breakpont\nbounds[2, 0] = 2.  # lower bound\nbounds[2, 1] = 6.  # upper bound\n\nres = differential_evolution(my_fun, bounds, maxiter=1000, popsize=30,\n                             disp=True)\n\n# assign optimum to my_pwlf object\nmy_fun(res.x)\n\n# generate predictions\nx_hat = np.linspace(min(x), max(x), 1000)\ny_hat = my_pwlf.predict(x_hat)\n\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(x_hat, y_hat)\nplt.show()\n"
  },
  {
    "path": "examples/model_persistence.py",
    "content": "# import our libraries\nimport numpy as np\nimport pwlf\n\n# if you use Python 2.x you should import cPickle\n# import cPickle as pickle\n# if you use Python 3.x you can just use pickle\nimport pickle\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# your desired line segment end locations\nx0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data with the specified break points (ie the x locations of where\n# the line segments should end\nmy_pwlf.fit_with_breaks(x0)\n\n# save the fitted model\nwith open('my_fit.pkl', 'wb') as f:\n    pickle.dump(my_pwlf, f, pickle.HIGHEST_PROTOCOL)\n\n# load the fitted model\nwith open('my_fit.pkl', 'rb') as f:\n    my_pwlf = pickle.load(f)\n"
  },
  {
    "path": "examples/model_persistence_prediction.py",
    "content": "# import our libraries\nimport numpy as np\nimport pwlf\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data with for 4 line segments\nmy_pwlf.fit(4)\n\n# save only the parameters necessary to predict for new data\nnp.save('ex_data/saved_parameters.npy', [my_pwlf.beta, my_pwlf.fit_breaks])\n\n# load the parameters necessary for prediction\nmy_prev_model = np.load('ex_data/saved_parameters.npy')\n\n# initialize new object\nmy_pwlf_new = pwlf.PiecewiseLinFit(x, y)\n\n# predict with the saved parameters\ny_hat = my_pwlf_new.predict(x, beta=my_prev_model[0], breaks=my_prev_model[1])\n"
  },
  {
    "path": "examples/prediction_variance.py",
    "content": "# fit for a specified number of line segments\n# you specify the number of line segments you want, the library does the rest\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data for four line segments\nres = my_pwlf.fit(4)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# Get the slopes\nmy_slopes = my_pwlf.slopes\n\n# Get my model parameters\nbeta = my_pwlf.beta\n\n# calculate the prediction variance at the xHat locations\npre_var = my_pwlf.prediction_variance(xHat)\n# turn variance into standard deviation\npre_sigma = np.sqrt(pre_var)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.fill_between(xHat, yHat - (pre_sigma*1.96), yHat + (pre_sigma*1.96),\n                 alpha=0.1, color=\"r\")\nplt.show()\n"
  },
  {
    "path": "examples/prediction_variance_degree2.py",
    "content": "# fit for a specified number of line segments\n# you specify the number of line segments you want, the library does the rest\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y, degree=2)\n\n# fit the data for four line segments\nres = my_pwlf.fit(4)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# Get the slopes\nmy_slopes = my_pwlf.slopes\n\n# Get my model parameters\nbeta = my_pwlf.beta\n\n# calculate the prediction variance at the xHat locations\npre_var = my_pwlf.prediction_variance(xHat)\n# turn variance into standard deviation\npre_sigma = np.sqrt(pre_var)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.fill_between(xHat, yHat - (pre_sigma*1.96), yHat + (pre_sigma*1.96),\n                 alpha=0.1, color=\"r\")\nplt.show()\n"
  },
  {
    "path": "examples/robust_regression.py",
    "content": "# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\nfrom scipy.optimize import least_squares\n\n# generate sin wave data\nnp.random.seed(1213)\nx = np.linspace(0, 10, num=100)\ny = np.sin(x * np.pi / 2)\n# add noise to the data\ny = np.random.normal(0, 0.5, 100) + y\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\nnum_of_line_segments = 5  # change this value\nnum_in_breaks = num_of_line_segments - 1\nn_beta = num_of_line_segments + 1\n\ndef my_fun(breaks_and_beta):\n    \"\"\"\n    Returns the residuals given an array of breaks and beta\n    \"\"\"\n    inner_breaks = breaks_and_beta[:num_in_breaks]  # break point locations\n    # breaks code is taken from pwlf...\n    breaks = np.zeros(len(inner_breaks) + 2)\n    breaks[1:-1] = inner_breaks.copy()\n    breaks[0] = my_pwlf.break_0  # smallest x value\n    breaks[-1] = my_pwlf.break_n  # largest x value\n    beta = breaks_and_beta[num_in_breaks:]  # beta paramters (slopes and int)\n    A = my_pwlf.assemble_regression_matrix(breaks,\n                                           my_pwlf.x_data)\n    y_hat = np.dot(A, beta)\n    resids = y_hat - my_pwlf.y_data\n    return resids\n\n\nn_runs = 50  # perfrom 50 robust regressions, and take the best one\nresults = []\nfor i in range(n_runs):\n    # fit the data three line segments and use this result as a starting point\n    res = my_pwlf.fitfast(num_of_line_segments)\n\n    breaks_and_beta_guess = np.zeros(num_in_breaks + n_beta)\n    breaks_and_beta_guess[:num_in_breaks] = res[1:num_of_line_segments]\n    breaks_and_beta_guess[num_in_breaks:] = my_pwlf.beta\n\n    # use the result from pwlf to start a robust regresion\n    # notes on soft_l1: from documentation\n    # https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.least_squares.html\n    # ‘soft_l1’ : rho(z) = 2 * ((1 + z)**0.5 - 1). The smooth approximation of l1\n    # (absolute value) loss. Usually a good choice for robust least squares.\n    result = least_squares(my_fun,\n                           breaks_and_beta_guess,  # initial guess\n                           loss='soft_l1',\n                           f_scale=0.1)  # inlier residuals less than 0.1\n    results.append(result)\n# find the best result\ncosts = []\nfor r in results:\n    costs.append(r['cost'])  # the objective function from each Robust Reg.\nindex_best_result = np.argmin(costs)\nresult = results[index_best_result]\n\n# least squares result\nxhat = np.linspace(0, 10, 1000)\nyhat_ols = my_pwlf.predict(xhat)  # initial guess\n\n# put the results back into my_pwlf\nbreaks = np.zeros(num_of_line_segments+1)\nbreaks[0] = my_pwlf.break_0\nbreaks[-1] = my_pwlf.break_n\nbreaks[1:num_in_breaks+1] = result.x[:num_in_breaks]\nmy_pwlf.fit_breaks = breaks\nbeta = result.x[num_in_breaks:]\nmy_pwlf.beta = beta\n\nyhat_robo = my_pwlf.predict(xhat)\n\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xhat, yhat_ols, '-', label='OLS')\nplt.plot(xhat, yhat_robo, '-', label='Robust Reg.')\nplt.legend()\nplt.show()\n"
  },
  {
    "path": "examples/run_opt_to_find_best_number_of_line_segments.py",
    "content": "# Running an optimization to find the best number of line segments\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\nfrom GPyOpt.methods import BayesianOptimization\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# define your objective function\n\n\ndef my_obj(x):\n    # define some penalty parameter l\n    # you'll have to arbitrarily pick this\n    # it depends upon the noise in your data,\n    # and the value of your sum of square of residuals\n    l = y.mean()*0.001\n    f = np.zeros(x.shape[0])\n    for i, j in enumerate(x):\n        my_pwlf.fit(j[0])\n        f[i] = my_pwlf.ssr + (l*j[0])\n    return f\n\n\n# define the lower and upper bound for the number of line segements\nbounds = [{'name': 'var_1', 'type': 'discrete', 'domain': np.arange(2, 40)}]\n\nnp.random.seed(12121)\n\nmyBopt = BayesianOptimization(my_obj, domain=bounds, model_type='GP',\n                              initial_design_numdata=10,\n                              initial_design_type='latin',\n                              exact_feval=True, verbosity=True,\n                              verbosity_model=False)\nmax_iter = 30\n\n# perform the bayesian optimization to find the optimum number of line segments\nmyBopt.run_optimization(max_iter=max_iter, verbosity=True)\n\nprint('\\n \\n Opt found \\n')\nprint('Optimum number of line segments:', myBopt.x_opt)\nprint('Function value:', myBopt.fx_opt)\nmyBopt.plot_acquisition()\nmyBopt.plot_convergence()\n\n# perform the fit for the optimum\nmy_pwlf.fit(myBopt.x_opt)\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n"
  },
  {
    "path": "examples/sineWave.py",
    "content": "# fit for a specified number of line segments\n# you specify the number of line segments you want, the library does the rest\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\n# generate sin wave data\nx = np.linspace(0, 10, num=100)\ny = np.sin(x * np.pi / 2)\n# add noise to the data\ny = np.random.normal(0, 0.05, 100) + y\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data for four line segments\nres = my_pwlf.fit(16, disp=True)\n# i'm passing the argument disp=True to see the progress of the differential\n# evolution so you can be sure the program isn't just hanging...\n\n# Be patient! this one takes some time - It's a difficult problem\n# using this differential evolution algo + bfgs can be over 500,000.0 function\n# evaluations\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n"
  },
  {
    "path": "examples/sineWave_custom_opt_bounds.py",
    "content": "# fit for a specified number of line segments\n# you specify the number of line segments you want, the library does the rest\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\n# generate sin wave data\nx = np.linspace(0, 10, num=100)\ny = np.sin(x * np.pi / 2)\n# add noise to the data\ny = np.random.normal(0, 0.05, 100) + y\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# define custom bounds for the interior break points\nn_segments = 4\nbounds = np.zeros((n_segments-1, 2))\n# first lower and upper bound\nbounds[0, 0] = 0.0\nbounds[0, 1] = 3.5\n# second lower and upper bound\nbounds[1, 0] = 3.0\nbounds[1, 1] = 7.0\n# third lower and upper bound\nbounds[2, 0] = 6.0\nbounds[2, 1] = 10.0\nres = my_pwlf.fit(n_segments, bounds=bounds)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n"
  },
  {
    "path": "examples/sineWave_degrees.py",
    "content": "# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\n# generate sin wave data\nx = np.linspace(0, 10, num=100)\ny = np.sin(x * np.pi / 2)\n# add noise to the data\ny = np.random.normal(0, 0.05, 100) + y\n\n# initialize piecewise linear fit with your x and y data\n# pwlf lets you fit continuous model for many degree polynomials\n# degree=0 constant\n# degree=1 linear (default)\n# degree=2 quadratic\nmy_pwlf_0 = pwlf.PiecewiseLinFit(x, y, degree=0)\nmy_pwlf_1 = pwlf.PiecewiseLinFit(x, y, degree=1)  # default\nmy_pwlf_2 = pwlf.PiecewiseLinFit(x, y, degree=2)\n\n# fit the data for four line segments\nres0 = my_pwlf_0.fitfast(5, pop=50)\nres1 = my_pwlf_1.fitfast(5, pop=50)\nres2 = my_pwlf_2.fitfast(5, pop=50)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat0 = my_pwlf_0.predict(xHat)\nyHat1 = my_pwlf_1.predict(xHat)\nyHat2 = my_pwlf_2.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o', label='Data')\nplt.plot(xHat, yHat0, '-', label='degree=0')\nplt.plot(xHat, yHat1, '--', label='degree=1')\nplt.plot(xHat, yHat2, ':', label='degree=2')\nplt.legend()\nplt.show()\n"
  },
  {
    "path": "examples/sineWave_time_compare.py",
    "content": "# fit for a specified number of line segments\n# you specify the number of line segments you want, the library does the rest\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\nfrom time import time\n\n# generate sin wave data\nx = np.linspace(0, 10, num=100)\ny = np.sin(x * np.pi / 2)\n# add noise to the data\ny = np.random.normal(0, 0.05, 100) + y\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data for sixteen line segments\nt0 = time()\nres1 = my_pwlf.fit(16, disp=True)\nt1 = time()\n# i'm passing the argument disp=True to see the progress of the differential\n# evolution so you can be sure the program isn't just hanging...\n\n# Be patient! this one takes some time - It's a difficult problem\n# using this differential evolution algo + bfgs can be over 500,000.0 function\n# evaluations\n\n# predict for the determined points\nxHat1 = np.linspace(min(x), max(x), num=10000)\nyHat1 = my_pwlf.predict(xHat1)\n\n# fit the data for sixteen line segments\n# using the default 50 number of multi starts\nt2 = time()\nres2 = my_pwlf.fitfast(16)  # this is equivalent to my_pwlf.fitfast(16,50)\nt3 = time()\n\n# predict for the determined points\nxHat2 = np.linspace(min(x), max(x), num=10000)\nyHat2 = my_pwlf.predict(xHat2)\n\nprint('Run time for differential_evolution', t1 - t0, 'seconds')\nprint('Run time for multi-start', t3 - t2, 'seconds')\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat1, yHat1, '-', label='Diff. evolution')\nplt.plot(xHat2, yHat2, '-', label='Multi start')\nplt.legend()\nplt.show()\n"
  },
  {
    "path": "examples/slope_constraint_demo.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"2.2.1\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"import numpy as np\\n\",\n    \"import matplotlib.pyplot as plt\\n\",\n    \"import pwlf\\n\",\n    \"print(pwlf.__version__)\\n\",\n    \"%matplotlib inline\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# your data\\n\",\n    \"y = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\\n\",\n    \"              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\\n\",\n    \"              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\\n\",\n    \"              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\\n\",\n    \"              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\\n\",\n    \"              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\\n\",\n    \"              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\\n\",\n    \"              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\\n\",\n    \"              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\\n\",\n    \"              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\\n\",\n    \"              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\\n\",\n    \"              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\\n\",\n    \"              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\\n\",\n    \"              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\\n\",\n    \"              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\\n\",\n    \"              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\\n\",\n    \"              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\\n\",\n    \"              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\\n\",\n    \"              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\\n\",\n    \"              1.41881288e-01, 1.62618058e-01])\\n\",\n    \"x = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\\n\",\n    \"              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\\n\",\n    \"              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\\n\",\n    \"              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\\n\",\n    \"              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\\n\",\n    \"              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\\n\",\n    \"              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\\n\",\n    \"              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\\n\",\n    \"              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\\n\",\n    \"              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\\n\",\n    \"              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\\n\",\n    \"              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\\n\",\n    \"              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\\n\",\n    \"              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\\n\",\n    \"              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\\n\",\n    \"              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\\n\",\n    \"              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\\n\",\n    \"              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\\n\",\n    \"              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\\n\",\n    \"              1.65299640e-01, 1.79942720e-01])\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# initialize piecewise linear fit with your x and y data\\n\",\n    \"my_pwlf = pwlf.PiecewiseLinFit(x, y)\\n\",\n    \"\\n\",\n    \"# initialize custom optimization\\n\",\n    \"number_of_line_segments = 3\\n\",\n    \"my_pwlf.use_custom_opt(number_of_line_segments)\\n\",\n    \"\\n\",\n    \"# maximum slope\\n\",\n    \"max_slope = 1.25\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 4,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"def my_con(var):\\n\",\n    \"    # define a constraint on the maximum slope\\n\",\n    \"    my_pwlf.fit_with_breaks_opt(var)\\n\",\n    \"    slopes = my_pwlf.calc_slopes()\\n\",\n    \"    # element must be greater or equal to 0.0\\n\",\n    \"    # in a successfully optimized problem\\n\",\n    \"    return np.array((max_slope - slopes.max()))\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 5,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Optimization terminated successfully    (Exit mode 0)\\n\",\n      \"            Current function value: 0.00026952124484395115\\n\",\n      \"            Iterations: 6\\n\",\n      \"            Function evaluations: 20\\n\",\n      \"            Gradient evaluations: 6\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"from scipy.optimize import fmin_slsqp\\n\",\n    \"# i have number_of_line_segments - 1 number of variables\\n\",\n    \"# let's guess the correct location of the two unknown variables\\n\",\n    \"# (the program defaults to have end segments at x0= min(x)\\n\",\n    \"# and xn=max(x)\\n\",\n    \"xGuess = np.zeros(number_of_line_segments - 1)\\n\",\n    \"xGuess[0] = 0.06\\n\",\n    \"xGuess[1] = 0.13\\n\",\n    \"bounds = np.zeros((number_of_line_segments - 1, 2))\\n\",\n    \"bounds[:, 0] = my_pwlf.break_0\\n\",\n    \"bounds[:, 1] = my_pwlf.break_n\\n\",\n    \"\\n\",\n    \"res = fmin_slsqp(my_pwlf.fit_with_breaks_opt, xGuess, f_ieqcons=my_con,\\n\",\n    \"                 bounds=bounds, iter=100, acc=1e-06, iprint=1,\\n\",\n    \"                 epsilon=1.4901161193847656e-08)\\n\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 6,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\\n\",\n      \"text/plain\": [\n       \"<Figure size 432x288 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# set up the break point locations\\n\",\n    \"x0 = np.zeros(number_of_line_segments + 1)\\n\",\n    \"x0[0] = np.min(x)\\n\",\n    \"x0[-1] = np.max(x)\\n\",\n    \"x0[1:-1] = res\\n\",\n    \"\\n\",\n    \"# calculate the parameters based on the optimal break point locations\\n\",\n    \"my_pwlf.fit_with_breaks(x0)\\n\",\n    \"\\n\",\n    \"# predict for the determined points\\n\",\n    \"xHat = np.linspace(min(x), max(x), num=10000)\\n\",\n    \"yHat = my_pwlf.predict(xHat)\\n\",\n    \"\\n\",\n    \"plt.figure()\\n\",\n    \"plt.plot(x, y, 'o')\\n\",\n    \"plt.plot(xHat, yHat, '-')\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 7,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"text/plain\": [\n       \"array([1.10704555, 0.50206765, 1.24978354])\"\n      ]\n     },\n     \"execution_count\": 7,\n     \"metadata\": {},\n     \"output_type\": \"execute_result\"\n    }\n   ],\n   \"source\": [\n    \"my_pwlf.calc_slopes()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 8,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"# the maximum slope is less than max_slope!\\n\",\n    \"# this would not be possible without the constrained fit!\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": null,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": []\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"Python 3 (ipykernel)\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.7.13\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 4\n}\n"
  },
  {
    "path": "examples/stack_overflow_example.py",
    "content": "import numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\n# https://stackoverflow.com/questions/29382903/how-to-apply-piecewise-linear-fit-in-python\n\nx = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])\ny = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59, 84.47, 98.36, 112.25, 126.14, 140.03])\n\n# pwlf has two approaches to perform your fit:\n# 1. You can fit for a specified number of line segments.\n# 2. You can specify the x locations where the continuous piecewise lines\n# should terminate.\n\n# Approach 1\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n# breaks will return the end location of each line segment\nbreaks = my_pwlf.fit(2)\nprint(breaks)\n# The gradient change point you asked for is at breaks[1]\n\nx_hat = np.linspace(x.min(), x.max(), 100)\ny_hat = my_pwlf.predict(x_hat)\n\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(x_hat, y_hat, '-')\nplt.show()"
  },
  {
    "path": "examples/standard_errrors_and_p-values.py",
    "content": "# example of how to calculate standard errors and p-values\nfrom __future__ import print_function\nimport numpy as np\nimport pwlf\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# your desired line segment end locations\nx0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n# fit the data for our specified line segment locations\nres = my_pwlf.fit_with_breaks(x0)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# Get my model parameters\nbeta = my_pwlf.beta\n\n# calculate the standard errors associated with each beta parameter\n# not that these standard errors and p-values are only meaningful if\n# you have specified the specific line segment end locations\n# at least for now...\nse = my_pwlf.standard_errors()\n\n# calculate my t-value\nt = beta / se\n\nk = len(beta) - 1\n\n# calculate the p-values\npvalues = my_pwlf.p_values()\n\n# print the results\nvalues = np.zeros((k, 4))\nvalues[:, 0] = beta\nvalues[:, 1] = se\nvalues[:, 2] = t\nvalues[:, 3] = pvalues\nheader = ['Beta value', 'Standard error', 't', 'P > |t| (p-value)']\nprint(*header, sep=' & ')\nfor row in values:\n    print(*row, sep=' & ')\n"
  },
  {
    "path": "examples/standard_errrors_and_p-values_non-linear.py",
    "content": "from __future__ import print_function\nimport numpy as np\nimport pwlf\n# import matplotlib.pyplot as plt\n\n# generate a true piecewise linear data\nnp.random.seed(5)\nn_data = 100\nx = np.linspace(0, 1, num=n_data)\ny = np.random.random(n_data)\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\ntrue_beta = np.random.normal(size=5)\ntrue_breaks = np.array([0.0, 0.2, 0.5, 0.75, 1.0])\ny = my_pwlf.predict(x, beta=true_beta, breaks=true_breaks)\n\n# plt.figure()\n# plt.title('True piecewise linear data')\n# plt.plot(x, y)\n# plt.show()\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n# fit the data for our specified line segment locations\nres = my_pwlf.fitfast(4, pop=100)\n\n# calculate the non-linear standard errors\nse = my_pwlf.standard_errors(method='non-linear', step_size=1e-4)\n\n# calculate p-values\np = my_pwlf.p_values(method='non-linear', step_size=1e-4)\n\nparameters = np.concatenate((my_pwlf.beta, my_pwlf.fit_breaks[1:-1]))\n\nheader = ['Parmater type', 'Parameter value', 'Standard error', 't',\n          'P > |t| (p-value)']\nprint(*header, sep=' & ')\nvalues = np.zeros((parameters.size, 5), dtype=np.object_)\nvalues[:, 1] = np.around(parameters, decimals=3)\nvalues[:, 2] = np.around(se, decimals=3)\nvalues[:, 3] = np.around(parameters / se, decimals=3)\nvalues[:, 4] = np.around(p, decimals=3)\n\nfor i, row in enumerate(values):\n    if i < my_pwlf.beta.size:\n        row[0] = 'Beta'\n        print(*row, sep=' & ')\n    else:\n        row[0] = 'Breakpoint'\n        print(*row, sep=' & ')\n"
  },
  {
    "path": "examples/test0.py",
    "content": "import numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\nfrom scipy.optimize import minimize\n\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\nx0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# fit the data with the specified break points (ie the x locations of where\n# the line segments should end\n# my_pwlf.fit_with_breaks(x0)\n# my_pwlf.seperateData(x0)\n\n# res = my_pwlf.fit(3)\n\n# initialize custom optimization\nnumber_of_line_segments = 3\nmy_pwlf.use_custom_opt(number_of_line_segments)\n\nres = minimize(my_pwlf.fit_with_breaks_opt, np.array([x0[1], x0[2]]))\n\n# set up the break point locations\nx0 = np.zeros(number_of_line_segments + 1)\nx0[0] = np.min(x)\nx0[-1] = np.max(x)\nx0[1:-1] = res.x\n\n# calculate the parameters based on the optimal break point locations\nmy_pwlf.fit_with_breaks(x0)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n"
  },
  {
    "path": "examples/test_for_model_significance.py",
    "content": "# example of how to calculate standard errors and p-values\nfrom __future__ import print_function\nimport numpy as np\nimport pwlf\nfrom scipy.stats import f\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\n\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# your desired line segment end locations\nx0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n# fit the data for our specified line segment locations\n# this is a linear model\nres = my_pwlf.fit_with_breaks(x0)\n\n# calculate the p-value as a test for significance in Regression\n# H0: beta0 = 0, beta1 = 0...\n# H1: betaj != 00 for at least 1 j\n# As defined in Section 2.4.1 of Myers RH, Montgomery DC, Anderson-Cook CM.\n# Response surface methodology . Hoboken. New Jersey: John Wiley & Sons, Inc.\n# 2009;20:38-44.\nsse = my_pwlf.ssr  # this is to follow the notation in the above textbook\nybar = np.ones(my_pwlf.n_data) * np.mean(my_pwlf.y_data)\nydiff = my_pwlf.y_data - ybar\nsst = np.dot(ydiff, ydiff)\n\nssr = sst - sse\nk = my_pwlf.beta.size - 1\nn = my_pwlf.n_data\nf0 = (ssr / k) / (sse / (n - k - 1))\n\np_value = f.sf(f0, k, n-k-1)\nprint(f\"Linear p-value: {p_value}\")\n\n# The above case is a linear model, where we know the breakpoints\n# The following case is for the non-linear model, where we do not know the\n# break point locations\nres = my_pwlf.fit(2)\nsse = my_pwlf.ssr  # to follow the Book notation\nybar = np.ones(my_pwlf.n_data) * np.mean(my_pwlf.y_data)\nydiff = my_pwlf.y_data - ybar\nsst = np.dot(ydiff, ydiff)\n\nssr = sst - sse\nnb = my_pwlf.beta.size + my_pwlf.fit_breaks.size - 2\nk = nb - 1\nn = my_pwlf.n_data\nf0 = (ssr / k) / (sse / (n - k - 1))\n\np_value = f.sf(f0, k, n-k-1)\nprint(f\"non-linear p_value: {p_value}\")\n\n# in both these cases, the p_value is very small, so we reject H0\n# and thus our paramters are significant!\n"
  },
  {
    "path": "examples/test_if_breaks_exact.py",
    "content": "import numpy as np\nimport pwlf\n\nx = np.array((0.0, 1.0, 1.5, 2.0))\ny = np.array((0.0, 1.0, 1.1, 1.5))\n\nmy_fit1 = pwlf.PiecewiseLinFit(x, y)\nx0 = x.copy()\n# check that I can fit when break poitns spot on a\nssr = my_fit1.fit_with_breaks(x0)\n\n# check that i can fit when I slightly modify x0\nmy_fit2 = pwlf.PiecewiseLinFit(x, y)\nx0[1] = 1.00001\nx0[2] = 1.50001\nssr2 = my_fit2.fit_with_breaks(x0)\n\n# check if my duplicate is in a different location\nx0 = x.copy()\nmy_fit3 = pwlf.PiecewiseLinFit(x, y)\nx0[1] = 0.9\nssr3 = my_fit3.fit_with_breaks(x0)\n\n# check if my duplicate is in a different location\nx0 = x.copy()\nmy_fit4 = pwlf.PiecewiseLinFit(x, y)\nx0[1] = 1.1\nssr4 = my_fit4.fit_with_breaks(x0)\n\n# check if my duplicate is in a different location\nx0 = x.copy()\nmy_fit5 = pwlf.PiecewiseLinFit(x, y)\nx0[2] = 1.6\nssr5 = my_fit5.fit_with_breaks(x0)\n\n# check if my duplicate is in a different location\nx0 = x.copy()\nmy_fit6 = pwlf.PiecewiseLinFit(x, y)\nx0[2] = 1.4\nssr6 = my_fit6.fit_with_breaks(x0)\n"
  },
  {
    "path": "examples/tf/fit_begin_and_end.py",
    "content": "# fit and predict between a known begging and known ending\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\nfrom scipy.optimize import differential_evolution\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFitTF(x, y, disp_res=True)\n\n# fit the function with four line segments\n# force the function to go through the data points\n# (0.0, 0.0) and (0.19, 0.16) \n# where the data points are of the form (x, y)\nx_c = [0.0, 0.19]\ny_c = [0.0, 0.2]\nbreaks = [0.00711605, 0.12014667, 0.1799223]\nL = my_pwlf.fit_with_breaks_force_points(breaks, x_c, y_c)\n\n# predict for the determined points\nxHat = np.linspace(min(x), 0.19, num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n"
  },
  {
    "path": "examples/tf/sine_benchmark_fixed_20_break_points.py",
    "content": "import numpy as np\nimport pwlf\nfrom time import time\nimport os\n\nbreaks = np.linspace(0.0, 10.0, num=21)\n\nn = np.logspace(3, 7, num=15, dtype=np.int)\nn_repeats = 10\nrun_times = np.zeros((3, n.size, n_repeats))\n\nfor i, n_data in enumerate(n):\n    # set random seed\n    np.random.seed(256)\n    # generate sin wave data\n    x = np.linspace(0, 10, num=n_data)\n    y = np.sin(x * np.pi / 2)\n    # add noise to the data\n    y = np.random.normal(0, 0.05, size=n_data) + y\n    for j in range(n_repeats):\n        # normal PWLF fit\n        t0 = time()\n        my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        ssr = my_pwlf.fit_with_breaks(breaks)\n        t1 = time()\n        # PWLF TF fit\n        t2 = time()\n        my_pwlf = pwlf.PiecewiseLinFitTF(x, y)\n        ssr = my_pwlf.fit_with_breaks(breaks)\n        t3 = time()\n        run_times[0, i, j] = t1 - t0\n        run_times[1, i, j] = t3 - t2\n\nnp.save('bench_run_times/20_break_times.npy', run_times)\nnp.save('bench_run_times/n.npy', n)\n"
  },
  {
    "path": "examples/tf/sine_benchmark_six_segments.py",
    "content": "import numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\nfrom time import time\n\n# set random seed\nnp.random.seed(256)\nbreaks = np.array((0.0, 0.94, 2.96, 4.93, 7.02, 9.04, 10.0))\n\nn_data = int(1e6)\n\n# generate sin wave data\nx = np.linspace(0, 10, num=n_data)\ny = np.sin(x * np.pi / 2)\n# add noise to the data\ny = np.random.normal(0, 0.05, size=n_data) + y\n\nt0 = time()\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# # fit the data for four line segments\n# res = my_pwlf.fit(16)\n# breaks = my_pwlf.fit(6)\n\nssr = my_pwlf.fit_with_breaks(breaks)\nt1 = time()\nprint('run time:', t1 - t0)\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n"
  },
  {
    "path": "examples/tf/test_fit.py",
    "content": "# fit and predict with known line segment x locations\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# your desired line segment end locations\nx0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFitTF(x, y)\n\n# fit the data with the specified break points (ie the x locations of where\n# the line segments should end\nssr = my_pwlf.fit_with_breaks(x0)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\n# plot the results\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n"
  },
  {
    "path": "examples/understanding_higher_degrees/polynomials_in_pwlf.ipynb",
    "content": "{\n \"cells\": [\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"import numpy as np\\n\",\n    \"import pwlf\\n\",\n    \"# generate sin wave data\\n\",\n    \"x = np.linspace(0, 10, num=100)\\n\",\n    \"y = np.sin(x * np.pi / 2)\\n\",\n    \"# add noise to the data\\n\",\n    \"y = np.random.normal(0, 0.05, 100) + y\\n\",\n    \"my_pwlf_2 = pwlf.PiecewiseLinFit(x, y, degree=2)\\n\",\n    \"res2 = my_pwlf_2.fitfast(5, pop=50)\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\\n\",\n      \"text/plain\": [\n       \"<Figure size 432x288 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"import matplotlib.pyplot as plt\\n\",\n    \"%matplotlib inline\\n\",\n    \"# first line\\n\",\n    \"xhat = np.linspace(my_pwlf_2.fit_breaks[0], my_pwlf_2.fit_breaks[1], 100)\\n\",\n    \"yhat = my_pwlf_2.beta[0] + my_pwlf_2.beta[1]*(xhat-my_pwlf_2.fit_breaks[0]) + my_pwlf_2.beta[6]*(xhat-my_pwlf_2.fit_breaks[0])**2\\n\",\n    \"plt.figure()\\n\",\n    \"plt.plot(x, y, 'o')\\n\",\n    \"plt.plot(xhat, yhat, '-.', label='First segment')\\n\",\n    \"plt.xlabel('x')\\n\",\n    \"plt.ylabel('y')\\n\",\n    \"plt.legend()\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 3,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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d2bMmDF8/fXXtG7dmmHDhpGamgrgXB9q/35atWpFWloavXs7u2NvvfVWFi5cWCs+9yXNr7vuOnr37s2aNWvIy8tj6NChgPN+Gp06deKrr75izJgxtGvXDoCZM2eye/fumueaOnUqSikGDRpE586da27/OmDAAPbv309BQQHbt29n1KhRAFRUVDBixIjq39ZcPcn5nvtlZLLmQ+fS5/YgXlMbusy41voD4AOvbY+7fV8ONJ/RZQP0TurN6gOrKa0spYWthdHhhFTHhI7MSp/VbMZjgq2uFkCg/dvGt23w74Pzntljx45l7NixDBo0iAPTN5oAABfRSURBVNdee40hQ4b4XAb8zJkz+JrlpdHEWHxP/3Jf2ttqtVJVVQVAfaaLuS9pPnHiRF5++WW01tx+++0888wzHvv6uuGSrzjclyd3/VxVVYXVauWaa67hrbfe8vHbitjq37FarNir34M1eFPeZAmP5q53295oNN+d/s7oUEKuX/t+PDb8MdrENWzFT2GMXbt21fT7A2zevJkePXr4XQa8devWpKam8skq530vKi5coKyslOzLR7Lmg6XY7XaKior47LPPGDZsmN/X7du3L99//z379u0D8HNy9lzSfNq0aWzZsoWrr76axYsXc/z4cQBOnTrFgQMHGDZsGP/+978pLi6mqqqKd999t0H/F8OHD2f9+vXs3evsJi4tLa1pkVgtCotXUrAoRecOSUFbolwSRTPn6q+P9gHtpfmFjFjwT9LmLWfU/LXNbvFD1zL6afNWRsz7P3fuHLfffjv9+/cnIyOD7du388QTTwRcBvytN/7Bu6+/zMwJo7ltxkTOnCzitpt/yJCsTAYPHsy4ceN47rnn6NKli9/XjY+PZ+HChUyePJnRo0fTo0cPn/u5L2m+c+dObrvtNvr3789TTz3FhAkTyMjI4JprruHIkSOkpKTws5/9jMsvv5zx48fTv3//Bi1R3rFjR1599VVuuukmMjIyGD58eM39ti0KuraJr7khk1KKlLYJzLp+Bu+9915QBrNlmfFmzu6wM/zN4dzQ5wYeGfaI0eGEhHN59c1YL/k5FadGU1F0LQk2a9TPvnfxvtsdUK/3L8uMB5drifKqqipmzJjBXXfdxYwZMwyJRZYZFw1itVi5J+MehnYZanQoIbNg1S7KqqooP3odVWedg4TNaaXc5nq3O7N54okn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\\n\",\n      \"text/plain\": [\n       \"<Figure size 432x288 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# second segment\\n\",\n    \"xhat2 = np.linspace(my_pwlf_2.fit_breaks[1], my_pwlf_2.fit_breaks[2], 100)\\n\",\n    \"yhat2 = (my_pwlf_2.beta[0] +\\n\",\n    \"         (my_pwlf_2.beta[1])*(xhat2-my_pwlf_2.fit_breaks[0]) +\\n\",\n    \"         (my_pwlf_2.beta[2])*(xhat2-my_pwlf_2.fit_breaks[1]) +\\n\",\n    \"         (my_pwlf_2.beta[6])*(xhat2-my_pwlf_2.fit_breaks[0])**2 +\\n\",\n    \"         (my_pwlf_2.beta[7])*(xhat2-my_pwlf_2.fit_breaks[1])**2)\\n\",\n    \"plt.plot(x, y, 'o')\\n\",\n    \"plt.plot(xhat, yhat, '-.', label='First segment')\\n\",\n    \"plt.plot(xhat2, yhat2, '-.', label='Second segment')\\n\",\n    \"\\n\",\n    \"plt.xlabel('x')\\n\",\n    \"plt.ylabel('y')\\n\",\n    \"plt.legend()\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 4,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\\n\",\n      \"text/plain\": [\n       \"<Figure size 432x288 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# Third segment\\n\",\n    \"xhat3 = np.linspace(my_pwlf_2.fit_breaks[2], my_pwlf_2.fit_breaks[3], 100)\\n\",\n    \"yhat3 = (my_pwlf_2.beta[0] +\\n\",\n    \"         (my_pwlf_2.beta[1])*(xhat3-my_pwlf_2.fit_breaks[0]) +\\n\",\n    \"         (my_pwlf_2.beta[2])*(xhat3-my_pwlf_2.fit_breaks[1]) +\\n\",\n    \"         (my_pwlf_2.beta[3])*(xhat3-my_pwlf_2.fit_breaks[2]) +\\n\",\n    \"         (my_pwlf_2.beta[6])*(xhat3-my_pwlf_2.fit_breaks[0])**2 +\\n\",\n    \"         (my_pwlf_2.beta[7])*(xhat3-my_pwlf_2.fit_breaks[1])**2 +\\n\",\n    \"         (my_pwlf_2.beta[8])*(xhat3-my_pwlf_2.fit_breaks[2])**2)\\n\",\n    \"plt.plot(x, y, 'o')\\n\",\n    \"plt.plot(xhat, yhat, '-.', label='First segment')\\n\",\n    \"plt.plot(xhat2, yhat2, '-.', label='Second segment')\\n\",\n    \"plt.plot(xhat3, yhat3, '-.', label='Third segment')\\n\",\n    \"\\n\",\n    \"plt.xlabel('x')\\n\",\n    \"plt.ylabel('y')\\n\",\n    \"plt.legend()\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 5,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\\n\",\n      \"text/plain\": [\n       \"<Figure size 432x288 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# Fourth segment\\n\",\n    \"xhat4 = np.linspace(my_pwlf_2.fit_breaks[3], my_pwlf_2.fit_breaks[4], 100)\\n\",\n    \"yhat4 = (my_pwlf_2.beta[0] +\\n\",\n    \"         (my_pwlf_2.beta[1])*(xhat4-my_pwlf_2.fit_breaks[0]) +\\n\",\n    \"         (my_pwlf_2.beta[2])*(xhat4-my_pwlf_2.fit_breaks[1]) +\\n\",\n    \"         (my_pwlf_2.beta[3])*(xhat4-my_pwlf_2.fit_breaks[2]) +\\n\",\n    \"         (my_pwlf_2.beta[4])*(xhat4-my_pwlf_2.fit_breaks[3]) +\\n\",\n    \"         (my_pwlf_2.beta[6])*(xhat4-my_pwlf_2.fit_breaks[0])**2 +\\n\",\n    \"         (my_pwlf_2.beta[7])*(xhat4-my_pwlf_2.fit_breaks[1])**2 +\\n\",\n    \"         (my_pwlf_2.beta[8])*(xhat4-my_pwlf_2.fit_breaks[2])**2 +\\n\",\n    \"         (my_pwlf_2.beta[9])*(xhat4-my_pwlf_2.fit_breaks[3])**2)\\n\",\n    \"plt.plot(x, y, 'o')\\n\",\n    \"plt.plot(xhat, yhat, '-.', label='First')\\n\",\n    \"plt.plot(xhat2, yhat2, '-.', label='Second')\\n\",\n    \"plt.plot(xhat3, yhat3, '-.', label='Third')\\n\",\n    \"plt.plot(xhat4, yhat4, '-.', label='Fourth')\\n\",\n    \"\\n\",\n    \"plt.xlabel('x')\\n\",\n    \"plt.ylabel('y')\\n\",\n    \"plt.legend()\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 6,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\\n\",\n      \"text/plain\": [\n       \"<Figure size 432x288 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"# Fifth segment\\n\",\n    \"xhat5 = np.linspace(my_pwlf_2.fit_breaks[4], my_pwlf_2.fit_breaks[5], 100)\\n\",\n    \"yhat5 = (my_pwlf_2.beta[0] +\\n\",\n    \"         (my_pwlf_2.beta[1])*(xhat5-my_pwlf_2.fit_breaks[0]) +\\n\",\n    \"         (my_pwlf_2.beta[2])*(xhat5-my_pwlf_2.fit_breaks[1]) +\\n\",\n    \"         (my_pwlf_2.beta[3])*(xhat5-my_pwlf_2.fit_breaks[2]) +\\n\",\n    \"         (my_pwlf_2.beta[4])*(xhat5-my_pwlf_2.fit_breaks[3]) +\\n\",\n    \"         (my_pwlf_2.beta[5])*(xhat5-my_pwlf_2.fit_breaks[4]) +\\n\",\n    \"         (my_pwlf_2.beta[6])*(xhat5-my_pwlf_2.fit_breaks[0])**2 +\\n\",\n    \"         (my_pwlf_2.beta[7])*(xhat5-my_pwlf_2.fit_breaks[1])**2 +\\n\",\n    \"         (my_pwlf_2.beta[8])*(xhat5-my_pwlf_2.fit_breaks[2])**2 +\\n\",\n    \"         (my_pwlf_2.beta[9])*(xhat5-my_pwlf_2.fit_breaks[3])**2 +\\n\",\n    \"         (my_pwlf_2.beta[10])*(xhat5-my_pwlf_2.fit_breaks[4])**2)\\n\",\n    \"plt.plot(x, y, 'o')\\n\",\n    \"plt.plot(xhat, yhat, '-.', label='First')\\n\",\n    \"plt.plot(xhat2, yhat2, '-.', label='Second')\\n\",\n    \"plt.plot(xhat3, yhat3, '-.', label='Third')\\n\",\n    \"plt.plot(xhat4, yhat4, '-.', label='Fourth')\\n\",\n    \"plt.plot(xhat5, yhat5, '-.', label='Fifth')\\n\",\n    \"\\n\",\n    \"plt.xlabel('x')\\n\",\n    \"plt.ylabel('y')\\n\",\n    \"plt.legend()\\n\",\n    \"plt.show()\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 7,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"from sympy import Symbol\\n\",\n    \"from sympy.utilities import lambdify\\n\",\n    \"x = Symbol('x')\\n\",\n    \"\\n\",\n    \"def get_symbolic_eqn(pwlf_, segment_number):\\n\",\n    \"    if pwlf_.degree < 1:\\n\",\n    \"        raise ValueError('Degree must be at least 1')\\n\",\n    \"    if segment_number < 1 or segment_number > pwlf_.n_segments:\\n\",\n    \"        raise ValueError('segment_number not possible')\\n\",\n    \"    # assemble degree = 1 first\\n\",\n    \"    for line in range(segment_number):\\n\",\n    \"        if line == 0:\\n\",\n    \"            my_eqn = pwlf_.beta[0] + (pwlf_.beta[1])*(x-pwlf_.fit_breaks[0])\\n\",\n    \"        else:\\n\",\n    \"            my_eqn += (pwlf_.beta[line+1])*(x-pwlf_.fit_breaks[line])\\n\",\n    \"    # assemble all other degrees\\n\",\n    \"    if pwlf_.degree > 1:\\n\",\n    \"        for k in range(2, pwlf_.degree + 1):\\n\",\n    \"            for line in range(segment_number):\\n\",\n    \"                beta_index = pwlf_.n_segments*(k-1) + line + 1 \\n\",\n    \"                my_eqn += (pwlf_.beta[beta_index])*(x-pwlf_.fit_breaks[line])**k\\n\",\n    \"    return my_eqn.simplify()\\n\",\n    \"\\n\",\n    \"eqn1 = get_symbolic_eqn(my_pwlf_2, 1)\\n\",\n    \"    \"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 8,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"name\": \"stdout\",\n     \"output_type\": \"stream\",\n     \"text\": [\n      \"Equation number:  1\\n\",\n      \"-0.953964059782599*x**2 + 1.89945177490653*x + 0.00538634182565454\\n\",\n      \"Equation number:  2\\n\",\n      \"0.951561315686298*x**2 - 5.69747505830914*x + 7.5772216545711\\n\",\n      \"Equation number:  3\\n\",\n      \"-0.949735350431857*x**2 + 9.48218236957122*x - 22.720785454735\\n\",\n      \"Equation number:  4\\n\",\n      \"0.926850298824217*x**2 - 12.9824424358344*x + 44.5102742956827\\n\",\n      \"Equation number:  5\\n\",\n      \"-1.03016230425747*x**2 + 18.5306546317065*x - 82.3508513333073\\n\"\n     ]\n    }\n   ],\n   \"source\": [\n    \"eqn_list = []\\n\",\n    \"f_list = []\\n\",\n    \"for i in range(my_pwlf_2.n_segments):\\n\",\n    \"    eqn_list.append(get_symbolic_eqn(my_pwlf_2, i + 1))\\n\",\n    \"    print('Equation number: ', i + 1)\\n\",\n    \"    print(eqn_list[-1])\\n\",\n    \"    f_list.append(lambdify(x, eqn_list[-1]))\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 9,\n   \"metadata\": {},\n   \"outputs\": [\n    {\n     \"data\": {\n      \"image/png\": \"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\\n\",\n      \"text/plain\": [\n       \"<Figure size 432x288 with 1 Axes>\"\n      ]\n     },\n     \"metadata\": {\n      \"needs_background\": \"light\"\n     },\n     \"output_type\": \"display_data\"\n    }\n   ],\n   \"source\": [\n    \"yhat1 = f_list[0](xhat)\\n\",\n    \"yhat2 = f_list[1](xhat2)\\n\",\n    \"yhat3 = f_list[2](xhat3)\\n\",\n    \"yhat4 = f_list[3](xhat4)\\n\",\n    \"yhat5 = f_list[4](xhat5)\\n\",\n    \"xtemp = np.linspace(0,10, 1000)\\n\",\n    \"plt.plot(my_pwlf_2.x_data, my_pwlf_2.y_data, 'o')\\n\",\n    \"plt.plot(xtemp, my_pwlf_2.predict(xtemp), '-k', label='Predict')\\n\",\n    \"plt.plot(xhat, yhat1, '-.', label='First')\\n\",\n    \"plt.plot(xhat2, yhat2, '-.', label='Second')\\n\",\n    \"plt.plot(xhat3, yhat3, '-.', label='Third')\\n\",\n    \"plt.plot(xhat4, yhat4, '-.', label='Fourth')\\n\",\n    \"plt.plot(xhat5, yhat5, '-.', label='Fifth')\\n\",\n    \"\\n\",\n    \"plt.xlabel('x')\\n\",\n    \"plt.ylabel('y')\\n\",\n    \"plt.legend()\\n\",\n    \"plt.show()\"\n   ]\n  }\n ],\n \"metadata\": {\n  \"kernelspec\": {\n   \"display_name\": \"Python 3\",\n   \"language\": \"python\",\n   \"name\": \"python3\"\n  },\n  \"language_info\": {\n   \"codemirror_mode\": {\n    \"name\": \"ipython\",\n    \"version\": 3\n   },\n   \"file_extension\": \".py\",\n   \"mimetype\": \"text/x-python\",\n   \"name\": \"python\",\n   \"nbconvert_exporter\": \"python\",\n   \"pygments_lexer\": \"ipython3\",\n   \"version\": \"3.6.8\"\n  }\n },\n \"nbformat\": 4,\n \"nbformat_minor\": 2\n}\n"
  },
  {
    "path": "examples/useCustomOptimizationRoutine.py",
    "content": "# use your own custom optimization routine to find the optimal location\n# of line segment locations\n\n# import our libraries\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\n# import custom optimization library\nfrom scipy.optimize import minimize\n\n# your data\ny = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n              4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n              8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n              1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n              8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n              4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n              5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n              7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n              1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n              1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n              3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n              6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n              1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n              1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n              5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n              9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n              0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n              4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n              8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n              1.41881288e-01, 1.62618058e-01])\nx = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n              5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n              1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n              1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n              7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n              4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n              7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n              1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n              1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n              1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n              3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n              1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n              1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n              1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n              7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n              1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n              0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n              6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n              1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n              1.65299640e-01, 1.79942720e-01])\n\n# initialize piecewise linear fit with your x and y data\nmy_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n# initialize custom optimization\nnumber_of_line_segments = 3\nmy_pwlf.use_custom_opt(number_of_line_segments)\n\n# i have number_of_line_segments - 1 number of variables\n# let's guess the correct location of the two unknown variables\n# (the program defaults to have end segments at x0= min(x) and xn=max(x)\nxGuess = np.zeros(number_of_line_segments - 1)\nxGuess[0] = 0.02\nxGuess[1] = 0.10\n\nres = minimize(my_pwlf.fit_with_breaks_opt, xGuess)\n\n# set up the break point locations\nx0 = np.zeros(number_of_line_segments + 1)\nx0[0] = np.min(x)\nx0[-1] = np.max(x)\nx0[1:-1] = res.x\n\n# calculate the parameters based on the optimal break point locations\nmy_pwlf.fit_with_breaks(x0)\n\n# predict for the determined points\nxHat = np.linspace(min(x), max(x), num=10000)\nyHat = my_pwlf.predict(xHat)\n\nplt.figure()\nplt.plot(x, y, 'o')\nplt.plot(xHat, yHat, '-')\nplt.show()\n"
  },
  {
    "path": "examples/weighted_least_squares_ex.py",
    "content": "from time import time\nimport os\nos.environ['OMP_NUM_THREADS'] = '1'\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\nt0 = time()\nnp.random.seed(123)\nn = 100\nn_data_sets = 100\nn_segments = 6\n# generate sine data\nx = np.linspace(0, 10, n)\ny = np.zeros((n_data_sets, n))\nsigma_change = np.linspace(0.001, 0.05, 100)\nfor i in range(n_data_sets):\n    y[i] = np.sin(x * np.pi / 2)\n    # add noise to the data\n    y[i] = np.random.normal(0, sigma_change, 100) + y[i]\nX = np.tile(x, n_data_sets)\n\n# perform an ordinary pwlf fit to the entire data\nmy_pwlf = pwlf.PiecewiseLinFit(X.flatten(), y.flatten())\nmy_pwlf.fit(n_segments)\n\n# compute the standard deviation in y\ny_std = np.std(y, axis=0)\n# set the weights to be one over the standard deviation\nweights = 1.0 / y_std\n\n# perform a weighted least squares to the data\nmy_pwlf_w = pwlf.PiecewiseLinFit(x, y.mean(axis=0), weights=weights)\nmy_pwlf_w.fit(n_segments)\n\n\n# compare the fits\nxhat = np.linspace(0, 10, 1000)\nyhat = my_pwlf.predict(xhat)\nyhat_w = my_pwlf_w.predict(xhat)\nt1 = time()\nprint('Runtime:', t1-t0)\nplt.figure()\nplt.plot(X.flatten(), y.flatten(), '.')\nplt.plot(xhat, yhat, '-', label='Ordinary LS')\nplt.plot(xhat, yhat_w, '-', label='Weighted LS')\nplt.legend()\nplt.show()\n"
  },
  {
    "path": "examples/weighted_least_squares_ex_stats.py",
    "content": "from time import time\nimport os\nos.environ['OMP_NUM_THREADS'] = '1'\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pwlf\nt0 = time()\nnp.random.seed(123)\nn = 100\nn_data_sets = 100\nn_segments = 6\n# generate sine data\nx = np.linspace(0, 10, n)\ny = np.zeros((n_data_sets, n))\nsigma_change = np.linspace(0.001, 0.05, 100)\nfor i in range(n_data_sets):\n    y[i] = np.sin(x * np.pi / 2)\n    # add noise to the data\n    y[i] = np.random.normal(0, sigma_change, 100) + y[i]\nX = np.tile(x, n_data_sets)\n\n# perform an ordinary pwlf fit to the entire data\nmy_pwlf = pwlf.PiecewiseLinFit(X.flatten(), y.flatten())\nmy_pwlf.fit(n_segments)\nse = my_pwlf.standard_errors()\npv = my_pwlf.prediction_variance(x)\n\n# compute the standard deviation in y\ny_std = np.std(y, axis=0)\n# set the weights to be one over the standard deviation\nweights = 1.0 / y_std\n\n# perform a weighted least squares to the data\nmy_pwlf_w = pwlf.PiecewiseLinFit(x, y.mean(axis=0), weights=weights)\nmy_pwlf_w.fit(n_segments)\nse_w = my_pwlf_w.standard_errors()\npv_w = my_pwlf_w.prediction_variance(x)\n\nprint('Standard errors', se, se_w)\nprint('Prediction varance', pv, pv_w)\n\n# compare the fits\nxhat = np.linspace(0, 10, 1000)\nyhat = my_pwlf.predict(xhat)\nyhat_w = my_pwlf_w.predict(xhat)\nt1 = time()\nprint('Runtime:', t1-t0)\nplt.figure()\nplt.plot(X.flatten(), y.flatten(), '.')\nplt.plot(xhat, yhat, '-', label='Ordinary LS')\nplt.plot(xhat, yhat_w, '-', label='Weighted LS')\nplt.legend()\nplt.show()\n"
  },
  {
    "path": "pwlf/__init__.py",
    "content": "from .pwlf import PiecewiseLinFit  # noqa F401\nfrom .version import __version__  # noqa F401\n"
  },
  {
    "path": "pwlf/pwlf.py",
    "content": "# -- coding: utf-8 --\n# MIT License\n#\n# Copyright (c) 2017-2022 Charles Jekel\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n# SOFTWARE.\n\n# import libraries\nimport numpy as np\nfrom scipy.optimize import differential_evolution\nfrom scipy.optimize import fmin_l_bfgs_b\nfrom scipy import linalg\nfrom scipy import stats\n\n# piecewise linear fit library\n\n\nclass PiecewiseLinFit(object):\n\n    def __init__(\n        self,\n        x,\n        y,\n        disp_res=False,\n        lapack_driver=\"gelsd\",\n        degree=1,\n        weights=None,\n        seed=None,\n    ):\n        r\"\"\"\n        An object to fit a continuous piecewise linear function\n        to data.\n\n        Initiate the library with the supplied x and y data.\n        Supply the x and y data of which you'll be fitting\n        a continuous piecewise linear model to where y(x).\n        by default pwlf won't print the optimization results.;\n\n        Parameters\n        ----------\n        x : array_like\n            The x or independent data point locations as list or 1 dimensional\n            numpy array.\n        y : array_like\n            The y or dependent data point locations as list or 1 dimensional\n            numpy array.\n        disp_res : bool, optional\n            Whether the optimization results should be printed. Default is\n            False.\n        lapack_driver : str, optional\n            Which LAPACK driver is used to solve the least-squares problem.\n            Default lapack_driver='gelsd'. Options are 'gelsd', 'gelsy',\n            'gelss'. For more see\n            https://docs.scipy.org/doc/scipy/reference/generated/scipy.linalg.lstsq.html\n            http://www.netlib.org/lapack/lug/node27.html\n        degree : int, list, optional\n            The degree of polynomial to use. The default is degree=1 for\n            linear models. Use degree=0 for constant models. Use a list for\n            mixed degrees (only supports degrees 1 or 0). List should be read\n            from left to right, degree=[1,0,1] corresponds to a mixed degree\n            model, where the left most segment has degree 1, the middle\n            segment degree 0, and the right most segment degree 1.\n        weights : None, or array_like\n            The individual weights are typically the reciprocal of the\n            standard deviation for each data point, where weights[i]\n            corresponds to one over the standard deviation of the ith data\n            point. Default weights=None.\n        seed : None, or int\n            Pick an integer which will set the numpy.random.seed on init.\n            The fit and fitfast methods rely on stochastic methods and setting\n            this value will make the results reproducible. The default\n            behavior is to not specify a seed.\n\n        Attributes\n        ----------\n        beta : ndarray (1-D)\n            The model parameters for the continuous piecewise linear fit.\n        break_0 : float\n            The smallest x value.\n        break_n : float\n            The largest x value.\n        c_n : int\n            The number of constraint points. This is the same as len(x_c).\n        degree: int, list\n            The degree of polynomial to use. The default is degree=1 for\n            linear models. Use degree=0 for constant models. This will be a\n            list if the user provided a list.\n        fit_breaks : ndarray (1-D)\n            breakpoint locations stored as a 1-D numpy array.\n        intercepts : ndarray (1-D)\n            The y-intercept of each line segment as a 1-D numpy array.\n        lapack_driver : str\n            Which LAPACK driver is used to solve the least-squares problem.\n        print : bool\n            Whether the optimization results should be printed. Default is\n            False.\n        n_data : int\n            The number of data points.\n        n_parameters : int\n            The number of model parameters. This is equivalent to the\n            len(beta).\n        n_segments : int\n            The number of line segments.\n        nVar : int\n            The number of variables in the global optimization problem.\n        se : ndarray (1-D)\n            Standard errors associated with each beta parameter. Specifically\n            se[0] correspounds to the standard error for beta[0], and so forth.\n        seed : int\n            Numpy random seed number set on init.\n        slopes : ndarray (1-D)\n            The slope of each ling segment as a 1-D numpy array. This assumes\n            that x[0] <= x[1] <= ... <= x[n]. Thus, slopes[0] is the slope\n            of the first line segment.\n        ssr : float\n            Optimal sum of square error.\n        x_c : ndarray (1-D)\n            The x locations of the data points that the piecewise linear\n            function will be forced to go through.\n        y_c : ndarray (1-D)\n            The y locations of the data points that the piecewise linear\n            function will be forced to go through.\n        x_data : ndarray (1-D)\n            The inputted parameter x from the 1-D data set.\n        y_data : ndarray (1-D)\n            The inputted parameter y from the 1-D data set.\n        y_w : ndarray (1-D)\n            The weighted y data vector.\n        zeta : ndarray (1-D)\n            The model parameters associated with the constraint function.\n\n        Methods\n        -------\n        fit(n_segments, x_c=None, y_c=None, **kwargs)\n            Fit a continuous piecewise linear function for a specified number\n            of line segments.\n        fitfast(n_segments, pop=2, **kwargs)\n            Fit a continuous piecewise linear function for a specified number\n            of line segments using a specialized optimization routine that\n            should be faster than fit() for large problems. The tradeoff may\n            be that fitfast() results in a lower quality model.\n        fit_with_breaks(breaks)\n            Fit a continuous piecewise linear function where the breakpoint\n            locations are known.\n        fit_with_breaks_force_points(breaks, x_c, y_c)\n            Fit a continuous piecewise linear function where the breakpoint\n            locations are known, and force the fit to go through points at x_c\n            and y_c.\n        predict(x, beta=None, breaks=None)\n            Evaluate the continuous piecewise linear function at new untested\n            points.\n        fit_with_breaks_opt(var)\n            The objective function to perform a continuous piecewise linear\n            fit for a specified number of breakpoints. This is to be used\n            with a custom optimization routine, and after use_custom_opt has\n            been called.\n        fit_force_points_opt(var)'\n            Same as fit_with_breaks_opt(var), except this allows for points to\n            be forced through x_c and y_c.\n        use_custom_opt(n_segments, x_c=None, y_c=None)\n            Function to initialize the attributes necessary to use a custom\n            optimization routine. Must be used prior to calling\n            fit_with_breaks_opt() or fit_force_points_opt().\n        calc_slopes()\n            Calculate the slopes of the lines after a piecewise linear\n            function has been fitted.\n        standard_errors()\n            Calculate the standard error of each model parameter in the fitted\n            piecewise linear function. Note, this assumes no uncertainty in\n            breakpoint locations.\n        prediction_variance(x)\n            Calculate the prediction variance at x locations for the fitted\n            piecewise linear function. Note, assumes no uncertainty in break\n            point locations.\n        r_squared()\n            Calculate the coefficient of determination, or 'R-squared' value\n            for a fitted piecewise linear function.\n\n        Examples\n        --------\n        Initialize for x, y data\n\n        >>> import pwlf\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n        Initialize for x,y data and print optimization results\n\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y, disp_res=True)\n\n        \"\"\"\n\n        self.print = disp_res\n        self.lapack_driver = lapack_driver\n        x, y = self._switch_to_np_array(x), self._switch_to_np_array(y)\n\n        self.x_data, self.y_data = x, y\n\n        # calculate the number of data points\n        self.n_data = x.size\n\n        # set the first and last break x values to be the min and max of x\n        self.break_0, self.break_n = np.min(self.x_data), np.max(self.x_data)\n        self.mixed_degree = False\n        if isinstance(degree, list):\n            # make sure the min and max are withing the limit\n            max_degree = max(degree)\n            min_degree = min(degree)\n            if min_degree >= 0 and max_degree <= 1:\n                self.mixed_degree = True\n                self.degree = degree\n            else:\n                not_suported = \"Not supported mixed degree. Max mixed degree=1\"\n                \", and min mixed degree=0\"\n                raise ValueError(not_suported)\n        elif degree < 12 and degree >= 0:\n            # I actually don't know what the upper degree limit should\n            self.degree = int(degree)\n        else:\n            raise ValueError(f\"degree = {degree} is not supported.\")\n\n        self.y_w = None\n        self.weights = None\n        # self.weights2 = None  # the squared weights vector\n        if weights is not None:\n            self.weights = self._switch_to_np_array(weights)\n            # self.weights2 = weights*weights\n            self.y_w = np.dot(self.y_data, np.eye(self.n_data) * self.weights)\n\n        if seed is not None:\n            np.random.seed(seed)\n        self.seed = seed\n\n        # initialize all empty attributes as None\n        self.fit_breaks = None\n        self.n_segments = None\n        self.n_parameters = None\n        self.beta = None\n        self.ssr = None\n        self.x_c = None\n        self.y_c = None\n        self.c_n = None\n        self.zeta = None\n        self.nVar = None\n        self.slopes = None\n        self.intercepts = None\n        self.se = None\n\n    @staticmethod\n    def _switch_to_np_array(input_):\n        r\"\"\"\n        Check the input, if it's not a Numpy array transform it to one.\n\n        Parameters\n        ----------\n        input_ : array_like\n            The object that requires a check.\n\n        Returns\n        -------\n        input_ : ndarray\n            The input data that's been transformed when required.\n        \"\"\"\n        if isinstance(input_, np.ndarray) is False:\n            input_ = np.array(input_)\n        return input_\n\n    def _get_breaks(self, input_):\n        r\"\"\"\n        Use input to form a ndarray containing breakpoints\n\n        Parameters\n        ----------\n        input_ : array_like\n            The object containing some of the breakpoints\n\n        Returns\n        -------\n        b_ : ndarray\n            All the line breaks\n        \"\"\"\n        v = np.sort(input_)\n        b_ = np.zeros(len(v) + 2)\n        b_[0], b_[1:-1], b_[-1] = self.break_0, v.copy(), self.break_n\n        return b_\n\n    def _fit_one_segment(self):\n        r\"\"\"\n        Fit for a single line segment\n        \"\"\"\n        self.fit_with_breaks([self.break_0, self.break_n])\n\n    def _fit_one_segment_force_points(self, x_c, y_c):\n        r\"\"\"\n        Fit for a single line segment with force points\n        \"\"\"\n        self.fit_with_breaks_force_points([self.break_0, self.break_n],\n                                          x_c, y_c)\n\n    def _check_mixed_degree_list(self, n_segments):\n        r\"\"\"\n        Fit for a single line segment with force points\n        \"\"\"\n        if self.mixed_degree:\n            degree_list_len = len(self.degree)\n            error_message = f\"\"\"\n            Error: degree list does not match n_segments!\n            degree list length {degree_list_len} must equal {n_segments}\"\"\"\n            if degree_list_len != n_segments:\n                raise ValueError(error_message)\n\n    def assemble_regression_matrix(self, breaks, x):\n        r\"\"\"\n        Assemble the linear regression matrix A\n\n        Parameters\n        ----------\n        breaks : array_like\n            The x locations where each line segment terminates. These are\n            referred to as breakpoints for each line segment. This should be\n            structured as a 1-D numpy array.\n        x : ndarray (1-D)\n            The x locations which the linear regression matrix is assembled on.\n            This must be a numpy array!\n\n        Returns\n        -------\n        A : ndarray (2-D)\n            The assembled linear regression matrix.\n\n        Examples\n        --------\n        Assemble the linear regression matrix on the x data for some set of\n        breakpoints.\n\n        >>> import pwlf\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        >>> breaks = [0.0, 0.5, 1.0]\n        >>> A = assemble_regression_matrix(breaks, self.x_data)\n\n        \"\"\"\n\n        breaks = self._switch_to_np_array(breaks)\n\n        # Sort the breaks, then store them\n        breaks_order = np.argsort(breaks)\n        self.fit_breaks = breaks[breaks_order]\n        # store the number of parameters and line segments\n        self.n_segments = len(breaks) - 1\n\n        # Assemble the regression matrix\n        A_list = [np.ones_like(x)]\n        if self.mixed_degree:\n            if len(self.degree) != self.n_segments:\n                raise ValueError(\n                    \"Number of degrees does not much number of segments.\",\n                )\n\n            for i in range(self.n_segments):\n                degree = self.degree[i]\n                if i == 0:\n                    A_list = [np.ones_like(x)]\n                    if degree == 1:\n                        A_list.append(x - self.fit_breaks[0])\n                if i > 0:\n                    if degree == 0:\n                        # all previous slopes must be written to 0\n                        inds = np.argwhere(x > self.fit_breaks[i])\n                        a_size = len(A_list)\n                        for j in range(1, a_size):\n                            A_list[j][inds] = 0.0\n                        # add the new zero slopes\n                        A_list.append(\n                            np.where(x > self.fit_breaks[i], 1.0, 0.0)\n                        )\n                    elif degree == 1:\n                        A_list.append(\n                            np.where(\n                                x > self.fit_breaks[i], x - self.fit_breaks[i],\n                                0.0\n                            )\n                        )\n        elif self.degree >= 1:\n            A_list.append(x - self.fit_breaks[0])\n            for i in range(self.n_segments - 1):\n                A_list.append(\n                    np.where(\n                        x > self.fit_breaks[i + 1], x - self.fit_breaks[i + 1],\n                        0.0\n                    )\n                )\n            if self.degree >= 2:\n                for k in range(2, self.degree + 1):\n                    A_list.append((x - self.fit_breaks[0]) ** k)\n                    for i in range(self.n_segments - 1):\n                        A_list.append(\n                            np.where(\n                                x > self.fit_breaks[i + 1],\n                                (x - self.fit_breaks[i + 1]) ** k,\n                                0.0,\n                            )\n                        )\n        else:\n            A_list = [np.ones_like(x)]\n            for i in range(self.n_segments - 1):\n                A_list.append(np.where(x > self.fit_breaks[i + 1], 1.0, 0.0))\n        A = np.vstack(A_list).T\n        self.n_parameters = A.shape[1]\n        return A\n\n    def fit_with_breaks(self, breaks):\n        r\"\"\"\n        A function which fits a continuous piecewise linear function\n        for specified breakpoint locations.\n\n        The function minimizes the sum of the square of the residuals for the\n        x y data.\n\n        If you want to understand the math behind this read\n        https://jekel.me/2018/Continous-piecewise-linear-regression/\n\n        Other useful resources:\n        http://golovchenko.org/docs/ContinuousPiecewiseLinearFit.pdf\n        https://www.mathworks.com/matlabcentral/fileexchange/40913-piecewise-linear-least-square-fittic\n        http://www.regressionist.com/2018/02/07/continuous-piecewise-linear-fitting/\n\n        Parameters\n        ----------\n        breaks : array_like\n            The x locations where each line segment terminates. These are\n            referred to as breakpoints for each line segment. This should be\n            structured as a 1-D numpy array.\n\n        Returns\n        -------\n        ssr : float\n            Returns the sum of squares of the residuals.\n\n        Raises\n        ------\n        LinAlgError\n            This typically means your regression problem is ill-conditioned.\n\n        Examples\n        --------\n        If your x data exists from 0 <= x <= 1 and you want three\n        piecewise linear lines where the lines terminate at x = 0.0, 0.3, 0.6,\n        and 1.0. This assumes that x is linearly spaced from [0, 1), and y is\n        random.\n\n        >>> import pwlf\n        >>> x = np.linspace(0.0, 1.0, 10)\n        >>> y = np.random.random(10)\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        >>> breaks = [0.0, 0.3, 0.6, 1.0]\n        >>> ssr = my_pwlf.fit_with_breaks(breaks)\n\n        \"\"\"\n        self._check_mixed_degree_list(len(breaks)-1)\n\n        breaks = self._switch_to_np_array(breaks)\n\n        A = self.assemble_regression_matrix(breaks, self.x_data)\n\n        # try to solve the regression problem\n        try:\n            ssr = self.lstsq(A)\n\n        except linalg.LinAlgError:\n            # the computation could not converge!\n            # on an error, return ssr = np.print_function\n            # You might have a singular Matrix!!!\n            ssr = np.inf\n        if ssr is None:\n            ssr = np.inf\n            # something went wrong...\n        self.ssr = ssr\n        return ssr\n\n    def fit_with_breaks_force_points(self, breaks, x_c, y_c):\n        r\"\"\"\n        A function which fits a continuous piecewise linear function\n        for specified breakpoint locations, where you force the\n        fit to go through the data points at x_c and y_c.\n\n        The function minimizes the sum of the square of the residuals for the\n        pair of x, y data points. If you want to understand the math behind\n        this read https://jekel.me/2018/Force-piecwise-linear-fit-through-data/\n\n        Parameters\n        ----------\n        breaks : array_like\n            The x locations where each line segment terminates. These are\n            referred to as breakpoints for each line segment. This should be\n            structured as a 1-D numpy array.\n        x_c : array_like\n            The x locations of the data points that the piecewise linear\n            function will be forced to go through.\n        y_c : array_like\n            The x locations of the data points that the piecewise linear\n            function will be forced to go through.\n\n        Returns\n        -------\n        L : float\n            Returns the Lagrangian function value. This is the sum of squares\n            of the residuals plus the constraint penalty.\n\n        Raises\n        ------\n        LinAlgError\n            This typically means your regression problem is ill-conditioned.\n        ValueError\n            You can't specify weights with x_c and y_c.\n\n        Examples\n        --------\n        If your x data exists from 0 <= x <= 1 and you want three\n        piecewise linear lines where the lines terminate at x = 0.0, 0.3, 0.6,\n        and 1.0. This assumes that x is linearly spaced from [0, 1), and y is\n        random. Additionally you desired that the piecewise linear function go\n        through the point (0.0, 0.0)\n\n        >>> import pwlf\n        >>> x = np.linspace(0.0, 1.0, 10)\n        >>> y = np.random.random(10)\n        >>> x_c = [0.0]\n        >>> y_c = [0.0]\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        >>> breaks = [0.0, 0.3, 0.6, 1.0]\n        >>> L = my_pwlf.fit_with_breaks_force_points(breaks, x_c, y_c)\n\n        \"\"\"\n        self._check_mixed_degree_list(len(breaks)-1)\n\n        x_c, y_c = self._switch_to_np_array(x_c), self._switch_to_np_array(y_c)\n        # sort the x_c and y_c data points, then store them\n        x_c_order = np.argsort(x_c)\n        self.x_c, self.y_c = x_c[x_c_order], y_c[x_c_order]\n        # store the number of constraints\n        self.c_n = len(self.x_c)\n\n        if self.weights is not None:\n            raise ValueError(\n                \"Constrained least squares with weights are\"\n                \" not supported since these have a tendency \"\n                \"of being numerically instable.\"\n            )\n\n        breaks = self._switch_to_np_array(breaks)\n\n        A = self.assemble_regression_matrix(breaks, self.x_data)\n        L = self.conlstsq(A)\n        return L\n\n    def predict(self, x, beta=None, breaks=None):\n        r\"\"\"\n        Evaluate the fitted continuous piecewise linear function at untested\n        points.\n\n        You can manfully specify the breakpoints and calculated\n        values for beta if you want to quickly predict from different models\n        and the same data set.\n\n        Parameters\n        ----------\n        x : array_like\n            The x locations where you want to predict the output of the fitted\n            continuous piecewise linear function.\n        beta : none or ndarray (1-D), optional\n            The model parameters for the continuous piecewise linear fit.\n            Default is None.\n        breaks : none or array_like, optional\n            The x locations where each line segment terminates. These are\n            referred to as breakpoints for each line segment. This should be\n            structured as a 1-D numpy array. Default is None.\n\n        Returns\n        -------\n        y_hat : ndarray (1-D)\n            The predicted values at x.\n\n        Examples\n        --------\n        Fits a simple model, then predict at x_new locations which are\n        linearly spaced.\n\n        >>> import pwlf\n        >>> x = np.linspace(0.0, 1.0, 10)\n        >>> y = np.random.random(10)\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        >>> breaks = [0.0, 0.3, 0.6, 1.0]\n        >>> ssr = my_pwlf.fit_with_breaks(breaks)\n        >>> x_new = np.linspace(0.0, 1.0, 100)\n        >>> yhat = my_pwlf.predict(x_new)\n\n        \"\"\"\n        if beta is not None and breaks is not None:\n            self.beta = beta\n            # Sort the breaks, then store them\n            breaks_order = np.argsort(breaks)\n            self.fit_breaks = breaks[breaks_order]\n            self.n_parameters = len(self.fit_breaks)\n            self.n_segments = self.n_parameters - 1\n\n        x = self._switch_to_np_array(x)\n\n        A = self.assemble_regression_matrix(self.fit_breaks, x)\n\n        # solve the regression problem\n        y_hat = np.dot(A, self.beta)\n        return y_hat\n\n    def fit_with_breaks_opt(self, var):\n        r\"\"\"\n        The objective function to perform a continuous piecewise linear\n        fit for a specified number of breakpoints. This is to be used\n        with a custom optimization routine, and after use_custom_opt has\n        been called.\n\n        This was intended for advanced users only.\n\n        See the following example\n        https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/useCustomOptimizationRoutine.py\n\n        Parameters\n        ----------\n        var : array_like\n            The breakpoint locations, or variable, in a custom\n            optimization routine.\n\n        Returns\n        -------\n        ssr : float\n            The sum of square of the residuals.\n\n        Raises\n        ------\n        LinAlgError\n            This typically means your regression problem is ill-conditioned.\n\n        Notes\n        -----\n        You should run use_custom_opt to initialize necessary object\n        attributes first.\n\n        Unlike fit_with_breaks, fit_with_breaks_opt automatically\n        assumes that the first and last breakpoints occur at the min and max\n        values of x.\n        \"\"\"\n        breaks = self._get_breaks(input_=var)\n        A = self.assemble_regression_matrix(breaks, self.x_data)\n\n        # try to solve the regression problem\n        try:\n            # least squares solver\n            ssr = self.lstsq(A, calc_slopes=False)\n\n        except linalg.LinAlgError:\n            # the computation could not converge!\n            # on an error, return ssr = np.inf\n            # You might have a singular Matrix!!!\n            ssr = np.inf\n        if ssr is None:\n            ssr = np.inf\n            # something went wrong...\n        return ssr\n\n    def fit_force_points_opt(self, var):\n        r\"\"\"\n        The objective function to perform a continuous piecewise linear\n        fit for a specified number of breakpoints. This is to be used\n        with a custom optimization routine, and after use_custom_opt has\n        been called.\n\n        Use this function if you intend to be force the model through\n        x_c and y_c, while performing a custom optimization.\n\n        This was intended for advanced users only.\n        See the following example\n        https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/useCustomOptimizationRoutine.py\n\n        Parameters\n        ----------\n        var : array_like\n            The breakpoint locations, or variable, in a custom\n            optimization routine.\n\n        Returns\n        -------\n        ssr : float\n            The sum of square of the residuals.\n\n        Raises\n        ------\n        LinAlgError\n            This typically means your regression problem is ill-conditioned.\n\n        Notes\n        -----\n        You should run use_custom_opt to initialize necessary object\n        attributes first.\n\n        Unlike fit_with_breaks_force_points, fit_force_points_opt\n        automatically assumes that the first and last breakpoints occur\n        at the min and max values of x.\n        \"\"\"\n\n        breaks = self._get_breaks(input_=var)\n        # Sort the breaks, then store them\n        breaks_order = np.argsort(breaks)\n        breaks = breaks[breaks_order]\n\n        A = self.assemble_regression_matrix(breaks, self.x_data)\n        L = self.conlstsq(A, calc_slopes=False)\n        return L\n\n    def fit(self, n_segments, x_c=None, y_c=None, bounds=None, **kwargs):\n        r\"\"\"\n        Fit a continuous piecewise linear function for a specified number\n        of line segments. Uses differential evolution to finds the optimum\n        location of breakpoints for a given number of line segments by\n        minimizing the sum of the square error.\n\n        Parameters\n        ----------\n        n_segments : int\n            The desired number of line segments.\n        x_c : array_like, optional\n            The x locations of the data points that the piecewise linear\n            function will be forced to go through.\n        y_c : array_like, optional\n            The x locations of the data points that the piecewise linear\n            function will be forced to go through.\n        bounds : array_like, optional\n            Bounds for each breakpoint location within the optimization. This\n            should have the shape of (n_segments, 2).\n        **kwargs : optional\n            Directly passed into scipy.optimize.differential_evolution(). This\n            will override any pwlf defaults when provided. See Note for more\n            information.\n\n        Returns\n        -------\n        fit_breaks : float\n            breakpoint locations stored as a 1-D numpy array.\n\n        Raises\n        ------\n        ValueError\n            You probably provided x_c without y_c (or vice versa).\n            You must provide both x_c and y_c if you plan to force\n            the model through data point(s).\n        ValueError\n            You can't specify weights with x_c and y_c.\n\n        Notes\n        -----\n        All **kwargs are passed into sicpy.optimize.differential_evolution.\n        If any **kwargs is used, it will override my differential_evolution,\n        defaults. This allows advanced users to tweak their own optimization.\n        For me information see:\n        https://github.com/cjekel/piecewise_linear_fit_py/issues/15#issuecomment-434717232\n\n        Examples\n        --------\n        This example shows you how to fit three continuous piecewise lines to\n        a dataset. This assumes that x is linearly spaced from [0, 1), and y is\n        random.\n\n        >>> import pwlf\n        >>> x = np.linspace(0.0, 1.0, 10)\n        >>> y = np.random.random(10)\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        >>> breaks = my_pwlf.fit(3)\n\n        Additionally you desired that the piecewise linear function go\n        through the point (0.0, 0.0).\n\n        >>> x_c = [0.0]\n        >>> y_c = [0.0]\n        >>> breaks = my_pwlf.fit(3, x_c=x_c, y_c=y_c)\n\n        Additionally you desired that the piecewise linear function go\n        through the points (0.0, 0.0) and (1.0, 1.0).\n\n        >>> x_c = [0.0, 1.0]\n        >>> y_c = [0.0, 1.0]\n        >>> breaks = my_pwlf.fit(3, x_c=x_c, y_c=y_c)\n\n        \"\"\"\n        self._check_mixed_degree_list(n_segments)\n        # check to see if you've provided just x_c or y_c\n        logic1 = x_c is not None and y_c is None\n        logic2 = y_c is not None and x_c is None\n        if logic1 or logic2:\n            raise ValueError(\"You must provide both x_c and y_c!\")\n\n        # set the function to minimize\n        min_function = self.fit_with_breaks_opt\n\n        # if you've provided both x_c and y_c\n        if x_c is not None and y_c is not None:\n            x_c = self._switch_to_np_array(x_c)\n            y_c = self._switch_to_np_array(y_c)\n            # sort the x_c and y_c data points, then store them\n            x_c_order = np.argsort(x_c)\n            self.x_c, self.y_c = x_c[x_c_order], y_c[x_c_order]\n            # store the number of constraints\n            self.c_n = len(self.x_c)\n            # Use a different function to minimize\n            min_function = self.fit_force_points_opt\n            if self.weights is not None:\n                raise ValueError(\n                    \"Constrained least squares with weights are\"\n                    \" not supported since these have a tendency \"\n                    \"of being numerically instable.\"\n                )\n            elif self.mixed_degree:\n                raise ValueError(\n                    \"Constrained least squares with mixed degree\"\n                    \" lists is not supported.\"\n                )\n\n        # store the number of line segments and number of parameters\n        self.n_segments = int(n_segments)\n        self.n_parameters = self.n_segments + 1\n\n        # calculate the number of variables I have to solve for\n        self.nVar = self.n_segments - 1\n\n        # special fit for one line segment\n        if self.n_segments == 1:\n            if x_c is None and y_c is None:\n                self._fit_one_segment()\n            else:\n                self._fit_one_segment_force_points(self.x_c, self.y_c)\n            return self.fit_breaks\n\n        # initiate the bounds of the optimization\n        if bounds is None:\n            bounds = np.zeros([self.nVar, 2])\n            bounds[:, 0] = self.break_0\n            bounds[:, 1] = self.break_n\n\n        # run the optimization\n        if len(kwargs) == 0:\n            res = differential_evolution(\n                min_function,\n                bounds,\n                strategy=\"best1bin\",\n                maxiter=1000,\n                popsize=50,\n                tol=1e-3,\n                mutation=(0.5, 1),\n                recombination=0.7,\n                seed=None,\n                callback=None,\n                disp=False,\n                polish=True,\n                init=\"latinhypercube\",\n                atol=1e-4,\n            )\n        else:\n            res = differential_evolution(min_function, bounds, **kwargs)\n        if self.print is True:\n            print(res)\n\n        self.ssr = res.fun\n\n        breaks = self._get_breaks(input_=res.x)\n\n        # assign values\n        if x_c is None and y_c is None:\n            self.fit_with_breaks(breaks)\n        else:\n            self.fit_with_breaks_force_points(breaks, self.x_c, self.y_c)\n\n        return self.fit_breaks\n\n    def fitfast(self, n_segments, pop=2, bounds=None, **kwargs):\n        r\"\"\"\n        Uses multi start LBFGSB optimization to find the location of\n        breakpoints for a given number of line segments by minimizing the sum\n        of the square of the errors.\n\n        The idea is that we generate n random latin hypercube samples\n        and run LBFGSB optimization on each one. This isn't guaranteed to\n        find the global optimum. It's suppose to be a reasonable compromise\n        between speed and quality of fit. Let me know how it works.\n\n        Since this is based on random sampling, you might want to run it\n        multiple times and save the best version... The best version will\n        have the lowest self.ssr (sum of square of residuals).\n\n        There is no guarantee that this will be faster than fit(), however\n        you may find it much faster sometimes.\n\n        Parameters\n        ----------\n        n_segments : int\n            The desired number of line segments.\n        pop : int, optional\n            The number of latin hypercube samples to generate. Default pop=2.\n        bounds : array_like, optional\n            Bounds for each breakpoint location within the optimization. This\n            should have the shape of (n_segments, 2).\n        **kwargs : optional\n            Directly passed into scipy.optimize.fmin_l_bfgs_b(). This\n            will override any pwlf defaults when provided. See Note for more\n            information.\n\n        Returns\n        -------\n        fit_breaks : float\n            breakpoint locations stored as a 1-D numpy array.\n\n        Notes\n        -----\n        The default number of multi start optimizations is 2.\n            - Decreasing this number will result in a faster run time.\n            - Increasing this number will improve the likelihood of finding\n                good results\n            - You can specify the number of starts using the following call\n            - Minimum value of pop is 2\n\n        All **kwargs are passed into sicpy.optimize.fmin_l_bfgs_b. If any\n        **kwargs is used, it will override my defaults. This allows\n        advanced users to tweak their own optimization. For me information see:\n        https://github.com/cjekel/piecewise_linear_fit_py/issues/15#issuecomment-434717232\n\n        Examples\n        --------\n        This example shows you how to fit three continuous piecewise lines to\n        a dataset. This assumes that x is linearly spaced from [0, 1), and y is\n        random.\n\n        >>> import pwlf\n        >>> x = np.linspace(0.0, 1.0, 10)\n        >>> y = np.random.random(10)\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        >>> breaks = my_pwlf.fitfast(3)\n\n        You can change the number of latin hypercube samples (or starting\n        point, locations) to use with pop. The following example will use 50\n        samples.\n\n        >>> breaks = my_pwlf.fitfast(3, pop=50)\n\n        \"\"\"\n        self._check_mixed_degree_list(n_segments)\n\n        pop = int(pop)  # ensure that the population is integer\n\n        self.n_segments = int(n_segments)\n        self.n_parameters = self.n_segments + 1\n\n        # calculate the number of variables I have to solve for\n        self.nVar = self.n_segments - 1\n\n        # special fit for one line segment\n        if self.n_segments == 1:\n            self._fit_one_segment()\n            return self.fit_breaks\n\n        # initiate the bounds of the optimization\n        if bounds is None:\n            bounds = np.zeros([self.nVar, 2])\n            bounds[:, 0] = self.break_0\n            bounds[:, 1] = self.break_n\n\n        # perform latin hypercube sampling\n        lhs = stats.qmc.LatinHypercube(self.nVar, seed=self.seed)\n        mypop = lhs.random(n=pop)\n\n        # scale the sampling to my variable range\n        mypop = mypop * (self.break_n - self.break_0) + self.break_0\n\n        x = np.zeros((pop, self.nVar))\n        f = np.zeros(pop)\n        d = []\n\n        for i, x0 in enumerate(mypop):\n            if len(kwargs) == 0:\n                resx, resf, resd = fmin_l_bfgs_b(\n                    self.fit_with_breaks_opt,\n                    x0,\n                    fprime=None,\n                    args=(),\n                    approx_grad=True,\n                    bounds=bounds,\n                    m=10,\n                    factr=1e2,\n                    pgtol=1e-05,\n                    epsilon=1e-08,\n                    iprint=-1,\n                    maxfun=15000,\n                    maxiter=15000,\n                    disp=None,\n                    callback=None,\n                )\n            else:\n                resx, resf, resd = fmin_l_bfgs_b(\n                    self.fit_with_breaks_opt,\n                    x0,\n                    fprime=None,\n                    approx_grad=True,\n                    bounds=bounds,\n                    **kwargs,\n                )\n            x[i, :] = resx\n            f[i] = resf\n            d.append(resd)\n            if self.print is True:\n                print(f\"{i + 1} of {pop} complete\")\n\n        # find the best result\n        best_ind = np.nanargmin(f)\n        best_val = f[best_ind]\n        best_break = x[best_ind]\n        res = (x[best_ind], f[best_ind], d[best_ind])\n        if self.print is True:\n            print(res)\n\n        self.ssr = best_val\n\n        breaks = self._get_breaks(input_=best_break)\n\n        # assign parameters\n        self.fit_with_breaks(breaks)\n\n        return self.fit_breaks\n\n    def fit_guess(self, guess_breakpoints, bounds=None, **kwargs):\n        r\"\"\"\n        Uses L-BFGS-B optimization to find the location of breakpoints\n        from a guess of where breakpoint locations should be.\n\n        In some cases you may have a good idea where the breakpoint locations\n        occur. It generally won't be necessary to run a full global\n        optimization to search the entire domain for the breakpoints when you\n        have a good idea where the breakpoints occur. Here a local optimization\n        is run from a guess of the breakpoint locations.\n\n        Parameters\n        ----------\n        guess_breakpoints : array_like\n            Guess where the breakpoints occur. This should be a list or numpy\n            array containing the locations where it appears breakpoints occur.\n        bounds : array_like, optional\n            Bounds for each breakpoint location within the optimization. This\n            should have the shape of (n_segments, 2).\n        **kwargs : optional\n            Directly passed into scipy.optimize.fmin_l_bfgs_b(). This\n            will override any pwlf defaults when provided. See Note for more\n            information.\n\n        Returns\n        -------\n        fit_breaks : float\n            breakpoint locations stored as a 1-D numpy array.\n\n        Notes\n        -----\n        All **kwargs are passed into sicpy.optimize.fmin_l_bfgs_b. If any\n        **kwargs is used, it will override my defaults. This allows\n        advanced users to tweak their own optimization. For me information see:\n        https://github.com/cjekel/piecewise_linear_fit_py/issues/15#issuecomment-434717232\n\n        You do not need to specify the x.min() or x.max() in geuss_breakpoints!\n\n        Examples\n        --------\n        In this example we see two distinct linear regions, and we believe a\n        breakpoint occurs at 6.0. We'll use the fit_guess() function to find\n        the best breakpoint location starting with this guess.\n\n        >>> import pwlf\n        >>> x = np.array([4., 5., 6., 7., 8.])\n        >>> y = np.array([11., 13., 16., 28.92, 42.81])\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        >>> breaks = my_pwlf.fit_guess([6.0])\n\n        Note specifying one breakpoint will result in two line segments.\n        If we wanted three line segments, we'll have to specify two\n        breakpoints.\n\n        >>> breaks = my_pwlf.fit_guess([5.5, 6.0])\n\n        \"\"\"\n        self._check_mixed_degree_list(guess_breakpoints)\n\n        # calculate the number of variables I have to solve for\n        self.nVar = len(guess_breakpoints)\n        self.n_segments = self.nVar + 1\n        self.n_parameters = self.n_segments + 1\n\n        # initiate the bounds of the optimization\n        if bounds is None:\n            bounds = np.zeros([self.nVar, 2])\n            bounds[:, 0] = self.break_0\n            bounds[:, 1] = self.break_n\n\n        if len(kwargs) == 0:\n            resx, resf, _ = fmin_l_bfgs_b(\n                self.fit_with_breaks_opt,\n                guess_breakpoints,\n                fprime=None,\n                args=(),\n                approx_grad=True,\n                bounds=bounds,\n                m=10,\n                factr=1e2,\n                pgtol=1e-05,\n                epsilon=1e-08,\n                iprint=-1,\n                maxfun=15000,\n                maxiter=15000,\n                disp=None,\n                callback=None,\n            )\n        else:\n            resx, resf, _ = fmin_l_bfgs_b(\n                self.fit_with_breaks_opt,\n                guess_breakpoints,\n                fprime=None,\n                approx_grad=True,\n                bounds=bounds,\n                **kwargs,\n            )\n\n        self.ssr = resf\n\n        breaks = self._get_breaks(input_=resx)\n\n        # assign values\n        self.fit_with_breaks(breaks)\n\n        return self.fit_breaks\n\n    def use_custom_opt(self, n_segments, x_c=None, y_c=None):\n        r\"\"\"\n        Provide the number of line segments you want to use with your\n        custom optimization routine.\n\n        Run this function first to initialize necessary attributes!!!\n\n        This was intended for advanced users only.\n\n        See the following example\n        https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/useCustomOptimizationRoutine.py\n\n        Parameters\n        ----------\n        n_segments : int\n            The x locations where each line segment terminates. These are\n            referred to as breakpoints for each line segment. This should be\n            structured as a 1-D numpy array.\n        x_c : none or array_like, optional\n            The x locations of the data points that the piecewise linear\n            function will be forced to go through.\n        y_c : none or array_like, optional\n            The x locations of the data points that the piecewise linear\n            function will be forced to go through.\n\n        Notes\n        -----\n        Optimize fit_with_breaks_opt(var) where var is a 1D array\n        containing the x locations of your variables\n        var has length n_segments - 1, because the two breakpoints\n        are always defined (1. the min of x, 2. the max of x).\n\n        fit_with_breaks_opt(var) will return the sum of the square of the\n        residuals which you'll want to minimize with your optimization\n        routine.\n\n        Raises\n        ------\n        ValueError\n            You can't specify weights with x_c and y_c.\n\n        \"\"\"\n        self._check_mixed_degree_list(n_segments)\n\n        self.n_segments = int(n_segments)\n        self.n_parameters = self.n_segments + 1\n\n        # calculate the number of variables I have to solve for\n        self.nVar = self.n_segments - 1\n        if x_c is not None or y_c is not None:\n            x_c = self._switch_to_np_array(x_c)\n            y_c = self._switch_to_np_array(y_c)\n            # sort the x_c and y_c data points, then store them\n            x_c_order = np.argsort(x_c)\n            self.x_c, self.y_c = x_c[x_c_order], y_c[x_c_order]\n            # store the number of constraints\n            self.c_n = len(self.x_c)\n            if self.weights is not None:\n                raise ValueError(\n                    \"Constrained least squares with weights are\"\n                    \" not supported since these have a tendency \"\n                    \"of being numerically instable.\"\n                )\n\n    def calc_slopes(self):\n        r\"\"\"\n        Calculate the slopes of the lines after a piecewise linear\n        function has been fitted.\n\n        This will also calculate the y-intercept from each line in the form\n        y = mx + b. The intercepts are stored at self.intercepts.\n\n        Returns\n        -------\n        slopes : ndarray(1-D)\n            The slope of each ling segment as a 1-D numpy array. This assumes\n            that x[0] <= x[1] <= ... <= x[n]. Thus, slopes[0] is the slope\n            of the first line segment.\n\n        Examples\n        --------\n        Calculate the slopes after performing a simple fit\n\n        >>> import pwlf\n        >>> x = np.linspace(0.0, 1.0, 10)\n        >>> y = np.random.random(10)\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        >>> breaks = my_pwlf.fit(3)\n        >>> slopes = my_pwlf.calc_slopes()\n\n        \"\"\"\n        y_hat = self.predict(self.fit_breaks)\n        self.slopes = np.divide(\n            (y_hat[1: self.n_segments + 1] - y_hat[: self.n_segments]),\n            (\n                self.fit_breaks[1: self.n_segments + 1]\n                - self.fit_breaks[: self.n_segments]\n            ),\n        )\n        self.intercepts = y_hat[0:-1] - self.slopes * self.fit_breaks[0:-1]\n        return self.slopes\n\n    def standard_errors(self, method=\"linear\", step_size=1e-4):\n        r\"\"\"\n        Calculate the standard errors for each beta parameter determined\n        from the piecewise linear fit. Typically +- 1.96*se will yield the\n        center of a 95% confidence region around your parameters. This\n        assumes the parmaters follow a normal distribution. For more\n        information see:\n        https://en.wikipedia.org/wiki/Standard_error\n\n        This calculation follows the derivation provided in [1]_.\n\n        Parameters\n        ----------\n        method : string, optional\n            Calculate the standard errors for a linear or non-linear\n            regression problem. The default is method='linear'. A taylor-\n            series expansion is performed when method='non-linear' (which is\n            commonly referred to as the Delta method).\n        step_size : float, optional\n            The step size to perform forward differences for the taylor-\n            series expansion when method='non-linear'. Default is\n            step_size=1e-4.\n\n        Returns\n        -------\n        se : ndarray (1-D)\n            Standard errors associated with each beta parameter. Specifically\n            se[0] correspounds to the standard error for beta[0], and so forth.\n\n        Raises\n        ------\n        AttributeError\n            You have probably not performed a fit yet.\n        ValueError\n            You supplied an unsupported method.\n        LinAlgError\n            This typically means your regression problem is ill-conditioned.\n\n        Notes\n        -----\n        The linear regression problem is when you know the breakpoint\n        locations (e.g. when using the fit_with_breaks function).\n\n        The non-linear regression problem is when you don't know the\n        breakpoint locations (e.g. when using the fit, fitfast, and fit_guess\n        functions).\n\n        References\n        ----------\n        .. [1] Coppe, A., Haftka, R. T., and Kim, N. H., “Uncertainty\n            Identification of Damage Growth Parameters Using Nonlinear\n            Regression,” AIAA Journal, Vol. 49, No. 12, dec 2011, pp.\n            2818–2821.\n\n        Examples\n        --------\n        Calculate the standard errors after performing a simple fit.\n\n        >>> import pwlf\n        >>> x = np.linspace(0.0, 1.0, 10)\n        >>> y = np.random.random(10)\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        >>> breaks = my_pwlf.fitfast(3)\n        >>> se = my_pwlf.standard_errors()\n\n        \"\"\"\n        try:\n            nb = self.beta.size\n        except AttributeError:\n            errmsg = (\n                \"You do not have any beta parameters. You must perform\"\n                \" a fit before using standard_errors().\"\n            )\n            raise AttributeError(errmsg)\n        ny = self.n_data\n        if method == \"linear\":\n            A = self.assemble_regression_matrix(self.fit_breaks, self.x_data)\n            y_hat = np.dot(A, self.beta)\n            e = y_hat - self.y_data\n\n        elif method == \"non-linear\":\n            nb = self.beta.size + self.fit_breaks.size - 2\n            f0 = self.predict(self.x_data)\n            A = np.zeros((ny, nb))\n            orig_beta = self.beta.copy()\n            orig_breaks = self.fit_breaks.copy()\n            # calculate differentials due to betas\n            for i in range(self.beta.size):\n                temp_beta = orig_beta.copy()\n                temp_beta[i] += step_size\n                # vary beta and keep breaks constant\n                f = self.predict(\n                    self.x_data, beta=temp_beta, breaks=orig_breaks,\n                )\n                A[:, i] = (f - f0) / step_size\n            # append differentials due to break points\n            for i in range(self.beta.size, nb):\n                # 'ind' ignores first and last entry in self.fit_breaks since\n                # these are simply the min/max of self.x_data.\n                ind = i - self.beta.size + 1\n                temp_breaks = orig_breaks.copy()\n                temp_breaks[ind] += step_size\n                # vary break and keep betas constant\n                f = self.predict(\n                    self.x_data,\n                    beta=orig_beta,\n                    breaks=temp_breaks,\n                )\n                A[:, i] = (f - f0) / step_size\n            e = f0 - self.y_data\n            # reset beta and breaks back to original values\n            self.beta = orig_beta\n            self.fit_breaks = orig_breaks\n\n        else:\n            errmsg = f\"Error: method='{method}' is not supported!\"\n            raise ValueError(errmsg)\n        # try to solve for the standard errors\n        try:\n            variance = np.dot(e, e) / (ny - nb)\n            if self.weights is None:\n                # solve for the unbiased estimate of variance\n                A2inv = np.abs(linalg.pinv(np.dot(A.T, A)).diagonal())\n                self.se = np.sqrt(variance * A2inv)\n            else:\n                A = (A.T * self.weights).T\n                A2inv = np.abs(linalg.pinv(np.dot(A.T, A)).diagonal())\n                self.se = np.sqrt(variance * A2inv)\n            return self.se\n\n        except linalg.LinAlgError:\n            raise linalg.LinAlgError(\"Singular matrix\")\n\n    def prediction_variance(self, x):\n        r\"\"\"\n        Calculate the prediction variance for each specified x location. The\n        prediction variance is the uncertainty of the model due to the lack of\n        data. This can be used to find a 95% confidence interval of possible\n        piecewise linear models based on the current data. This would be\n        done typically as y_hat +- 1.96*np.sqrt(pre_var). The\n        prediction_variance needs to be calculated at various x locations.\n        For more information see:\n        www2.mae.ufl.edu/haftka/vvuq/lectures/Regression-accuracy.pptx\n\n        Parameters\n        ----------\n        x : array_like\n            The x locations where you want the prediction variance from the\n            fitted continuous piecewise linear function.\n\n        Returns\n        -------\n        pre_var : ndarray (1-D)\n            Numpy array (floats) of prediction variance at each x location.\n\n        Raises\n        ------\n        AttributeError\n            You have probably not performed a fit yet.\n        LinAlgError\n            This typically means your regression problem is ill-conditioned.\n\n        Notes\n        -----\n        This assumes that your breakpoint locations are exact! and does\n        not consider the uncertainty with your breakpoint locations.\n\n        Examples\n        --------\n        Calculate the prediction variance at x_new after performing a simple\n        fit.\n\n        >>> import pwlf\n        >>> x = np.linspace(0.0, 1.0, 10)\n        >>> y = np.random.random(10)\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        >>> breaks = my_pwlf.fitfast(3)\n        >>> x_new = np.linspace(0.0, 1.0, 100)\n        >>> pre_var = my_pwlf.prediction_variance(x_new)\n\n        see also examples/prediction_variance.py\n\n        \"\"\"\n        try:\n            nb = self.beta.size\n        except AttributeError:\n            errmsg = (\n                \"You do not have any beta parameters. You must perform\"\n                \" a fit before using standard_errors().\"\n            )\n            raise AttributeError(errmsg)\n\n        ny = self.n_data\n        x = self._switch_to_np_array(x)\n\n        # Regression matrix on training data\n        Ad = self.assemble_regression_matrix(self.fit_breaks, self.x_data)\n\n        # try to solve for the unbiased variance estimation\n        try:\n            y_hat = np.dot(Ad, self.beta)\n            e = y_hat - self.y_data\n            # solve for the unbiased estimate of variance\n            variance = np.dot(e, e) / (ny - nb)\n\n        except linalg.LinAlgError:\n            raise linalg.LinAlgError(\"Singular matrix\")\n\n        # Regression matrix on prediction data\n        A = self.assemble_regression_matrix(self.fit_breaks, x)\n\n        # try to solve for the prediction variance at the x locations\n        try:\n            pre_var = variance * np.dot(\n                np.dot(A, linalg.pinv(np.dot(Ad.T, Ad))), A.T,\n            )\n            return pre_var.diagonal()\n\n        except linalg.LinAlgError:\n            raise linalg.LinAlgError(\"Singular matrix\")\n\n    def r_squared(self):\n        r\"\"\"\n        Calculate the coefficient of determination (\"R squared\", R^2) value\n        after a fit has been performed.\n        For more information see:\n        https://en.wikipedia.org/wiki/Coefficient_of_determination\n\n        Returns\n        -------\n        rsq : float\n            Coefficient of determination, or 'R squared' value.\n\n        Raises\n        ------\n        AttributeError\n            You have probably not performed a fit yet.\n        LinAlgError\n            This typically means your regression problem is ill-conditioned.\n\n        Examples\n        --------\n        Calculate the R squared value after performing a simple fit.\n\n        >>> import pwlf\n        >>> x = np.linspace(0.0, 1.0, 10)\n        >>> y = np.random.random(10)\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        >>> breaks = my_pwlf.fitfast(3)\n        >>> rsq = my_pwlf.r_squared()\n\n        \"\"\"\n        if self.fit_breaks is None:\n            errmsg = (\n                \"You do not have any beta parameters. You must perform\"\n                \" a fit before using standard_errors().\"\n            )\n            raise AttributeError(errmsg)\n        ssr = self.fit_with_breaks(self.fit_breaks)\n        ybar = np.ones(self.n_data) * np.mean(self.y_data)\n        ydiff = self.y_data - ybar\n        try:\n            sst = np.dot(ydiff, ydiff)\n            rsq = 1.0 - (ssr / sst)\n            return rsq\n        except linalg.LinAlgError:\n            raise linalg.LinAlgError(\"Singular matrix\")\n\n    def p_values(self, method=\"linear\", step_size=1e-4):\n        r\"\"\"\n        Calculate the p-values for each beta parameter.\n\n        This calculates the p-values for the beta parameters under the\n        assumption that your breakpoint locations are known. Section 2.4.2 of\n        [2]_ defines how to calculate the p-value of individual parameters.\n        This is really a marginal test since each parameter is dependent upon\n        the other parameters.\n\n        These values are typically compared to some confidence level alpha for\n        significance. A 95% confidence level would have alpha = 0.05.\n\n        Parameters\n        ----------\n        method : string, optional\n            Calculate the standard errors for a linear or non-linear\n            regression problem. The default is method='linear'. A taylor-\n            series expansion is performed when method='non-linear' (which is\n            commonly referred to as the Delta method).\n        step_size : float, optional\n            The step size to perform forward differences for the taylor-\n            series expansion when method='non-linear'. Default is\n            step_size=1e-4.\n\n        Returns\n        -------\n        p : ndarray (1-D)\n            p-values for each beta parameter where p-value[0] corresponds to\n            beta[0] and so forth\n\n        Raises\n        ------\n        AttributeError\n            You have probably not performed a fit yet.\n        ValueError\n            You supplied an unsupported method.\n\n        Notes\n        -----\n        The linear regression problem is when you know the breakpoint\n        locations (e.g. when using the fit_with_breaks function).\n\n        The non-linear regression problem is when you don't know the\n        breakpoint locations (e.g. when using the fit, fitfast, and fit_guess\n        functions).\n\n        See https://github.com/cjekel/piecewise_linear_fit_py/issues/14\n\n        References\n        ----------\n        .. [2] Myers RH, Montgomery DC, Anderson-Cook CM. Response surface\n            methodology . Hoboken. New Jersey: John Wiley & Sons, Inc.\n            2009;20:38-44.\n\n        Examples\n        --------\n        After performing a fit, one can calculate the p-value for each beta\n        parameter\n\n        >>> import pwlf\n        >>> x = np.linspace(0.0, 1.0, 10)\n        >>> y = np.random.random(10)\n        >>> my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        >>> breaks = my_pwlf.fitfast(3)\n        >>> x_new = np.linspace(0.0, 1.0, 100)\n        >>> p = my_pwlf.p_values(x_new)\n\n        see also examples/standard_errrors_and_p-values.py\n\n        \"\"\"\n        n = self.n_data\n        # degrees of freedom for t-distribution\n        if self.beta is None:\n            errmsg = (\n                \"You do not have any beta parameters. You must perform\"\n                \" a fit before using standard_errors().\"\n            )\n            raise AttributeError(errmsg)\n        k = self.beta.size - 1\n\n        if method == \"linear\":\n            self.standard_errors()\n            # calculate my t-value\n            t = self.beta / self.se\n\n        elif method == \"non-linear\":\n            nb = self.beta.size + self.fit_breaks.size - 2\n            k = nb - 1\n            self.standard_errors(method=method, step_size=step_size)\n            # the parameters for a non-linear model include interior breaks\n            parameters = np.concatenate((self.beta, self.fit_breaks[1:-1]))\n            # calculate my t-value\n            t = parameters / self.se\n        else:\n            errmsg = f\"Error: method='{method}' is not supported!\"\n            raise ValueError(errmsg)\n        # calculate the p-values\n        p = 2.0 * stats.t.sf(np.abs(t), df=n - k - 1)\n        return p\n\n    def lstsq(self, A, calc_slopes=True):\n        r\"\"\"\n        Perform the least squares fit for A matrix.\n\n        Parameters\n        ----------\n        A : ndarray (2-D)\n            The regression matrix you want to fit in the linear system of\n            equations Ab=y.\n        calc_slopes : boolean, optional\n            Whether to calculate slopes after performing a fit. Default is\n            calc_slopes=True.\n        \"\"\"\n        if self.weights is None:\n            beta, ssr, _, _ = linalg.lstsq(\n                A, self.y_data, lapack_driver=self.lapack_driver\n            )\n            # ssr is only calculated if self.n_data > self.n_parameters\n            # in this case I'll need to calculate ssr manually\n            # where ssr = sum of square of residuals\n            if self.n_data <= self.n_parameters:\n                y_hat = np.dot(A, beta)\n                e = y_hat - self.y_data\n                ssr = np.dot(e, e)\n        else:\n            beta, _, _, _ = linalg.lstsq(\n                (A.T * self.weights).T,\n                self.y_w,\n                lapack_driver=self.lapack_driver,\n            )\n            # calculate the weighted sum of square of residuals\n            y_hat = np.dot(A, beta)\n            e = y_hat - self.y_data\n            r = e * self.weights\n            ssr = np.dot(r, r)\n        if isinstance(ssr, list):\n            ssr = ssr[0]\n        elif isinstance(ssr, np.ndarray):\n            if ssr.size == 0:\n                y_hat = np.dot(A, beta)\n                e = y_hat - self.y_data\n                ssr = np.dot(e, e)\n            else:\n                ssr = ssr[0]\n        # save the beta parameters\n        self.beta = beta\n\n        if calc_slopes:\n            # save the slopes\n            self.calc_slopes()\n        return ssr\n\n    def conlstsq(self, A, calc_slopes=True):\n        r\"\"\"\n        Perform a constrained least squares fit for A matrix.\n\n        Parameters\n        ----------\n        A : ndarray (2-D)\n            The regression matrix you want to fit in the linear system of\n            equations Ab=y.\n        calc_slopes : boolean, optional\n            Whether to calculate slopes after performing a fit. Default is\n            calc_slopes=True.\n        \"\"\"\n        # Assemble the constraint matrix\n        C_list = [np.ones_like(self.x_c)]\n        if self.degree >= 1:\n            C_list.append(self.x_c - self.fit_breaks[0])\n            for i in range(self.n_segments - 1):\n                C_list.append(\n                    np.where(\n                        self.x_c > self.fit_breaks[i + 1],\n                        self.x_c - self.fit_breaks[i + 1],\n                        0.0,\n                    )\n                )\n            if self.degree >= 2:\n                for k in range(2, self.degree + 1):\n                    C_list.append((self.x_c - self.fit_breaks[0]) ** k)\n                    for i in range(self.n_segments - 1):\n                        C_list.append(\n                            np.where(\n                                self.x_c > self.fit_breaks[i + 1],\n                                (self.x_c - self.fit_breaks[i + 1]) ** k,\n                                0.0,\n                            )\n                        )\n        else:\n            for i in range(self.n_segments - 1):\n                C_list.append(\n                    np.where(\n                        self.x_c > self.fit_breaks[i + 1],\n                        1.0, 0.0,\n                        )\n                    )\n        C = np.vstack(C_list).T\n\n        _, m = A.shape\n        o, _ = C.shape\n\n        K = np.zeros((m + o, m + o))\n\n        K[:m, :m] = 2.0 * np.dot(A.T, A)\n        K[:m, m:] = C.T\n        K[m:, :m] = C\n        # Assemble right hand side vector\n        yt = np.dot(2.0 * A.T, self.y_data)\n\n        z = np.zeros(self.n_parameters + self.c_n)\n        z[: self.n_parameters] = yt\n        z[self.n_parameters:] = self.y_c\n\n        # try to solve the regression problem\n        try:\n            # Solve the least squares problem\n            beta_prime = linalg.solve(K, z)\n\n            # save the beta parameters\n            self.beta = beta_prime[0: self.n_parameters]\n            # save the zeta parameters\n            self.zeta = beta_prime[self.n_parameters:]\n\n            # save the slopes\n            if calc_slopes:\n                self.calc_slopes()\n\n            # Calculate ssr\n            # where ssr = sum of square of residuals\n            y_hat = np.dot(A, self.beta)\n            e = y_hat - self.y_data\n            ssr = np.dot(e, e)\n            self.ssr = ssr\n\n            # Calculate the Lagrangian function\n            # c_x_y = np.dot(C, self.x_c.T) - self.y_c\n            p = np.dot(C.T, self.zeta)\n            L = np.sum(np.abs(p)) + ssr\n\n        except linalg.LinAlgError:\n            # the computation could not converge!\n            # on an error, return L = np.inf\n            # You might have a singular Matrix!!!\n            L = np.inf\n        if L is None:\n            L = np.inf\n            # something went wrong...\n        return L\n"
  },
  {
    "path": "pwlf/version.py",
    "content": "__version__ = \"2.5.2\"\n"
  },
  {
    "path": "setup.py",
    "content": "import io\nfrom distutils.core import setup\n\n# load the version from version.py\nversion = {}\nwith open(\"pwlf/version.py\") as fp:\n    exec(fp.read(), version)\n\nsetup(\n    name=\"pwlf\",\n    version=version[\"__version__\"],\n    author=\"Charles Jekel\",\n    author_email=\"cjekel@gmail.com\",\n    packages=[\"pwlf\"],\n    url=\"https://github.com/cjekel/piecewise_linear_fit_py\",\n    license=\"MIT License\",\n    description=\"fit piecewise linear functions to data\",\n    long_description=io.open(\"README.rst\", encoding=\"utf-8\").read(),\n    # long_description_content_type='text/markdown',\n    platforms=[\"any\"],\n    install_requires=[\n        \"numpy >= 1.14.0\",\n        \"scipy >= 1.8.0\",\n    ],\n    classifiers=[\n        \"Programming Language :: Python :: 3\",\n    ],\n    python_requires=\">3.5\",\n)\n"
  },
  {
    "path": "sphinx_build_script.sh",
    "content": "\n#!/usr/bin/env bash\npip install .\n# clean docs and doctrees\nrm -r docs/*\nrm -r doctrees/*\n# make the documentation in gitignore folder\ncp examples/README.rst sphinxdocs/source/examples.rst\ncd sphinxdocs\nmake clean\nmake html\n# copy sphinx build into docs and doctrees\ncp -r build/doctrees/* ../doctrees/\ncp -r build/html/* ../docs/\n# grep -rl -e \"word-break: break-word\" --exclude=sphinx_build_script.sh | xargs sed -i 's/word-break: break-word/word-break: break-all/g'\n#cd ..\n#sed -i 's/break-word/break-all/g' docs/_static/basic.css \n"
  },
  {
    "path": "sphinxdocs/Makefile",
    "content": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD   = sphinx-build\nSOURCEDIR     = source\nBUILDDIR      = build\n\n# Put it first so that \"make\" without argument is like \"make help\".\nhelp:\n\t@$(SPHINXBUILD) -M help \"$(SOURCEDIR)\" \"$(BUILDDIR)\" $(SPHINXOPTS) $(O)\n\n.PHONY: help Makefile\n\n# Catch-all target: route all unknown targets to Sphinx using the new\n# \"make mode\" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).\n%: Makefile\n\t@$(SPHINXBUILD) -M $@ \"$(SOURCEDIR)\" \"$(BUILDDIR)\" $(SPHINXOPTS) $(O)"
  },
  {
    "path": "sphinxdocs/make.bat",
    "content": "@ECHO OFF\n\npushd %~dp0\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=sphinx-build\n)\nset SOURCEDIR=source\nset BUILDDIR=build\n\nif \"%1\" == \"\" goto help\n\n%SPHINXBUILD% >NUL 2>NUL\nif errorlevel 9009 (\n\techo.\n\techo.The 'sphinx-build' command was not found. Make sure you have Sphinx\n\techo.installed, then set the SPHINXBUILD environment variable to point\n\techo.to the full path of the 'sphinx-build' executable. Alternatively you\n\techo.may add the Sphinx directory to PATH.\n\techo.\n\techo.If you don't have Sphinx installed, grab it from\n\techo.http://sphinx-doc.org/\n\texit /b 1\n)\n\n%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%\ngoto end\n\n:help\n%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%\n\n:end\npopd\n"
  },
  {
    "path": "sphinxdocs/source/about.rst",
    "content": "About\n============\n\nA library for fitting continuous piecewise linear functions to data. Just specify the number of line segments you desire and provide the data.\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/examplePiecewiseFit.png\n   :alt: Example of a continuous piecewise linear fit to data.\n\nExample of a continuous piecewise linear fit to data.\n\nAll changes now stored in\n`CHANGELOG.md <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/CHANGELOG.md>`__\n\nPlease cite pwlf in your publications if it helps your research.\n\n.. code:: bibtex\n\n    @Manual{pwlf,\n        author = {Jekel, Charles F. and Venter, Gerhard},\n        title = {{pwlf:} A Python Library for Fitting 1D Continuous Piecewise Linear Functions},\n        year = {2019},\n        url = {https://github.com/cjekel/piecewise_linear_fit_py}\n    }\n"
  },
  {
    "path": "sphinxdocs/source/conf.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# Configuration file for the Sphinx documentation builder.\n#\n# This file does only contain a selection of the most common options. For a\n# full list see the documentation:\n# http://www.sphinx-doc.org/en/master/config\n\n# -- Path setup --------------------------------------------------------------\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#\nimport os\nimport sys\nimport pwlf\nsys.path.insert(0, os.path.abspath('../../pwlf'))\n\n\n# -- Project information -----------------------------------------------------\n\nproject = 'pwlf'\ncopyright = '2024, Charles Jekel'\nauthor = 'Charles Jekel'\n\n# The short X.Y version\nversion = ''\n# The full version, including alpha/beta/rc tags\nrelease = pwlf.__version__\n\n# -- General configuration ---------------------------------------------------\n\n# autoclass_content = 'both'\n\n# If your documentation needs a minimal Sphinx version, state it here.\n#\n# needs_sphinx = '1.0'\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n    'sphinx.ext.autodoc',\n    'sphinx.ext.intersphinx',\n    'sphinx.ext.githubpages',\n    'numpydoc',\n]\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = ['_templates']\n\n# The suffix(es) of source filenames.\n# You can specify multiple suffix as a list of string:\n#\n# source_suffix = ['.rst', '.md']\nsource_suffix = '.rst'\n\n# The master toctree document.\nmaster_doc = 'index'\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#\n# This is also used if you do content translation via gettext catalogs.\n# Usually you set \"language\" from the command line for these cases.\nlanguage = \"en\"\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\n# This pattern also affects html_static_path and html_extra_path.\nexclude_patterns = []\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = None\n\n\n# -- Options for HTML output -------------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\n#\n#html_theme = 'sphinx'\n\n# Theme options are theme-specific and customize the look and feel of a theme\n# further.  For a list of options available for each theme, see the\n# documentation.\n#\nhtml_theme_options = {'analytics_id': 'G-QKPGZSZ8CD'}\nhtml_favicon = 'favicon.ico'\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = ['_static']\n\n# Custom sidebar templates, must be a dictionary that maps document names\n# to template names.\n#\n# The default sidebars (for documents that don't match any pattern) are\n# defined by theme itself.  Builtin themes are using these templates by\n# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',\n# 'searchbox.html']``.\n#\n# html_sidebars = {}\n\n\n# -- Options for HTMLHelp output ---------------------------------------------\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = 'pwlfdoc'\n\n\n# -- Options for LaTeX output ------------------------------------------------\n\nlatex_elements = {\n    # The paper size ('letterpaper' or 'a4paper').\n    #\n    # 'papersize': 'letterpaper',\n\n    # The font size ('10pt', '11pt' or '12pt').\n    #\n    # 'pointsize': '10pt',\n\n    # Additional stuff for the LaTeX preamble.\n    #\n    # 'preamble': '',\n\n    # Latex figure (float) alignment\n    #\n    # 'figure_align': 'htbp',\n}\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title,\n#  author, documentclass [howto, manual, or own class]).\nlatex_documents = [\n    (master_doc, 'pwlf.tex', 'pwlf Documentation',\n     'Charles Jekel', 'manual'),\n]\n\n\n# -- Options for manual page output ------------------------------------------\n\n# One entry per manual page. List of tuples\n# (source start file, name, description, authors, manual section).\nman_pages = [\n    (master_doc, 'pwlf', 'pwlf Documentation',\n     [author], 1)\n]\n\n\n# -- Options for Texinfo output ----------------------------------------------\n\n# Grouping the document tree into Texinfo files. List of tuples\n# (source start file, target name, title, author,\n#  dir menu entry, description, category)\ntexinfo_documents = [\n    (master_doc, 'pwlf', 'pwlf Documentation',\n     author, 'pwlf', 'One line description of project.',\n     'Miscellaneous'),\n]\n\n\n# -- Options for Epub output -------------------------------------------------\n\n# Bibliographic Dublin Core info.\nepub_title = project\n\n# The unique identifier of the text. This can be a ISBN number\n# or the project homepage.\n#\n# epub_identifier = ''\n\n# A unique identification for the text.\n#\n# epub_uid = ''\n\n# A list of files that should not be packed into the epub file.\nepub_exclude_files = ['search.html']\n\n\n# -- Extension configuration -------------------------------------------------\n\n# -- Options for intersphinx extension ---------------------------------------\n\n# Example configuration for intersphinx: refer to the Python standard library.\nintersphinx_mapping = {'python': ('https://docs.python.org/3', None)}\n"
  },
  {
    "path": "sphinxdocs/source/examples.rst",
    "content": "Examples\n========\n\nAll of these examples will use the following data and imports.\n\n.. code:: python\n\n   import numpy as np\n   import matplotlib.pyplot as plt\n   import pwlf\n\n   # your data\n   y = np.array([0.00000000e+00, 9.69801700e-03, 2.94350340e-02,\n                 4.39052750e-02, 5.45343950e-02, 6.74104940e-02,\n                 8.34831790e-02, 1.02580042e-01, 1.22767939e-01,\n                 1.42172312e-01, 0.00000000e+00, 8.58600000e-06,\n                 8.31543400e-03, 2.34184100e-02, 3.39709150e-02,\n                 4.03581990e-02, 4.53545600e-02, 5.02345260e-02,\n                 5.55253360e-02, 6.14750770e-02, 6.82125120e-02,\n                 7.55892510e-02, 8.38356810e-02, 9.26413070e-02,\n                 1.02039790e-01, 1.11688258e-01, 1.21390666e-01,\n                 1.31196948e-01, 0.00000000e+00, 1.56706510e-02,\n                 3.54628780e-02, 4.63739040e-02, 5.61442590e-02,\n                 6.78542550e-02, 8.16388310e-02, 9.77756110e-02,\n                 1.16531753e-01, 1.37038283e-01, 0.00000000e+00,\n                 1.16951050e-02, 3.12089850e-02, 4.41776550e-02,\n                 5.42877590e-02, 6.63321350e-02, 8.07655920e-02,\n                 9.70363280e-02, 1.15706975e-01, 1.36687642e-01,\n                 0.00000000e+00, 1.50144640e-02, 3.44519970e-02,\n                 4.55907760e-02, 5.59556700e-02, 6.88450940e-02,\n                 8.41374060e-02, 1.01254006e-01, 1.20605073e-01,\n                 1.41881288e-01, 1.62618058e-01])\n   x = np.array([0.00000000e+00, 8.82678000e-03, 3.25615100e-02,\n                 5.66106800e-02, 7.95549800e-02, 1.00936330e-01,\n                 1.20351520e-01, 1.37442010e-01, 1.51858250e-01,\n                 1.64433570e-01, 0.00000000e+00, -2.12600000e-05,\n                 7.03872000e-03, 1.85494500e-02, 3.00926700e-02,\n                 4.17617000e-02, 5.37279600e-02, 6.54941000e-02,\n                 7.68092100e-02, 8.76596300e-02, 9.80525800e-02,\n                 1.07961810e-01, 1.17305210e-01, 1.26063930e-01,\n                 1.34180360e-01, 1.41725010e-01, 1.48629710e-01,\n                 1.55374770e-01, 0.00000000e+00, 1.65610200e-02,\n                 3.91016100e-02, 6.18679400e-02, 8.30997400e-02,\n                 1.02132890e-01, 1.19011260e-01, 1.34620080e-01,\n                 1.49429370e-01, 1.63539960e-01, -0.00000000e+00,\n                 1.01980300e-02, 3.28642800e-02, 5.59461900e-02,\n                 7.81388400e-02, 9.84458400e-02, 1.16270210e-01,\n                 1.31279040e-01, 1.45437090e-01, 1.59627540e-01,\n                 0.00000000e+00, 1.63404300e-02, 4.00086000e-02,\n                 6.34390200e-02, 8.51085900e-02, 1.04787860e-01,\n                 1.22120350e-01, 1.36931660e-01, 1.50958760e-01,\n                 1.65299640e-01, 1.79942720e-01])\n\n1.  `fit with known breakpoint\n    locations <#fit-with-known-breakpoint-locations>`__\n2.  `fit for specified number of line\n    segments <#fit-for-specified-number-of-line-segments>`__\n3.  `fitfast for specified number of line\n    segments <#fitfast-for-specified-number-of-line-segments>`__\n4.  `force a fit through data\n    points <#force-a-fit-through-data-points>`__\n5.  `use custom optimization\n    routine <#use-custom-optimization-routine>`__\n6.  `pass differential evolution\n    keywords <#pass-differential-evolution-keywords>`__\n7.  `find the best number of line\n    segments <#find-the-best-number-of-line-segments>`__\n8.  `model persistence <#model-persistence>`__\n9.  `bad fits when you have more unknowns than\n    data <#bad-fits-when-you-have-more-unknowns-than-data>`__\n10. `fit with a breakpoint guess <#fit-with-a-breakpoint-guess>`__\n11. `get the linear regression\n    matrix <#get-the-linear-regression-matrix>`__\n12. `use of TensorFlow <#use-of-tensorflow>`__\n13. `fit constants or polynomials <#fit-constants-or-polynomials>`__\n14. `specify breakpoint bounds <#specify-breakpoint-bounds>`__\n15. `non-linear standard errors and\n    p-values <#non-linear-standard-errors-and-p-values>`__\n16. `obtain the equations of fitted\n    pwlf <#obtain-the-equations-of-fitted-pwlf>`__\n17. `weighted least squares fit <#weighted-least-squares-fit>`__\n18. `reproducible results <#reproducible results>`__\n\nfit with known breakpoint locations\n-----------------------------------\n\nYou can perform a least squares fit if you know the breakpoint\nlocations.\n\n.. code:: python\n\n   # your desired line segment end locations\n   x0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data with the specified break points\n   # (ie the x locations of where the line segments\n   # will terminate)\n   my_pwlf.fit_with_breaks(x0)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/fit_breaks.png\n   :alt: fit with known breakpoint locations\n\n   fit with known breakpoint locations\n\nfit for specified number of line segments\n-----------------------------------------\n\nUse a global optimization to find the breakpoint locations that minimize\nthe sum of squares error. This uses `Differential\nEvolution <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html>`__\nfrom scipy.\n\n.. code:: python\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data for four line segments\n   res = my_pwlf.fit(4)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/numberoflines.png\n   :alt: fit for specified number of line segments\n\n   fit for specified number of line segments\n\nfitfast for specified number of line segments\n---------------------------------------------\n\nThis performs a fit for a specified number of line segments with a\nmulti-start gradient based optimization. This should be faster than\n`Differential\nEvolution <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html>`__\nfor a small number of starting points.\n\n.. code:: python\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data for four line segments\n   # this performs 3 multi-start optimizations\n   res = my_pwlf.fitfast(4, pop=3)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/fitfast.png\n   :alt: fitfast for specified number of line segments\n\n   fitfast for specified number of line segments\n\nforce a fit through data points\n-------------------------------\n\nSometimes it’s necessary to force the piecewise continuous model through\na particular data point, or a set of data points. The following example\nfinds the best 4 line segments that go through two data points.\n\n.. code:: python\n\n   # initialize piecewise linear fit with your x and y data\n   myPWLF = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the function with four line segments\n   # force the function to go through the data points\n   # (0.0, 0.0) and (0.19, 0.16) \n   # where the data points are of the form (x, y)\n   x_c = [0.0, 0.19]\n   y_c = [0.0, 0.2]\n   res = myPWLF.fit(4, x_c, y_c)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), 0.19, num=10000)\n   yHat = myPWLF.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/force.png\n   :alt: force a fit through data points\n\n   force a fit through data points\n\nuse custom optimization routine\n-------------------------------\n\nYou can use your favorite optimization routine to find the breakpoint\nlocations. The following example uses scipy’s\n`minimize <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html>`__\nfunction.\n\n.. code:: python\n\n   from scipy.optimize import minimize\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # initialize custom optimization\n   number_of_line_segments = 3\n   my_pwlf.use_custom_opt(number_of_line_segments)\n\n   # i have number_of_line_segments - 1 number of variables\n   # let's guess the correct location of the two unknown variables\n   # (the program defaults to have end segments at x0= min(x)\n   # and xn=max(x)\n   xGuess = np.zeros(number_of_line_segments - 1)\n   xGuess[0] = 0.02\n   xGuess[1] = 0.10\n\n   res = minimize(my_pwlf.fit_with_breaks_opt, xGuess)\n\n   # set up the break point locations\n   x0 = np.zeros(number_of_line_segments + 1)\n   x0[0] = np.min(x)\n   x0[-1] = np.max(x)\n   x0[1:-1] = res.x\n\n   # calculate the parameters based on the optimal break point locations\n   my_pwlf.fit_with_breaks(x0)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\npass differential evolution keywords\n------------------------------------\n\nYou can pass keyword arguments from the ``fit`` function into scipy’s\n`Differential\nEvolution <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html>`__.\n\n.. code:: python\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data for four line segments\n   # this sets DE to have an absolute tolerance of 0.1\n   res = my_pwlf.fit(4, atol=0.1)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\nfind the best number of line segments\n-------------------------------------\n\nThis example uses EGO (bayesian optimization) and a penalty function to\nfind the best number of line segments. This will require careful use of\nthe penalty parameter ``l``. Use this template to automatically find the\nbest number of line segments.\n\n.. code:: python\n\n   from GPyOpt.methods import BayesianOptimization\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # define your objective function\n\n\n   def my_obj(x):\n       # define some penalty parameter l\n       # you'll have to arbitrarily pick this\n       # it depends upon the noise in your data,\n       # and the value of your sum of square of residuals\n       l = y.mean()*0.001\n       f = np.zeros(x.shape[0])\n       for i, j in enumerate(x):\n           my_pwlf.fit(j[0])\n           f[i] = my_pwlf.ssr + (l*j[0])\n       return f\n\n\n   # define the lower and upper bound for the number of line segments\n   bounds = [{'name': 'var_1', 'type': 'discrete',\n              'domain': np.arange(2, 40)}]\n\n   np.random.seed(12121)\n\n   myBopt = BayesianOptimization(my_obj, domain=bounds, model_type='GP',\n                                 initial_design_numdata=10,\n                                 initial_design_type='latin',\n                                 exact_feval=True, verbosity=True,\n                                 verbosity_model=False)\n   max_iter = 30\n\n   # perform the bayesian optimization to find the optimum number\n   # of line segments\n   myBopt.run_optimization(max_iter=max_iter, verbosity=True)\n\n   print('\\n \\n Opt found \\n')\n   print('Optimum number of line segments:', myBopt.x_opt)\n   print('Function value:', myBopt.fx_opt)\n   myBopt.plot_acquisition()\n   myBopt.plot_convergence()\n\n   # perform the fit for the optimum\n   my_pwlf.fit(myBopt.x_opt)\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\nmodel persistence\n-----------------\n\nYou can save fitted models with pickle. Alternatively see\n`joblib <https://joblib.readthedocs.io/en/latest/>`__.\n\n.. code:: python\n\n   # if you use Python 2.x you should import cPickle\n   # import cPickle as pickle\n   # if you use Python 3.x you can just use pickle\n   import pickle\n\n   # your desired line segment end locations\n   x0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # fit the data with the specified break points\n   my_pwlf.fit_with_breaks(x0)\n\n   # save the fitted model\n   with open('my_fit.pkl', 'wb') as f:\n       pickle.dump(my_pwlf, f, pickle.HIGHEST_PROTOCOL)\n\n   # load the fitted model\n   with open('my_fit.pkl', 'rb') as f:\n       my_pwlf = pickle.load(f)\n\nbad fits when you have more unknowns than data\n----------------------------------------------\n\nYou can get very bad fits with pwlf when you have more unknowns than\ndata points. The following example will fit 99 line segments to the 59\ndata points. While this will result in an error of zero, the model will\nhave very weird predictions within the data. You should not fit more\nunknowns than you have data with pwlf!\n\n.. code:: python\n\n   break_locations = np.linspace(min(x), max(x), num=100)\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n   my_pwlf.fit_with_breaks(break_locations)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o')\n   plt.plot(xHat, yHat, '-')\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/badfit.png\n   :alt: bad fits when you have more unknowns than data\n\n   bad fits when you have more unknowns than data\n\nfit with a breakpoint guess\n---------------------------\n\nIn this example we see two distinct linear regions, and we believe a\nbreakpoint occurs at 6.0. We’ll use the fit_guess() function to find the\nbest breakpoint location starting with this guess. These fits should be\nmuch faster than the ``fit`` or ``fitfast`` function when you have a\nreasonable idea where the breakpoints occur.\n\n.. code:: python\n\n   import numpy as np\n   import pwlf\n   x = np.array([4., 5., 6., 7., 8.])\n   y = np.array([11., 13., 16., 28.92, 42.81])\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n   breaks = my_pwlf.fit_guess([6.0])\n\nNote specifying one breakpoint will result in two line segments. If we\nwanted three line segments, we’ll have to specify two breakpoints.\n\n.. code:: python\n\n   breaks = my_pwlf.fit_guess([5.5, 6.0])\n\nget the linear regression matrix\n--------------------------------\n\nIn some cases it may be desirable to work with the linear regression\nmatrix directly. The following example grabs the linear regression\nmatrix ``A`` for a specific set of breakpoints. In this case we assume\nthat the breakpoints occur at each of the data points. Please see the\n`paper <https://github.com/cjekel/piecewise_linear_fit_py/tree/master/paper>`__\nfor details about the regression matrix ``A``.\n\n.. code:: python\n\n   import numpy as np\n   import pwlf\n   # select random seed for reproducibility\n   np.random.seed(123)\n   # generate sin wave data\n   x = np.linspace(0, 10, num=100)\n   y = np.sin(x * np.pi / 2)\n   ytrue = y.copy()\n   # add noise to the data\n   y = np.random.normal(0, 0.05, 100) + ytrue\n\n   my_pwlf_en = pwlf.PiecewiseLinFit(x, y)\n   # copy the x data to use as break points\n   breaks = my_pwlf_en.x_data.copy()\n   # create the linear regression matrix A \n   A = my_pwlf_en.assemble_regression_matrix(breaks, my_pwlf_en.x_data)\n\nWe can perform fits that are more complicated than a least squares fit\nwhen we have the regression matrix. The following uses the Elastic Net\nregularizer to perform an interesting fit with the regression matrix.\n\n.. code:: python\n\n   from sklearn.linear_model import ElasticNetCV\n   # set up the elastic net\n   en_model = ElasticNetCV(cv=5,\n                           l1_ratio=[.1, .5, .7, .9,\n                                     .95, .99, 1],\n                           fit_intercept=False,\n                           max_iter=1000000, n_jobs=-1)\n   # fit the model using the elastic net\n   en_model.fit(A, my_pwlf_en.y_data)\n\n   # predict from the elastic net parameters\n   xhat = np.linspace(x.min(), x.max(), 1000)\n   yhat_en = my_pwlf_en.predict(xhat, breaks=breaks,\n                                beta=en_model.coef_)\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/sin_en_net_fit.png\n   :alt: interesting elastic net fit\n\n   interesting elastic net fit\n\nuse of tensorflow\n-----------------\n\nYou need to install\n`pwlftf <https://github.com/cjekel/piecewise_linear_fit_py_tf>`__ which\nwill have the ``PiecewiseLinFitTF`` class. For performance benchmarks\n(these benchmarks are outdated! and the regular pwlf may be faster in\nmany applications) see this blog\n`post <https://jekel.me/2019/Adding-tensorflow-to-pwlf/>`__.\n\nThe use of the TF class is nearly identical to the original class,\nhowever note the following exceptions. ``PiecewiseLinFitTF`` does:\n\n-  not have a ``lapack_driver`` option\n-  have an optional parameter ``dtype``, so you can choose between the\n   float64 and float32 data types\n-  have an optional parameter ``fast`` to switch between Cholesky\n   decomposition (default ``fast=True``), and orthogonal decomposition\n   (``fast=False``)\n\n.. code:: python\n\n   import pwlftf as pwlf\n   # your desired line segment end locations\n   x0 = np.array([min(x), 0.039, 0.10, max(x)])\n\n   # initialize TF piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFitTF(x, y, dtype='float32)\n\n   # fit the data with the specified break points\n   # (ie the x locations of where the line segments\n   # will terminate)\n   my_pwlf.fit_with_breaks(x0)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat = my_pwlf.predict(xHat)\n\nfit constants or polynomials\n----------------------------\n\nYou can use pwlf to fit segmented constant models, or piecewise\npolynomials. The following example fits a segmented constant model,\npiecewise linear, and a piecewise quadratic model to a sine wave.\n\n.. code:: python\n\n   # generate sin wave data\n   x = np.linspace(0, 10, num=100)\n   y = np.sin(x * np.pi / 2)\n   # add noise to the data\n   y = np.random.normal(0, 0.05, 100) + y\n\n   # initialize piecewise linear fit with your x and y data\n   # pwlf lets you fit continuous model for many degree polynomials\n   # degree=0 constant\n   # degree=1 linear (default)\n   # degree=2 quadratic\n   my_pwlf_0 = pwlf.PiecewiseLinFit(x, y, degree=0)\n   my_pwlf_1 = pwlf.PiecewiseLinFit(x, y, degree=1)  # default\n   my_pwlf_2 = pwlf.PiecewiseLinFit(x, y, degree=2)\n\n   # fit the data for four line segments\n   res0 = my_pwlf_0.fitfast(5, pop=50)\n   res1 = my_pwlf_1.fitfast(5, pop=50)\n   res2 = my_pwlf_2.fitfast(5, pop=50)\n\n   # predict for the determined points\n   xHat = np.linspace(min(x), max(x), num=10000)\n   yHat0 = my_pwlf_0.predict(xHat)\n   yHat1 = my_pwlf_1.predict(xHat)\n   yHat2 = my_pwlf_2.predict(xHat)\n\n   # plot the results\n   plt.figure()\n   plt.plot(x, y, 'o', label='Data')\n   plt.plot(xHat, yHat0, '-', label='degree=0')\n   plt.plot(xHat, yHat1, '--', label='degree=1')\n   plt.plot(xHat, yHat2, ':', label='degree=2')\n   plt.legend()\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/multi_degree.png\n   :alt: Example of multiple degree fits to a sine wave.\n\n   Example of multiple degree fits to a sine wave.\n\nspecify breakpoint bounds\n-------------------------\n\nYou may want extra control over the search space for feasible\nbreakpoints. One way to do this is to specify the bounds for each\nbreakpoint location.\n\n.. code:: python\n\n   # generate sin wave data\n   x = np.linspace(0, 10, num=100)\n   y = np.sin(x * np.pi / 2)\n   # add noise to the data\n   y = np.random.normal(0, 0.05, 100) + y\n\n   # initialize piecewise linear fit with your x and y data\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n\n   # define custom bounds for the interior break points\n   n_segments = 4\n   bounds = np.zeros((n_segments-1, 2))\n   # first breakpoint\n   bounds[0, 0] = 0.0  # lower bound\n   bounds[0, 1] = 3.5  # upper bound\n   # second breakpoint\n   bounds[1, 0] = 3.0  # lower bound\n   bounds[1, 1] = 7.0  # upper bound\n   # third breakpoint\n   bounds[2, 0] = 6.0  # lower bound\n   bounds[2, 1] = 10.0  # upper bound\n   res = my_pwlf.fit(n_segments, bounds=bounds)\n\nnon-linear standard errors and p-values\n---------------------------------------\n\nYou can calculate non-linear standard errors using the Delta method.\nThis will calculate the standard errors of the piecewise linear\nparameters (intercept + slopes) and the breakpoint locations!\n\nFirst let us generate true piecewise linear data.\n\n.. code:: python\n\n   from __future__ import print_function\n   # generate a true piecewise linear data\n   np.random.seed(5)\n   n_data = 100\n   x = np.linspace(0, 1, num=n_data)\n   y = np.random.random(n_data)\n   my_pwlf_gen = pwlf.PiecewiseLinFit(x, y)\n   true_beta = np.random.normal(size=5)\n   true_breaks = np.array([0.0, 0.2, 0.5, 0.75, 1.0])\n   y = my_pwlf_gen.predict(x, beta=true_beta, breaks=true_breaks)\n\n   plt.figure()\n   plt.title('True piecewise linear data')\n   plt.plot(x, y)\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/figs/true_pwlf.png\n   :alt: True piecewise linear data.\n\n   True piecewise linear data.\n\nNow we can perform a fit, calculate the standard errors, and p-values.\nThe non-linear method uses a first order taylor series expansion to\nlinearize the non-linear regression problem. A positive step_size\nperforms a forward difference, and a negative step_size would perform a\nbackwards difference.\n\n.. code:: python\n\n   my_pwlf = pwlf.PiecewiseLinFit(x, y)\n   res = my_pwlf.fitfast(4, pop=100)\n\n   p = my_pwlf.p_values(method='non-linear', step_size=1e-4)\n   se = my_pwlf.se  # standard errors\n\nThe standard errors and p-values correspond to each model parameter.\nFirst the beta parameters (intercept + slopes) and then the breakpoints.\nWe can assemble the parameters, and print a table of the result with the\nfollowing code.\n\n.. code:: python\n\n   parameters = np.concatenate((my_pwlf.beta,\n                                my_pwlf.fit_breaks[1:-1]))\n\n   header = ['Parameter type', 'Parameter value', 'Standard error', 't',\n             'P > np.abs(t) (p-value)']\n   print(*header, sep=' | ')\n   values = np.zeros((parameters.size, 5), dtype=np.object_)\n   values[:, 1] = np.around(parameters, decimals=3)\n   values[:, 2] = np.around(se, decimals=3)\n   values[:, 3] = np.around(parameters / se, decimals=3)\n   values[:, 4] = np.around(p, decimals=3)\n\n   for i, row in enumerate(values):\n       if i < my_pwlf.beta.size:\n           row[0] = 'Beta'\n           print(*row, sep=' | ')\n       else:\n           row[0] = 'Breakpoint'\n           print(*row, sep=' | ')\n\n============== =============== ============== ============== =======================\nParameter type Parameter value Standard error t              P > np.abs(t) (p-value)\n============== =============== ============== ============== =======================\nBeta           1.821           0.0            1763191476.046 0.0\nBeta           -0.427          0.0            -46404554.493  0.0\nBeta           -1.165          0.0            -111181494.162 0.0\nBeta           -1.397          0.0            -168954500.421 0.0\nBeta           0.873           0.0            93753841.242   0.0\nBreakpoint     0.2             0.0            166901856.885  0.0\nBreakpoint     0.5             0.0            537785803.646  0.0\nBreakpoint     0.75            0.0            482311769.159  0.0\n============== =============== ============== ============== =======================\n\nobtain the equations of fitted pwlf\n-----------------------------------\n\nSometimes you may want the mathematical equations that represent your\nfitted model. This is easy to perform if you don’t mind using sympy.\n\nThe following code will fit 5 line segments of degree=2 to a sin wave.\n\n.. code:: python\n\n   import numpy as np\n   import pwlf\n   # generate sin wave data\n   x = np.linspace(0, 10, num=100)\n   y = np.sin(x * np.pi / 2)\n   # add noise to the data\n   y = np.random.normal(0, 0.05, 100) + y\n   my_pwlf_2 = pwlf.PiecewiseLinFit(x, y, degree=2)\n   res2 = my_pwlf_2.fitfast(5, pop=50)\n\nGiven this fit, the following code will print the mathematical equation\nfor each line segment.\n\n.. code:: python\n\n   from sympy import Symbol\n   from sympy.utilities import lambdify\n   x = Symbol('x')\n\n\n   def get_symbolic_eqn(pwlf_, segment_number):\n       if pwlf_.degree < 1:\n           raise ValueError('Degree must be at least 1')\n       if segment_number < 1 or segment_number > pwlf_.n_segments:\n           raise ValueError('segment_number not possible')\n       # assemble degree = 1 first\n       for line in range(segment_number):\n           if line == 0:\n               my_eqn = pwlf_.beta[0] + (pwlf_.beta[1])*(x-pwlf_.fit_breaks[0])\n           else:\n               my_eqn += (pwlf_.beta[line+1])*(x-pwlf_.fit_breaks[line])\n       # assemble all other degrees\n       if pwlf_.degree > 1:\n           for k in range(2, pwlf_.degree + 1):\n               for line in range(segment_number):\n                   beta_index = pwlf_.n_segments*(k-1) + line + 1 \n                   my_eqn += (pwlf_.beta[beta_index])*(x-pwlf_.fit_breaks[line])**k\n       return my_eqn.simplify()\n\n\n   eqn_list = []\n   f_list = []\n   for i in range(my_pwlf_2.n_segments):\n       eqn_list.append(get_symbolic_eqn(my_pwlf_2, i + 1))\n       print('Equation number: ', i + 1)\n       print(eqn_list[-1])\n       f_list.append(lambdify(x, eqn_list[-1]))\n\nwhich should print out something like the following:\n\n.. code:: python\n\n   Equation number:  1\n   -0.953964059782599*x**2 + 1.89945177490653*x + 0.00538634182565454\n   Equation number:  2\n   0.951561315686298*x**2 - 5.69747505830914*x + 7.5772216545711\n   Equation number:  3\n   -0.949735350431857*x**2 + 9.48218236957122*x - 22.720785454735\n   Equation number:  4\n   0.926850298824217*x**2 - 12.9824424358344*x + 44.5102742956827\n   Equation number:  5\n   -1.03016230425747*x**2 + 18.5306546317065*x - 82.3508513333073\n\nFor more information on how this works, see\n`this <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/understanding_higher_degrees/polynomials_in_pwlf.ipynb>`__\njupyter notebook.\n\nweighted least squares fit\n--------------------------\n\nSometimes your data will not have a constant variance\n(heteroscedasticity), and you need to perform a weighted least squares\nfit. The following example will perform a standard and weighted fit so\nyou can compare the differences. First we need to generate a data set\nwhich will be a good candidate to use for weighted least squares fits.\n\n.. code:: python\n\n   # generate data with heteroscedasticity\n   n = 100\n   n_data_sets = 100\n   n_segments = 6\n   # generate sine data\n   x = np.linspace(0, 10, n)\n   y = np.zeros((n_data_sets, n))\n   sigma_change = np.linspace(0.001, 0.05, 100)\n   for i in range(n_data_sets):\n       y[i] = np.sin(x * np.pi / 2)\n       # add noise to the data\n       y[i] = np.random.normal(0, sigma_change, 100) + y[i]\n   X = np.tile(x, n_data_sets)\n\nThe individual weights in pwlf are the reciprocal of the standard\ndeviation for each data point. Here weights[i] corresponds to one over\nthe standard deviation of the ith data point. The result of this is that\ndata points with higher variance are less important to the overall pwlf\nthan data point with small variance. Let’s perform a standard pwlf fit\nand a weighted fit.\n\n.. code:: python\n\n   # perform an ordinary pwlf fit to the entire data\n   my_pwlf = pwlf.PiecewiseLinFit(X.flatten(), y.flatten())\n   my_pwlf.fit(n_segments)\n\n   # compute the standard deviation in y\n   y_std = np.std(y, axis=0)\n   # set the weights to be one over the standard deviation\n   weights = 1.0 / y_std\n\n   # perform a weighted least squares to the data\n   my_pwlf_w = pwlf.PiecewiseLinFit(x, y.mean(axis=0), weights=weights)\n   my_pwlf_w.fit(n_segments)\n\n   # compare the fits\n   xhat = np.linspace(0, 10, 1000)\n   yhat = my_pwlf.predict(xhat)\n   yhat_w = my_pwlf_w.predict(xhat)\n\n   plt.figure()\n   plt.plot(X.flatten(), y.flatten(), '.')\n   plt.plot(xhat, yhat, '-', label='Ordinary LS')\n   plt.plot(xhat, yhat_w, '-', label='Weighted LS')\n   plt.legend()\n   plt.show()\n\n.. figure:: https://raw.githubusercontent.com/cjekel/piecewise_linear_fit_py/master/examples/weighted_least_squares_example.png\n   :alt: Weighted pwlf fit.\n\n   Weighted pwlf fit.\n\nWe can see that the weighted pwlf fit tries fit data with low variance\nbetter than data with high variance, however the ordinary pwlf fits the\ndata assuming a uniform variance.\n\nreproducible results\n--------------------\n\nThe `fit` and `fitfast` methods are stochastic and may not give the same\nresult every time the program is run. To have reproducible results you can\nmanually specify a numpy.random.seed on init. Now everytime the following\nprogram is run, the results of the fit(2) should be the same.\n\n.. code:: python\n\n   # initialize piecewise linear fit with a random seed\n   my_pwlf = pwlf.PiecewiseLinFit(x, y, seed=123)\n\n   # Now the fit() method will be reproducible\n   my_pwlf.fit(2)\n\n"
  },
  {
    "path": "sphinxdocs/source/how_it_works.rst",
    "content": "How it works\n============\n\nThis\n`paper <https://github.com/cjekel/piecewise_linear_fit_py/raw/master/paper/pwlf_Jekel_Venter_v2.pdf>`__\nexplains how this library works in detail.\n\nThis is based on a formulation of a piecewise linear least squares fit,\nwhere the user must specify the location of break points. See `this\npost <http://jekel.me/2018/Continous-piecewise-linear-regression/>`__\nwhich goes through the derivation of a least squares regression problem\nif the break point locations are known. Alternatively check out\n`Golovchenko\n(2004) <http://golovchenko.org/docs/ContinuousPiecewiseLinearFit.pdf>`__.\n\nGlobal optimization is used to find the best location for the user\ndefined number of line segments. I specifically use the `differential\nevolution <https://docs.scipy.org/doc/scipy-0.17.0/reference/generated/scipy.optimize.differential_evolution.html>`__\nalgorithm in SciPy. I default the differential evolution algorithm to be\naggressive, and it is probably overkill for your problem. So feel free\nto pass your own differential evolution keywords to the library. See\n`this\nexample <https://github.com/cjekel/piecewise_linear_fit_py/blob/master/examples/fitForSpecifiedNumberOfLineSegments_passDiffEvoKeywords.py>`__.\n"
  },
  {
    "path": "sphinxdocs/source/index.rst",
    "content": "pwlf: piecewise linear fitting\n================================\n\nFit piecewise linear functions to data!\n\n.. toctree::\n   :maxdepth: 2\n\n   installation\n   how_it_works\n   examples\n   pwlf\n   about\n   requirements\n   license\n\nIndices and tables\n==================\n\n* :ref:`genindex`\n* :ref:`search`\n"
  },
  {
    "path": "sphinxdocs/source/installation.rst",
    "content": "Installation\n============\n\nPython Package Index (PyPI)\n---------------------------\n\nYou can now install with pip.\n\n::\n\n   python -m pip install pwlf\n\nConda\n-----\n\nIf you have conda, you can also install from conda-forge.\n\n::\n\n   conda install -c conda-forge pwlf\n\nFrom source\n-----------\n\nOr clone the repo\n\n::\n\n   git clone https://github.com/cjekel/piecewise_linear_fit_py.git\n\nthen install with pip\n\n::\n\n   python -m pip install ./piecewise_linear_fit_py\n\n"
  },
  {
    "path": "sphinxdocs/source/license.rst",
    "content": "License\n=======\n\nMIT License\n\nCopyright (c) 2017-2020 Charles Jekel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "sphinxdocs/source/modules.rst",
    "content": "pwlf\n====\n\n.. toctree::\n   :maxdepth: 4\n\n   pwlf\n"
  },
  {
    "path": "sphinxdocs/source/pwlf.rst",
    "content": "pwlf package contents\n============\n\n.. autosummary::\n     :toctree: stubs\n\n     pwlf.PiecewiseLinFit\n\n.. autoclass:: pwlf.PiecewiseLinFit\n    :members:\n    :undoc-members:\n    :show-inheritance:\n"
  },
  {
    "path": "sphinxdocs/source/requirements.rst",
    "content": "Requirements\n============\n\n`NumPy <https://pypi.org/project/numpy/>`__ (>= 1.14.0)\n\n`SciPy <https://pypi.org/project/scipy/>`__ (>= 1.2.0)\n\n`pyDOE <https://pypi.org/project/pyDOE/>`__ ( >= 0.3.8)\n"
  },
  {
    "path": "tests/__init__.py",
    "content": ""
  },
  {
    "path": "tests/tests.py",
    "content": "import numpy as np\nimport unittest\nimport pwlf\n\n\nclass TestEverything(unittest.TestCase):\n\n    x_small = np.array((0.0, 1.0, 1.5, 2.0))\n    y_small = np.array((0.0, 1.0, 1.1, 1.5))\n    x_sin = np.linspace(0, 10, num=100)\n    y_sin = np.sin(x_sin * np.pi / 2)\n\n    def test_break_point_spot_on(self):\n        # check that I can fit when break points spot on a\n        my_fit1 = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x0 = self.x_small.copy()\n        ssr = my_fit1.fit_with_breaks(x0)\n        self.assertTrue(np.isclose(ssr, 0.0))\n\n    def test_break_point_spot_on_list(self):\n        # check that I can fit when break points spot on a\n        my_fit1 = pwlf.PiecewiseLinFit(list(self.x_small), list(self.y_small))\n        x0 = self.x_small.copy()\n        ssr = my_fit1.fit_with_breaks(x0)\n        self.assertTrue(np.isclose(ssr, 0.0))\n\n    def test_degree_not_supported(self):\n        try:\n            _ = pwlf.PiecewiseLinFit(self.x_small, self.y_small,\n                                     degree=100)\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n\n    def test_x_c_not_supplied(self):\n        try:\n            mf = pwlf.PiecewiseLinFit(self.x_small, self.y_small,\n                                      degree=1)\n            mf.fit(2, x_c=[1.0])\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n\n    def test_y_c_not_supplied(self):\n        try:\n            mf = pwlf.PiecewiseLinFit(self.x_small, self.y_small,\n                                      degree=1)\n            mf.fit(2, y_c=[1.0])\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n\n    def test_lapack_driver(self):\n        # check that I can fit when break points spot on a\n        my_fit1 = pwlf.PiecewiseLinFit(self.x_small, self.y_small,\n                                       lapack_driver='gelsy')\n        x0 = self.x_small.copy()\n        ssr = my_fit1.fit_with_breaks(x0)\n        self.assertTrue(np.isclose(ssr, 0.0))\n\n    def test_assembly(self):\n        # check that I can fit when break points spot on a\n        my_fit = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x0 = self.x_small.copy()\n        A = my_fit.assemble_regression_matrix(x0, my_fit.x_data)\n        Asb = np.array([[1.,  0.,  0.,  0.],\n                        [1.,  x0[1]-x0[0],  0.,  0.],\n                        [1.,  x0[2]-x0[0], x0[2]-x0[1], 0.],\n                        [1.,  x0[3]-x0[0], x0[3]-x0[1], x0[3]-x0[2]]])\n        self.assertTrue(np.allclose(A, Asb))\n\n    def test_assembly_list(self):\n        # check that I can fit when break points spot on a\n        my_fit = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x0 = self.x_small.copy()\n        A = my_fit.assemble_regression_matrix(x0, list(my_fit.x_data))\n        Asb = np.array([[1.,  0.,  0.,  0.],\n                        [1.,  x0[1]-x0[0],  0.,  0.],\n                        [1.,  x0[2]-x0[0], x0[2]-x0[1], 0.],\n                        [1.,  x0[3]-x0[0], x0[3]-x0[1], x0[3]-x0[2]]])\n        self.assertTrue(np.allclose(A, Asb))\n\n    def test_break_point_spot_on_r2(self):\n        # test r squared value with known solution\n        my_fit1 = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x0 = self.x_small.copy()\n        my_fit1.fit_with_breaks(x0)\n        rsq = my_fit1.r_squared()\n        self.assertTrue(np.isclose(rsq, 1.0))\n\n    def test_break_point_diff_x0_0(self):\n        # check diff loc\n        my_fit2 = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x0 = self.x_small.copy()\n        x0[1] = 1.00001\n        x0[2] = 1.50001\n        ssr2 = my_fit2.fit_with_breaks(x0)\n        self.assertTrue(np.isclose(ssr2, 0.0))\n\n    def test_break_point_diff_x0_1(self):\n        # check if my duplicate is in a different location\n        x0 = self.x_small.copy()\n        my_fit3 = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x0[1] = 0.9\n        ssr3 = my_fit3.fit_with_breaks(x0)\n        self.assertTrue(np.isclose(ssr3, 0.0))\n\n    def test_break_point_diff_x0_2(self):\n        # check if my duplicate is in a different location\n        x0 = self.x_small.copy()\n        my_fit4 = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x0[1] = 1.1\n        ssr4 = my_fit4.fit_with_breaks(x0)\n        self.assertTrue(np.isclose(ssr4, 0.0))\n\n    def test_break_point_diff_x0_3(self):\n        # check if my duplicate is in a different location\n        x0 = self.x_small.copy()\n        my_fit5 = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x0[2] = 1.6\n        ssr5 = my_fit5.fit_with_breaks(x0)\n        self.assertTrue(np.isclose(ssr5, 0.0))\n\n    def test_break_point_diff_x0_4(self):\n        # check if my duplicate is in a different location\n        x0 = self.x_small.copy()\n        my_fit6 = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x0[2] = 1.4\n        ssr6 = my_fit6.fit_with_breaks(x0)\n        self.assertTrue(np.isclose(ssr6, 0.0))\n\n    def test_diff_evo(self):\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        my_pwlf.fit(4, disp=False)\n        self.assertTrue(np.isclose(my_pwlf.ssr, 0.0))\n\n    def test_custom_bounds1(self):\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        n_segments = 3\n        bounds = np.zeros((n_segments-1, 2))\n        bounds[0, 0] = self.x_small[0]\n        bounds[0, 1] = self.x_small[2]\n        bounds[1, 0] = self.x_small[1]\n        bounds[1, 1] = self.x_small[-1]\n        my_pwlf.fit(n_segments, bounds=bounds)\n        self.assertTrue(np.isclose(my_pwlf.ssr, 0.0))\n\n    def test_custom_bounds2(self):\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        n_segments = 3\n        bounds = np.zeros((n_segments-1, 2))\n        bounds[0, 0] = self.x_small[0]\n        bounds[0, 1] = self.x_small[2]\n        bounds[1, 0] = self.x_small[1]\n        bounds[1, 1] = self.x_small[-1]\n        my_pwlf.fitfast(n_segments, pop=20, bounds=bounds)\n        self.assertTrue(np.isclose(my_pwlf.ssr, 0.0))\n\n    def test_predict(self):\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        xmax = np.max(self.x_small)\n        xmin = np.min(self.x_small)\n        my_pwlf.fit_with_breaks((xmin, xmax))\n        x = np.linspace(xmin, xmax, 10)\n        yHat = my_pwlf.predict(x)\n        self.assertTrue(np.isclose(np.sum(yHat), 8.085714285714287))\n\n    def test_custom_opt(self):\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        my_pwlf.use_custom_opt(3)\n        x_guess = np.array((0.9, 1.1))\n        from scipy.optimize import minimize\n        res = minimize(my_pwlf.fit_with_breaks_opt, x_guess)\n        self.assertTrue(np.isclose(res['fun'], 0.0))\n\n    def test_custom_opt_with_con(self):\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        my_pwlf.use_custom_opt(3, x_c=[0.], y_c=[0.])\n        x_guess = np.array((0.9, 1.1))\n        from scipy.optimize import minimize\n        _ = minimize(my_pwlf.fit_with_breaks_opt, x_guess)\n        self.assertTrue(True)\n\n    def test_single_force_break_point1(self):\n        my_fit = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x_c = [-0.5]\n        y_c = [-0.5]\n        my_fit.fit_with_breaks_force_points([0.2, 0.7], x_c, y_c)\n        yhat = my_fit.predict(x_c)\n        self.assertTrue(np.isclose(y_c, yhat))\n\n    def test_single_force_break_point2(self):\n        my_fit = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x_c = [2.0]\n        y_c = [1.5]\n        my_fit.fit_with_breaks_force_points([0.2, 0.7], x_c, y_c)\n        yhat = my_fit.predict(x_c)\n        self.assertTrue(np.isclose(y_c, yhat))\n\n    def test_single_force_break_point_degree(self):\n        my_fit = pwlf.PiecewiseLinFit(self.x_small, self.y_small, degree=2)\n        x_c = [2.0]\n        y_c = [1.5]\n        my_fit.fit_with_breaks_force_points([0.2, 0.7], x_c, y_c)\n        yhat = my_fit.predict(x_c)\n        self.assertTrue(np.isclose(y_c, yhat))\n\n    def test_single_force_break_point_degree_zero(self):\n        my_fit = pwlf.PiecewiseLinFit(self.x_small, self.y_small, degree=0)\n        x_c = [2.0]\n        y_c = [1.5]\n        my_fit.fit_with_breaks_force_points([0.2, 0.7], x_c, y_c)\n        yhat = my_fit.predict(x_c)\n        self.assertTrue(np.isclose(y_c, yhat))\n\n    def test_opt_fit_with_force_points(self):\n        # I need more data points to test this function because of\n        # ill conditioning in the least squares problem...\n        x = np.linspace(0.0, 1.0, num=100)\n        y = np.sin(6.0*x)\n        my_fit = pwlf.PiecewiseLinFit(x, y, disp_res=True)\n        x_c = [0.0]\n        y_c = [0.0]\n        my_fit.fit(3, x_c, y_c)\n        yhat = my_fit.predict(x_c)\n        self.assertTrue(np.isclose(y_c, yhat))\n\n    def test_opt_fit_single_segment(self):\n        # Test fit for a single segment without force points\n        x = np.linspace(0.0, 1.0, num=100)\n        y = x + 1\n        my_fit = pwlf.PiecewiseLinFit(x, y, disp_res=True)\n        my_fit.fit(1)\n        xhat = 0\n        yhat = my_fit.predict(xhat)\n        self.assertTrue(np.isclose(xhat + 1, yhat))\n\n    def test_opt_fit_with_force_points_single_segment(self):\n        # Test fit for a single segment (same as above)\n        # but with a force point\n        x = np.linspace(0.0, 1.0, num=100)\n        y = x + 1\n        my_fit = pwlf.PiecewiseLinFit(x, y, disp_res=True)\n        x_c = [0.0]\n        y_c = [0.0]\n        my_fit.fit(1, x_c, y_c)\n        yhat = my_fit.predict(x_c)\n        self.assertTrue(np.isclose(y_c, yhat))\n\n    def test_se(self):\n        # check to see if it will let me calculate standard errors\n        my_pwlf = pwlf.PiecewiseLinFit(np.random.random(20),\n                                       np.random.random(20))\n        my_pwlf.fitfast(2)\n        my_pwlf.standard_errors()\n\n    def test_p(self):\n        # check to see if it will let me calculate p-values\n        my_pwlf = pwlf.PiecewiseLinFit(np.random.random(20),\n                                       np.random.random(20))\n        my_pwlf.fitfast(2)\n        my_pwlf.p_values()\n\n    def test_nonlinear_p_and_se(self):\n        # generate a true piecewise linear data\n        np.random.seed(1)\n        n_data = 20\n        x = np.linspace(0, 1, num=n_data)\n        y = np.random.random(n_data)\n        my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        true_beta = np.array((1.0, 0.2, 0.2))\n        true_breaks = np.array((0.0, 0.5, 1.0))\n        y = my_pwlf.predict(x, beta=true_beta, breaks=true_breaks)\n        my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        my_pwlf.fitfast(2)\n        # calculate p-values\n        p = my_pwlf.p_values(method='non-linear', step_size=1e-4)\n        self.assertTrue(p.max() <= 0.05)\n\n    def test_pv(self):\n        # check to see if it will let me calculate prediction variance for\n        # random data\n        my_pwlf = pwlf.PiecewiseLinFit(np.random.random(20),\n                                       np.random.random(20))\n        my_pwlf.fitfast(2)\n        my_pwlf.prediction_variance(np.random.random(20))\n\n    def test_predict_with_custom_param(self):\n        # check to see if predict runs with custom parameters\n        x = np.random.random(20)\n        my_pwlf = pwlf.PiecewiseLinFit(x, np.random.random(20))\n        my_pwlf.predict(x, beta=np.array((1e-4, 1e-2, 1e-3)),\n                        breaks=np.array((0.0, 0.5, 1.0)))\n\n    def test_fit_guess(self):\n        x = np.array([4., 5., 6., 7., 8.])\n        y = np.array([11., 13., 16., 28.92, 42.81])\n        my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        breaks = my_pwlf.fit_guess([6.0])\n        self.assertTrue(np.isclose(breaks[1], 6.0705297))\n\n    def test_fit_guess_kwrds(self):\n        x = np.array([4., 5., 6., 7., 8.])\n        y = np.array([11., 13., 16., 28.92, 42.81])\n        my_pwlf = pwlf.PiecewiseLinFit(x, y)\n        breaks = my_pwlf.fit_guess([6.0], m=10,\n                                   factr=1e2, pgtol=1e-05,\n                                   epsilon=1e-6, iprint=-1,\n                                   maxfun=1500000, maxiter=150000,\n                                   disp=None)\n        self.assertTrue(np.isclose(breaks[1], 6.0705297))\n\n    def test_multi_start_fitfast(self):\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        my_pwlf.fitfast(4, 50)\n        self.assertTrue(np.isclose(my_pwlf.ssr, 0.0))\n\n    # =================================================\n    # Start of degree tests\n    def test_n_parameters_correct(self):\n        my_pwlf_0 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin, degree=0)\n        my_pwlf_1 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin, degree=1)\n        my_pwlf_2 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin, degree=2)\n        breaks = np.array([0.,  1.03913513,  3.04676334,  4.18647526, 10.])\n\n        A0 = my_pwlf_0.assemble_regression_matrix(breaks, self.x_sin)\n        A1 = my_pwlf_1.assemble_regression_matrix(breaks, self.x_sin)\n        A2 = my_pwlf_2.assemble_regression_matrix(breaks, self.x_sin)\n        self.assertTrue(A0.shape[1] == my_pwlf_0.n_parameters)\n        self.assertTrue(A1.shape[1] == my_pwlf_1.n_parameters)\n        self.assertTrue(A2.shape[1] == my_pwlf_2.n_parameters)\n        # Also check n_segments correct\n        self.assertTrue(4 == my_pwlf_0.n_segments)\n        self.assertTrue(4 == my_pwlf_1.n_segments)\n        self.assertTrue(4 == my_pwlf_2.n_segments)\n\n    def test_force_fits_through_points_other_degrees(self):\n        # generate sin wave data\n        x = np.linspace(0, 10, num=100)\n        y = np.sin(x * np.pi / 2)\n        # add noise to the data\n        y = np.random.normal(0, 0.15, 100) + y\n\n        # linear fit\n        my_pwlf_1 = pwlf.PiecewiseLinFit(x, y, degree=1)\n        my_pwlf_1.fit(n_segments=6, x_c=[0], y_c=[0])\n        y_predict_1 = my_pwlf_1.predict(x)\n\n        # quadratic fit\n        my_pwlf_2 = pwlf.PiecewiseLinFit(x, y, degree=2)\n        my_pwlf_2.fit(n_segments=5, x_c=[0], y_c=[0])\n        y_predict_2 = my_pwlf_2.predict(x)\n        self.assertTrue(np.isclose(0, y_predict_1[0]))\n        self.assertTrue(np.isclose(0, y_predict_2[0]))\n\n    def test_fitfast(self):\n        my_pwlf_0 = pwlf.PiecewiseLinFit(\n            self.x_sin, self.y_sin, degree=0, seed=123\n        )\n        my_pwlf_1 = pwlf.PiecewiseLinFit(\n            self.x_sin, self.y_sin, degree=1, seed=123,\n        )\n        my_pwlf_2 = pwlf.PiecewiseLinFit(\n            self.x_sin, self.y_sin, degree=2, seed=123,\n        )\n\n        # fit the data for four line segments\n        my_pwlf_0.fitfast(4, pop=10)\n        my_pwlf_1.fitfast(4, pop=10)\n        my_pwlf_2.fitfast(4, pop=10)\n\n        self.assertTrue(my_pwlf_0.ssr <= 35.)\n        self.assertTrue(my_pwlf_1.ssr <= 15.)\n        self.assertTrue(my_pwlf_2.ssr <= 2.0)\n\n    def test_fit(self):\n        my_pwlf_0 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin, degree=0)\n        my_pwlf_1 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin, degree=1)\n        my_pwlf_2 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin, degree=2)\n\n        # fit the data for four line segments\n        np.random.seed(123123)\n        my_pwlf_0.fit(5)\n        my_pwlf_1.fit(5)\n        my_pwlf_2.fit(5)\n\n        self.assertTrue(my_pwlf_0.ssr <= 10.)\n        self.assertTrue(my_pwlf_1.ssr <= 7.0)\n        self.assertTrue(my_pwlf_2.ssr <= 0.5)\n\n    def test_se_no_fit(self):\n        my_pwlf_0 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin)\n        try:\n            my_pwlf_0.standard_errors()\n            self.assertTrue(False)\n        except AttributeError:\n            self.assertTrue(True)\n\n    def test_se_no_method(self):\n        my_fit1 = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x0 = self.x_small.copy()\n        _ = my_fit1.fit_with_breaks(x0)\n        try:\n            my_fit1.standard_errors(method='blah')\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n\n    def test_pv_list(self):\n        my_fit1 = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x0 = self.x_small.copy()\n        _ = my_fit1.fit_with_breaks(x0)\n        my_fit1.prediction_variance(list(self.x_small))\n\n    def test_pv_no_fit(self):\n        my_pwlf_0 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin)\n        try:\n            my_pwlf_0.prediction_variance(self.x_sin)\n            self.assertTrue(False)\n        except AttributeError:\n            self.assertTrue(True)\n\n    def test_r2_no_fit(self):\n        my_pwlf_0 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin)\n        try:\n            my_pwlf_0.r_squared()\n            self.assertTrue(False)\n        except AttributeError:\n            self.assertTrue(True)\n\n    def test_pvalue_no_fit(self):\n        my_pwlf_0 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin)\n        try:\n            my_pwlf_0.p_values()\n            self.assertTrue(False)\n        except AttributeError:\n            self.assertTrue(True)\n\n    def test_pvalues_wrong_method(self):\n        my_fit1 = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x0 = self.x_small.copy()\n        _ = my_fit1.fit_with_breaks(x0)\n        try:\n            my_fit1.p_values(method='blah')\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n\n    def test_all_stats(self):\n        np.random.seed(121)\n        my_pwlf_0 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin, degree=0)\n        my_pwlf_0.fitfast(3)\n        my_pwlf_0.standard_errors()\n        my_pwlf_0.prediction_variance(np.random.random(20))\n        my_pwlf_0.p_values()\n        my_pwlf_0.r_squared()\n        my_pwlf_0.calc_slopes()\n\n        my_pwlf_2 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin, degree=2)\n        my_pwlf_2.fitfast(3)\n        my_pwlf_2.standard_errors()\n        my_pwlf_2.prediction_variance(np.random.random(20))\n        my_pwlf_2.p_values()\n        my_pwlf_2.r_squared()\n        my_pwlf_2.calc_slopes()\n\n        my_pwlf_3 = pwlf.PiecewiseLinFit(self.x_sin, self.y_sin, degree=3)\n        my_pwlf_3.fitfast(3)\n        my_pwlf_3.standard_errors()\n        my_pwlf_3.prediction_variance(np.random.random(20))\n        my_pwlf_3.p_values()\n        my_pwlf_3.r_squared()\n        my_pwlf_3.calc_slopes()\n    # End of degree tests\n    # =================================================\n\n    # =================================================\n    # Start weighted least squares tests\n    def test_weighted_same_as_ols(self):\n        # test that weighted least squares is same as OLS\n        # when the weight is equal to 1.0\n        n_segments = 2\n        my = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        x = np.random.random()\n        breaks = my.fit_guess([x])\n        my_w = pwlf.PiecewiseLinFit(self.x_small, self.y_small,\n                                    weights=np.ones_like(self.x_small))\n        breaks_w = my_w.fit_guess([x])\n\n        self.assertTrue(np.isclose(my.ssr, my_w.ssr))\n        for i in range(n_segments+1):\n            self.assertTrue(np.isclose(breaks[i], breaks_w[i]))\n\n    def test_heteroscedastic_data(self):\n        n_segments = 3\n        weights = self.y_small.copy()\n        weights[0] = 0.01\n        weights = 1.0 / weights\n        my_w = pwlf.PiecewiseLinFit(self.x_small, self.y_small,\n                                    weights=weights)\n        _ = my_w.fit(n_segments)\n        _ = my_w.standard_errors()\n\n    def test_not_supported_fit(self):\n        x = np.linspace(0.0, 1.0, num=100)\n        y = np.sin(6.0*x)\n        w = np.random.random(size=100)\n        my_fit = pwlf.PiecewiseLinFit(x, y, disp_res=True, weights=w)\n        x_c = [0.0]\n        y_c = [0.0]\n        try:\n            my_fit.fit(3, x_c, y_c)\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n\n    def test_not_supported_fit_with_breaks_force_points(self):\n        x = np.linspace(0.0, 1.0, num=100)\n        y = np.sin(6.0*x)\n        w = list(np.random.random(size=100))\n        my_fit = pwlf.PiecewiseLinFit(x, y, disp_res=True, weights=w)\n        x_c = [0.0]\n        y_c = [0.0]\n        try:\n            my_fit.fit_with_breaks_force_points([0.1, 0.2, 0.3], x_c, y_c)\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n\n    def test_custom_opt_not_supported(self):\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small,\n                                       weights=self.y_small)\n        try:\n            my_pwlf.use_custom_opt(3, x_c=[0], y_c=[0])\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n\n    def test_random_seed_fit(self):\n        np.random.seed(1)\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small,\n                                       seed=123)\n        fit1 = my_pwlf.fit(2)\n        np.random.seed(2)\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small,\n                                       seed=123)\n        fit2 = my_pwlf.fit(2)\n        same_breaks = np.isclose(fit1, fit2)\n        self.assertTrue(same_breaks.sum() == same_breaks.size)\n\n    def test_random_seed_fitfast(self):\n        # specifically test for seed = 0\n        np.random.seed(1)\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small,\n                                       seed=0)\n        fit1 = my_pwlf.fitfast(2)\n        np.random.seed(2)\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small,\n                                       seed=0)\n        fit2 = my_pwlf.fitfast(2)\n        same_breaks = np.isclose(fit1, fit2)\n        self.assertTrue(same_breaks.sum() == same_breaks.size)\n\n    def test_one_segment_fits(self):\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        fit1 = my_pwlf.fitfast(1)\n        my_pwlf = pwlf.PiecewiseLinFit(self.x_small, self.y_small)\n        fit2 = my_pwlf.fit(1)\n        same_breaks = np.isclose(fit1, fit2)\n        self.assertTrue(same_breaks[0])\n        self.assertTrue(same_breaks[1])\n\n    def test_float32(self):\n        my_pwlf = pwlf.PiecewiseLinFit(\n            np.linspace(0, 10, 3, dtype=np.float32),\n            np.random.random(3).astype(np.float32),\n        )\n        _ = my_pwlf.fitfast(2)\n        self.assertTrue(True)\n\n    def test_lfloat128(self):\n        try:\n            x = np.linspace(0, 10, 3, dtype=np.float128)\n            y = np.random.random(3).astype(np.float128)\n            my_pwlf = pwlf.PiecewiseLinFit(x, y)\n            _ = my_pwlf.fitfast(2)\n            self.assertTrue(True)\n        except AttributeError:\n            # this means that float128 is not supported\n            self.assertTrue(True)\n\n    def test_mixed_degree1(self):\n        x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n        y = [1, 2, 3, 4, 4.25, 3.75, 4, 5, 6, 7]\n\n        degree_list = [1, 0, 1]\n        my_pwlf = pwlf.PiecewiseLinFit(x, y, degree=degree_list)\n        _ = my_pwlf.fit(3)\n\n        # generate predictions\n        x_hat = np.linspace(min(x), max(x), 1000)\n        _ = my_pwlf.predict(x_hat)\n\n    def test_mixed_degree2(self):\n        x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n        y = [1, 2, 3, 4, 4.25, 3.75, 4, 5, 6, 7]\n\n        degree_list = [1, 1, 1]\n        my_pwlf = pwlf.PiecewiseLinFit(x, y, degree=degree_list)\n        _ = my_pwlf.fit(3)\n\n        # generate predictions\n        x_hat = np.linspace(min(x), max(x), 1000)\n        _ = my_pwlf.predict(x_hat)\n\n    def test_mixed_degree3(self):\n        x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n        y = [1, 2, 3, 4, 4.25, 3.75, 4, 5, 6, 7]\n\n        degree_list = [1, 3]\n        try:\n            my_pwlf = pwlf.PiecewiseLinFit(x, y, degree=degree_list)\n            _ = my_pwlf.fit(3)\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n\n    def test_mixed_degree_wrong_list(self):\n        x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n        y = [1, 2, 3, 4, 4.25, 3.75, 4, 5, 6, 7]\n        degree_list = [1, 1]\n        my_pwlf = pwlf.PiecewiseLinFit(x, y, degree=degree_list)\n        try:\n            _ = my_pwlf.fit(3)\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n        try:\n            _ = my_pwlf.fitfast(3)\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n        try:\n            _ = my_pwlf.fit_with_breaks([0, 3, 4, 5])\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n\n    def test_mixed_degree_force_point(self):\n        x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n        y = [1, 2, 3, 4, 4.25, 3.75, 4, 5, 6, 7]\n        degree_list = [1, 1]\n        my_pwlf = pwlf.PiecewiseLinFit(x, y, degree=degree_list)\n        try:\n            _ = my_pwlf.fit(2, x_c=[0,], y_c=[0,])\n            self.assertTrue(False)\n        except ValueError:\n            self.assertTrue(True)\n\n\nif __name__ == '__main__':\n    unittest.main()\n"
  }
]