├── test ├── __init__.py ├── test_aggregateevents.py ├── test_errorcheck.py ├── test_datacorrection.py └── test_datacheck.py ├── MANIFEST.in ├── data └── example.pkl ├── requirements.txt ├── .travis.yml ├── ctmc ├── __init__.py ├── generatormatrix.py ├── aggregateevents.py ├── errorcheck.py ├── datacorrection.py ├── simulate.py ├── datacheck.py ├── ctmc_class.py └── ctmc_func.py ├── CHANGES.md ├── setup.py ├── LICENSE ├── README.md ├── profile ├── speed (timeit).ipynb ├── funcalls (prun).ipynb ├── memory (mprun).ipynb └── linebyline (lprun).ipynb ├── .gitignore └── examples ├── demo datacorrection.ipynb ├── demo datacheck.ipynb ├── automatic data correction.ipynb ├── demo ctmc.ipynb ├── internal data format of ctmc_fit.ipynb └── demo Ctmc sklearn API.ipynb /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | recursive-include test *.py 3 | -------------------------------------------------------------------------------- /data/example.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kmedian/ctmc/HEAD/data/example.pkl -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | line_profiler>=2.1.2 2 | memory_profiler>=0.54.0 3 | matplotlib>=2.2.2 4 | nose>=1.3.7 5 | numpy>=1.14.5 6 | scipy>=1.1.0 7 | scikit-learn>=0.19.2 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: python 3 | python: 4 | - "3.6" 5 | install: 6 | - pip install flake8>=3.5.0 7 | - pip install -r requirements.txt 8 | script: 9 | - flake8 --ignore=F401 10 | - python -W ignore -m unittest discover 11 | cache: pip 12 | -------------------------------------------------------------------------------- /ctmc/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from .datacheck import datacheck 3 | from .errorcheck import errorcheck 4 | from .datacorrection import datacorrection 5 | from .ctmc_func import ctmc 6 | from .ctmc_class import Ctmc 7 | from .simulate import simulate 8 | 9 | # for profiling 10 | from .aggregateevents import aggregateevents 11 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # 0.1.3 / 2019-09-26 2 | 3 | * add type hints 4 | * add unit tests 5 | * automatic data correction in ctmc.ctmc and ctmc.Ctmc 6 | 7 | # 0.1.2 / 2018-10-04 8 | 9 | * Comply to sklearn's instantiation rule, http://scikit-learn.org/stable/developers/contributing.html#instantiation 10 | 11 | # 0.1.1 / 2018-09-25 12 | 13 | * missing dependency added 14 | 15 | # 0.1.0 / 2018-09-21 16 | 17 | * Initial Release 18 | -------------------------------------------------------------------------------- /ctmc/generatormatrix.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def generatormatrix(transcount: np.ndarray, 5 | statetime: np.ndarray) -> np.ndarray: 6 | 7 | tmp = transcount.copy() 8 | n = tmp.shape[0] 9 | 10 | rowsum = np.sum(tmp, axis=1) 11 | for i in range(n): 12 | tmp[i, i] = -rowsum[i] 13 | 14 | genmat = np.zeros(shape=(n, n), dtype=float) 15 | for i in range(n): 16 | genmat[i, :] = tmp[i, :] / statetime[i] 17 | 18 | return genmat 19 | -------------------------------------------------------------------------------- /ctmc/aggregateevents.py: -------------------------------------------------------------------------------- 1 | import scipy.sparse 2 | import numpy as np 3 | 4 | 5 | def aggregateevents(data: list, numstates: int) -> (np.ndarray, np.ndarray): 6 | 7 | transcount = scipy.sparse.lil_matrix((numstates, numstates), dtype=int) 8 | statetime = np.zeros(numstates, dtype=float) 9 | 10 | for _, example in enumerate(data): 11 | states = example[0] 12 | times = example[1] 13 | 14 | for i, s in enumerate(states): 15 | statetime[s] += times[i] 16 | if i: 17 | transcount[states[i - 1], s] += 1 18 | 19 | return transcount.toarray(), statetime 20 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | def read(fname): 5 | import os 6 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 7 | 8 | 9 | setup(name='ctmc', 10 | version='0.1.3', 11 | description='Continous Time Markov Chain', 12 | long_description=read('README.md'), 13 | long_description_content_type='text/markdown', 14 | url='http://github.com/kmedian/ctmc', 15 | author='Ulf Hamster', 16 | author_email='554c46@gmail.com', 17 | license='MIT', 18 | packages=['ctmc'], 19 | install_requires=[ 20 | 'setuptools>=40.0.0', 21 | 'nose>=1.3.7', 22 | 'numpy>=1.14.5', 23 | 'scipy>=1.1.0', 24 | 'scikit-learn>=0.19.2'], 25 | python_requires='>=3.6', 26 | zip_safe=False) 27 | -------------------------------------------------------------------------------- /ctmc/errorcheck.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def errorcheck(transcount: np.ndarray, statetime: np.ndarray, 5 | toltime: float) -> bool: 6 | # check transitions counting went wrong 7 | if np.any(np.diag(transcount) != 0): 8 | raise Exception( 9 | ("Transition Count Matrix have diagonal " 10 | "elements 'm[i,i] != 0'. There are no transition counts " 11 | "for the i-th state to itself by definition.")) 12 | 13 | # check if statetime[i] is big enough to work as divisor 14 | if np.any(statetime < toltime): 15 | ids = ",".join([str(i) for i in np.where(statetime < toltime)[0]]) 16 | raise Exception( 17 | ("The states i={:s} have each a cumulated time period" 18 | " that is smaller than toltime.").format(ids)) 19 | 20 | return False 21 | -------------------------------------------------------------------------------- /test/test_aggregateevents.py: -------------------------------------------------------------------------------- 1 | import ctmc 2 | import unittest 3 | import numpy as np 4 | import numpy.testing as npt 5 | 6 | 7 | def flatten(x): 8 | import itertools 9 | return list(itertools.chain.from_iterable( 10 | itertools.chain.from_iterable(x))) 11 | 12 | 13 | class Test_Aggregateevents(unittest.TestCase): 14 | 15 | def test1(self): 16 | # test case 17 | data = [ 18 | ([0, 1, 0], [0.5, 0.5, 0.5]) 19 | ] 20 | n_states = 2 21 | 22 | # solution 23 | sol_mat = [[0, 1], [1, 0]] 24 | sol_stm = [1, .5] 25 | 26 | # result 27 | res_mat, res_stm = ctmc.aggregateevents(data, n_states) 28 | 29 | # compare 30 | npt.assert_allclose(res_mat, sol_mat) 31 | npt.assert_allclose(res_stm, sol_stm) 32 | 33 | 34 | # run 35 | if __name__ == '__main__': 36 | unittest.main() 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Ulf Hamster 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/test_errorcheck.py: -------------------------------------------------------------------------------- 1 | import ctmc 2 | import unittest 3 | import numpy as np 4 | 5 | 6 | class Test_Errorcheck(unittest.TestCase): 7 | 8 | def test1(self): 9 | transcount = np.array([[0, 99], [99, 1]]) # error: diag <> 0 10 | statetime = np.array([12, 34]) 11 | toltime = 1e-8 12 | 13 | with self.assertRaises(Exception) as context: 14 | ctmc.errorcheck(transcount, statetime, toltime) 15 | 16 | # print("\ntest1: " + str(context.exception)) 17 | self.assertTrue( 18 | 'Transition Count Matrix have diagonal' 19 | in str(context.exception)) 20 | 21 | def test2(self): 22 | transcount = np.array([[0, 99], [99, 0]]) 23 | statetime = np.array([12, .0]) # error: statetime for id=1 too small 24 | toltime = 1e-8 25 | 26 | with self.assertRaises(Exception) as context: 27 | ctmc.errorcheck(transcount, statetime, toltime) 28 | 29 | # print("\ntest2: " + str(context.exception)) 30 | self.assertTrue( 31 | 'is smaller than toltime' 32 | in str(context.exception)) 33 | 34 | 35 | # run 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /ctmc/datacorrection.py: -------------------------------------------------------------------------------- 1 | 2 | def datacorrection(datalist: list, toltime: float = 1e-8) -> list: 3 | 4 | newlist = list() 5 | 6 | for example in datalist: 7 | states = example[0] 8 | times = example[1] 9 | 10 | # skip this example 11 | if len(states) < 2: 12 | continue 13 | 14 | # delete durations < toltime 15 | tmp = [row for row in zip(states, times) if row[1] >= toltime] 16 | 17 | # skip this example 18 | if len(tmp) < 2: 19 | continue 20 | 21 | # merge consecutive states that are the same 22 | tmp2 = list() 23 | s = tmp[0][0] 24 | t = tmp[0][1] 25 | for i in range(1, len(tmp)): 26 | if s is tmp[i][0]: 27 | t += tmp[i][1] 28 | else: 29 | tmp2.append([s, t]) 30 | s = tmp[i][0] 31 | t = tmp[i][1] 32 | 33 | # add the last 34 | tmp2.append([s, t]) 35 | 36 | # skip this example 37 | if len(tmp2) < 2: 38 | continue 39 | 40 | # add to new list 41 | newlist.append([l for l in zip(*tmp2)]) 42 | 43 | # done 44 | return newlist 45 | -------------------------------------------------------------------------------- /ctmc/simulate.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def simulate(s0: np.ndarray, transmat: np.ndarray, 5 | steps: int = 1) -> np.ndarray: 6 | """Simulate the next state 7 | 8 | Parameters 9 | ---------- 10 | s0 : ndarray 11 | Vector with state variables at t=0 12 | 13 | transmat : ndarray 14 | The estimated transition/stochastic matrix. 15 | 16 | steps : int 17 | (Default: 1) The number of steps to simulate model outputs ahead. 18 | If steps>1 the a Mult-Step Simulation is triggered. 19 | 20 | Returns 21 | ------- 22 | out : ndarray 23 | (steps=1) Vector with simulated state variables (). 24 | 25 | (steps>1) Matrix with out[:,step] columns (Fortran order) from a 26 | Multi-Step Simulation. The first column is the initial state 27 | vector out[:,0]=s0 for algorithmic reasons. 28 | """ 29 | # Single-Step simulation 30 | if steps == 1: 31 | return np.dot(s0, transmat) 32 | 33 | # Multi-Step simulation 34 | out = np.zeros(shape=(steps + 1, len(s0)), order='C') 35 | out[0, :] = s0 36 | 37 | for i in range(1, steps + 1): 38 | out[i, :] = np.dot(out[i - 1, :], transmat) 39 | 40 | return out 41 | -------------------------------------------------------------------------------- /ctmc/datacheck.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def datacheck(data: list, numstates: int, toltime: float) -> bool: 5 | 6 | eligiblestates = range(numstates) 7 | 8 | for exid, example in enumerate(data): 9 | states = example[0] 10 | times = example[1] 11 | 12 | if not np.all(np.isin(states, eligiblestates)): 13 | raise Exception( 14 | ("The example id={:d} has faulty state " 15 | "labels/encodings").format(exid)) 16 | 17 | if len(np.unique(states)) < 2: 18 | raise Exception( 19 | ("The example id={:d} has only 1 distinct " 20 | "state").format(exid)) 21 | 22 | for i in range(1, len(states)): 23 | if states[i - 1] == states[i]: 24 | raise Exception( 25 | ("The example id={:d} has two consequtive entries " 26 | "state[{:d}]==state[{:d}]").format(exid, i - 1, i)) 27 | 28 | for i, t in enumerate(times): 29 | if t < toltime: 30 | raise Exception( 31 | ("The example id={:d} has a state[{:d}] that have not " 32 | "been active for longer than toltime").format(exid, i)) 33 | 34 | return False 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/kmedian/ctmc.svg?branch=master)](https://travis-ci.org/kmedian/ctmc) 2 | [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/kmedian/ctmc/master?urlpath=lab) 3 | 4 | # ctmc 5 | 6 | 7 | ## Table of Contents 8 | * [Installation](#installation) 9 | * [Usage](#usage) 10 | * [Commands](#commands) 11 | * [Support](#support) 12 | * [Contributing](#contributing) 13 | 14 | 15 | ## Installation 16 | The `ctmc` [git repo](http://github.com/kmedian/ctmc) is available as [PyPi package](https://pypi.org/project/ctmc) 17 | 18 | ``` 19 | pip install ctmc 20 | ``` 21 | 22 | 23 | ## Usage 24 | Check the [examples](https://github.com/kmedian/ctmc/tree/master/examples) folder for notebooks. 25 | 26 | 27 | ## Commands 28 | * Check syntax: `flake8 --ignore=F401` 29 | * Run Unit Tests: `python -W ignore -m unittest discover` 30 | * Remove `.pyc` files: `find . -type f -name "*.pyc" | xargs rm` 31 | * Remove `__pycache__` folders: `find . -type d -name "__pycache__" | xargs rm -rf` 32 | * Upload to PyPi with twine: `python setup.py sdist && twine upload -r pypi dist/*` 33 | 34 | 35 | ## Debugging 36 | * Notebooks to profile python code are in the [profile](https://github.com/kmedian/ctmc/tree/master/profile) folder 37 | 38 | 39 | ## Support 40 | Please [open an issue](https://github.com/kmedian/ctmc/issues/new) for support. 41 | 42 | 43 | ## Contributing 44 | Please contribute using [Github Flow](https://guides.github.com/introduction/flow/). Create a branch, add commits, and [open a pull request](https://github.com/kmedian/ctmc/compare/). 45 | -------------------------------------------------------------------------------- /ctmc/ctmc_class.py: -------------------------------------------------------------------------------- 1 | from sklearn.base import BaseEstimator 2 | from .ctmc_func import ctmc 3 | from .simulate import simulate 4 | import numpy as np 5 | 6 | 7 | class Ctmc(BaseEstimator): 8 | """Continous Time Markov Chain, sklearn API class""" 9 | 10 | def __init__(self, numstates: int = None, transintv: float = 1.0, 11 | toltime: float = 1e-8, autocorrect: bool = False, 12 | debug: bool = False): 13 | self.numstates = numstates 14 | self.transintv = transintv 15 | self.toltime = toltime 16 | self.autocorrect = autocorrect 17 | self.debug = debug 18 | 19 | def fit(self, X: list, y=None): 20 | """Calls the ctmc.ctmc function 21 | 22 | Parameters 23 | ---------- 24 | X : list of lists 25 | (see ctmc function 'data') 26 | 27 | y 28 | not used, present for API consistence purpose. 29 | """ 30 | self.transmat, self.genmat, self.transcount, self.statetime = ctmc( 31 | X, numstates=self.numstates, 32 | transintv=self.transintv, 33 | toltime=self.toltime, 34 | autocorrect=self.autocorrect, 35 | debug=self.debug) 36 | return self 37 | 38 | def predict(self, X: np.ndarray, steps: int = 1) -> np.ndarray: 39 | """ 40 | Parameters 41 | ---------- 42 | X : ndarray 43 | vector with state variables at t 44 | 45 | Returns 46 | ------- 47 | C : ndarray 48 | vector with state variables at t+1 49 | """ 50 | return simulate(X, self.transmat, steps) 51 | -------------------------------------------------------------------------------- /profile/speed (timeit).ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Total execution time" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import pickle\n", 17 | "import sys\n", 18 | "sys.path.append('..')\n", 19 | "import ctmc" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 2, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "with open(\"../data/example.pkl\", \"rb\") as f:\n", 29 | " datalist = pickle.load(f)\n", 30 | "numstates = 9" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 3, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "name": "stdout", 40 | "output_type": "stream", 41 | "text": [ 42 | "3.19 ms ± 149 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n" 43 | ] 44 | } 45 | ], 46 | "source": [ 47 | "%timeit ctmc.ctmc(datalist, numstates, 1.0)" 48 | ] 49 | } 50 | ], 51 | "metadata": { 52 | "kernelspec": { 53 | "display_name": "Python 3", 54 | "language": "python", 55 | "name": "python3" 56 | }, 57 | "language_info": { 58 | "codemirror_mode": { 59 | "name": "ipython", 60 | "version": 3 61 | }, 62 | "file_extension": ".py", 63 | "mimetype": "text/x-python", 64 | "name": "python", 65 | "nbconvert_exporter": "python", 66 | "pygments_lexer": "ipython3", 67 | "version": "3.6.2" 68 | } 69 | }, 70 | "nbformat": 4, 71 | "nbformat_minor": 2 72 | } 73 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | 107 | # other 108 | .vscode 109 | profile/data* 110 | -------------------------------------------------------------------------------- /profile/funcalls (prun).ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Execution Time by Function Calls" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 4, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import pickle\n", 17 | "import sys\n", 18 | "sys.path.append('..')\n", 19 | "import ctmc" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 5, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "with open(\"../data/example.pkl\", \"rb\") as f:\n", 29 | " datalist = pickle.load(f)\n", 30 | "numstates = 9" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 10, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "name": "stdout", 40 | "output_type": "stream", 41 | "text": [ 42 | " " 43 | ] 44 | }, 45 | { 46 | "data": { 47 | "text/plain": [ 48 | " 3130 function calls in 0.008 seconds\n", 49 | "\n", 50 | " Ordered by: internal time\n", 51 | " List reduced from 105 to 1 due to restriction <'ctmc_func.py'>\n", 52 | "\n", 53 | " ncalls tottime percall cumtime percall filename:lineno(function)\n", 54 | " 1 0.000 0.000 0.008 0.008 ctmc_func.py:9(ctmc)" 55 | ] 56 | }, 57 | "metadata": {}, 58 | "output_type": "display_data" 59 | } 60 | ], 61 | "source": [ 62 | "%prun -l ctmc_func.py ctmc.ctmc(datalist, numstates, 1.0)" 63 | ] 64 | } 65 | ], 66 | "metadata": { 67 | "kernelspec": { 68 | "display_name": "Python 3", 69 | "language": "python", 70 | "name": "python3" 71 | }, 72 | "language_info": { 73 | "codemirror_mode": { 74 | "name": "ipython", 75 | "version": 3 76 | }, 77 | "file_extension": ".py", 78 | "mimetype": "text/x-python", 79 | "name": "python", 80 | "nbconvert_exporter": "python", 81 | "pygments_lexer": "ipython3", 82 | "version": "3.6.2" 83 | } 84 | }, 85 | "nbformat": 4, 86 | "nbformat_minor": 2 87 | } 88 | -------------------------------------------------------------------------------- /test/test_datacorrection.py: -------------------------------------------------------------------------------- 1 | 2 | # import sys 3 | # sys.path.append('..') 4 | import ctmc 5 | 6 | import unittest 7 | import numpy as np 8 | import numpy.testing as npt 9 | 10 | 11 | def flatten(x): 12 | import itertools 13 | return list(itertools.chain.from_iterable( 14 | itertools.chain.from_iterable(x))) 15 | 16 | 17 | class Test_Datacorrection(unittest.TestCase): 18 | 19 | def test1(self): 20 | sol = [[(2, 3), (1.6, 2.7)]] 21 | 22 | test = [([1], [0.5]), 23 | ([2, 3], [1.6, 2.7])] 24 | res = ctmc.datacorrection(test) 25 | 26 | # npt.assert_allclose(res, sol) 27 | npt.assert_allclose(flatten(res), flatten(sol)) 28 | 29 | def test2(self): 30 | sol = [[(2, 3), (1.6, 2.7)], [(4, 5, 6), (0.1, 0.2, 0.1)]] 31 | 32 | test = [([2, 3], [1.6, 2.7]), 33 | ([4, 5, 5, 6], [.1, .1, .1, .1])] 34 | res = ctmc.datacorrection(test) 35 | 36 | npt.assert_allclose(flatten(res), flatten(sol)) 37 | 38 | def test3(self): 39 | sol = [[(4, 5, 6), (0.1, 0.2, 0.1)]] 40 | 41 | test = [([4, 5, 5, 6], [.1, .1, .1, .1]), 42 | ([7, 7, 7, 7], [.1, .1, .1, .1])] 43 | res = ctmc.datacorrection(test) 44 | 45 | npt.assert_allclose(flatten(res), flatten(sol)) 46 | 47 | def test4(self): 48 | sol = [[(1, 2, 3), (0.1, 0.1, 0.1)], [(4, 6), (0.1, 0.1)]] 49 | 50 | test = [([1, 2, 3], [.1, .1, .1]), 51 | ([4, 5, 6], [.1, .0, .1])] 52 | res = ctmc.datacorrection(test) 53 | 54 | npt.assert_allclose(flatten(res), flatten(sol)) 55 | 56 | def test5(self): 57 | sol = [[(1, 2, 3), (0.1, 0.1, 0.1)], [(4, 6), (0.1, 0.1)]] 58 | 59 | test = [([1, 2, 3], [.1, .1, .1]), 60 | ([4, 5, 6], [.1, .0, .1])] 61 | res = ctmc.datacorrection(test) 62 | 63 | npt.assert_allclose(flatten(res), flatten(sol)) 64 | 65 | def test6(self): 66 | sol = [[(4, 6), (0.1, 0.1)]] 67 | 68 | test = [([4, 5, 6], [.1, .0, .1]), 69 | ([7, 8, 9], [.1, .0, .0])] 70 | res = ctmc.datacorrection(test) 71 | 72 | npt.assert_allclose(flatten(res), flatten(sol)) 73 | 74 | 75 | # run 76 | if __name__ == '__main__': 77 | unittest.main() 78 | -------------------------------------------------------------------------------- /test/test_datacheck.py: -------------------------------------------------------------------------------- 1 | import ctmc 2 | import unittest 3 | 4 | 5 | class Test_Datacheck(unittest.TestCase): 6 | 7 | def test1(self): 8 | data = [ 9 | ([0, 1], [.7, .7]), # ok 10 | ([0, 1, 2], [0.5, 0.5, 0.5]) # example id=1 doesn't work 11 | ] 12 | n_states = 2 # but there are 3 states 13 | toltime = 1e-8 14 | 15 | with self.assertRaises(Exception) as context: 16 | ctmc.datacheck(data, n_states, toltime) 17 | 18 | # print("\ntest1: " + str(context.exception)) 19 | self.assertTrue( 20 | 'has faulty state' 21 | in str(context.exception)) 22 | 23 | def test2(self): 24 | data = [ 25 | ([0, 1], [.7, .7]), # ok 26 | ([0], [.3]) # example id=1 doesn't work 27 | ] 28 | n_states = 2 29 | toltime = 1e-8 30 | 31 | with self.assertRaises(Exception) as context: 32 | ctmc.datacheck(data, n_states, toltime) 33 | 34 | # print("\ntest2: " + str(context.exception)) 35 | self.assertTrue( 36 | 'has only 1 distinct' 37 | in str(context.exception)) 38 | 39 | def test3(self): 40 | data = [ 41 | ([0, 1], [.7, .7]), # ok 42 | ([0, 1, 1], [.3, .3, .3]) # example id=1 doesn't work 43 | ] 44 | n_states = 2 45 | toltime = 1e-8 46 | 47 | with self.assertRaises(Exception) as context: 48 | ctmc.datacheck(data, n_states, toltime) 49 | 50 | # print("\ntest3: " + str(context.exception)) 51 | self.assertTrue( 52 | 'has two consequtive entries' 53 | in str(context.exception)) 54 | 55 | def test4(self): 56 | data = [ 57 | ([0, 1], [.7, .7]), # ok 58 | ([0, 1], [.3, .0]) # example id=1 doesn't work 59 | ] 60 | n_states = 2 61 | toltime = 1e-8 62 | 63 | with self.assertRaises(Exception) as context: 64 | ctmc.datacheck(data, n_states, toltime) 65 | 66 | # print("\ntest4: " + str(context.exception)) 67 | self.assertTrue( 68 | 'that have not been active for longer than toltime' 69 | in str(context.exception)) 70 | 71 | def test5(self): 72 | data = [ 73 | ([0, 1], [.7, .7]), # ok example 74 | ] 75 | n_states = 2 76 | toltime = 1e-8 77 | 78 | flag = ctmc.datacheck(data, n_states, toltime) 79 | self.assertFalse(flag) 80 | 81 | 82 | # run 83 | if __name__ == '__main__': 84 | unittest.main() 85 | -------------------------------------------------------------------------------- /ctmc/ctmc_func.py: -------------------------------------------------------------------------------- 1 | from .datacheck import datacheck 2 | from .aggregateevents import aggregateevents 3 | from .errorcheck import errorcheck 4 | from .generatormatrix import generatormatrix 5 | from .datacorrection import datacorrection 6 | import scipy.linalg 7 | import numpy as np 8 | 9 | 10 | def ctmc(data: list, numstates: int, transintv: float = 1.0, 11 | toltime: float = 1e-8, autocorrect: bool = False, debug: bool = False 12 | ) -> (np.ndarray, np.ndarray, np.ndarray, np.ndarray): 13 | """ Continous Time Markov Chain 14 | 15 | Parameters 16 | ---------- 17 | data : list of lists 18 | A python list of N examples (e.g. rating histories of N companies, 19 | the event data of N basketball games, etc.). The i-th example 20 | consist of one list with M_i encoded state labels and M_i the 21 | durations or time periods the state lasted since the recording 22 | started. 23 | 24 | numstates : int 25 | number of unique states 26 | 27 | transintv : float 28 | The time interval 29 | 30 | toltime : float 31 | (If debug=True) Will throw an exception if the aggregated state 32 | duration or aggregated time periods of any state is smaller 33 | than toltime. 34 | 35 | autocorrect : bool 36 | (Default: False) If True run ctmc.datacorretion function. 37 | 38 | debug : bool 39 | (Default: False) If True run the ctmc.datacheck function. 40 | Enable this flag if you to check if your 'data' variable 41 | has been processed correctly. 42 | 43 | Returns 44 | ------- 45 | transmat : ndarray 46 | The estimated transition/stochastic matrix. 47 | 48 | genmat : ndarray 49 | The estimated generator matrix 50 | 51 | transcount : ndarray 52 | 53 | statetime : ndarray 54 | 55 | 56 | Errors: 57 | ------- 58 | - ctmc assumes a clean data object and does not 59 | autocorrect any errors as result of it 60 | 61 | The main error sources are 62 | 63 | - transitions counting (e.g. two consequtive states 64 | has not been aggregated, only one distinct state 65 | reported) and 66 | - a state is modeled ore required that does not occur 67 | in the dataset (e.g. you a certain scale in mind 68 | and just assume it's in the data) or resp. involved 69 | in any transition (e.g. an example with just one 70 | state) 71 | 72 | You can enable error checking and exceptions by setting 73 | debug=True. You should do this for the first run on a 74 | smaller dataset. 75 | 76 | Example: 77 | -------- 78 | Use `datacheck` to check during preprocessing the 79 | dataset 80 | 81 | data = ... 82 | ctmc.datacheck(data, numstates, toltime) 83 | 84 | Disable checks in `ctmc` 85 | 86 | transmat, genmat, transcount, statetime = ctmc.ctmc( 87 | data, numstates, toltime, checks=False) 88 | 89 | Check aftwards if there has been an error 90 | 91 | ctmc.errorcheck(transcount, statetime, toltime) 92 | 93 | """ 94 | # auto-correct data list 95 | if autocorrect: 96 | data = datacorrection(data, toltime) 97 | 98 | # raise an exception if the data format is wrong 99 | if debug: 100 | datacheck(data, numstates, toltime) 101 | 102 | # aggregate event data 103 | transcount, statetime = aggregateevents(data, numstates) 104 | 105 | # raise an exception if the event data aggregation failed 106 | if debug: 107 | errorcheck(transcount, statetime, toltime) 108 | 109 | # create generator matrix 110 | genmat = generatormatrix(transcount, statetime) 111 | 112 | # compute matrix exponential of the generator matrix 113 | transmat = scipy.linalg.expm(genmat * transintv) 114 | 115 | # done 116 | return transmat, genmat, transcount, statetime 117 | -------------------------------------------------------------------------------- /examples/demo datacorrection.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import sys\n", 10 | "sys.path.append('..')\n", 11 | "import ctmc" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": {}, 17 | "source": [ 18 | "## What errors will cause exceptions?\n", 19 | "* Duration or time period in a certain state is smaller than `toltime` => Delete these observations\n", 20 | "* Two consecutive states refer to the same state, i.e. there is no transition => Merge these observations\n", 21 | "* An example has just one state as observation => Delete the example" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "## Examples how ctmc.datacorrection behaves" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 2, 34 | "metadata": {}, 35 | "outputs": [ 36 | { 37 | "data": { 38 | "text/plain": [ 39 | "[[(2, 3), (1.6, 2.7)]]" 40 | ] 41 | }, 42 | "execution_count": 2, 43 | "metadata": {}, 44 | "output_type": "execute_result" 45 | } 46 | ], 47 | "source": [ 48 | "test = [([1], [0.5]), \n", 49 | " ([2, 3], [1.6, 2.7])]\n", 50 | "res = ctmc.datacorrection(test)\n", 51 | "res" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": 3, 57 | "metadata": {}, 58 | "outputs": [ 59 | { 60 | "data": { 61 | "text/plain": [ 62 | "[[(2, 3), (1.6, 2.7)], [(4, 5, 6), (0.1, 0.2, 0.1)]]" 63 | ] 64 | }, 65 | "execution_count": 3, 66 | "metadata": {}, 67 | "output_type": "execute_result" 68 | } 69 | ], 70 | "source": [ 71 | "test = [([2, 3], [1.6, 2.7]),\n", 72 | " ([4, 5, 5, 6], [.1, .1, .1, .1])]\n", 73 | "res = ctmc.datacorrection(test)\n", 74 | "res" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 4, 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "data": { 84 | "text/plain": [ 85 | "[[(4, 5, 6), (0.1, 0.2, 0.1)]]" 86 | ] 87 | }, 88 | "execution_count": 4, 89 | "metadata": {}, 90 | "output_type": "execute_result" 91 | } 92 | ], 93 | "source": [ 94 | "test = [([4, 5, 5, 6], [.1, .1, .1, .1]),\n", 95 | " ([7, 7, 7, 7], [.1, .1, .1, .1])]\n", 96 | "res = ctmc.datacorrection(test)\n", 97 | "res" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 5, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/plain": [ 108 | "[[(1, 2, 3), (0.1, 0.1, 0.1)], [(4, 6), (0.1, 0.1)]]" 109 | ] 110 | }, 111 | "execution_count": 5, 112 | "metadata": {}, 113 | "output_type": "execute_result" 114 | } 115 | ], 116 | "source": [ 117 | "test = [([1, 2, 3], [.1, .1, .1]),\n", 118 | " ([4, 5, 6], [.1, .0, .1])]\n", 119 | "res = ctmc.datacorrection(test)\n", 120 | "res" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": 6, 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "data": { 130 | "text/plain": [ 131 | "[[(4, 6), (0.1, 0.1)]]" 132 | ] 133 | }, 134 | "execution_count": 6, 135 | "metadata": {}, 136 | "output_type": "execute_result" 137 | } 138 | ], 139 | "source": [ 140 | "test = [([4, 5, 6], [.1, .0, .1]),\n", 141 | " ([7, 8, 9], [.1, .0, .0])]\n", 142 | "res = ctmc.datacorrection(test)\n", 143 | "res" 144 | ] 145 | } 146 | ], 147 | "metadata": { 148 | "kernelspec": { 149 | "display_name": "Python 3", 150 | "language": "python", 151 | "name": "python3" 152 | }, 153 | "language_info": { 154 | "codemirror_mode": { 155 | "name": "ipython", 156 | "version": 3 157 | }, 158 | "file_extension": ".py", 159 | "mimetype": "text/x-python", 160 | "name": "python", 161 | "nbconvert_exporter": "python", 162 | "pygments_lexer": "ipython3", 163 | "version": "3.6.2" 164 | } 165 | }, 166 | "nbformat": 4, 167 | "nbformat_minor": 2 168 | } 169 | -------------------------------------------------------------------------------- /examples/demo datacheck.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import pickle\n", 10 | "\n", 11 | "import pprint\n", 12 | "pp = pprint.PrettyPrinter(indent=4)\n", 13 | "\n", 14 | "import sys\n", 15 | "sys.path.append('..')\n", 16 | "import ctmc" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "## Load Demo Dataset\n", 24 | "A preprocessed data list is used." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 2, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "with open(\"../data/example.pkl\", \"rb\") as f:\n", 34 | " datalist = pickle.load(f)\n", 35 | "numstates = 9" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "## ctmc.datacheck\n", 43 | "However the file can contain inconsistencies" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 3, 49 | "metadata": {}, 50 | "outputs": [ 51 | { 52 | "name": "stdout", 53 | "output_type": "stream", 54 | "text": [ 55 | "The example id=40 has a state[2] that have not been active for longer than toltime\n" 56 | ] 57 | } 58 | ], 59 | "source": [ 60 | "try:\n", 61 | " ctmc.datacheck(datalist, numstates, toltime=1e-8)\n", 62 | "except Exception as e:\n", 63 | " print(e)" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": {}, 69 | "source": [ 70 | "## Correct the error\n", 71 | "The 40-th example has a states $8$ with a duration of $0.0$." 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 4, 77 | "metadata": {}, 78 | "outputs": [ 79 | { 80 | "data": { 81 | "text/plain": [ 82 | "([3, 4, 8, 5],\n", 83 | " [1.8164383561643835, 0.1178082191780822, 0.0, 1.3415300546448088])" 84 | ] 85 | }, 86 | "execution_count": 4, 87 | "metadata": {}, 88 | "output_type": "execute_result" 89 | } 90 | ], 91 | "source": [ 92 | "datalist[40]" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": {}, 98 | "source": [ 99 | "The quick fix is to remove it" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 5, 105 | "metadata": {}, 106 | "outputs": [ 107 | { 108 | "data": { 109 | "text/plain": [ 110 | "([3, 4, 5], [1.8164383561643835, 0.1178082191780822, 1.3415300546448088])" 111 | ] 112 | }, 113 | "execution_count": 5, 114 | "metadata": {}, 115 | "output_type": "execute_result" 116 | } 117 | ], 118 | "source": [ 119 | "del datalist[40][0][2]\n", 120 | "del datalist[40][1][2]\n", 121 | "datalist[40]" 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": {}, 127 | "source": [ 128 | "## Try it again" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 6, 134 | "metadata": {}, 135 | "outputs": [], 136 | "source": [ 137 | "try:\n", 138 | " ctmc.datacheck(datalist, numstates, toltime=1e-8)\n", 139 | "except Exception as e:\n", 140 | " print(e)" 141 | ] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "metadata": {}, 146 | "source": [ 147 | "We were able to find the needle in the haystack.\n", 148 | "However, correcting each error manually is not really user-friendly.\n", 149 | "\n", 150 | "Better try \n", 151 | "\n", 152 | "```\n", 153 | "newlist = ctmc.datacorrection(oldlist)\n", 154 | "```" 155 | ] 156 | } 157 | ], 158 | "metadata": { 159 | "kernelspec": { 160 | "display_name": "Python 3", 161 | "language": "python", 162 | "name": "python3" 163 | }, 164 | "language_info": { 165 | "codemirror_mode": { 166 | "name": "ipython", 167 | "version": 3 168 | }, 169 | "file_extension": ".py", 170 | "mimetype": "text/x-python", 171 | "name": "python", 172 | "nbconvert_exporter": "python", 173 | "pygments_lexer": "ipython3", 174 | "version": "3.6.2" 175 | } 176 | }, 177 | "nbformat": 4, 178 | "nbformat_minor": 2 179 | } 180 | -------------------------------------------------------------------------------- /examples/automatic data correction.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import pickle\n", 10 | "import numpy as np\n", 11 | "\n", 12 | "import sys\n", 13 | "sys.path.append('..')\n", 14 | "import ctmc" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Load Demo Dataset\n", 22 | "A preprocessed data list is used." 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 2, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "with open(\"../data/example.pkl\", \"rb\") as f:\n", 32 | " datalist = pickle.load(f)\n", 33 | "numstates = 9" 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "metadata": {}, 39 | "source": [ 40 | "# Fit with uncorrected data" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": 3, 46 | "metadata": {}, 47 | "outputs": [ 48 | { 49 | "data": { 50 | "text/plain": [ 51 | "array([[0.96, 0.04, 0. , 0. , 0. , 0. , 0. , 0. , 0. ],\n", 52 | " [0.04, 0.9 , 0.06, 0. , 0. , 0. , 0. , 0. , 0. ],\n", 53 | " [0. , 0.03, 0.89, 0.08, 0. , 0. , 0. , 0. , 0. ],\n", 54 | " [0. , 0. , 0.06, 0.86, 0.06, 0.01, 0. , 0. , 0. ],\n", 55 | " [0. , 0. , 0. , 0.11, 0.8 , 0.08, 0. , 0. , 0.01],\n", 56 | " [0. , 0. , 0. , 0.01, 0.1 , 0.79, 0.05, 0.01, 0.04],\n", 57 | " [0. , 0. , 0. , 0. , 0.01, 0.21, 0.53, 0.17, 0.07],\n", 58 | " [0. , 0. , 0. , 0. , 0.03, 0.38, 0.06, 0.52, 0.01],\n", 59 | " [0. , 0. , 0. , 0. , 0. , 0.03, 0. , 0. , 0.97]])" 60 | ] 61 | }, 62 | "execution_count": 3, 63 | "metadata": {}, 64 | "output_type": "execute_result" 65 | } 66 | ], 67 | "source": [ 68 | "model1 = ctmc.Ctmc(numstates, transintv=1.0, toltime=1e-8, debug=False)\n", 69 | "model1 = model1.fit(datalist)\n", 70 | "mat1 = model1.transmat\n", 71 | "mat1.round(2)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "# Fit with auto-corrected data" 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": 4, 84 | "metadata": {}, 85 | "outputs": [ 86 | { 87 | "data": { 88 | "text/plain": [ 89 | "array([[0.96, 0.04, 0. , 0. , 0. , 0. , 0. , 0. , 0. ],\n", 90 | " [0.04, 0.9 , 0.06, 0. , 0. , 0. , 0. , 0. , 0. ],\n", 91 | " [0. , 0.03, 0.89, 0.08, 0. , 0. , 0. , 0. , 0. ],\n", 92 | " [0. , 0. , 0.06, 0.86, 0.06, 0.01, 0. , 0. , 0. ],\n", 93 | " [0. , 0. , 0. , 0.11, 0.8 , 0.08, 0. , 0. , 0. ],\n", 94 | " [0. , 0. , 0. , 0.01, 0.1 , 0.79, 0.05, 0.01, 0.04],\n", 95 | " [0. , 0. , 0. , 0. , 0.01, 0.21, 0.53, 0.17, 0.07],\n", 96 | " [0. , 0. , 0. , 0. , 0.03, 0.38, 0.06, 0.52, 0.01],\n", 97 | " [0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 1. ]])" 98 | ] 99 | }, 100 | "execution_count": 4, 101 | "metadata": {}, 102 | "output_type": "execute_result" 103 | } 104 | ], 105 | "source": [ 106 | "model2 = ctmc.Ctmc(numstates, transintv=1.0, toltime=1e-8, autocorrect=True, debug=False)\n", 107 | "model2 = model2.fit(datalist)\n", 108 | "mat2 = model2.transmat\n", 109 | "mat2.round(2)" 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [ 116 | "# Differences" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": 5, 122 | "metadata": {}, 123 | "outputs": [ 124 | { 125 | "data": { 126 | "text/plain": [ 127 | "array([[ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , -0. ],\n", 128 | " [ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , -0. ],\n", 129 | " [ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , -0. ],\n", 130 | " [ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , -0. ],\n", 131 | " [ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , -0. ],\n", 132 | " [-0. , -0. , -0. , -0. , -0. , -0. , -0. , -0. , 0. ],\n", 133 | " [-0. , -0. , -0. , -0. , -0. , -0. , -0. , -0. , 0. ],\n", 134 | " [-0. , -0. , -0. , -0. , -0. , -0. , -0. , -0. , 0. ],\n", 135 | " [-0. , -0. , -0. , -0. , -0. , -0.03, -0. , -0. , 0.03]])" 136 | ] 137 | }, 138 | "execution_count": 5, 139 | "metadata": {}, 140 | "output_type": "execute_result" 141 | } 142 | ], 143 | "source": [ 144 | "(mat2 - mat1).round(2)" 145 | ] 146 | } 147 | ], 148 | "metadata": { 149 | "kernelspec": { 150 | "display_name": "Python 3", 151 | "language": "python", 152 | "name": "python3" 153 | }, 154 | "language_info": { 155 | "codemirror_mode": { 156 | "name": "ipython", 157 | "version": 3 158 | }, 159 | "file_extension": ".py", 160 | "mimetype": "text/x-python", 161 | "name": "python", 162 | "nbconvert_exporter": "python", 163 | "pygments_lexer": "ipython3", 164 | "version": "3.7.1" 165 | } 166 | }, 167 | "nbformat": 4, 168 | "nbformat_minor": 2 169 | } 170 | -------------------------------------------------------------------------------- /examples/demo ctmc.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import pickle\n", 10 | "\n", 11 | "import pprint\n", 12 | "pp = pprint.PrettyPrinter(indent=4)\n", 13 | "\n", 14 | "import sys\n", 15 | "sys.path.append('..')\n", 16 | "import ctmc" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "## Load Demo Dataset\n", 24 | "A preprocessed data list is used." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": 2, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "with open(\"../data/example.pkl\", \"rb\") as f:\n", 34 | " datalist = pickle.load(f)" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "The number of states is 9." 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 3, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "numstates = 9" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "## Visual Inspection\n", 58 | "`datalist` is a list of examples.\n", 59 | "Each example consist of two lists.\n", 60 | "The first list contains encoded state labels.\n", 61 | "The second list contains the durations or time periods the corresponding states has been active." 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": 4, 67 | "metadata": {}, 68 | "outputs": [ 69 | { 70 | "name": "stdout", 71 | "output_type": "stream", 72 | "text": [ 73 | "[ ([4, 3], [8.467213114754099, 4.371584699453552]),\n", 74 | " ([4, 3, 2], [0.6147540983606558, 10.616438356164384, 5.576502732240437])]\n" 75 | ] 76 | } 77 | ], 78 | "source": [ 79 | "pp.pprint(datalist[49:51])" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": {}, 85 | "source": [ 86 | "## Estimate Markov Model\n", 87 | "`ctmc` with `debug=True` will throw an exception if something is wrong." 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": 5, 93 | "metadata": {}, 94 | "outputs": [ 95 | { 96 | "name": "stdout", 97 | "output_type": "stream", 98 | "text": [ 99 | "The example id=40 has a state[2] that have not been active for longer than toltime\n" 100 | ] 101 | } 102 | ], 103 | "source": [ 104 | "try:\n", 105 | " transmat, genmat, transcount, statetime = ctmc.ctmc(\n", 106 | " datalist, numstates, 1.0, toltime=1e-8, debug=True)\n", 107 | "except Exception as e:\n", 108 | " print(e)" 109 | ] 110 | }, 111 | { 112 | "cell_type": "markdown", 113 | "metadata": {}, 114 | "source": [ 115 | "With `debug=False` (Default) `ctmc` is very fast but might crash at a later or generate bogus results.\n", 116 | "Therefore, the faulty data should be corrected." 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "metadata": {}, 122 | "source": [ 123 | "## Repeat Estimation" 124 | ] 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": 6, 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "newlist = ctmc.datacorrection(datalist, toltime=1e-8)" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": 7, 138 | "metadata": {}, 139 | "outputs": [], 140 | "source": [ 141 | "try:\n", 142 | " transmat, genmat, transcount, statetime = ctmc.ctmc(\n", 143 | " newlist, numstates, 1.0, toltime=1e-8, debug=True)\n", 144 | "except Exception as e:\n", 145 | " print(e)" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": 8, 151 | "metadata": {}, 152 | "outputs": [ 153 | { 154 | "data": { 155 | "text/plain": [ 156 | "array([[0.96, 0.04, 0. , 0. , 0. , 0. , 0. , 0. , 0. ],\n", 157 | " [0.04, 0.9 , 0.06, 0. , 0. , 0. , 0. , 0. , 0. ],\n", 158 | " [0. , 0.03, 0.89, 0.08, 0. , 0. , 0. , 0. , 0. ],\n", 159 | " [0. , 0. , 0.06, 0.86, 0.06, 0.01, 0. , 0. , 0. ],\n", 160 | " [0. , 0. , 0. , 0.11, 0.8 , 0.08, 0. , 0. , 0. ],\n", 161 | " [0. , 0. , 0. , 0.01, 0.1 , 0.79, 0.05, 0.01, 0.04],\n", 162 | " [0. , 0. , 0. , 0. , 0.01, 0.21, 0.53, 0.17, 0.07],\n", 163 | " [0. , 0. , 0. , 0. , 0.03, 0.38, 0.06, 0.52, 0.01],\n", 164 | " [0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 1. ]])" 165 | ] 166 | }, 167 | "execution_count": 8, 168 | "metadata": {}, 169 | "output_type": "execute_result" 170 | } 171 | ], 172 | "source": [ 173 | "transmat.round(2)" 174 | ] 175 | } 176 | ], 177 | "metadata": { 178 | "kernelspec": { 179 | "display_name": "Python 3", 180 | "language": "python", 181 | "name": "python3" 182 | }, 183 | "language_info": { 184 | "codemirror_mode": { 185 | "name": "ipython", 186 | "version": 3 187 | }, 188 | "file_extension": ".py", 189 | "mimetype": "text/x-python", 190 | "name": "python", 191 | "nbconvert_exporter": "python", 192 | "pygments_lexer": "ipython3", 193 | "version": "3.6.2" 194 | } 195 | }, 196 | "nbformat": 4, 197 | "nbformat_minor": 2 198 | } 199 | -------------------------------------------------------------------------------- /examples/internal data format of ctmc_fit.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### The Internal Data Format for ctmc\n", 8 | "The function `ctmc` or `Ctmc` class expect the data to be structured as follows" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "metadata": { 15 | "ExecuteTime": { 16 | "end_time": "2018-09-01T20:16:48.521661Z", 17 | "start_time": "2018-09-01T20:16:48.511886Z" 18 | } 19 | }, 20 | "outputs": [], 21 | "source": [ 22 | "data = [([0, 1, 2, 1], [2.2, 3.35, 9.4, 1.3]), \n", 23 | " ([1, 0, 1], [4.0, 1.25, 1.7])]" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "Each example or event chain is one element in a array `data`.\n", 31 | "\n", 32 | "* The first entry of entry of an example row is a list of **states**, \n", 33 | "* the second entry a list **time periods** a state lasted.\n" 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "metadata": {}, 39 | "source": [ 40 | "### How does it work in ctmc?" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "Initialize variables" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 2, 53 | "metadata": { 54 | "ExecuteTime": { 55 | "end_time": "2018-09-01T20:17:32.967965Z", 56 | "start_time": "2018-09-01T20:17:32.961972Z" 57 | } 58 | }, 59 | "outputs": [], 60 | "source": [ 61 | "import numpy as np\n", 62 | "numstates = 3\n", 63 | "statetime = np.zeros(numstates, dtype=float)\n", 64 | "transcount = np.zeros(shape=(numstates, numstates), dtype=int)" 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "metadata": {}, 70 | "source": [ 71 | "Loop over all examples, \n", 72 | "and cumulate time periods and count transitions across all examples." 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 3, 78 | "metadata": { 79 | "ExecuteTime": { 80 | "end_time": "2018-09-01T20:20:46.174968Z", 81 | "start_time": "2018-09-01T20:20:46.169468Z" 82 | } 83 | }, 84 | "outputs": [], 85 | "source": [ 86 | "for _, example in enumerate(data):\n", 87 | " states = example[0]\n", 88 | " times = example[1]\n", 89 | " \n", 90 | " for i,s in enumerate(states):\n", 91 | " statetime[s] += times[i]\n", 92 | " if i: transcount[states[i-1], s] += 1" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": {}, 98 | "source": [ 99 | "The intermediate results are" 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 4, 105 | "metadata": { 106 | "ExecuteTime": { 107 | "end_time": "2018-09-01T20:21:29.070819Z", 108 | "start_time": "2018-09-01T20:21:29.059698Z" 109 | } 110 | }, 111 | "outputs": [ 112 | { 113 | "data": { 114 | "text/plain": [ 115 | "array([ 3.45, 10.35, 9.4 ])" 116 | ] 117 | }, 118 | "execution_count": 4, 119 | "metadata": {}, 120 | "output_type": "execute_result" 121 | } 122 | ], 123 | "source": [ 124 | "statetime" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 5, 130 | "metadata": { 131 | "ExecuteTime": { 132 | "end_time": "2018-09-01T20:21:29.759006Z", 133 | "start_time": "2018-09-01T20:21:29.750955Z" 134 | } 135 | }, 136 | "outputs": [ 137 | { 138 | "data": { 139 | "text/plain": [ 140 | "array([[0, 2, 0],\n", 141 | " [1, 0, 1],\n", 142 | " [0, 1, 0]])" 143 | ] 144 | }, 145 | "execution_count": 5, 146 | "metadata": {}, 147 | "output_type": "execute_result" 148 | } 149 | ], 150 | "source": [ 151 | "transcount" 152 | ] 153 | } 154 | ], 155 | "metadata": { 156 | "kernelspec": { 157 | "display_name": "Python 3", 158 | "language": "python", 159 | "name": "python3" 160 | }, 161 | "language_info": { 162 | "codemirror_mode": { 163 | "name": "ipython", 164 | "version": 3 165 | }, 166 | "file_extension": ".py", 167 | "mimetype": "text/x-python", 168 | "name": "python", 169 | "nbconvert_exporter": "python", 170 | "pygments_lexer": "ipython3", 171 | "version": "3.6.2" 172 | }, 173 | "toc": { 174 | "base_numbering": 1, 175 | "nav_menu": {}, 176 | "number_sections": true, 177 | "sideBar": true, 178 | "skip_h1_title": false, 179 | "title_cell": "Table of Contents", 180 | "title_sidebar": "Contents", 181 | "toc_cell": false, 182 | "toc_position": {}, 183 | "toc_section_display": true, 184 | "toc_window_display": false 185 | }, 186 | "varInspector": { 187 | "cols": { 188 | "lenName": 16, 189 | "lenType": 16, 190 | "lenVar": 40 191 | }, 192 | "kernels_config": { 193 | "python": { 194 | "delete_cmd_postfix": "", 195 | "delete_cmd_prefix": "del ", 196 | "library": "var_list.py", 197 | "varRefreshCmd": "print(var_dic_list())" 198 | }, 199 | "r": { 200 | "delete_cmd_postfix": ") ", 201 | "delete_cmd_prefix": "rm(", 202 | "library": "var_list.r", 203 | "varRefreshCmd": "cat(var_dic_list()) " 204 | } 205 | }, 206 | "types_to_exclude": [ 207 | "module", 208 | "function", 209 | "builtin_function_or_method", 210 | "instance", 211 | "_Feature" 212 | ], 213 | "window_display": false 214 | } 215 | }, 216 | "nbformat": 4, 217 | "nbformat_minor": 2 218 | } 219 | -------------------------------------------------------------------------------- /profile/memory (mprun).ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Memory Profile" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import pickle\n", 17 | "import sys\n", 18 | "sys.path.append('..')\n", 19 | "import ctmc" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 2, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "with open(\"../data/example.pkl\", \"rb\") as f:\n", 29 | " datalist = pickle.load(f)\n", 30 | "numstates = 9" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 3, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "%load_ext memory_profiler" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 4, 45 | "metadata": {}, 46 | "outputs": [ 47 | { 48 | "name": "stdout", 49 | "output_type": "stream", 50 | "text": [ 51 | "peak memory: 53.62 MiB, increment: 0.24 MiB\n" 52 | ] 53 | } 54 | ], 55 | "source": [ 56 | "%memit ctmc.ctmc(datalist, numstates, 1.0)" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "## ctmc.ctmc" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": 5, 69 | "metadata": {}, 70 | "outputs": [ 71 | { 72 | "name": "stdout", 73 | "output_type": "stream", 74 | "text": [ 75 | "\n" 76 | ] 77 | }, 78 | { 79 | "data": { 80 | "text/plain": [ 81 | "Filename: ../ctmc/ctmc_func.py\n", 82 | "\n", 83 | "Line # Mem usage Increment Line Contents\n", 84 | "================================================\n", 85 | " 9 53.9 MiB 53.9 MiB def ctmc(data, numstates, transintv=1.0, toltime=1e-8, debug=False):\n", 86 | " 10 \"\"\" Continous Time Markov Chain\n", 87 | " 11 \n", 88 | " 12 Parameters\n", 89 | " 13 ----------\n", 90 | " 14 data : list of lists\n", 91 | " 15 A python list of N examples (e.g. rating histories of N companies,\n", 92 | " 16 the event data of N basketball games, etc.). The i-th example\n", 93 | " 17 consist of one list with M_i encoded state labels and M_i the\n", 94 | " 18 durations or time periods the state lasted since the recording\n", 95 | " 19 started.\n", 96 | " 20 \n", 97 | " 21 numstates : int\n", 98 | " 22 number of unique states\n", 99 | " 23 \n", 100 | " 24 transintv : float\n", 101 | " 25 The time interval\n", 102 | " 26 \n", 103 | " 27 toltime : float\n", 104 | " 28 (If debug=True) Will throw an exception if the aggregated state\n", 105 | " 29 duration or aggregated time periods of any state is smaller\n", 106 | " 30 than toltime.\n", 107 | " 31 \n", 108 | " 32 debug : bool\n", 109 | " 33 (Default: False) If True run the ctmc.datacheck function.\n", 110 | " 34 Enable this flag if you to check if your 'data' variable\n", 111 | " 35 has been processed correctly.\n", 112 | " 36 \n", 113 | " 37 Returns\n", 114 | " 38 -------\n", 115 | " 39 transmat : ndarray\n", 116 | " 40 The estimated transition/stochastic matrix.\n", 117 | " 41 \n", 118 | " 42 genmat : ndarray\n", 119 | " 43 The estimated generator matrix\n", 120 | " 44 \n", 121 | " 45 transcount : ndarray\n", 122 | " 46 \n", 123 | " 47 statetime : ndarray\n", 124 | " 48 \n", 125 | " 49 \n", 126 | " 50 Errors:\n", 127 | " 51 -------\n", 128 | " 52 - ctmc assumes a clean data object and does not\n", 129 | " 53 autocorrect any errors as result of it\n", 130 | " 54 \n", 131 | " 55 The main error sources are\n", 132 | " 56 \n", 133 | " 57 - transitions counting (e.g. two consequtive states\n", 134 | " 58 has not been aggregated, only one distinct state\n", 135 | " 59 reported) and\n", 136 | " 60 - a state is modeled ore required that does not occur\n", 137 | " 61 in the dataset (e.g. you a certain scale in mind\n", 138 | " 62 and just assume it's in the data) or resp. involved\n", 139 | " 63 in any transition (e.g. an example with just one\n", 140 | " 64 state)\n", 141 | " 65 \n", 142 | " 66 You can enable error checking and exceptions by setting\n", 143 | " 67 debug=True. You should do this for the first run on a\n", 144 | " 68 smaller dataset.\n", 145 | " 69 \n", 146 | " 70 Example:\n", 147 | " 71 --------\n", 148 | " 72 Use `datacheck` to check during preprocessing the\n", 149 | " 73 dataset\n", 150 | " 74 \n", 151 | " 75 data = ...\n", 152 | " 76 ctmc.datacheck(data, numstates, toltime)\n", 153 | " 77 \n", 154 | " 78 Disable checks in `ctmc`\n", 155 | " 79 \n", 156 | " 80 transmat, genmat, transcount, statetime = ctmc.ctmc(\n", 157 | " 81 data, numstates, toltime, checks=False)\n", 158 | " 82 \n", 159 | " 83 Check aftwards if there has been an error\n", 160 | " 84 \n", 161 | " 85 ctmc.errorcheck(transcount, statetime, toltime)\n", 162 | " 86 \n", 163 | " 87 \"\"\"\n", 164 | " 88 # raise an exception if the data format is wrong\n", 165 | " 89 53.9 MiB 0.0 MiB if debug:\n", 166 | " 90 datacheck(data, numstates, toltime)\n", 167 | " 91 \n", 168 | " 92 # aggregate event data\n", 169 | " 93 53.9 MiB 0.0 MiB transcount, statetime = aggregateevents(data, numstates)\n", 170 | " 94 \n", 171 | " 95 # raise an exception if the event data aggregation failed\n", 172 | " 96 53.9 MiB 0.0 MiB if debug:\n", 173 | " 97 errorcheck(transcount, statetime, toltime)\n", 174 | " 98 \n", 175 | " 99 # create generator matrix\n", 176 | " 100 53.9 MiB 0.0 MiB genmat = generatormatrix(transcount, statetime)\n", 177 | " 101 \n", 178 | " 102 # compute matrix exponential of the generator matrix\n", 179 | " 103 53.9 MiB 0.0 MiB transmat = scipy.linalg.expm(genmat * transintv)\n", 180 | " 104 \n", 181 | " 105 # done\n", 182 | " 106 53.9 MiB 0.0 MiB return transmat, genmat, transcount, statetime" 183 | ] 184 | }, 185 | "metadata": {}, 186 | "output_type": "display_data" 187 | } 188 | ], 189 | "source": [ 190 | "%mprun -f ctmc.ctmc ctmc.ctmc(datalist, numstates, 1.0)" 191 | ] 192 | }, 193 | { 194 | "cell_type": "markdown", 195 | "metadata": {}, 196 | "source": [ 197 | "## ctmc.aggregateevents" 198 | ] 199 | }, 200 | { 201 | "cell_type": "code", 202 | "execution_count": 6, 203 | "metadata": {}, 204 | "outputs": [ 205 | { 206 | "name": "stdout", 207 | "output_type": "stream", 208 | "text": [ 209 | "\n" 210 | ] 211 | }, 212 | { 213 | "data": { 214 | "text/plain": [ 215 | "Filename: ../ctmc/aggregateevents.py\n", 216 | "\n", 217 | "Line # Mem usage Increment Line Contents\n", 218 | "================================================\n", 219 | " 6 53.9 MiB 53.9 MiB def aggregateevents(data, numstates):\n", 220 | " 7 \n", 221 | " 8 53.9 MiB 0.0 MiB transcount = scipy.sparse.lil_matrix((numstates, numstates), dtype=int)\n", 222 | " 9 53.9 MiB 0.0 MiB statetime = np.zeros(numstates, dtype=float)\n", 223 | " 10 \n", 224 | " 11 53.9 MiB 0.0 MiB for _, example in enumerate(data):\n", 225 | " 12 53.9 MiB 0.0 MiB states = example[0]\n", 226 | " 13 53.9 MiB 0.0 MiB times = example[1]\n", 227 | " 14 \n", 228 | " 15 53.9 MiB 0.0 MiB for i, s in enumerate(states):\n", 229 | " 16 53.9 MiB 0.0 MiB statetime[s] += times[i]\n", 230 | " 17 53.9 MiB 0.0 MiB if i:\n", 231 | " 18 53.9 MiB 0.0 MiB transcount[states[i - 1], s] += 1\n", 232 | " 19 \n", 233 | " 20 53.9 MiB 0.0 MiB return transcount.toarray(), statetime" 234 | ] 235 | }, 236 | "metadata": {}, 237 | "output_type": "display_data" 238 | } 239 | ], 240 | "source": [ 241 | "%mprun -f ctmc.aggregateevents ctmc.ctmc(datalist, numstates, 1.0)" 242 | ] 243 | } 244 | ], 245 | "metadata": { 246 | "kernelspec": { 247 | "display_name": "Python 3", 248 | "language": "python", 249 | "name": "python3" 250 | }, 251 | "language_info": { 252 | "codemirror_mode": { 253 | "name": "ipython", 254 | "version": 3 255 | }, 256 | "file_extension": ".py", 257 | "mimetype": "text/x-python", 258 | "name": "python", 259 | "nbconvert_exporter": "python", 260 | "pygments_lexer": "ipython3", 261 | "version": "3.6.2" 262 | } 263 | }, 264 | "nbformat": 4, 265 | "nbformat_minor": 2 266 | } 267 | -------------------------------------------------------------------------------- /profile/linebyline (lprun).ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Line by Line Execution Time" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": {}, 14 | "outputs": [], 15 | "source": [ 16 | "import pickle\n", 17 | "import sys\n", 18 | "sys.path.append('..')\n", 19 | "import ctmc" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 2, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "with open(\"../data/example.pkl\", \"rb\") as f:\n", 29 | " datalist = pickle.load(f)\n", 30 | "numstates = 9" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 3, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "%load_ext line_profiler" 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "metadata": {}, 45 | "source": [ 46 | "## ctmc.ctmc" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": 4, 52 | "metadata": {}, 53 | "outputs": [ 54 | { 55 | "data": { 56 | "text/plain": [ 57 | "Timer unit: 1e-06 s\n", 58 | "\n", 59 | "Total time: 0.01663 s\n", 60 | "File: ../ctmc/ctmc_func.py\n", 61 | "Function: ctmc at line 9\n", 62 | "\n", 63 | "Line # Hits Time Per Hit % Time Line Contents\n", 64 | "==============================================================\n", 65 | " 9 def ctmc(data, numstates, transintv=1.0, toltime=1e-8, debug=False):\n", 66 | " 10 \"\"\" Continous Time Markov Chain\n", 67 | " 11 \n", 68 | " 12 Parameters\n", 69 | " 13 ----------\n", 70 | " 14 data : list of lists\n", 71 | " 15 A python list of N examples (e.g. rating histories of N companies,\n", 72 | " 16 the event data of N basketball games, etc.). The i-th example\n", 73 | " 17 consist of one list with M_i encoded state labels and M_i the\n", 74 | " 18 durations or time periods the state lasted since the recording\n", 75 | " 19 started.\n", 76 | " 20 \n", 77 | " 21 numstates : int\n", 78 | " 22 number of unique states\n", 79 | " 23 \n", 80 | " 24 transintv : float\n", 81 | " 25 The time interval\n", 82 | " 26 \n", 83 | " 27 toltime : float\n", 84 | " 28 (If debug=True) Will throw an exception if the aggregated state\n", 85 | " 29 duration or aggregated time periods of any state is smaller\n", 86 | " 30 than toltime.\n", 87 | " 31 \n", 88 | " 32 debug : bool\n", 89 | " 33 (Default: False) If True run the ctmc.datacheck function.\n", 90 | " 34 Enable this flag if you to check if your 'data' variable\n", 91 | " 35 has been processed correctly.\n", 92 | " 36 \n", 93 | " 37 Returns\n", 94 | " 38 -------\n", 95 | " 39 transmat : ndarray\n", 96 | " 40 The estimated transition/stochastic matrix.\n", 97 | " 41 \n", 98 | " 42 genmat : ndarray\n", 99 | " 43 The estimated generator matrix\n", 100 | " 44 \n", 101 | " 45 transcount : ndarray\n", 102 | " 46 \n", 103 | " 47 statetime : ndarray\n", 104 | " 48 \n", 105 | " 49 \n", 106 | " 50 Errors:\n", 107 | " 51 -------\n", 108 | " 52 - ctmc assumes a clean data object and does not\n", 109 | " 53 autocorrect any errors as result of it\n", 110 | " 54 \n", 111 | " 55 The main error sources are\n", 112 | " 56 \n", 113 | " 57 - transitions counting (e.g. two consequtive states\n", 114 | " 58 has not been aggregated, only one distinct state\n", 115 | " 59 reported) and\n", 116 | " 60 - a state is modeled ore required that does not occur\n", 117 | " 61 in the dataset (e.g. you a certain scale in mind\n", 118 | " 62 and just assume it's in the data) or resp. involved\n", 119 | " 63 in any transition (e.g. an example with just one\n", 120 | " 64 state)\n", 121 | " 65 \n", 122 | " 66 You can enable error checking and exceptions by setting\n", 123 | " 67 debug=True. You should do this for the first run on a\n", 124 | " 68 smaller dataset.\n", 125 | " 69 \n", 126 | " 70 Example:\n", 127 | " 71 --------\n", 128 | " 72 Use `datacheck` to check during preprocessing the\n", 129 | " 73 dataset\n", 130 | " 74 \n", 131 | " 75 data = ...\n", 132 | " 76 ctmc.datacheck(data, numstates, toltime)\n", 133 | " 77 \n", 134 | " 78 Disable checks in `ctmc`\n", 135 | " 79 \n", 136 | " 80 transmat, genmat, transcount, statetime = ctmc.ctmc(\n", 137 | " 81 data, numstates, toltime, checks=False)\n", 138 | " 82 \n", 139 | " 83 Check aftwards if there has been an error\n", 140 | " 84 \n", 141 | " 85 ctmc.errorcheck(transcount, statetime, toltime)\n", 142 | " 86 \n", 143 | " 87 \"\"\"\n", 144 | " 88 # raise an exception if the data format is wrong\n", 145 | " 89 1 11.0 11.0 0.1 if debug:\n", 146 | " 90 datacheck(data, numstates, toltime)\n", 147 | " 91 \n", 148 | " 92 # aggregate event data\n", 149 | " 93 1 14128.0 14128.0 85.0 transcount, statetime = aggregateevents(data, numstates)\n", 150 | " 94 \n", 151 | " 95 # raise an exception if the event data aggregation failed\n", 152 | " 96 1 3.0 3.0 0.0 if debug:\n", 153 | " 97 errorcheck(transcount, statetime, toltime)\n", 154 | " 98 \n", 155 | " 99 # create generator matrix\n", 156 | " 100 1 264.0 264.0 1.6 genmat = generatormatrix(transcount, statetime)\n", 157 | " 101 \n", 158 | " 102 # compute matrix exponential of the generator matrix\n", 159 | " 103 1 2222.0 2222.0 13.4 transmat = scipy.linalg.expm(genmat * transintv)\n", 160 | " 104 \n", 161 | " 105 # done\n", 162 | " 106 1 2.0 2.0 0.0 return transmat, genmat, transcount, statetime" 163 | ] 164 | }, 165 | "metadata": {}, 166 | "output_type": "display_data" 167 | } 168 | ], 169 | "source": [ 170 | "%lprun -f ctmc.ctmc ctmc.ctmc(datalist, numstates, 1.0)" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "## ctmc.aggregateevents" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 5, 183 | "metadata": {}, 184 | "outputs": [ 185 | { 186 | "data": { 187 | "text/plain": [ 188 | "Timer unit: 1e-06 s\n", 189 | "\n", 190 | "Total time: 0.009175 s\n", 191 | "File: ../ctmc/aggregateevents.py\n", 192 | "Function: aggregateevents at line 6\n", 193 | "\n", 194 | "Line # Hits Time Per Hit % Time Line Contents\n", 195 | "==============================================================\n", 196 | " 6 def aggregateevents(data, numstates):\n", 197 | " 7 \n", 198 | " 8 1 151.0 151.0 1.6 transcount = scipy.sparse.lil_matrix((numstates, numstates), dtype=int)\n", 199 | " 9 1 6.0 6.0 0.1 statetime = np.zeros(numstates, dtype=float)\n", 200 | " 10 \n", 201 | " 11 72 88.0 1.2 1.0 for _, example in enumerate(data):\n", 202 | " 12 71 86.0 1.2 0.9 states = example[0]\n", 203 | " 13 71 75.0 1.1 0.8 times = example[1]\n", 204 | " 14 \n", 205 | " 15 316 506.0 1.6 5.5 for i, s in enumerate(states):\n", 206 | " 16 245 509.0 2.1 5.5 statetime[s] += times[i]\n", 207 | " 17 245 310.0 1.3 3.4 if i:\n", 208 | " 18 174 7388.0 42.5 80.5 transcount[states[i - 1], s] += 1\n", 209 | " 19 \n", 210 | " 20 1 56.0 56.0 0.6 return transcount.toarray(), statetime" 211 | ] 212 | }, 213 | "metadata": {}, 214 | "output_type": "display_data" 215 | } 216 | ], 217 | "source": [ 218 | "%lprun -f ctmc.aggregateevents ctmc.ctmc(datalist, numstates, 1.0)" 219 | ] 220 | } 221 | ], 222 | "metadata": { 223 | "kernelspec": { 224 | "display_name": "Python 3", 225 | "language": "python", 226 | "name": "python3" 227 | }, 228 | "language_info": { 229 | "codemirror_mode": { 230 | "name": "ipython", 231 | "version": 3 232 | }, 233 | "file_extension": ".py", 234 | "mimetype": "text/x-python", 235 | "name": "python", 236 | "nbconvert_exporter": "python", 237 | "pygments_lexer": "ipython3", 238 | "version": "3.6.2" 239 | } 240 | }, 241 | "nbformat": 4, 242 | "nbformat_minor": 2 243 | } 244 | -------------------------------------------------------------------------------- /examples/demo Ctmc sklearn API.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import pickle\n", 10 | "import numpy as np\n", 11 | "\n", 12 | "import sys\n", 13 | "sys.path.append('..')\n", 14 | "import ctmc\n", 15 | "\n", 16 | "import matplotlib.pyplot as plt\n", 17 | "%matplotlib inline" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "## Load Demo Dataset\n", 25 | "A preprocessed data list is used." 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 2, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "with open(\"../data/example.pkl\", \"rb\") as f:\n", 35 | " datalist = pickle.load(f)\n", 36 | "numstates = 9" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": {}, 42 | "source": [ 43 | "## Correct Data Errors" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 3, 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "newlist = ctmc.datacorrection(datalist, toltime=1e-8)" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": {}, 58 | "source": [ 59 | "## Fit" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 4, 65 | "metadata": {}, 66 | "outputs": [], 67 | "source": [ 68 | "model = ctmc.Ctmc(numstates, transintv=1.0, toltime=1e-8, debug=False)\n", 69 | "model = model.fit(newlist)" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 5, 75 | "metadata": {}, 76 | "outputs": [ 77 | { 78 | "data": { 79 | "text/plain": [ 80 | "array([[0.96, 0.04, 0. , 0. , 0. , 0. , 0. , 0. , 0. ],\n", 81 | " [0.04, 0.9 , 0.06, 0. , 0. , 0. , 0. , 0. , 0. ],\n", 82 | " [0. , 0.03, 0.89, 0.08, 0. , 0. , 0. , 0. , 0. ],\n", 83 | " [0. , 0. , 0.06, 0.86, 0.06, 0.01, 0. , 0. , 0. ],\n", 84 | " [0. , 0. , 0. , 0.11, 0.8 , 0.08, 0. , 0. , 0. ],\n", 85 | " [0. , 0. , 0. , 0.01, 0.1 , 0.79, 0.05, 0.01, 0.04],\n", 86 | " [0. , 0. , 0. , 0. , 0.01, 0.21, 0.53, 0.17, 0.07],\n", 87 | " [0. , 0. , 0. , 0. , 0.03, 0.38, 0.06, 0.52, 0.01],\n", 88 | " [0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 1. ]])" 89 | ] 90 | }, 91 | "execution_count": 5, 92 | "metadata": {}, 93 | "output_type": "execute_result" 94 | } 95 | ], 96 | "source": [ 97 | "model.transmat.round(2)" 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": {}, 103 | "source": [ 104 | "## Predict" 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": 6, 110 | "metadata": {}, 111 | "outputs": [], 112 | "source": [ 113 | "s0 = np.zeros(shape=(numstates,))\n", 114 | "s0[0] = 1" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": 7, 120 | "metadata": {}, 121 | "outputs": [ 122 | { 123 | "data": { 124 | "text/plain": [ 125 | "array([9.59042201e-01, 3.96720153e-02, 1.24751277e-03, 3.75024034e-05,\n", 126 | " 7.05714400e-07, 6.12327701e-08, 8.50006366e-10, 4.32672048e-11,\n", 127 | " 4.85809264e-10])" 128 | ] 129 | }, 130 | "execution_count": 7, 131 | "metadata": {}, 132 | "output_type": "execute_result" 133 | } 134 | ], 135 | "source": [ 136 | "out = model.predict(s0)\n", 137 | "out" 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": 8, 143 | "metadata": {}, 144 | "outputs": [], 145 | "source": [ 146 | "#sum(out)" 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "metadata": {}, 152 | "source": [ 153 | "## Multi-Step Simulation" 154 | ] 155 | }, 156 | { 157 | "cell_type": "code", 158 | "execution_count": 9, 159 | "metadata": {}, 160 | "outputs": [ 161 | { 162 | "data": { 163 | "text/plain": [ 164 | "array([[1. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ],\n", 165 | " [0.96, 0.04, 0. , 0. , 0. , 0. , 0. , 0. , 0. ],\n", 166 | " [0.92, 0.07, 0. , 0. , 0. , 0. , 0. , 0. , 0. ],\n", 167 | " [0.89, 0.1 , 0.01, 0. , 0. , 0. , 0. , 0. , 0. ],\n", 168 | " [0.86, 0.13, 0.02, 0. , 0. , 0. , 0. , 0. , 0. ],\n", 169 | " [0.83, 0.15, 0.02, 0. , 0. , 0. , 0. , 0. , 0. ],\n", 170 | " [0.8 , 0.17, 0.03, 0. , 0. , 0. , 0. , 0. , 0. ],\n", 171 | " [0.77, 0.18, 0.04, 0.01, 0. , 0. , 0. , 0. , 0. ],\n", 172 | " [0.75, 0.2 , 0.04, 0.01, 0. , 0. , 0. , 0. , 0. ],\n", 173 | " [0.73, 0.21, 0.05, 0.01, 0. , 0. , 0. , 0. , 0. ]])" 174 | ] 175 | }, 176 | "execution_count": 9, 177 | "metadata": {}, 178 | "output_type": "execute_result" 179 | } 180 | ], 181 | "source": [ 182 | "out = model.predict(s0, steps=500)\n", 183 | "out[:10].round(2)" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": 10, 189 | "metadata": {}, 190 | "outputs": [ 191 | { 192 | "data": { 193 | "image/png": "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5fDbcvitLF5yeKwsbpPDQxaXyeIsjQQrRyl7NFRlsBXT2AoZrEIa8uk5cZVKgUdEREREpMLkSxZ9WSd9WecZ/TlBR4FqZ4GQo0jIWRi5OuUoELDlCdrz+G15fLY8flsOL3k8Vm4kXJHDTQ6XORquTG7kalUpi72UxfgXAl1ntPapUuAREREREZmjji04cbptsoWBF0/7+54KW7kLEBEREREROVMUeEREREREZNZS4BERERERkVlLgWcK0uk0X/rSl1i1ahUej4f58+fzqU99is7OznKXJiIiIiIik1DgOYFMJsPll1/OnXfeSSKRYPv27SxatIif/exnnHPOObS2nomFCEVERERE5HRQ4DmBr33ta/zud7/jwgsv5MCBA/z85z/nhRde4K677qK/v59PfepT5S5RRERERESOQ4FnErlcjh/+8IcA/OhHPyIQCIzO3X777WzYsIGnnnqKnTt3lqtEERERERGZhALPJJ577jlisRjNzc2cc8454+Y/9KEPAfDQQw9Nd2kiIiIiIjIFCjyT2L17NwCbNm2acP7Y+J49e6atJhERERERmbrTv63qLNLW1gbAwoULJ5w/Nn7kyJEpvd+6desmHN+3bx8ly07X//8Xp1CliIiIiEhlGXLayEW6cTqd5S5FgWcyiUQCAJ/PN+G83+8HIB6Pv6OfUyqVsNlgZWPgxAfLnNbS0gJAc3NzmSuRSqdekalSr8jJUL/IVLW0tJDP5wmHw+UuRYFnOr366qsTjh+78nO8eZFj1CsyVeoVmSr1ipwM9YtMVSX1ip7hmcSxVdlSqdSE88lkEoBgMDhtNYmIiIiIyNQp8Exi8eLFAHR0dEw4f2x8yZIl01aTiIiIiIhMnQLPJM4++2wAdu3aNeH8sfENGzZMW00iIiIiIjJ1CjyT2Lp1K6FQiJaWFl5++eVx8w888AAA73//+6e7NBERERERmQIFnkm4XC5uueUWAG6++ebRZ3YAvvvd77Jnzx62bdvG5s2by1WiiIiIiIhMwjLGmHIXUckymQyXXnopL7zwAk1NTVx88cUcOXKEF154gfr6en73u9+xfPnycpcpIiIiIiITUOCZgnQ6zTe+8Q3+/d//nfb2dmpqarj66qu58847j7spqYiIiIiIlJ8Cj4iIiIiIzFp6hkdERERERGYtBR4REREREZm1FHhERERERGTWUuARERER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REREKpMWLRARERERkVlLgUdERERERGYtBR4REREREZm1FHhERERERGTWUuAREREREZFZS4FHRERERERmLQUeERERERGZtRR4RERERERk1lLgERERERGRWUuBR0REREREZi0FHhERERERmbUUeEREREREZNZS4BERkRnvySefxLIsbrrppnKXIiIiFUaBR0REREREZi0FHhERERERmbUUeEREpKK98sor3HjjjSxfvhyPx0N9fT0bN27ktttuo7u7m5tuuonLLrsMgHvuuQfLskZfX/nKV8a8V3t7O7fccgvNzc14PB5qamq49tpref7558f93LfeJnfs5zQ2NuL1etm0aRP33nvvdHx8ERF5hxzlLkBEROR4du7cyUUXXUQmk2HDhg1s376dVCpFa2sr3/ve9/jABz7ARRddRE9PD4888gjNzc1cdNFFo+dv3Lhx9D//7//+L9dccw2RSITVq1dzzTXX0N/fzyOPPMJvfvMb/u3f/o2PfvSj42oYGhriggsuIJvNcumllxKJRHjiiSfYsWMHra2t40KViIhUFssYY8pdhIiIyER27NjBvffey3e+8x0+97nPjZnbt28foVCIpqYmnnzySS677DJ27NjB3XffPe59hoeHWbNmDX19fdxzzz388R//8ejc73//e6688kry+Tytra3U19cDjL4nwBVXXMGDDz6I3+8H4KWXXuLyyy8nlUrx0ksvsWnTpjP0LyAiIu+UbmkTEZGK1d/fD8B73vOecXNr1qyhqalpSu/zL//yL3R3d3PbbbeNCTsA5557LnfccQeJRIJ//dd/HXeuzWbjBz/4wWjYATjvvPO4+eabKZVK/OM//uPJfCQREZlmCjwiIlKxNm/eDMDNN9/Mk08+SaFQOKX3+e1vfwvADTfcMOH8xRdfDMCLL744bm7jxo2sXr163PjHPvYxAJ555plTqklERKaHnuEREZGK9Vd/9Vc8++yzo7eXBQIBLrzwQq655hpuuukmQqHQlN7n8OHDAGzdunXS4wYGBsaNLVmyZMJjly5dCkBXV9eUahARkfJQ4BERkYpVVVXF448/znPPPcdDDz3Ek08+yeOPP86jjz7KN77xDZ555hlWrlx5wvcplUoAfOhDHxpza9rbrVmz5rTVLiIilUGBR0REKpplWVx00UWjq6/19fVx2223cf/99/OFL3yB//zP/zzheyxcuJD9+/fzN3/zN6O3yU3VkSNHJh2fP3/+Sb2fiIhMLz3DIyIiM0pDQ8PoUtCvvPIKAC6XC+C4z/hcccUVADz44IMn/fNefvllDh48OG78P/7jPwDGLIMtIiKVR4FHREQq1o9//GMOHTo0bvxXv/oVAIsWLQLevMqyf//+Cd/nz/7sz2hoaOBb3/oW//zP/zx6i9sxhUKBRx55ZDRAvVWpVOKzn/0sqVRqdGznzp388Ic/xLIsPvOZz5zahxMRkWmhfXhERKRibdy4kd27d3PWWWexdu1aHA4H+/btY/fu3Xg8Hh577LHRhQjOPvts9uzZw3nnnce6deuw2+1cd911XHfddQD87ne/4/3vfz8DAwMsWrSI9evXU11dTU9PD7t27SIajfLggw/ygQ98AHhzH55rr72W3bt3k8/nueSSS4jFYjz++OPk83m++MUvcuedd5bt30dERE7M/hVtES0iIhVqwYIFeL1eOjs72b17N6+//jo+n4/rr7+ee++9l3POOWf02CuuuIL29nZ2797NCy+8wK5du1i9ejWXXnopMPIczyc+8QnsdjttbW28/PLL7Nu3j2KxyJYtW/jbv/1brr322tHb4w4fPsw999zDhRdeyP33309rayuPPfYY+/fvZ+3atXzzm9/k9ttvL8c/i4iInARd4REREZnAsSs8O3bs4O677y53OSIicor0DI+IiIiIiMxaCjwiIiIiIjJrKfCIiIiIiMispWd4RERERERk1tIVHhERERERmbUUeEREREREZNZS4BERERERkVlLgUdERERERGYtBR4REREREZm1FHhERERERGTWUuAREREREZFZS4FHRERERERmLQUeERERERGZtRR4RERERERk1lLgERERERGRWUuBR0REREREZi0FHhERERERmbX+H7B7b7gvyEAuAAAAAElFTkSuQmCC\n", 194 | "text/plain": [ 195 | "
" 196 | ] 197 | }, 198 | "metadata": {}, 199 | "output_type": "display_data" 200 | } 201 | ], 202 | "source": [ 203 | "fig, ax = plt.subplots(dpi=150, facecolor='white')\n", 204 | "ax.stackplot(list(range(len(out))), out.T * 100, labels=list(range(numstates)));\n", 205 | "ax.legend(loc='upper right');\n", 206 | "ax.set_xlabel('step');\n", 207 | "ax.set_ylabel('percentage');\n", 208 | "ax.set_xlim(0, len(out));\n", 209 | "ax.set_ylim(0, 100);" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": null, 215 | "metadata": {}, 216 | "outputs": [], 217 | "source": [] 218 | } 219 | ], 220 | "metadata": { 221 | "kernelspec": { 222 | "display_name": "Python 3", 223 | "language": "python", 224 | "name": "python3" 225 | }, 226 | "language_info": { 227 | "codemirror_mode": { 228 | "name": "ipython", 229 | "version": 3 230 | }, 231 | "file_extension": ".py", 232 | "mimetype": "text/x-python", 233 | "name": "python", 234 | "nbconvert_exporter": "python", 235 | "pygments_lexer": "ipython3", 236 | "version": "3.6.2" 237 | } 238 | }, 239 | "nbformat": 4, 240 | "nbformat_minor": 2 241 | } 242 | --------------------------------------------------------------------------------