├── MANIFEST.in ├── requirements.txt ├── saxpy ├── __init__.py ├── strfunc.py ├── distance.py ├── util.py ├── visit_registry.py ├── paa.py ├── znorm.py ├── discord.py ├── saxvsm.py ├── hotsax.py ├── alphabet.py └── sax.py ├── setup.py ├── AUTHORS ├── tests ├── test_cuts.py ├── test_discord_bruteforce.py ├── test_str.py ├── test_discord_hotsax.py ├── test_registry.py ├── test_znorm.py ├── test_doctests.py ├── test_sax_chunking.py ├── test_distance.py ├── test_ts2string.py ├── test_paa.py ├── test_sax_window.py └── test_vsm.py ├── .gitignore ├── tox.ini ├── setup.cfg ├── site └── citation.bib ├── conda.recipe └── meta.yaml ├── .github └── workflows │ └── build.yml ├── .travis.yml ├── jupyter ├── visit_registry.ipynb ├── str_func.ipynb ├── distance.ipynb ├── znorm.ipynb ├── .ipynb_checkpoints │ ├── znorm-checkpoint.ipynb │ ├── insect-checkpoint.ipynb │ └── paa-checkpoint.ipynb ├── tinkah.ipynb ├── paa.ipynb └── sax.ipynb ├── README.rst ├── README.md ├── LICENSE └── data └── ecg0606_1.csv /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | pytest 3 | pytest-cov 4 | codecov 5 | scikit-learn 6 | scipy 7 | -------------------------------------------------------------------------------- /saxpy/__init__.py: -------------------------------------------------------------------------------- 1 | """SAX stack implementation.""" 2 | 3 | __version__ = '0.1.0' 4 | __author__ = 'Pavel Senin ' 5 | __all__ = [] 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """building saxpy.""" 3 | 4 | from setuptools import setup 5 | 6 | setup( 7 | setup_requires=['pbr>=5.8.0', 'setuptools>=60.5.0'], 8 | pbr=True, 9 | ) 10 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Ameya Daigavane 2 | Ameya Daigavane 3 | Pavel Senin 4 | Pavel Senin 5 | seninp 6 | -------------------------------------------------------------------------------- /tests/test_cuts.py: -------------------------------------------------------------------------------- 1 | """Testing PAA implementation.""" 2 | from saxpy import alphabet 3 | 4 | 5 | def test_sizing(): 6 | """Test alphabet sizes.""" 7 | for s in range(2, 20): 8 | assert len(alphabet.cuts_for_asize(s)) == s 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/workspace.xml 2 | build/ 3 | dist/ 4 | _build/ 5 | _generate/ 6 | .cache* 7 | .tox* 8 | .eggs* 9 | ChangeLog 10 | *.so 11 | *.py[cod] 12 | *.egg-info 13 | .coverage 14 | .pypirc 15 | jupyter/.ipynb* 16 | /.venv/ 17 | /.vscode/ 18 | .idea/ 19 | -------------------------------------------------------------------------------- /saxpy/strfunc.py: -------------------------------------------------------------------------------- 1 | """Convert a normlized timeseries to SAX symbols.""" 2 | 3 | 4 | def idx2letter(idx): 5 | """Convert a numerical index to a char.""" 6 | if 0 <= idx < 20: 7 | return chr(97 + idx) 8 | else: 9 | raise ValueError('A wrong idx value supplied.') 10 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py{310,311,312}-{linux,macos,windows} 3 | 4 | [gh-actions] 5 | python = 6 | 3.10: py310 7 | 3.11: py311, mypy 8 | 3.12: py312 9 | 10 | [gh-actions:env] 11 | PLATFORM = 12 | ubuntu-latest: linux 13 | macos-latest: macos 14 | windows-latest: windows 15 | 16 | [testenv] 17 | commands=py.test --cov saxpy tests 18 | deps = -rrequirements.txt 19 | setenv = 20 | PYTHONPATH = . 21 | -------------------------------------------------------------------------------- /tests/test_discord_bruteforce.py: -------------------------------------------------------------------------------- 1 | """Testing brute force discord search implementation.""" 2 | import numpy as np 3 | from saxpy.discord import find_discords_brute_force 4 | 5 | 6 | def test_brute_force(): 7 | """Test brute force discord discovery.""" 8 | dd = np.genfromtxt("data/ecg0606_1.csv", delimiter=',') 9 | discords = find_discords_brute_force(dd[0:400], 100, 4) 10 | assert 3 == len(discords) 11 | assert 173 == discords[0][0] 12 | -------------------------------------------------------------------------------- /tests/test_str.py: -------------------------------------------------------------------------------- 1 | """Testing STR functions.""" 2 | import pytest 3 | from saxpy.strfunc import idx2letter 4 | 5 | 6 | def test_sizing(): 7 | """Test idx to char.""" 8 | assert 'a' == idx2letter(0) 9 | assert 'h' == idx2letter(7) 10 | assert 't' == idx2letter(19) 11 | 12 | with pytest.raises(ValueError, match=r'.* idx'): 13 | idx2letter(-1) 14 | 15 | with pytest.raises(ValueError, match=r'.* idx .*'): 16 | idx2letter(20) 17 | -------------------------------------------------------------------------------- /tests/test_discord_hotsax.py: -------------------------------------------------------------------------------- 1 | """Testing HOTSAX discord search implementation.""" 2 | import numpy as np 3 | from saxpy.hotsax import find_discords_hotsax 4 | 5 | 6 | def test_brute_force(): 7 | """Test HOT-SAX discord discovery.""" 8 | dd = np.genfromtxt("data/ecg0606_1.csv", delimiter=',') 9 | 10 | discords = find_discords_hotsax(dd) 11 | assert 430 == discords[0][0] 12 | assert 318 == discords[1][0] 13 | 14 | discords = find_discords_hotsax(dd[0:400], 100, 4) 15 | assert 3 == len(discords) 16 | assert 173 == discords[0][0] 17 | -------------------------------------------------------------------------------- /saxpy/distance.py: -------------------------------------------------------------------------------- 1 | """Distance computation.""" 2 | import numpy as np 3 | 4 | 5 | def euclidean(a, b): 6 | """Compute a Euclidean distance value.""" 7 | return np.sqrt(np.sum((a-b)**2)) 8 | 9 | 10 | def early_abandoned_euclidean(a, b, upper_limit): 11 | """Compute a Euclidean distance value in early abandoning fashion.""" 12 | lim = upper_limit * upper_limit 13 | res = 0. 14 | for i in range(0, len(a)): 15 | res += np.dot((a[i]-b[i]), (a[i]-b[i])) 16 | if res > lim: 17 | return np.nan 18 | return np.sqrt(res) 19 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = saxpy 3 | version=1.0.1 4 | author = Pavel Senin 5 | author-email = seninp@gmail.org 6 | summary = SAX, HOTSAX, EMMA implementations for Python 7 | license = GPL2 8 | description-file = README.rst 9 | home-page = https://github.com/seninp/saxpy.git 10 | requires-python = >=3.7 11 | classifier = 12 | Development Status :: 4 - Beta 13 | Environment :: Console 14 | Intended Audience :: Developers 15 | Intended Audience :: Information Technology 16 | Operating System :: OS Independent 17 | Programming Language :: Python 18 | 19 | [files] 20 | packages = saxpy 21 | -------------------------------------------------------------------------------- /site/citation.bib: -------------------------------------------------------------------------------- 1 | @article{senin2018grammarviz, 2 | author = {Senin, Pavel and Lin, Jessica and Wang, Xing and Oates, Tim and Gandhi, Sunil and Boedihardjo, Arnold P. and Chen, Crystal and Frankenstein, Susan}, 3 | title = {GrammarViz 3.0: Interactive Discovery of Variable-Length Time Series Patterns}, 4 | journal = {ACM Trans. Knowl. Discov. Data}, 5 | issue_date = {February 2018}, 6 | volume = {12}, 7 | number = {1}, 8 | month = feb, 9 | year = {2018}, 10 | issn = {1556-4681}, 11 | pages = {10:1--10:28}, 12 | articleno = {10}, 13 | numpages = {28}, 14 | url = {http://doi.acm.org/10.1145/3051126}, 15 | doi = {10.1145/3051126}, 16 | acmid = {3051126}, 17 | publisher = {ACM}, 18 | address = {New York, NY, USA}, 19 | keywords = {Interactive data mining}, 20 | } 21 | -------------------------------------------------------------------------------- /conda.recipe/meta.yaml: -------------------------------------------------------------------------------- 1 | package: 2 | name: saxpy 3 | version: 0.1.0 4 | 5 | build: 6 | # If the installation is complex, or different between Unix and Windows, use 7 | # separate bld.bat and build.sh files instead of this key. Add the line 8 | # "skip: True # [py<35]" (for example) to limit to Python 3.5 and newer, or 9 | # "skip: True # [not win]" to limit to Windows. 10 | script: python setup.py install --single-version-externally-managed --record=record.txt 11 | 12 | source: 13 | path: .. 14 | 15 | requirements: 16 | build: 17 | - python 18 | - setuptools 19 | - numpy 20 | run: 21 | - python 22 | 23 | test: 24 | imports: 25 | - saxpy 26 | 27 | about: 28 | summary: SAX: time series symbolic discretization stack 29 | license_file: LICENSE 30 | -------------------------------------------------------------------------------- /tests/test_registry.py: -------------------------------------------------------------------------------- 1 | """Testing PAA implementation.""" 2 | import numpy as np 3 | from saxpy.visit_registry import VisitRegistry 4 | 5 | 6 | def test_sizing(): 7 | """Test the registry.""" 8 | reg = VisitRegistry(77) 9 | assert 77 == reg.get_unvisited_count() 10 | 11 | reg.mark_visited(0) 12 | assert 76 == reg.get_unvisited_count() 13 | 14 | reg.mark_visited_range(70, 77) 15 | assert 69 == reg.get_unvisited_count() 16 | 17 | reg.mark_visited(0) 18 | assert 69 == reg.get_unvisited_count() 19 | reg.mark_visited(1) 20 | assert 68 == reg.get_unvisited_count() 21 | 22 | reg.mark_visited(reg.get_next_unvisited()) 23 | assert 67 == reg.get_unvisited_count() 24 | 25 | reg.mark_visited_range(0, 77) 26 | assert np.isnan(reg.get_next_unvisited()) 27 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Python package 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | build: 9 | runs-on: ${{ matrix.platform }} 10 | strategy: 11 | matrix: 12 | platform: [ubuntu-latest, macOS-15, windows-latest] 13 | python-version: ['3.10', '3.11', '3.12'] 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Python ${{ matrix.python-version }} 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: ${{ matrix.python-version }} 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | python -m pip install tox tox-gh-actions 25 | - name: Test with tox 26 | run: tox 27 | env: 28 | PLATFORM: ${{ matrix.platform }} 29 | -------------------------------------------------------------------------------- /tests/test_znorm.py: -------------------------------------------------------------------------------- 1 | """Testing znorm implementation.""" 2 | import pytest 3 | from numpy import array, std, mean 4 | from saxpy import znorm 5 | 6 | 7 | def test_znorm(): 8 | """Test the znorm implementation.""" 9 | # test std is 1 and mean is 0 10 | ts = array([-1., -2., -1., 0., 2., 1., 1., 0.]) 11 | z_thrsh = 0.001 12 | x_scaled = [x / 100.0 for x in ts] 13 | assert pytest.approx(1.0, 0.000001) == std(znorm.znorm(x_scaled, z_thrsh)) 14 | assert pytest.approx(0.0, 0.000001) == mean(znorm.znorm(x_scaled, z_thrsh)) 15 | 16 | # test std and mean wouldnt change on hi threshold 17 | ts = array([-0.1, -0.2, 0.2, 0.1]) 18 | z_thrsh = 0.5 19 | ts_mean = mean(ts) 20 | ts_sd = std(ts) 21 | assert ts_mean == mean(znorm.znorm(ts, z_thrsh)) 22 | assert ts_sd == std(znorm.znorm(ts, z_thrsh)) 23 | -------------------------------------------------------------------------------- /saxpy/util.py: -------------------------------------------------------------------------------- 1 | """Some helpers.""" 2 | import re 3 | 4 | 5 | def read_ucr_data(fname): 6 | data = [] 7 | 8 | with open(fname, 'r') as fp: 9 | read_lines = fp.readlines() 10 | for line in read_lines: 11 | tokens = re.split("\\s+", line.strip()) 12 | 13 | t0 = tokens.pop(0) 14 | if re.match("^\d+?\.\d+?e[\+\-]?\d+?$", t0) is None: 15 | class_label = t0 16 | else: 17 | class_label = str(int(float(t0))) 18 | 19 | data_line = [] 20 | for token in tokens: 21 | data_line.append(float(token)) 22 | 23 | data.append((class_label, data_line)) 24 | 25 | res = {} 26 | for key, arr in data: 27 | if key in res.keys(): 28 | res[key].append(arr) 29 | else: 30 | dat = [arr] 31 | res[key] = dat 32 | 33 | return res -------------------------------------------------------------------------------- /tests/test_doctests.py: -------------------------------------------------------------------------------- 1 | import doctest 2 | import warnings 3 | from sklearn.exceptions import ConvergenceWarning 4 | from saxpy import paa, sax, znorm 5 | 6 | def run_doctests(module): 7 | """Helper to run doctests on a module and fail if any fail.""" 8 | with warnings.catch_warnings(): 9 | warnings.filterwarnings( 10 | "ignore", 11 | message=r"Number of distinct clusters", 12 | category=ConvergenceWarning, 13 | module=r"^sklearn(\.|$)", 14 | ) 15 | failures, _ = doctest.testmod( 16 | module, 17 | optionflags=doctest.NORMALIZE_WHITESPACE 18 | ) 19 | assert failures == 0, f"Doctests failed in {module.__name__}" 20 | 21 | def test_paa_doctests(): 22 | """Test PAA module doctests.""" 23 | run_doctests(paa) 24 | 25 | def test_sax_doctests(): 26 | """Test SAX module doctests.""" 27 | run_doctests(sax) 28 | 29 | def test_znorm_doctests(): 30 | """Test Z-norm module doctests.""" 31 | run_doctests(znorm) -------------------------------------------------------------------------------- /tests/test_sax_chunking.py: -------------------------------------------------------------------------------- 1 | """Testing SAX implementation.""" 2 | import numpy as np 3 | from saxpy.sax import sax_by_chunking 4 | 5 | 6 | def test_chunking(): 7 | """Test SAX by chunking.""" 8 | dat1 = np.array([2.02, 2.33, 2.99, 6.85, 9.2, 8.8, 7.5, 6, 5.85, 9 | 3.85, 4.85, 3.85, 2.22, 1.45, 1.34]) 10 | 11 | dats1_9_7 = "bcggfddba" 12 | dats1_10_11 = "bcjkjheebb" 13 | dats1_14_10 = "bbdijjigfeecbb" 14 | 15 | assert dats1_9_7 == sax_by_chunking(dat1, 9, 7) 16 | assert dats1_10_11 == sax_by_chunking(dat1, 10, 11) 17 | assert dats1_14_10 == sax_by_chunking(dat1, 14, 10) 18 | 19 | dat2 = np.array([0.5, 1.29, 2.58, 3.83, 3.25, 4.25, 3.83, 5.63, 6.44, 6.25, 20 | 8.75, 8.83, 3.25, 0.75, 0.72]) 21 | 22 | dats2_9_7 = "accdefgda" 23 | dats2_10_11 = "bcefgijkcb" 24 | dats2_14_10 = "abdeeffhijjfbb" 25 | 26 | assert dats2_9_7 == sax_by_chunking(dat2, 9, 7) 27 | assert dats2_10_11 == sax_by_chunking(dat2, 10, 11) 28 | assert dats2_14_10 == sax_by_chunking(dat2, 14, 10) 29 | -------------------------------------------------------------------------------- /tests/test_distance.py: -------------------------------------------------------------------------------- 1 | """Testing PAA implementation.""" 2 | import pytest 3 | import numpy as np 4 | from saxpy import distance 5 | 6 | 7 | def test_euclidean(): 8 | """Test euclidean distance.""" 9 | assert pytest.approx(np.sqrt(2), 0.0000001) == distance.euclidean( 10 | np.array([1., 1.]), np.array([2., 2.])) 11 | 12 | a = np.array([0.5, 0.8, 0.9]) 13 | b = np.array([-0.15, 0.38, 0.92]) 14 | assert pytest.approx(0.7741447, 0.0000001) == distance.euclidean(a, b) 15 | 16 | 17 | def test_early_abandoned(): 18 | """Test euclidean distance.""" 19 | assert pytest.approx(np.sqrt(2), 0.0000001) ==\ 20 | distance.early_abandoned_euclidean(np.array([1., 1.]), 21 | np.array([2., 2.]), np.inf) 22 | 23 | a = np.array([0.5, 0.8, 0.9]) 24 | b = np.array([-0.15, 0.38, 0.92]) 25 | assert pytest.approx(0.7741447, 0.0000001) ==\ 26 | distance.early_abandoned_euclidean(a, b, np.inf) 27 | 28 | assert 1 == np.isnan(distance.early_abandoned_euclidean(a, b, 0.1)) 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: python 3 | python: 4 | 5 | - "3.7" 6 | install: pip install tox-travis numpy pytest-cov codecov sklearn scipy 7 | 8 | script: 9 | tox 10 | 11 | after_success: 12 | - codecov 13 | 14 | #deploy: 15 | # provider: pypi 16 | # user: "seninp" 17 | # password: 18 | # secure: "ko6k7dTrXb6x53Eipa9nQ1HnewD3SM7jeWw7CYVYWL11xjc5C2+CAv6vNIlD+HfXJbcQtljNUm7SlBDN5GJdBXY5S13/R9gKlqN8N+HZ29d7cBwmYuKaQglKLxpSaAajDHsqc+h/QeDEuvJGRcmdnINxE4MkfJU981/0lbwEPSDtaQaMletQQaBol1BeJKmJDK/kxulPX+2AwCsKS/+o3FMnu+OhwgFjk589dTLmKpuPEpJBpG2ItHe/iWw9qydXE8wSm1wmrSx4A0QcNZOE19iaMxo3GuiQxqMFCtdQcoogxsX4CCxd6MxcjqPvTYHCIZCcRQFak3dLBRqF9wEIL/mz3nQ7ZTXPFNDEFSQD6om5ni9TnqEybMtNYR2QKu4fUhs5dG0y+5HxACyw7nWdLx0Wf6SfxjqpyDfd7rsSmPIUtKjzihgdWPSpESqP0TiYR7btZmue6ympQGcbeTSJ/cHOv+oL+mXhjdU/cRM625vN29ogXG8FwzDXICca4sKtEtXL/utAxF3fEUYkJecAP1p71+99Jhq2h/fbayAjViVe7m7H9fvahkgFT5MLQfiBIVWu6DD2+vnZJoYWbu6fG8HZTRTjfBGVXIiDVusxEKMc77bCJtHkM+McxCmG1gm+gYhiAp44BmidqfryKfaHQi2THfHRs1VpsbBb5FjKjw0=" 19 | 20 | notifications: 21 | email: 22 | on_success: never # default: change 23 | on_failure: always # default: always 24 | -------------------------------------------------------------------------------- /tests/test_ts2string.py: -------------------------------------------------------------------------------- 1 | """Testing PAA implementation.""" 2 | import numpy as np 3 | from saxpy import alphabet 4 | from saxpy import sax 5 | 6 | 7 | def test_stringing(): 8 | """Test string conversion.""" 9 | # 11: np.array([-np.inf, -1.33517773611894, -0.908457868537385, 10 | # -0.604585346583237, -0.348755695517045, 11 | # -0.114185294321428, 0.114185294321428, 0.348755695517045, 12 | # 0.604585346583237, 0.908457868537385, 1.33517773611894]), 13 | ab = sax.ts_to_string(np.array([-1.33517773611895, -1.33517773611894]), 14 | alphabet.cuts_for_asize(11)) 15 | assert 'ab' == ab 16 | 17 | kj = sax.ts_to_string(np.array([1.33517773611895, 1.33517773611894]), 18 | alphabet.cuts_for_asize(11)) 19 | assert 'kj' == kj 20 | 21 | 22 | def test_mindist(): 23 | """Test MINDIST.""" 24 | assert sax.is_mindist_zero('ab', 'ab') 25 | assert sax.is_mindist_zero('ab', 'bc') 26 | assert sax.is_mindist_zero('abcd', 'bccc') 27 | 28 | assert 0 == sax.is_mindist_zero('ab', 'bd') 29 | assert 0 == sax.is_mindist_zero('ab', 'abc') 30 | -------------------------------------------------------------------------------- /saxpy/visit_registry.py: -------------------------------------------------------------------------------- 1 | """Keeps visited indexes in check.""" 2 | import numpy as np 3 | import random 4 | 5 | 6 | class VisitRegistry: 7 | """A straightforward visit array implementation.""" 8 | 9 | def __init__(self, capacity=0): 10 | """Constructor.""" 11 | self.remaining = set() 12 | for num in range(capacity): 13 | self.remaining.add(num) 14 | 15 | def get_unvisited_count(self): 16 | """An unvisited count getter.""" 17 | return len(self.remaining) 18 | 19 | def mark_visited(self, index): 20 | """Set a single index as visited.""" 21 | self.remaining.discard(index) 22 | 23 | def mark_visited_range(self, start, stop): 24 | """Set a range as visited.""" 25 | for i in range(start, stop): 26 | self.mark_visited(i) 27 | 28 | def get_next_unvisited(self): 29 | """Next unvisited entry.""" 30 | if self.get_unvisited_count() == 0: 31 | return np.nan 32 | 33 | return random.choice(tuple(self.remaining)) 34 | 35 | def clone(self): 36 | """Make the array's copy.""" 37 | clone = VisitRegistry() 38 | clone.remaining = self.remaining.copy() 39 | return clone 40 | -------------------------------------------------------------------------------- /tests/test_paa.py: -------------------------------------------------------------------------------- 1 | """Testing PAA implementation.""" 2 | import numpy as np 3 | from saxpy import paa 4 | 5 | 6 | def test_paa1(): 7 | """Test points to points via PAA.""" 8 | y = np.array([-1, -2, -1, 0, 2, 1, 1, 0]) 9 | v = np.array([-1.375, 0.75, 0.625]) 10 | np.testing.assert_array_equal(paa.paa(y, 3), v) 11 | np.testing.assert_array_equal(paa.paa(y, 8), y) 12 | np.testing.assert_array_equal(paa.paa(y, 2), np.array([-1, 1])) 13 | 14 | 15 | def test_paa2(): 16 | """An irregular points to points via PAA (15 -> 10).""" 17 | dat = np.array([-0.9796808, -0.8622706, -0.6123005, 0.8496459, 1.739691, 18 | 1.588194, 1.095829, 0.5277147, 0.4709033, -0.2865819, 19 | 0.0921607, -0.2865819, -0.9039323, -1.195564, -1.237226]) 20 | dat_paa = np.array([-0.9405441, -0.6956239, 1.146328, 1.638693, 0.9064573, 21 | 0.4898404, -0.1603344, -0.1603344, -1.001143, 22 | -1.223339]) 23 | np.testing.assert_array_almost_equal(paa.paa(dat, 10), 24 | dat_paa, decimal=6) 25 | 26 | 27 | def test_paa3(): 28 | """An irregular points to points via PAA.""" 29 | dat = np.array([-1.289433, -0.9992189, -0.5253246, -0.06612478, -0.2791935, 30 | 0.08816637, -0.06612478, 0.595123, 0.8926845, 0.8228861, 31 | 1.741286, 1.770675, -0.2791935, -1.197593, -1.208614]) 32 | dat_paa = np.array([-1.192695, -0.6832894, -0.1371477, -0.03428692, 33 | 0.1542912, 0.7934974, 1.129019, 1.760878, -0.5853268, 34 | -1.20494]) 35 | np.testing.assert_array_almost_equal(paa.paa(dat, 10), 36 | dat_paa, decimal=6) 37 | -------------------------------------------------------------------------------- /saxpy/paa.py: -------------------------------------------------------------------------------- 1 | """Implements PAA.""" 2 | from __future__ import division 3 | import numpy as np 4 | 5 | 6 | def paa(series, paa_segment_size, sax_type='unidim'): 7 | """PAA implementation. 8 | 9 | >>> paa([1, 2, 3], 3, 'unidim') 10 | array([1., 2., 3.]) 11 | >>> paa([1, 2, 3], 1, 'unidim') 12 | array([2.]) 13 | >>> paa([4, 3, 8, 5], 1, 'unidim') 14 | array([5.]) 15 | >>> paa([[1, 2, 3], [6, 5, 4]], 1, 'repeat') 16 | array([[3.5, 3.5, 3.5]]) 17 | >>> paa([[1, 2, 3], [6, 5, 4]], 2, 'repeat') 18 | array([[1., 2., 3.], 19 | [6., 5., 4.]]) 20 | """ 21 | 22 | series = np.array(series) 23 | series_len = series.shape[0] 24 | 25 | if sax_type in ['repeat', 'energy']: 26 | num_dims = series.shape[1] 27 | else: 28 | num_dims = 1 29 | is_multidimensional = (len(series.shape) > 1) and (series.shape[1] > 1) 30 | if not is_multidimensional: 31 | series = series.reshape(series.shape[0], 1) 32 | 33 | res = np.zeros((num_dims, paa_segment_size)) 34 | 35 | for dim in range(num_dims): 36 | # Check if we can evenly divide the series. 37 | if series_len % paa_segment_size == 0: 38 | inc = series_len // paa_segment_size 39 | 40 | for i in range(0, series_len): 41 | idx = i // inc 42 | np.add.at(res[dim], idx, np.mean(series[i][dim])) 43 | res[dim] /= inc 44 | # Process otherwise. 45 | else: 46 | for i in range(0, paa_segment_size * series_len): 47 | idx = i // series_len 48 | pos = i // paa_segment_size 49 | np.add.at(res[dim], idx, np.mean(series[pos][dim])) 50 | res[dim] /= series_len 51 | 52 | if sax_type in ['repeat', 'energy']: 53 | return res.T 54 | else: 55 | return res.flatten() 56 | -------------------------------------------------------------------------------- /saxpy/znorm.py: -------------------------------------------------------------------------------- 1 | """Implements znorm.""" 2 | 3 | from __future__ import division 4 | import numpy as np 5 | from scipy.linalg import sqrtm 6 | from scipy.linalg import inv 7 | 8 | 9 | def l2norm(array): 10 | """ 11 | :param array: numpy array 12 | :return: non-negative real indicating the L2-norm of the array. 13 | 14 | >>> '%0.2f' % l2norm(np.array([1, 2, 3])) 15 | '3.74' 16 | >>> '%0.2f' % l2norm(np.array([1, 2, 3])[1]) 17 | '2.00' 18 | >>> '%0.2f' % l2norm(np.array([1, 2, 3])[1:]) 19 | '3.61' 20 | """ 21 | 22 | return np.sqrt(np.sum(np.square(array))) 23 | 24 | 25 | def znorm(series, znorm_threshold=0.01): 26 | """Znorm implementation. 27 | 28 | >>> print(['{:0.2f}'.format(x) for x in znorm([1, 2, 3])]) 29 | ['-1.22', '0.00', '1.22'] 30 | >>> print(['{:0.2f}'.format(x) for x in znorm([3, 2, 1])]) 31 | ['1.22', '0.00', '-1.22'] 32 | >>> print(['{:0.2f}'.format(x) for x in znorm([1, 2])]) 33 | ['-1.00', '1.00'] 34 | >>> print(['{:0.2f}'.format(x) for x in np.sum(znorm([[1, 2, 3], [6, 5, 4]]), axis=0)]) 35 | ['0.00', '0.00', '0.00'] 36 | >>> znorm([[1, 2, 3], [6, 5, 4]]) 37 | array([[-1., -1., -1.], 38 | [ 1., 1., 1.]]) 39 | """ 40 | 41 | series = np.array(series) 42 | original_series_shape = series.shape 43 | is_multidimensional = (len(series.shape) > 1) and (series.shape[1] > 1) 44 | mu = np.average(series, axis=0) 45 | C = np.cov(series, bias=True, rowvar=not is_multidimensional) 46 | 47 | # Only update those subsequences with variance over the threshold. 48 | if is_multidimensional: 49 | series = series - mu 50 | C = np.diagonal(C) 51 | indexes = (C >= np.square(znorm_threshold)) 52 | series[:, indexes] = (series[:, indexes] / np.sqrt(C[indexes])) 53 | else: 54 | series = series - mu 55 | if C >= np.square(znorm_threshold): 56 | series /= np.sqrt(C) 57 | 58 | # Check on shape returned. 59 | assert(series.shape == original_series_shape) 60 | 61 | return series 62 | -------------------------------------------------------------------------------- /tests/test_sax_window.py: -------------------------------------------------------------------------------- 1 | """Testing SAX implementation.""" 2 | import numpy as np 3 | from saxpy.sax import sax_via_window 4 | 5 | 6 | def test_via_window(): 7 | """Test SAX via window.""" 8 | dat = np.array([0., 0., 0., 0., 0., -0.270340178359072, -0.367828308500142, 9 | 0.666980581124872, 1.87088147328446, 2.14548907684624, 10 | -0.480859313143032, -0.72911654245842, -0.490308602315934, 11 | -0.66152028906509, -0.221049033806403, 0.367003418871239, 12 | 0.631073992586373, 0.0487728723414486, 0.762655178750436, 13 | 0.78574757843331, 0.338239686422963, 0.784206454089066, 14 | -2.14265084073625, 2.11325193044223, 0.186018356196443, 15 | 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.519132472499234, 16 | -2.604783141655, -0.244519550114012, -1.6570790528784, 17 | 3.34184602886343, 2.10361226260999, 1.9796808733979, 18 | -0.822247322003058, 1.06850578033292, -0.678811824405992, 19 | 0.804225748913681, 0.57363964388698, 0.437113583759113, 20 | 0.437208643628268, 0.989892093383503, 1.76545983424176, 21 | 0.119483882364649, -0.222311941138971, -0.74669456611669, 22 | -0.0663660879732063, 0., 0., 0., 0., 0.]) 23 | 24 | sax_none = sax_via_window(dat, win_size=6, paa_size=3, alphabet_size=3, nr_strategy=None, znorm_threshold=0.01) 25 | 26 | elements_num = 0 27 | for key in sax_none: 28 | elements_num += len(sax_none[key]) 29 | assert len(dat) - 6 + 1 == elements_num 30 | 31 | cca = sax_none['cca'] 32 | assert np.array_equal(np.array(cca), np.array([0, 1])) 33 | 34 | sax_exact = sax_via_window(dat, 6, 3, 3, "exact", 0.01) 35 | cca = sax_exact['cca'] 36 | assert np.array_equal(np.array(cca), np.array([0])) 37 | 38 | sax_mindist = sax_via_window(dat, 6, 3, 3, "mindist", 0.01) 39 | cca = sax_mindist['cca'] 40 | bbc = sax_mindist['bbc'] 41 | assert np.array_equal(np.array(cca), np.array([0])) 42 | assert np.array_equal(np.array(bbc), np.array([2])) 43 | -------------------------------------------------------------------------------- /tests/test_vsm.py: -------------------------------------------------------------------------------- 1 | """Testing SAX implementation.""" 2 | import numpy as np 3 | from saxpy.sax import sax_via_window 4 | from saxpy.saxvsm import series_to_wordbag 5 | from saxpy.saxvsm import manyseries_to_wordbag 6 | from saxpy.saxvsm import bags_to_tfidf 7 | 8 | 9 | def test_series_to_wordbag(): 10 | """Test TS to vector.""" 11 | dat = np.array([0., 0., 0., 0., 0., -0.270340178359072, -0.367828308500142, 12 | 0.666980581124872, 1.87088147328446, 2.14548907684624, 13 | -0.480859313143032, -0.72911654245842, -0.490308602315934, 14 | -0.66152028906509, -0.221049033806403, 0.367003418871239, 15 | 0.631073992586373, 0.0487728723414486, 0.762655178750436, 16 | 0.78574757843331, 0.338239686422963, 0.784206454089066, 17 | -2.14265084073625, 2.11325193044223, 0.186018356196443, 18 | 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.519132472499234, 19 | -2.604783141655, -0.244519550114012, -1.6570790528784, 20 | 3.34184602886343, 2.10361226260999, 1.9796808733979, 21 | -0.822247322003058, 1.06850578033292, -0.678811824405992, 22 | 0.804225748913681, 0.57363964388698, 0.437113583759113, 23 | 0.437208643628268, 0.989892093383503, 1.76545983424176, 24 | 0.119483882364649, -0.222311941138971, -0.74669456611669, 25 | -0.0663660879732063, 0., 0., 0., 0., 0.]) 26 | 27 | sax_none = sax_via_window(dat, 6, 3, 3, "none", 0.01) 28 | 29 | wordbag = series_to_wordbag(dat, 6, 3, 3, "none", 0.01) 30 | wordbag2 = manyseries_to_wordbag(np.array([dat, dat]), 31 | 6, 3, 3, "none", 0.01) 32 | 33 | frequencies = {} 34 | for k, v in sax_none.items(): 35 | frequencies[k] = len(v) 36 | 37 | for k, v in wordbag.items(): 38 | assert v == frequencies[k] 39 | 40 | for k, v in wordbag2.items(): 41 | assert v == frequencies[k] * 2 42 | 43 | 44 | def test_vsm(): 45 | """Test TF*IDF""" 46 | bag1 = {"this": 10, "is": 1, "a": 2, "sample": 1} 47 | bag2 = {"this": 10, "is": 1, "another": 2, "example": 3} 48 | bags = {"bag1": bag1, "bag2": bag2} 49 | 50 | res = bags_to_tfidf(bags) 51 | 52 | example = np.log(1. + 3.) * np.log(2. / 1.) 53 | bag2_idx = res["classes"].index("bag2") 54 | assert res["vectors"]["example"][bag2_idx] == example 55 | 56 | a = np.log(1. + 2.) * np.log(2. / 1.) 57 | bag1_idx = res["classes"].index("bag1") 58 | assert res["vectors"]["a"][bag1_idx] == a 59 | 60 | 61 | #def test_cosine(): -------------------------------------------------------------------------------- /saxpy/discord.py: -------------------------------------------------------------------------------- 1 | """Discord discovery routines.""" 2 | import numpy as np 3 | from saxpy.visit_registry import VisitRegistry 4 | from saxpy.distance import early_abandoned_euclidean 5 | from saxpy.znorm import znorm 6 | 7 | 8 | def find_discords_brute_force(series, win_size, num_discords=2, znorm_threshold=0.01): 9 | """Early-abandoned distance-based discord discovery.""" 10 | discords = list() 11 | 12 | globalRegistry = VisitRegistry(len(series) - win_size + 1) 13 | znorms = np.array([znorm(series[pos: pos + win_size], znorm_threshold) for pos in range(len(series) - win_size + 1)]) 14 | 15 | while len(discords) < num_discords: 16 | 17 | bestDiscord = find_best_discord_brute_force(series, win_size, 18 | globalRegistry, 19 | znorms) 20 | 21 | if -1 == bestDiscord[0]: 22 | break 23 | 24 | discords.append(bestDiscord) 25 | 26 | mark_start = max(0, bestDiscord[0] - win_size + 1) 27 | mark_end = bestDiscord[0] + win_size 28 | 29 | globalRegistry.mark_visited_range(mark_start, mark_end) 30 | 31 | return discords 32 | 33 | 34 | def find_best_discord_brute_force(series, win_size, global_registry, znorms): 35 | """Early-abandoned distance-based discord discovery.""" 36 | best_so_far_distance = -1.0 37 | best_so_far_index = -1 38 | 39 | outer_registry = global_registry.clone() 40 | 41 | outer_idx = outer_registry.get_next_unvisited() 42 | 43 | while ~np.isnan(outer_idx): 44 | 45 | outer_registry.mark_visited(outer_idx) 46 | 47 | candidate_seq = znorms[outer_idx] 48 | 49 | nn_distance = np.inf 50 | inner_registry = VisitRegistry(len(series) - win_size + 1) 51 | 52 | inner_idx = inner_registry.get_next_unvisited() 53 | 54 | while ~np.isnan(inner_idx): 55 | inner_registry.mark_visited(inner_idx) 56 | 57 | if abs(inner_idx - outer_idx) >= win_size: 58 | 59 | curr_seq = znorms[inner_idx] 60 | 61 | dist = early_abandoned_euclidean(candidate_seq, curr_seq, nn_distance) 62 | 63 | if (~np.isnan(dist)) and (dist < nn_distance): 64 | nn_distance = dist 65 | 66 | inner_idx = inner_registry.get_next_unvisited() 67 | 68 | if ~(np.inf == nn_distance) and (nn_distance > best_so_far_distance): 69 | best_so_far_distance = nn_distance 70 | best_so_far_index = outer_idx 71 | 72 | outer_idx = outer_registry.get_next_unvisited() 73 | 74 | return best_so_far_index, best_so_far_distance 75 | -------------------------------------------------------------------------------- /jupyter/visit_registry.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import os \n", 10 | "os.getcwd()" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": null, 16 | "metadata": { 17 | "collapsed": true 18 | }, 19 | "outputs": [], 20 | "source": [ 21 | "os.chdir(\"/home/psenin/git/saxpy\")\n", 22 | "import numpy as np\n", 23 | "from saxpy.strfunc import idx2letter \n", 24 | "from saxpy.znorm import znorm\n", 25 | "from saxpy.paa import paa\n", 26 | "from saxpy.alphabet import cuts_for_asize\n", 27 | "from saxpy.sax import sax_via_window\n", 28 | "from saxpy.visit_registry import VisitRegistry" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": null, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "%%timeit\n", 38 | "arr = VisitRegistry(10000)\n", 39 | "while 0 < arr.get_unvisited_count():\n", 40 | " num = arr.get_next_unvisited()\n", 41 | " arr.mark_visited(num)" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "%%timeit\n", 51 | "arr = VisitRegistry(10000)\n", 52 | "while 0 < arr.get_unvisited_count():\n", 53 | " num = arr.get_next_unvisited2()\n", 54 | " arr.mark_visited(num)" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": { 61 | "collapsed": true 62 | }, 63 | "outputs": [], 64 | "source": [] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": null, 69 | "metadata": { 70 | "collapsed": true 71 | }, 72 | "outputs": [], 73 | "source": [] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "metadata": { 79 | "collapsed": true 80 | }, 81 | "outputs": [], 82 | "source": [] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": null, 87 | "metadata": { 88 | "collapsed": true 89 | }, 90 | "outputs": [], 91 | "source": [] 92 | } 93 | ], 94 | "metadata": { 95 | "kernelspec": { 96 | "display_name": "Python 3", 97 | "language": "python", 98 | "name": "python3" 99 | }, 100 | "language_info": { 101 | "codemirror_mode": { 102 | "name": "ipython", 103 | "version": 3 104 | }, 105 | "file_extension": ".py", 106 | "mimetype": "text/x-python", 107 | "name": "python", 108 | "nbconvert_exporter": "python", 109 | "pygments_lexer": "ipython3", 110 | "version": "3.6.3" 111 | } 112 | }, 113 | "nbformat": 4, 114 | "nbformat_minor": 2 115 | } 116 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Time series symbolic discretization with SAX 2 | ============================================= 3 | 4 | .. image:: https://img.shields.io/pypi/v/saxpy.svg 5 | :target: https://pypi.python.org/pypi/saxpy 6 | :alt: Latest PyPI version 7 | 8 | .. image:: https://travis-ci.org/seninp/saxpy.png 9 | :target: https://travis-ci.org/seninp/saxpy 10 | :alt: Latest Travis CI build status 11 | 12 | .. image:: https://codecov.io/gh/seninp/saxpy/branch/master/graph/badge.svg 13 | :target: https://codecov.io/gh/seninp/saxpy 14 | 15 | .. image:: http://img.shields.io/:license-gpl2-green.svg 16 | :target: http://www.gnu.org/licenses/gpl-2.0.html 17 | 18 | 19 | This code is released under `GPL v.2.0 `_ and implements in Python: 20 | * Symbolic Aggregate approXimation (i.e., SAX) stack [LIN2002] 21 | * a simple function for time series motif discovery [PATEL2001] 22 | * HOT-SAX - a time series anomaly (discord) discovery algorithm [KEOGH2005] 23 | 24 | .. [LIN2002] Lin, J., Keogh, E., Patel, P., and Lonardi, S., `Finding Motifs in Time Series `_, The 2nd Workshop on Temporal Data Mining, the 8th ACM Int'l Conference on KDD (2002) 25 | .. [PATEL2001] Patel, P., Keogh, E., Lin, J., Lonardi, S., `Mining Motifs in Massive Time Series Databases `__, In Proc. ICDM (2002) 26 | .. [KEOGH2005] Keogh, E., Lin, J., Fu, A., `HOT SAX: Efficiently finding the most unusual time series subsequence `__, In Proc. ICDM (2005) 27 | 28 | Note that the most of the library's functionality is also available in `R `__ and `Java `__ 29 | 30 | 31 | Citing this work: 32 | ------------------ 33 | If you are using this implementation for you academic work, please cite our `Grammarviz 2.0 34 | paper `__: 35 | 36 | .. [SENIN2014] Senin, P., Lin, J., Wang, X., Oates, T., Gandhi, S., Boedihardjo, A.P., Chen, C., Frankenstein, S., Lerner, M., `GrammarViz 2.0: a tool for grammar-based pattern discovery in time series `__, ECML/PKDD, 2014. 37 | 38 | In a nutshell 39 | -------------- 40 | SAX is used to transform a sequence of rational numbers (i.e., a time series) into a sequence of letters (i.e., a string) which is (typically) much shorterthan the input time series. Thus, SAX transform addresses a chief problem in time-series analysis -- the dimensionality curse. 41 | 42 | This is an illustration of a time series of 128 points converted into the word of 8 letters: 43 | 44 | .. figure:: https://raw.githubusercontent.com/jMotif/SAX/master/src/resources/sax_transform.png 45 | :alt: SAX in a nutshell 46 | 47 | SAX in a nutshell 48 | 49 | As discretization is probably the most used transformation in data 50 | mining, SAX has been widely used throughout the field. Find more 51 | information about SAX at its authors pages: `SAX overview by Jessica 52 | Lin `__, `Eamonn Keogh's SAX 53 | page `__, or at `sax-vsm wiki 54 | page `__. 55 | 56 | Installation 57 | ------------- 58 | 59 | :: 60 | 61 | $ pip install saxpy 62 | 63 | Requirements 64 | ^^^^^^^^^^^^ 65 | 66 | Compatibility 67 | ------------- 68 | 69 | Licence 70 | ------- 71 | GNU General Public License v2.0 72 | 73 | Authors 74 | ------- 75 | 76 | `saxpy` was written by `Pavel Senin `_. 77 | -------------------------------------------------------------------------------- /jupyter/str_func.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "text/plain": [ 11 | "'/home/psenin/git/saxpy/jupyter'" 12 | ] 13 | }, 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "output_type": "execute_result" 17 | } 18 | ], 19 | "source": [ 20 | "import os \n", 21 | "os.getcwd()" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 2, 27 | "metadata": {}, 28 | "outputs": [], 29 | "source": [ 30 | "os.chdir(\"/home/psenin/git/saxpy\")\n", 31 | "import numpy as np\n", 32 | "from saxpy.strfunc import idx2letter \n", 33 | "from saxpy.znorm import znorm\n", 34 | "from saxpy.paa import paa\n", 35 | "from saxpy.alphabet import cuts_for_asize" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 3, 41 | "metadata": {}, 42 | "outputs": [], 43 | "source": [ 44 | "from saxpy.sax import sax_by_chunking\n", 45 | "dat1 = np.array([2.02, 2.33, 2.99, 6.85, 9.2, 8.8, 7.5, 6, 5.85,\n", 46 | " 3.85, 4.85, 3.85, 2.22, 1.45, 1.34])\n", 47 | "dats1_9_7 = \"bcggfddba\"\n", 48 | "dats1_10_11 = \"bcjkiheebb\"\n", 49 | "dats1_14_10 = \"bcdijjhgfeecbb\"" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 4, 55 | "metadata": {}, 56 | "outputs": [ 57 | { 58 | "data": { 59 | "text/plain": [ 60 | "'bcggfddba'" 61 | ] 62 | }, 63 | "execution_count": 4, 64 | "metadata": {}, 65 | "output_type": "execute_result" 66 | } 67 | ], 68 | "source": [ 69 | "sax_by_chunking(dat1, 9, 7)" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": { 76 | "collapsed": true 77 | }, 78 | "outputs": [], 79 | "source": [ 80 | "dats1_9_7 <- \"bcggfddba\"\n", 81 | "dats1_10_11 <- \"bcjkiheebb\"\n", 82 | "dats1_14_10 <- \"bcdijjhgfeecbb\"\n", 83 | "\n", 84 | "test_that(\"points to letters, i.e. SAX, CPP #2\", {\n", 85 | " str1_10_11 <- paste( matrix(unlist(sax_by_chunking(dat1, 10, 11, 0.01)),\n", 86 | " nrow = 10, byrow = T)[,1], collapse = \"\")\n", 87 | " str1_14_10 <- paste( matrix(unlist(sax_by_chunking(dat1, 14, 10, 0.01)),\n", 88 | " nrow = 14, byrow = T)[,1], collapse = \"\")\n", 89 | " str1_9_7 <- paste( matrix(unlist(sax_by_chunking(dat1, 9, 7, 0.01)),\n", 90 | " nrow = 9, byrow = T)[,1], collapse = \"\")\n", 91 | " expect_equal(str1_10_11, dats1_10_11)\n", 92 | " expect_equal(str1_14_10, dats1_14_10)\n", 93 | " expect_equal(str1_9_7, dats1_9_7)\n", 94 | "})" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": null, 100 | "metadata": { 101 | "collapsed": true 102 | }, 103 | "outputs": [], 104 | "source": [] 105 | } 106 | ], 107 | "metadata": { 108 | "kernelspec": { 109 | "display_name": "Python 3", 110 | "language": "python", 111 | "name": "python3" 112 | }, 113 | "language_info": { 114 | "codemirror_mode": { 115 | "name": "ipython", 116 | "version": 3 117 | }, 118 | "file_extension": ".py", 119 | "mimetype": "text/x-python", 120 | "name": "python", 121 | "nbconvert_exporter": "python", 122 | "pygments_lexer": "ipython3", 123 | "version": "3.6.3" 124 | } 125 | }, 126 | "nbformat": 4, 127 | "nbformat_minor": 2 128 | } 129 | -------------------------------------------------------------------------------- /jupyter/distance.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "text/plain": [ 11 | "'/home/psenin/git/saxpy/jupyter'" 12 | ] 13 | }, 14 | "execution_count": 2, 15 | "metadata": {}, 16 | "output_type": "execute_result" 17 | } 18 | ], 19 | "source": [ 20 | "import os \n", 21 | "os.getcwd()" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 3, 27 | "metadata": { 28 | "collapsed": true 29 | }, 30 | "outputs": [], 31 | "source": [ 32 | "os.chdir(\"/home/psenin/git/saxpy\")\n", 33 | "import numpy as np\n", 34 | "from saxpy.distance import euclidean\n", 35 | "from saxpy.distance import early_abandoned_dist " 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 10, 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "name": "stdout", 45 | "output_type": "stream", 46 | "text": [ 47 | "7.13 µs ± 21.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n" 48 | ] 49 | } 50 | ], 51 | "source": [ 52 | "%timeit euclidean(np.array([1., 1.]), np.array([2., 2.]))" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": 13, 58 | "metadata": {}, 59 | "outputs": [ 60 | { 61 | "data": { 62 | "text/plain": [ 63 | "nan" 64 | ] 65 | }, 66 | "execution_count": 13, 67 | "metadata": {}, 68 | "output_type": "execute_result" 69 | } 70 | ], 71 | "source": [ 72 | "early_abandoned_dist(np.array([1., 1.]), np.array([2., 2.]), 1)" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 15, 78 | "metadata": {}, 79 | "outputs": [ 80 | { 81 | "name": "stdout", 82 | "output_type": "stream", 83 | "text": [ 84 | "5.17 µs ± 242 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n" 85 | ] 86 | } 87 | ], 88 | "source": [ 89 | "a = np.array([0.5, 0.8, 0.9])\n", 90 | "b = np.array([-0.15, 0.38, 0.92])\n", 91 | "%timeit euclidean(a, b)" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 17, 97 | "metadata": {}, 98 | "outputs": [ 99 | { 100 | "name": "stdout", 101 | "output_type": "stream", 102 | "text": [ 103 | "3.77 µs ± 222 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n" 104 | ] 105 | } 106 | ], 107 | "source": [ 108 | "%timeit early_abandoned_dist(a, b, 1)" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 18, 114 | "metadata": {}, 115 | "outputs": [ 116 | { 117 | "name": "stdout", 118 | "output_type": "stream", 119 | "text": [ 120 | "3.39 µs ± 17.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n" 121 | ] 122 | } 123 | ], 124 | "source": [ 125 | "%timeit early_abandoned_dist(a, b, np.inf)" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": 21, 131 | "metadata": {}, 132 | "outputs": [ 133 | { 134 | "data": { 135 | "text/plain": [ 136 | "nan" 137 | ] 138 | }, 139 | "execution_count": 21, 140 | "metadata": {}, 141 | "output_type": "execute_result" 142 | } 143 | ], 144 | "source": [ 145 | "early_abandoned_dist(a, b, 0.1)" 146 | ] 147 | } 148 | ], 149 | "metadata": { 150 | "kernelspec": { 151 | "display_name": "Python 3", 152 | "language": "python", 153 | "name": "python3" 154 | }, 155 | "language_info": { 156 | "codemirror_mode": { 157 | "name": "ipython", 158 | "version": 3 159 | }, 160 | "file_extension": ".py", 161 | "mimetype": "text/x-python", 162 | "name": "python", 163 | "nbconvert_exporter": "python", 164 | "pygments_lexer": "ipython3", 165 | "version": "3.6.3" 166 | } 167 | }, 168 | "nbformat": 4, 169 | "nbformat_minor": 2 170 | } 171 | -------------------------------------------------------------------------------- /saxpy/saxvsm.py: -------------------------------------------------------------------------------- 1 | """Implements VSM.""" 2 | import math 3 | import numpy as np 4 | from saxpy.sax import sax_via_window 5 | 6 | 7 | def series_to_wordbag(series, win_size, paa_size, alphabet_size=3, 8 | nr_strategy='exact', z_threshold=0.01): 9 | """VSM implementation.""" 10 | sax = sax_via_window(series, win_size, paa_size, alphabet_size, 11 | nr_strategy, z_threshold) 12 | 13 | # convert the dict to a wordbag 14 | frequencies = {} 15 | for k, v in sax.items(): 16 | frequencies[k] = len(v) 17 | return frequencies 18 | 19 | 20 | def manyseries_to_wordbag(series_npmatrix, win_size, paa_size, alphabet_size=3, 21 | nr_strategy='exact', z_threshold=0.01): 22 | """VSM implementation.""" 23 | frequencies = {} 24 | 25 | for row in series_npmatrix: 26 | tmp_freq = series_to_wordbag(np.squeeze(np.asarray(row)), 27 | win_size, paa_size, alphabet_size, 28 | nr_strategy, z_threshold) 29 | for k, v in tmp_freq.items(): 30 | if k in frequencies: 31 | frequencies[k] += v 32 | else: 33 | frequencies[k] = v 34 | 35 | return frequencies 36 | 37 | 38 | def bags_to_tfidf(bags_dict): 39 | """VSM implementation.""" 40 | 41 | # classes 42 | count_size = len(bags_dict) 43 | classes = [*bags_dict.copy()] 44 | 45 | # word occurrence frequency counts 46 | counts = {} 47 | 48 | # compute frequencies 49 | idx = 0 50 | for name in classes: 51 | for word, count in bags_dict[name].items(): 52 | if word in counts: 53 | counts[word][idx] = count 54 | else: 55 | counts[word] = [0] * count_size 56 | counts[word][idx] = count 57 | idx = idx + 1 58 | 59 | # compute tf*idf 60 | tfidf = {} # the resulting vectors dictionary 61 | idx = 0 62 | for word, freqs in counts.items(): 63 | 64 | # document frequency 65 | df_counter = 0 66 | for i in freqs: 67 | if i > 0: 68 | df_counter = df_counter + 1 69 | 70 | # if the word is everywhere, dismiss it 71 | if df_counter == len(freqs): 72 | continue 73 | 74 | # tf*idf vector 75 | tf_idf = [0.0] * len(freqs) 76 | i_idx = 0 77 | for i in freqs: 78 | if i != 0: 79 | tf = np.log(1 + i) 80 | idf = np.log(len(freqs) / df_counter) 81 | tf_idf[i_idx] = tf * idf 82 | i_idx = i_idx + 1 83 | 84 | tfidf[word] = tf_idf 85 | 86 | idx = idx + 1 87 | 88 | return {"vectors": tfidf, "classes": classes} 89 | 90 | 91 | def tfidf_to_vector(tfidf, vector_label): 92 | """VSM implementation.""" 93 | if vector_label in tfidf['classes']: 94 | idx = tfidf['classes'].index(vector_label) 95 | weight_vec = {} 96 | for word, weights in tfidf['vectors'].items(): 97 | weight_vec[word] = weights[idx] 98 | return weight_vec 99 | else: 100 | return [] 101 | 102 | 103 | def cosine_measure(weight_vec, test_bag): 104 | """VSM implementation.""" 105 | sumxx, sumxy, sumyy = 0, 0, 0 106 | for word in set([*weight_vec.copy()]).union([*test_bag.copy()]): 107 | x, y = 0, 0 108 | if word in weight_vec.keys(): 109 | x = weight_vec[word] 110 | if word in test_bag.keys(): 111 | y = test_bag[word] 112 | sumxx += x * x 113 | sumyy += y * y 114 | sumxy += x * y 115 | return sumxy / math.sqrt(sumxx * sumyy) 116 | 117 | 118 | def cosine_similarity(tfidf, test_bag): 119 | """VSM implementation.""" 120 | res = {} 121 | for cls in tfidf['classes']: 122 | res[cls] = 1. - cosine_measure(tfidf_to_vector(tfidf, cls), test_bag) 123 | 124 | return res 125 | 126 | 127 | def class_for_bag(similarity_dict): 128 | # do i need to take care about equal values? 129 | return min(similarity_dict, key=lambda x: similarity_dict[x]) 130 | -------------------------------------------------------------------------------- /jupyter/znorm.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import os\n", 12 | "import sys\n", 13 | "sys.path.append(\"..\")" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 3, 19 | "metadata": {}, 20 | "outputs": [ 21 | { 22 | "data": { 23 | "text/plain": [ 24 | "array([-0.81649658, -1.63299316, -0.81649658, 0. , 1.63299316,\n", 25 | " 0.81649658, 0.81649658, 0. ])" 26 | ] 27 | }, 28 | "execution_count": 3, 29 | "metadata": {}, 30 | "output_type": "execute_result" 31 | } 32 | ], 33 | "source": [ 34 | "from saxpy import znorm\n", 35 | "ts = [-1., -2., -1., 0., 2., 1., 1., 0.]\n", 36 | "z_thrsh = 0.001\n", 37 | "x_scaled = [x / 100.0 for x in ts]\n", 38 | "znorm.znorm(x_scaled, z_thrsh)" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 4, 44 | "metadata": { 45 | "collapsed": true 46 | }, 47 | "outputs": [], 48 | "source": [ 49 | "ts = [-0.1, -0.2, 0.2, 0.1]" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 7, 55 | "metadata": {}, 56 | "outputs": [ 57 | { 58 | "data": { 59 | "text/plain": [ 60 | "array([-0.63245553, -1.26491106, 1.26491106, 0.63245553])" 61 | ] 62 | }, 63 | "execution_count": 7, 64 | "metadata": {}, 65 | "output_type": "execute_result" 66 | } 67 | ], 68 | "source": [ 69 | "znorm.znorm(ts, z_thrsh)" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 12, 75 | "metadata": {}, 76 | "outputs": [ 77 | { 78 | "data": { 79 | "text/plain": [ 80 | "0.158113883008419" 81 | ] 82 | }, 83 | "execution_count": 12, 84 | "metadata": {}, 85 | "output_type": "execute_result" 86 | } 87 | ], 88 | "source": [ 89 | "from numpy import std\n", 90 | "std(znorm.znorm(ts, 0.5))" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "metadata": { 97 | "collapsed": true 98 | }, 99 | "outputs": [], 100 | "source": [] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": null, 105 | "metadata": { 106 | "collapsed": true 107 | }, 108 | "outputs": [], 109 | "source": [] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": { 115 | "collapsed": true 116 | }, 117 | "outputs": [], 118 | "source": [] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": null, 123 | "metadata": { 124 | "collapsed": true 125 | }, 126 | "outputs": [], 127 | "source": [] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": 8, 132 | "metadata": {}, 133 | "outputs": [ 134 | { 135 | "data": { 136 | "text/plain": [ 137 | "'/home/psenin/git/saxpy/jupyter'" 138 | ] 139 | }, 140 | "execution_count": 8, 141 | "metadata": {}, 142 | "output_type": "execute_result" 143 | } 144 | ], 145 | "source": [ 146 | "os.getcwd()" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 2, 152 | "metadata": {}, 153 | "outputs": [ 154 | { 155 | "data": { 156 | "text/plain": [ 157 | "['',\n", 158 | " '/home/psenin/anaconda3/lib/python36.zip',\n", 159 | " '/home/psenin/anaconda3/lib/python3.6',\n", 160 | " '/home/psenin/anaconda3/lib/python3.6/lib-dynload',\n", 161 | " '/home/psenin/anaconda3/lib/python3.6/site-packages',\n", 162 | " '/home/psenin/anaconda3/lib/python3.6/site-packages/IPython/extensions',\n", 163 | " '/home/psenin/.ipython',\n", 164 | " '..']" 165 | ] 166 | }, 167 | "execution_count": 2, 168 | "metadata": {}, 169 | "output_type": "execute_result" 170 | } 171 | ], 172 | "source": [ 173 | "sys.path" 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.3" 194 | } 195 | }, 196 | "nbformat": 4, 197 | "nbformat_minor": 2 198 | } 199 | -------------------------------------------------------------------------------- /jupyter/.ipynb_checkpoints/znorm-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import os\n", 12 | "import sys\n", 13 | "sys.path.append(\"..\")" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 3, 19 | "metadata": {}, 20 | "outputs": [ 21 | { 22 | "data": { 23 | "text/plain": [ 24 | "array([-0.81649658, -1.63299316, -0.81649658, 0. , 1.63299316,\n", 25 | " 0.81649658, 0.81649658, 0. ])" 26 | ] 27 | }, 28 | "execution_count": 3, 29 | "metadata": {}, 30 | "output_type": "execute_result" 31 | } 32 | ], 33 | "source": [ 34 | "from saxpy import znorm\n", 35 | "ts = [-1., -2., -1., 0., 2., 1., 1., 0.]\n", 36 | "z_thrsh = 0.001\n", 37 | "x_scaled = [x / 100.0 for x in ts]\n", 38 | "znorm.znorm(x_scaled, z_thrsh)" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 4, 44 | "metadata": { 45 | "collapsed": true 46 | }, 47 | "outputs": [], 48 | "source": [ 49 | "ts = [-0.1, -0.2, 0.2, 0.1]" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 7, 55 | "metadata": {}, 56 | "outputs": [ 57 | { 58 | "data": { 59 | "text/plain": [ 60 | "array([-0.63245553, -1.26491106, 1.26491106, 0.63245553])" 61 | ] 62 | }, 63 | "execution_count": 7, 64 | "metadata": {}, 65 | "output_type": "execute_result" 66 | } 67 | ], 68 | "source": [ 69 | "znorm.znorm(ts, z_thrsh)" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 12, 75 | "metadata": {}, 76 | "outputs": [ 77 | { 78 | "data": { 79 | "text/plain": [ 80 | "0.158113883008419" 81 | ] 82 | }, 83 | "execution_count": 12, 84 | "metadata": {}, 85 | "output_type": "execute_result" 86 | } 87 | ], 88 | "source": [ 89 | "from numpy import std\n", 90 | "std(znorm.znorm(ts, 0.5))" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": null, 96 | "metadata": { 97 | "collapsed": true 98 | }, 99 | "outputs": [], 100 | "source": [] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": null, 105 | "metadata": { 106 | "collapsed": true 107 | }, 108 | "outputs": [], 109 | "source": [] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": { 115 | "collapsed": true 116 | }, 117 | "outputs": [], 118 | "source": [] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": null, 123 | "metadata": { 124 | "collapsed": true 125 | }, 126 | "outputs": [], 127 | "source": [] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": 8, 132 | "metadata": {}, 133 | "outputs": [ 134 | { 135 | "data": { 136 | "text/plain": [ 137 | "'/home/psenin/git/saxpy/jupyter'" 138 | ] 139 | }, 140 | "execution_count": 8, 141 | "metadata": {}, 142 | "output_type": "execute_result" 143 | } 144 | ], 145 | "source": [ 146 | "os.getcwd()" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 2, 152 | "metadata": {}, 153 | "outputs": [ 154 | { 155 | "data": { 156 | "text/plain": [ 157 | "['',\n", 158 | " '/home/psenin/anaconda3/lib/python36.zip',\n", 159 | " '/home/psenin/anaconda3/lib/python3.6',\n", 160 | " '/home/psenin/anaconda3/lib/python3.6/lib-dynload',\n", 161 | " '/home/psenin/anaconda3/lib/python3.6/site-packages',\n", 162 | " '/home/psenin/anaconda3/lib/python3.6/site-packages/IPython/extensions',\n", 163 | " '/home/psenin/.ipython',\n", 164 | " '..']" 165 | ] 166 | }, 167 | "execution_count": 2, 168 | "metadata": {}, 169 | "output_type": "execute_result" 170 | } 171 | ], 172 | "source": [ 173 | "sys.path" 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.3" 194 | } 195 | }, 196 | "nbformat": 4, 197 | "nbformat_minor": 2 198 | } 199 | -------------------------------------------------------------------------------- /jupyter/.ipynb_checkpoints/insect-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import numpy as np\n", 12 | "def znorm(series, znorm_threshold=0.01):\n", 13 | " \"\"\"Fallback Python implementation.\"\"\"\n", 14 | " sd = np.std(series)\n", 15 | " if (sd < znorm_threshold):\n", 16 | " return series\n", 17 | " mean = np.mean(series)\n", 18 | " res = np.zeros(len(series))\n", 19 | " for i in range(0, len(series)):\n", 20 | " res[i] = (series[i] - mean) / sd\n", 21 | " return res.ravel()" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": null, 27 | "metadata": { 28 | "collapsed": true 29 | }, 30 | "outputs": [], 31 | "source": [] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": null, 36 | "metadata": { 37 | "collapsed": true 38 | }, 39 | "outputs": [], 40 | "source": [ 41 | "from numpy import std\n", 42 | "from saxpy import znorm as zn" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "metadata": {}, 49 | "outputs": [], 50 | "source": [ 51 | "\"\"\"Test the znorm implementation.\"\"\"\n", 52 | "ts = [-1., -2., -1., 0., 2., 1., 1., 0.]\n", 53 | "z_thrsh = 0.001\n", 54 | "\n", 55 | "x_scaled = [x / 100.0 for x in ts]\n" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "zn.znorm(x_scaled, z_thrsh)" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 1, 70 | "metadata": {}, 71 | "outputs": [ 72 | { 73 | "ename": "AttributeError", 74 | "evalue": "'builtin_function_or_method' object has no attribute 'znorm'", 75 | "output_type": "error", 76 | "traceback": [ 77 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 78 | "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", 79 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0minspect\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0msaxpy\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mznorm\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mzn\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mlines\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minspect\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mgetsourcelines\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mzn\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mznorm\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlines\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", 80 | "\u001b[0;31mAttributeError\u001b[0m: 'builtin_function_or_method' object has no attribute 'znorm'" 81 | ] 82 | } 83 | ], 84 | "source": [ 85 | "import inspect\n", 86 | "from saxpy import znorm as zn\n", 87 | "lines = inspect.getsourcelines(zn.znorm)\n", 88 | "print(\"\".join(lines[0]))\n" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": null, 94 | "metadata": {}, 95 | "outputs": [], 96 | "source": [ 97 | "mean = np.mean(zz)\n", 98 | "mean" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": null, 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "std = np.std(zz, axis=0, ddof=1)\n", 108 | "std" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": null, 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "metadata": { 122 | "collapsed": true 123 | }, 124 | "outputs": [], 125 | "source": [] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": null, 130 | "metadata": { 131 | "collapsed": true 132 | }, 133 | "outputs": [], 134 | "source": [] 135 | } 136 | ], 137 | "metadata": { 138 | "kernelspec": { 139 | "display_name": "Python 3", 140 | "language": "python", 141 | "name": "python3" 142 | }, 143 | "language_info": { 144 | "codemirror_mode": { 145 | "name": "ipython", 146 | "version": 3 147 | }, 148 | "file_extension": ".py", 149 | "mimetype": "text/x-python", 150 | "name": "python", 151 | "nbconvert_exporter": "python", 152 | "pygments_lexer": "ipython3", 153 | "version": "3.6.3" 154 | } 155 | }, 156 | "nbformat": 4, 157 | "nbformat_minor": 2 158 | } 159 | -------------------------------------------------------------------------------- /jupyter/tinkah.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 3, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "def idx2letter(idx):\n", 12 | " \"\"\"Convert a numerical index to a char.\"\"\"\n", 13 | " if 0 <= idx < 20:\n", 14 | " return chr(97 + idx)\n", 15 | " else:\n", 16 | " raise ValueError('A wrong idx value supplied.')" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 4, 22 | "metadata": {}, 23 | "outputs": [ 24 | { 25 | "data": { 26 | "text/plain": [ 27 | "'a'" 28 | ] 29 | }, 30 | "execution_count": 4, 31 | "metadata": {}, 32 | "output_type": "execute_result" 33 | } 34 | ], 35 | "source": [ 36 | "idx2letter(0)" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 9, 42 | "metadata": {}, 43 | "outputs": [ 44 | { 45 | "data": { 46 | "text/plain": [ 47 | "'h'" 48 | ] 49 | }, 50 | "execution_count": 9, 51 | "metadata": {}, 52 | "output_type": "execute_result" 53 | } 54 | ], 55 | "source": [ 56 | "idx2letter(7)" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": 6, 62 | "metadata": {}, 63 | "outputs": [ 64 | { 65 | "data": { 66 | "text/plain": [ 67 | "'t'" 68 | ] 69 | }, 70 | "execution_count": 6, 71 | "metadata": {}, 72 | "output_type": "execute_result" 73 | } 74 | ], 75 | "source": [ 76 | "idx2letter(19)" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 7, 82 | "metadata": {}, 83 | "outputs": [ 84 | { 85 | "ename": "ValueError", 86 | "evalue": "A wrong idx value supplied.", 87 | "output_type": "error", 88 | "traceback": [ 89 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 90 | "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", 91 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0midx2letter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 92 | "\u001b[0;32m\u001b[0m in \u001b[0;36midx2letter\u001b[0;34m(idx)\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mchr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m97\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0midx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'A wrong idx value supplied.'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 93 | "\u001b[0;31mValueError\u001b[0m: A wrong idx value supplied." 94 | ] 95 | } 96 | ], 97 | "source": [ 98 | "idx2letter(-1)" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": 8, 104 | "metadata": {}, 105 | "outputs": [ 106 | { 107 | "ename": "ValueError", 108 | "evalue": "A wrong idx value supplied.", 109 | "output_type": "error", 110 | "traceback": [ 111 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 112 | "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", 113 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0midx2letter\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m20\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 114 | "\u001b[0;32m\u001b[0m in \u001b[0;36midx2letter\u001b[0;34m(idx)\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mchr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m97\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0midx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'A wrong idx value supplied.'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 115 | "\u001b[0;31mValueError\u001b[0m: A wrong idx value supplied." 116 | ] 117 | } 118 | ], 119 | "source": [ 120 | "idx2letter(20)" 121 | ] 122 | } 123 | ], 124 | "metadata": { 125 | "kernelspec": { 126 | "display_name": "Python 3", 127 | "language": "python", 128 | "name": "python3" 129 | }, 130 | "language_info": { 131 | "codemirror_mode": { 132 | "name": "ipython", 133 | "version": 3 134 | }, 135 | "file_extension": ".py", 136 | "mimetype": "text/x-python", 137 | "name": "python", 138 | "nbconvert_exporter": "python", 139 | "pygments_lexer": "ipython3", 140 | "version": "3.6.3" 141 | } 142 | }, 143 | "nbformat": 4, 144 | "nbformat_minor": 2 145 | } 146 | -------------------------------------------------------------------------------- /saxpy/hotsax.py: -------------------------------------------------------------------------------- 1 | """Implements HOT-SAX.""" 2 | import numpy as np 3 | from saxpy.znorm import znorm 4 | from saxpy.sax import sax_via_window 5 | from saxpy.distance import euclidean 6 | 7 | 8 | def find_discords_hotsax(series, win_size=100, num_discords=2, alphabet_size=3, 9 | paa_size=3, znorm_threshold=0.01, sax_type='unidim'): 10 | """HOT-SAX-driven discords discovery.""" 11 | discords = list() 12 | 13 | global_registry = set() 14 | 15 | # Z-normalized versions for every subsequence. 16 | znorms = np.array([znorm(series[pos: pos + win_size], znorm_threshold) for pos in range(len(series) - win_size + 1)]) 17 | 18 | # SAX words for every subsequence. 19 | sax_data = sax_via_window(series, win_size=win_size, paa_size=paa_size, alphabet_size=alphabet_size, 20 | nr_strategy=None, znorm_threshold=0.01, sax_type=sax_type) 21 | 22 | """[2.0] build the 'magic' array""" 23 | magic_array = list() 24 | for k, v in sax_data.items(): 25 | magic_array.append((k, len(v))) 26 | 27 | """[2.1] sort it ascending by the number of occurrences""" 28 | magic_array = sorted(magic_array, key=lambda tup: tup[1]) 29 | 30 | while len(discords) < num_discords: 31 | 32 | best_discord = find_best_discord_hotsax(series, win_size, global_registry, sax_data, magic_array, znorms) 33 | 34 | if -1 == best_discord[0]: 35 | break 36 | 37 | discords.append(best_discord) 38 | 39 | mark_start = max(0, best_discord[0] - win_size + 1) 40 | mark_end = best_discord[0] + win_size 41 | 42 | for i in range(mark_start, mark_end): 43 | global_registry.add(i) 44 | 45 | return discords 46 | 47 | 48 | def find_best_discord_hotsax(series, win_size, global_registry, sax_data, magic_array, znorms): 49 | """Find the best discord with hotsax.""" 50 | 51 | """[3.0] define the key vars""" 52 | best_so_far_position = -1 53 | best_so_far_distance = 0. 54 | 55 | distance_calls = 0 56 | 57 | visit_array = np.zeros(len(series), dtype=int) 58 | 59 | """[4.0] and we are off iterating over the magic array entries""" 60 | for entry in magic_array: 61 | 62 | """[5.0] current SAX words and the number of other sequences mapping to the same SAX word.""" 63 | curr_word = entry[0] 64 | occurrences = sax_data[curr_word] 65 | 66 | """[6.0] jumping around by the same word occurrences makes it easier to 67 | nail down the possibly small distance value -- so we can be efficient 68 | and all that...""" 69 | for curr_pos in occurrences: 70 | 71 | if curr_pos in global_registry: 72 | continue 73 | 74 | """[7.0] we don't want an overlapping subsequence""" 75 | mark_start = curr_pos - win_size + 1 76 | mark_end = curr_pos + win_size 77 | visit_set = set(range(mark_start, mark_end)) 78 | 79 | """[8.0] here is our subsequence in question""" 80 | cur_seq = znorms[curr_pos] 81 | 82 | """[9.0] let's see what is NN distance""" 83 | nn_dist = np.inf 84 | do_random_search = True 85 | 86 | """[10.0] ordered by occurrences search first""" 87 | for next_pos in occurrences: 88 | 89 | """[11.0] skip bad pos""" 90 | if next_pos in visit_set: 91 | continue 92 | else: 93 | visit_set.add(next_pos) 94 | 95 | """[12.0] distance we compute""" 96 | 97 | dist = euclidean(cur_seq, znorms[next_pos]) 98 | distance_calls += 1 99 | 100 | """[13.0] keep the books up-to-date""" 101 | if dist < nn_dist: 102 | nn_dist = dist 103 | if dist < best_so_far_distance: 104 | do_random_search = False 105 | break 106 | 107 | """[13.0] if not broken above, 108 | we shall proceed with random search""" 109 | if do_random_search: 110 | """[14.0] build that random visit order array""" 111 | curr_idx = 0 112 | for i in range(0, (len(series) - win_size + 1)): 113 | if not(i in visit_set): 114 | visit_array[curr_idx] = i 115 | curr_idx += 1 116 | it_order = np.random.permutation(visit_array[0:curr_idx]) 117 | curr_idx -= 1 118 | 119 | """[15.0] and go random""" 120 | while curr_idx >= 0: 121 | rand_pos = it_order[curr_idx] 122 | curr_idx -= 1 123 | 124 | dist = euclidean(cur_seq, znorms[rand_pos]) 125 | distance_calls += 1 126 | 127 | """[16.0] keep the books up-to-date again""" 128 | if dist < nn_dist: 129 | nn_dist = dist 130 | if dist < best_so_far_distance: 131 | nn_dist = dist 132 | break 133 | 134 | """[17.0] and BIGGER books""" 135 | if (nn_dist > best_so_far_distance) and (nn_dist < np.inf): 136 | best_so_far_distance = nn_dist 137 | best_so_far_position = curr_pos 138 | 139 | return best_so_far_position, best_so_far_distance 140 | -------------------------------------------------------------------------------- /saxpy/alphabet.py: -------------------------------------------------------------------------------- 1 | """Implements Alphabet cuts.""" 2 | import numpy as np 3 | 4 | 5 | def cuts_for_asize(a_size): 6 | """Generate a set of alphabet cuts for its size.""" 7 | """ Typically, we generate cuts in R as follows: 8 | get_cuts_for_num <- function(num) { 9 | cuts = c(-Inf) 10 | for (i in 1:(num-1)) { 11 | cuts = c(cuts, qnorm(i * 1/num)) 12 | } 13 | cuts 14 | } 15 | 16 | get_cuts_for_num(3) """ 17 | options = { 18 | 2: np.array([-np.inf, 0.00]), 19 | 3: np.array([-np.inf, -0.4307273, 0.4307273]), 20 | 4: np.array([-np.inf, -0.6744898, 0, 0.6744898]), 21 | 5: np.array([-np.inf, -0.841621233572914, -0.2533471031358, 22 | 0.2533471031358, 0.841621233572914]), 23 | 6: np.array([-np.inf, -0.967421566101701, -0.430727299295457, 0, 24 | 0.430727299295457, 0.967421566101701]), 25 | 7: np.array([-np.inf, -1.06757052387814, -0.565948821932863, 26 | -0.180012369792705, 0.180012369792705, 0.565948821932863, 27 | 1.06757052387814]), 28 | 8: np.array([-np.inf, -1.15034938037601, -0.674489750196082, 29 | -0.318639363964375, 0, 0.318639363964375, 30 | 0.674489750196082, 1.15034938037601]), 31 | 9: np.array([-np.inf, -1.22064034884735, -0.764709673786387, 32 | -0.430727299295457, -0.139710298881862, 0.139710298881862, 33 | 0.430727299295457, 0.764709673786387, 1.22064034884735]), 34 | 10: np.array([-np.inf, -1.2815515655446, -0.841621233572914, 35 | -0.524400512708041, -0.2533471031358, 0, 0.2533471031358, 36 | 0.524400512708041, 0.841621233572914, 1.2815515655446]), 37 | 11: np.array([-np.inf, -1.33517773611894, -0.908457868537385, 38 | -0.604585346583237, -0.348755695517045, 39 | -0.114185294321428, 0.114185294321428, 0.348755695517045, 40 | 0.604585346583237, 0.908457868537385, 1.33517773611894]), 41 | 12: np.array([-np.inf, -1.38299412710064, -0.967421566101701, 42 | -0.674489750196082, -0.430727299295457, 43 | -0.210428394247925, 0, 0.210428394247925, 44 | 0.430727299295457, 0.674489750196082, 0.967421566101701, 45 | 1.38299412710064]), 46 | 13: np.array([-np.inf, -1.42607687227285, -1.0200762327862, 47 | -0.736315917376129, -0.502402223373355, 48 | -0.293381232121193, -0.0965586152896391, 49 | 0.0965586152896394, 0.293381232121194, 0.502402223373355, 50 | 0.73631591737613, 1.0200762327862, 1.42607687227285]), 51 | 14: np.array([-np.inf, -1.46523379268552, -1.06757052387814, 52 | -0.791638607743375, -0.565948821932863, -0.36610635680057, 53 | -0.180012369792705, 0, 0.180012369792705, 54 | 0.36610635680057, 0.565948821932863, 0.791638607743375, 55 | 1.06757052387814, 1.46523379268552]), 56 | 15: np.array([-np.inf, -1.50108594604402, -1.11077161663679, 57 | -0.841621233572914, -0.622925723210088, 58 | -0.430727299295457, -0.2533471031358, -0.0836517339071291, 59 | 0.0836517339071291, 0.2533471031358, 0.430727299295457, 60 | 0.622925723210088, 0.841621233572914, 1.11077161663679, 61 | 1.50108594604402]), 62 | 16: np.array([-np.inf, -1.53412054435255, -1.15034938037601, 63 | -0.887146559018876, -0.674489750196082, 64 | -0.488776411114669, -0.318639363964375, 65 | -0.157310684610171, 0, 0.157310684610171, 66 | 0.318639363964375, 0.488776411114669, 0.674489750196082, 67 | 0.887146559018876, 1.15034938037601, 1.53412054435255]), 68 | 17: np.array([-np.inf, -1.5647264713618, -1.18683143275582, 69 | -0.928899491647271, -0.721522283982343, 70 | -0.541395085129088, -0.377391943828554, 71 | -0.223007830940367, -0.0737912738082727, 72 | 0.0737912738082727, 0.223007830940367, 0.377391943828554, 73 | 0.541395085129088, 0.721522283982343, 0.928899491647271, 74 | 1.18683143275582, 1.5647264713618]), 75 | 18: np.array([-np.inf, -1.59321881802305, -1.22064034884735, 76 | -0.967421566101701, -0.764709673786387, 77 | -0.589455797849779, -0.430727299295457, 78 | -0.282216147062508, -0.139710298881862, 0, 79 | 0.139710298881862, 0.282216147062508, 0.430727299295457, 80 | 0.589455797849779, 0.764709673786387, 0.967421566101701, 81 | 1.22064034884735, 1.59321881802305]), 82 | 19: np.array([-np.inf, -1.61985625863827, -1.25211952026522, 83 | -1.00314796766253, -0.8045963803603, -0.633640000779701, 84 | -0.47950565333095, -0.336038140371823, -0.199201324789267, 85 | -0.0660118123758407, 0.0660118123758406, 86 | 0.199201324789267, 0.336038140371823, 0.47950565333095, 87 | 0.633640000779701, 0.8045963803603, 1.00314796766253, 88 | 1.25211952026522, 1.61985625863827]), 89 | 20: np.array([-np.inf, -1.64485362695147, -1.2815515655446, 90 | -1.03643338949379, -0.841621233572914, -0.674489750196082, 91 | -0.524400512708041, -0.385320466407568, -0.2533471031358, 92 | -0.125661346855074, 0, 0.125661346855074, 0.2533471031358, 93 | 0.385320466407568, 0.524400512708041, 0.674489750196082, 94 | 0.841621233572914, 1.03643338949379, 1.2815515655446, 95 | 1.64485362695147]), 96 | } 97 | 98 | return options[a_size] 99 | -------------------------------------------------------------------------------- /saxpy/sax.py: -------------------------------------------------------------------------------- 1 | """Converts a normlized timeseries to SAX symbols.""" 2 | from collections import defaultdict 3 | from saxpy.strfunc import idx2letter 4 | from saxpy.znorm import znorm 5 | from saxpy.paa import paa 6 | from saxpy.alphabet import cuts_for_asize 7 | import numpy as np 8 | from sklearn.cluster import KMeans 9 | 10 | 11 | # For SAX-REPEAT. 12 | def get_sax_list(series, cuts): 13 | """ 14 | >>> get_sax_list([[1, 2, -3], [4, 9, -2], [5, 7, -8], [0, 3, -1], [-1, -2, -10]], cuts_for_asize(3)) 15 | [[2, 2, 0], [2, 2, 0], [2, 2, 0], [1, 2, 0], [0, 0, 0]] 16 | """ 17 | 18 | series = np.array(series) 19 | a_size = len(cuts) 20 | multidim_sax_list = [] 21 | 22 | for i in range(series.shape[0]): 23 | multidim_sax = [] 24 | 25 | for j in range(series.shape[1]): 26 | num = series[i][j] 27 | 28 | # If the number is below 0, start from the bottom, otherwise from the top 29 | if num >= 0: 30 | j = a_size - 1 31 | while j > 0 and cuts[j] >= num: 32 | j = j - 1 33 | multidim_sax.append(j) 34 | else: 35 | j = 1 36 | while j < a_size and cuts[j] <= num: 37 | j = j + 1 38 | multidim_sax.append(j - 1) 39 | 40 | multidim_sax_list.append(multidim_sax) 41 | 42 | return multidim_sax_list 43 | 44 | 45 | def ts_to_string(series, cuts): 46 | """A straightforward num-to-string conversion. 47 | 48 | >>> ts_to_string([-1, 0, 1], cuts_for_asize(3)) 49 | 'abc' 50 | 51 | >>> ts_to_string([1, -1, 1], cuts_for_asize(3)) 52 | 'cac' 53 | """ 54 | 55 | series = np.array(series) 56 | a_size = len(cuts) 57 | sax = list() 58 | 59 | for i in range(series.shape[0]): 60 | num = series[i] 61 | 62 | # If the number is below 0, start from the bottom, otherwise from the top 63 | if num >= 0: 64 | j = a_size - 1 65 | while j > 0 and cuts[j] >= num: 66 | 67 | j = j - 1 68 | sax.append(idx2letter(j)) 69 | else: 70 | j = 1 71 | while j < a_size and cuts[j] <= num: 72 | j = j + 1 73 | sax.append(idx2letter(j-1)) 74 | 75 | return ''.join(sax) 76 | 77 | 78 | def is_mindist_zero(a, b): 79 | """Check mindist.""" 80 | if len(a) != len(b): 81 | return 0 82 | else: 83 | for i in range(0, len(b)): 84 | if abs(ord(a[i]) - ord(b[i])) > 1: 85 | return 0 86 | return 1 87 | 88 | 89 | def sax_by_chunking(series, paa_size, alphabet_size=3, znorm_threshold=0.01): 90 | """Simple chunking conversion implementation.""" 91 | paa_rep = paa(znorm(series, znorm_threshold), paa_size) 92 | cuts = cuts_for_asize(alphabet_size) 93 | return ts_to_string(paa_rep, cuts) 94 | 95 | 96 | def sax_via_window(series, win_size, paa_size, alphabet_size=3, 97 | nr_strategy='exact', znorm_threshold=0.01, sax_type='unidim'): 98 | """Simple via window conversion implementation. 99 | 100 | # SAX-ENERGY 101 | >>> sax_via_window([[1, 2, 3], [4, 5, 6]], win_size=1, paa_size=3, sax_type='energy', nr_strategy=None)['abc'] 102 | [0, 1] 103 | 104 | >>> sax_via_window([[1, 2, 3, 4], [4, 5, 6, 7]], win_size=1, paa_size=4, sax_type='energy', nr_strategy=None)['aacc'] 105 | [0, 1] 106 | 107 | >>> sax_via_window([[1, 2, 3, 4], [4, 5, 6, 7]], win_size=2, paa_size=4, sax_type='energy', nr_strategy=None)['aaccaacc'] 108 | [0] 109 | 110 | # SAX-REPEAT 111 | >>> sax_via_window([[1, 2, 3], [4, 5, 6], [7, 8, 9]], win_size=2, paa_size=2, sax_type='repeat', nr_strategy=None)['ac'] 112 | [0, 1] 113 | 114 | >>> sax_via_window([[1, 2, 3], [4, 5, 6], [7, 8, 9]], win_size=1, paa_size=1, sax_type='repeat', nr_strategy=None)['a'] 115 | [0, 1, 2] 116 | 117 | # SAX-INDEPENDENT 118 | >>> sax_via_window([[1, 2, 3, 4], [4, 5, 6, 7]], win_size=2, paa_size=2, sax_type='independent', nr_strategy=None)['acacacac'] 119 | [0] 120 | 121 | >>> sax_via_window([[1, 2], [4, 5], [7, 8]], win_size=2, paa_size=2, sax_type='independent', nr_strategy=None)['acac'] 122 | [0, 1] 123 | 124 | >>> sax_via_window([[1, 2], [4, 8], [7, 5]], win_size=2, paa_size=2, sax_type='independent', nr_strategy=None)['acac'] 125 | [0] 126 | 127 | >>> sax_via_window([[1, 2], [4, 8], [7, 5]], win_size=2, paa_size=2, sax_type='independent', nr_strategy=None)['acca'] 128 | [1] 129 | 130 | """ 131 | 132 | # Convert to numpy array. 133 | series = np.array(series) 134 | 135 | # Check on dimensions. 136 | if len(series.shape) > 2: 137 | raise ValueError('Please reshape time-series to stack dimensions along the 2nd dimension, so that the array shape is a 2-tuple.') 138 | 139 | # PAA size is the length of the PAA sequence. 140 | if sax_type != 'energy' and paa_size > win_size: 141 | raise ValueError('PAA size cannot be greater than the window size.') 142 | 143 | if sax_type == 'energy' and len(series.shape) == 1: 144 | raise ValueError('Must pass a multidimensional time-series to SAX-ENERGY.') 145 | 146 | # Breakpoints. 147 | cuts = cuts_for_asize(alphabet_size) 148 | 149 | # Dictionary mapping SAX words to indices. 150 | sax = defaultdict(list) 151 | 152 | if sax_type == 'repeat': 153 | # Maps indices to multi-dimensional SAX words. 154 | multidim_sax_dict = [] 155 | 156 | # List of all the multi-dimensional SAX words. 157 | multidim_sax_list = [] 158 | 159 | # Sliding window across time dimension. 160 | for i in range(series.shape[0] - win_size + 1): 161 | 162 | # Subsection starting at this index. 163 | sub_section = series[i: i + win_size] 164 | 165 | # Z-normalized subsection. 166 | if win_size == 1: 167 | zn = sub_section 168 | else: 169 | zn = znorm(sub_section, znorm_threshold) 170 | 171 | # PAA representation of subsection. 172 | paa_rep = paa(zn, paa_size, 'repeat') 173 | 174 | # SAX representation of subsection, but in terms of multi-dimensional vectors. 175 | multidim_sax = get_sax_list(paa_rep, cuts) 176 | 177 | # Update data-structures. 178 | multidim_sax_dict.append(multidim_sax) 179 | multidim_sax_list.extend(multidim_sax) 180 | 181 | # Cluster with k-means++. 182 | kmeans = KMeans(n_clusters=alphabet_size, random_state=0).fit(multidim_sax_list) 183 | 184 | # Cluster indices in sorted order. 185 | order = np.lexsort(np.rot90(kmeans.cluster_centers_)) 186 | 187 | # Sliding window across time dimension. 188 | prev_word = '' 189 | for i in range(series.shape[0] - win_size + 1): 190 | 191 | # Map cluster indices to new SAX letters. 192 | curr_word_list = map(lambda cluster_index: idx2letter(order[cluster_index]), kmeans.predict(multidim_sax_dict[i])) 193 | curr_word = ''.join(curr_word_list) 194 | 195 | if '' != prev_word: 196 | if 'exact' == nr_strategy and prev_word == curr_word: 197 | continue 198 | elif 'mindist' == nr_strategy and is_mindist_zero(prev_word, curr_word): 199 | continue 200 | 201 | prev_word = curr_word 202 | 203 | sax[curr_word].append(i) 204 | 205 | else: 206 | # Sliding window across time dimension. 207 | prev_word = '' 208 | for i in range(series.shape[0] - win_size + 1): 209 | 210 | # Subsection starting at this index. 211 | sub_section = series[i: i + win_size] 212 | 213 | if sax_type == 'energy': 214 | curr_word = '' 215 | for energy_dist in sub_section: 216 | # Normalize energy distribution. 217 | energy_zn = znorm(energy_dist, znorm_threshold) 218 | 219 | # PAA representation of energy distribution. 220 | paa_rep = paa(energy_zn, paa_size, 'unidim') 221 | # paa_rep = energy_zn 222 | 223 | # SAX representation of the energy distribution. 224 | energy_word = ts_to_string(paa_rep, cuts) 225 | 226 | # Add to current word. 227 | curr_word += energy_word 228 | 229 | elif sax_type == 'independent': 230 | curr_word = '' 231 | for dim in range(sub_section.shape[1]): 232 | # Obtain the subsequence restricted to one dimension. 233 | one_dimension_sub_section = sub_section[:, dim] 234 | 235 | # Z-normalized subsection. 236 | zn = znorm(one_dimension_sub_section, znorm_threshold) 237 | 238 | # PAA representation of subsection. 239 | paa_rep = paa(zn, paa_size, 'unidim') 240 | 241 | # Get the SAX word - just a unidimensional SAX. 242 | one_dim_word = ts_to_string(paa_rep, cuts) 243 | 244 | # Add this dimensions' representation to the overall SAX word. 245 | curr_word += one_dim_word 246 | 247 | else: 248 | # Z-normalized subsection. 249 | zn = znorm(sub_section, znorm_threshold) 250 | 251 | # PAA representation of subsection. 252 | paa_rep = paa(zn, paa_size, sax_type) 253 | 254 | # SAX representation of subsection. 255 | curr_word = ts_to_string(paa_rep, cuts) 256 | 257 | if '' != prev_word: 258 | if 'exact' == nr_strategy and prev_word == curr_word: 259 | continue 260 | elif 'mindist' == nr_strategy and is_mindist_zero(prev_word, curr_word): 261 | continue 262 | 263 | prev_word = curr_word 264 | 265 | sax[curr_word].append(i) 266 | 267 | return sax 268 | 269 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Time series symbolic discretization with SAX 2 | ==== 3 | [![Latest PyPI version](https://img.shields.io/pypi/v/saxpy.svg)](https://pypi.python.org/pypi/saxpy) 4 | [![Latest Travis CI build status](https://travis-ci.org/seninp/saxpy.png)](https://travis-ci.org/seninp/saxpy) 5 | [![image](https://codecov.io/gh/seninp/saxpy/branch/master/graph/badge.svg)](https://codecov.io/gh/seninp/saxpy) 6 | [![image](http://img.shields.io/:license-gpl2-green.svg)](http://www.gnu.org/licenses/gpl-2.0.html) 7 | 8 | 9 | This code is released under [GPL v.2.0](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) and implements in Python: 10 | * Symbolic Aggregate approXimation (SAX) (with z-normalization and PAA) [1] 11 | * EMMA -- an algorithm for time series motif discovery [2] 12 | * HOT-SAX - a time series anomaly (discord) discovery algorithm [3] 13 | * SAX-ZSCORE - an extension to SAX for multi-dimensional time-series SAX that modifies the z-normalization to multi-dimensional sequences and PAA aggregation with the average along data-dimensions. [4] 14 | * SAX-REPEAT - an extension to SAX for multi-dimensional time-series that performs standard SAX on individual dimensions, then clusters to map multi-dimensional words into strings from the required alphabet size. [4] 15 | 16 | 17 | Note that all of the library's functionality is also available in [R](https://github.com/jMotif/jmotif-R) and [Java](https://github.com/jMotif/SAX). 18 | 19 | 20 | ## References 21 | [1] Lin, J., Keogh, E., Patel, P., and Lonardi, S., 22 | [*Finding Motifs in Time Series*](http://cs.gmu.edu/~jessica/Lin_motif.pdf), 23 | The 2nd Workshop on Temporal Data Mining, the 8th ACM Int'l Conference on KDD (2002) 24 | 25 | [2] Patel, P., Keogh, E., Lin, J., Lonardi, S., 26 | [*Mining Motifs in Massive Time Series Databases*](http://www.cs.gmu.edu/~jessica/publications/motif_icdm02.pdf), 27 | In Proc. ICDM (2002) 28 | 29 | [3] Keogh, E., Lin, J., Fu, A., 30 | [*HOT SAX: Efficiently finding the most unusual time series subsequence*](http://www.cs.ucr.edu/~eamonn/HOT%20SAX%20%20long-ver.pdf), 31 | In Proc. ICDM (2005) 32 | 33 | [4] Mohammad, Y., Nishida T., 34 | [*Robust learning from demonstrations using multidimensional SAX*](https://ieeexplore.ieee.org/document/6987960), 35 | 2014 14th International Conference on Control, Automation and Systems (ICCAS 2014) 36 | 37 | ## Citing this work 38 | 39 | If you are using this implementation for you academic work, please cite our [Grammarviz 2.0 paper](http://link.springer.com/chapter/10.1007/978-3-662-44845-8_37): 40 | 41 | [[Citation]](https://raw.githubusercontent.com/jMotif/SAX/master/citation.bib) Senin, P., Lin, J., Wang, X., Oates, T., Gandhi, S., Boedihardjo, A.P., Chen, C., Frankenstein, S., Lerner, M., [*GrammarViz 2.0: a tool for grammar-based pattern discovery in time series*](http://csdl.ics.hawaii.edu/techreports/2014/14-06/14-06.pdf), ECML/PKDD Conference, 2014. 42 | 43 | SAX in a nutshell 44 | ------------ 45 | SAX is used to transform a sequence of rational numbers (i.e., a time series) into a sequence of letters (i.e., a string). An illustration of a time series of 128 points converted into the word of 8 letters: 46 | 47 | ![SAX in a nutshell](https://raw.githubusercontent.com/jMotif/SAX/master/src/resources/sax_transform.png) 48 | 49 | As discretization is probably the most used transformation in data mining, SAX has been widely used throughout the field. Find more information about SAX at its authors pages: [SAX overview by Jessica Lin](http://cs.gmu.edu/~jessica/sax.htm), [Eamonn Keogh's SAX page](http://www.cs.ucr.edu/~eamonn/SAX.htm), or at [sax-vsm wiki page](http://jmotif.github.io/sax-vsm_site/morea/algorithm/SAX.html). 50 | 51 | Building 52 | ------------ 53 | The code is written in Python and hosted on PyPi, so use `pip` to install it. This is what happens in my clean test environment: 54 | 55 | $ pip install saxpy 56 | Collecting saxpy 57 | Downloading saxpy-1.0.0.dev154.tar.gz (180kB) 58 | 100% |████████████████████████████████| 184kB 778kB/s 59 | Requirement already satisfied: numpy in /home/psenin/anaconda3/lib/python3.6/site-packages (from saxpy) 60 | Requirement already satisfied: pytest in /home/psenin/anaconda3/lib/python3.6/site-packages (from saxpy) 61 | ... 62 | Installing collected packages: coverage, pytest-cov, codecov, saxpy 63 | Successfully installed codecov-2.0.15 coverage-4.5.1 pytest-cov-2.5.1 saxpy-1.0.0.dev154 64 | 65 | 66 | 67 | Simple time series to SAX conversion 68 | ------------ 69 | To convert a time series of an arbitrary length to SAX we need to define the alphabet cuts. Saxpy retrieves cuts for a normal alphabet (we use size 3 here) via `cuts_for_asize` function: 70 | 71 | from saxpy.alphabet import cuts_for_asize 72 | cuts_for_asize(3) 73 | 74 | which yields an array: 75 | 76 | array([ -inf, -0.4307273, 0.4307273]) 77 | 78 | To convert a time series to letters with SAX we use `ts_to_string` function but not forgetting to z-normalize the input time series (we use Normal alphabet): 79 | 80 | import numpy as np 81 | from saxpy.znorm import znorm 82 | from saxpy.sax import ts_to_string 83 | ts_to_string(znorm(np.array([-2, 0, 2, 0, -1])), cuts_for_asize(3)) 84 | 85 | this produces a string: 86 | 87 | 'abcba' 88 | 89 | Time series to SAX conversion with PAA aggregation (by "chunking") 90 | ------------ 91 | In order to reduce dimensionality further, the PAA (Piecewise Aggregate Approximation) is usually applied prior to SAX: 92 | 93 | import numpy as np 94 | from saxpy.znorm import znorm 95 | from saxpy.paa import paa 96 | from saxpy.sax import ts_to_string 97 | 98 | dat = np.array([-2, 0, 2, 0, -1]) 99 | dat_znorm = znorm(dat) 100 | dat_paa_3 = paa(dat_znorm, 3) 101 | 102 | ts_to_string(dat_paa_3, cuts_for_asize(3)) 103 | 104 | and a string with three letters is produced: 105 | 106 | 'acb' 107 | 108 | 109 | Time series to SAX conversion via sliding window 110 | ------------ 111 | Typically, in order to investigate the input time series structure in order to discover anomalous (i.e., discords) and recurrent (i.e., motifs) patterns we employ time series to SAX conversion via sliding window. Saxpy implements this workflow: 112 | 113 | import numpy as np 114 | from saxpy.sax import sax_via_window 115 | 116 | dat = np.array([0., 0., 0., 0., 0., -0.270340178359072, -0.367828308500142, 117 | 0.666980581124872, 1.87088147328446, 2.14548907684624, 118 | -0.480859313143032, -0.72911654245842, -0.490308602315934, 119 | -0.66152028906509, -0.221049033806403, 0.367003418871239, 120 | 0.631073992586373, 0.0487728723414486, 0.762655178750436, 121 | 0.78574757843331, 0.338239686422963, 0.784206454089066, 122 | -2.14265084073625, 2.11325193044223, 0.186018356196443, 123 | 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.519132472499234, 124 | -2.604783141655, -0.244519550114012, -1.6570790528784, 125 | 3.34184602886343, 2.10361226260999, 1.9796808733979, 126 | -0.822247322003058, 1.06850578033292, -0.678811824405992, 127 | 0.804225748913681, 0.57363964388698, 0.437113583759113, 128 | 0.437208643628268, 0.989892093383503, 1.76545983424176, 129 | 0.119483882364649, -0.222311941138971, -0.74669456611669, 130 | -0.0663660879732063, 0., 0., 0., 0., 0.,]) 131 | 132 | sax_none = sax_via_window(dat, win_size=6, paa_size=3, alphabet_size=3, nr_strategy=None, znorm_threshold=0.01) 133 | 134 | sax1 135 | 136 | the result is represented as a data structure of resulting words and their respective positions on time series: 137 | 138 | defaultdict(list, 139 | {'aac': [4, 10, 11, 30, 35], 140 | 'abc': [12, 14, 36, 44], 141 | 'acb': [5, 16, 21, 37, 43], 142 | 'acc': [13, 52, 53], 143 | 'bac': [3, 19, 34, 45, 51], 144 | 'bba': [31], 145 | 'bbb': [15, 18, 20, 22, 25, 26, 27, 28, 29, 41, 42, 46], 146 | 'bbc': [2], 147 | 'bca': [6, 17, 32, 38, 47, 48], 148 | 'caa': [8, 23, 24, 40], 149 | 'cab': [9, 50], 150 | 'cba': [7, 39, 49], 151 | 'cbb': [33], 152 | 'cca': [0, 1]}) 153 | 154 | `sax_via_window` is parameterised with a sliding window size, desired PAA aggregation, alphabet size, a numerosity reduction strategy, z-normalization threshold, and a SAX type ('unidim' for unidimensional SAX (default), 'zscore' for SAX-ZSCORE, 'repeat' for SAX-REPEAT): 155 | 156 | def sax_via_window(series, win_size, paa_size, alphabet_size=3, 157 | nr_strategy='exact', z_threshold=0.01, sax_type='unidim') 158 | 159 | 160 | Time series discord discovery with HOT-SAX 161 | ------------ 162 | Saxpy implements HOT-SAX discord discovery algorithm in `find_discords_hotsax` function which can be used as follows: 163 | 164 | import numpy as np 165 | from saxpy.hotsax import find_discords_hotsax 166 | from numpy import genfromtxt 167 | dd = genfromtxt("data/ecg0606_1.csv", delimiter=',') 168 | discords = find_discords_hotsax(dd) 169 | discords 170 | 171 | and discovers anomalies easily: 172 | 173 | [(430, 5.2790800061718386), (318, 4.1757563573086953)] 174 | 175 | The function has a similar parameterization: sliding window size, PAA and alphabet sizes, z-normalization threshold, and a parameter specifying how many discords are desired to be found: 176 | 177 | def find_discords_hotsax(series, win_size=100, num_discords=2, a_size=3, 178 | paa_size=3, z_threshold=0.01) 179 | 180 | Saxpy also provides a brute-force implementation of the discord search if you'd like to verify discords or evaluate the speed-up: 181 | 182 | find_discords_brute_force(series, win_size, num_discords=2, 183 | z_threshold=0.01) 184 | which can be called as follows: 185 | 186 | discords = find_discords_brute_force(dd[100:500], 100, 4) 187 | discords 188 | 189 | [(73, 6.198555329625453), (219, 5.5636923991016136)] 190 | 191 | Time series motif discovery with EMMA 192 | ------------ 193 | ToDo... 194 | 195 | ## Made with Aloha! 196 | ![Made with Aloha!](https://raw.githubusercontent.com/GrammarViz2/grammarviz2_src/master/src/resources/assets/aloha.jpg) 197 | -------------------------------------------------------------------------------- /jupyter/paa.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import os\n", 12 | "import sys\n", 13 | "sys.path.append(\"..\")" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 23, 19 | "metadata": {}, 20 | "outputs": [ 21 | { 22 | "ename": "ModuleNotFoundError", 23 | "evalue": "No module named 'saxpy'", 24 | "output_type": "error", 25 | "traceback": [ 26 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 27 | "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", 28 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0msaxpy\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpaa\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 29 | "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'saxpy'" 30 | ] 31 | } 32 | ], 33 | "source": [ 34 | "from saxpy import paa" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 24, 40 | "metadata": { 41 | "collapsed": true 42 | }, 43 | "outputs": [], 44 | "source": [ 45 | "import numpy as np\n", 46 | "def paa(series, paa_segments):\n", 47 | " \"\"\"PAA implementation.\"\"\"\n", 48 | " series_len = len(series)\n", 49 | "\n", 50 | " # check for the trivial case\n", 51 | " if (series_len == paa_segments):\n", 52 | " return np.copy(series)\n", 53 | " else:\n", 54 | " res = np.zeros(paa_segments)\n", 55 | " if (series_len % paa_segments == 0):\n", 56 | " inc = series_len // paa_segments\n", 57 | " for i in range(0, series_len):\n", 58 | " idx = i // inc\n", 59 | " res[idx] = res[idx] + series[i]\n", 60 | " return res / inc\n", 61 | " else:\n", 62 | " for i in range(0, paa_segments * series_len):\n", 63 | " idx = i // series_len\n", 64 | " pos = i // paa_segments\n", 65 | " res[idx] = res[idx] + series[pos]\n", 66 | " return res / series_len" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 11, 72 | "metadata": { 73 | "collapsed": true 74 | }, 75 | "outputs": [], 76 | "source": [ 77 | "ts = np.array([1, 1, 2, 2, 3, 3])" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 12, 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "data": { 87 | "text/plain": [ 88 | "array([1, 1, 2, 2, 3, 3])" 89 | ] 90 | }, 91 | "execution_count": 12, 92 | "metadata": {}, 93 | "output_type": "execute_result" 94 | } 95 | ], 96 | "source": [ 97 | "paa(ts, 6)" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 13, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/plain": [ 108 | "array([ 1., 2., 3.])" 109 | ] 110 | }, 111 | "execution_count": 13, 112 | "metadata": {}, 113 | "output_type": "execute_result" 114 | } 115 | ], 116 | "source": [ 117 | "paa(ts, 3)" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 20, 123 | "metadata": {}, 124 | "outputs": [ 125 | { 126 | "data": { 127 | "text/plain": [ 128 | "array([ 1. , 1.33333333, 1.66666667, 2.33333333, 2.66666667, 3. ])" 129 | ] 130 | }, 131 | "execution_count": 20, 132 | "metadata": {}, 133 | "output_type": "execute_result" 134 | } 135 | ], 136 | "source": [ 137 | "paa(paa(ts, 4), 6)" 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": 25, 143 | "metadata": {}, 144 | "outputs": [ 145 | { 146 | "data": { 147 | "text/plain": [ 148 | "array([-0.94054407, -0.69562387, 1.1463276 , 1.638693 , 0.90645757,\n", 149 | " 0.48984043, -0.16033437, -0.16033437, -1.00114287, -1.22333867])" 150 | ] 151 | }, 152 | "execution_count": 25, 153 | "metadata": {}, 154 | "output_type": "execute_result" 155 | } 156 | ], 157 | "source": [ 158 | "dat = np.array([-0.9796808, -0.8622706, -0.6123005, 0.8496459, 1.739691,\n", 159 | " 1.588194, 1.095829, 0.5277147, 0.4709033, -0.2865819,\n", 160 | " 0.0921607, -0.2865819, -0.9039323, -1.195564, -1.237226])\n", 161 | "\n", 162 | "paa(dat, 10)" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": 26, 168 | "metadata": {}, 169 | "outputs": [ 170 | { 171 | "data": { 172 | "text/plain": [ 173 | "array([ -3.33333332e-08, -3.33333333e-08, 4.00000000e-07,\n", 174 | " -4.44089210e-16, -2.66666667e-07, -3.33333331e-08,\n", 175 | " -3.33333333e-08, -3.33333333e-08, -1.33333333e-07,\n", 176 | " -3.33333333e-07])" 177 | ] 178 | }, 179 | "execution_count": 26, 180 | "metadata": {}, 181 | "output_type": "execute_result" 182 | } 183 | ], 184 | "source": [ 185 | "dat_paa = np.array([-0.9405441, -0.6956239, 1.146328, 1.638693, 0.9064573,\n", 186 | " 0.4898404, -0.1603344, -0.1603344, -1.001143,\n", 187 | " -1.223339])\n", 188 | "dat_paa - paa(dat, 10)" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 8, 194 | "metadata": {}, 195 | "outputs": [], 196 | "source": [ 197 | "import numpy as np\n", 198 | "def cuts_for_asize(a_size):\n", 199 | " \"\"\"Generate a set of alphabet cuts for its size.\"\"\"\n", 200 | " options = {\n", 201 | " 2: np.array([-np.inf, 0.00]),\n", 202 | " 3: np.array([-np.inf, -0.4307273, 0.4307273]),\n", 203 | " 4: np.array([-np.inf, -0.6744898, 0, 0.6744898]),\n", 204 | " 5: np.array([-np.inf, -0.841621233572914, -0.2533471031358,\n", 205 | " 0.2533471031358, 0.841621233572914]),\n", 206 | " 6: np.array([-np.inf, -0.967421566101701, -0.430727299295457, 0,\n", 207 | " 0.430727299295457, 0.967421566101701]),\n", 208 | " 7: np.array([-np.inf, -1.06757052387814, -0.565948821932863,\n", 209 | " -0.180012369792705, 0.180012369792705, 0.565948821932863,\n", 210 | " 1.06757052387814]),\n", 211 | " 8: np.array([-np.inf, -1.15034938037601, -0.674489750196082,\n", 212 | " -0.318639363964375, 0, 0.318639363964375,\n", 213 | " 0.674489750196082, 1.15034938037601]),\n", 214 | " 9: np.array([-np.inf, -1.22064034884735, -0.764709673786387,\n", 215 | " -0.430727299295457, -0.139710298881862, 0.139710298881862,\n", 216 | " 0.430727299295457, 0.764709673786387, 1.22064034884735]),\n", 217 | " 10: np.array([-np.inf, -1.2815515655446, -0.841621233572914,\n", 218 | " -0.524400512708041, -0.2533471031358, 0, 0.2533471031358,\n", 219 | " 0.524400512708041, 0.841621233572914, 1.2815515655446]),\n", 220 | " 11: np.array([-np.inf, -1.33517773611894, -0.908457868537385,\n", 221 | " -0.604585346583237, -0.348755695517045,\n", 222 | " -0.114185294321428, 0.114185294321428, 0.348755695517045,\n", 223 | " 0.604585346583237, 0.908457868537385, 1.33517773611894]),\n", 224 | " 12: np.array([-np.inf, -1.38299412710064, -0.967421566101701,\n", 225 | " -0.674489750196082, -0.430727299295457,\n", 226 | " -0.210428394247925, 0, 0.210428394247925,\n", 227 | " 0.430727299295457, 0.674489750196082, 0.967421566101701,\n", 228 | " 1.38299412710064]),\n", 229 | " 13: np.array([-np.inf, -1.42607687227285, -1.0200762327862,\n", 230 | " -0.736315917376129, -0.502402223373355,\n", 231 | " -0.293381232121193, -0.0965586152896391,\n", 232 | " 0.0965586152896394, 0.293381232121194, 0.502402223373355,\n", 233 | " 0.73631591737613, 1.0200762327862, 1.42607687227285]),\n", 234 | " 14: np.array([-np.inf, -1.46523379268552, -1.06757052387814,\n", 235 | " -0.791638607743375, -0.565948821932863, -0.36610635680057,\n", 236 | " -0.180012369792705, 0, 0.180012369792705,\n", 237 | " 0.36610635680057, 0.565948821932863, 0.791638607743375,\n", 238 | " 1.06757052387814, 1.46523379268552]),\n", 239 | " 15: np.array([-np.inf, -1.50108594604402, -1.11077161663679,\n", 240 | " -0.841621233572914, -0.622925723210088,\n", 241 | " -0.430727299295457, -0.2533471031358, -0.0836517339071291,\n", 242 | " 0.0836517339071291, 0.2533471031358, 0.430727299295457,\n", 243 | " 0.622925723210088, 0.841621233572914, 1.11077161663679,\n", 244 | " 1.50108594604402]),\n", 245 | " 16: np.array([-np.inf, -1.53412054435255, -1.15034938037601,\n", 246 | " -0.887146559018876, -0.674489750196082,\n", 247 | " -0.488776411114669, -0.318639363964375,\n", 248 | " -0.157310684610171, 0, 0.157310684610171,\n", 249 | " 0.318639363964375, 0.488776411114669, 0.674489750196082,\n", 250 | " 0.887146559018876, 1.15034938037601, 1.53412054435255]),\n", 251 | " 17: np.array([-np.inf, -1.5647264713618, -1.18683143275582,\n", 252 | " -0.928899491647271, -0.721522283982343,\n", 253 | " -0.541395085129088, -0.377391943828554,\n", 254 | " -0.223007830940367, -0.0737912738082727,\n", 255 | " 0.0737912738082727, 0.223007830940367, 0.377391943828554,\n", 256 | " 0.541395085129088, 0.721522283982343, 0.928899491647271,\n", 257 | " 1.18683143275582, 1.5647264713618]),\n", 258 | " 18: np.array([-np.inf, -1.59321881802305, -1.22064034884735,\n", 259 | " -0.967421566101701, -0.764709673786387,\n", 260 | " -0.589455797849779, -0.430727299295457,\n", 261 | " -0.282216147062508, -0.139710298881862, 0,\n", 262 | " 0.139710298881862, 0.282216147062508, 0.430727299295457,\n", 263 | " 0.589455797849779, 0.764709673786387, 0.967421566101701,\n", 264 | " 1.22064034884735, 1.59321881802305]),\n", 265 | " 19: np.array([-np.inf, -1.61985625863827, -1.25211952026522,\n", 266 | " -1.00314796766253, -0.8045963803603, -0.633640000779701,\n", 267 | " -0.47950565333095, -0.336038140371823, -0.199201324789267,\n", 268 | " -0.0660118123758407, 0.0660118123758406,\n", 269 | " 0.199201324789267, 0.336038140371823, 0.47950565333095,\n", 270 | " 0.633640000779701, 0.8045963803603, 1.00314796766253,\n", 271 | " 1.25211952026522, 1.61985625863827]),\n", 272 | " 20: np.array([-np.inf, -1.64485362695147, -1.2815515655446,\n", 273 | " -1.03643338949379, -0.841621233572914, -0.674489750196082,\n", 274 | " -0.524400512708041, -0.385320466407568, -0.2533471031358,\n", 275 | " -0.125661346855074, 0, 0.125661346855074, 0.2533471031358,\n", 276 | " 0.385320466407568, 0.524400512708041, 0.674489750196082,\n", 277 | " 0.841621233572914, 1.03643338949379, 1.2815515655446,\n", 278 | " 1.64485362695147]),\n", 279 | " }\n", 280 | " \n", 281 | " return options[a_size]" 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": 9, 287 | "metadata": {}, 288 | "outputs": [ 289 | { 290 | "data": { 291 | "text/plain": [ 292 | "array([ -inf, -0.4307273, 0.4307273])" 293 | ] 294 | }, 295 | "execution_count": 9, 296 | "metadata": {}, 297 | "output_type": "execute_result" 298 | } 299 | ], 300 | "source": [ 301 | "cuts_for_asize(3)" 302 | ] 303 | }, 304 | { 305 | "cell_type": "code", 306 | "execution_count": null, 307 | "metadata": { 308 | "collapsed": true 309 | }, 310 | "outputs": [], 311 | "source": [] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": null, 316 | "metadata": { 317 | "collapsed": true 318 | }, 319 | "outputs": [], 320 | "source": [] 321 | }, 322 | { 323 | "cell_type": "code", 324 | "execution_count": 8, 325 | "metadata": {}, 326 | "outputs": [ 327 | { 328 | "data": { 329 | "text/plain": [ 330 | "'/home/psenin/git/saxpy/jupyter'" 331 | ] 332 | }, 333 | "execution_count": 8, 334 | "metadata": {}, 335 | "output_type": "execute_result" 336 | } 337 | ], 338 | "source": [ 339 | "os.getcwd()" 340 | ] 341 | }, 342 | { 343 | "cell_type": "code", 344 | "execution_count": 2, 345 | "metadata": {}, 346 | "outputs": [ 347 | { 348 | "data": { 349 | "text/plain": [ 350 | "['',\n", 351 | " '/home/psenin/anaconda3/lib/python36.zip',\n", 352 | " '/home/psenin/anaconda3/lib/python3.6',\n", 353 | " '/home/psenin/anaconda3/lib/python3.6/lib-dynload',\n", 354 | " '/home/psenin/anaconda3/lib/python3.6/site-packages',\n", 355 | " '/home/psenin/anaconda3/lib/python3.6/site-packages/IPython/extensions',\n", 356 | " '/home/psenin/.ipython',\n", 357 | " '..']" 358 | ] 359 | }, 360 | "execution_count": 2, 361 | "metadata": {}, 362 | "output_type": "execute_result" 363 | } 364 | ], 365 | "source": [ 366 | "sys.path" 367 | ] 368 | } 369 | ], 370 | "metadata": { 371 | "kernelspec": { 372 | "display_name": "Python 2", 373 | "language": "python", 374 | "name": "python2" 375 | }, 376 | "language_info": { 377 | "codemirror_mode": { 378 | "name": "ipython", 379 | "version": 2 380 | }, 381 | "file_extension": ".py", 382 | "mimetype": "text/x-python", 383 | "name": "python", 384 | "nbconvert_exporter": "python", 385 | "pygments_lexer": "ipython2", 386 | "version": "2.7.12" 387 | } 388 | }, 389 | "nbformat": 4, 390 | "nbformat_minor": 2 391 | } 392 | -------------------------------------------------------------------------------- /jupyter/.ipynb_checkpoints/paa-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import os\n", 12 | "import sys\n", 13 | "sys.path.append(\"..\")" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": 23, 19 | "metadata": {}, 20 | "outputs": [ 21 | { 22 | "ename": "ModuleNotFoundError", 23 | "evalue": "No module named 'saxpy'", 24 | "output_type": "error", 25 | "traceback": [ 26 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 27 | "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", 28 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0msaxpy\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpaa\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 29 | "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'saxpy'" 30 | ] 31 | } 32 | ], 33 | "source": [ 34 | "from saxpy import paa" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 24, 40 | "metadata": { 41 | "collapsed": true 42 | }, 43 | "outputs": [], 44 | "source": [ 45 | "import numpy as np\n", 46 | "def paa(series, paa_segments):\n", 47 | " \"\"\"PAA implementation.\"\"\"\n", 48 | " series_len = len(series)\n", 49 | "\n", 50 | " # check for the trivial case\n", 51 | " if (series_len == paa_segments):\n", 52 | " return np.copy(series)\n", 53 | " else:\n", 54 | " res = np.zeros(paa_segments)\n", 55 | " if (series_len % paa_segments == 0):\n", 56 | " inc = series_len // paa_segments\n", 57 | " for i in range(0, series_len):\n", 58 | " idx = i // inc\n", 59 | " res[idx] = res[idx] + series[i]\n", 60 | " return res / inc\n", 61 | " else:\n", 62 | " for i in range(0, paa_segments * series_len):\n", 63 | " idx = i // series_len\n", 64 | " pos = i // paa_segments\n", 65 | " res[idx] = res[idx] + series[pos]\n", 66 | " return res / series_len" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 11, 72 | "metadata": { 73 | "collapsed": true 74 | }, 75 | "outputs": [], 76 | "source": [ 77 | "ts = np.array([1, 1, 2, 2, 3, 3])" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 12, 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "data": { 87 | "text/plain": [ 88 | "array([1, 1, 2, 2, 3, 3])" 89 | ] 90 | }, 91 | "execution_count": 12, 92 | "metadata": {}, 93 | "output_type": "execute_result" 94 | } 95 | ], 96 | "source": [ 97 | "paa(ts, 6)" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 13, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/plain": [ 108 | "array([ 1., 2., 3.])" 109 | ] 110 | }, 111 | "execution_count": 13, 112 | "metadata": {}, 113 | "output_type": "execute_result" 114 | } 115 | ], 116 | "source": [ 117 | "paa(ts, 3)" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 20, 123 | "metadata": {}, 124 | "outputs": [ 125 | { 126 | "data": { 127 | "text/plain": [ 128 | "array([ 1. , 1.33333333, 1.66666667, 2.33333333, 2.66666667, 3. ])" 129 | ] 130 | }, 131 | "execution_count": 20, 132 | "metadata": {}, 133 | "output_type": "execute_result" 134 | } 135 | ], 136 | "source": [ 137 | "paa(paa(ts, 4), 6)" 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": 25, 143 | "metadata": {}, 144 | "outputs": [ 145 | { 146 | "data": { 147 | "text/plain": [ 148 | "array([-0.94054407, -0.69562387, 1.1463276 , 1.638693 , 0.90645757,\n", 149 | " 0.48984043, -0.16033437, -0.16033437, -1.00114287, -1.22333867])" 150 | ] 151 | }, 152 | "execution_count": 25, 153 | "metadata": {}, 154 | "output_type": "execute_result" 155 | } 156 | ], 157 | "source": [ 158 | "dat = np.array([-0.9796808, -0.8622706, -0.6123005, 0.8496459, 1.739691,\n", 159 | " 1.588194, 1.095829, 0.5277147, 0.4709033, -0.2865819,\n", 160 | " 0.0921607, -0.2865819, -0.9039323, -1.195564, -1.237226])\n", 161 | "\n", 162 | "paa(dat, 10)" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": 26, 168 | "metadata": {}, 169 | "outputs": [ 170 | { 171 | "data": { 172 | "text/plain": [ 173 | "array([ -3.33333332e-08, -3.33333333e-08, 4.00000000e-07,\n", 174 | " -4.44089210e-16, -2.66666667e-07, -3.33333331e-08,\n", 175 | " -3.33333333e-08, -3.33333333e-08, -1.33333333e-07,\n", 176 | " -3.33333333e-07])" 177 | ] 178 | }, 179 | "execution_count": 26, 180 | "metadata": {}, 181 | "output_type": "execute_result" 182 | } 183 | ], 184 | "source": [ 185 | "dat_paa = np.array([-0.9405441, -0.6956239, 1.146328, 1.638693, 0.9064573,\n", 186 | " 0.4898404, -0.1603344, -0.1603344, -1.001143,\n", 187 | " -1.223339])\n", 188 | "dat_paa - paa(dat, 10)" 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 7, 194 | "metadata": {}, 195 | "outputs": [], 196 | "source": [ 197 | "import numpy as np\n", 198 | "def cuts_for_asize(a_size):\n", 199 | " \"\"\"Generate a set of alphabet cuts for its size.\"\"\"\n", 200 | " options = {\n", 201 | " 2: np.array([-np.inf, 0.00]),\n", 202 | " 3: np.array([-np.inf, -0.4307273, 0.4307273]),\n", 203 | " 4: np.array([-np.inf, -0.6744898, 0, 0.6744898]),\n", 204 | " 5: np.array([-np.inf, -0.841621233572914, -0.2533471031358,\n", 205 | " 0.2533471031358, 0.841621233572914]),\n", 206 | " 6: np.array([-np.inf, -0.967421566101701, -0.430727299295457, 0,\n", 207 | " 0.430727299295457, 0.967421566101701]),\n", 208 | " 7: np.array([-np.inf, -1.06757052387814, -0.565948821932863,\n", 209 | " -0.180012369792705, 0.180012369792705, 0.565948821932863,\n", 210 | " 1.06757052387814]),\n", 211 | " 8: np.array([-np.inf, -1.15034938037601, -0.674489750196082,\n", 212 | " -0.318639363964375, 0, 0.318639363964375,\n", 213 | " 0.674489750196082, 1.15034938037601]),\n", 214 | " 9: np.array([-np.inf, -1.22064034884735, -0.764709673786387,\n", 215 | " -0.430727299295457, -0.139710298881862, 0.139710298881862,\n", 216 | " 0.430727299295457, 0.764709673786387, 1.22064034884735]),\n", 217 | " 10: np.array([-np.inf, -1.2815515655446, -0.841621233572914,\n", 218 | " -0.524400512708041, -0.2533471031358, 0, 0.2533471031358,\n", 219 | " 0.524400512708041, 0.841621233572914, 1.2815515655446]),\n", 220 | " 11: np.array([-np.inf, -1.33517773611894, -0.908457868537385,\n", 221 | " -0.604585346583237, -0.348755695517045,\n", 222 | " -0.114185294321428, 0.114185294321428, 0.348755695517045,\n", 223 | " 0.604585346583237, 0.908457868537385, 1.33517773611894]),\n", 224 | " 12: np.array([-np.inf, -1.38299412710064, -0.967421566101701,\n", 225 | " -0.674489750196082, -0.430727299295457,\n", 226 | " -0.210428394247925, 0, 0.210428394247925,\n", 227 | " 0.430727299295457, 0.674489750196082, 0.967421566101701,\n", 228 | " 1.38299412710064]),\n", 229 | " 13: np.array([-np.inf, -1.42607687227285, -1.0200762327862,\n", 230 | " -0.736315917376129, -0.502402223373355,\n", 231 | " -0.293381232121193, -0.0965586152896391,\n", 232 | " 0.0965586152896394, 0.293381232121194, 0.502402223373355,\n", 233 | " 0.73631591737613, 1.0200762327862, 1.42607687227285]),\n", 234 | " 14: np.array([-np.inf, -1.46523379268552, -1.06757052387814,\n", 235 | " -0.791638607743375, -0.565948821932863, -0.36610635680057,\n", 236 | " -0.180012369792705, 0, 0.180012369792705,\n", 237 | " 0.36610635680057, 0.565948821932863, 0.791638607743375,\n", 238 | " 1.06757052387814, 1.46523379268552]),\n", 239 | " 15: np.array([-np.inf, -1.50108594604402, -1.11077161663679,\n", 240 | " -0.841621233572914, -0.622925723210088,\n", 241 | " -0.430727299295457, -0.2533471031358, -0.0836517339071291,\n", 242 | " 0.0836517339071291, 0.2533471031358, 0.430727299295457,\n", 243 | " 0.622925723210088, 0.841621233572914, 1.11077161663679,\n", 244 | " 1.50108594604402]),\n", 245 | " 16: np.array([-np.inf, -1.53412054435255, -1.15034938037601,\n", 246 | " -0.887146559018876, -0.674489750196082,\n", 247 | " -0.488776411114669, -0.318639363964375,\n", 248 | " -0.157310684610171, 0, 0.157310684610171,\n", 249 | " 0.318639363964375, 0.488776411114669, 0.674489750196082,\n", 250 | " 0.887146559018876, 1.15034938037601, 1.53412054435255]),\n", 251 | " 17: np.array([-np.inf, -1.5647264713618, -1.18683143275582,\n", 252 | " -0.928899491647271, -0.721522283982343,\n", 253 | " -0.541395085129088, -0.377391943828554,\n", 254 | " -0.223007830940367, -0.0737912738082727,\n", 255 | " 0.0737912738082727, 0.223007830940367, 0.377391943828554,\n", 256 | " 0.541395085129088, 0.721522283982343, 0.928899491647271,\n", 257 | " 1.18683143275582, 1.5647264713618]),\n", 258 | " 18: np.array([-np.inf, -1.59321881802305, -1.22064034884735,\n", 259 | " -0.967421566101701, -0.764709673786387,\n", 260 | " -0.589455797849779, -0.430727299295457,\n", 261 | " -0.282216147062508, -0.139710298881862, 0,\n", 262 | " 0.139710298881862, 0.282216147062508, 0.430727299295457,\n", 263 | " 0.589455797849779, 0.764709673786387, 0.967421566101701,\n", 264 | " 1.22064034884735, 1.59321881802305]),\n", 265 | " 19: np.array([-np.inf, -1.61985625863827, -1.25211952026522,\n", 266 | " -1.00314796766253, -0.8045963803603, -0.633640000779701,\n", 267 | " -0.47950565333095, -0.336038140371823, -0.199201324789267,\n", 268 | " -0.0660118123758407, 0.0660118123758406,\n", 269 | " 0.199201324789267, 0.336038140371823, 0.47950565333095,\n", 270 | " 0.633640000779701, 0.8045963803603, 1.00314796766253,\n", 271 | " 1.25211952026522, 1.61985625863827]),\n", 272 | " 20: np.array([-np.inf, -1.64485362695147, -1.2815515655446,\n", 273 | " -1.03643338949379, -0.841621233572914, -0.674489750196082,\n", 274 | " -0.524400512708041, -0.385320466407568, -0.2533471031358,\n", 275 | " -0.125661346855074, 0, 0.125661346855074, 0.2533471031358,\n", 276 | " 0.385320466407568, 0.524400512708041, 0.674489750196082,\n", 277 | " 0.841621233572914, 1.03643338949379, 1.2815515655446,\n", 278 | " 1.64485362695147]),\n", 279 | " }\n", 280 | " \n", 281 | " return options[a_size]" 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": 5, 287 | "metadata": {}, 288 | "outputs": [ 289 | { 290 | "ename": "TypeError", 291 | "evalue": "'numpy.ndarray' object is not callable", 292 | "output_type": "error", 293 | "traceback": [ 294 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 295 | "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", 296 | "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mcuts_for_asize\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 297 | "\u001b[0;32m\u001b[0m in \u001b[0;36mcuts_for_asize\u001b[0;34m(a_size)\u001b[0m\n\u001b[1;32m 83\u001b[0m }\n\u001b[1;32m 84\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 85\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0moptions\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0ma_size\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", 298 | "\u001b[0;31mTypeError\u001b[0m: 'numpy.ndarray' object is not callable" 299 | ] 300 | } 301 | ], 302 | "source": [ 303 | "cuts_for_asize(3)" 304 | ] 305 | }, 306 | { 307 | "cell_type": "code", 308 | "execution_count": null, 309 | "metadata": { 310 | "collapsed": true 311 | }, 312 | "outputs": [], 313 | "source": [] 314 | }, 315 | { 316 | "cell_type": "code", 317 | "execution_count": null, 318 | "metadata": { 319 | "collapsed": true 320 | }, 321 | "outputs": [], 322 | "source": [] 323 | }, 324 | { 325 | "cell_type": "code", 326 | "execution_count": 8, 327 | "metadata": {}, 328 | "outputs": [ 329 | { 330 | "data": { 331 | "text/plain": [ 332 | "'/home/psenin/git/saxpy/jupyter'" 333 | ] 334 | }, 335 | "execution_count": 8, 336 | "metadata": {}, 337 | "output_type": "execute_result" 338 | } 339 | ], 340 | "source": [ 341 | "os.getcwd()" 342 | ] 343 | }, 344 | { 345 | "cell_type": "code", 346 | "execution_count": 2, 347 | "metadata": {}, 348 | "outputs": [ 349 | { 350 | "data": { 351 | "text/plain": [ 352 | "['',\n", 353 | " '/home/psenin/anaconda3/lib/python36.zip',\n", 354 | " '/home/psenin/anaconda3/lib/python3.6',\n", 355 | " '/home/psenin/anaconda3/lib/python3.6/lib-dynload',\n", 356 | " '/home/psenin/anaconda3/lib/python3.6/site-packages',\n", 357 | " '/home/psenin/anaconda3/lib/python3.6/site-packages/IPython/extensions',\n", 358 | " '/home/psenin/.ipython',\n", 359 | " '..']" 360 | ] 361 | }, 362 | "execution_count": 2, 363 | "metadata": {}, 364 | "output_type": "execute_result" 365 | } 366 | ], 367 | "source": [ 368 | "sys.path" 369 | ] 370 | } 371 | ], 372 | "metadata": { 373 | "kernelspec": { 374 | "display_name": "Python 3", 375 | "language": "python", 376 | "name": "python3" 377 | }, 378 | "language_info": { 379 | "codemirror_mode": { 380 | "name": "ipython", 381 | "version": 3 382 | }, 383 | "file_extension": ".py", 384 | "mimetype": "text/x-python", 385 | "name": "python", 386 | "nbconvert_exporter": "python", 387 | "pygments_lexer": "ipython3", 388 | "version": "3.6.3" 389 | } 390 | }, 391 | "nbformat": 4, 392 | "nbformat_minor": 2 393 | } 394 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /data/ecg0606_1.csv: -------------------------------------------------------------------------------- 1 | -6.095 2 | -6.095 3 | -6.1 4 | -6.1 5 | -6.095 6 | -6.095 7 | -6.1 8 | -6.105 9 | -6.105 10 | -6.115 11 | -6.105 12 | -6.1 13 | -6.095 14 | -6.09 15 | -6.08 16 | -6.075 17 | -6.065 18 | -6.06 19 | -6.035 20 | -6.015 21 | -6 22 | -5.975 23 | -5.955 24 | -5.92 25 | -5.89 26 | -5.865 27 | -5.83 28 | -5.805 29 | -5.775 30 | -5.75 31 | -5.725 32 | -5.705 33 | -5.695 34 | -5.68 35 | -5.67 36 | -5.655 37 | -5.64 38 | -5.635 39 | -5.635 40 | -5.64 41 | -5.64 42 | -5.64 43 | -5.65 44 | -5.66 45 | -5.68 46 | -5.7 47 | -5.71 48 | -5.71 49 | -5.715 50 | -5.72 51 | -5.73 52 | -5.735 53 | -5.74 54 | -5.77 55 | -5.78 56 | -5.775 57 | -5.78 58 | -5.79 59 | -5.785 60 | -5.79 61 | -5.8 62 | -5.81 63 | -5.815 64 | -5.8 65 | -5.805 66 | -5.815 67 | -5.82 68 | -5.82 69 | -5.82 70 | -5.825 71 | -5.82 72 | -5.83 73 | -5.83 74 | -5.82 75 | -5.81 76 | -5.815 77 | -5.82 78 | -5.82 79 | -5.815 80 | -5.815 81 | -5.8 82 | -5.79 83 | -5.78 84 | -5.77 85 | -5.76 86 | -5.755 87 | -5.76 88 | -5.765 89 | -5.76 90 | -5.76 91 | -5.75 92 | -5.74 93 | -5.72 94 | -5.7 95 | -5.69 96 | -5.695 97 | -5.7 98 | -5.695 99 | -5.7 100 | -5.71 101 | -5.71 102 | -5.72 103 | -5.735 104 | -5.755 105 | -5.775 106 | -5.79 107 | -5.8 108 | -5.825 109 | -5.84 110 | -5.845 111 | -5.85 112 | -5.86 113 | -5.875 114 | -5.865 115 | -5.86 116 | -5.855 117 | -5.84 118 | -5.84 119 | -5.84 120 | -5.84 121 | -5.835 122 | -5.855 123 | -5.855 124 | -5.815 125 | -5.695 126 | -5.555 127 | -5.345 128 | -5.015 129 | -4.62 130 | -4.265 131 | -4.055 132 | -3.985 133 | -4 134 | -4.175 135 | -4.455 136 | -4.87 137 | -5.32 138 | -5.775 139 | -6.1 140 | -6.245 141 | -6.245 142 | -6.245 143 | -6.245 144 | -6.245 145 | -6.21 146 | -6.155 147 | -6.105 148 | -6.07 149 | -6.065 150 | -6.06 151 | -6.045 152 | -6.02 153 | -6.01 154 | -6.005 155 | -6.015 156 | -6.015 157 | -6.01 158 | -6.01 159 | -6.01 160 | -6.01 161 | -6 162 | -5.985 163 | -5.98 164 | -5.975 165 | -5.96 166 | -5.96 167 | -5.94 168 | -5.905 169 | -5.875 170 | -5.865 171 | -5.825 172 | -5.77 173 | -5.73 174 | -5.69 175 | -5.655 176 | -5.62 177 | -5.61 178 | -5.585 179 | -5.57 180 | -5.55 181 | -5.52 182 | -5.485 183 | -5.465 184 | -5.46 185 | -5.465 186 | -5.48 187 | -5.5 188 | -5.52 189 | -5.53 190 | -5.55 191 | -5.565 192 | -5.575 193 | -5.595 194 | -5.61 195 | -5.635 196 | -5.66 197 | -5.695 198 | -5.72 199 | -5.725 200 | -5.75 201 | -5.76 202 | -5.775 203 | -5.785 204 | -5.8 205 | -5.8 206 | -5.81 207 | -5.81 208 | -5.825 209 | -5.845 210 | -5.865 211 | -5.87 212 | -5.86 213 | -5.87 214 | -5.865 215 | -5.875 216 | -5.87 217 | -5.875 218 | -5.88 219 | -5.87 220 | -5.86 221 | -5.85 222 | -5.845 223 | -5.84 224 | -5.83 225 | -5.82 226 | -5.81 227 | -5.81 228 | -5.805 229 | -5.805 230 | -5.8 231 | -5.8 232 | -5.795 233 | -5.785 234 | -5.76 235 | -5.75 236 | -5.75 237 | -5.745 238 | -5.755 239 | -5.755 240 | -5.74 241 | -5.72 242 | -5.705 243 | -5.69 244 | -5.69 245 | -5.7 246 | -5.715 247 | -5.715 248 | -5.715 249 | -5.72 250 | -5.74 251 | -5.76 252 | -5.78 253 | -5.795 254 | -5.815 255 | -5.835 256 | -5.86 257 | -5.89 258 | -5.89 259 | -5.88 260 | -5.885 261 | -5.885 262 | -5.89 263 | -5.895 264 | -5.885 265 | -5.885 266 | -5.88 267 | -5.875 268 | -5.87 269 | -5.88 270 | -5.895 271 | -5.9 272 | -5.855 273 | -5.735 274 | -5.595 275 | -5.4 276 | -5.105 277 | -4.71 278 | -4.34 279 | -4.105 280 | -4.01 281 | -4.02 282 | -4.2 283 | -4.505 284 | -4.935 285 | -5.395 286 | -5.84 287 | -6.15 288 | -6.25 289 | -6.24 290 | -6.24 291 | -6.235 292 | -6.215 293 | -6.17 294 | -6.12 295 | -6.085 296 | -6.075 297 | -6.065 298 | -6.06 299 | -6.055 300 | -6.055 301 | -6.055 302 | -6.05 303 | -6.045 304 | -6.035 305 | -6.03 306 | -6.025 307 | -6.015 308 | -6.015 309 | -6.005 310 | -6 311 | -5.99 312 | -5.99 313 | -5.97 314 | -5.955 315 | -5.94 316 | -5.915 317 | -5.885 318 | -5.865 319 | -5.84 320 | -5.8 321 | -5.765 322 | -5.725 323 | -5.68 324 | -5.635 325 | -5.615 326 | -5.58 327 | -5.56 328 | -5.545 329 | -5.52 330 | -5.515 331 | -5.505 332 | -5.51 333 | -5.505 334 | -5.5 335 | -5.51 336 | -5.52 337 | -5.54 338 | -5.55 339 | -5.565 340 | -5.58 341 | -5.6 342 | -5.62 343 | -5.64 344 | -5.665 345 | -5.69 346 | -5.71 347 | -5.725 348 | -5.74 349 | -5.755 350 | -5.765 351 | -5.775 352 | -5.78 353 | -5.79 354 | -5.8 355 | -5.81 356 | -5.815 357 | -5.81 358 | -5.815 359 | -5.82 360 | -5.835 361 | -5.835 362 | -5.835 363 | -5.835 364 | -5.835 365 | -5.83 366 | -5.825 367 | -5.82 368 | -5.81 369 | -5.81 370 | -5.805 371 | -5.805 372 | -5.8 373 | -5.795 374 | -5.785 375 | -5.77 376 | -5.76 377 | -5.76 378 | -5.76 379 | -5.745 380 | -5.735 381 | -5.725 382 | -5.715 383 | -5.695 384 | -5.685 385 | -5.68 386 | -5.68 387 | -5.68 388 | -5.68 389 | -5.67 390 | -5.65 391 | -5.63 392 | -5.625 393 | -5.635 394 | -5.635 395 | -5.635 396 | -5.635 397 | -5.64 398 | -5.66 399 | -5.68 400 | -5.7 401 | -5.715 402 | -5.725 403 | -5.74 404 | -5.76 405 | -5.78 406 | -5.795 407 | -5.805 408 | -5.825 409 | -5.845 410 | -5.865 411 | -5.895 412 | -5.92 413 | -5.925 414 | -5.885 415 | -5.805 416 | -5.705 417 | -5.58 418 | -5.425 419 | -5.23 420 | -4.97 421 | -4.65 422 | -4.36 423 | -4.14 424 | -4 425 | -3.94 426 | -3.96 427 | -4.075 428 | -4.34 429 | -4.8 430 | -5.27 431 | -5.64 432 | -5.835 433 | -6.005 434 | -6.13 435 | -6.2 436 | -6.215 437 | -6.165 438 | -6.075 439 | -6.025 440 | -6.005 441 | -6.005 442 | -6.005 443 | -6.005 444 | -6.005 445 | -6.015 446 | -6.015 447 | -6.02 448 | -6.025 449 | -6.035 450 | -6.045 451 | -6.045 452 | -6.05 453 | -6.05 454 | -6.055 455 | -6.06 456 | -6.065 457 | -6.065 458 | -6.07 459 | -6.07 460 | -6.065 461 | -6.065 462 | -6.055 463 | -6.045 464 | -6.035 465 | -6.01 466 | -5.99 467 | -5.965 468 | -5.935 469 | -5.905 470 | -5.88 471 | -5.85 472 | -5.825 473 | -5.795 474 | -5.76 475 | -5.735 476 | -5.7 477 | -5.68 478 | -5.66 479 | -5.64 480 | -5.635 481 | -5.625 482 | -5.625 483 | -5.615 484 | -5.61 485 | -5.615 486 | -5.615 487 | -5.62 488 | -5.615 489 | -5.625 490 | -5.63 491 | -5.635 492 | -5.64 493 | -5.655 494 | -5.66 495 | -5.67 496 | -5.68 497 | -5.69 498 | -5.7 499 | -5.715 500 | -5.72 501 | -5.735 502 | -5.74 503 | -5.75 504 | -5.755 505 | -5.76 506 | -5.765 507 | -5.775 508 | -5.785 509 | -5.795 510 | -5.8 511 | -5.8 512 | -5.8 513 | -5.8 514 | -5.8 515 | -5.8 516 | -5.8 517 | -5.795 518 | -5.795 519 | -5.79 520 | -5.785 521 | -5.785 522 | -5.78 523 | -5.78 524 | -5.77 525 | -5.77 526 | -5.76 527 | -5.755 528 | -5.74 529 | -5.73 530 | -5.72 531 | -5.705 532 | -5.695 533 | -5.69 534 | -5.69 535 | -5.7 536 | -5.69 537 | -5.68 538 | -5.655 539 | -5.635 540 | -5.62 541 | -5.625 542 | -5.63 543 | -5.63 544 | -5.63 545 | -5.635 546 | -5.645 547 | -5.665 548 | -5.685 549 | -5.7 550 | -5.725 551 | -5.75 552 | -5.76 553 | -5.79 554 | -5.805 555 | -5.81 556 | -5.81 557 | -5.815 558 | -5.815 559 | -5.815 560 | -5.81 561 | -5.805 562 | -5.8 563 | -5.8 564 | -5.805 565 | -5.805 566 | -5.805 567 | -5.825 568 | -5.835 569 | -5.785 570 | -5.665 571 | -5.525 572 | -5.36 573 | -5.06 574 | -4.665 575 | -4.3 576 | -4.08 577 | -4 578 | -4.04 579 | -4.24 580 | -4.555 581 | -4.965 582 | -5.44 583 | -5.855 584 | -6.115 585 | -6.19 586 | -6.18 587 | -6.18 588 | -6.17 589 | -6.13 590 | -6.07 591 | -6.015 592 | -5.985 593 | -5.98 594 | -5.975 595 | -5.97 596 | -5.97 597 | -5.96 598 | -5.955 599 | -5.955 600 | -5.96 601 | -5.96 602 | -5.96 603 | -5.96 604 | -5.955 605 | -5.95 606 | -5.945 607 | -5.94 608 | -5.93 609 | -5.915 610 | -5.895 611 | -5.88 612 | -5.855 613 | -5.825 614 | -5.795 615 | -5.76 616 | -5.73 617 | -5.695 618 | -5.66 619 | -5.625 620 | -5.59 621 | -5.56 622 | -5.535 623 | -5.515 624 | -5.495 625 | -5.465 626 | -5.445 627 | -5.43 628 | -5.415 629 | -5.405 630 | -5.4 631 | -5.4 632 | -5.41 633 | -5.425 634 | -5.44 635 | -5.46 636 | -5.475 637 | -5.495 638 | -5.52 639 | -5.55 640 | -5.575 641 | -5.6 642 | -5.62 643 | -5.645 644 | -5.665 645 | -5.685 646 | -5.7 647 | -5.72 648 | -5.735 649 | -5.75 650 | -5.765 651 | -5.775 652 | -5.79 653 | -5.805 654 | -5.815 655 | -5.82 656 | -5.825 657 | -5.83 658 | -5.835 659 | -5.835 660 | -5.835 661 | -5.835 662 | -5.83 663 | -5.82 664 | -5.82 665 | -5.82 666 | -5.815 667 | -5.805 668 | -5.805 669 | -5.8 670 | -5.8 671 | -5.795 672 | -5.79 673 | -5.78 674 | -5.765 675 | -5.75 676 | -5.74 677 | -5.73 678 | -5.725 679 | -5.725 680 | -5.725 681 | -5.71 682 | -5.695 683 | -5.67 684 | -5.645 685 | -5.635 686 | -5.635 687 | -5.645 688 | -5.645 689 | -5.645 690 | -5.65 691 | -5.66 692 | -5.675 693 | -5.69 694 | -5.71 695 | -5.73 696 | -5.755 697 | -5.78 698 | -5.8 699 | -5.82 700 | -5.835 701 | -5.84 702 | -5.85 703 | -5.855 704 | -5.855 705 | -5.86 706 | -5.865 707 | -5.87 708 | -5.87 709 | -5.87 710 | -5.865 711 | -5.86 712 | -5.87 713 | -5.885 714 | -5.89 715 | -5.825 716 | -5.695 717 | -5.555 718 | -5.355 719 | -5.03 720 | -4.63 721 | -4.3 722 | -4.12 723 | -4.08 724 | -4.135 725 | -4.355 726 | -4.665 727 | -5.08 728 | -5.525 729 | -5.93 730 | -6.2 731 | -6.3 732 | -6.285 733 | -6.28 734 | -6.28 735 | -6.255 736 | -6.19 737 | -6.12 738 | -6.065 739 | -6.045 740 | -6.04 741 | -6.035 742 | -6.03 743 | -6.025 744 | -6.025 745 | -6.03 746 | -6.03 747 | -6.025 748 | -6.02 749 | -6.02 750 | -6.02 751 | -6.015 752 | -6.015 753 | -6 754 | -5.995 755 | -5.98 756 | -5.965 757 | -5.945 758 | -5.93 759 | -5.91 760 | -5.88 761 | -5.85 762 | -5.82 763 | -5.795 764 | -5.755 765 | -5.72 766 | -5.685 767 | -5.66 768 | -5.625 769 | -5.6 770 | -5.58 771 | -5.565 772 | -5.55 773 | -5.54 774 | -5.535 775 | -5.53 776 | -5.53 777 | -5.53 778 | -5.54 779 | -5.555 780 | -5.57 781 | -5.58 782 | -5.6 783 | -5.625 784 | -5.64 785 | -5.66 786 | -5.67 787 | -5.69 788 | -5.715 789 | -5.73 790 | -5.75 791 | -5.77 792 | -5.785 793 | -5.8 794 | -5.815 795 | -5.825 796 | -5.835 797 | -5.84 798 | -5.85 799 | -5.855 800 | -5.865 801 | -5.875 802 | -5.88 803 | -5.885 804 | -5.89 805 | -5.885 806 | -5.88 807 | -5.895 808 | -5.895 809 | -5.905 810 | -5.915 811 | -5.915 812 | -5.9 813 | -5.89 814 | -5.88 815 | -5.875 816 | -5.87 817 | -5.865 818 | -5.86 819 | -5.85 820 | -5.84 821 | -5.83 822 | -5.82 823 | -5.805 824 | -5.8 825 | -5.795 826 | -5.79 827 | -5.795 828 | -5.8 829 | -5.79 830 | -5.77 831 | -5.745 832 | -5.73 833 | -5.73 834 | -5.73 835 | -5.72 836 | -5.73 837 | -5.735 838 | -5.74 839 | -5.755 840 | -5.775 841 | -5.785 842 | -5.8 843 | -5.825 844 | -5.845 845 | -5.865 846 | -5.88 847 | -5.89 848 | -5.89 849 | -5.895 850 | -5.905 851 | -5.9 852 | -5.895 853 | -5.895 854 | -5.895 855 | -5.9 856 | -5.905 857 | -5.91 858 | -5.91 859 | -5.92 860 | -5.955 861 | -5.945 862 | -5.865 863 | -5.73 864 | -5.575 865 | -5.34 866 | -4.99 867 | -4.6 868 | -4.29 869 | -4.14 870 | -4.1 871 | -4.17 872 | -4.39 873 | -4.73 874 | -5.17 875 | -5.635 876 | -6.015 877 | -6.25 878 | -6.31 879 | -6.3 880 | -6.3 881 | -6.3 882 | -6.27 883 | -6.22 884 | -6.165 885 | -6.12 886 | -6.105 887 | -6.11 888 | -6.105 889 | -6.095 890 | -6.07 891 | -6.055 892 | -6.05 893 | -6.045 894 | -6.04 895 | -6.03 896 | -6.025 897 | -6.02 898 | -6.02 899 | -6.01 900 | -6 901 | -6 902 | -5.985 903 | -5.97 904 | -5.945 905 | -5.92 906 | -5.895 907 | -5.87 908 | -5.84 909 | -5.81 910 | -5.78 911 | -5.745 912 | -5.715 913 | -5.695 914 | -5.67 915 | -5.64 916 | -5.62 917 | -5.59 918 | -5.575 919 | -5.56 920 | -5.555 921 | -5.545 922 | -5.535 923 | -5.54 924 | -5.545 925 | -5.54 926 | -5.555 927 | -5.57 928 | -5.6 929 | -5.615 930 | -5.63 931 | -5.65 932 | -5.665 933 | -5.685 934 | -5.715 935 | -5.735 936 | -5.755 937 | -5.78 938 | -5.805 939 | -5.82 940 | -5.83 941 | -5.825 942 | -5.825 943 | -5.835 944 | -5.845 945 | -5.855 946 | -5.87 947 | -5.88 948 | -5.885 949 | -5.89 950 | -5.895 951 | -5.885 952 | -5.87 953 | -5.87 954 | -5.87 955 | -5.87 956 | -5.875 957 | -5.875 958 | -5.87 959 | -5.86 960 | -5.85 961 | -5.84 962 | -5.84 963 | -5.845 964 | -5.85 965 | -5.835 966 | -5.825 967 | -5.815 968 | -5.805 969 | -5.795 970 | -5.785 971 | -5.78 972 | -5.785 973 | -5.78 974 | -5.76 975 | -5.72 976 | -5.7 977 | -5.695 978 | -5.71 979 | -5.71 980 | -5.71 981 | -5.715 982 | -5.74 983 | -5.755 984 | -5.77 985 | -5.79 986 | -5.815 987 | -5.835 988 | -5.845 989 | -5.88 990 | -5.89 991 | -5.905 992 | -5.92 993 | -5.91 994 | -5.905 995 | -5.895 996 | -5.9 997 | -5.9 998 | -5.9 999 | -5.9 1000 | -5.9 1001 | -5.89 1002 | -5.885 1003 | -5.89 1004 | -5.91 1005 | -5.915 1006 | -5.865 1007 | -5.745 1008 | -5.6 1009 | -5.395 1010 | -5.075 1011 | -4.67 1012 | -4.325 1013 | -4.135 1014 | -4.075 1015 | -4.125 1016 | -4.335 1017 | -4.68 1018 | -5.12 1019 | -5.58 1020 | -5.98 1021 | -6.24 1022 | -6.3 1023 | -6.29 1024 | -6.295 1025 | -6.28 1026 | -6.26 1027 | -6.2 1028 | -6.145 1029 | -6.105 1030 | -6.09 1031 | -6.085 1032 | -6.085 1033 | -6.085 1034 | -6.095 1035 | -6.095 1036 | -6.095 1037 | -6.085 1038 | -6.08 1039 | -6.07 1040 | -6.065 1041 | -6.07 1042 | -6.065 1043 | -6.05 1044 | -6.035 1045 | -6.015 1046 | -6.005 1047 | -5.99 1048 | -5.97 1049 | -5.945 1050 | -5.92 1051 | -5.88 1052 | -5.845 1053 | -5.805 1054 | -5.77 1055 | -5.735 1056 | -5.71 1057 | -5.7 1058 | -5.675 1059 | -5.64 1060 | -5.61 1061 | -5.59 1062 | -5.58 1063 | -5.58 1064 | -5.575 1065 | -5.565 1066 | -5.56 1067 | -5.56 1068 | -5.565 1069 | -5.58 1070 | -5.595 1071 | -5.615 1072 | -5.63 1073 | -5.64 1074 | -5.66 1075 | -5.68 1076 | -5.7 1077 | -5.715 1078 | -5.725 1079 | -5.755 1080 | -5.78 1081 | -5.805 1082 | -5.815 1083 | -5.815 1084 | -5.825 1085 | -5.84 1086 | -5.85 1087 | -5.875 1088 | -5.88 1089 | -5.885 1090 | -5.905 1091 | -5.9 1092 | -5.9 1093 | -5.895 1094 | -5.895 1095 | -5.91 1096 | -5.905 1097 | -5.9 1098 | -5.905 1099 | -5.905 1100 | -5.89 1101 | -5.88 1102 | -5.88 1103 | -5.875 1104 | -5.86 1105 | -5.865 1106 | -5.865 1107 | -5.865 1108 | -5.855 1109 | -5.84 1110 | -5.83 1111 | -5.805 1112 | -5.8 1113 | -5.785 1114 | -5.775 1115 | -5.775 1116 | -5.78 1117 | -5.78 1118 | -5.755 1119 | -5.74 1120 | -5.715 1121 | -5.71 1122 | -5.72 1123 | -5.715 1124 | -5.72 1125 | -5.73 1126 | -5.74 1127 | -5.755 1128 | -5.775 1129 | -5.79 1130 | -5.8 1131 | -5.81 1132 | -5.835 1133 | -5.85 1134 | -5.88 1135 | -5.89 1136 | -5.89 1137 | -5.89 1138 | -5.9 1139 | -5.905 1140 | -5.9 1141 | -5.905 1142 | -5.92 1143 | -5.915 1144 | -5.9 1145 | -5.89 1146 | -5.89 1147 | -5.895 1148 | -5.91 1149 | -5.905 1150 | -5.855 1151 | -5.705 1152 | -5.565 1153 | -5.335 1154 | -4.985 1155 | -4.595 1156 | -4.25 1157 | -4.07 1158 | -4.01 1159 | -4.08 1160 | -4.3 1161 | -4.64 1162 | -5.08 1163 | -5.55 1164 | -5.955 1165 | -6.2 1166 | -6.25 1167 | -6.24 1168 | -6.245 1169 | -6.24 1170 | -6.21 1171 | -6.175 1172 | -6.135 1173 | -6.11 1174 | -6.09 1175 | -6.09 1176 | -6.07 1177 | -6.065 1178 | -6.065 1179 | -6.07 1180 | -6.06 1181 | -6.05 1182 | -6.055 1183 | -6.05 1184 | -6.045 1185 | -6.035 1186 | -6.025 1187 | -6.025 1188 | -6.03 1189 | -6.03 1190 | -6.02 1191 | -6 1192 | -5.98 1193 | -5.96 1194 | -5.935 1195 | -5.905 1196 | -5.88 1197 | -5.845 1198 | -5.815 1199 | -5.78 1200 | -5.75 1201 | -5.715 1202 | -5.675 1203 | -5.635 1204 | -5.61 1205 | -5.585 1206 | -5.565 1207 | -5.55 1208 | -5.535 1209 | -5.525 1210 | -5.525 1211 | -5.525 1212 | -5.535 1213 | -5.555 1214 | -5.565 1215 | -5.575 1216 | -5.59 1217 | -5.605 1218 | -5.625 1219 | -5.64 1220 | -5.67 1221 | -5.695 1222 | -5.72 1223 | -5.74 1224 | -5.755 1225 | -5.77 1226 | -5.775 1227 | -5.785 1228 | -5.8 1229 | -5.81 1230 | -5.82 1231 | -5.82 1232 | -5.825 1233 | -5.84 1234 | -5.85 1235 | -5.86 1236 | -5.86 1237 | -5.865 1238 | -5.87 1239 | -5.875 1240 | -5.88 1241 | -5.88 1242 | -5.88 1243 | -5.87 1244 | -5.87 1245 | -5.875 1246 | -5.875 1247 | -5.87 1248 | -5.865 1249 | -5.855 1250 | -5.845 1251 | -5.84 1252 | -5.825 1253 | -5.82 1254 | -5.81 1255 | -5.805 1256 | -5.785 1257 | -5.77 1258 | -5.76 1259 | -5.74 1260 | -5.74 1261 | -5.74 1262 | -5.735 1263 | -5.73 1264 | -5.72 1265 | -5.7 1266 | -5.68 1267 | -5.67 1268 | -5.67 1269 | -5.675 1270 | -5.675 1271 | -5.67 1272 | -5.685 1273 | -5.695 1274 | -5.71 1275 | -5.73 1276 | -5.75 1277 | -5.77 1278 | -5.785 1279 | -5.815 1280 | -5.84 1281 | -5.86 1282 | -5.86 1283 | -5.85 1284 | -5.855 1285 | -5.86 1286 | -5.86 1287 | -5.87 1288 | -5.875 1289 | -5.865 1290 | -5.86 1291 | -5.86 1292 | -5.85 1293 | -5.85 1294 | -5.87 1295 | -5.885 1296 | -5.865 1297 | -5.775 1298 | -5.64 1299 | -5.48 1300 | -5.215 1301 | -4.825 1302 | -4.425 1303 | -4.13 1304 | -3.985 1305 | -3.955 1306 | -4.065 1307 | -4.315 1308 | -4.68 1309 | -5.14 1310 | -5.6 1311 | -5.975 1312 | -6.19 1313 | -6.215 1314 | -6.2 1315 | -6.2 1316 | -6.19 1317 | -6.155 1318 | -6.1 1319 | -6.045 1320 | -6.03 1321 | -6.025 1322 | -6.02 1323 | -6.015 1324 | -6.015 1325 | -6.015 1326 | -6.015 1327 | -6.01 1328 | -6 1329 | -5.995 1330 | -5.99 1331 | -5.99 1332 | -5.99 1333 | -5.99 1334 | -5.98 1335 | -5.975 1336 | -5.965 1337 | -5.955 1338 | -5.935 1339 | -5.92 1340 | -5.9 1341 | -5.88 1342 | -5.86 1343 | -5.82 1344 | -5.79 1345 | -5.765 1346 | -5.73 1347 | -5.695 1348 | -5.66 1349 | -5.625 1350 | -5.6 1351 | -5.58 1352 | -5.56 1353 | -5.535 1354 | -5.51 1355 | -5.49 1356 | -5.48 1357 | -5.47 1358 | -5.47 1359 | -5.465 1360 | -5.465 1361 | -5.48 1362 | -5.49 1363 | -5.505 1364 | -5.52 1365 | -5.53 1366 | -5.55 1367 | -5.575 1368 | -5.6 1369 | -5.625 1370 | -5.65 1371 | -5.67 1372 | -5.69 1373 | -5.71 1374 | -5.715 1375 | -5.735 1376 | -5.745 1377 | -5.76 1378 | -5.765 1379 | -5.78 1380 | -5.79 1381 | -5.785 1382 | -5.795 1383 | -5.8 1384 | -5.8 1385 | -5.81 1386 | -5.815 1387 | -5.815 1388 | -5.81 1389 | -5.805 1390 | -5.81 1391 | -5.82 1392 | -5.82 1393 | -5.82 1394 | -5.815 1395 | -5.81 1396 | -5.81 1397 | -5.805 1398 | -5.8 1399 | -5.8 1400 | -5.795 1401 | -5.79 1402 | -5.785 1403 | -5.78 1404 | -5.77 1405 | -5.76 1406 | -5.745 1407 | -5.73 1408 | -5.71 1409 | -5.71 1410 | -5.7 1411 | -5.7 1412 | -5.7 1413 | -5.695 1414 | -5.68 1415 | -5.655 1416 | -5.64 1417 | -5.635 1418 | -5.64 1419 | -5.645 1420 | -5.65 1421 | -5.655 1422 | -5.655 1423 | -5.665 1424 | -5.68 1425 | -5.7 1426 | -5.72 1427 | -5.735 1428 | -5.76 1429 | -5.775 1430 | -5.8 1431 | -5.82 1432 | -5.825 1433 | -5.83 1434 | -5.83 1435 | -5.83 1436 | -5.83 1437 | -5.835 1438 | -5.84 1439 | -5.84 1440 | -5.835 1441 | -5.83 1442 | -5.825 1443 | -5.83 1444 | -5.84 1445 | -5.865 1446 | -5.845 1447 | -5.76 1448 | -5.62 1449 | -5.46 1450 | -5.215 1451 | -4.845 1452 | -4.445 1453 | -4.15 1454 | -4.005 1455 | -3.98 1456 | -4.08 1457 | -4.31 1458 | -4.675 1459 | -5.11 1460 | -5.57 1461 | -5.955 1462 | -6.165 1463 | -6.2 1464 | -6.19 1465 | -6.185 1466 | -6.18 1467 | -6.14 1468 | -6.09 1469 | -6.04 1470 | -6.01 1471 | -6.01 1472 | -6.005 1473 | -6 1474 | -6 1475 | -6 1476 | -5.995 1477 | -5.99 1478 | -5.995 1479 | -6 1480 | -6 1481 | -5.995 1482 | -5.99 1483 | -5.98 1484 | -5.97 1485 | -5.965 1486 | -5.96 1487 | -5.955 1488 | -5.94 1489 | -5.92 1490 | -5.9 1491 | -5.88 1492 | -5.86 1493 | -5.835 1494 | -5.8 1495 | -5.76 1496 | -5.735 1497 | -5.7 1498 | -5.67 1499 | -5.64 1500 | -5.61 1501 | -5.585 1502 | -5.56 1503 | -5.54 1504 | -5.52 1505 | -5.51 1506 | -5.485 1507 | -5.475 1508 | -5.465 1509 | -5.465 1510 | -5.47 1511 | -5.475 1512 | -5.49 1513 | -5.505 1514 | -5.525 1515 | -5.545 1516 | -5.565 1517 | -5.59 1518 | -5.61 1519 | -5.635 1520 | -5.65 1521 | -5.675 1522 | -5.695 1523 | -5.71 1524 | -5.73 1525 | -5.745 1526 | -5.76 1527 | -5.775 1528 | -5.785 1529 | -5.8 1530 | -5.81 1531 | -5.81 1532 | -5.82 1533 | -5.825 1534 | -5.825 1535 | -5.83 1536 | -5.84 1537 | -5.84 1538 | -5.835 1539 | -5.835 1540 | -5.835 1541 | -5.835 1542 | -5.83 1543 | -5.825 1544 | -5.825 1545 | -5.815 1546 | -5.815 1547 | -5.815 1548 | -5.81 1549 | -5.805 1550 | -5.8 1551 | -5.79 1552 | -5.785 1553 | -5.785 1554 | -5.78 1555 | -5.775 1556 | -5.76 1557 | -5.745 1558 | -5.72 1559 | -5.71 1560 | -5.7 1561 | -5.7 1562 | -5.705 1563 | -5.7 1564 | -5.685 1565 | -5.66 1566 | -5.64 1567 | -5.635 1568 | -5.64 1569 | -5.64 1570 | -5.645 1571 | -5.655 1572 | -5.66 1573 | -5.68 1574 | -5.695 1575 | -5.705 1576 | -5.725 1577 | -5.75 1578 | -5.77 1579 | -5.795 1580 | -5.82 1581 | -5.84 1582 | -5.84 1583 | -5.84 1584 | -5.84 1585 | -5.84 1586 | -5.84 1587 | -5.84 1588 | -5.84 1589 | -5.84 1590 | -5.835 1591 | -5.835 1592 | -5.83 1593 | -5.835 1594 | -5.85 1595 | -5.86 1596 | -5.825 1597 | -5.72 1598 | -5.58 1599 | -5.42 1600 | -5.15 1601 | -4.76 1602 | -4.37 1603 | -4.115 1604 | -4.01 1605 | -4.01 1606 | -4.17 1607 | -4.45 1608 | -4.84 1609 | -5.29 1610 | -5.74 1611 | -6.055 1612 | -6.2 1613 | -6.195 1614 | -6.195 1615 | -6.19 1616 | -6.165 1617 | -6.115 1618 | -6.055 1619 | -6.01 1620 | -6 1621 | -5.995 1622 | -5.99 1623 | -5.99 1624 | -5.99 1625 | -5.985 1626 | -5.985 1627 | -5.98 1628 | -5.975 1629 | -5.97 1630 | -5.965 1631 | -5.965 1632 | -5.965 1633 | -5.955 1634 | -5.945 1635 | -5.935 1636 | -5.925 1637 | -5.91 1638 | -5.89 1639 | -5.875 1640 | -5.855 1641 | -5.835 1642 | -5.81 1643 | -5.785 1644 | -5.75 1645 | -5.715 1646 | -5.68 1647 | -5.65 1648 | -5.62 1649 | -5.59 1650 | -5.56 1651 | -5.535 1652 | -5.51 1653 | -5.49 1654 | -5.48 1655 | -5.47 1656 | -5.465 1657 | -5.455 1658 | -5.45 1659 | -5.45 1660 | -5.46 1661 | -5.47 1662 | -5.485 1663 | -5.5 1664 | -5.52 1665 | -5.54 1666 | -5.565 1667 | -5.585 1668 | -5.61 1669 | -5.635 1670 | -5.66 1671 | -5.68 1672 | -5.705 1673 | -5.72 1674 | -5.745 1675 | -5.76 1676 | -5.77 1677 | -5.78 1678 | -5.79 1679 | -5.8 1680 | -5.805 1681 | -5.82 1682 | -5.82 1683 | -5.83 1684 | -5.835 1685 | -5.84 1686 | -5.84 1687 | -5.84 1688 | -5.84 1689 | -5.84 1690 | -5.845 1691 | -5.845 1692 | -5.84 1693 | -5.84 1694 | -5.84 1695 | -5.84 1696 | -5.84 1697 | -5.835 1698 | -5.83 1699 | -5.83 1700 | -5.82 1701 | -5.82 1702 | -5.815 1703 | -5.805 1704 | -5.8 1705 | -5.78 1706 | -5.765 1707 | -5.76 1708 | -5.75 1709 | -5.74 1710 | -5.74 1711 | -5.74 1712 | -5.725 1713 | -5.71 1714 | -5.685 1715 | -5.67 1716 | -5.67 1717 | -5.68 1718 | -5.68 1719 | -5.68 1720 | -5.685 1721 | -5.69 1722 | -5.7 1723 | -5.72 1724 | -5.735 1725 | -5.75 1726 | -5.775 1727 | -5.8 1728 | -5.82 1729 | -5.84 1730 | -5.85 1731 | -5.86 1732 | -5.865 1733 | -5.875 1734 | -5.88 1735 | -5.88 1736 | -5.88 1737 | -5.875 1738 | -5.875 1739 | -5.87 1740 | -5.87 1741 | -5.87 1742 | -5.875 1743 | -5.895 1744 | -5.89 1745 | -5.815 1746 | -5.69 1747 | -5.555 1748 | -5.35 1749 | -5.015 1750 | -4.615 1751 | -4.265 1752 | -4.075 1753 | -4.025 1754 | -4.105 1755 | -4.345 1756 | -4.68 1757 | -5.115 1758 | -5.575 1759 | -5.97 1760 | -6.205 1761 | -6.265 1762 | -6.255 1763 | -6.245 1764 | -6.235 1765 | -6.195 1766 | -6.13 1767 | -6.075 1768 | -6.04 1769 | -6.04 1770 | -6.035 1771 | -6.025 1772 | -6.02 1773 | -6.01 1774 | -6.005 1775 | -6 1776 | -6 1777 | -5.995 1778 | -5.99 1779 | -5.985 1780 | -5.98 1781 | -5.98 1782 | -5.98 1783 | -5.975 1784 | -5.965 1785 | -5.96 1786 | -5.945 1787 | -5.925 1788 | -5.905 1789 | -5.875 1790 | -5.845 1791 | -5.815 1792 | -5.78 1793 | -5.75 1794 | -5.72 1795 | -5.68 1796 | -5.655 1797 | -5.625 1798 | -5.6 1799 | -5.58 1800 | -5.555 1801 | -5.54 1802 | -5.52 1803 | -5.505 1804 | -5.495 1805 | -5.485 1806 | -5.48 1807 | -5.48 1808 | -5.49 1809 | -5.5 1810 | -5.515 1811 | -5.525 1812 | -5.54 1813 | -5.555 1814 | -5.575 1815 | -5.595 1816 | -5.62 1817 | -5.645 1818 | -5.67 1819 | -5.69 1820 | -5.705 1821 | -5.725 1822 | -5.745 1823 | -5.76 1824 | -5.775 1825 | -5.79 1826 | -5.8 1827 | -5.81 1828 | -5.815 1829 | -5.825 1830 | -5.83 1831 | -5.835 1832 | -5.84 1833 | -5.84 1834 | -5.845 1835 | -5.86 1836 | -5.86 1837 | -5.86 1838 | -5.865 1839 | -5.865 1840 | -5.865 1841 | -5.86 1842 | -5.85 1843 | -5.845 1844 | -5.84 1845 | -5.84 1846 | -5.835 1847 | -5.825 1848 | -5.82 1849 | -5.815 1850 | -5.8 1851 | -5.795 1852 | -5.77 1853 | -5.76 1854 | -5.76 1855 | -5.75 1856 | -5.755 1857 | -5.75 1858 | -5.745 1859 | -5.735 1860 | -5.71 1861 | -5.69 1862 | -5.685 1863 | -5.69 1864 | -5.685 1865 | -5.68 1866 | -5.675 1867 | -5.685 1868 | -5.695 1869 | -5.715 1870 | -5.73 1871 | -5.745 1872 | -5.765 1873 | -5.79 1874 | -5.81 1875 | -5.835 1876 | -5.85 1877 | -5.86 1878 | -5.86 1879 | -5.86 1880 | -5.87 1881 | -5.875 1882 | -5.875 1883 | -5.875 1884 | -5.87 1885 | -5.87 1886 | -5.87 1887 | -5.875 1888 | -5.88 1889 | -5.89 1890 | -5.915 1891 | -5.905 1892 | -5.825 1893 | -5.69 1894 | -5.55 1895 | -5.33 1896 | -4.98 1897 | -4.575 1898 | -4.245 1899 | -4.07 1900 | -4.025 1901 | -4.135 1902 | -4.385 1903 | -4.74 1904 | -5.165 1905 | -5.615 1906 | -6 1907 | -6.23 1908 | -6.28 1909 | -6.275 1910 | -6.265 1911 | -6.27 1912 | -6.235 1913 | -6.18 1914 | -6.12 1915 | -6.08 1916 | -6.07 1917 | -6.06 1918 | -6.04 1919 | -6.03 1920 | -6.02 1921 | -6.01 1922 | -6.005 1923 | -6 1924 | -5.995 1925 | -6 1926 | -6 1927 | -5.99 1928 | -5.985 1929 | -5.985 1930 | -5.97 1931 | -5.96 1932 | -5.945 1933 | -5.935 1934 | -5.92 1935 | -5.895 1936 | -5.875 1937 | -5.85 1938 | -5.82 1939 | -5.795 1940 | -5.76 1941 | -5.73 1942 | -5.705 1943 | -5.67 1944 | -5.645 1945 | -5.61 1946 | -5.585 1947 | -5.565 1948 | -5.55 1949 | -5.535 1950 | -5.52 1951 | -5.52 1952 | -5.52 1953 | -5.515 1954 | -5.52 1955 | -5.52 1956 | -5.53 1957 | -5.54 1958 | -5.55 1959 | -5.565 1960 | -5.58 1961 | -5.6 1962 | -5.62 1963 | -5.64 1964 | -5.67 1965 | -5.69 1966 | -5.71 1967 | -5.735 1968 | -5.755 1969 | -5.77 1970 | -5.78 1971 | -5.79 1972 | -5.795 1973 | -5.805 1974 | -5.815 1975 | -5.82 1976 | -5.83 1977 | -5.835 1978 | -5.84 1979 | -5.85 1980 | -5.85 1981 | -5.855 1982 | -5.855 1983 | -5.86 1984 | -5.86 1985 | -5.86 1986 | -5.86 1987 | -5.86 1988 | -5.855 1989 | -5.855 1990 | -5.85 1991 | -5.85 1992 | -5.85 1993 | -5.85 1994 | -5.85 1995 | -5.845 1996 | -5.83 1997 | -5.82 1998 | -5.8 1999 | -5.795 2000 | -5.785 2001 | -5.785 2002 | -5.785 2003 | -5.77 2004 | -5.75 2005 | -5.725 2006 | -5.705 2007 | -5.7 2008 | -5.705 2009 | -5.715 2010 | -5.72 2011 | -5.715 2012 | -5.73 2013 | -5.74 2014 | -5.76 2015 | -5.775 2016 | -5.79 2017 | -5.805 2018 | -5.83 2019 | -5.85 2020 | -5.87 2021 | -5.89 2022 | -5.895 2023 | -5.885 2024 | -5.88 2025 | -5.88 2026 | -5.88 2027 | -5.88 2028 | -5.88 2029 | -5.88 2030 | -5.88 2031 | -5.88 2032 | -5.875 2033 | -5.875 2034 | -5.89 2035 | -5.91 2036 | -5.895 2037 | -5.8 2038 | -5.67 2039 | -5.525 2040 | -5.28 2041 | -4.905 2042 | -4.51 2043 | -4.22 2044 | -4.085 2045 | -4.075 2046 | -4.23 2047 | -4.5 2048 | -4.88 2049 | -5.315 2050 | -5.76 2051 | -6.09 2052 | -6.28 2053 | -6.295 2054 | -6.28 2055 | -6.28 2056 | -6.265 2057 | -6.215 2058 | -6.155 2059 | -6.095 2060 | -6.065 2061 | -6.065 2062 | -6.06 2063 | -6.055 2064 | -6.05 2065 | -6.04 2066 | -6.035 2067 | -6.035 2068 | -6.035 2069 | -6.025 2070 | -6.02 2071 | -6.02 2072 | -6.01 2073 | -5.995 2074 | -5.99 2075 | -5.975 2076 | -5.955 2077 | -5.93 2078 | -5.92 2079 | -5.91 2080 | -5.895 2081 | -5.88 2082 | -5.84 2083 | -5.8 2084 | -5.765 2085 | -5.735 2086 | -5.705 2087 | -5.67 2088 | -5.64 2089 | -5.61 2090 | -5.58 2091 | -5.56 2092 | -5.54 2093 | -5.52 2094 | -5.515 2095 | -5.5 2096 | -5.495 2097 | -5.49 2098 | -5.495 2099 | -5.5 2100 | -5.515 2101 | -5.525 2102 | -5.54 2103 | -5.555 2104 | -5.57 2105 | -5.585 2106 | -5.605 2107 | -5.625 2108 | -5.645 2109 | -5.665 2110 | -5.685 2111 | -5.705 2112 | -5.725 2113 | -5.745 2114 | -5.76 2115 | -5.775 2116 | -5.79 2117 | -5.8 2118 | -5.815 2119 | -5.825 2120 | -5.83 2121 | -5.84 2122 | -5.84 2123 | -5.845 2124 | -5.85 2125 | -5.85 2126 | -5.85 2127 | -5.845 2128 | -5.84 2129 | -5.835 2130 | -5.83 2131 | -5.825 2132 | -5.82 2133 | -5.815 2134 | -5.805 2135 | -5.805 2136 | -5.8 2137 | -5.79 2138 | -5.78 2139 | -5.76 2140 | -5.745 2141 | -5.74 2142 | -5.735 2143 | -5.74 2144 | -5.74 2145 | -5.735 2146 | -5.72 2147 | -5.695 2148 | -5.68 2149 | -5.665 2150 | -5.67 2151 | -5.68 2152 | -5.685 2153 | -5.68 2154 | -5.69 2155 | -5.705 2156 | -5.72 2157 | -5.74 2158 | -5.76 2159 | -5.765 2160 | -5.795 2161 | -5.81 2162 | -5.84 2163 | -5.86 2164 | -5.87 2165 | -5.875 2166 | -5.875 2167 | -5.875 2168 | -5.88 2169 | -5.885 2170 | -5.885 2171 | -5.875 2172 | -5.87 2173 | -5.875 2174 | -5.89 2175 | -5.875 2176 | -5.89 2177 | -5.91 2178 | -5.89 2179 | -5.795 2180 | -5.66 2181 | -5.52 2182 | -5.315 2183 | -4.98 2184 | -4.585 2185 | -4.255 2186 | -4.08 2187 | -4.04 2188 | -4.14 2189 | -4.385 2190 | -4.73 2191 | -5.16 2192 | -5.615 2193 | -5.995 2194 | -6.22 2195 | -6.27 2196 | -6.255 2197 | -6.25 2198 | -6.245 2199 | -6.205 2200 | -6.15 2201 | -6.09 2202 | -6.055 2203 | -6.055 2204 | -6.055 2205 | -6.045 2206 | -6.04 2207 | -6.025 2208 | -6.02 2209 | -6.01 2210 | -6 2211 | -5.995 2212 | -5.985 2213 | -5.985 2214 | -5.975 2215 | -5.965 2216 | -5.96 2217 | -5.95 2218 | -5.935 2219 | -5.93 2220 | -5.91 2221 | -5.895 2222 | -5.88 2223 | -5.86 2224 | -5.83 2225 | -5.8 2226 | -5.775 2227 | -5.745 2228 | -5.71 2229 | -5.68 2230 | -5.655 2231 | -5.625 2232 | -5.59 2233 | -5.56 2234 | -5.54 2235 | -5.525 2236 | -5.51 2237 | -5.5 2238 | -5.485 2239 | -5.49 2240 | -5.49 2241 | -5.49 2242 | -5.495 2243 | -5.51 2244 | -5.525 2245 | -5.54 2246 | -5.555 2247 | -5.57 2248 | -5.59 2249 | -5.605 2250 | -5.625 2251 | -5.65 2252 | -5.67 2253 | -5.695 2254 | -5.72 2255 | -5.74 2256 | -5.765 2257 | -5.785 2258 | -5.8 2259 | -5.815 2260 | -5.825 2261 | -5.83 2262 | -5.835 2263 | -5.84 2264 | -5.84 2265 | -5.845 2266 | -5.85 2267 | -5.85 2268 | -5.85 2269 | -5.855 2270 | -5.855 2271 | -5.855 2272 | -5.85 2273 | -5.845 2274 | -5.84 2275 | -5.835 2276 | -5.83 2277 | -5.825 2278 | -5.815 2279 | -5.8 2280 | -5.78 2281 | -5.775 2282 | -5.77 2283 | -5.76 2284 | -5.755 2285 | -5.74 2286 | -5.73 2287 | -5.705 2288 | -5.685 2289 | -5.665 2290 | -5.66 2291 | -5.67 2292 | -5.67 2293 | -5.665 2294 | -5.67 2295 | -5.68 2296 | -5.695 2297 | -5.715 2298 | -5.735 2299 | -5.755 2300 | -------------------------------------------------------------------------------- /jupyter/sax.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "text/plain": [ 11 | "'/home/psenin/git/saxpy/jupyter'" 12 | ] 13 | }, 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "output_type": "execute_result" 17 | } 18 | ], 19 | "source": [ 20 | "import os \n", 21 | "os.getcwd()" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 2, 27 | "metadata": { 28 | "collapsed": true 29 | }, 30 | "outputs": [], 31 | "source": [ 32 | "os.chdir(\"/home/psenin/git/saxpy\")\n", 33 | "import numpy as np\n", 34 | "from saxpy.strfunc import idx2letter \n", 35 | "from saxpy.znorm import znorm\n", 36 | "from saxpy.paa import paa\n", 37 | "from saxpy.alphabet import cuts_for_asize\n", 38 | "from saxpy.sax import sax_via_window" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 12, 44 | "metadata": {}, 45 | "outputs": [ 46 | { 47 | "data": { 48 | "text/plain": [ 49 | "defaultdict(list,\n", 50 | " {'aac': [4, 10, 11, 30, 35],\n", 51 | " 'abc': [12, 14, 36, 44],\n", 52 | " 'acb': [5, 16, 21, 37, 43],\n", 53 | " 'acc': [13, 52, 53],\n", 54 | " 'bac': [3, 19, 34, 45, 51],\n", 55 | " 'bba': [31],\n", 56 | " 'bbb': [15, 18, 20, 22, 25, 26, 27, 28, 29, 41, 42, 46],\n", 57 | " 'bbc': [2],\n", 58 | " 'bca': [6, 17, 32, 38, 47, 48],\n", 59 | " 'caa': [8, 23, 24, 40],\n", 60 | " 'cab': [9, 50],\n", 61 | " 'cba': [7, 39, 49],\n", 62 | " 'cbb': [33],\n", 63 | " 'cca': [0, 1]})" 64 | ] 65 | }, 66 | "execution_count": 12, 67 | "metadata": {}, 68 | "output_type": "execute_result" 69 | } 70 | ], 71 | "source": [ 72 | "dat = np.array([0., 0., 0., 0., 0., -0.270340178359072, -0.367828308500142,\n", 73 | " 0.666980581124872, 1.87088147328446, 2.14548907684624,\n", 74 | " -0.480859313143032, -0.72911654245842, -0.490308602315934,\n", 75 | " -0.66152028906509, -0.221049033806403, 0.367003418871239,\n", 76 | " 0.631073992586373, 0.0487728723414486, 0.762655178750436,\n", 77 | " 0.78574757843331, 0.338239686422963, 0.784206454089066,\n", 78 | " -2.14265084073625, 2.11325193044223, 0.186018356196443,\n", 79 | " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.519132472499234,\n", 80 | " -2.604783141655, -0.244519550114012, -1.6570790528784,\n", 81 | " 3.34184602886343, 2.10361226260999, 1.9796808733979,\n", 82 | " -0.822247322003058, 1.06850578033292, -0.678811824405992,\n", 83 | " 0.804225748913681, 0.57363964388698, 0.437113583759113,\n", 84 | " 0.437208643628268, 0.989892093383503, 1.76545983424176,\n", 85 | " 0.119483882364649, -0.222311941138971, -0.74669456611669,\n", 86 | " -0.0663660879732063, 0., 0., 0., 0., 0.,])\n", 87 | "\n", 88 | "sax1 = sax_via_window(dat, 6, 3, 3, \"none\", 0.01)\n", 89 | "\n", 90 | "sax1" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 5, 96 | "metadata": {}, 97 | "outputs": [ 98 | { 99 | "data": { 100 | "text/plain": [ 101 | "array([ -inf, -0.4307273, 0.4307273])" 102 | ] 103 | }, 104 | "execution_count": 5, 105 | "metadata": {}, 106 | "output_type": "execute_result" 107 | } 108 | ], 109 | "source": [ 110 | "from saxpy.znorm import znorm\n", 111 | "from saxpy.alphabet import cuts_for_asize\n", 112 | "cuts_for_asize(3)" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 9, 118 | "metadata": {}, 119 | "outputs": [ 120 | { 121 | "data": { 122 | "text/plain": [ 123 | "'acb'" 124 | ] 125 | }, 126 | "execution_count": 9, 127 | "metadata": {}, 128 | "output_type": "execute_result" 129 | } 130 | ], 131 | "source": [ 132 | "from saxpy.znorm import znorm\n", 133 | "from saxpy.paa import paa\n", 134 | "from saxpy.sax import ts_to_string\n", 135 | "ts_to_string(paa(znorm(np.array([-2, 0, 2, 0, -1])), 3), cuts_for_asize(3))" 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": 11, 141 | "metadata": {}, 142 | "outputs": [ 143 | { 144 | "data": { 145 | "text/plain": [ 146 | "'acb'" 147 | ] 148 | }, 149 | "execution_count": 11, 150 | "metadata": {}, 151 | "output_type": "execute_result" 152 | } 153 | ], 154 | "source": [ 155 | "import numpy as np\n", 156 | "from saxpy.alphabet import cuts_for_asize\n", 157 | "from saxpy.znorm import znorm\n", 158 | "from saxpy.paa import paa\n", 159 | "from saxpy.sax import ts_to_string\n", 160 | "\n", 161 | "dat = np.array([-2, 0, 2, 0, -1])\n", 162 | "dat_znorm = znorm(dat)\n", 163 | "dat_paa_3 = paa(dat_znorm, 3)\n", 164 | "\n", 165 | "ts_to_string(dat_paa_3, cuts_for_asize(3))" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": null, 171 | "metadata": { 172 | "collapsed": true 173 | }, 174 | "outputs": [], 175 | "source": [] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": null, 180 | "metadata": { 181 | "collapsed": true 182 | }, 183 | "outputs": [], 184 | "source": [] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": { 190 | "collapsed": true 191 | }, 192 | "outputs": [], 193 | "source": [] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 4, 198 | "metadata": {}, 199 | "outputs": [ 200 | { 201 | "data": { 202 | "image/png": "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\n", 203 | "text/plain": [ 204 | "" 205 | ] 206 | }, 207 | "metadata": {}, 208 | "output_type": "display_data" 209 | } 210 | ], 211 | "source": [ 212 | "import matplotlib.pyplot as plt\n", 213 | "plt.plot(dat)\n", 214 | "plt.show()" 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "execution_count": 5, 220 | "metadata": {}, 221 | "outputs": [ 222 | { 223 | "data": { 224 | "text/plain": [ 225 | "defaultdict(list,\n", 226 | " {'aac': [4, 10, 11, 30, 35],\n", 227 | " 'abc': [12, 14, 36, 44],\n", 228 | " 'acb': [5, 16, 21, 37, 43],\n", 229 | " 'acc': [13, 52, 53],\n", 230 | " 'bac': [3, 19, 34, 45, 51],\n", 231 | " 'bba': [31],\n", 232 | " 'bbb': [15, 18, 20, 22, 25, 26, 27, 28, 29, 41, 42, 46],\n", 233 | " 'bbc': [2],\n", 234 | " 'bca': [6, 17, 32, 38, 47, 48],\n", 235 | " 'caa': [8, 23, 24, 40],\n", 236 | " 'cab': [9, 50],\n", 237 | " 'cba': [7, 39, 49],\n", 238 | " 'cbb': [33],\n", 239 | " 'cca': [0, 1]})" 240 | ] 241 | }, 242 | "execution_count": 5, 243 | "metadata": {}, 244 | "output_type": "execute_result" 245 | } 246 | ], 247 | "source": [ 248 | "saxpy.ts_to_string()" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": 7, 254 | "metadata": {}, 255 | "outputs": [ 256 | { 257 | "data": { 258 | "text/plain": [ 259 | "[0, 1]" 260 | ] 261 | }, 262 | "execution_count": 7, 263 | "metadata": {}, 264 | "output_type": "execute_result" 265 | } 266 | ], 267 | "source": [ 268 | "sax1['cca']" 269 | ] 270 | }, 271 | { 272 | "cell_type": "code", 273 | "execution_count": 14, 274 | "metadata": {}, 275 | "outputs": [ 276 | { 277 | "data": { 278 | "text/plain": [ 279 | "54" 280 | ] 281 | }, 282 | "execution_count": 14, 283 | "metadata": {}, 284 | "output_type": "execute_result" 285 | } 286 | ], 287 | "source": [ 288 | "elements_num = 0\n", 289 | "for key in sax1:\n", 290 | " elements_num += len(sax1[key])\n", 291 | "elements_num " 292 | ] 293 | }, 294 | { 295 | "cell_type": "code", 296 | "execution_count": 16, 297 | "metadata": {}, 298 | "outputs": [ 299 | { 300 | "data": { 301 | "text/plain": [ 302 | "defaultdict(list,\n", 303 | " {'aac': [4, 10, 30, 35],\n", 304 | " 'abc': [12, 14, 36, 44],\n", 305 | " 'acb': [5, 16, 21, 37, 43],\n", 306 | " 'acc': [13, 52],\n", 307 | " 'bac': [3, 19, 34, 45, 51],\n", 308 | " 'bba': [31],\n", 309 | " 'bbb': [15, 18, 20, 22, 25, 41, 46],\n", 310 | " 'bbc': [2],\n", 311 | " 'bca': [6, 17, 32, 38, 47],\n", 312 | " 'caa': [8, 23, 40],\n", 313 | " 'cab': [9, 50],\n", 314 | " 'cba': [7, 39, 49],\n", 315 | " 'cbb': [33],\n", 316 | " 'cca': [0]})" 317 | ] 318 | }, 319 | "execution_count": 16, 320 | "metadata": {}, 321 | "output_type": "execute_result" 322 | } 323 | ], 324 | "source": [ 325 | "sax_exact = sax_via_window(dat, 6, 3, 3, \"exact\", 0.01)\n", 326 | "sax_exact" 327 | ] 328 | }, 329 | { 330 | "cell_type": "code", 331 | "execution_count": 17, 332 | "metadata": {}, 333 | "outputs": [ 334 | { 335 | "data": { 336 | "text/plain": [ 337 | "defaultdict(list,\n", 338 | " {'aac': [10, 30],\n", 339 | " 'acb': [21, 37, 43],\n", 340 | " 'acc': [13, 52],\n", 341 | " 'bac': [19, 34, 45],\n", 342 | " 'bba': [31],\n", 343 | " 'bbc': [2],\n", 344 | " 'bca': [6, 17, 47],\n", 345 | " 'caa': [8, 23],\n", 346 | " 'cab': [50],\n", 347 | " 'cba': [39],\n", 348 | " 'cca': [0]})" 349 | ] 350 | }, 351 | "execution_count": 17, 352 | "metadata": {}, 353 | "output_type": "execute_result" 354 | } 355 | ], 356 | "source": [ 357 | "sax_mindist = sax_via_window(dat, 6, 3, 3, \"mindist\", 0.01)\n", 358 | "sax_mindist" 359 | ] 360 | } 361 | ], 362 | "metadata": { 363 | "kernelspec": { 364 | "display_name": "Python 2", 365 | "language": "python", 366 | "name": "python2" 367 | }, 368 | "language_info": { 369 | "codemirror_mode": { 370 | "name": "ipython", 371 | "version": 2 372 | }, 373 | "file_extension": ".py", 374 | "mimetype": "text/x-python", 375 | "name": "python", 376 | "nbconvert_exporter": "python", 377 | "pygments_lexer": "ipython2", 378 | "version": "2.7.12" 379 | } 380 | }, 381 | "nbformat": 4, 382 | "nbformat_minor": 2 383 | } 384 | --------------------------------------------------------------------------------