├── tests ├── __init__.py └── test_fcm.py ├── docs ├── reference.md ├── examples │ ├── images │ │ ├── oarsman.jpeg │ │ ├── distances.jpg │ │ ├── oarsman_10colors.jpg │ │ └── basic-clustering-output.jpg │ ├── 00 - Basic clustering.ipynb │ ├── 02 - Clustering validation.ipynb │ ├── 03 - Using different distances.ipynb │ └── 01 - Colour quantization.ipynb ├── getting-started.md ├── index.md ├── citation.md ├── contributing.md ├── CLI.md ├── requirements.txt └── CHANGELOG.md ├── fcmeans ├── __init__.py ├── cli.py └── main.py ├── CONTRIBUTING.md ├── .github └── workflows │ ├── publish.yml │ ├── release.yml │ └── ci.yml ├── .readthedocs.yaml ├── .gitignore ├── requirements.txt ├── LICENSE ├── mkdocs.yml ├── .pre-commit-config.yaml ├── pyproject.toml └── README.md /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/reference.md: -------------------------------------------------------------------------------- 1 | # Reference 2 | 3 | ::: fcmeans.FCM 4 | -------------------------------------------------------------------------------- /docs/examples/images/oarsman.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omadson/fuzzy-c-means/HEAD/docs/examples/images/oarsman.jpeg -------------------------------------------------------------------------------- /docs/examples/images/distances.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omadson/fuzzy-c-means/HEAD/docs/examples/images/distances.jpg -------------------------------------------------------------------------------- /docs/examples/images/oarsman_10colors.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omadson/fuzzy-c-means/HEAD/docs/examples/images/oarsman_10colors.jpg -------------------------------------------------------------------------------- /docs/examples/images/basic-clustering-output.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omadson/fuzzy-c-means/HEAD/docs/examples/images/basic-clustering-output.jpg -------------------------------------------------------------------------------- /fcmeans/__init__.py: -------------------------------------------------------------------------------- 1 | # flake8: noqa 2 | """fuzzy-c-means - A simple implementation of Fuzzy C-means algorithm.""" 3 | from .main import FCM 4 | 5 | __version__ = "1.7.2" 6 | -------------------------------------------------------------------------------- /docs/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | ## installation 4 | the `fuzzy-c-means` package is available in [PyPI](https://pypi.org/project/fuzzy-c-means/). to install, simply type the following command: 5 | ``` 6 | pip install fuzzy-c-means 7 | ``` 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # contributing 2 | 3 | this project is open for contributions. here are some of the ways for you to contribute: 4 | - bug reports/fix 5 | - features requests 6 | - use-case demonstrations 7 | 8 | to make a contribution, just fork this repository, push the changes in your fork, open up an issue, and make a pull request! 9 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # fuzzy-c-means 2 | 3 | `fuzzy-c-means` is a Python module implementing the Fuzzy C-means[^1] clustering algorithm. 4 | 5 | [^1]: Bezdek, James C., Robert Ehrlich, and William Full. "[FCM: The fuzzy c-means clustering algorithm.](https://doi.org/10.1016/0098-3004(84)90020-7)" _Computers & geosciences_ 10.2-3 (1984): 191-203. 6 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Python package 2 | on: 3 | push: 4 | tags: 5 | - "v*.*.*" 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - name: Build and publish to pypi 12 | uses: JRubics/poetry-publish@v2.0 13 | with: 14 | pypi_token: ${{ secrets.PYPI_TOKEN }} 15 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Required 2 | version: 2 3 | 4 | # Set the version of Python and other tools you might need 5 | build: 6 | os: ubuntu-20.04 7 | tools: 8 | python: "3.9" 9 | 10 | mkdocs: 11 | configuration: mkdocs.yml 12 | 13 | # Optionally declare the Python requirements required to build your docs 14 | python: 15 | install: 16 | - requirements: docs/requirements.txt 17 | -------------------------------------------------------------------------------- /docs/citation.md: -------------------------------------------------------------------------------- 1 | # Citation 2 | if you use `fuzzy-c-means` package in your paper, please cite it in your publication. 3 | ``` 4 | @software{dias2019fuzzy, 5 | author = {Madson Luiz Dantas Dias}, 6 | title = {fuzzy-c-means: An implementation of Fuzzy $C$-means clustering algorithm.}, 7 | month = may, 8 | year = 2019, 9 | publisher = {Zenodo}, 10 | doi = {10.5281/zenodo.3066222}, 11 | url = {https://git.io/fuzzy-c-means} 12 | } 13 | ``` 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | .ipynb_checkpoints/ 6 | 7 | # Packages 8 | *.egg 9 | *.egg-info 10 | dist 11 | build 12 | eggs 13 | parts 14 | bin 15 | var 16 | sdist 17 | develop-eggs 18 | .installed.cfg 19 | lib 20 | lib64 21 | __pycache__ 22 | 23 | # Installer logs 24 | pip-log.txt 25 | 26 | # Unit test / coverage reports 27 | .coverage 28 | .tox 29 | nosetests.xml 30 | 31 | # Translations 32 | *.mo 33 | 34 | # Mr Developer 35 | .mr.developer.cfg 36 | .project 37 | .pydevproject 38 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Semantic Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | concurrency: release 12 | permissions: 13 | id-token: write 14 | contents: write 15 | 16 | steps: 17 | - uses: actions/checkout@v3 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Python Semantic Release 22 | uses: python-semantic-release/python-semantic-release@master 23 | with: 24 | github_token: ${{ secrets.GITHUB_TOKEN }} 25 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | this project is open for contributions. here are some of the ways for you to contribute: 4 | 5 | - bug reports/fix 6 | - features requests 7 | - use-case demonstrations 8 | 9 | please open an [issue](https://github.com/omadson/fuzzy-c-means/issues) with enough information for us to reproduce your problem. A [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) would be very helpful. 10 | 11 | to make a contribution, just fork this repository, push the changes in your fork, open up an issue, and make a pull request! 12 | -------------------------------------------------------------------------------- /tests/test_fcm.py: -------------------------------------------------------------------------------- 1 | """Tests for FCM Class""" 2 | # flake8: noqa 3 | import numpy as np 4 | import pytest 5 | 6 | from fcmeans import FCM 7 | 8 | # some test data 9 | X = np.random.normal(size=(10, 2)) 10 | 11 | 12 | def test_u_creation(): 13 | """Test if its generate u matrix""" 14 | fcm = FCM() 15 | fcm.fit(X) 16 | assert fcm.u is not None 17 | 18 | 19 | def test_dont_fit(): 20 | """Test if its returns Exceptions""" 21 | fcm = FCM() 22 | assert fcm._is_trained() == False 23 | with pytest.raises(ReferenceError): 24 | partition_entropy_coefficient = fcm.partition_entropy_coefficient 25 | with pytest.raises(ReferenceError): 26 | partition_coefficient = fcm.partition_coefficient 27 | with pytest.raises(ReferenceError): 28 | centers = fcm.centers 29 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | annotated-types==0.6.0 ; python_version >= "3.9" and python_version < "4.0" 2 | click==8.1.7 ; python_version >= "3.9" and python_version < "4.0" 3 | colorama==0.4.6 ; python_version >= "3.9" and python_version < "4.0" and platform_system == "Windows" 4 | joblib==1.3.2 ; python_version >= "3.9" and python_version < "4.0" 5 | numpy==1.26.4 ; python_version >= "3.9" and python_version < "4.0" 6 | pydantic-core==2.16.3 ; python_version >= "3.9" and python_version < "4.0" 7 | pydantic==2.6.4 ; python_version >= "3.9" and python_version < "4.0" 8 | tabulate==0.8.10 ; python_version >= "3.9" and python_version < "4.0" 9 | tqdm==4.66.2 ; python_version >= "3.9" and python_version < "4.0" 10 | typer==0.9.0 ; python_version >= "3.9" and python_version < "4.0" 11 | typing-extensions==4.10.0 ; python_version >= "3.9" and python_version < "4.0" 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Madson Dias 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. -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | setup: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | with: 11 | fetch-depth: '0' 12 | - uses: actions/setup-python@v2 13 | - uses: snok/install-poetry@v1 14 | with: 15 | virtualenvs-create: true 16 | virtualenvs-in-project: true 17 | - uses: syphar/restore-virtualenv@v1 18 | id: cache-virtualenv 19 | - run: poetry install 20 | 21 | tests: 22 | needs: setup 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v2 26 | with: 27 | fetch-depth: '0' 28 | - uses: actions/setup-python@v2 29 | - uses: snok/install-poetry@v1 30 | - uses: syphar/restore-virtualenv@v1 31 | id: cache-virtualenv 32 | - run: poetry run pytest --cov=fcmeans 33 | 34 | linter: 35 | needs: setup 36 | runs-on: ubuntu-latest 37 | steps: 38 | - uses: actions/checkout@v2 39 | with: 40 | fetch-depth: '0' 41 | - uses: actions/setup-python@v2 42 | - uses: snok/install-poetry@v1 43 | - uses: syphar/restore-virtualenv@v1 44 | id: cache-virtualenv 45 | - run: | 46 | poetry run black . --line-length=79 47 | poetry run isort **/*.py -c 48 | poetry run flake8 --exclude ".*" 49 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: fuzzy-c-means 2 | plugins: 3 | - mkdocs-jupyter 4 | - search 5 | - mkdocstrings 6 | nav: 7 | - Home: 'index.md' 8 | - 'Getting started': 'getting-started.md' 9 | - 'User Guide': 10 | - 'Command Line Interface': 'CLI.md' 11 | - 'Reference': 'reference.md' 12 | - Examples: 13 | - 'Basic clustering': 'examples/00 - Basic clustering.ipynb' 14 | - 'Colour quantization': 'examples/01 - Colour quantization.ipynb' 15 | - 'Clustering validation': 'examples/02 - Clustering validation.ipynb' 16 | - About: 17 | - 'Citation': 'citation.md' 18 | - 'Changelog': 'CHANGELOG.md' 19 | - 'Contributing': 'contributing.md' 20 | theme: 21 | name: material 22 | icon: 23 | repo: fontawesome/brands/github 24 | palette: 25 | - scheme: default 26 | toggle: 27 | icon: material/toggle-switch-off-outline 28 | name: Switch to dark mode 29 | - scheme: slate 30 | toggle: 31 | icon: material/toggle-switch 32 | name: Switch to light mode 33 | features: 34 | - navigation.sections 35 | markdown_extensions: 36 | - footnotes 37 | - pymdownx.arithmatex: 38 | generic: true 39 | 40 | extra_javascript: 41 | - javascripts/mathjax.js 42 | - https://polyfill.io/v3/polyfill.min.js?features=es6 43 | - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js 44 | repo_url: https://github.com/omadson/fuzzy-c-means 45 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v2.4.0 4 | hooks: 5 | - id: check-ast 6 | - id: check-byte-order-marker 7 | - id: check-case-conflict 8 | - id: check-docstring-first 9 | - id: check-executables-have-shebangs 10 | - id: check-json 11 | - id: check-toml 12 | - id: check-yaml 13 | - id: debug-statements 14 | - id: detect-private-key 15 | - id: end-of-file-fixer 16 | - id: trailing-whitespace 17 | - id: mixed-line-ending 18 | - id: check-added-large-files 19 | - repo: https://github.com/asottile/blacken-docs 20 | rev: v1.8.0 21 | hooks: 22 | - id: blacken-docs 23 | additional_dependencies: [black==20.8b1] 24 | - repo: https://github.com/pre-commit/mirrors-isort 25 | rev: v5.4.2 26 | hooks: 27 | - id: isort 28 | - repo: https://github.com/asottile/pyupgrade 29 | rev: v2.7.2 30 | hooks: 31 | - id: pyupgrade 32 | args: [--py36-plus] 33 | - repo: https://github.com/pre-commit/mirrors-mypy 34 | rev: v0.782 35 | hooks: 36 | - id: mypy 37 | args: [--ignore-missing-imports] 38 | - repo: https://gitlab.com/pycqa/flake8 39 | rev: '3.8.3' 40 | hooks: 41 | - id: flake8 42 | - repo: https://github.com/GussSoares/create-requirements 43 | rev: 'v0.1.0' 44 | hooks: 45 | - id: create-requirements 46 | - repo: https://github.com/compilerla/conventional-pre-commit 47 | rev: 'v1.2.0' 48 | hooks: 49 | - id: conventional-pre-commit 50 | stages: [commit-msg] 51 | - repo: https://github.com/econchick/interrogate 52 | rev: 1.5.0 53 | hooks: 54 | - id: interrogate 55 | args: [-vv, --fail-under=80, --config=pyproject.toml] 56 | - repo: local 57 | hooks: 58 | - id: pytest coverage 59 | name: Check pytest coverage 60 | entry: poetry run pytest --cov=fcmeans 61 | pass_filenames: false 62 | language: system 63 | types: [python] 64 | -------------------------------------------------------------------------------- /docs/CLI.md: -------------------------------------------------------------------------------- 1 | # `fcm` 2 | 3 | Fuzzy C-means 4 | 5 | Fit and use fuzzy-c-means models to clustering. 6 | 7 | You probably want to install completion for the typer command. 8 | If you are using bash, try to type: 9 | 10 | $ fcm --install-completion bash 11 | 12 | https://github.com/omadson/fuzzy-c-means 13 | 14 | **Usage**: 15 | 16 | ```console 17 | $ fcm [OPTIONS] COMMAND [ARGS]... 18 | ``` 19 | 20 | **Options**: 21 | 22 | * `--install-completion`: Install completion for the current shell. 23 | * `--show-completion`: Show completion for the current shell, to copy it or customize the installation. 24 | * `--help`: Show this message and exit. 25 | 26 | **Commands**: 27 | 28 | * `fit`: Train and save a fuzzy-c-means model given a... 29 | * `predict`: Predict labels given a data set and a... 30 | 31 | ## `fcm fit` 32 | 33 | Train and save a fuzzy-c-means model given a dataset. 34 | 35 | **Usage**: 36 | 37 | ```console 38 | $ fcm fit [OPTIONS] [DATASET_PATH] [MODEL_PATH] 39 | ``` 40 | 41 | **Arguments**: 42 | 43 | * `[DATASET_PATH]`: Data set file path (only .csv). [default: dataset.csv] 44 | * `[MODEL_PATH]`: Path to save the created model. [default: model.sav] 45 | 46 | **Options**: 47 | 48 | * `-d, --delimiter TEXT`: Delimiter of data set file. [default: ,] 49 | * `-c, --clusters INTEGER RANGE`: Number of clusters. [default: 2] 50 | * `-e, --exponent FLOAT RANGE`: Fuzzy partition exponent. [default: 2.0] 51 | * `-m, --max-iter INTEGER RANGE`: Maximum number of iterations. [default: 150] 52 | * `-t, --tolerance FLOAT RANGE`: Stop Tolerance criteria. [default: 1e-05] 53 | * `-s, --seed INTEGER`: Seed for the random number generator. 54 | * `-q, --quiet`: Suppress model info. [default: False] 55 | * `-p, --predict`: Prediction flag. [default: False] 56 | * `--help`: Show this message and exit. 57 | 58 | ## `fcm predict` 59 | 60 | Predict labels given a data set and a fuzzy-c-means saved model. 61 | 62 | **Usage**: 63 | 64 | ```console 65 | $ fcm predict [OPTIONS] [DATASET_PATH] [MODEL_PATH] 66 | ``` 67 | 68 | **Arguments**: 69 | 70 | * `[DATASET_PATH]`: Data set file path (only .csv). [default: dataset.csv] 71 | * `[MODEL_PATH]`: Path to save the created model. [default: model.sav] 72 | 73 | **Options**: 74 | 75 | * `-d, --delimiter TEXT`: Delimiter of data set file. [default: ,] 76 | * `-q, --quiet`: Suppress model info. [default: False] 77 | * `--help`: Show this message and exit. 78 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "fuzzy-c-means" 3 | version = "1.7.2" 4 | description = "A simple python implementation of Fuzzy C-means algorithm." 5 | authors = ["Madson Dias "] 6 | 7 | 8 | license = "MIT" 9 | readme = "README.md" 10 | documentation = "https://fuzzy-c-means.readthedocs.io/en/latest/" 11 | repository = "https://github.com/omadson/fuzzy-c-means" 12 | keywords = ["machine-learning", "data-science", "fuzzy-c-means", "clustering"] 13 | classifiers = [ 14 | "Operating System :: OS Independent", 15 | "Topic :: Software Development :: Libraries :: Python Modules", 16 | ] 17 | include = [ 18 | "LICENSE", 19 | ] 20 | 21 | packages = [ 22 | { include = "fcmeans" } 23 | ] 24 | 25 | 26 | [tool.poetry.dependencies] 27 | python = "^3.9" 28 | numpy = "^1.21.1" 29 | tabulate = "^0.8.9" 30 | tqdm = "^4.64.1" 31 | joblib = "^1.2.0" 32 | pydantic = "^2.6.4" 33 | typer = "^0.9.0" 34 | 35 | [tool.poetry.group.dev.dependencies] 36 | pre-commit = "^3.6.2" 37 | matplotlib = "^3.8.3" 38 | jupyterlab = "^4.1.5" 39 | pytest = "^8.1.1" 40 | pytest-cov = "^4.1.0" 41 | flake8 = "^7.0.0" 42 | isort = "^5.13.2" 43 | mypy = "^1.9.0" 44 | python-semantic-release = "^9.2.0" 45 | black = "^24.3.0" 46 | interrogate = "^1.5.0" 47 | mkdocs = "^1.5.3" 48 | mkdocs-material = "^9.5.14" 49 | mkdocs-jupyter = "^0.24.6" 50 | mkdocstrings = "^0.24.1" 51 | mkdocstrings-python-legacy = "^0.2.3" 52 | 53 | [build-system] 54 | requires = ["poetry-core>=1.0.0"] 55 | build-backend = "poetry.core.masonry.api" 56 | 57 | [tool.poetry.scripts] 58 | fcm = 'fcmeans.cli:app' 59 | 60 | 61 | [tool.semantic_release] 62 | version_variables = [ 63 | 'fcmeans/__init__.py:__version__', 64 | ] 65 | version_toml = ["pyproject.toml:tool.poetry.version"] 66 | [tool.semantic_release.branches.main] 67 | match = "(main|master)" 68 | prerelease_token = "rc" 69 | prerelease = false 70 | build_command = "poetry build" 71 | 72 | [tool.semantic_release.publish] 73 | upload_to_vcs_release = true 74 | 75 | [tool.semantic_release.changelog] 76 | changelog_file = "docs/CHANGELOG.md" 77 | 78 | [mypy] 79 | plugins = ['numpy.typing.mypy_plugin'] 80 | 81 | [tool.coverage.report] 82 | omit = ['fcmeans/my_typing.py', 'fcmeans/__init__.py', 'fcmeans/cli.py'] 83 | fail_under = 70 84 | 85 | [tool.interrogate] 86 | ignore-init-method = true 87 | ignore-init-module = false 88 | ignore-magic = false 89 | ignore-semiprivate = true 90 | ignore-private = true 91 | ignore-property-decorators = true 92 | ignore-module = false 93 | ignore-nested-functions = false 94 | ignore-nested-classes = true 95 | ignore-setters = false 96 | fail-under = 95 97 | exclude = ["setup.py", "docs", "build"] 98 | ignore-regex = ["^get$", "^mock_.*", ".*BaseClass.*"] 99 | verbose = 2 100 | quiet = false 101 | whitelist-regex = [] 102 | color = true 103 | omit-covered-files = false 104 | -------------------------------------------------------------------------------- /docs/examples/00 - Basic clustering.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Basic clustering\n", 8 | "## importing libraries" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "metadata": {}, 15 | "outputs": [], 16 | "source": [ 17 | "%matplotlib inline\n", 18 | "import numpy as np\n", 19 | "from fcmeans import FCM\n", 20 | "from matplotlib import pyplot as plt" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "metadata": {}, 26 | "source": [ 27 | "## creating artificial data set" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "n_samples = 3000\n", 37 | "\n", 38 | "X = np.concatenate((\n", 39 | " np.random.normal((-2, -2), size=(n_samples, 2)),\n", 40 | " np.random.normal((2, 2), size=(n_samples, 2))\n", 41 | "))\n", 42 | "\n", 43 | "plt.figure(figsize=(5, 5))\n", 44 | "plt.scatter(X[:,0], X[:,1], alpha=.1)\n", 45 | "plt.show()" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "# fitting the fuzzy-c-means" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "fcm = FCM(n_clusters=2)\n", 62 | "fcm.fit(X)" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": {}, 68 | "source": [ 69 | "# showing results" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [ 78 | "# outputs\n", 79 | "fcm_centers = fcm.centers\n", 80 | "fcm_labels = fcm.predict(X)\n", 81 | "\n", 82 | "# plot result\n", 83 | "f, axes = plt.subplots(1, 2, figsize=(11,5))\n", 84 | "axes[0].scatter(X[:,0], X[:,1], alpha=.1)\n", 85 | "axes[1].scatter(X[:,0], X[:,1], c=fcm_labels, alpha=.1)\n", 86 | "axes[1].scatter(fcm_centers[:,0], fcm_centers[:,1], marker=\"+\", s=500, c='w')\n", 87 | "plt.savefig('images/basic-clustering-output.jpg')\n", 88 | "plt.show()" 89 | ] 90 | } 91 | ], 92 | "metadata": { 93 | "kernelspec": { 94 | "display_name": "Python 3 (ipykernel)", 95 | "language": "python", 96 | "name": "python3" 97 | }, 98 | "language_info": { 99 | "codemirror_mode": { 100 | "name": "ipython", 101 | "version": 3 102 | }, 103 | "file_extension": ".py", 104 | "mimetype": "text/x-python", 105 | "name": "python", 106 | "nbconvert_exporter": "python", 107 | "pygments_lexer": "ipython3", 108 | "version": "3.10.10" 109 | } 110 | }, 111 | "nbformat": 4, 112 | "nbformat_minor": 4 113 | } 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fuzzy-c-means 2 | 3 | ![GitHub](https://img.shields.io/github/license/omadson/fuzzy-c-means.svg) 4 | [![PyPI](https://img.shields.io/pypi/v/fuzzy-c-means.svg)](http://pypi.org/project/fuzzy-c-means/) 5 | [![Documentation Status](https://readthedocs.org/projects/fuzzy-c-means/badge/?version=latest)](https://fuzzy-c-means.readthedocs.io/en/latest/?badge=latest) 6 | [![GitHub last commit](https://img.shields.io/github/last-commit/omadson/fuzzy-c-means.svg)](https://github.com/omadson/fuzzy-c-means/commit/master) 7 | [![Downloads](https://pepy.tech/badge/fuzzy-c-means)](https://pepy.tech/project/fuzzy-c-means) 8 | [![DOI](https://zenodo.org/badge/186457481.svg)](https://zenodo.org/badge/latestdoi/186457481) 9 | 10 | 11 | **[Documentation](https://fuzzy-c-means.readthedocs.io/)** | **[Changelog](https://fuzzy-c-means.readthedocs.io/en/latest/CHANGELOG/)** | **[Citation](https://fuzzy-c-means.readthedocs.io/en/latest/citation/)** 12 | 13 | 14 | 15 | `fuzzy-c-means` is a Python module implementing the [Fuzzy C-means][1] clustering algorithm. 16 | 17 | ## installation 18 | the `fuzzy-c-means` package is available in [PyPI](https://pypi.org/project/fuzzy-c-means/). to install, simply type the following command: 19 | ``` 20 | pip install fuzzy-c-means 21 | ``` 22 | ## citation 23 | if you use `fuzzy-c-means` package in your paper, please cite it in your publication. 24 | ``` 25 | @software{dias2019fuzzy, 26 | author = {Madson Luiz Dantas Dias}, 27 | title = {fuzzy-c-means: An implementation of Fuzzy $C$-means clustering algorithm.}, 28 | month = may, 29 | year = 2019, 30 | publisher = {Zenodo}, 31 | doi = {10.5281/zenodo.3066222}, 32 | url = {https://git.io/fuzzy-c-means} 33 | } 34 | ``` 35 | 36 | 45 | 46 | 47 | ## contributing and support 48 | 49 | this project is open for contributions. here are some of the ways for you to contribute: 50 | - bug reports/fix 51 | - features requests 52 | - use-case demonstrations 53 | 54 | please open an [issue](https://github.com/omadson/fuzzy-c-means/issues) with enough information for us to reproduce your problem. A [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) would be very helpful. 55 | 56 | to make a contribution, just fork this repository, push the changes in your fork, open up an issue, and make a pull request! 57 | 58 | 62 | 63 | [1]: https://doi.org/10.1016/0098-3004(84)90020-7 64 | [2]: http://scikit-learn.org/ 65 | -------------------------------------------------------------------------------- /docs/examples/02 - Clustering validation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Clustering validation\n", 8 | "## importing libraries" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "metadata": {}, 15 | "outputs": [], 16 | "source": [ 17 | "%matplotlib inline\n", 18 | "import numpy as np\n", 19 | "from fcmeans import FCM\n", 20 | "from matplotlib import pyplot as plt" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "metadata": {}, 26 | "source": [ 27 | "## creating artificial data set" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "n_samples = 3000\n", 37 | "\n", 38 | "X = np.concatenate((\n", 39 | " np.random.normal((-2, -2), size=(n_samples, 2)),\n", 40 | " np.random.normal((2, 2), size=(n_samples, 2)),\n", 41 | " np.random.normal((9, 0), size=(n_samples, 2)),\n", 42 | " np.random.normal((5, -8), size=(n_samples, 2))\n", 43 | "))\n", 44 | "\n", 45 | "plt.figure(figsize=(5, 5))\n", 46 | "plt.scatter(X[:,0], X[:,1], alpha=.1)\n", 47 | "plt.show()" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "# fitting the fuzzy-c-means\n", 55 | " - create models with 2, 3, 4, 5, 6 and 6 centers" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "n_clusters_list = [2, 3, 4, 5, 6, 7]\n", 65 | "models = list()\n", 66 | "for n_clusters in n_clusters_list:\n", 67 | " fcm = FCM(n_clusters=n_clusters)\n", 68 | " fcm.fit(X)\n", 69 | " models.append(fcm)" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": {}, 75 | "source": [ 76 | "# showing results" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "# outputs\n", 86 | "num_clusters = len(n_clusters_list)\n", 87 | "rows = int(np.ceil(np.sqrt(num_clusters)))\n", 88 | "cols = int(np.ceil(num_clusters / rows))\n", 89 | "f, axes = plt.subplots(rows, cols, figsize=(11,16))\n", 90 | "for n_clusters, model, axe in zip(n_clusters_list, models, axes.ravel()):\n", 91 | " # get validation metrics\n", 92 | " pc = model.partition_coefficient\n", 93 | " pec = model.partition_entropy_coefficient\n", 94 | " \n", 95 | " fcm_centers = model.centers\n", 96 | " fcm_labels = model.predict(X)\n", 97 | " # plot result\n", 98 | " axe.scatter(X[:,0], X[:,1], c=fcm_labels, alpha=.1)\n", 99 | " axe.scatter(fcm_centers[:,0], fcm_centers[:,1], marker=\"+\", s=500, c='black')\n", 100 | " axe.set_title(f'n_clusters = {n_clusters}, PC = {pc:.3f}, PEC = {pec:.3f}')\n", 101 | "plt.show()" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "note that the model with 4 clusters obtained the highest partition coefficient (PC) value and the lowerst partition entropy coefficient (PEC) value for this example. " 109 | ] 110 | } 111 | ], 112 | "metadata": { 113 | "kernelspec": { 114 | "display_name": "Python 3 (ipykernel)", 115 | "language": "python", 116 | "name": "python3" 117 | }, 118 | "language_info": { 119 | "codemirror_mode": { 120 | "name": "ipython", 121 | "version": 3 122 | }, 123 | "file_extension": ".py", 124 | "mimetype": "text/x-python", 125 | "name": "python", 126 | "nbconvert_exporter": "python", 127 | "pygments_lexer": "ipython3", 128 | "version": "3.10.10" 129 | } 130 | }, 131 | "nbformat": 4, 132 | "nbformat_minor": 4 133 | } 134 | -------------------------------------------------------------------------------- /docs/examples/03 - Using different distances.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Basic clustering\n", 8 | "## importing libraries" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "metadata": {}, 15 | "outputs": [], 16 | "source": [ 17 | "%matplotlib inline\n", 18 | "import numpy as np\n", 19 | "from fcmeans import FCM\n", 20 | "from matplotlib import pyplot as plt" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "metadata": {}, 26 | "source": [ 27 | "## creating artificial data set" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "n_samples = 3000\n", 37 | "\n", 38 | "X = np.concatenate((\n", 39 | " np.random.normal((-2, -2), size=(n_samples, 2)),\n", 40 | " np.random.normal((2, 2), size=(n_samples, 2)),\n", 41 | " np.random.normal((0, 4), size=(n_samples, 2))\n", 42 | "))\n", 43 | "\n", 44 | "plt.figure(figsize=(5, 5))\n", 45 | "plt.scatter(X[:,0], X[:,1], alpha=.1)\n", 46 | "plt.show()" 47 | ] 48 | }, 49 | { 50 | "attachments": {}, 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "# fitting the fuzzy-c-means using several types of distance" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "fcm_cosine = FCM(n_clusters=3, distance='cosine', random_state=42)\n", 64 | "fcm_minkowski = FCM(n_clusters=3, distance='minkowski', distance_params={'p': 1}, random_state=42)\n", 65 | "fcm_euclidean = FCM(n_clusters=3)\n", 66 | "\n", 67 | "fcm_cosine.fit(X)\n", 68 | "fcm_minkowski.fit(X)\n", 69 | "fcm_euclidean.fit(X)" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": {}, 75 | "source": [ 76 | "# showing results" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "# plot result\n", 86 | "f, axes = plt.subplots(2, 2, figsize=(11,11))\n", 87 | "axes[0, 0].scatter(X[:,0], X[:,1], alpha=.1)\n", 88 | "axes[0, 0].set_title(\"Original data set\")\n", 89 | "\n", 90 | "# cosine\n", 91 | "fcm_cosine_centers = fcm_cosine.centers\n", 92 | "fcm_cosine_labels = fcm_cosine.predict(X)\n", 93 | "axes[0, 1].scatter(X[:,0], X[:,1], c=fcm_cosine_labels, alpha=.1)\n", 94 | "axes[0, 1].scatter(fcm_cosine_centers[:,0], fcm_cosine_centers[:,1], marker=\"+\", s=500, c='w')\n", 95 | "axes[0, 1].set_title(\"Cosine similarity\")\n", 96 | "\n", 97 | "# minkowski\n", 98 | "fcm_minkowski_centers = fcm_minkowski.centers\n", 99 | "fcm_minkowski_labels = fcm_minkowski.predict(X)\n", 100 | "axes[1, 0].scatter(X[:,0], X[:,1], c=fcm_minkowski_labels, alpha=.1)\n", 101 | "axes[1, 0].scatter(fcm_minkowski_centers[:,0], fcm_minkowski_centers[:,1], marker=\"+\", s=500, c='w')\n", 102 | "axes[1, 0].set_title(\"Minkowski distance (p=1)\")\n", 103 | "\n", 104 | "# euclidean\n", 105 | "fcm_euclidean_centers = fcm_euclidean.centers\n", 106 | "fcm_euclidean_labels = fcm_euclidean.predict(X)\n", 107 | "axes[1, 1].scatter(X[:,0], X[:,1], c=fcm_euclidean_labels, alpha=.1)\n", 108 | "axes[1, 1].scatter(fcm_euclidean_centers[:,0], fcm_euclidean_centers[:,1], marker=\"+\", s=500, c='w')\n", 109 | "axes[1, 1].set_title(\"Euclidean distance\")\n", 110 | "\n", 111 | "plt.savefig('images/distances.jpg')\n", 112 | "plt.show()" 113 | ] 114 | } 115 | ], 116 | "metadata": { 117 | "kernelspec": { 118 | "display_name": "Python 3.9.7 ('.venv': poetry)", 119 | "language": "python", 120 | "name": "python3" 121 | }, 122 | "language_info": { 123 | "codemirror_mode": { 124 | "name": "ipython", 125 | "version": 3 126 | }, 127 | "file_extension": ".py", 128 | "mimetype": "text/x-python", 129 | "name": "python", 130 | "nbconvert_exporter": "python", 131 | "pygments_lexer": "ipython3", 132 | "version": "3.10.10" 133 | }, 134 | "vscode": { 135 | "interpreter": { 136 | "hash": "36847eb9e4823506b276005e97c8ce098bb3d2e74aa52f09327d3369dc00854c" 137 | } 138 | } 139 | }, 140 | "nbformat": 4, 141 | "nbformat_minor": 4 142 | } 143 | -------------------------------------------------------------------------------- /docs/examples/01 - Colour quantization.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Color quantization\n", 8 | "## importing libraries" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "metadata": {}, 15 | "outputs": [], 16 | "source": [ 17 | "import numpy as np\n", 18 | "from PIL import Image\n", 19 | "from fcmeans import FCM" 20 | ] 21 | }, 22 | { 23 | "cell_type": "markdown", 24 | "metadata": {}, 25 | "source": [ 26 | "## Getting and rescaling the image" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "image = Image.open('images/oarsman.jpeg') # read image (oarsman at https://omadson.github.io/photos/)\n", 36 | "N, M = image.size # get the number of columns (N) and rows (M)\n", 37 | "image # show resized image" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "## Transforming image into a data set" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": null, 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "X = (\n", 54 | " np.asarray(image) # convert a PIL image to np array\n", 55 | " .reshape((N*M, 3)) # reshape the image to convert each pixel to an instance of a data set\n", 56 | ")" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "## Creating and fitting the model" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": null, 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [ 72 | "fcm = FCM(n_clusters=10) # create a FCM instance with 10 clusters\n", 73 | "fcm.fit(X) # fit the model" 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": {}, 79 | "source": [ 80 | "## Pixel quantization" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": null, 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "labeld_X = fcm.predict(X) # get the label of each data point\n", 90 | "transformed_X = fcm.centers[labeld_X] # pixel quantization into the centers" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "metadata": {}, 96 | "source": [ 97 | "# Converting and saving image" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "metadata": {}, 104 | "outputs": [], 105 | "source": [ 106 | "quatized_array = (\n", 107 | " transformed_X\n", 108 | " .astype('uint8') # convert data points into 8-bit unsigned integers\n", 109 | " .reshape((M, N, 3)) # reshape image\n", 110 | ")\n", 111 | "\n", 112 | "quatized_image = Image.fromarray(np.asarray(quatized_array)) # convert array into a PIL image object\n", 113 | "quatized_image.save('images/oarsman_10colors.jpg') # save image" 114 | ] 115 | }, 116 | { 117 | "cell_type": "markdown", 118 | "metadata": {}, 119 | "source": [ 120 | "## Final result\n", 121 | "### Original / Quantized" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": null, 127 | "metadata": {}, 128 | "outputs": [], 129 | "source": [ 130 | "side_by_side = Image.fromarray(\n", 131 | " np.hstack([\n", 132 | " np.array(image),\n", 133 | " np.array(quatized_image)\n", 134 | " ])\n", 135 | ")\n", 136 | "side_by_side" 137 | ] 138 | } 139 | ], 140 | "metadata": { 141 | "kernelspec": { 142 | "display_name": "Python 3 (ipykernel)", 143 | "language": "python", 144 | "name": "python3" 145 | }, 146 | "language_info": { 147 | "codemirror_mode": { 148 | "name": "ipython", 149 | "version": 3 150 | }, 151 | "file_extension": ".py", 152 | "mimetype": "text/x-python", 153 | "name": "python", 154 | "nbconvert_exporter": "python", 155 | "pygments_lexer": "ipython3", 156 | "version": "3.10.10" 157 | } 158 | }, 159 | "nbformat": 4, 160 | "nbformat_minor": 4 161 | } 162 | -------------------------------------------------------------------------------- /fcmeans/cli.py: -------------------------------------------------------------------------------- 1 | """ 2 | Fuzzy C-means 3 | 4 | Fit and use fuzzy-c-means models to clustering. 5 | 6 | You probably want to install completion for the typer command. 7 | If you are using bash, try to type: 8 | 9 | $ fcm --install-completion bash 10 | 11 | https://github.com/omadson/fuzzy-c-means 12 | """ 13 | import pickle 14 | import time 15 | from pathlib import Path 16 | 17 | import numpy as np 18 | import typer 19 | from tabulate import tabulate 20 | 21 | from . import FCM 22 | 23 | app = typer.Typer(help=__doc__) 24 | 25 | 26 | class Options: 27 | def __init__(self, dictionary): 28 | for k, v in dictionary.items(): 29 | setattr(self, k, v) 30 | 31 | 32 | def extension_check(extension: str, value: Path): 33 | if value.suffix != extension: 34 | raise typer.BadParameter(f"File '{value}' must be extension '{extension}'.") 35 | return value 36 | 37 | 38 | def input_path_callback(value: Path): 39 | return extension_check(".csv", value) 40 | 41 | 42 | def model_path_callback(value: Path): 43 | if value.exists(): 44 | typer.confirm( 45 | f"Do you confirm to replace '{value}' file?", 46 | default=True, 47 | abort=True, 48 | ) 49 | return value 50 | 51 | 52 | def delimiter_callback(value: str): 53 | delimiters = [" ", ",", "|", ";"] 54 | if value in delimiters: 55 | return value 56 | raise typer.BadParameter( 57 | f"The delimiters must be in the following list: {delimiters}." 58 | ) 59 | 60 | 61 | def _predict(data, model): 62 | return model.predict(data) 63 | 64 | 65 | def _read_data(dataset_path, delimiter, quiet): 66 | typer.echo() 67 | if not quiet: 68 | typer.echo("Reading data set... ", nl=False) 69 | X = np.genfromtxt(dataset_path, delimiter=delimiter) 70 | # Check file read 71 | if not np.all(X): 72 | typer.echo( 73 | "Error: Please verify if value for '--delimiter' / '-d' is " 74 | f"the delimiter of the '{dataset_path}' file." 75 | ) 76 | raise typer.Abort() 77 | if np.isnan(np.sum(X)): 78 | typer.echo(f"Error: File '{dataset_path}' cannot contain NaN.") 79 | raise typer.Abort() 80 | if not quiet: 81 | typer.echo("Data set read without errors...") 82 | return X 83 | 84 | 85 | def _model_predict(model, X, dataset_path, delimiter, quiet): 86 | labels = model.predict(X) 87 | new_file_name = dataset_path.with_suffix(".labels.csv") 88 | if new_file_name.exists(): 89 | typer.confirm( 90 | f"Do you confirm to replace '{new_file_name}' file?", 91 | default=True, 92 | abort=True, 93 | ) 94 | np.savetxt(new_file_name, labels, delimiter=delimiter, fmt="%d") 95 | if not quiet: 96 | typer.echo(f"Model predictions has been saved as '{new_file_name}'.") 97 | 98 | 99 | @app.command() 100 | def fit( 101 | dataset_path: Path = typer.Argument( 102 | "dataset.csv", 103 | help="Data set file path (only .csv).", 104 | dir_okay=False, 105 | exists=True, 106 | callback=input_path_callback, 107 | ), 108 | delimiter: str = typer.Option( 109 | ",", 110 | "--delimiter", 111 | "-d", 112 | help="Delimiter of data set file.", 113 | callback=delimiter_callback, 114 | ), 115 | model_path: Path = typer.Argument( 116 | "model.sav", 117 | help="Path to save the created model.", 118 | dir_okay=False, 119 | callback=model_path_callback, 120 | ), 121 | n_clusters: int = typer.Option( 122 | 2, "--clusters", "-c", max=500, help="Number of clusters." 123 | ), 124 | m: float = typer.Option( 125 | 2.0, 126 | "--exponent", 127 | "-e", 128 | min=1, 129 | max=100, 130 | help="Fuzzy partition exponent.", 131 | ), 132 | max_iter: int = typer.Option( 133 | 150, 134 | "--max-iter", 135 | "-m", 136 | min=1, 137 | max=5000, 138 | help="Maximum number of iterations.", 139 | ), 140 | error: float = typer.Option( 141 | 1e-5, "--tolerance", "-t", min=1e-10, help="Stop Tolerance criteria." 142 | ), 143 | random_state: int = typer.Option( 144 | None, "--seed", "-s", help="Seed for the random number generator." 145 | ), 146 | quiet: bool = typer.Option(False, "--quiet", "-q", help="Suppress model info."), 147 | predict: bool = typer.Option(False, "--predict", "-p", help="Prediction flag."), 148 | ): 149 | """Train and save a fuzzy-c-means model given a dataset.""" 150 | X = _read_data(dataset_path, delimiter, quiet) 151 | model = FCM( 152 | n_clusters=n_clusters, 153 | max_iter=max_iter, 154 | m=m, 155 | error=error, 156 | random_state=random_state, 157 | ) 158 | if not quiet: 159 | typer.echo("Training model... ", nl=False) 160 | start_time = time.time() 161 | try: 162 | model.fit(X) 163 | except Exception: 164 | typer.echo("\nError: There was an error in the fitting step.") 165 | typer.echo( 166 | "If the problem continues, create an issue at:" 167 | "https://github.com/omadson/fuzzy-c-means/issues" 168 | ) 169 | raise typer.Abort() 170 | if not quiet: 171 | typer.echo("Model trained without errors...") 172 | elapsed_time = (time.time() - start_time) * 1000 173 | with open(model_path, "wb") as file: 174 | pickle.dump(model, file) 175 | if not quiet: 176 | headers = ["Variable", "Value"] 177 | table = [ 178 | ["Number of clusters", n_clusters], 179 | ["Fuzzy partition matrix exponent", m], 180 | ["Stop tolerance criteria", error], 181 | ["Training time (ms)", elapsed_time], 182 | ] 183 | typer.echo("\nModel info:") 184 | typer.echo(tabulate(table, headers, tablefmt="fancy_grid")) 185 | if not quiet: 186 | typer.echo(f"\nYour model has been saved as '{model_path}'.") 187 | if predict: 188 | _model_predict(model, X, dataset_path, delimiter, quiet) 189 | 190 | 191 | @app.command() 192 | def predict( 193 | dataset_path: Path = typer.Argument( 194 | "dataset.csv", 195 | help="Data set file path (only .csv).", 196 | dir_okay=False, 197 | exists=True, 198 | callback=input_path_callback, 199 | ), 200 | delimiter: str = typer.Option( 201 | ",", 202 | "--delimiter", 203 | "-d", 204 | help="Delimiter of data set file.", 205 | callback=delimiter_callback, 206 | ), 207 | quiet: bool = typer.Option(False, "--quiet", "-q", help="Suppress model info."), 208 | model_path: Path = typer.Argument( 209 | "model.sav", 210 | help="Path to save the created model.", 211 | dir_okay=False, 212 | exists=True, 213 | ), 214 | ): 215 | """Predict labels given a data set and a fuzzy-c-means saved model.""" 216 | X = _read_data(dataset_path, delimiter, quiet) 217 | if not quiet: 218 | typer.echo("Reading model... ", nl=False) 219 | try: 220 | with open(model_path, "rb") as file: 221 | model = pickle.load(file) 222 | except Exception: 223 | typer.echo("Error: Something wrong with your models.") 224 | raise typer.Abort() 225 | if not quiet: 226 | typer.echo("Model loaded without errors...") 227 | _model_predict(model, X, dataset_path, delimiter, quiet) 228 | -------------------------------------------------------------------------------- /fcmeans/main.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | from typing import Callable, Dict, Optional, Union 3 | 4 | import numpy as np 5 | import tqdm 6 | from joblib import Parallel, delayed 7 | from numpy.typing import NDArray 8 | from pydantic import BaseModel, ConfigDict, Field, validate_call 9 | 10 | 11 | class DistanceOptions(str, Enum): 12 | """Implemented distances""" 13 | euclidean = 'euclidean' 14 | minkowski = 'minkowski' 15 | cosine = 'cosine' 16 | 17 | 18 | class FCM(BaseModel): 19 | r"""Fuzzy C-means Model 20 | 21 | Attributes: 22 | n_clusters (int): The number of clusters to form as well as the number 23 | of centroids to generate by the fuzzy C-means. 24 | max_iter (int): Maximum number of iterations of the fuzzy C-means 25 | algorithm for a single run. 26 | m (float): Degree of fuzziness: $m \in (1, \infty)$. 27 | error (float): Relative tolerance with regards to Frobenius norm of 28 | the difference 29 | in the cluster centers of two consecutive iterations to declare 30 | convergence. 31 | random_state (Optional[int]): Determines random number generation for 32 | centroid initialization. 33 | Use an int to make the randomness deterministic. 34 | trained (bool): Variable to store whether or not the model has been 35 | trained. 36 | 37 | Returns: 38 | FCM: A FCM model. 39 | 40 | Raises: 41 | ReferenceError: If called without the model being trained 42 | """ 43 | 44 | model_config = ConfigDict(extra="allow", arbitrary_types_allowed=True) 45 | 46 | n_clusters: int = Field(5, ge=1) 47 | max_iter: int = Field(150, ge=1, le=1000) 48 | m: float = Field(2.0, ge=1.0) 49 | error: float = Field(1e-5, ge=1e-9) 50 | random_state: Optional[int] = None 51 | trained: bool = False 52 | n_jobs: int = Field(1, ge=1) 53 | verbose: Optional[bool] = False 54 | distance: Optional[Union[DistanceOptions, Callable]] = ( 55 | DistanceOptions.euclidean 56 | ) 57 | distance_params: Optional[Dict] = {} 58 | 59 | @validate_call(config=dict(arbitrary_types_allowed=True)) 60 | def fit(self, X: NDArray) -> None: 61 | """Train the fuzzy-c-means model 62 | 63 | Args: 64 | X (NDArray): Training instances to cluster. 65 | """ 66 | self.rng = np.random.default_rng(self.random_state) 67 | n_samples = X.shape[0] 68 | self.u = self.rng.uniform(size=(n_samples, self.n_clusters)) 69 | self.u = self.u / np.tile( 70 | self.u.sum(axis=1)[np.newaxis].T, self.n_clusters 71 | ) 72 | for _ in tqdm.tqdm( 73 | range(self.max_iter), desc="Training", disable=not self.verbose 74 | ): 75 | u_old = self.u.copy() 76 | self._centers = FCM._next_centers(X, self.u, self.m) 77 | self.u = self.soft_predict(X) 78 | # Stopping rule 79 | if np.linalg.norm(self.u - u_old) < self.error: 80 | break 81 | self.trained = True 82 | 83 | @validate_call(config=dict(arbitrary_types_allowed=True)) 84 | def soft_predict(self, X: NDArray) -> NDArray: 85 | """Soft predict of FCM 86 | 87 | Args: 88 | X (NDArray): New data to predict. 89 | 90 | Returns: 91 | NDArray: Fuzzy partition array, returned as an array with 92 | n_samples rows and n_clusters columns. 93 | """ 94 | temp = FCM._dist( 95 | X, 96 | self._centers, 97 | self.distance, 98 | self.distance_params 99 | ) ** (2 / (self.m - 1)) 100 | u_dist = Parallel(n_jobs=self.n_jobs)( 101 | delayed( 102 | lambda data, col: (data[:, col] / data.T).sum(0) 103 | )(temp, col) 104 | for col in range(temp.shape[1]) 105 | ) 106 | u_dist = np.vstack(u_dist).T 107 | return 1 / u_dist 108 | 109 | @validate_call(config=dict(arbitrary_types_allowed=True)) 110 | def predict(self, X: NDArray) -> NDArray: 111 | """Predict the closest cluster each sample in X belongs to. 112 | 113 | Args: 114 | X (NDArray): New data to predict. 115 | 116 | Raises: 117 | ReferenceError: If it called without the model being trained. 118 | 119 | Returns: 120 | NDArray: Index of the cluster each sample belongs to. 121 | """ 122 | if self._is_trained(): 123 | X = np.expand_dims(X, axis=0) if len(X.shape) == 1 else X 124 | return self.soft_predict(X).argmax(axis=-1) 125 | raise ReferenceError( 126 | "You need to train the model. Run `.fit()` method to this." 127 | ) 128 | 129 | def _is_trained(self) -> bool: 130 | if self.trained: 131 | return True 132 | return False 133 | 134 | @staticmethod 135 | def _dist( 136 | A: NDArray, 137 | B: NDArray, 138 | distance: Optional[Union[DistanceOptions, Callable]] = ( 139 | DistanceOptions.euclidean 140 | ), 141 | distance_params: Optional[Dict] = {} 142 | ) -> NDArray: 143 | """Compute the distance between two matrices""" 144 | if callable(distance): 145 | return distance(A, B, distance_params) 146 | elif distance == 'minkowski': 147 | if isinstance(distance_params, dict): 148 | p = distance_params.get("p", 1.0) 149 | else: 150 | p = 1.0 151 | return FCM._minkowski(A, B, p) 152 | elif distance == 'cosine': 153 | return FCM._cosine(A, B) 154 | else: 155 | return FCM._euclidean(A, B) 156 | 157 | @staticmethod 158 | def _euclidean(A: NDArray, B: NDArray) -> NDArray: 159 | """Compute the euclidean distance between two matrices""" 160 | return np.sqrt(np.einsum("ijk->ij", (A[:, None, :] - B) ** 2)) 161 | 162 | @staticmethod 163 | def _minkowski(A: NDArray, B: NDArray, p: float) -> NDArray: 164 | """Compute the minkowski distance between two matrices""" 165 | return (np.einsum("ijk->ij", (A[:, None, :] - B) ** p)) ** (1/p) 166 | 167 | @staticmethod 168 | def _cosine_similarity(A: NDArray, B: NDArray) -> NDArray: 169 | """Compute the cosine similarity between two matrices""" 170 | p1 = np.sqrt(np.sum(A**2, axis=1))[:, np.newaxis] 171 | p2 = np.sqrt(np.sum(B**2, axis=1))[np.newaxis, :] 172 | return np.dot(A, B.T) / (p1*p2) 173 | 174 | @staticmethod 175 | def _cosine(A: NDArray, B: NDArray) -> NDArray: 176 | """Compute the cosine distance between two matrices""" 177 | return np.abs(1 - FCM._cosine_similarity(A, B)) 178 | 179 | @staticmethod 180 | def _next_centers(X: NDArray, u: NDArray, m: float): 181 | """Update cluster centers""" 182 | um = u**m 183 | return (X.T @ um / np.sum(um, axis=0)).T 184 | 185 | @property 186 | def centers(self) -> NDArray: 187 | if self._is_trained(): 188 | return self._centers 189 | raise ReferenceError( 190 | "You need to train the model. Run `.fit()` method to this." 191 | ) 192 | 193 | @property 194 | def partition_coefficient(self) -> float: 195 | """Partition coefficient 196 | 197 | Equation 12a of 198 | [this paper](https://doi.org/10.1016/0098-3004(84)90020-7). 199 | """ 200 | if self._is_trained(): 201 | return np.mean(self.u**2) 202 | raise ReferenceError( 203 | "You need to train the model. Run `.fit()` method to this." 204 | ) 205 | 206 | @property 207 | def partition_entropy_coefficient(self): 208 | if self._is_trained(): 209 | return -np.mean(self.u * np.log2(self.u)) 210 | raise ReferenceError( 211 | "You need to train the model. Run `.fit()` method to this." 212 | ) 213 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.5.0; python_full_version >= "3.6.2" and python_version >= "3.7" 2 | appnope==0.1.2; sys_platform == "darwin" and python_version >= "3.8" and python_full_version >= "3.6.2" and platform_system == "Darwin" 3 | argon2-cffi-bindings==21.2.0; python_version >= "3.7" 4 | argon2-cffi==21.3.0; python_version >= "3.7" 5 | asttokens==2.0.5; python_full_version >= "3.6.2" and python_version >= "3.8" 6 | atomicwrites==1.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.6" and python_full_version >= "3.4.0" 7 | attrs==21.4.0; python_full_version >= "3.7.1" and python_version >= "3.7" and python_version < "4.0" 8 | babel==2.9.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" 9 | backcall==0.2.0; python_full_version >= "3.6.2" and python_version >= "3.8" 10 | black==22.1.0; python_full_version >= "3.6.2" 11 | bleach==4.1.0; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 12 | certifi==2021.10.8; python_full_version >= "3.6.0" and python_version >= "3.6" 13 | cffi==1.15.0; implementation_name == "pypy" and python_version >= "3.7" and python_full_version >= "3.6.1" and sys_platform == "linux" 14 | cfgv==3.3.1; python_full_version >= "3.6.1" 15 | charset-normalizer==2.0.12; python_full_version >= "3.6.0" and python_version >= "3.6" 16 | click-log==0.3.2 17 | click==8.0.4; python_version >= "3.8" and python_full_version >= "3.7.1" and python_version < "4" 18 | colorama==0.4.4; sys_platform == "win32" and python_version >= "3.8" and python_full_version >= "3.6.2" and platform_system == "Windows" and (python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.6" and python_full_version >= "3.5.0") and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6") and (python_version >= "3.6" and python_full_version < "3.0.0" and platform_system == "Windows" or python_full_version >= "3.5.0" and python_version >= "3.6" and platform_system == "Windows") 19 | coverage==6.3.2; python_version >= "3.7" 20 | cryptography==36.0.1; sys_platform == "linux" and python_version >= "3.7" 21 | cycler==0.11.0; python_version >= "3.7" 22 | debugpy==1.5.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" 23 | decorator==5.1.1; python_full_version >= "3.6.2" and python_version >= "3.8" 24 | defusedxml==0.7.1; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 25 | distlib==0.3.4; python_full_version >= "3.6.1" 26 | docutils==0.18.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" 27 | dotty-dict==1.3.0 28 | entrypoints==0.4; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 29 | executing==0.8.2; python_full_version >= "3.6.2" and python_version >= "3.8" 30 | filelock==3.6.0; python_version >= "3.7" and python_full_version >= "3.6.1" 31 | flake8==4.0.1; python_version >= "3.6" 32 | fonttools==4.29.1; python_version >= "3.7" 33 | ghp-import==2.0.2; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 34 | gitdb==4.0.9; python_version >= "3.7" 35 | gitpython==3.1.27; python_version >= "3.7" 36 | identify==2.4.10; python_version >= "3.7" and python_full_version >= "3.6.1" 37 | idna==3.3; python_full_version >= "3.6.2" and python_version >= "3.7" 38 | importlib-metadata==4.11.1; python_version < "3.10" and python_version >= "3.7" and python_full_version >= "3.7.1" 39 | iniconfig==1.1.1; python_version >= "3.6" 40 | interrogate==1.5.0; python_version >= "3.6" 41 | invoke==1.6.0 42 | ipykernel==6.9.1; python_version >= "3.7" 43 | ipython-genutils==0.2.0; python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.7.1" 44 | ipython==8.0.1; python_full_version >= "3.6.2" and python_version >= "3.8" 45 | isort==5.10.1; python_full_version >= "3.6.1" and python_version < "4.0" 46 | jedi==0.18.1; python_full_version >= "3.6.2" and python_version >= "3.8" 47 | jeepney==0.7.1; sys_platform == "linux" and python_version >= "3.7" 48 | jinja2==3.0.3; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 49 | json5==0.9.6; python_version >= "3.6" 50 | jsonschema==4.4.0; python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.7.1" 51 | jupyter-client==7.1.2; python_full_version >= "3.7.1" and python_version >= "3.7" and python_version < "4" 52 | jupyter-core==4.9.2; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 53 | jupyter-server==1.17.0; python_version >= "3.7" 54 | jupyterlab-pygments==0.1.2; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 55 | jupyterlab-server==2.10.3; python_version >= "3.6" 56 | jupyterlab==3.2.9; python_version >= "3.6" 57 | jupytext==1.13.7; python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.7.1" 58 | keyring==23.5.0; python_version >= "3.7" 59 | kiwisolver==1.3.2; python_version >= "3.7" 60 | markdown-it-py==1.1.0; python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.7.1" 61 | markdown==3.3.6; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" and python_full_version < "4.0.0" 62 | markupsafe==2.1.0; python_version >= "3.7" 63 | matplotlib-inline==0.1.3; python_full_version >= "3.6.2" and python_version >= "3.8" 64 | matplotlib==3.5.1; python_version >= "3.7" 65 | mccabe==0.6.1; python_version >= "3.6" 66 | mdit-py-plugins==0.3.0; python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.7.1" 67 | mergedeep==1.3.4; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 68 | mistune==0.8.4; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 69 | mkdocs-autorefs==0.3.1; python_full_version >= "3.6.2" and python_full_version < "4.0.0" and python_version >= "3.7" 70 | mkdocs-jupyter==0.20.0; python_full_version >= "3.7.1" and python_version < "4" 71 | mkdocs-material-extensions==1.0.3; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.6" 72 | mkdocs-material==8.2.1; python_version >= "3.6" 73 | mkdocs==1.2.3; python_version >= "3.6" 74 | mkdocstrings-python-legacy==0.2.2; python_version >= "3.7" 75 | mkdocstrings==0.18.0; python_version >= "3.7" 76 | mypy-extensions==0.4.3; python_version >= "3.8" and python_full_version >= "3.6.2" 77 | mypy==0.931; python_version >= "3.6" 78 | nbclassic==0.3.5; python_version >= "3.6" 79 | nbclient==0.5.11; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 80 | nbconvert==6.4.2; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 81 | nbformat==5.1.3; python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.7.1" 82 | nest-asyncio==1.5.4; python_full_version >= "3.7.1" and python_version >= "3.7" and python_version < "4" 83 | nodeenv==1.6.0; python_full_version >= "3.6.1" 84 | notebook==6.4.12; python_version >= "3.6" 85 | numpy==1.22.2; python_version >= "3.8" 86 | packaging==21.3; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 87 | pandocfilters==1.5.0; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 88 | parso==0.8.3; python_full_version >= "3.6.2" and python_version >= "3.8" 89 | pathspec==0.9.0; python_full_version >= "3.6.2" and python_version >= "3.8" 90 | pexpect==4.8.0; sys_platform != "win32" and python_version >= "3.8" and python_full_version >= "3.6.2" 91 | pickleshare==0.7.5; python_full_version >= "3.6.2" and python_version >= "3.8" 92 | pillow==9.0.1; python_version >= "3.7" 93 | pkginfo==1.8.2; python_version >= "3.6" 94 | platformdirs==2.5.1; python_version >= "3.8" and python_full_version >= "3.6.2" 95 | pluggy==1.0.0; python_version >= "3.6" 96 | pre-commit==2.17.0; python_full_version >= "3.6.1" 97 | prometheus-client==0.13.1; python_version >= "3.7" 98 | prompt-toolkit==3.0.28; python_full_version >= "3.6.2" and python_version >= "3.8" 99 | ptyprocess==0.7.0; sys_platform != "win32" and python_version >= "3.8" and python_full_version >= "3.6.2" and os_name != "nt" 100 | pure-eval==0.2.2; python_full_version >= "3.6.2" and python_version >= "3.8" 101 | py==1.11.0; python_full_version >= "3.6.1" and python_version >= "3.7" and implementation_name == "pypy" 102 | pycodestyle==2.8.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" 103 | pycparser==2.21; implementation_name == "pypy" and python_version >= "3.7" and python_full_version >= "3.6.1" 104 | pydantic==1.9.0; python_full_version >= "3.6.1" 105 | pyflakes==2.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" 106 | pygments==2.11.2; python_full_version >= "3.7.1" and python_version >= "3.8" and python_version < "4" 107 | pymdown-extensions==9.2; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 108 | pyparsing==3.0.7; python_version >= "3.7" 109 | pyrsistent==0.18.1; python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.7.1" 110 | pytest-cov==3.0.0; python_version >= "3.6" 111 | pytest==7.0.1; python_version >= "3.6" 112 | python-dateutil==2.8.2; python_full_version >= "3.6.1" and python_version >= "3.7" 113 | python-gitlab==2.10.1; python_full_version >= "3.6.0" 114 | python-semantic-release==7.25.0 115 | pytkdocs==0.16.0; python_version >= "3.7" 116 | pytz==2021.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" 117 | pywin32-ctypes==0.2.0; sys_platform == "win32" and python_version >= "3.7" 118 | pywin32==303; sys_platform == "win32" and platform_python_implementation != "PyPy" and python_version >= "3.6" 119 | pywinpty==1.1.6; os_name == "nt" and python_version >= "3.7" 120 | pyyaml-env-tag==0.1; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 121 | pyyaml==6.0; python_version >= "3.7" and python_full_version >= "3.7.1" and python_version < "4" 122 | pyzmq==22.3.0; python_full_version >= "3.6.1" and python_version >= "3.7" 123 | readme-renderer==32.0; python_version >= "3.6" 124 | requests-toolbelt==0.9.1; python_full_version >= "3.6.0" and python_version >= "3.6" 125 | requests==2.27.1; python_full_version >= "3.6.0" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6") 126 | rfc3986==2.0.0; python_version >= "3.7" 127 | secretstorage==3.3.1; sys_platform == "linux" and python_version >= "3.7" 128 | semver==2.13.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" 129 | send2trash==1.8.0; python_version >= "3.7" 130 | setuptools-scm==6.4.2; python_version >= "3.7" 131 | six==1.16.0; python_full_version >= "3.7.1" and python_version >= "3.8" and python_version < "4" 132 | smmap==5.0.0; python_version >= "3.7" 133 | sniffio==1.2.0; python_full_version >= "3.6.2" and python_version >= "3.7" 134 | stack-data==0.2.0; python_full_version >= "3.6.2" and python_version >= "3.8" 135 | tabulate==0.8.9 136 | terminado==0.13.1; python_version >= "3.7" 137 | testpath==0.5.0; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 138 | tokenize-rt==4.2.1; python_full_version >= "3.6.2" and python_version >= "3.8" 139 | toml==0.10.2; python_full_version >= "3.7.1" and python_version >= "3.6" and python_version < "4.0" 140 | tomli==2.0.1 141 | tomlkit==0.7.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" 142 | tornado==6.1; python_full_version >= "3.6.1" and python_version >= "3.7" 143 | tqdm==4.62.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" 144 | traitlets==5.1.1; python_full_version >= "3.7.1" and python_version >= "3.8" and python_version < "4" 145 | twine==3.8.0; python_version >= "3.6" 146 | typer==0.4.0; python_version >= "3.6" 147 | typing-extensions==4.1.1; python_version >= "3.8" and python_full_version >= "3.6.2" and python_version < "3.10" 148 | urllib3==1.26.8; python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.6") 149 | virtualenv==20.13.1; python_full_version >= "3.6.1" 150 | watchdog==2.1.6; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 151 | wcwidth==0.2.5; python_full_version >= "3.6.2" and python_version >= "3.8" 152 | webencodings==0.5.1; python_full_version >= "3.7.1" and python_version < "4" and python_version >= "3.7" 153 | websocket-client==1.2.3; python_version >= "3.7" 154 | zipp==3.7.0; python_version >= "3.7" 155 | -------------------------------------------------------------------------------- /docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | 4 | 5 | ## v1.7.2 (2024-03-18) 6 | 7 | ### Fix 8 | 9 | * fix: fix release and publish scripts. ([`7718856`](https://github.com/omadson/fuzzy-c-means/commit/7718856ed5823b68129e28839b174b60d75239a3)) 10 | 11 | 12 | ## v1.7.1 (2024-03-18) 13 | 14 | ### Build 15 | 16 | * build: change publish pipeline. ([`2ec4255`](https://github.com/omadson/fuzzy-c-means/commit/2ec42554b1b444d96055b730743488a20c84c774)) 17 | 18 | * build(deps-dev): bump jinja2 from 3.1.2 to 3.1.3 19 | 20 | Bumps [jinja2](https://github.com/pallets/jinja) from 3.1.2 to 3.1.3. 21 | - [Release notes](https://github.com/pallets/jinja/releases) 22 | - [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst) 23 | - [Commits](https://github.com/pallets/jinja/compare/3.1.2...3.1.3) 24 | 25 | --- 26 | updated-dependencies: 27 | - dependency-name: jinja2 28 | dependency-type: indirect 29 | ... 30 | 31 | Signed-off-by: dependabot[bot] <support@github.com> ([`bff083f`](https://github.com/omadson/fuzzy-c-means/commit/bff083fb146f64e516a05d1638bf407a52c80e03)) 32 | 33 | * build(deps): bump markdown-it-py from 2.1.0 to 2.2.0 34 | 35 | Bumps [markdown-it-py](https://github.com/executablebooks/markdown-it-py) from 2.1.0 to 2.2.0. 36 | - [Release notes](https://github.com/executablebooks/markdown-it-py/releases) 37 | - [Changelog](https://github.com/executablebooks/markdown-it-py/blob/master/CHANGELOG.md) 38 | - [Commits](https://github.com/executablebooks/markdown-it-py/compare/v2.1.0...v2.2.0) 39 | 40 | --- 41 | updated-dependencies: 42 | - dependency-name: markdown-it-py 43 | dependency-type: indirect 44 | ... 45 | 46 | Signed-off-by: dependabot[bot] <support@github.com> ([`a5af1d9`](https://github.com/omadson/fuzzy-c-means/commit/a5af1d96738c9dc893b4ee4c37b7cf371003bf60)) 47 | 48 | ### Chore 49 | 50 | * chore: change semantic release options. ([`ee5ffef`](https://github.com/omadson/fuzzy-c-means/commit/ee5ffef98e8c6ebd3f5bafb54cdb4ef6789a05eb)) 51 | 52 | * chore: remove notebook outputs ([`b9bd71c`](https://github.com/omadson/fuzzy-c-means/commit/b9bd71ca9faf5119d5423554e1b4a97f1759a6d1)) 53 | 54 | * chore: add new env var. ([`8a2cd12`](https://github.com/omadson/fuzzy-c-means/commit/8a2cd12dfa66dd28832e4c78a618891e76158061)) 55 | 56 | ### Fix 57 | 58 | * fix: correction of the cosine distance calculation method (#78). ([`c0fd2f8`](https://github.com/omadson/fuzzy-c-means/commit/c0fd2f8e33ad3328484701b7a4b747e89990261c)) 59 | 60 | ### Refactor 61 | 62 | * refactor: update pydantic and typer version. ([`5d6384e`](https://github.com/omadson/fuzzy-c-means/commit/5d6384e7a0fc28cd711a0ac97363e64709a76530)) 63 | 64 | ### Unknown 65 | 66 | * Merge pull request #92 from omadson/docs/remove-notebook-outputs 67 | 68 | docs: remove notebook outputs ([`0c4b407`](https://github.com/omadson/fuzzy-c-means/commit/0c4b407326ee26e490abb45268af7e4844e3cd9a)) 69 | 70 | * Merge pull request #91 from omadson/chore/change-publish-pipeline 71 | 72 | chore: add new env var. ([`4cde06d`](https://github.com/omadson/fuzzy-c-means/commit/4cde06d86707e9dfef6c3f1b94bef35c9712cb63)) 73 | 74 | * Merge pull request #87 from omadson/feature/upgrade-pydantic-to-v2 75 | 76 | feature/upgrade pydantic to v2 ([`c4be239`](https://github.com/omadson/fuzzy-c-means/commit/c4be239a7d5d6f13af530dba48d24884d110b999)) 77 | 78 | * Merge pull request #83 from omadson/dependabot/pip/jinja2-3.1.3 79 | 80 | build(deps-dev): bump jinja2 from 3.1.2 to 3.1.3 ([`721f8ef`](https://github.com/omadson/fuzzy-c-means/commit/721f8ef06e884a9cd11fbdf014d5920cf59363a8)) 81 | 82 | * Merge pull request #73 from omadson/dependabot/pip/markdown-it-py-2.2.0 83 | 84 | build(deps): bump markdown-it-py from 2.1.0 to 2.2.0 ([`2ad8c6a`](https://github.com/omadson/fuzzy-c-means/commit/2ad8c6a63ba1f6b47eca49f5d6e562d5de7637ec)) 85 | 86 | 87 | ## v1.7.0 (2022-12-09) 88 | 89 | ### Build 90 | 91 | * build(deps): bump jupyter-server from 1.15.4 to 1.17.0 92 | 93 | Bumps [jupyter-server](https://github.com/jupyter-server/jupyter_server) from 1.15.4 to 1.17.0. 94 | - [Release notes](https://github.com/jupyter-server/jupyter_server/releases) 95 | - [Changelog](https://github.com/jupyter-server/jupyter_server/blob/main/CHANGELOG.md) 96 | - [Commits](https://github.com/jupyter-server/jupyter_server/compare/v1.15.4...v1.17.0) 97 | 98 | --- 99 | updated-dependencies: 100 | - dependency-name: jupyter-server 101 | dependency-type: direct:production 102 | ... 103 | 104 | Signed-off-by: dependabot[bot] <support@github.com> ([`aeed1c0`](https://github.com/omadson/fuzzy-c-means/commit/aeed1c068aec3397f403a956b0c2d4e3f893a263)) 105 | 106 | * build(deps): bump jupyter-server from 1.15.4 to 1.17.0 in /docs 107 | 108 | Bumps [jupyter-server](https://github.com/jupyter-server/jupyter_server) from 1.15.4 to 1.17.0. 109 | - [Release notes](https://github.com/jupyter-server/jupyter_server/releases) 110 | - [Changelog](https://github.com/jupyter-server/jupyter_server/blob/main/CHANGELOG.md) 111 | - [Commits](https://github.com/jupyter-server/jupyter_server/compare/v1.15.4...v1.17.0) 112 | 113 | --- 114 | updated-dependencies: 115 | - dependency-name: jupyter-server 116 | dependency-type: direct:production 117 | ... 118 | 119 | Signed-off-by: dependabot[bot] <support@github.com> ([`77f3dc0`](https://github.com/omadson/fuzzy-c-means/commit/77f3dc099ddfd583e8f24ee1833f075814a24e2f)) 120 | 121 | * build(deps): bump nbconvert from 6.4.2 to 6.5.1 122 | 123 | Bumps [nbconvert](https://github.com/jupyter/nbconvert) from 6.4.2 to 6.5.1. 124 | - [Release notes](https://github.com/jupyter/nbconvert/releases) 125 | - [Commits](https://github.com/jupyter/nbconvert/compare/6.4.2...6.5.1) 126 | 127 | --- 128 | updated-dependencies: 129 | - dependency-name: nbconvert 130 | dependency-type: indirect 131 | ... 132 | 133 | Signed-off-by: dependabot[bot] <support@github.com> ([`f9ca62f`](https://github.com/omadson/fuzzy-c-means/commit/f9ca62f722be87c799573342ed1c6551affdb5eb)) 134 | 135 | * build(deps): bump notebook from 6.4.10 to 6.4.12 136 | 137 | Bumps [notebook](http://jupyter.org) from 6.4.10 to 6.4.12. 138 | 139 | --- 140 | updated-dependencies: 141 | - dependency-name: notebook 142 | dependency-type: direct:production 143 | ... 144 | 145 | Signed-off-by: dependabot[bot] <support@github.com> ([`57199d7`](https://github.com/omadson/fuzzy-c-means/commit/57199d77805110c5304f9030eb716227d885c701)) 146 | 147 | * build(deps): bump notebook from 6.4.10 to 6.4.12 in /docs 148 | 149 | Bumps [notebook](http://jupyter.org) from 6.4.10 to 6.4.12. 150 | 151 | --- 152 | updated-dependencies: 153 | - dependency-name: notebook 154 | dependency-type: direct:production 155 | ... 156 | 157 | Signed-off-by: dependabot[bot] <support@github.com> ([`c6cf621`](https://github.com/omadson/fuzzy-c-means/commit/c6cf6212e9dddc951ad8c84957b6d824091144ce)) 158 | 159 | * build(deps): bump notebook from 6.4.8 to 6.4.10 160 | 161 | Bumps [notebook](http://jupyter.org) from 6.4.8 to 6.4.10. 162 | 163 | --- 164 | updated-dependencies: 165 | - dependency-name: notebook 166 | dependency-type: indirect 167 | ... 168 | 169 | Signed-off-by: dependabot[bot] <support@github.com> ([`9a15579`](https://github.com/omadson/fuzzy-c-means/commit/9a15579da2ff12ed951aacd3dab963ff6bf63426)) 170 | 171 | * build(deps): bump notebook from 6.4.8 to 6.4.10 in /docs 172 | 173 | Bumps [notebook](http://jupyter.org) from 6.4.8 to 6.4.10. 174 | 175 | --- 176 | updated-dependencies: 177 | - dependency-name: notebook 178 | dependency-type: direct:production 179 | ... 180 | 181 | Signed-off-by: dependabot[bot] <support@github.com> ([`24edbbe`](https://github.com/omadson/fuzzy-c-means/commit/24edbbe407c75776f42c228419a18a8714c06c9c)) 182 | 183 | * build(deps): bump jupyter-server from 1.13.5 to 1.15.4 184 | 185 | Bumps [jupyter-server](https://github.com/jupyter/jupyter_server) from 1.13.5 to 1.15.4. 186 | - [Release notes](https://github.com/jupyter/jupyter_server/releases) 187 | - [Changelog](https://github.com/jupyter-server/jupyter_server/blob/main/CHANGELOG.md) 188 | - [Commits](https://github.com/jupyter/jupyter_server/compare/v1.13.5...v1.15.4) 189 | 190 | --- 191 | updated-dependencies: 192 | - dependency-name: jupyter-server 193 | dependency-type: indirect 194 | ... 195 | 196 | Signed-off-by: dependabot[bot] <support@github.com> ([`7dc2a2e`](https://github.com/omadson/fuzzy-c-means/commit/7dc2a2e2ed44ad46020822bc3f30610685818663)) 197 | 198 | * build(deps): bump jupyter-server from 1.13.5 to 1.15.4 in /docs 199 | 200 | Bumps [jupyter-server](https://github.com/jupyter/jupyter_server) from 1.13.5 to 1.15.4. 201 | - [Release notes](https://github.com/jupyter/jupyter_server/releases) 202 | - [Changelog](https://github.com/jupyter-server/jupyter_server/blob/main/CHANGELOG.md) 203 | - [Commits](https://github.com/jupyter/jupyter_server/compare/v1.13.5...v1.15.4) 204 | 205 | --- 206 | updated-dependencies: 207 | - dependency-name: jupyter-server 208 | dependency-type: direct:production 209 | ... 210 | 211 | Signed-off-by: dependabot[bot] <support@github.com> ([`741a4c9`](https://github.com/omadson/fuzzy-c-means/commit/741a4c9d6df4c13b38e5b93390228beb190243f6)) 212 | 213 | ### Chore 214 | 215 | * chore: change interrogate pre-commit. ([`e2a4b57`](https://github.com/omadson/fuzzy-c-means/commit/e2a4b57fd32866fdce125f220432c03258752742)) 216 | 217 | ### Documentation 218 | 219 | * docs: add readthedocs badge ([`40bec9e`](https://github.com/omadson/fuzzy-c-means/commit/40bec9e8b24461ed1ab9bb602ccfbc446e19ba71)) 220 | 221 | * docs: add all packages ([`bd8cfe9`](https://github.com/omadson/fuzzy-c-means/commit/bd8cfe9bb87952003c64c59c961c9da27da84707)) 222 | 223 | * docs: create documentation 224 | 225 | docs: create documentation ([`70395ea`](https://github.com/omadson/fuzzy-c-means/commit/70395eab3e8dcf6483b1241460d3cf2bee8a22df)) 226 | 227 | * docs: readthedocs setup ([`b6a65fe`](https://github.com/omadson/fuzzy-c-means/commit/b6a65fe5ec4a8012bfb73f56cefca979e613bbd3)) 228 | 229 | * docs: create documentation ([`95f11c1`](https://github.com/omadson/fuzzy-c-means/commit/95f11c19db0f20ebdf379b76b318cbcfc1deceb3)) 230 | 231 | * docs(main): adds docstrings. ([`aa19e55`](https://github.com/omadson/fuzzy-c-means/commit/aa19e5532e6012c4687e6d948d294500399c3a19)) 232 | 233 | * docs: adds interrogate pre-commit ([`5258adb`](https://github.com/omadson/fuzzy-c-means/commit/5258adb4c9bac17d3910a6fd6f002ae0ab44919f)) 234 | 235 | ### Feature 236 | 237 | * feat: add support for custom distance metrics (#61) ([`1b0a340`](https://github.com/omadson/fuzzy-c-means/commit/1b0a340b37c77d9d8be9c9a3df31720cdc755f64)) 238 | 239 | ### Unknown 240 | 241 | * Merge pull request #68 from omadson/feature/add-distance-metrics 242 | 243 | feat: add support for custom distance metrics (#61) ([`e957f67`](https://github.com/omadson/fuzzy-c-means/commit/e957f67034d878ae391d3ff6102eba27671ff8d3)) 244 | 245 | * Merge pull request #64 from danich1/allow-larger-clusters 246 | 247 | Update package to include any size cluster ([`56f62ee`](https://github.com/omadson/fuzzy-c-means/commit/56f62ee9a274628df3e5a1ed19ca90e22a215a70)) 248 | 249 | * Update to include any size cluster ([`f89dc8b`](https://github.com/omadson/fuzzy-c-means/commit/f89dc8b4b0f0d5282c70617ac36cc6963f5c4ec8)) 250 | 251 | * Merge pull request #58 from omadson/dependabot/pip/docs/jupyter-server-1.17.0 252 | 253 | build(deps): bump jupyter-server from 1.15.4 to 1.17.0 in /docs ([`87b415a`](https://github.com/omadson/fuzzy-c-means/commit/87b415a7b0da08527c0716b25a7c62eb9fb1a80b)) 254 | 255 | * Merge pull request #59 from omadson/dependabot/pip/jupyter-server-1.17.0 256 | 257 | build(deps): bump jupyter-server from 1.15.4 to 1.17.0 ([`207b68b`](https://github.com/omadson/fuzzy-c-means/commit/207b68bb290c5ac68d8ea5075e40bf0759ae291a)) 258 | 259 | * Merge pull request #57 from omadson/dependabot/pip/nbconvert-6.5.1 260 | 261 | build(deps): bump nbconvert from 6.4.2 to 6.5.1 ([`bc8e5f7`](https://github.com/omadson/fuzzy-c-means/commit/bc8e5f786fe906540231a1db292ee3dbdefca6bb)) 262 | 263 | * Merge pull request #55 from omadson/dependabot/pip/notebook-6.4.12 264 | 265 | build(deps): bump notebook from 6.4.10 to 6.4.12 ([`7473c8d`](https://github.com/omadson/fuzzy-c-means/commit/7473c8d64fb4eed99b9863dd42aed487747ce80d)) 266 | 267 | * Merge pull request #56 from omadson/dependabot/pip/docs/notebook-6.4.12 268 | 269 | build(deps): bump notebook from 6.4.10 to 6.4.12 in /docs ([`084e46a`](https://github.com/omadson/fuzzy-c-means/commit/084e46a455295e1c682697de17e53d13c0e8f30b)) 270 | 271 | * Merge pull request #52 from omadson/dependabot/pip/docs/notebook-6.4.10 272 | 273 | build(deps): bump notebook from 6.4.8 to 6.4.10 in /docs ([`4c9fe09`](https://github.com/omadson/fuzzy-c-means/commit/4c9fe09022f535f428789e51378a66be7052b851)) 274 | 275 | * Merge pull request #53 from omadson/dependabot/pip/notebook-6.4.10 276 | 277 | build(deps): bump notebook from 6.4.8 to 6.4.10 ([`8e58b1c`](https://github.com/omadson/fuzzy-c-means/commit/8e58b1c7c2fe72ed7f7d79234f16011171122c6b)) 278 | 279 | * Merge pull request #50 from omadson/dependabot/pip/docs/jupyter-server-1.15.4 280 | 281 | build(deps): bump jupyter-server from 1.13.5 to 1.15.4 in /docs ([`e983426`](https://github.com/omadson/fuzzy-c-means/commit/e983426c2abfb669dd1e61519fea7683af941ca2)) 282 | 283 | * Merge pull request #51 from omadson/dependabot/pip/jupyter-server-1.15.4 284 | 285 | build(deps): bump jupyter-server from 1.13.5 to 1.15.4 ([`6194de0`](https://github.com/omadson/fuzzy-c-means/commit/6194de05d6a29305e56267e3d4498eef8162cf31)) 286 | 287 | 288 | ## v1.6.4 (2022-02-19) 289 | 290 | ### Build 291 | 292 | * build: fix flake8 command ([`6032206`](https://github.com/omadson/fuzzy-c-means/commit/60322068b67d51e86a81ff1c2fa26691b8f6d233)) 293 | 294 | * build: change checkout action depth ([`abb2df5`](https://github.com/omadson/fuzzy-c-means/commit/abb2df542c0f5853610b09cbe0afc1b7a20bd6a2)) 295 | 296 | * build: fix pytest run ([`7593c20`](https://github.com/omadson/fuzzy-c-means/commit/7593c20ad65576dc49bc5e5227e75e17a7b1eca1)) 297 | 298 | ### Documentation 299 | 300 | * docs: remove old sphynx docs ([`cedfdf6`](https://github.com/omadson/fuzzy-c-means/commit/cedfdf6f4a5c310f9a78bce01cb82d949a0680c6)) 301 | 302 | ### Fix 303 | 304 | * fix: tests and packaging method 305 | 306 | fix: tests and packaging method ([`62f26c3`](https://github.com/omadson/fuzzy-c-means/commit/62f26c3e8267679a2a52fb14099be1ec50579917)) 307 | 308 | * fix: removing tests/ from .gitignore ([`f18c73a`](https://github.com/omadson/fuzzy-c-means/commit/f18c73a6a5fd88219f36dc8d1cfc52675fb5e4ed)) 309 | 310 | * fix: fix some stuff. ([`f3289ad`](https://github.com/omadson/fuzzy-c-means/commit/f3289ad195ff23707fcc50a9b48908ba60718e65)) 311 | 312 | * fix: fix some stuff. ([`a5d50b7`](https://github.com/omadson/fuzzy-c-means/commit/a5d50b77b955985eb3ae2a6ed98049d2311af9f7)) 313 | 314 | * fix: tests and packaging method ([`797d283`](https://github.com/omadson/fuzzy-c-means/commit/797d283020853eb123a63d9b30e535ba51680630)) 315 | 316 | ### Style 317 | 318 | * style: adding black style. ([`02133e5`](https://github.com/omadson/fuzzy-c-means/commit/02133e56882bafc8545fd32511a832b42a3e16aa)) 319 | 320 | * style: adds black on jupyter notebooks ([`80ef85f`](https://github.com/omadson/fuzzy-c-means/commit/80ef85fdf9dceb4d59fa994f6f585e2b72f3f6c7)) 321 | 322 | ### Unknown 323 | 324 | * Merge branch 'master' into feature/add-pre-commit-hooks-and-github-workflows ([`42e9633`](https://github.com/omadson/fuzzy-c-means/commit/42e9633a47764db26f10e52809be165321a6fdb8)) 325 | 326 | * Update README.md ([`ed3154d`](https://github.com/omadson/fuzzy-c-means/commit/ed3154d8ca913dd39e380ac1c21a75b451c2478d)) 327 | 328 | * Merge pull request #47 from omadson/dependabot/pip/ipython-7.31.1 329 | 330 | Bump ipython from 7.27.0 to 7.31.1 ([`2065885`](https://github.com/omadson/fuzzy-c-means/commit/20658852f4f1aa73e17d21b3b05bd10b3a03ed5b)) 331 | 332 | * Bump ipython from 7.27.0 to 7.31.1 333 | 334 | Bumps [ipython](https://github.com/ipython/ipython) from 7.27.0 to 7.31.1. 335 | - [Release notes](https://github.com/ipython/ipython/releases) 336 | - [Commits](https://github.com/ipython/ipython/compare/7.27.0...7.31.1) 337 | 338 | --- 339 | updated-dependencies: 340 | - dependency-name: ipython 341 | dependency-type: indirect 342 | ... 343 | 344 | Signed-off-by: dependabot[bot] <support@github.com> ([`519078f`](https://github.com/omadson/fuzzy-c-means/commit/519078f31b7e10399b5ae98e21d6ce420ec7cff1)) 345 | 346 | * Merge pull request #46 from omadson/dependabot/pip/pillow-9.0.0 347 | 348 | Bump pillow from 8.3.2 to 9.0.0 ([`096a74c`](https://github.com/omadson/fuzzy-c-means/commit/096a74c96aed47439bfc35ab9306d57a9db1a1d7)) 349 | 350 | * Bump pillow from 8.3.2 to 9.0.0 351 | 352 | Bumps [pillow](https://github.com/python-pillow/Pillow) from 8.3.2 to 9.0.0. 353 | - [Release notes](https://github.com/python-pillow/Pillow/releases) 354 | - [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst) 355 | - [Commits](https://github.com/python-pillow/Pillow/compare/8.3.2...9.0.0) 356 | 357 | --- 358 | updated-dependencies: 359 | - dependency-name: pillow 360 | dependency-type: indirect 361 | ... 362 | 363 | Signed-off-by: dependabot[bot] <support@github.com> ([`7879cde`](https://github.com/omadson/fuzzy-c-means/commit/7879cdea3662a6083a37daf51d002429d8cb66cf)) 364 | 365 | * Update README.md ([`d0b56cd`](https://github.com/omadson/fuzzy-c-means/commit/d0b56cd92cd6992b0744b8ace9bfda382483b17f)) 366 | 367 | * Merge pull request #43 from omadson/dependabot/pip/pillow-8.3.2 368 | 369 | Bump pillow from 8.3.1 to 8.3.2 ([`e985b7f`](https://github.com/omadson/fuzzy-c-means/commit/e985b7ff6671f1b28ad5f0c7f7361bf4a9942c01)) 370 | 371 | * Bump pillow from 8.3.1 to 8.3.2 372 | 373 | Bumps [pillow](https://github.com/python-pillow/Pillow) from 8.3.1 to 8.3.2. 374 | - [Release notes](https://github.com/python-pillow/Pillow/releases) 375 | - [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst) 376 | - [Commits](https://github.com/python-pillow/Pillow/compare/8.3.1...8.3.2) 377 | 378 | --- 379 | updated-dependencies: 380 | - dependency-name: pillow 381 | dependency-type: indirect 382 | ... 383 | 384 | Signed-off-by: dependabot[bot] <support@github.com> ([`7b877cb`](https://github.com/omadson/fuzzy-c-means/commit/7b877cbd8ed1c4a13b40e258f31f025f660ff8c8)) 385 | 386 | * Merge pull request #42 from omadson/docs/add-first-pages 387 | 388 | feat: Adds first pages of documentation. ([`b0a8e8b`](https://github.com/omadson/fuzzy-c-means/commit/b0a8e8b360fcfe9903dfd7b294b0ba6e9a6cb140)) 389 | 390 | * Adds text on docs. ([`e590b72`](https://github.com/omadson/fuzzy-c-means/commit/e590b722455234b8eb27487609a98a6ac1601878)) 391 | 392 | * Adds first pages of documentation. ([`12265d4`](https://github.com/omadson/fuzzy-c-means/commit/12265d4a723e09b01fab970f6c2e1f862e6068cb)) 393 | 394 | * Update README.md ([`8ccde76`](https://github.com/omadson/fuzzy-c-means/commit/8ccde76243afa7b806a9798490c54d8cb707f707)) 395 | 396 | * Update citations ([`aa52a45`](https://github.com/omadson/fuzzy-c-means/commit/aa52a4532b3874866d16c39a44508e802480b6ce)) 397 | 398 | 399 | ## v1.6.3 (2021-09-09) 400 | 401 | ### Unknown 402 | 403 | * Merge pull request #40 from omadson/release/1.6.3 404 | 405 | Fix __init__ call and change random_state to Optional. ([`7b43b69`](https://github.com/omadson/fuzzy-c-means/commit/7b43b69e16d43c44af05189784c0af518d3bdace)) 406 | 407 | * Fix __init__ call and change random_state to Optional. ([`376d558`](https://github.com/omadson/fuzzy-c-means/commit/376d5589e0e8e747db4991e9f6cf5dc7bf8060d8)) 408 | 409 | 410 | ## v1.6.2 (2021-09-08) 411 | 412 | ### Unknown 413 | 414 | * Bumping version from 1.2.1 to 1.6.2. ([`db60a4f`](https://github.com/omadson/fuzzy-c-means/commit/db60a4f17c170837fd37c572d02df78bbc810b50)) 415 | 416 | * Update README.md ([`1f3f2c5`](https://github.com/omadson/fuzzy-c-means/commit/1f3f2c58ea50e4ef4fdfc80d03833e5800b1cfe4)) 417 | 418 | * Merge pull request #35 from omadson/refactor/add-pydantic 419 | 420 | refactor: Add pydantic ([`b560190`](https://github.com/omadson/fuzzy-c-means/commit/b56019019e7a101da22c53a4497270e39c2a85df)) 421 | 422 | * Refactor to use pydantic. ([`68579fb`](https://github.com/omadson/fuzzy-c-means/commit/68579fb2fdc0aed30b15f53350d8db6e23a8cfd2)) 423 | 424 | * Update examples folder. ([`653b877`](https://github.com/omadson/fuzzy-c-means/commit/653b877e396a66f4da52082b72c99ee43376d173)) 425 | 426 | * Doc generation ([`acad294`](https://github.com/omadson/fuzzy-c-means/commit/acad2946979b76cddd68db99d9fd1c5cffb232dd)) 427 | 428 | * remove jax as main dependency ([`4d6e494`](https://github.com/omadson/fuzzy-c-means/commit/4d6e4948e7f51e9d532df61735675ae91d84b9c6)) 429 | 430 | 431 | ## v1.4.0 (2021-05-10) 432 | 433 | ### Build 434 | 435 | * build: Add extra cli dependencies ([`9e9f6d1`](https://github.com/omadson/fuzzy-c-means/commit/9e9f6d1f381065cc2cdbbefc039d249331b5e1a6)) 436 | 437 | ### Documentation 438 | 439 | * docs(CLI.md): Add documentation about cli 440 | 441 | Add typer generated documentation about fcm commands. ([`3aee113`](https://github.com/omadson/fuzzy-c-means/commit/3aee1130b17195ae59e61597c41209461f51a039)) 442 | 443 | ### Feature 444 | 445 | * feat(fcmeans/cli.py): Add the command line interface tool 446 | 447 | Add a command line tool that allows you to train and use models without the need for programming, just by executing commands. ([`01906b3`](https://github.com/omadson/fuzzy-c-means/commit/01906b3047b188b1a100e9579bb59f08a5789ee1)) 448 | 449 | ### Refactor 450 | 451 | * refactor: Rename old files due to library name conflict 452 | 453 | Change of jax and numpy submodules because they are conclicting with the libraries ([`eb8169b`](https://github.com/omadson/fuzzy-c-means/commit/eb8169bda8dc360e048702651aa338c1101055fb)) 454 | 455 | ### Unknown 456 | 457 | * Merge pull request #28 from omadson/feature/add-cli 458 | 459 | feat: Add cli ([`fc0dd13`](https://github.com/omadson/fuzzy-c-means/commit/fc0dd13650be2d948bb429402e7771930dcdbdc9)) 460 | 461 | 462 | ## v1.3.1 (2021-05-06) 463 | 464 | ### Fix 465 | 466 | * fix(pyproject.toml): Change extra dependencies ([`ffd3477`](https://github.com/omadson/fuzzy-c-means/commit/ffd34771091feb3e5e28c3daa3cb7d3c435cb21a)) 467 | 468 | ### Unknown 469 | 470 | * Merge pull request #27 from omadson/bugfix/add-extras 471 | 472 | fix(pyproject.toml): Change extra dependencies ([`ef3fcdc`](https://github.com/omadson/fuzzy-c-means/commit/ef3fcdcbe55e8b07f8944a1f38378cad5baf6674)) 473 | 474 | 475 | ## v1.3.0 (2021-05-06) 476 | 477 | ### Build 478 | 479 | * build: Add commitizen and pre-commit ([`eb382d6`](https://github.com/omadson/fuzzy-c-means/commit/eb382d65855a9f865784cf16584563eb83553850)) 480 | 481 | ### Documentation 482 | 483 | * docs(README.md): Add new installation instructions 484 | 485 | Add instructions to install extra dependencies of windows and examples ([`cc95952`](https://github.com/omadson/fuzzy-c-means/commit/cc95952269ffc68bd79af8abe8471a7e13c5d9fc)) 486 | 487 | ### Feature 488 | 489 | * feat: Add Windows support ([`7ae1e19`](https://github.com/omadson/fuzzy-c-means/commit/7ae1e19acd9ba9699e1443ee7c9667c8ec350b8d)) 490 | 491 | ### Unknown 492 | 493 | * Merge pull request #26 from omadson/feature/add-windows-support 494 | 495 | feat: Add Windows support ([`04914f5`](https://github.com/omadson/fuzzy-c-means/commit/04914f54071afc6a7296826d2e5bcb12eaddd810)) 496 | 497 | * Update README.md ([`ccdee79`](https://github.com/omadson/fuzzy-c-means/commit/ccdee791901aa131b38d86ac45a8996f97865c7f)) 498 | 499 | * Update README.md ([`39e9479`](https://github.com/omadson/fuzzy-c-means/commit/39e94799fb3ab05d1a9851f5a1b37b5698e58f8b)) 500 | 501 | * Update README.md ([`e12fe32`](https://github.com/omadson/fuzzy-c-means/commit/e12fe32eae47ddcd20afd21949ac0e27178bb1da)) 502 | 503 | * Update README.md ([`e81f223`](https://github.com/omadson/fuzzy-c-means/commit/e81f2231b7cd7f7bbee8e2f551e55bbd3dd52cca)) 504 | 505 | * Merge pull request #24 from omadson/omadson-patch-2 506 | 507 | Adding a citaion on README.md ([`2a003e4`](https://github.com/omadson/fuzzy-c-means/commit/2a003e42ad51fd5557bb25d611ea4208a350c9d3)) 508 | 509 | * Adding a citaion on README.md ([`cec7006`](https://github.com/omadson/fuzzy-c-means/commit/cec7006a6dae0ed5d7c4420cd2f60011c5629bbc)) 510 | 511 | * Merge pull request #22 from omadson/omadson-patch-1 512 | 513 | change image of the basic example. ([`7ea091d`](https://github.com/omadson/fuzzy-c-means/commit/7ea091ddb6daaae1c4c4f421e2ed58948a136513)) 514 | 515 | * change image of the basic example. ([`b1aee42`](https://github.com/omadson/fuzzy-c-means/commit/b1aee425e90ab520aa417149ddb3b5cd85edfbdb)) 516 | 517 | 518 | ## v1.2.4 (2020-12-15) 519 | 520 | ### Unknown 521 | 522 | * Merge pull request #20 from omadson/hotfix/change-python-version 523 | 524 | change python version ([`a37e4e9`](https://github.com/omadson/fuzzy-c-means/commit/a37e4e92263243c30d903f2f24532b43258c9e0a)) 525 | 526 | * change python version ([`8e60cfd`](https://github.com/omadson/fuzzy-c-means/commit/8e60cfdfb2fddc9439b99193edbff25fad9792b0)) 527 | 528 | * Merge pull request #18 from omadson/feature/partition-entropy-coefficient 529 | 530 | adding partition entropy coefficient metric ([`d270bff`](https://github.com/omadson/fuzzy-c-means/commit/d270bff932e905e27a0698735bb00e6db4ab0ce7)) 531 | 532 | * adding partition entropy coefficient metric ([`a076842`](https://github.com/omadson/fuzzy-c-means/commit/a0768422321f38fc64e1be42f77ce43babf5de68)) 533 | 534 | 535 | ## v1.2.3 (2020-12-07) 536 | 537 | ### Unknown 538 | 539 | * Merge pull request #17 from omadson/hotfix/versioning 540 | 541 | Update __init__.py ([`02c4765`](https://github.com/omadson/fuzzy-c-means/commit/02c4765ede48a429c2be8bea3770ddf3407bc5cb)) 542 | 543 | * Update __init__.py 544 | 545 | remove some things ([`7ddb07b`](https://github.com/omadson/fuzzy-c-means/commit/7ddb07b4af35ceac099ba11bacb28dfc08d4c6e2)) 546 | 547 | 548 | ## v1.2.2 (2020-12-07) 549 | 550 | ### Unknown 551 | 552 | * Merge pull request #15 from omadson/feature/partition-coefficient-metric 553 | 554 | Feature/partition coefficient metric ([`4412e1f`](https://github.com/omadson/fuzzy-c-means/commit/4412e1f17ad75841a5d4c80a979a15490095915c)) 555 | 556 | * adding clustering validation example. ([`c00fa57`](https://github.com/omadson/fuzzy-c-means/commit/c00fa570dae69d1f37834635f09cbb0373a0d126)) 557 | 558 | * adding partition coefficient validation metric. ([`032f200`](https://github.com/omadson/fuzzy-c-means/commit/032f20064621e0b2a86465587886a9cf0392401c)) 559 | 560 | * adding new dev dependencies ([`7c25633`](https://github.com/omadson/fuzzy-c-means/commit/7c25633794d18affec1b8dda5e9ff125c678bc32)) 561 | 562 | * changing basic example and adding an image ([`ea186f9`](https://github.com/omadson/fuzzy-c-means/commit/ea186f9127e439576bf6f35a5ce2efd984f0e002)) 563 | 564 | * adding basic clustering example ([`4d2fe13`](https://github.com/omadson/fuzzy-c-means/commit/4d2fe130573569eae3d2ff5157abb6d3dbab0c42)) 565 | 566 | 567 | ## v1.2.1 (2020-12-02) 568 | 569 | ### Unknown 570 | 571 | * Merge pull request #12 from omadson/hotfix/dynamic-versioning 572 | 573 | fix dynamic versioning ([`2c3f7cb`](https://github.com/omadson/fuzzy-c-means/commit/2c3f7cbe1b643361ace3ce131d2d3ffe5d88d6ae)) 574 | 575 | * fix dinamic versioning ([`90e3a24`](https://github.com/omadson/fuzzy-c-means/commit/90e3a243247bfb331560b512ebfb052bfea52a7e)) 576 | 577 | 578 | ## v1.2.0 (2020-12-01) 579 | 580 | ### Unknown 581 | 582 | * Merge pull request #11 from omadson/refactor/use-jax 583 | 584 | Refactor/use jax ([`8897991`](https://github.com/omadson/fuzzy-c-means/commit/889799167fb4018dba5e813d57503b3298ea1a10)) 585 | 586 | * refactoring to use jax ([`c4a2967`](https://github.com/omadson/fuzzy-c-means/commit/c4a2967735fb4d9a889999655510cd1486a07681)) 587 | 588 | * refactoring to work with jax arrays ([`ab6cc9c`](https://github.com/omadson/fuzzy-c-means/commit/ab6cc9cee037a9af0ae56a54483cde8a02907719)) 589 | 590 | * removing numpy and adding jax as dependency ([`5174cc2`](https://github.com/omadson/fuzzy-c-means/commit/5174cc2ce82b43f4378005b05ae68f1fdf88d27c)) 591 | 592 | * Merge pull request #10 from omadson/feature/add-examples-1 593 | 594 | Feature/add examples 1 ([`eb027fd`](https://github.com/omadson/fuzzy-c-means/commit/eb027fd4b1ee9d6e9b1a76bb2e30c1f43cafd776)) 595 | 596 | * adding colour quantization example ([`04b23d4`](https://github.com/omadson/fuzzy-c-means/commit/04b23d48bf9f6e2bf2c3d9b5f6cdfdd2307200d7)) 597 | 598 | * adding dev dependencies ([`c633d18`](https://github.com/omadson/fuzzy-c-means/commit/c633d181d7d78863e028e1afa204c2db9f2ab110)) 599 | 600 | 601 | ## v1.1.1 (2020-11-20) 602 | 603 | ### Unknown 604 | 605 | * Merge pull request #9 from omadson/refactor/changing-zenodo-version 606 | 607 | Update README.md ([`f03df97`](https://github.com/omadson/fuzzy-c-means/commit/f03df97bf1401ca25dde2fee8bc7be0993e8792f)) 608 | 609 | * Update README.md 610 | 611 | - add zenodo badged 612 | - change citation style ([`9f30097`](https://github.com/omadson/fuzzy-c-means/commit/9f30097d88b116e500f4009102983558a1cbaf57)) 613 | 614 | 615 | ## v1.1.0 (2020-11-20) 616 | 617 | ### Unknown 618 | 619 | * Merge pull request #8 from omadson/feature/publish-package-on-github-release 620 | 621 | [feature] automate PyPi package publishing with GitHub Actions ([`3e28320`](https://github.com/omadson/fuzzy-c-means/commit/3e2832060dae0ed70896f6b44e824db66aa9e53f)) 622 | 623 | * adding tools to publish the package with the creation of a github release ([`0f7b37e`](https://github.com/omadson/fuzzy-c-means/commit/0f7b37e1a0e0c50025f2ece6e53b2e73c72448ce)) 624 | 625 | * Merge pull request #7 from omadson/feature/remove-scipy-as-dependence 626 | 627 | Feature/remove scipy as dependence ([`43cf499`](https://github.com/omadson/fuzzy-c-means/commit/43cf499670d1b8a59b036909a6f4409d1c07456e)) 628 | 629 | * changing version number ([`f18c432`](https://github.com/omadson/fuzzy-c-means/commit/f18c4321fa040625713efd6e95c2918f8f5161f5)) 630 | 631 | * changing basic example ([`9c2b660`](https://github.com/omadson/fuzzy-c-means/commit/9c2b6601981357f5d8fc6ba640f739b722f49fe9)) 632 | 633 | * removing sklean as dependency and adding np.einsum to compute distance ([`fbb1a45`](https://github.com/omadson/fuzzy-c-means/commit/fbb1a45e558cba8cd4e098bbf29de5ced43c7d58)) 634 | 635 | * removing dev libraries ([`fc1e510`](https://github.com/omadson/fuzzy-c-means/commit/fc1e510dd6219d24432a5c84724133a7d4ae483f)) 636 | 637 | * Merge pull request #6 from zealberth/feature/add-poetry 638 | 639 | [feature] Add Poetry as dependency management system and packaging ([`d8721ac`](https://github.com/omadson/fuzzy-c-means/commit/d8721acd82c7cf4ef83d0b8bdf4e8545ba0cfca1)) 640 | 641 | * Moving some dependencies to development dependencies and adding me into the contributors section ([`9f924f9`](https://github.com/omadson/fuzzy-c-means/commit/9f924f9819320da7ada96554b9fd3487638e21f9)) 642 | 643 | * changing to poetry dependencies system ([`e521b07`](https://github.com/omadson/fuzzy-c-means/commit/e521b0774bd9563c7b4a1236997a802a08ad3240)) 644 | 645 | * adding ipynb folder ([`b5a0ab8`](https://github.com/omadson/fuzzy-c-means/commit/b5a0ab89f8337b24aad183d055eb3b9c9f3ee914)) 646 | 647 | * adds download badge ([`152091e`](https://github.com/omadson/fuzzy-c-means/commit/152091e205aa9ea8e20acb30bde9afbf146fa02f)) 648 | 649 | * Update README.md ([`592a9be`](https://github.com/omadson/fuzzy-c-means/commit/592a9be597d39ff8d41440137ddcb1ef7a9e188c)) 650 | 651 | * Merge pull request #1 from dirknbr/patch-1 652 | 653 | some fixes ([`e966835`](https://github.com/omadson/fuzzy-c-means/commit/e9668353a0335c83b3e492d1e0dfd8dc38ddf5d5)) 654 | 655 | * Merge pull request #2 from dirknbr/patch-2 656 | 657 | proper test with data ([`c9aa081`](https://github.com/omadson/fuzzy-c-means/commit/c9aa081203b50d5b0b1722057817f09d736ee47d)) 658 | 659 | * proper test with data ([`718e91a`](https://github.com/omadson/fuzzy-c-means/commit/718e91a36afe4c7eb1d1b2a8ec585714feca4242)) 660 | 661 | * some fixes 662 | 663 | don't retun self, so model stays in the object, will also add changes to test ([`f6cf931`](https://github.com/omadson/fuzzy-c-means/commit/f6cf931d91dbc8b72220ecb972611e532e9be9de)) 664 | 665 | * add docstrings (WIP) ([`032143b`](https://github.com/omadson/fuzzy-c-means/commit/032143ba10f51febc8ad6141d3f094283615966e)) 666 | 667 | * add some docstrings (WIP) ([`653ea51`](https://github.com/omadson/fuzzy-c-means/commit/653ea51703a7fc513fb12999f595b98702f72ea7)) 668 | 669 | * Create CONTRIBUTING.md ([`6402ae5`](https://github.com/omadson/fuzzy-c-means/commit/6402ae54ede6d60975550f34ab22c4acd45d8ae5)) 670 | 671 | * add random_state parameter to enable reproducibility ([`71dbffa`](https://github.com/omadson/fuzzy-c-means/commit/71dbffa395426e5cc8a3bae2aa51c7bee1cce153)) 672 | 673 | * fix package name ([`5ed086a`](https://github.com/omadson/fuzzy-c-means/commit/5ed086a94e3a3d8a886c147cd9dfaa9b15df8b06)) 674 | 675 | * update to 0.0.4 version ([`8bf6bd5`](https://github.com/omadson/fuzzy-c-means/commit/8bf6bd5686076a9a68bac6e646995f31746e397e)) 676 | 677 | * add tests/ folder ([`0c4e7b0`](https://github.com/omadson/fuzzy-c-means/commit/0c4e7b09330ed3c9db5ac29eff99d4dcaf22b92f)) 678 | 679 | * fix bug ([`fb84d8b`](https://github.com/omadson/fuzzy-c-means/commit/fb84d8b0f03df8e15b3aa9b4af0b0d744ade1cf8)) 680 | 681 | * change lib name ([`1c1e88e`](https://github.com/omadson/fuzzy-c-means/commit/1c1e88e9874213a6f8dd0ca7b81c7e6736ffac4b)) 682 | 683 | * add FCM class ([`1dff450`](https://github.com/omadson/fuzzy-c-means/commit/1dff45025b58937580e368cfac318f3482c4c8e9)) 684 | 685 | * initial commit ([`eecea35`](https://github.com/omadson/fuzzy-c-means/commit/eecea3556917465e92ca15dd57fdf2595f13570e)) 686 | --------------------------------------------------------------------------------