├── tests
├── __init__.py
├── test_doctests.py
└── test_trendypy.py
├── trendypy
├── __init__.py
├── utils.py
├── algos.py
└── trendy.py
├── docs
├── README.md
├── image_data.zip
├── _static
│ ├── trendypy.png
│ └── favicon
│ │ ├── favicon.ico
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── apple-touch-icon.png
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ └── site.webmanifest
├── image_data
│ ├── car-01.gif
│ ├── car-02.gif
│ ├── car-03.gif
│ ├── car-20.gif
│ ├── chopper-01.gif
│ ├── chopper-02.gif
│ ├── chopper-03.gif
│ ├── chopper-08.gif
│ ├── carriage-02.gif
│ ├── carriage-03.gif
│ ├── carriage-04.gif
│ └── carriage-20.gif
├── source
│ ├── algos.rst
│ ├── utils.rst
│ ├── trendy.rst
│ ├── api_reference.rst
│ └── seeinaction.rst
├── requirements.txt
├── index.rst
├── Makefile
├── make.bat
├── conf.py
└── stock_data.csv
├── requirements.txt
├── .github
└── workflows
│ ├── upload_pypi.yml
│ ├── test.yml
│ └── test_coverage.yml
├── LICENSE
├── setup.py
├── .gitignore
└── README.md
/tests/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/trendypy/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ../README.md
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy>=1.20.2
2 | pandas>=1.2.4
3 | fastdtw>=0.3.4
4 |
--------------------------------------------------------------------------------
/docs/image_data.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data.zip
--------------------------------------------------------------------------------
/docs/_static/trendypy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/_static/trendypy.png
--------------------------------------------------------------------------------
/docs/image_data/car-01.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data/car-01.gif
--------------------------------------------------------------------------------
/docs/image_data/car-02.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data/car-02.gif
--------------------------------------------------------------------------------
/docs/image_data/car-03.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data/car-03.gif
--------------------------------------------------------------------------------
/docs/image_data/car-20.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data/car-20.gif
--------------------------------------------------------------------------------
/docs/image_data/chopper-01.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data/chopper-01.gif
--------------------------------------------------------------------------------
/docs/image_data/chopper-02.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data/chopper-02.gif
--------------------------------------------------------------------------------
/docs/image_data/chopper-03.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data/chopper-03.gif
--------------------------------------------------------------------------------
/docs/image_data/chopper-08.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data/chopper-08.gif
--------------------------------------------------------------------------------
/docs/_static/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/_static/favicon/favicon.ico
--------------------------------------------------------------------------------
/docs/image_data/carriage-02.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data/carriage-02.gif
--------------------------------------------------------------------------------
/docs/image_data/carriage-03.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data/carriage-03.gif
--------------------------------------------------------------------------------
/docs/image_data/carriage-04.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data/carriage-04.gif
--------------------------------------------------------------------------------
/docs/image_data/carriage-20.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/image_data/carriage-20.gif
--------------------------------------------------------------------------------
/docs/_static/favicon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/_static/favicon/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/_static/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/_static/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/source/algos.rst:
--------------------------------------------------------------------------------
1 | algos
2 | -----
3 |
4 | .. automodule:: algos
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/source/utils.rst:
--------------------------------------------------------------------------------
1 | utils
2 | -----
3 |
4 | .. automodule:: utils
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/_static/favicon/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/_static/favicon/apple-touch-icon.png
--------------------------------------------------------------------------------
/docs/source/trendy.rst:
--------------------------------------------------------------------------------
1 | trendy
2 | ------
3 |
4 | .. automodule:: trendy
5 | :members:
6 | :undoc-members:
7 | :show-inheritance:
--------------------------------------------------------------------------------
/docs/_static/favicon/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/_static/favicon/android-chrome-192x192.png
--------------------------------------------------------------------------------
/docs/_static/favicon/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ddaskan/trendypy/HEAD/docs/_static/favicon/android-chrome-512x512.png
--------------------------------------------------------------------------------
/docs/source/api_reference.rst:
--------------------------------------------------------------------------------
1 | API Reference
2 | =============
3 | .. toctree::
4 | :maxdepth: 2
5 |
6 | trendy
7 | algos
8 | utils
--------------------------------------------------------------------------------
/docs/requirements.txt:
--------------------------------------------------------------------------------
1 | Jinja2<3.0.0
2 | sphinx==3.0.3
3 | pydata-sphinx-theme==0.3.0
4 | sphinxcontrib-napoleon==0.7
5 | sphinx-copybutton==0.2.12
6 | recommonmark==0.6.0
7 | matplotlib==3.2.2
8 | ipython==7.15.0
9 | Pillow==8.3.1
--------------------------------------------------------------------------------
/docs/_static/favicon/site.webmanifest:
--------------------------------------------------------------------------------
1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
--------------------------------------------------------------------------------
/tests/test_doctests.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import unittest
3 | import doctest
4 | sys.path.append('../')
5 | from trendypy import trendy
6 | from trendypy import algos
7 | from trendypy import utils
8 |
9 | def load_tests(loader, tests, ignore):
10 | tests.addTests(doctest.DocTestSuite(trendy))
11 | tests.addTests(doctest.DocTestSuite(algos))
12 | tests.addTests(doctest.DocTestSuite(utils))
13 | return tests
14 |
15 | if __name__ == '__main__':
16 | unittest.main()
17 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. TrendyPy documentation master file, created by
2 | sphinx-quickstart on Fri Jun 19 23:29:35 2020.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | TrendyPy Documentation
7 | ======================
8 |
9 | .. toctree::
10 | :maxdepth: 2
11 |
12 | README.md
13 | source/seeinaction
14 | source/api_reference
15 |
16 |
17 | Indices and tables
18 | ------------------
19 |
20 | * :ref:`genindex`
21 | * :ref:`modindex`
22 | * :ref:`search`
23 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/docs/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=.
11 | set BUILDDIR=_build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/.github/workflows/upload_pypi.yml:
--------------------------------------------------------------------------------
1 | # This workflows will upload a Python Package using Twine when a release is created
2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
3 |
4 | name: Upload to PyPI
5 |
6 | on:
7 | release:
8 | types: [created]
9 |
10 | jobs:
11 | deploy:
12 |
13 | runs-on: ubuntu-latest
14 |
15 | steps:
16 | - uses: actions/checkout@v2
17 | - name: Set up Python
18 | uses: actions/setup-python@v2
19 | with:
20 | python-version: '3.x'
21 | - name: Install dependencies
22 | run: |
23 | python -m pip install --upgrade pip
24 | pip install setuptools wheel twine
25 | - name: Build and publish
26 | env:
27 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
28 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
29 | run: |
30 | python setup.py sdist bdist_wheel
31 | twine upload dist/*
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020-2021 Dogan Askan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import setuptools
2 |
3 | with open("README.md", "r") as fh:
4 | long_description = fh.read()
5 |
6 | with open('requirements.txt', 'r') as f:
7 | install_requires = f.read().splitlines()
8 |
9 | setuptools.setup(
10 | name="trendypy",
11 | version="0.2.2",
12 | author="Dogan Askan",
13 | author_email="doganaskan@gmail.com",
14 | description="A package for trend line clustering.",
15 | long_description=long_description,
16 | long_description_content_type="text/markdown",
17 | url="https://github.com/ddaskan/trendypy",
18 | download_url="https://pypi.python.org/pypi/trendypy",
19 | project_urls={
20 | "Bug Tracker": "https://github.com/ddaskan/trendypy/issues",
21 | "Documentation": "https://trendypy.readthedocs.io/",
22 | "Source Code": "https://github.com/ddaskan/trendypy",
23 | },
24 | license='MIT',
25 | keywords='ml ai data-analysis machine-learning clustering',
26 | packages=setuptools.find_packages(),
27 | classifiers=[
28 | "Programming Language :: Python :: 3",
29 | "License :: OSI Approved :: MIT License",
30 | "Operating System :: OS Independent",
31 | 'Topic :: Scientific/Engineering',
32 | "Topic :: Scientific/Engineering :: Artificial Intelligence",
33 | "Topic :: Software Development",
34 | ],
35 | python_requires='>=3.7',
36 | install_requires=install_requires,
37 | )
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | # Weekly tests to be sure dependencies are up-to-date
2 |
3 | name: tests
4 |
5 | on:
6 | workflow_dispatch:
7 | schedule:
8 | - cron: '17 10 * * 5'
9 |
10 | jobs:
11 | build:
12 |
13 | runs-on: ${{ matrix.os }}
14 | strategy:
15 | matrix:
16 | os: [macos-latest, ubuntu-latest, windows-latest]
17 | python-version: [3.7, 3.8, 3.9]
18 |
19 | steps:
20 | - uses: actions/checkout@v2
21 | - name: Set up Python ${{ matrix.python-version }}
22 | uses: actions/setup-python@v2
23 | with:
24 | python-version: ${{ matrix.python-version }}
25 | - name: Install dependencies
26 | run: |
27 | python -m pip install --upgrade pip
28 | pip install -r requirements.txt
29 | - name: Test with pytest
30 | run: |
31 | pip install pytest
32 | pip install pytest-cov
33 | python -m doctest README.md
34 | pytest --doctest-modules --junitxml=junit/test-results-${{ matrix.os }}-py${{ matrix.python-version }}.xml --cov=trendypy --cov-report=xml --cov-report=html
35 | - name: Upload pytest test results
36 | uses: actions/upload-artifact@v2
37 | with:
38 | name: pytest-results-${{ matrix.os }}-py${{ matrix.python-version }}
39 | path: junit/test-results-${{ matrix.os }}-py${{ matrix.python-version }}.xml
40 | # Use always() to always run this step to publish test results when there are test failures
41 | if: ${{ always() }}
--------------------------------------------------------------------------------
/trendypy/utils.py:
--------------------------------------------------------------------------------
1 | '''
2 | Utility functions for the package.
3 | '''
4 | import numpy as np
5 |
6 | def scale_01(x):
7 | '''Scales array to 0-1.
8 |
9 | Args:
10 | x (iter): 1d array of float
11 |
12 | Returns:
13 | np.array: scaled 1d array
14 |
15 | Example:
16 | >>> scale_01([1, 2, 3, 5]).tolist()
17 | [0.0, 0.25, 0.5, 1.0]
18 |
19 | '''
20 | arr_min = min(x)
21 | x = np.array(x) - float(arr_min)
22 | arr_max = max(x)
23 | return x / float(arr_max)
24 |
25 | def abs_distance(x, y):
26 | '''Returns absolute distance.
27 |
28 | Args:
29 | x (float): input 1
30 | y (float): input 2
31 |
32 | Returns:
33 | float: \|x-y\|
34 |
35 | Example:
36 | >>> abs_distance(5, 7)
37 | 2.0
38 | >>> abs_distance(4, 1)
39 | 3.0
40 |
41 | '''
42 | return float(abs(x - y))
43 |
44 | def euclidean_distance(x, y):
45 | '''Returns Euclidean distance.
46 |
47 | Args:
48 | x (float or iter): input 1
49 | y (float or iter): input 2
50 |
51 | Returns:
52 | float: Euclidean distance
53 |
54 | References:
55 | https://numpy.org/doc/stable/reference/generated/numpy.linalg.norm.html
56 |
57 | Examples:
58 | >>> x, y = 1, 2
59 | >>> euclidean_distance(x, y)
60 | 1.0
61 | >>> x, y = [1, 2], [4, 6]
62 | >>> euclidean_distance(x, y)
63 | 5.0
64 |
65 | '''
66 | return np.linalg.norm(np.array(x) - np.array(y))
67 |
68 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 | docs/*.png
74 |
75 | # PyBuilder
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | .python-version
87 |
88 | # pipenv
89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
92 | # install all needed dependencies.
93 | #Pipfile.lock
94 |
95 | # celery beat schedule file
96 | celerybeat-schedule
97 |
98 | # SageMath parsed files
99 | *.sage.py
100 |
101 | # Environments
102 | .env
103 | .venv
104 | env/
105 | venv/
106 | ENV/
107 | env.bak/
108 | venv.bak/
109 |
110 | # Spyder project settings
111 | .spyderproject
112 | .spyproject
113 |
114 | # Rope project settings
115 | .ropeproject
116 |
117 | # mkdocs documentation
118 | /site
119 |
120 | # mypy
121 | .mypy_cache/
122 | .dmypy.json
123 | dmypy.json
124 |
125 | # Pyre type checker
126 | .pyre/
127 | Icon?
128 | .DS_Store
129 | trendypy/sandbox_.py
130 |
--------------------------------------------------------------------------------
/.github/workflows/test_coverage.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and create a coverage report.
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3 |
4 | name: tests_and_coverage
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ${{ matrix.os }}
16 | strategy:
17 | matrix:
18 | os: [macos-latest, ubuntu-latest, windows-latest]
19 | python-version: [3.7, 3.8, 3.9]
20 |
21 | steps:
22 | - uses: actions/checkout@v2
23 | - name: Set up Python ${{ matrix.python-version }}
24 | uses: actions/setup-python@v2
25 | with:
26 | python-version: ${{ matrix.python-version }}
27 | - name: Install dependencies
28 | run: |
29 | python -m pip install --upgrade pip
30 | pip install -r requirements.txt
31 | - name: Test with pytest
32 | run: |
33 | pip install pytest
34 | pip install pytest-cov
35 | python -m doctest README.md
36 | pytest --doctest-modules --junitxml=junit/test-results-${{ matrix.os }}-py${{ matrix.python-version }}.xml --cov=trendypy --cov-report=xml --cov-report=html
37 | - name: Upload pytest test results
38 | uses: actions/upload-artifact@v2
39 | with:
40 | name: pytest-results-${{ matrix.os }}-py${{ matrix.python-version }}
41 | path: junit/test-results-${{ matrix.os }}-py${{ matrix.python-version }}.xml
42 | # Use always() to always run this step to publish test results when there are test failures
43 | if: ${{ always() }}
44 | - name: Upload coverage to Codecov
45 | uses: codecov/codecov-action@v1
46 | with:
47 | directory: ./
48 | name: codecov-umbrella
49 | fail_ci_if_error: true
50 | path_to_write_report: ./codecov_report_${{ matrix.os }}_py${{ matrix.python-version }}.gz
51 |
52 | publish-test-results:
53 | name: "Publish Unit Tests Results"
54 | needs: build
55 | runs-on: ubuntu-latest
56 | # the build job might be skipped, we don't need to run this job then
57 | if: success() || failure()
58 |
59 | steps:
60 | - name: Download Artifacts
61 | uses: actions/download-artifact@v2
62 | with:
63 | path: artifacts
64 |
65 | - name: Publish Unit Test Results
66 | uses: EnricoMi/publish-unit-test-result-action@v1
67 | with:
68 | files: artifacts/**/*.xml
69 |
--------------------------------------------------------------------------------
/tests/test_trendypy.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import sys
3 | sys.path.append('../')
4 | sys.path.append('../trendypy/')
5 | from trendypy.trendy import Trendy
6 | from trendypy.algos import levenshtein_distance
7 |
8 | class TestTrendy(unittest.TestCase):
9 |
10 | def test___init__(self):
11 | self.assertRaises(TypeError, Trendy)
12 | self.assertRaises(TypeError, Trendy, *[None])
13 | self.assertRaises(
14 | TypeError,
15 | Trendy,
16 | **{'n_clusters':5, 'algorithm':'error'})
17 | self.assertRaises(ValueError, Trendy, **{'n_clusters':'1'})
18 | self.assertRaises(ValueError, Trendy, **{'n_clusters':1})
19 |
20 | trendy = Trendy(n_clusters=3)
21 | self.assertEqual(trendy.n_clusters, 3)
22 | self.assertTrue(callable(trendy.dist_func))
23 |
24 | test_func = lambda x,y:abs(x-y)
25 | trendy = Trendy(n_clusters=3, algorithm=test_func)
26 | self.assertTrue(callable(trendy.dist_func))
27 | self.assertEqual(
28 | trendy.dist_func.__code__.co_code,
29 | test_func.__code__.co_code)
30 |
31 | def test_fit(self):
32 | a = [0.8, 2, 3, 4, 5]
33 | b = [1, 1.9, 2.5, 4.4, 5.1]
34 | c = [6.2, 4, 4, 2, 0]
35 | d = [7, 6, 5, 4, 3, 2, 1]
36 |
37 | trendy = Trendy(6)
38 | self.assertRaises(ValueError, trendy.fit, *[[a, b, c, d]])
39 |
40 | trendy = Trendy(2)
41 | trendy.fit([a, b, c, d])
42 | self.assertListEqual(trendy.labels_, [0, 0, 1, 1])
43 |
44 | e = [3, 4, 3, 2, 5, 5.5]
45 |
46 | trendy = Trendy(3)
47 | trendy.fit([a, b, c, d, e])
48 | self.assertListEqual(trendy.labels_, [0, 0, 1, 1, 2])
49 |
50 | trendy = Trendy(5)
51 | trendy.fit([a, b, c, d, e])
52 | self.assertListEqual(trendy.labels_, [0, 1, 2, 3, 4])
53 | self.assertListEqual(trendy.cluster_centers_, [a, b, c, d, e])
54 |
55 | def test_predict(self):
56 | a = [0.8, 2, 3, 4, 5]
57 | b = [1, 1.9, 2.5, 4.4, 5.1]
58 | c = [6.2, 4, 4, 2, 0]
59 | d = [7, 6, 5, 4, 3, 2, 1]
60 | trendy = Trendy(2)
61 | trendy.fit([a, b, c, d])
62 |
63 | preds = trendy.predict([[0.9, 2, 2.9, 3.8, 5]])
64 | self.assertEqual(preds, [0])
65 |
66 | preds = trendy.predict([
67 | [0.9, 2, 2.9, 3.8, 5],
68 | [6.4, 4.4, 3.9, 3],
69 | [6, 3.5, 3.9, 3, 1.5]])
70 | self.assertEqual(preds, [0, 1, 1])
71 |
72 | def test_string_clustering(self):
73 | company_names = [
74 | 'apple inc',
75 | 'Apple Inc.',
76 | 'Microsoft Corporation',
77 | 'Microsft Corp.']
78 | trendy = Trendy(n_clusters=2, algorithm=levenshtein_distance)
79 | trendy.fit(company_names)
80 | self.assertEqual(trendy.labels_, [0, 0, 1, 1])
81 | self.assertEqual(trendy.predict(['Apple']), [0])
82 |
83 | if __name__ == '__main__':
84 | unittest.main()
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TrendyPy
2 |
3 |
4 |
5 | [](https://pypi.org/project/trendypy/)
6 | [](https://github.com/ddaskan/trendypy/actions?query=workflow%3Atests)
7 | [](https://codecov.io/gh/ddaskan/trendypy/)
8 | [](https://trendypy.readthedocs.io/en/latest/?badge=latest)
9 | [](https://pepy.tech/project/trendypy)
10 | [](https://github.com/ddaskan/trendypy)
11 | [](https://twitter.com/intent/tweet?text=Wow:&url=https%3A%2F%2Fgithub.com%2Fddaskan%2Ftrendypy)
12 |
13 | TrendyPy is a small Python package for sequence clustering. It is initially developed to create time series clusters by calculating trend similarity distance with [Dynamic Time Warping](https://en.wikipedia.org/wiki/Dynamic_time_warping).
14 |
15 | ## Installation
16 |
17 | You can install TrendyPy with pip.
18 |
19 | ```
20 | pip install trendypy
21 | ```
22 |
23 | TrendyPy depends on Pandas, Numpy and fastdtw and works in Python 3.7+.
24 |
25 | ## Quickstart
26 |
27 | Trendy has scikit-learn like api to allow easy integration to existing programs. Below is a quick example to show how it clusters increasing and decreasing trends.
28 |
29 | ```python
30 | >>> from trendypy.trendy import Trendy
31 | >>> a = [1, 2, 3, 4, 5] # increasing trend
32 | >>> b = [1, 2.1, 2.9, 4.4, 5.1] # increasing trend
33 | >>> c = [6.2, 5, 4, 3, 2] # decreasing trend
34 | >>> d = [7, 6, 5, 4, 3, 2, 1] # decreasing trend
35 | >>> trendy = Trendy(n_clusters=2)
36 | >>> trendy.fit([a, b, c, d])
37 | >>> print(trendy.labels_)
38 | [0, 0, 1, 1]
39 | >>> trendy.predict([[0.9, 2, 3.1, 4]]) # another increasing trend
40 | [0]
41 |
42 | ```
43 |
44 | It can also be utilized to cluster strings by using string similarity metrics.
45 |
46 | ```python
47 | >>> from trendypy.trendy import Trendy
48 | >>> from trendypy.algos import levenshtein_distance
49 | >>> company_names = [
50 | ... 'apple inc',
51 | ... 'Apple Inc.',
52 | ... 'Microsoft Corporation',
53 | ... 'Microsft Corp.']
54 | >>> trendy = Trendy(n_clusters=2, algorithm=levenshtein_distance)
55 | >>> trendy.fit(company_names)
56 | >>> print(trendy.labels_)
57 | [0, 0, 1, 1]
58 | >>> trendy.predict(['Apple'])
59 | [0]
60 |
61 | ```
62 |
63 | Refer to [extensive demo](https://trendypy.readthedocs.io/en/latest/source/seeinaction.html) to see it in clustering [stock trends](https://trendypy.readthedocs.io/en/latest/source/seeinaction.html#stock-data), [images](https://trendypy.readthedocs.io/en/latest/source/seeinaction.html#image-clustering) or to see how to [define your own metric](https://trendypy.readthedocs.io/en/latest/source/seeinaction.html#custom-metric) or just check [API Reference](https://trendypy.readthedocs.io/en/latest/source/api_reference.html) for details.
64 |
65 | ## Post
66 | The idea is originated from the post [Trend Clustering](http://www.doganaskan.com/blog/posts/trendcluster.html).
67 |
--------------------------------------------------------------------------------
/trendypy/algos.py:
--------------------------------------------------------------------------------
1 | '''
2 | Algorithms for the package.
3 | '''
4 | import sys
5 | sys.path.append('../')
6 | import numpy as np
7 | from fastdtw import fastdtw
8 | from trendypy import utils
9 |
10 | def dtw_distance(x, y, d=utils.euclidean_distance, scaled=False):
11 | '''Returns the distance of two arrays with dynamic time warping method.
12 |
13 | Args:
14 | x (iter): input array 1
15 | y (iter): input array 2
16 | d (func): distance function, default is euclidean
17 | scaled (bool): should arrays be scaled (i.e. 0-1) before calculation
18 |
19 | Returns:
20 | float: distance, 0.0 means arrays are exactly same, upper limit is\
21 | positive infinity
22 |
23 | References:
24 | https://en.wikipedia.org/wiki/Dynamic_time_warping
25 |
26 | Examples:
27 | >>> dtw_distance([1, 2, 3, 4], [1, 2, 3, 4])
28 | 0.0
29 | >>> dtw_distance([1, 2, 3, 4], [0, 0, 0])
30 | 10.0
31 | >>> dtw_distance([1, 2, 3, 4], [0, 2, 0, 4])
32 | 4.0
33 | >>> dtw_distance([1, 2, 3, 4], [10, 20, 30, 40])
34 | 90.0
35 | >>> dtw_distance([1, 2, 3, 4], [10, 20, 30, 40], scaled=True)
36 | 0.0
37 |
38 | '''
39 | if scaled:
40 | x = utils.scale_01(x)
41 | y = utils.scale_01(y)
42 | n = len(x) + 1
43 | m = len(y) + 1
44 | DTW = np.zeros((n, m))
45 | DTW[:, 0] = float('Inf')
46 | DTW[0, :] = float('Inf')
47 | DTW[0, 0] = 0
48 |
49 | for i in range(1, n):
50 | for j in range(1, m):
51 | cost = d(x[i-1], y[j-1])
52 | DTW[i, j] = cost + min(DTW[i-1, j], DTW[i, j-1], DTW[i-1, j-1])
53 |
54 | return DTW[n-1, m-1]
55 |
56 | def fastdtw_distance(x, y, d=utils.euclidean_distance):
57 | '''Dynamic Time Warping (DTW) algorithm with an O(N) time and memory
58 | complexity.
59 |
60 | Args:
61 | x (iter): input array 1
62 | y (iter): input array 2
63 | d (func): distance function, default is euclidean
64 |
65 | Returns:
66 | float: distance, 0.0 means arrays are exactly same, upper limit is\
67 | positive infinity
68 |
69 | References:
70 | https://pypi.org/project/fastdtw/
71 |
72 | Examples:
73 | >>> fastdtw_distance([1, 2, 3, 4], [1, 2, 3, 4])
74 | 0.0
75 | >>> fastdtw_distance([1, 2, 3, 4], [0, 0, 0])
76 | 10.0
77 | >>> fastdtw_distance([1, 2, 3, 4], [0, 2, 0, 4])
78 | 4.0
79 | >>> fastdtw_distance([1, 2, 3, 4], [10, 20, 30, 40])
80 | 90.0
81 |
82 | '''
83 | return fastdtw(x, y, dist=d)[0]
84 |
85 | def levenshtein_distance(x, y):
86 | """Levenshtein distance for string similarity.
87 |
88 | Args:
89 | x (str): input string 1
90 | y (str): input string 2
91 |
92 | Returns:
93 | int: distance, 0 means strings are exactly same, upper limit is\
94 | positive infinity
95 |
96 | References:
97 | https://en.wikipedia.org/wiki/Levenshtein_distance
98 |
99 | Examples:
100 | >>> levenshtein_distance('Apple', 'Apple')
101 | 0
102 | >>> levenshtein_distance('Apple', 'apple')
103 | 1
104 | >>> levenshtein_distance('Apple Inc.', 'apple inc')
105 | 3
106 |
107 | """
108 | m, n = len(x), len(y)
109 | v0 = list(range(n + 1))
110 | v1 = [None] * (n + 1)
111 |
112 | for i in range(m):
113 | v1[0] = i + 1
114 |
115 | for j in range(n):
116 | deletion_cost = v0[j + 1] + 1
117 | insertion_cost = v1[j] + 1
118 | if x[i] == y[j]:
119 | substitution_cost = v0[j]
120 | else:
121 | substitution_cost = v0[j] + 1
122 |
123 | v1[j + 1] = min(deletion_cost, insertion_cost, substitution_cost)
124 |
125 | v0, v1 = v1, v0
126 |
127 | return v0[n]
128 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | # Configuration file for the Sphinx documentation builder.
2 | #
3 | # This file only contains a selection of the most common options. For a full
4 | # list see the documentation:
5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html
6 |
7 | # -- Path setup --------------------------------------------------------------
8 |
9 | # If extensions (or modules to document with autodoc) are in another directory,
10 | # add these directories to sys.path here. If the directory is relative to the
11 | # documentation root, use os.path.abspath to make it absolute, like shown here.
12 | #
13 | import os
14 | import sys
15 | import inspect
16 | sys.path.insert(0, os.path.abspath('.'))
17 | sys.path.append('../')
18 | sys.path.append('../trendypy/')
19 |
20 |
21 | # -- Project information -----------------------------------------------------
22 |
23 | project = 'TrendyPy'
24 | copyright = '2020-2021, Dogan Askan'
25 | author = 'Dogan Askan'
26 |
27 | # The full version, including alpha/beta/rc tags
28 | release = '0.2.2'
29 |
30 |
31 | # -- General configuration ---------------------------------------------------
32 |
33 | # Add any Sphinx extension module names here, as strings. They can be
34 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
35 | # ones.
36 | extensions = [
37 | 'sphinx.ext.autodoc',
38 | 'sphinxcontrib.napoleon',
39 | #'sphinx.ext.viewcode',
40 | 'sphinx.ext.linkcode',
41 | 'sphinx_copybutton',
42 | 'recommonmark'
43 | ]
44 |
45 | extensions += [#'matplotlib.sphinxext.only_directives',
46 | 'matplotlib.sphinxext.plot_directive',
47 | 'IPython.sphinxext.ipython_directive',
48 | 'IPython.sphinxext.ipython_console_highlighting',
49 | 'sphinx.ext.mathjax',
50 | 'sphinx.ext.doctest',
51 | ]
52 |
53 | # Add any paths that contain templates here, relative to this directory.
54 | templates_path = ['_templates']
55 |
56 | # List of patterns, relative to source directory, that match files and
57 | # directories to ignore when looking for source files.
58 | # This pattern also affects html_static_path and html_extra_path.
59 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
60 |
61 |
62 | # -- Options for HTML output -------------------------------------------------
63 |
64 | # The theme to use for HTML and HTML Help pages. See the documentation for
65 | # a list of builtin themes.
66 | #
67 | #html_theme = 'alabaster'
68 | html_theme = "pydata_sphinx_theme"
69 | html_logo = "_static/trendypy.png"
70 | html_favicon = "_static/favicon/favicon.ico"
71 | html_theme_options = {
72 | "github_url": "https://github.com/ddaskan/trendypy/",
73 | "twitter_url": "https://twitter.com/_DoganAskan",
74 | "google_analytics_id": "UA-100432301-2",
75 | "navigation_with_keys": True,
76 | "use_edit_page_button": True,
77 | # "search_bar_position": "navbar",
78 | }
79 |
80 | html_context = {
81 | "github_user": "ddaskan",
82 | "github_repo": "trendypy",
83 | "github_version": "master",
84 | "doc_path": "docs",
85 | 'page_source_suffix': '.rst',
86 | }
87 |
88 | # Add any paths that contain custom static files (such as style sheets) here,
89 | # relative to this directory. They are copied after the builtin static files,
90 | # so a file named "default.css" will overwrite the builtin "default.css".
91 | html_static_path = ['_static']
92 |
93 | autodoc_member_order = 'bysource'
94 |
95 | # Napoleon settings
96 | napoleon_google_docstring = True
97 | napoleon_include_init_with_doc = True
98 | napoleon_include_private_with_doc = True
99 | napoleon_use_admonition_for_examples = False
100 | napoleon_use_ivar = False
101 | napoleon_use_param = True
102 | napoleon_use_rtype = True
103 | napoleon_use_keyword = True
104 | napoleon_custom_sections = None
105 |
106 | copybutton_prompt_text = '>>> |\\\\.\\\\.\\\\. |\\\\$ |In \\\\[\\\\d*\\\\]: |\\\\s+\\.\\.\\.\\.: '
107 | copybutton_prompt_is_regexp = True
108 |
109 | ipython_savefig_dir = ""
110 |
111 | def linkcode_resolve(domain, info):
112 | """
113 | Determine the URL corresponding to Python object
114 | """
115 | if domain != "py":
116 | return None
117 |
118 | modname = info["module"]
119 | fullname = info["fullname"]
120 |
121 | submod = sys.modules.get(modname)
122 | if submod is None:
123 | return None
124 |
125 | obj = submod
126 | for part in fullname.split("."):
127 | try:
128 | obj = getattr(obj, part)
129 | except AttributeError:
130 | return None
131 |
132 | try:
133 | fn = inspect.getsourcefile(inspect.unwrap(obj))
134 | except TypeError:
135 | fn = None
136 | if not fn:
137 | return None
138 |
139 | try:
140 | source, lineno = inspect.getsourcelines(obj)
141 | except OSError:
142 | lineno = None
143 |
144 | if lineno:
145 | linespec = f"#L{lineno}-L{lineno + len(source) - 1}"
146 | else:
147 | linespec = ""
148 |
149 | filename = info['module'].replace('.', '/')
150 | return "https://github.com/ddaskan/trendypy/blob/master/trendypy/%s.py" % filename+linespec
151 |
--------------------------------------------------------------------------------
/trendypy/trendy.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from itertools import combinations
3 | import pickle
4 | import pandas as pd
5 | sys.path.append('../')
6 | from trendypy import algos
7 |
8 | class Trendy():
9 | '''Estimator to cluster trend-lines and assign new lines accordingly.
10 |
11 | Notes:
12 | Scaling and missing values need to be handled externally.
13 |
14 | Args:
15 | n_clusters (int): The number of clusters to form.
16 | algorithm (callable): Algorithm to calculate the difference. Default
17 | is `fast DTW with Euclidean `_.
18 |
19 | Example:
20 | >>> a = [1, 2, 3, 4, 5] # increasing trend
21 | >>> b = [1, 2.1, 2.9, 4.4, 5.1] # increasing trend
22 | >>> c = [6.2, 5, 4, 3, 2] # decreasing trend
23 | >>> d = [7, 6, 5, 4, 3, 2, 1] # decreasing trend
24 | >>> trendy = Trendy(n_clusters=2)
25 | >>> trendy.fit([a, b, c, d])
26 | >>> print(trendy.labels_)
27 | [0, 0, 1, 1]
28 | >>> trendy.predict([[0.9, 2, 3.1, 4]]) # another increasing trend
29 | [0]
30 |
31 | '''
32 | def __init__(self, n_clusters, algorithm=algos.fastdtw_distance):
33 |
34 | self.labels_ = None
35 | self.cluster_centers_ = None
36 |
37 | self.n_clusters = int(n_clusters)
38 | if not self.n_clusters >= 2:
39 | raise ValueError('cluster count must be >= 2')
40 |
41 | self.dist_func = algorithm
42 | if not callable(self.dist_func):
43 | raise TypeError('distance `algorithm` must be a callable')
44 |
45 | def fit(self, X):
46 | '''Compute clustering based on given distance algorithm.
47 |
48 | Args:
49 | X (array of arrays): Training instances to cluster.
50 |
51 | Example:
52 | >>> a = [1, 2, 3, 4, 5] # increasing
53 | >>> b = [1, 2.1, 2.9, 4.4, 5.1] # increasing
54 | >>> c = [6.2, 5, 4, 3, 2] # decreasing
55 | >>> d = [7, 6, 5, 4, 3, 2, 1] # decreasing
56 | >>> trendy = Trendy(2)
57 | >>> trendy.fit([a, b, c, d])
58 | >>> print(trendy.labels_)
59 | [0, 0, 1, 1]
60 |
61 | '''
62 | X_len = len(X)
63 | if X_len < self.n_clusters:
64 | raise ValueError('length of `X` < `n_clusters`')
65 |
66 | X_idx = pd.Series(range(X_len))
67 | combs = combinations(X_idx, self.n_clusters)
68 | combs = [[list(c), -1] for c in combs]
69 |
70 | d_matrix = pd.DataFrame(
71 | X_idx.apply(
72 | lambda x: X_idx.apply(
73 | lambda y: self.dist_func(X[x], X[y]))))
74 | d_matrix.columns, d_matrix.index = X_idx, X_idx
75 | for c in combs:
76 | c[1] = d_matrix.loc[c[0], :].min(axis=0).sum()
77 |
78 | combs.sort(key=lambda x: x[1])
79 | cluster_idx = combs[0][0]
80 | self.cluster_centers_ = [X[c] for c in cluster_idx]
81 |
82 | self.labels_ = []
83 | for i in X_idx:
84 | self.labels_.append(
85 | cluster_idx.index(
86 | d_matrix.loc[cluster_idx, i].idxmin()))
87 |
88 | def predict(self, X):
89 | '''Predict the closest cluster each sample in X belongs to.
90 |
91 | Args:
92 | X (array of arrays): New data to predict.
93 |
94 | Returns:
95 | list: Index of the cluster each sample belongs to.
96 |
97 | Example:
98 | >>> a = [1, 2, 3, 4, 5] # increasing
99 | >>> b = [1, 2.1, 2.9, 4.4, 5.1] # increasing
100 | >>> c = [6.2, 5, 4, 3, 2] # decreasing
101 | >>> d = [7, 6, 5, 4, 3, 2, 1] # decreasing
102 | >>> trendy = Trendy(2)
103 | >>> trendy.fit([a, b, c, d])
104 | >>> trendy.predict([[0.9, 2, 3.1, 4]])
105 | [0]
106 | >>> trendy.predict([[0.9, 2, 3.1], [7, 6.6, 5.5, 4.4]])
107 | [0, 1]
108 |
109 | '''
110 | preds = []
111 | for x in X:
112 | dists = [self.dist_func(x, c) for c in self.cluster_centers_]
113 | preds.append(pd.Series(dists).idxmin())
114 | return preds
115 |
116 | def assign(self, X):
117 | '''Alias of `predict()`'''
118 | return self.predict(X)
119 |
120 | def fit_predict(self, X):
121 | '''Compute cluster centers and predict cluster index for each sample.
122 |
123 | Args:
124 | X (array of arrays): Training instances to cluster.
125 |
126 | Returns:
127 | list: predicted labels
128 |
129 | Example:
130 | >>> a = [1, 2, 3, 4, 5] # increasing
131 | >>> b = [1, 2.1, 2.9, 4.4, 5.1] # increasing
132 | >>> c = [6.2, 5, 4, 3, 2] # decreasing
133 | >>> d = [7, 6, 5, 4, 3, 2, 1] # decreasing
134 | >>> trendy = Trendy(2)
135 | >>> trendy.fit_predict([a, b, c, d])
136 | [0, 0, 1, 1]
137 |
138 | '''
139 | self.fit(X)
140 | return self.labels_
141 |
142 | def to_pickle(self, path):
143 | '''Pickle (serialize) object to a file.
144 |
145 | Args:
146 | path (str): file path where the pickled object will be stored
147 |
148 | Example:
149 | To save a `*.pkl` file:
150 |
151 | >>> t1 = Trendy(n_clusters=2)
152 | >>> t1.fit([[1, 2, 3], [2, 3, 3]])
153 | >>> t1.to_pickle(path='trendy.pkl')
154 |
155 | To load the same object later:
156 |
157 | >>> import pickle, os
158 | >>> pkl_file = open('trendy.pkl', 'rb')
159 | >>> t2 = pickle.load(pkl_file)
160 | >>> pkl_file.close()
161 | >>> os.remove('trendy.pkl')
162 |
163 | '''
164 | output = open(path, 'wb')
165 | pickle.dump(self, output, -1)
166 | output.close()
167 |
--------------------------------------------------------------------------------
/docs/source/seeinaction.rst:
--------------------------------------------------------------------------------
1 | See in Action
2 | =============
3 |
4 | Let's see how TrendyPy works with a few use cases.
5 |
6 | Stock Data
7 | ----------
8 |
9 | In this demo, I'd like to show you how to use TrendyPy in some :download:`stock data <../stock_data.csv>` between 2018-01-01 and 2020-06-28. You can download the data from :download:`here <../stock_data.csv>` to reproduce the demo.
10 |
11 | Let's say we have some stock data from a combination of tech and banking. And, we want to identify an unknown trend if it's a tech stock or banking. For this purpose, we'll use FB (i.e. Facebook), GOOGL (i.e. Google), AMZN (i.e Amazon), BAC (i.e. Bank of America) and WFC (i.e. Wells Fargo) for training data then AAPL (i.e. Apple) and c (i.e. Citigroup) for prediction data.
12 |
13 | But first, here is how the data looks.
14 |
15 | .. ipython:: python
16 |
17 | import pandas as pd
18 | import matplotlib.pyplot as plt
19 | df = pd.read_csv('stock_data.csv')
20 | @savefig ticks_raw.png
21 | df.plot()
22 |
23 | If we cluster like this, the expensive stocks like GOOGL and AMZN will alone constitute one cluster which it's clearly not intended. So, let's scale first.
24 |
25 | .. ipython:: python
26 |
27 | from trendypy import utils
28 | df = df.apply(utils.scale_01)
29 | @savefig ticks_scaled.png
30 | df.plot()
31 |
32 | It's a bit apparent that BAC, WFC and c are different than the others. Let's put sectors side by side to see the difference better.
33 |
34 | .. ipython:: python
35 |
36 | fig, axes_ = plt.subplots(nrows=1, ncols=2)
37 | axes_[0].set_title('Tech')
38 | axes_[1].set_title('Banking')
39 | df[['AAPL', 'FB', 'GOOGL', 'AMZN']].plot(ax=axes_[0])
40 | @savefig ticks_scaled_subplot.png
41 | df[['BAC', 'WFC', 'c']].plot(ax=axes_[1])
42 |
43 |
44 | Now, we can use the training data to fit. Remember, we're setting AAPL and c aside to predict later and only fit by using the rest.
45 |
46 | .. ipython:: python
47 |
48 | from trendypy.trendy import Trendy
49 | trendy = Trendy(n_clusters=2) # 2 for tech and banking
50 | trendy.fit([df.FB, df.GOOGL, df.AMZN, df.BAC, df.WFC])
51 | trendy.labels_
52 |
53 | .. ipython:: python
54 | :suppress:
55 |
56 | assert trendy.labels_ == [0, 0, 0, 1, 1]
57 |
58 | You can also use `fit_predict `_ method for this purpose, it's essentially the same.
59 |
60 | .. ipython:: python
61 |
62 | trendy.fit_predict([df.FB, df.GOOGL, df.AMZN, df.BAC, df.WFC])
63 |
64 | .. ipython:: python
65 | :suppress:
66 |
67 | assert trendy.fit_predict([df.FB, df.GOOGL, df.AMZN, df.BAC, df.WFC]) == [0, 0, 0, 1, 1]
68 |
69 | As expected, it successfully assigns FB, GOOGL and AMZN into the first cluster (i.e. ``0``) and BAC and WFC into the second (i.e. ``1``). So, we can name ``0`` as tech and ``1`` as banking.
70 |
71 | Now, let's make predictions on the prediction data that we set aside earlier (i.e. AAPL, c).
72 |
73 | .. ipython:: python
74 | :suppress:
75 |
76 | assert trendy.predict([df.AAPL]) == [0]
77 | assert trendy.predict([df.c]) == [1]
78 |
79 | .. ipython:: python
80 |
81 | trendy.predict([df.AAPL]) # expecting `0` since AAPL is a part of tech
82 | trendy.predict([df.c]) # expecting `1` since c is a part of banking
83 |
84 | As seen above, it correctly predicts trends.
85 |
86 | You can easily pickle the model object to be used later with `to_pickle `_ method.
87 |
88 | .. ipython:: python
89 |
90 | trendy.to_pickle('my_first_trendy.pkl')
91 |
92 | .. ipython:: python
93 | :suppress:
94 |
95 | import os
96 | os.remove('my_first_trendy.pkl')
97 |
98 | And, that's all.
99 |
100 |
101 | Image Clustering
102 | ----------------
103 |
104 | If you have the proper distance metric function for the right data, you can use TrendyPy to even cluster images. In this demo, I'll use black & white images from `MPEG7 CE Shape-1 Part B `_ database. The goal is to correctly cluster the images and assign new ones to the appropriate clusters. Here are some simple images that'll be used to create the clusters. Each image is slightly different than the others in the same group. You can :download:`download the images <../image_data.zip>` if you want to reproduce the demo.
105 |
106 | +------------------------------------------+------------------------------------------+------------------------------------------+
107 | | .. figure:: ../image_data/car-01.gif | .. figure:: ../image_data/car-02.gif | .. figure:: ../image_data/car-03.gif |
108 | | | | |
109 | | car-01.gif | car-02.gif | car-03.gif |
110 | +------------------------------------------+------------------------------------------+------------------------------------------+
111 | | .. figure:: ../image_data/carriage-02.gif| .. figure:: ../image_data/carriage-03.gif| .. figure:: ../image_data/carriage-04.gif|
112 | | | | |
113 | | carriage-02.gif | carriage-03.gif | carriage-04.gif |
114 | +------------------------------------------+------------------------------------------+------------------------------------------+
115 | | .. figure:: ../image_data/chopper-01.gif | .. figure:: ../image_data/chopper-02.gif | .. figure:: ../image_data/chopper-03.gif |
116 | | | | |
117 | | chopper-01.gif | chopper-02.gif | chopper-03.gif |
118 | +------------------------------------------+------------------------------------------+------------------------------------------+
119 |
120 | Define a function to read the image and convert to a numpy array.
121 |
122 | .. ipython:: python
123 |
124 | from PIL import Image
125 | import numpy as np
126 | def load_image(file):
127 | img = Image.open(file)
128 | img.load()
129 | return np.asarray(img, dtype="int32")
130 |
131 | Read images and assign them into lists.
132 |
133 | .. ipython:: python
134 |
135 | cars = [
136 | load_image('image_data/car-01.gif'),
137 | load_image('image_data/car-02.gif'),
138 | load_image('image_data/car-03.gif')
139 | ]
140 | carriages = [
141 | load_image('image_data/carriage-02.gif'),
142 | load_image('image_data/carriage-03.gif'),
143 | load_image('image_data/carriage-04.gif')
144 | ]
145 | choppers = [
146 | load_image('image_data/chopper-01.gif'),
147 | load_image('image_data/chopper-02.gif'),
148 | load_image('image_data/chopper-03.gif')
149 | ]
150 |
151 | `Euclidean Distance `_ can be used to calculate the similarity between images. So, let's import `euclidean_distance `_ from `utils `_ module, then assign it as `algorithm` argument during the initialization.
152 |
153 | .. ipython:: python
154 |
155 | from trendypy.trendy import Trendy
156 | from trendypy.utils import euclidean_distance
157 | trendy = Trendy(n_clusters=3, algorithm=euclidean_distance)
158 | trendy.fit(cars + carriages + choppers)
159 | trendy.labels_
160 |
161 | .. ipython:: python
162 | :suppress:
163 |
164 | assert trendy.labels_ == [0, 0, 0, 1, 1, 1, 2, 2, 2]
165 |
166 | As expected, it correctly clusters these simple images. Let's see if it predicts new data correctly.
167 |
168 | +------------------------------------------+------------------------------------------+------------------------------------------+
169 | | .. figure:: ../image_data/car-20.gif | .. figure:: ../image_data/carriage-20.gif| .. figure:: ../image_data/chopper-08.gif |
170 | | | | |
171 | | car-20.gif | carriage-20.gif | chopper-08.gif |
172 | +------------------------------------------+------------------------------------------+------------------------------------------+
173 |
174 | .. ipython:: python
175 |
176 | new_car = load_image('image_data/car-20.gif')
177 | new_carriage = load_image('image_data/carriage-20.gif')
178 | new_chopper = load_image('image_data/chopper-08.gif')
179 | trendy.predict([new_car, new_carriage, new_chopper])
180 |
181 | .. ipython:: python
182 | :suppress:
183 |
184 | assert trendy.predict([new_car, new_carriage, new_chopper]) == [0, 1, 2]
185 |
186 | Looks like it correctly predicts new data as well.
187 |
188 | .. note::
189 |
190 | Because of the limitation of the selected metric function (i.e. `Euclidean Distance `_), I had to cherry pick images with exact same sizes (i.e. 352×288). Depending on the function you choose, you may or may not do the same.
191 |
192 |
193 | Custom Metric
194 | -------------
195 |
196 | TrendyPy is flexible enough to be able to utilize user defined metrics. In this example, I'll show how to create your own metric and use it during the clustering.
197 |
198 | Let's say we want to cluster DNA sequences and need a metric to do that. `Needleman–Wunsch algorithm `_ is an algorithm used in bioinformatics to align protein or nucleotide sequences. It's not a metric but it inspires us to create our own metric. The metric basically compares two sequences with same length and it penalizes each mismatch by increasing the distance by `p` then divides it to total length.
199 |
200 | .. ipython:: python
201 |
202 | def my_metric(x, y, p=1):
203 | assert len(x) == len(y)
204 | dist = 0
205 | for i in range(len(x)):
206 | if x[i] != y[i]:
207 | dist += p
208 | return dist/len(x)
209 |
210 | As you can see, you just need to consider inputs and output of your custom function. Specifically,
211 |
212 | #. Input must have `x` and `y` for two data points to compare. You may have other default arguments (e.g. `p`).
213 | #. Output must be a float. 0 indicates same and greater is farther.
214 |
215 | .. note::
216 |
217 | Technically, any float range should work as the output of the custom function as long as greater is farther. However, it won't be named as `metric` in that case.
218 |
219 | Anyway, let's use it.
220 |
221 | .. ipython:: python
222 |
223 | set_of_sequences = [
224 | 'AAATTT', 'AAACTT', 'AAATCT', # group 1
225 | 'GACTAG', 'GGCTAG', 'GACAAG' # group 2
226 | ]
227 |
228 | .. ipython:: python
229 |
230 | from trendypy.trendy import Trendy
231 | trendy = Trendy(
232 | n_clusters=2, # there are 2 groups
233 | algorithm=my_metric # this is where to set custom metric
234 | )
235 | trendy.fit(set_of_sequences)
236 | trendy.labels_
237 |
238 | .. ipython:: python
239 | :suppress:
240 |
241 | assert trendy.labels_ == [0, 0, 0, 1, 1, 1]
242 |
243 | It clearly clusters first and second group. Now, let's see on new data.
244 |
245 | .. ipython:: python
246 |
247 | new_seq1 = 'AAAGGT' # similar to group 1
248 | new_seq2 = 'GTCCAG' # similar to group 2
249 | trendy.predict([new_seq1, new_seq2])
250 |
251 | .. ipython:: python
252 | :suppress:
253 |
254 | assert trendy.predict([new_seq1, new_seq2]) == [0, 1]
255 |
256 | Very simple.
257 |
--------------------------------------------------------------------------------
/docs/stock_data.csv:
--------------------------------------------------------------------------------
1 | AAPL,FB,GOOGL,AMZN,BAC,WFC,c
2 | 170.16,177.68,1053.02,1172.0,29.75,61.04,75.09
3 | 172.53,181.88,1073.93,1188.3,29.9,61.22,74.35
4 | 172.54,184.9,1097.09,1205.0,29.97,61.98,75.01
5 | 173.44,185.59,1103.45,1217.51,30.37,62.76,75.71
6 | 174.35,187.2,1111.0,1236.0,30.23,62.66,75.17
7 | 174.55,188.7,1118.44,1256.9,30.2,62.3,74.76
8 | 173.16,186.94,1107.0,1245.15,30.37,62.48,75.7
9 | 174.59,188.4,1112.31,1259.74,30.66,63.65,75.98
10 | 176.18,178.06,1110.1,1273.39,30.88,63.2,75.9
11 | 177.9,181.5,1140.31,1323.0,31.74,62.79,77.76
12 | 176.15,179.26,1136.36,1312.24,31.0,62.85,76.89
13 | 179.37,178.13,1139.35,1293.95,31.33,63.87,77.66
14 | 178.61,180.85,1138.03,1312.0,31.58,64.15,77.57
15 | 177.3,180.8,1143.82,1297.17,31.67,64.0,78.24
16 | 177.3,186.05,1170.62,1338.09,31.86,64.31,78.46
17 | 177.25,189.89,1184.98,1374.82,32.01,64.95,78.96
18 | 174.505,187.95,1180.71,1368.0,32.24,65.7,79.85
19 | 172.0,187.75,1187.53,1392.01,32.11,65.89,79.61
20 | 170.16,188.75,1188.0,1409.18,32.25,65.78,80.12
21 | 165.525,183.01,1177.72,1403.17,31.95,65.43,79.2
22 | 166.87,188.37,1183.81,1451.3,32.05,65.27,78.78
23 | 167.165,188.22,1175.99,1445.0,32.0,65.37,78.27
24 | 166.0,192.04,1127.42,1477.39,32.44,65.33,78.65
25 | 159.1,186.93,1100.61,1402.62,31.12,58.7,75.52
26 | 154.83,178.57,1033.98,1361.46,29.41,56.905,71.52
27 | 163.085,184.15,1084.97,1449.0,31.12,56.94,74.77
28 | 160.29,181.01,1059.87,1429.67,31.31,57.33,75.07
29 | 157.07,174.76,1025.88,1373.49,30.17,56.14,73.02
30 | 158.5,177.06,1056.67,1364.67,30.62,56.36,74.47
31 | 161.95,175.62,1050.0,1385.93,31.04,56.06,74.34
32 | 163.045,173.45,1054.32,1406.25,31.17,57.85,75.03
33 | 169.79,180.5,1083.45,1466.89,32.39,59.82,77.18
34 | 172.36,178.99,1093.38,1457.37,32.0,59.67,76.8
35 | 172.05,175.77,1092.76,1446.49,31.96,59.86,76.64
36 | 172.83,176.71,1109.1,1485.0,31.8,59.86,76.4
37 | 171.8,178.7,1119.17,1495.36,31.99,59.88,77.28
38 | 173.67,179.9,1118.66,1495.34,31.8,59.07,76.48
39 | 176.35,184.58,1131.86,1509.2,32.17,59.75,77.23
40 | 179.1,184.45,1143.7,1524.5,32.32,60.03,77.52
41 | 179.26,182.3,1122.0,1519.51,32.49,59.47,76.6
42 | 178.54,179.01,1109.54,1513.6,32.07,58.25,75.5
43 | 172.8,173.29,1057.98,1469.1,31.12,56.92,73.17
44 | 175.21,176.2,1078.13,1494.24,31.35,56.81,73.07
45 | 177.91,181.78,1102.1,1533.2,32.3,57.71,74.93
46 | 174.94,178.74,1092.82,1526.52,31.7,56.4,73.18
47 | 175.48,183.56,1117.2,1550.0,32.19,56.75,74.14
48 | 177.96,183.91,1139.5,1563.5,32.47,57.16,74.95
49 | 180.29,185.23,1165.05,1592.6,32.69,58.27,75.95
50 | 182.59,185.61,1171.83,1615.96,32.97,58.39,76.14
51 | 180.32,182.6,1145.8,1597.0,32.55,57.86,75.28
52 | 178.5,183.24,1149.57,1595.0,32.29,56.77,73.78
53 | 178.65,184.49,1155.35,1583.45,32.11,56.99,73.17
54 | 177.32,177.01,1117.76,1554.53,32.13,55.88,73.47
55 | 175.24,167.47,1098.4,1550.34,32.06,55.77,73.05
56 | 175.04,164.8,1092.57,1586.45,32.0,55.02,73.18
57 | 170.0,166.13,1080.01,1565.47,31.44,54.21,72.33
58 | 168.39,165.44,1051.37,1539.01,30.69,52.72,70.32
59 | 168.07,160.82,1050.6,1530.0,29.89,51.95,69.11
60 | 173.68,156.31,1063.9,1572.4,30.65,52.4,70.24
61 | 167.25,151.65,1001.91,1447.0,29.79,51.16,68.48
62 | 167.805,155.15,1011.21,1406.0,29.57,52.06,68.52
63 | 167.88,157.81,1027.62,1417.62,29.8,52.37,68.33
64 | 167.64,156.55,1016.15,1391.38,29.54,51.72,68.05
65 | 164.88,152.025,998.23,1358.24,29.0,51.13,67.16
66 | 172.58,161.56,1046.39,1441.99,30.18,53.34,70.07
67 | 170.97,157.73,1023.1,1429.97,30.01,52.65,69.52
68 | 169.88,157.82,1020.04,1425.03,29.82,52.5,69.06
69 | 173.0,157.93,1030.26,1431.99,30.48,52.99,71.05
70 | 172.23,165.36,1032.0,1439.44,30.15,52.32,69.97
71 | 173.41,166.98,1031.47,1439.5,30.22,52.16,70.47
72 | 174.78,164.58,1046.89,1449.14,31.13,52.01,73.21
73 | 175.0301,165.7249,1045.55,1445.0,30.08,50.59,71.09
74 | 176.49,165.83,1061.2,1462.3,30.17,50.95,70.65
75 | 177.81,166.88,1079.01,1514.65,30.03,50.78,69.81
76 | 174.95,166.2,1069.02,1543.22,29.55,50.51,69.1
77 | 170.595,167.79,1084.27,1561.2,30.26,51.93,70.4
78 | 166.8348,167.27,1082.98,1546.69,30.27,52.55,70.0
79 | 165.67,165.43,1059.2,1535.8,30.46,52.95,69.76
80 | 162.62,160.1448,1029.75,1458.0,30.09,52.44,68.77
81 | 164.12,173.22,1033.22,1485.01,30.04,52.99,69.11
82 | 164.0,176.81,1045.54,1634.01,29.99,52.28,69.0
83 | 162.1302,173.79,1034.42,1582.5,30.27,52.56,69.2
84 | 166.4102,172.0,1016.3,1563.22,29.92,51.76,68.24
85 | 175.225,174.246,1034.0,1580.98,29.95,52.38,67.95
86 | 175.88,175.13,1025.37,1560.01,29.51,51.62,67.8
87 | 178.25,173.08,1019.61,1562.45,28.99,51.17,67.05
88 | 185.18,177.35,1053.89,1589.34,29.44,52.97,68.27
89 | 184.99,178.25,1064.62,1595.0,29.77,52.72,69.65
90 | 186.55,179.67,1064.1,1600.0,30.1,53.45,71.23
91 | 187.74,183.15,1095.0,1608.48,30.61,54.13,71.96
92 | 189.49,184.85,1100.41,1610.99,30.91,54.69,72.53
93 | 189.01,187.71,1105.57,1604.0,31.04,54.78,72.93
94 | 186.78,184.88,1096.9,1587.8,30.92,54.43,72.51
95 | 186.07,183.6952,1085.09,1577.5,31.18,54.7,72.44
96 | 188.0,182.68,1081.46,1580.56,31.04,54.4,71.73
97 | 187.19,183.49,1066.0,1581.33,30.77,54.15,71.26
98 | 188.0,183.77,1079.0,1585.0,30.52,54.08,70.65
99 | 188.375,184.93,1089.8,1589.89,30.6,54.63,70.79
100 | 186.35,182.5,1070.0,1571.05,30.71,55.03,70.65
101 | 188.77,185.88,1086.9,1598.03,30.4,55.87,69.84
102 | 188.23,186.02,1086.55,1603.0,30.01,54.6,68.93
103 | 187.6,184.34,1076.0,1600.71,29.76,54.04,67.12
104 | 187.72,186.54,1073.48,1618.1,29.29,53.66,66.56
105 | 187.22,187.87,1082.0,1623.0,29.2,54.21,66.55
106 | 187.9912,193.065,1112.87,1637.03,29.49,54.56,67.49
107 | 191.635,191.84,1138.5,1648.9,29.55,54.79,67.44
108 | 193.065,194.3,1154.66,1672.99,29.31,54.61,67.08
109 | 193.63,191.0252,1152.77,1704.51,29.29,54.72,67.21
110 | 194.14,190.75,1144.58,1698.56,30.2,55.77,68.93
111 | 191.17,187.53,1131.21,1681.12,30.01,55.56,68.13
112 | 191.35,188.81,1132.94,1681.51,30.13,55.79,68.92
113 | 191.385,192.17,1141.02,1693.0,30.17,55.64,68.26
114 | 192.42,192.74,1152.28,1702.81,29.98,55.39,67.82
115 | 191.55,193.1,1152.21,1713.48,30.04,55.33,67.56
116 | 190.03,195.79,1159.92,1714.0,29.25,54.55,66.32
117 | 187.88,194.8,1152.69,1706.26,28.94,54.51,65.75
118 | 185.14,196.2352,1170.11,1709.04,29.04,54.68,66.03
119 | 186.35,199.1,1183.3,1742.5,29.42,55.46,67.72
120 | 187.25,202.76,1185.51,1760.0,29.21,54.25,67.16
121 | 186.12,201.16,1171.49,1742.62,29.46,54.96,68.04
122 | 183.4,200.0,1155.0,1702.51,28.86,53.78,66.79
123 | 182.99,197.6,1144.14,1672.37,28.52,53.9,65.51
124 | 185.2278,199.18,1136.0,1708.11,28.51,53.24,66.22
125 | 184.1,195.18,1112.39,1672.54,28.4,53.55,65.98
126 | 186.29,197.32,1132.31,1717.0,29.09,55.62,68.0
127 | 183.82,193.37,1115.35,1682.7,28.08,55.2,66.21
128 | 187.79,194.55,1149.42,1723.96,28.33,56.43,67.45
129 | 185.26,194.74,1124.6,1705.38,27.95,55.92,66.44
130 | 185.42,198.45,1141.77,1696.0,27.81,55.3,66.22
131 | 189.5,204.93,1160.0,1724.05,28.23,56.19,67.5
132 | 190.71,204.5,1169.99,1738.53,29.22,57.06,69.23
133 | 188.5,202.22,1155.62,1737.99,28.67,56.4,67.97
134 | 189.53,203.43,1174.86,1764.51,28.9,56.46,68.36
135 | 191.08,207.81,1202.8,1803.93,28.62,54.74,67.99
136 | 191.52,207.5,1203.81,1821.95,28.78,55.74,67.36
137 | 189.75,204.9,1182.74,1811.56,29.89,56.95,69.5
138 | 191.78,209.82,1208.53,1848.0,29.92,56.26,69.22
139 | 189.69,208.77,1206.65,1829.46,29.93,56.26,69.5
140 | 191.78,208.85,1199.24,1825.01,29.62,56.07,68.79
141 | 190.68,210.58,1195.66,1812.21,30.14,56.39,69.16
142 | 192.45,215.11,1271.0,1829.01,30.85,58.0,70.4
143 | 193.0602,215.715,1252.62,1829.3,30.7,58.1,70.82
144 | 194.61,174.89,1267.18,1839.0,31.19,58.47,71.75
145 | 194.99,179.87,1289.12,1876.05,30.99,58.38,71.36
146 | 191.9,175.3,1245.05,1827.33,31.14,58.83,71.86
147 | 190.3,170.67,1231.71,1786.49,31.36,58.61,72.2
148 | 199.13,173.93,1239.11,1784.0,31.22,57.96,72.5
149 | 200.58,170.68,1218.5,1788.77,30.98,57.08,71.34
150 | 207.03,177.69,1245.18,1837.74,31.18,58.06,71.64
151 | 208.0,178.97,1241.61,1825.81,31.45,58.58,72.16
152 | 209.32,186.5,1252.01,1854.53,31.55,58.94,72.57
153 | 206.05,184.75,1256.72,1861.0,31.51,58.76,72.14
154 | 207.28,185.8492,1262.73,1882.0,31.73,58.65,72.44
155 | 207.36,182.04,1259.18,1888.51,31.23,57.38,70.63
156 | 207.7,180.1,1251.2,1898.5,31.08,57.66,70.2
157 | 210.155,180.71,1252.5,1919.39,30.61,57.67,69.3
158 | 209.22,179.34,1244.28,1909.55,30.48,57.68,69.23
159 | 211.75,180.42,1241.99,1903.94,30.56,58.14,69.16
160 | 213.44,174.5,1222.04,1885.8,30.66,58.51,69.42
161 | 218.1,174.04,1220.66,1890.57,30.69,58.81,69.46
162 | 216.8,172.81,1223.02,1880.0,30.91,59.0,70.63
163 | 214.1,172.21,1214.22,1876.64,30.92,59.04,71.16
164 | 214.65,173.09,1219.88,1907.17,30.94,59.0,71.03
165 | 216.6,173.7,1226.0,1910.51,30.94,58.9,70.6
166 | 217.15,175.99,1244.14,1915.0,31.03,58.87,71.07
167 | 219.01,178.1,1255.9,1937.73,31.36,59.19,72.57
168 | 220.15,176.295,1255.0,1953.45,31.24,59.05,72.3
169 | 223.25,175.9,1263.4,1997.42,31.02,58.67,72.09
170 | 226.51,177.15,1252.21,2007.0,30.88,58.27,71.05
171 | 228.41,173.5,1222.52,2026.5,30.91,58.45,70.99
172 | 228.99,169.49,1209.22,2038.11,31.07,58.88,71.2
173 | 226.23,166.98,1198.57,2006.51,31.05,58.91,70.93
174 | 221.85,160.31,1172.0,1938.71,31.0,57.92,70.34
175 | 220.95,163.51,1184.2,1971.0,30.88,57.62,69.98
176 | 218.01,163.94,1171.1,1928.27,30.72,57.4,69.26
177 | 224.94,163.25,1182.0,1994.0,30.88,57.33,70.96
178 | 223.52,162.0,1179.7,2000.0,30.53,56.01,70.9
179 | 225.75,161.715,1188.0,1992.93,30.13,55.19,70.18
180 | 222.15,161.92,1177.77,1954.73,30.34,54.75,70.79
181 | 217.79,159.39,1162.66,1918.65,30.33,54.25,71.3
182 | 218.5,160.08,1168.96,1940.5,30.13,54.49,71.54
183 | 220.24,164.5,1180.67,1938.58,31.3,55.63,74.5
184 | 220.78,166.64,1194.92,1954.22,31.34,55.75,74.98
185 | 216.82,161.03,1159.41,1903.79,30.98,54.8,74.08
186 | 219.75,161.99,1184.25,1942.9,30.85,54.3,74.22
187 | 221.0,164.3,1193.69,1968.5,30.71,54.38,73.52
188 | 223.82,167.55,1200.0,1993.24,30.24,53.28,72.9
189 | 224.79,168.33,1204.09,2004.41,29.65,52.69,72.06
190 | 227.95,163.03,1213.0,2021.99,29.68,52.74,72.24
191 | 227.25,161.58,1206.67,1999.99,29.58,52.24,71.51
192 | 230.05,160.0,1212.0,1981.7,29.81,52.5,72.54
193 | 230.78,161.46,1205.03,1949.0,30.17,52.73,72.78
194 | 227.96,159.21,1176.0,1917.99,30.6,53.7,72.95
195 | 222.21,155.54,1160.0,1874.0,30.05,52.98,71.69
196 | 223.64,157.69,1151.31,1859.99,30.03,53.38,72.06
197 | 225.46,156.82,1136.4,1857.89,29.98,53.7,72.07
198 | 214.52,150.13,1079.04,1724.0,28.89,52.38,69.14
199 | 220.42,156.73,1119.64,1808.0,28.99,52.1,70.45
200 | 221.16,153.32,1118.0,1795.0,28.49,52.51,70.13
201 | 218.93,155.4,1113.48,1783.5,28.24,53.31,69.89
202 | 222.3,159.56,1140.0,1842.79,28.37,53.56,69.35
203 | 217.86,158.51,1130.0,1821.49,28.67,54.17,69.54
204 | 218.06,155.86,1103.71,1785.16,28.14,53.08,68.54
205 | 219.79,154.76,1112.51,1784.0,28.32,53.07,68.89
206 | 215.83,151.22,1091.29,1742.24,26.39,50.84,64.15
207 | 222.6,154.28,1115.0,1773.7,26.86,51.31,65.41
208 | 217.71,147.73,1080.3,1703.34,26.38,50.53,64.77
209 | 215.9,145.82,1048.33,1649.59,26.33,51.315,64.17
210 | 219.19,148.5,1096.54,1660.0,26.69,51.88,65.06
211 | 211.15,139.935,1020.01,1486.16,26.76,52.45,64.6
212 | 216.88,155.0,1068.2,1569.99,27.1,53.04,65.01
213 | 219.05,151.52,1091.4,1623.53,27.77,53.43,66.09
214 | 209.55,151.8,1089.0,1678.59,28.01,54.21,66.07
215 | 204.3,150.1,1072.53,1657.57,27.95,53.73,66.3
216 | 201.92,149.31,1055.02,1618.35,28.02,53.36,67.31
217 | 205.97,151.57,1083.49,1673.0,28.415,53.82,67.29
218 | 209.98,150.49,1107.3,1755.0,28.5,52.9,67.94
219 | 205.55,146.75,1084.02,1732.5,28.75,53.085,67.2
220 | 199.0,144.48,1073.13,1698.24,28.38,53.13,65.56
221 | 191.63,142.0,1054.81,1649.29,27.75,52.62,64.38
222 | 193.9,143.7,1060.0,1656.32,27.95,53.14,65.39
223 | 188.39,142.33,1051.46,1581.01,27.14,51.54,62.97
224 | 190.5,141.07,1065.23,1587.5,27.69,52.65,64.49
225 | 190.0,137.61,1063.39,1577.01,27.78,52.97,65.08
226 | 178.37,127.03,1007.29,1437.5,27.42,53.05,63.82
227 | 179.73,134.4,1045.31,1542.99,27.59,52.62,62.76
228 | 174.94,133.65,1033.5,1517.0,27.08,51.97,62.33
229 | 174.24,133.0,1044.0,1539.0,27.18,52.33,62.67
230 | 171.51,135.75,1051.34,1575.99,27.43,52.69,63.35
231 | 176.73,136.28,1057.46,1613.92,27.88,53.15,63.64
232 | 182.66,135.92,1083.53,1674.99,28.18,53.97,65.09
233 | 180.29,138.26,1095.63,1679.5,27.94,54.08,64.37
234 | 184.46,143.0,1132.16,1769.46,28.99,54.78,66.04
235 | 180.95,140.73,1112.99,1756.0,28.32,53.95,64.58
236 | 171.76,133.82,1045.0,1614.87,26.23,50.65,59.36
237 | 173.49,139.25,1072.23,1705.07,26.15,50.89,59.72
238 | 165.0,139.6,1042.94,1623.84,25.18,50.07,57.95
239 | 171.66,143.88,1066.94,1678.0,25.21,49.41,58.17
240 | 170.4,143.08,1077.08,1669.0,24.87,48.29,57.13
241 | 170.49,145.57,1075.67,1680.0,24.66,47.97,56.38
242 | 169.0,143.34,1060.02,1638.0,24.18,46.55,54.73
243 | 165.45,143.08,1047.01,1566.0,24.26,46.22,54.85
244 | 165.38,141.08,1034.0,1540.0,24.67,46.94,54.72
245 | 166.0,141.21,1047.29,1543.05,24.45,46.39,53.9
246 | 160.4,130.7,1026.0,1484.0,23.85,45.4,52.21
247 | 156.86,133.39,1032.04,1464.99,23.91,45.59,51.9
248 | 148.15,123.1,984.32,1346.0,22.76,44.47,49.4
249 | 148.3,126.0,997.99,1368.89,22.91,43.84,49.65
250 | 155.84,132.44,1026.2,1454.2,23.78,44.72,50.62
251 | 157.5,135.34,1059.5,1473.35,24.59,45.68,51.93
252 | 158.53,134.45,1057.83,1510.8,24.57,45.98,51.98
253 | 154.89,128.99,1027.2,1465.2,24.08,45.525,50.68
254 | 143.98,134.69,1050.67,1520.01,24.94,46.65,53.41
255 | 144.53,134.01,1042.56,1530.0,25.1,47.42,54.01
256 | 148.7,137.56,1080.97,1602.31,25.56,47.78,55.33
257 | 149.56,139.89,1086.0,1664.69,25.72,47.9,56.03
258 | 151.29,142.95,1087.99,1652.98,25.67,47.51,55.71
259 | 152.5,143.08,1074.94,1641.01,25.56,47.5,55.99
260 | 152.88,143.15,1069.9,1640.55,25.53,47.5,56.46
261 | 150.85,142.0,1053.34,1615.0,25.77,47.51,56.1
262 | 150.27,146.01,1058.01,1632.0,26.21,47.6,59.89
263 | 153.08,149.0,1090.0,1684.22,28.13,48.15,61.95
264 | 154.2,146.95,1087.99,1680.0,28.34,48.64,61.63
265 | 157.5,149.75,1108.59,1712.0,29.02,49.1,62.86
266 | 156.41,149.2,1096.0,1681.0,28.98,49.77,62.67
267 | 154.15,148.28,1086.86,1656.0,29.22,50.0,62.27
268 | 154.11,144.64,1082.51,1641.07,28.75,49.79,61.74
269 | 155.48,147.48,1094.23,1670.5,29.28,50.4,63.33
270 | 155.79,148.05,1090.07,1643.59,29.32,49.77,63.19
271 | 156.25,148.09,1081.04,1631.27,29.54,49.78,63.71
272 | 163.25,146.22,1077.36,1623.0,29.42,49.84,63.46
273 | 166.11,165.6,1112.24,1692.85,28.75,49.28,63.65
274 | 166.96,165.84,1122.29,1638.88,28.6,49.0,64.25
275 | 167.41,165.7,1119.01,1623.0,28.47,48.85,63.5
276 | 172.86,169.15,1129.63,1643.34,28.85,49.27,64.19
277 | 174.65,171.2,1149.27,1670.75,28.67,49.09,63.83
278 | 172.4,168.2,1111.82,1625.0,28.54,49.09,63.61
279 | 168.99,164.47,1094.88,1586.0,28.15,47.94,62.13
280 | 171.05,167.9,1103.75,1600.98,28.34,47.87,62.41
281 | 170.1,166.86,1111.01,1604.0,28.62,48.01,62.15
282 | 171.39,165.38,1133.04,1647.0,28.87,49.24,63.3
283 | 169.71,163.19,1125.0,1624.5,28.36,48.63,62.35
284 | 171.25,164.51,1139.3,1627.86,28.76,49.09,63.14
285 | 169.71,160.5,1116.64,1601.0,28.93,49.03,63.73
286 | 171.19,162.25,1128.88,1630.0,29.1,49.43,64.5
287 | 171.8,161.93,1118.78,1619.85,29.33,49.76,64.55
288 | 171.58,160.58,1109.7,1623.5,29.05,49.6,64.63
289 | 174.16,163.07,1121.93,1641.45,29.12,49.26,64.59
290 | 173.71,164.335,1114.37,1625.98,29.02,49.49,64.09
291 | 173.21,162.9,1114.01,1628.18,29.3,49.59,64.24
292 | 174.32,162.37,1119.0,1635.25,29.5,49.98,64.46
293 | 174.28,162.6,1131.0,1655.13,29.33,50.23,64.78
294 | 175.69,163.9,1154.56,1685.0,29.33,50.29,64.53
295 | 175.94,167.37,1156.0,1702.95,29.02,50.03,63.66
296 | 174.67,172.9,1171.76,1695.97,29.01,49.97,62.7
297 | 173.87,171.5,1160.5,1667.37,28.67,49.71,62.03
298 | 170.32,166.2,1133.9,1604.01,28.06,49.26,60.96
299 | 175.49,171.6,1152.0,1626.12,28.7,50.0,62.53
300 | 180.0,172.09,1182.3,1669.0,29.0,49.78,62.3
301 | 182.25,172.32,1205.93,1683.0,29.05,49.87,63.14
302 | 183.9,169.76,1199.02,1691.2,29.31,50.07,63.69
303 | 184.85,167.16,1198.0,1703.0,29.44,50.22,64.16
304 | 185.8,163.57,1189.69,1712.7,29.38,50.84,65.21
305 | 188.35,161.48,1191.72,1753.51,30.01,52.42,66.46
306 | 186.23,161.5,1201.4,1769.94,29.62,51.19,65.26
307 | 190.02,164.89,1220.0,1796.26,28.45,49.98,63.67
308 | 195.34,165.65,1228.85,1810.17,27.91,49.25,62.98
309 | 191.51,163.0,1199.56,1757.79,26.91,48.42,60.98
310 | 191.664,167.35,1205.19,1793.0,27.15,48.52,60.99
311 | 188.75,167.85,1191.92,1784.13,27.09,48.94,61.38
312 | 188.95,164.57,1175.5,1770.0,27.2,48.73,60.95
313 | 189.83,166.39,1180.18,1786.58,27.55,49.8,62.33
314 | 191.64,167.83,1187.54,1800.11,27.9,48.43,62.85
315 | 191.09,170.14,1200.05,1811.02,28.47,48.57,64.24
316 | 193.25,174.5,1212.7,1826.72,29.07,48.47,64.99
317 | 194.79,176.02,1211.29,1820.65,28.85,48.95,64.81
318 | 196.45,176.88,1219.3,1829.0,29.32,49.26,65.93
319 | 196.42,175.21,1211.11,1833.23,28.89,48.64,65.13
320 | 200.32,175.62,1201.89,1845.49,29.0,48.68,65.6
321 | 198.68,178.18,1205.09,1841.0,28.9,48.08,65.48
322 | 200.85,178.24,1208.9,1848.7,29.25,47.97,65.8
323 | 199.2,178.0,1215.62,1848.4,29.56,47.75,67.08
324 | 198.58,178.5,1224.09,1842.0,30.1,45.87,67.39
325 | 199.46,179.0,1230.0,1851.35,29.3,46.88,67.5
326 | 199.54,179.6,1237.0,1872.99,29.83,47.96,69.95
327 | 203.12,178.8,1245.0,1868.79,29.95,47.44,70.01
328 | 202.83,178.25,1236.67,1855.4,29.93,47.41,69.58
329 | 204.43,182.74,1256.64,1891.2,29.99,47.2,68.84
330 | 207.36,184.49,1270.59,1925.0,29.95,47.06,68.99
331 | 206.83,196.98,1270.3,1917.0,29.91,47.17,68.56
332 | 204.9,192.5,1273.38,1929.0,30.17,47.52,68.9
333 | 204.4,190.95,1280.51,1949.0,30.43,47.97,69.69
334 | 203.06,194.19,1190.63,1930.1,30.8,48.35,71.02
335 | 209.88,194.78,1197.5,1933.09,30.56,48.32,70.68
336 | 209.84,193.0,1172.6,1913.33,30.26,48.35,69.74
337 | 210.89,194.38,1177.41,1949.0,30.66,48.5194,70.39
338 | 204.29,191.24,1172.0,1917.98,30.11,47.99,69.05
339 | 205.88,192.54,1185.81,1939.99,30.16,48.05,69.35
340 | 201.9,189.39,1177.29,1918.87,29.73,47.06,67.88
341 | 200.4,187.2,1162.6,1900.0,29.42,46.0,66.83
342 | 197.419,188.25,1168.84,1898.0,29.46,46.41,67.27
343 | 187.71,183.5,1145.24,1836.56,28.96,46.28,66.13
344 | 186.41,182.52,1142.32,1839.5,28.36,46.38,64.62
345 | 186.27,180.42,1122.55,1827.95,28.1,46.02,64.46
346 | 189.91,185.05,1171.84,1885.94,28.46,45.99,65.31
347 | 186.93,184.84,1175.83,1893.05,28.25,45.44,64.97
348 | 183.52,181.88,1153.0,1852.69,28.4,45.62,64.75
349 | 185.22,184.57,1154.48,1874.79,28.57,45.62,65.5
350 | 184.66,184.73,1151.25,1851.78,28.51,46.07,65.84
351 | 179.8,182.42,1146.07,1836.59,28.13,45.83,63.82
352 | 180.2,182.33,1152.0,1835.89,27.93,45.76,64.29
353 | 178.92,181.54,1141.48,1832.75,28.05,46.07,64.09
354 | 176.42,183.5,1132.7,1823.12,27.53,45.39,63.15
355 | 177.95,183.08,1120.15,1825.49,27.77,45.69,64.77
356 | 176.23,180.28,1105.64,1790.01,26.5,44.53,62.39
357 | 175.6,175.0,1066.93,1760.01,26.59,44.24,62.1
358 | 175.44,163.71,1044.49,1699.24,27.18,45.16,63.79
359 | 184.28,167.48,1055.0,1749.6,27.84,45.87,65.45
360 | 183.08,168.3,1046.21,1737.71,27.76,45.74,65.82
361 | 186.51,170.17,1054.28,1763.7,27.75,45.9,66.16
362 | 191.81,174.75,1077.0,1822.0,27.86,46.06,66.88
363 | 194.86,178.48,1096.99,1883.25,28.38,45.84,67.58
364 | 193.95,178.38,1079.95,1853.98,28.2,46.01,67.65
365 | 194.7,175.53,1084.71,1866.72,27.97,45.1,66.83
366 | 191.545,180.51,1089.74,1864.0,27.91,45.31,67.15
367 | 192.9,185.01,1089.1,1876.5,28.01,45.58,67.5
368 | 196.05,194.0,1111.5,1901.35,28.02,45.25,66.81
369 | 199.68,187.0,1107.24,1907.84,28.7,46.48,68.16
370 | 200.37,190.95,1121.7,1933.33,28.59,45.85,68.56
371 | 198.8,188.75,1109.86,1916.1,28.19,45.84,68.03
372 | 198.54,192.42,1120.0,1912.66,28.08,46.55,67.82
373 | 198.43,192.88,1115.08,1911.84,28.02,46.13,67.46
374 | 197.77,189.54,1091.0,1892.48,27.94,46.21,67.04
375 | 200.29,189.88,1086.75,1902.0,28.08,46.22,67.62
376 | 198.68,190.55,1077.23,1909.1,29.01,46.81,69.28
377 | 203.17,195.21,1101.04,1922.98,29.48,47.88,70.86
378 | 201.41,193.0,1104.83,1919.38,29.34,47.52,70.36
379 | 203.28,194.16,1118.5,1935.89,29.19,47.3,70.71
380 | 203.35,196.18,1119.37,1928.6,29.36,48.1,71.27
381 | 200.81,195.19,1125.87,1934.12,29.01,47.4,70.76
382 | 199.2,194.97,1110.32,1947.8,28.97,47.3,70.53
383 | 201.85,200.0,1132.32,1996.51,29.17,47.67,71.5
384 | 203.31,203.26,1146.16,2025.62,29.1,47.21,71.4298
385 | 202.45,199.68,1142.93,2008.27,29.44,47.12,71.89
386 | 204.09,204.25,1145.34,2021.4,29.5,47.4,71.73
387 | 204.59,203.89,1146.73,2010.58,29.17,46.72,71.7
388 | 204.05,204.18,1150.92,2007.05,29.1,45.2,71.19
389 | 204.0,200.15,1142.0,1980.01,29.28,45.22,70.54
390 | 205.79,202.18,1149.32,1991.21,29.54,45.96,71.73
391 | 203.65,199.91,1135.47,1971.14,29.29,45.89,70.72
392 | 208.46,202.84,1143.45,1995.99,29.75,46.68,71.33
393 | 207.67,197.63,1132.62,1969.3,30.07,47.3,71.66
394 | 208.89,206.7,1138.95,2001.0,30.74,48.52,72.96
395 | 207.48,200.19,1228.0,1942.0,30.57,48.15,72.15
396 | 208.46,199.0,1242.5,1930.0,30.72,49.38,71.91
397 | 208.76,195.39,1227.0,1891.12,30.21,48.01,71.03
398 | 216.42,196.95,1224.87,1898.11,30.83,48.26,71.4
399 | 213.9,194.17,1217.63,1871.72,30.55,48.41,70.67
400 | 205.53,191.1,1203.0,1845.0699,29.36,47.11,67.61
401 | 197.99,184.69,1172.97,1770.22,28.53,46.5,65.6
402 | 196.31,183.69,1165.52,1792.23,28.41,46.61,66.0
403 | 195.41,183.6,1157.8,1773.99,27.61,46.07,64.63
404 | 200.2,186.62,1186.4301,1806.0,28.11,45.69,65.85
405 | 201.3,190.0,1199.995,1828.95,28.27,46.02,66.33
406 | 199.62,186.85,1180.0,1795.99,27.83,45.51,64.61
407 | 201.02,185.52,1174.35,1783.0,27.57,45.61,63.9
408 | 203.16,185.8,1176.07,1793.01,26.94,45.02,62.88
409 | 203.46,180.9619,1168.43,1781.99,26.58,44.3,61.98
410 | 204.28,183.75,1180.79,1792.89,26.53,43.74,61.93
411 | 210.62,186.01,1191.83,1818.08,27.64,45.13,64.82
412 | 210.88,185.45,1195.35,1814.5,27.02,45.04,63.72
413 | 212.99,185.0,1195.8199,1819.39,26.93,44.96,64.13
414 | 213.19,183.43,1193.8,1828.0,27.09,45.33,63.81
415 | 209.43,180.84,1185.17,1793.03,26.95,45.2,63.28
416 | 205.86,179.4,1159.45,1766.91,26.7,44.71,62.57
417 | 207.86,181.93,1183.0,1775.73,26.86,45.23,63.01
418 | 204.1,180.53,1164.87,1755.0,26.22,44.64,61.3
419 | 208.5,183.77,1186.42,1783.0,27.0,46.0,63.31
420 | 210.16,186.78,1200.35,1797.49,27.5,46.54,64.34
421 | 206.43,184.0,1181.85,1770.0,27.21,46.31,64.0
422 | 208.39,184.65,1179.45,1805.0,27.32,46.54,64.0
423 | 212.0,188.53,1193.66,1821.95,27.85,47.31,65.65
424 | 214.05,190.21,1209.14,1838.22,28.02,47.58,66.19
425 | 214.84,187.73,1207.08,1841.0,28.0,47.32,66.76
426 | 213.86,187.44,1196.09,1822.75,28.89,48.07,69.18
427 | 218.07,186.46,1203.89,1812.14,29.37,48.29,68.72
428 | 224.8,189.86,1223.47,1837.63,29.22,48.52,68.11
429 | 220.0,187.325,1232.11,1842.01,30.0,49.01,70.34
430 | 217.73,186.93,1230.44,1824.02,29.68,48.46,68.96
431 | 219.96,186.66,1231.63,1807.08,29.85,48.7,69.78
432 | 221.06,188.09,1230.24,1817.04,29.77,48.63,69.21
433 | 222.01,188.66,1232.32,1821.02,30.0,48.99,70.06
434 | 221.38,190.66,1233.64,1821.71,29.97,49.07,70.15
435 | 218.95,189.34,1226.57,1777.0,29.31,48.32,68.62
436 | 221.055,187.98,1240.0,1790.61,29.6,48.98,69.5
437 | 218.55,181.45,1216.01,1747.36,28.78,48.73,67.91
438 | 220.0,181.33,1242.14,1762.79,29.21,49.25,69.32
439 | 220.54,178.16,1242.83,1748.0,29.41,50.36,69.82
440 | 220.9,177.87,1220.6,1726.99,29.49,50.77,69.7965
441 | 225.07,179.15,1222.49,1746.0,29.44,50.65,69.57
442 | 223.06,174.84,1196.5,1727.74,28.2,48.72,67.76
443 | 218.43,175.57,1183.34,1713.0,27.76,48.3,66.08
444 | 225.64,179.55,1194.29,1726.02,27.85,48.66,66.76
445 | 226.27,180.0,1207.0,1731.63,28.33,48.95,67.87
446 | 225.82,178.26,1198.77,1722.49,27.87,48.25,67.03
447 | 227.03,179.16,1201.33,1719.61,27.83,48.17,67.0
448 | 227.93,180.32,1198.6,1725.24,28.04,48.33,67.77
449 | 232.95,182.15,1224.03,1742.92,28.99,49.46,69.99
450 | 234.9,184.2,1213.89,1728.91,28.74,49.09,69.53
451 | 236.39,183.8,1221.5,1742.14,29.34,49.28,70.17
452 | 233.37,188.32,1241.81,1773.33,30.37,50.04,70.82
453 | 235.09,190.3,1251.4,1796.49,30.3,49.98,70.03
454 | 234.59,190.23,1254.69,1787.8,30.13,49.35,69.32
455 | 237.52,187.04,1248.7,1769.66,30.67,50.28,70.52
456 | 241.16,190.0,1244.48,1788.15,30.97,50.44,71.72
457 | 242.1,182.01,1240.21,1761.3,31.13,50.72,71.9
458 | 244.51,184.62,1259.11,1771.09,31.45,50.66,72.55
459 | 243.16,185.83,1252.0,1697.55,31.36,51.08,71.97
460 | 247.42,187.2,1275.0,1748.06,31.97,51.94,73.73
461 | 248.97,191.69,1276.0,1774.81,31.94,51.5,73.14
462 | 244.76,189.56,1255.15,1759.12,32.01,51.88,72.75
463 | 247.24,196.7,1260.0,1775.99,31.41,51.77,72.36
464 | 249.54,192.85,1265.8,1788.01,31.7,52.13,72.25
465 | 257.33,194.55,1276.11,1801.01,32.24,52.58,74.94
466 | 257.05,195.37,1291.2,1809.16,32.51,52.74,75.19
467 | 256.77,194.03,1290.09,1801.0,32.76,53.29,74.42
468 | 258.74,191.91,1294.28,1803.76,33.11,53.78,75.41
469 | 258.69,190.0,1301.52,1787.89,33.07,53.83,75.48
470 | 258.3,189.93,1304.0,1778.0,33.03,53.79,75.45
471 | 261.55,190.0,1298.57,1774.66,33.13,53.75,75.55
472 | 261.13,194.7,1293.18,1773.39,32.72,53.81,74.25
473 | 263.75,192.93,1295.0,1751.43,32.69,53.22,73.61
474 | 263.68,194.26,1315.05,1760.05,32.92,53.78,74.34
475 | 265.8,194.56,1332.34,1738.3,32.86,53.84,74.29
476 | 267.9,197.4,1326.63,1756.99,33.12,54.1,74.97
477 | 265.54,198.58,1311.36,1749.14,32.79,53.73,74.63
478 | 263.69,197.42,1299.25,1743.0,32.78,53.84,74.08
479 | 262.59,198.38,1303.0,1739.02,32.96,53.9,74.1
480 | 262.71,199.515,1296.26,1753.25,33.33,54.53,74.93
481 | 266.94,200.0,1309.91,1779.92,33.38,54.11,75.84
482 | 265.58,199.9,1315.42,1801.0,33.49,54.15,75.84
483 | 266.6,201.6,1306.6,1817.78,33.37,54.07,75.43
484 | 267.27,202.13,1302.56,1804.4,33.45,54.31,75.42
485 | 258.31,197.6,1278.66,1760.0,32.87,53.01,73.38
486 | 261.07,200.0,1306.1,1774.01,33.08,52.6,73.83
487 | 263.79,199.86,1327.0,1763.5,33.16,53.41,74.65
488 | 267.48,200.5,1332.75,1751.2,33.68,53.86,75.93
489 | 270.0,200.65,1338.86,1750.66,33.5,54.17,75.18
490 | 268.6,201.66,1339.94,1747.4,33.4,53.49,75.07
491 | 268.81,200.28,1348.3,1741.67,33.48,53.74,76.12
492 | 267.78,202.35,1343.21,1750.0,33.78,53.37,75.81
493 | 271.46,196.4,1347.9,1765.0,34.69,54.05,77.05
494 | 277.0,195.27,1355.0,1767.0,34.95,54.24,77.36
495 | 279.57,198.84,1362.41,1778.01,34.85,54.11,77.29
496 | 279.8,200.09,1357.0,1795.02,35.11,54.46,77.7
497 | 279.5,202.78,1351.91,1780.5,35.15,53.74,78.0
498 | 282.23,207.48,1363.1,1799.62,35.24,54.05,78.94
499 | 280.53,206.7,1358.73,1788.26,35.04,53.34,78.67
500 | 284.69,206.3,1350.21,1793.81,35.19,53.95,78.7
501 | 284.82,205.5665,1346.55,1801.01,35.32,54.05,78.75
502 | 291.12,208.6697,1364.0,1882.92,35.7,54.29,80.0
503 | 289.46,207.86,1356.81,1874.0,35.57,54.17,80.15
504 | 289.93,203.995,1335.79,1842.0,35.03,53.53,79.32
505 | 296.24,206.75,1348.41,1875.0,35.35,53.85,80.13
506 | 297.15,207.2135,1348.0,1864.5,34.98,53.11,79.8
507 | 293.79,206.92,1351.63,1860.0,34.41,52.74,78.72
508 | 299.84,212.82,1400.46,1904.5,34.7,53.05,79.29
509 | 297.16,213.0,1394.82,1898.04,34.57,52.84,78.77
510 | 307.235,217.54,1421.93,1909.89,35.3,53.2,80.98
511 | 310.6,219.2,1429.47,1905.37,35.0,52.79,80.0
512 | 311.64,219.5965,1435.25,1891.31,34.84,52.5,79.5
513 | 316.7,221.61,1440.0,1885.88,35.3,50.23,81.2
514 | 311.85,220.61,1433.02,1872.25,34.765,48.83,81.73
515 | 313.59,222.57,1445.45,1882.99,34.9,48.46,81.96
516 | 316.27,222.03,1462.54,1885.89,34.92,49.37,81.16
517 | 317.19,222.155,1479.0,1865.0,34.42,49.09,80.48
518 | 318.58,222.31,1489.73,1896.09,34.37,49.03,80.2
519 | 317.92,220.75,1487.55,1885.11,34.09,48.39,79.58
520 | 320.25,220.8,1492.82,1891.37,34.12,48.19,79.62
521 | 310.06,213.1,1431.54,1820.0,32.85,46.89,76.26
522 | 312.6,216.14,1441.74,1840.5,33.02,47.51,77.21
523 | 324.45,221.44,1458.46,1864.0,33.33,47.42,77.54
524 | 320.5435,206.53,1438.1,1858.0,32.7,47.17,75.74
525 | 320.93,208.43,1467.86,2051.47,33.07,47.42,75.96
526 | 304.3,203.44,1461.65,2010.6,33.0,47.24,74.7
527 | 315.31,206.6165,1454.49,2029.88,33.56,47.7,76.75
528 | 323.52,212.51,1463.61,2071.02,34.1,47.9,77.92
529 | 322.57,210.47,1451.98,2041.02,34.94,48.44,79.8
530 | 322.37,210.3,1467.38,2041.99,34.32,47.73,78.13
531 | 314.18,211.52,1477.23,2085.01,34.44,47.67,78.08
532 | 323.6,210.19,1513.27,2150.9,34.85,48.08,78.75
533 | 321.47,207.85,1515.86,2163.2,35.08,48.22,79.9
534 | 324.19,209.5235,1510.0,2144.99,34.76,47.62,78.89
535 | 324.73,214.0,1514.53,2155.68,34.88,48.14,78.89
536 | 315.36,213.55,1514.34,2125.02,34.77,47.97,78.61
537 | 320.0,217.99,1527.2,2167.8,34.45,47.25,77.87
538 | 322.63,216.52,1519.01,2173.07,34.46,47.0,77.66
539 | 318.62,213.48,1504.58,2142.15,34.53,47.48,77.56
540 | 297.26,201.8,1423.05,2003.18,33.18,46.58,73.38
541 | 300.95,202.27,1431.0,2026.42,32.69,46.29,72.63
542 | 286.53,197.19,1394.98,1970.28,31.39,45.48,70.02
543 | 281.1,191.82,1359.14,1934.38,29.55,43.32,66.1
544 | 257.26,182.695,1274.31,1814.63,28.0,41.31,62.0
545 | 282.28,194.03,1351.39,1906.49,28.35,40.98,63.85
546 | 303.67,196.22,1397.68,1975.37,29.37,42.06,67.86
547 | 296.44,189.17,1358.96,1946.57,28.25,41.01,66.05
548 | 295.52,186.78,1345.55,1933.0,27.24,40.0,64.8
549 | 282.0,178.33,1269.95,1875.0,25.47,37.0,60.46
550 | 263.75,169.6,1204.96,1773.86,22.23,33.72,54.31
551 | 277.14,174.67,1254.39,1870.88,23.25,34.63,54.73
552 | 277.39,174.01,1248.27,1857.85,22.84,34.05,53.95
553 | 255.94,159.54,1122.62,1721.98,20.59,29.81,45.3
554 | 264.89,163.53,1174.99,1755.0,22.19,30.15,47.82
555 | 241.95,152.32,1089.61,1641.51,19.85,26.34,40.49
556 | 247.51,150.74,1090.64,1775.47,21.06,27.63,42.0
557 | 239.77,139.75,1059.94,1750.0,20.27,27.7,37.06
558 | 247.385,146.62,1088.22,1860.0,20.26,27.66,35.47
559 | 247.18,156.02,1130.9,1926.31,21.76,28.68,40.46
560 | 228.08,149.66,1056.37,1827.75,19.26,26.26,37.55
561 | 236.36,155.205,1103.98,1952.01,19.42,26.96,37.65
562 | 250.75,158.92,1124.58,1920.69,21.71,29.0,42.31
563 | 246.52,158.25,1114.72,1902.0,21.31,29.33,43.68
564 | 252.75,158.2,1127.47,1930.86,21.69,30.02,44.13
565 | 250.74,159.18,1132.64,1922.83,21.65,30.36,44.05
566 | 255.6,165.48,1148.73,1964.35,21.82,29.41,43.63
567 | 246.5,161.615,1124.0,1932.97,19.93,27.0197,39.14
568 | 240.34,159.1,1100.0,1901.64,19.65,26.47,38.36
569 | 242.8,157.15,1114.71,1911.15,20.4,27.0,39.0
570 | 250.9,160.15,1133.0,1936.0,21.03,27.41,39.8
571 | 270.8,171.79,1217.01,2017.11,22.8,30.75,44.74
572 | 262.74,171.25,1203.1,2021.0,22.41,29.34,42.85
573 | 268.7,175.9,1218.18,2044.3,24.07,31.12,46.94
574 | 268.31,173.67,1201.5,2040.0,24.78,33.22,47.5
575 | 280.0,178.9765,1239.97,2200.47,24.5,32.11,47.66
576 | 282.4,175.1865,1246.51,2257.68,22.16,28.77,43.37
577 | 287.38,177.95,1267.14,2346.0,22.15,28.28,42.71
578 | 284.69,179.2,1281.7,2372.33,22.34,28.15,43.15
579 | 277.95,177.41,1269.89,2389.95,22.57,27.325,43.395
580 | 276.28,175.25,1242.71,2416.61,21.9,26.9,42.35
581 | 273.61,178.45,1241.11,2369.0,22.16,27.5,43.0
582 | 275.87,184.08,1265.74,2399.98,21.96,26.95,42.65
583 | 277.2,183.23,1255.0,2417.0,22.11,26.8,43.0
584 | 281.8,192.99,1292.0,2443.2,22.52,27.37,44.17
585 | 285.08,188.66,1283.2,2372.1,24.45,29.6,48.94
586 | 284.73,190.93,1345.0,2330.01,24.91,30.1,49.7
587 | 289.96,206.92,1331.36,2419.84,24.21,29.32,49.07
588 | 286.25,201.6,1324.09,2336.8,23.38,28.5,46.31
589 | 289.17,200.2,1308.13,2256.38,22.7,26.96,45.03
590 | 295.06,207.02,1337.5,2340.0,23.48,27.52,46.3
591 | 300.46,208.12,1358.0,2329.44,23.0,26.46,44.49
592 | 303.22,211.16,1361.31,2374.78,22.66,25.59,43.52
593 | 305.64,212.24,1381.82,2372.14,23.47,25.64,45.32
594 | 308.1,210.8865,1376.79,2374.7,23.11,25.11,45.21
595 | 317.83,213.29,1408.22,2411.85,22.71,24.96,44.39
596 | 312.15,209.43,1376.16,2366.8,21.66,23.95,42.0
597 | 304.51,202.56,1333.52,2361.01,20.29,22.07,39.99
598 | 300.35,205.27,1348.26,2368.52,21.4,23.69,41.58
599 | 313.17,212.15,1361.58,2402.48,22.42,24.55,44.05
600 | 315.03,213.27,1385.48,2429.83,22.66,25.0,45.27
601 | 316.68,223.5,1389.16,2477.87,22.68,24.49,45.57
602 | 318.66,234.72,1410.99,2500.0,22.81,24.39,45.17
603 | 315.77,231.51,1403.9,2455.01,22.93,24.44,44.77
604 | 323.5,239.77,1441.96,2458.0,23.75,25.05,46.2
605 | 316.14,229.07,1420.0,2404.99,26.07,27.8,51.68
606 | 316.77,224.3,1400.0,2384.33,26.08,28.32,52.99
607 | 319.25,225.2,1420.43,2415.94,24.42,26.5,48.02
608 | 317.75,224.59,1425.7,2448.0,24.28,26.61,48.14
609 | 320.745,230.94,1435.0,2467.0,24.96,27.58,50.71
610 | 324.66,232.11,1442.7,2468.01,25.5,28.39,52.56
611 | 324.39,229.56,1436.78,2477.43,25.71,29.48,53.3
612 | 323.35,226.71,1415.64,2444.51,28.95,33.89,61.57
613 | 330.25,229.03,1426.28,2500.2,28.59,32.9,60.66
614 | 332.14,231.52,1445.24,2529.44,27.72,32.44,59.0
615 | 347.9,240.96,1461.51,2645.0,27.97,32.3,58.9
616 | 349.31,229.94,1441.03,2603.5,24.98,27.2,51.67
617 | 344.72,229.9,1425.86,2601.21,25.03,28.0,51.4
618 | 333.25,225.09,1389.49,2526.6,23.76,26.86,49.96
619 | 351.46,237.14,1449.0,2620.0,26.18,29.43,56.3
620 | 355.15,235.0,1452.94,2647.5,25.9,28.5,54.7
621 | 351.41,234.99,1449.85,2647.01,24.7,27.1,52.67
622 |
--------------------------------------------------------------------------------