=========
MatCoupLy
=========
*Learning coupled matrix factorizations with Python*
.. image:: https://github.com/MarieRoald/matcouply/actions/workflows/Tests.yml/badge.svg
:target: https://github.com/MarieRoald/matcouply/actions/workflows/Tests.yml
:alt: Tests
.. image:: https://codecov.io/gh/MarieRoald/matcouply/branch/main/graph/badge.svg?token=GDCXEF2MGE
:target: https://codecov.io/gh/MarieRoald/matcouply
:alt: Coverage
.. image:: https://readthedocs.org/projects/matcouply/badge/?version=latest
:target: https://matcouply.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
.. image:: https://zenodo.org/badge/402865945.svg
:target: https://zenodo.org/badge/latestdoi/402865945
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/psf/black
MatCoupLy is a Python library for learning coupled matrix factorizations with flexible constraints and regularization.
For a quick introduction to coupled matrix factorization and PARAFAC2 see the `online documentation <https://matcouply.readthedocs.io/en/latest/index.html>`_.
Installation
------------
To install MatCoupLy and all MIT-compatible dependencies from PyPI, you can run
.. code::
pip install matcouply
If you also want to enable total variation regularization, you need to install all components, which comes with a GPL-v3 lisence
.. code::
pip install matcouply[gpl]
About
-----
.. image:: docs/figures/CMF_multiblock.svg
:alt: Illustration of a coupled matrix factorization
MatCoupLy is a Python library that adds support for coupled matrix factorization in
`TensorLy <https://github.com/tensorly/tensorly/>`_. For optimization, MatCoupLy uses
alternating updates with the alternating direction method of multipliers (AO-ADMM),
which allows you to fit coupled matrix factorization (and PARAFAC2) models with flexible
constraints in any mode of your data [1, 2]. Currently, MatCoupLy supports the NumPy and
PyTorch backends of TensorLy.
Example
-------
Below is a simulated example, where a set of 15 non-negative coupled matrices are generated and
decomposed using a non-negative PARAFAC2 factorization with an L1 penalty on **C**, constraining
the maximum norm of the **A** and **Bᵢ** matrices and unimodality constraints on the component
vectors in the **Bᵢ** matrices. For more examples, see the `Gallery of examples <https://matcouply.readthedocs.io/en/latest/auto_examples/index.html>`_
in the `online documentation <https://matcouply.readthedocs.io/en/latest/index.html>`_.
.. code:: python
import matplotlib.pyplot as plt
import numpy as np
from matcouply.data import get_simple_simulated_data
from matcouply.decomposition import cmf_aoadmm
noisy_matrices, cmf = get_simple_simulated_data(noise_level=0.2, random_state=1)
rank = cmf.rank
weights, (A, B_is, C) = cmf
# Decompose the dataset
estimated_cmf = cmf_aoadmm(
noisy_matrices,
rank=rank,
non_negative=True, # Constrain all components to be non-negative
l1_penalty={2: 0.1}, # Sparsity on C
l2_norm_bound=[1, 1, 0], # Norm of A and B_i-component vectors less than 1
parafac2=True, # Enforce PARAFAC2 constraint
unimodal={1: True}, # Unimodality (one peak) on the B_i component vectors
constant_feasibility_penalty=True, # Must be set to apply l2_norm_penalty (row-penalty) on A. See documentation for more details
verbose=-1, # Negative verbosity level for minimal (nonzero) printouts
random_state=0, # A seed can be given similar to how it's done in TensorLy
)
est_weights, (est_A, est_B_is, est_C) = estimated_cmf
# Code to display the results
def normalize(M):
return M / np.linalg.norm(M, axis=0)
fig, axes = plt.subplots(2, 3, figsize=(5, 2))
axes[0, 0].plot(normalize(A))
axes[0, 1].plot(normalize(B_is[0]))
axes[0, 2].plot(normalize(C))
axes[1, 0].plot(normalize(est_A))
axes[1, 1].plot(normalize(est_B_is[0]))
axes[1, 2].plot(normalize(est_C))
axes[0, 0].set_title(r"$\mathbf{A}$")
axes[0, 1].set_title(r"$\mathbf{B}_0$")
axes[0, 2].set_title(r"$\mathbf{C}$")
axes[0, 0].set_ylabel("True")
axes[1, 0].set_ylabel("Estimated")
for ax in axes.ravel():
ax.set_yticks([]) # Components can be aribtrarily scaled
for ax in axes[0]:
ax.set_xticks([]) # Remove xticks from upper row
plt.savefig("figures/readme_components.png", dpi=300)
.. code:: raw
All regularization penalties (including regs list):
* Mode 0:
- <'matcouply.penalties.L2Ball' with aux_init='random_uniform', dual_init='random_uniform', norm_bound=1, non_negativity=True)>
* Mode 1:
- <'matcouply.penalties.Parafac2' with svd='truncated_svd', aux_init='random_uniform', dual_init='random_uniform', update_basis_matrices=True, update_coordinate_matrix=True, n_iter=1)>
- <'matcouply.penalties.Unimodality' with aux_init='random_uniform', dual_init='random_uniform', non_negativity=True)>
- <'matcouply.penalties.L2Ball' with aux_init='random_uniform', dual_init='random_uniform', norm_bound=1, non_negativity=True)>
* Mode 2:
- <'matcouply.penalties.L1Penalty' with aux_init='random_uniform', dual_init='random_uniform', reg_strength=0.1, non_negativity=True)>
converged in 218 iterations: FEASIBILITY GAP CRITERION AND RELATIVE LOSS CRITERION SATISFIED
.. image:: figures/readme_components.png
:alt: Plot of simulated and estimated components
References
----------
* [1]: Roald M, Schenker C, Cohen JE, Acar E PARAFAC2 AO-ADMM: Constraints in all modes. EUSIPCO (2021).
* [2]: Roald M, Schenker C, Calhoun VD, Adali T, Bro R, Cohen JE, Acar E An AO-ADMM approach to constraining PARAFAC2 on all modes (2022). Accepted for publication in SIAM Journal on Mathematics of Data Science, arXiv preprint arXiv:2110.01278.
Raw data
{
"_id": null,
"home_page": "https://github.com/marieroald/matcouply",
"name": "matcouply",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "",
"keywords": "matcouply",
"author": "Marie Roald",
"author_email": "roald.marie@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/39/ce/63ec5ae13beb308e1b86039b9f1588bfc5018302ef3bd43b12f399220e56/matcouply-0.1.6.tar.gz",
"platform": null,
"description": "=========\nMatCoupLy\n=========\n*Learning coupled matrix factorizations with Python*\n\n.. image:: https://github.com/MarieRoald/matcouply/actions/workflows/Tests.yml/badge.svg\n :target: https://github.com/MarieRoald/matcouply/actions/workflows/Tests.yml\n :alt: Tests\n\n.. image:: https://codecov.io/gh/MarieRoald/matcouply/branch/main/graph/badge.svg?token=GDCXEF2MGE\n :target: https://codecov.io/gh/MarieRoald/matcouply\n :alt: Coverage\n\n.. image:: https://readthedocs.org/projects/matcouply/badge/?version=latest\n :target: https://matcouply.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation Status\n\n.. image:: https://zenodo.org/badge/402865945.svg\n :target: https://zenodo.org/badge/latestdoi/402865945\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n :target: https://github.com/psf/black\n\n\nMatCoupLy is a Python library for learning coupled matrix factorizations with flexible constraints and regularization.\nFor a quick introduction to coupled matrix factorization and PARAFAC2 see the `online documentation <https://matcouply.readthedocs.io/en/latest/index.html>`_.\n\nInstallation\n------------\n\nTo install MatCoupLy and all MIT-compatible dependencies from PyPI, you can run\n\n.. code::\n\n pip install matcouply\n\nIf you also want to enable total variation regularization, you need to install all components, which comes with a GPL-v3 lisence\n\n.. code::\n\n pip install matcouply[gpl]\n\nAbout\n-----\n\n.. image:: docs/figures/CMF_multiblock.svg\n :alt: Illustration of a coupled matrix factorization\n\nMatCoupLy is a Python library that adds support for coupled matrix factorization in\n`TensorLy <https://github.com/tensorly/tensorly/>`_. For optimization, MatCoupLy uses\nalternating updates with the alternating direction method of multipliers (AO-ADMM),\nwhich allows you to fit coupled matrix factorization (and PARAFAC2) models with flexible\nconstraints in any mode of your data [1, 2]. Currently, MatCoupLy supports the NumPy and\nPyTorch backends of TensorLy.\n\n\nExample\n-------\n\nBelow is a simulated example, where a set of 15 non-negative coupled matrices are generated and\ndecomposed using a non-negative PARAFAC2 factorization with an L1 penalty on **C**, constraining\nthe maximum norm of the **A** and **B\u1d62** matrices and unimodality constraints on the component\nvectors in the **B\u1d62** matrices. For more examples, see the `Gallery of examples <https://matcouply.readthedocs.io/en/latest/auto_examples/index.html>`_\nin the `online documentation <https://matcouply.readthedocs.io/en/latest/index.html>`_.\n\n\n.. code:: python\n\n import matplotlib.pyplot as plt\n import numpy as np\n\n from matcouply.data import get_simple_simulated_data\n from matcouply.decomposition import cmf_aoadmm\n\n noisy_matrices, cmf = get_simple_simulated_data(noise_level=0.2, random_state=1)\n rank = cmf.rank\n weights, (A, B_is, C) = cmf\n\n # Decompose the dataset\n estimated_cmf = cmf_aoadmm(\n noisy_matrices,\n rank=rank,\n non_negative=True, # Constrain all components to be non-negative\n l1_penalty={2: 0.1}, # Sparsity on C\n l2_norm_bound=[1, 1, 0], # Norm of A and B_i-component vectors less than 1\n parafac2=True, # Enforce PARAFAC2 constraint\n unimodal={1: True}, # Unimodality (one peak) on the B_i component vectors\n constant_feasibility_penalty=True, # Must be set to apply l2_norm_penalty (row-penalty) on A. See documentation for more details\n verbose=-1, # Negative verbosity level for minimal (nonzero) printouts\n random_state=0, # A seed can be given similar to how it's done in TensorLy\n )\n\n est_weights, (est_A, est_B_is, est_C) = estimated_cmf\n\n # Code to display the results\n def normalize(M):\n return M / np.linalg.norm(M, axis=0)\n\n fig, axes = plt.subplots(2, 3, figsize=(5, 2))\n axes[0, 0].plot(normalize(A))\n axes[0, 1].plot(normalize(B_is[0]))\n axes[0, 2].plot(normalize(C))\n\n axes[1, 0].plot(normalize(est_A))\n axes[1, 1].plot(normalize(est_B_is[0]))\n axes[1, 2].plot(normalize(est_C))\n\n axes[0, 0].set_title(r\"$\\mathbf{A}$\")\n axes[0, 1].set_title(r\"$\\mathbf{B}_0$\")\n axes[0, 2].set_title(r\"$\\mathbf{C}$\")\n\n axes[0, 0].set_ylabel(\"True\")\n axes[1, 0].set_ylabel(\"Estimated\")\n\n for ax in axes.ravel():\n ax.set_yticks([]) # Components can be aribtrarily scaled\n for ax in axes[0]:\n ax.set_xticks([]) # Remove xticks from upper row\n\n plt.savefig(\"figures/readme_components.png\", dpi=300)\n\n\n\n\n.. code:: raw\n\n All regularization penalties (including regs list):\n * Mode 0:\n - <'matcouply.penalties.L2Ball' with aux_init='random_uniform', dual_init='random_uniform', norm_bound=1, non_negativity=True)>\n * Mode 1:\n - <'matcouply.penalties.Parafac2' with svd='truncated_svd', aux_init='random_uniform', dual_init='random_uniform', update_basis_matrices=True, update_coordinate_matrix=True, n_iter=1)>\n - <'matcouply.penalties.Unimodality' with aux_init='random_uniform', dual_init='random_uniform', non_negativity=True)>\n - <'matcouply.penalties.L2Ball' with aux_init='random_uniform', dual_init='random_uniform', norm_bound=1, non_negativity=True)>\n * Mode 2:\n - <'matcouply.penalties.L1Penalty' with aux_init='random_uniform', dual_init='random_uniform', reg_strength=0.1, non_negativity=True)>\n converged in 218 iterations: FEASIBILITY GAP CRITERION AND RELATIVE LOSS CRITERION SATISFIED\n\n.. image:: figures/readme_components.png\n :alt: Plot of simulated and estimated components\n\nReferences\n----------\n\n* [1]: Roald M, Schenker C, Cohen JE, Acar E PARAFAC2 AO-ADMM: Constraints in all modes. EUSIPCO (2021).\n* [2]: Roald M, Schenker C, Calhoun VD, Adali T, Bro R, Cohen JE, Acar E An AO-ADMM approach to constraining PARAFAC2 on all modes (2022). Accepted for publication in SIAM Journal on Mathematics of Data Science, arXiv preprint arXiv:2110.01278.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Regularized coupled matrix factorisation with AO-ADMM",
"version": "0.1.6",
"split_keywords": [
"matcouply"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "0e586f519a2238d44b8e50e8a654b4b68e921bcdfa800d7c0ba34a0f58183fb3",
"md5": "94b97d692bc99984c4605e80dff2263b",
"sha256": "b536271774807da452a236b65bb652dcd268f9ed8fb1753ae618f0020883dc97"
},
"downloads": -1,
"filename": "matcouply-0.1.6-py3-none-any.whl",
"has_sig": false,
"md5_digest": "94b97d692bc99984c4605e80dff2263b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 2311874,
"upload_time": "2023-02-07T18:35:55",
"upload_time_iso_8601": "2023-02-07T18:35:55.045055Z",
"url": "https://files.pythonhosted.org/packages/0e/58/6f519a2238d44b8e50e8a654b4b68e921bcdfa800d7c0ba34a0f58183fb3/matcouply-0.1.6-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "39ce63ec5ae13beb308e1b86039b9f1588bfc5018302ef3bd43b12f399220e56",
"md5": "c9fb3464bb5ff989701f07d0372fa271",
"sha256": "58ad0871abd0c6933a76023d947bb1803c22a5946284c3c0dbe24d8d2f8fa43a"
},
"downloads": -1,
"filename": "matcouply-0.1.6.tar.gz",
"has_sig": false,
"md5_digest": "c9fb3464bb5ff989701f07d0372fa271",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 1576080,
"upload_time": "2023-02-07T18:35:57",
"upload_time_iso_8601": "2023-02-07T18:35:57.459783Z",
"url": "https://files.pythonhosted.org/packages/39/ce/63ec5ae13beb308e1b86039b9f1588bfc5018302ef3bd43b12f399220e56/matcouply-0.1.6.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-02-07 18:35:57",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "marieroald",
"github_project": "matcouply",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [
{
"name": "coverage",
"specs": []
},
{
"name": "pytest",
"specs": []
},
{
"name": "pytest-cov",
"specs": []
},
{
"name": "pytest-randomly",
"specs": []
},
{
"name": "sphinx",
"specs": []
},
{
"name": "sphinx-rtd-theme",
"specs": []
},
{
"name": "sphinx-gallery",
"specs": []
},
{
"name": "sphinxcontrib-bibtex",
"specs": []
},
{
"name": "flake8",
"specs": []
},
{
"name": "black",
"specs": []
},
{
"name": "isort",
"specs": []
},
{
"name": "bump2version",
"specs": []
},
{
"name": "wheel",
"specs": []
},
{
"name": "numpy",
"specs": []
},
{
"name": "scipy",
"specs": []
},
{
"name": "tensorly",
"specs": []
},
{
"name": "autodocsumm",
"specs": []
},
{
"name": "matplotlib",
"specs": []
},
{
"name": "plotly",
"specs": []
},
{
"name": "pandas",
"specs": []
},
{
"name": "wordcloud",
"specs": []
},
{
"name": "tqdm",
"specs": []
},
{
"name": "tlviz",
"specs": []
},
{
"name": "condat_tv",
"specs": []
}
],
"lcname": "matcouply"
}