diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 8d5748e..30c80a6 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,47 +1,45 @@
repos:
-- repo: https://github.com/datarootsio/databooks
- rev: 1.3.7
- hooks:
- - id: databooks-meta
-- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v3.4.0
- hooks:
- - id: check-added-large-files
- args: ['--maxkb=300']
- - id: check-byte-order-marker
- - id: check-case-conflict
- - id: check-merge-conflict
- - id: end-of-file-fixer
- - id: forbid-new-submodules
- - id: mixed-line-ending
- - id: trailing-whitespace
- - id: debug-statements
- - id: check-yaml
- exclude: .conda/meta.yaml
- - id: requirements-txt-fixer
-- repo: https://github.com/pycqa/flake8.git
- rev: 6.1.0
- hooks:
- - id: flake8
- additional_dependencies: [flake8-print, "importlib-metadata<5.0.0"]
- args: [--config=setup.cfg]
- exclude: ^examples/
-- repo: https://github.com/psf/black
- rev: 23.11.0
- hooks:
- - id: black
- language_version: python3
- additional_dependencies: ['click==8.0.4']
-- repo: https://github.com/pycqa/isort
- rev: 5.11.2
- hooks:
- - id: isort
- name: isort
- entry: python -m isort
- args: [--settings-path, ./pyproject.toml]
- language: system
- types: [python]
-- repo: https://github.com/pre-commit/mirrors-mypy
- rev: v1.5.0
- hooks:
- - id: mypy
+ - repo: https://github.com/datarootsio/databooks
+ rev: 1.3.7
+ hooks:
+ - id: databooks-meta
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v3.4.0
+ hooks:
+ - id: check-added-large-files
+ args: ["--maxkb=300"]
+ - id: check-byte-order-marker
+ - id: check-case-conflict
+ - id: check-merge-conflict
+ - id: end-of-file-fixer
+ - id: forbid-new-submodules
+ - id: mixed-line-ending
+ - id: trailing-whitespace
+ - id: debug-statements
+ - id: check-yaml
+ exclude: .conda/meta.yaml
+ - id: requirements-txt-fixer
+ - repo: https://github.com/pycqa/flake8.git
+ rev: 6.1.0
+ hooks:
+ - id: flake8
+ additional_dependencies: [flake8-print, "importlib-metadata<5.0.0"]
+ args: [--config=setup.cfg]
+ exclude: ^examples/
+ - repo: https://github.com/psf/black
+ rev: 23.11.0
+ hooks:
+ - id: black
+ language_version: python3
+ additional_dependencies: ["click==8.0.4"]
+ - repo: https://github.com/pycqa/isort
+ rev: 5.13.2
+ hooks:
+ - id: isort
+ name: isort
+ args: [--settings-path, ./pyproject.toml]
+ types: [python]
+ - repo: https://github.com/pre-commit/mirrors-mypy
+ rev: v1.5.0
+ hooks:
+ - id: mypy
diff --git a/README.md b/README.md
index cb87e08..f32c024 100644
--- a/README.md
+++ b/README.md
@@ -1,40 +1,32 @@
-# Kale-Linear
+
+
+
-Kale-Linear is a Python library for non-deep, knowledge-aware machine learning
-from multiple sources, domains, or views. It provides NumPy-based methods for
-leveraging related data distributions and structural assumptions, including
-transfer learning, domain adaptation, manifold regularization, and group-aware
-learning, through a scikit-learn style API.
+
+
+[](https://github.com/pykale/linear/blob/main/LICENSE)
+[](https://www.python.org)
+[](https://pypi.org/project/kalelinear/)
+[](https://pepy.tech/project/kalelinear)
-The package is part of the PyKale ecosystem and focuses on classical linear and
-kernel methods that are useful when data are structured by domain labels,
-covariates, side information, or unlabeled target samples.
-## Features
+`kalelinear` is a Python library for learning harmonized or individualized models from multi-source/multi-view data in linear or reproducing kernel Hilbert spaces (RKHS). It provides NumPy-based methods for leveraging related data distributions and structural assumptions, including transfer learning, domain adaptation, manifold regularization, and group-aware learning, through a [`scikit-learn`](https://github.com/scikit-learn/scikit-learn) style API.
+
+The package is part of the [PyKale](https://github.com/pykale/pykale) ecosystem and focuses on linear and kernel methods for data characterized by covariates (e.g., domain labels, group labels, side information), unlabeled target samples, or tensor structures.
+
+## Methods and features
- Transformer models for learning feature embeddings:
- - Multilinear Principal Component Analysis (MPCA): Lu et al., 2008
- [[IEEE](https://ieeexplore.ieee.org/abstract/document/4359192)]
- - Transfer Component Analysis (TCA): Pan et al., 2009
- [[paper](http://www.aaai.org/ocs/index.php/IJCAI/IJCAI-09/paper/download/294/962)]
- - Joint Distribution Adaptation (JDA): Long et al., 2013
- [[paper](http://openaccess.thecvf.com/content_iccv_2013/papers/Long_Transfer_Feature_Learning_2013_ICCV_paper.pdf)]
- - Balanced Distribution Adaptation (BDA): Wang et al., 2017
- [[paper](http://jd92.wang/assets/files/a08_icdm17.pdf)]
- - Maximum Independence Domain Adaptation (MIDA): Yan et al., 2017
- [[paper](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=7815350)]
-- Estimator models for classification and adaptation:
- - Manifold Regularization Learning Framework (LapSVM, LapRLS): Belkin et al.,
- 2006 [[paper](http://www.jmlr.org/papers/v7/belkin06a.html)]
- - Adaptation Regularization Learning Framework (ARSVM, ARRLS): Long et al.,
- 2014 [[paper](https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=6550016)]
- - Covariate Independence Regularized Learning Framework (CoIRSVM, CoIRLS):
- Zhou et al., 2020
- [[paper](https://aaai.org/ojs/index.php/AAAI/article/view/6179)],
- Zhou, 2022 [[thesis](https://etheses.whiterose.ac.uk/id/eprint/31044/)]
- - Group-specific Discriminant Analysis (GSDA): Zhou et al., 2025
- [[paper](https://academic.oup.com/gigascience/article/doi/10.1093/gigascience/giaf082/8244707)],
- Zhou, 2022 [[thesis](https://etheses.whiterose.ac.uk/id/eprint/31044/)]
+ - Multilinear Principal Component Analysis (MPCA) [[1](#references)]
+ - Transfer Component Analysis (TCA) [[2](#references)]
+ - Joint Distribution Adaptation (JDA) [[3](#references)]
+ - Balanced Distribution Adaptation (BDA) [[4](#references)]
+ - Maximum Independence Domain Adaptation (MIDA) [[5](#references)]
+- Estimator models for classification:
+ - Manifold Regularization Learning Framework (LapSVM, LapRLS) [[6](#references)]
+ - Adaptation Regularization Learning Framework (ARSVM, ARRLS) [[7](#references)]
+ - Covariate Independence Regularized Learning Framework (CoIRSVM, CoIRLS) [[8](#references)][[9](#references)]
+ - Group-specific Discriminant Analysis (GSDA) [[9](#references)][[10](#references)]
- NumPy-compatible inputs and outputs.
- scikit-learn style `fit`, `transform`, `predict`, `fit_transform`, and
`fit_predict` workflows where applicable.
@@ -54,7 +46,7 @@ Install from a local checkout for development:
pip install -e ".[dev]"
```
-Kale-Linear requires Python 3.10 or later. Core dependencies include:
+`kalelinear` requires Python 3.10 or later. Core dependencies include:
- [NumPy](http://www.numpy.org/)
- [SciPy](https://www.scipy.org/)
@@ -198,8 +190,29 @@ From the root of the repository, run the following commands in your terminal:
sphinx-build -b html docs/source docs/build/html
```
+# References
+
+[1] Lu, H., Plataniotis, K.N. and Venetsanopoulos, A.N., 2008. [MPCA: Multilinear principal component analysis of tensor objects](https://ieeexplore.ieee.org/abstract/document/4359192/). _IEEE Transactions on Neural Networks_, 19(1), pp.18-39.
+
+[2] Pan, S.J., Tsang, I.W., Kwok, J.T. and Yang, Q., 2011. [Domain adaptation via transfer component analysis](https://dl.acm.org/doi/abs/10.1109/TNN.2010.2091281). _IEEE Transactions on Neural Networks_, 22(2), p.199-210.
+
+[3] Long, M., Wang, J., Ding, G., Sun, J. and Yu, P.S., 2013. [Transfer feature learning with joint distribution adaptation.](https://openaccess.thecvf.com/content_iccv_2013/papers/Long_Transfer_Feature_Learning_2013_ICCV_paper.pdf) In _Proceedings of the IEEE International Conference on Computer Vision_ (pp. 2200-2207).
+
+[4] Wang, J., Chen, Y., Hao, S., Feng, W. and Shen, Z., 2017, November. [Balanced distribution adaptation for transfer learning](https://ieeexplore.ieee.org/document/8215613). In _2017 IEEE International Conference on Data Mining (ICDM)_ (pp. 1129-1134). IEEE.
+
+[5] Yan, K., Kou, L. and Zhang, D., 2017. [Learning domain-invariant subspace using domain features and independence maximization](https://ieeexplore.ieee.org/document/7815350). _IEEE Transactions on Cybernetics_, 48(1), pp.288-299.
+
+[6] Belkin, M., Niyogi, P. and Sindhwani, V., 2006. Manifold regularization: [A geometric framework for learning from labeled and unlabeled examples](https://www.jmlr.org/papers/v7/belkin06a.html). _Journal of Machine Learning Research_, 7(11).
+
+[7] Long, M., Wang, J., Ding, G., Pan, S.J. and Yu, P.S., 2013. [Adaptation regularization: A general framework for transfer learning](https://ieeexplore.ieee.org/abstract/document/6550016/). _IEEE Transactions on Knowledge and Data Engineering_, 26(5), pp.1076-1089.
+
+[8] Zhou, S., Li, W., Cox, C. and Lu, H., 2020, April. [Side information dependence as a regularizer for analyzing human brain conditions across cognitive experiments](https://ojs.aaai.org/index.php/AAAI/article/view/6179). In _Proceedings of the AAAI Conference on Artificial Intelligence_ (Vol. 34, No. 04, pp. 6957-6964).
+
+[9] Zhou, S., 2022. [Interpretable Domain-Aware Learning for Neuroimage Classification](https://etheses.whiterose.ac.uk/id/eprint/31044/) (Doctoral dissertation, University of Sheffield).
+
+[10] Zhou, S., Luo, J., Jiang, Y., Wang, H., Lu, H. and Gong, G., 2025. [Group-specific discriminant analysis enhances detection of sex differences in brain functional network lateralization](https://academic.oup.com/gigascience/article/doi/10.1093/gigascience/giaf082/8244707). _GigaScience_, 14, p.giaf082.
-## Related Projects
+## Other open domain adaptation repositories
- [POT: Python Optimal Transport](https://github.com/rflamary/POT)
- [Everything about Transfer Learning](https://github.com/jindongwang/transferlearning)
@@ -211,4 +224,4 @@ From the root of the repository, run the following commands in your terminal:
## License
-Kale-Linear is released under the MIT License. See [LICENSE](LICENSE) for details.
+`kalelinear` is released under the MIT License. See [LICENSE](LICENSE) for details.
diff --git a/docs/images/kalelinear.jpg b/docs/images/kalelinear.jpg
new file mode 100644
index 0000000..ffb3519
Binary files /dev/null and b/docs/images/kalelinear.jpg differ
diff --git a/docs/source/api.rst b/docs/source/api.rst
index 44d0c82..29a5189 100644
--- a/docs/source/api.rst
+++ b/docs/source/api.rst
@@ -6,6 +6,8 @@ API Reference
This page is kept for existing links. The API reference is now split into the
following pages:
+* :doc:`api_embed`
* :doc:`api_transformers`
+* :doc:`api_predict`
* :doc:`api_estimators`
* :doc:`api_utilities`
diff --git a/docs/source/api_embed.rst b/docs/source/api_embed.rst
new file mode 100644
index 0000000..a3dd0dd
--- /dev/null
+++ b/docs/source/api_embed.rst
@@ -0,0 +1,37 @@
+Embed
+=====
+
+.. currentmodule:: kalelinear.embed
+
+This compatibility module mirrors the PyKale-style import path while exposing
+the same transformer classes as :mod:`kalelinear.transformer`.
+
+.. autoclass:: MPCA
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :no-index:
+
+.. autoclass:: TCA
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :no-index:
+
+.. autoclass:: JDA
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :no-index:
+
+.. autoclass:: BDA
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :no-index:
+
+.. autoclass:: MIDA
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :no-index:
diff --git a/docs/source/api_predict.rst b/docs/source/api_predict.rst
new file mode 100644
index 0000000..8483b17
--- /dev/null
+++ b/docs/source/api_predict.rst
@@ -0,0 +1,49 @@
+Predict
+=======
+
+.. currentmodule:: kalelinear.predict
+
+This compatibility module mirrors the PyKale-style import path while exposing
+the same estimator classes as :mod:`kalelinear.estimator`.
+
+.. autoclass:: LapSVM
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :no-index:
+
+.. autoclass:: LapRLS
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :no-index:
+
+.. autoclass:: ARSVM
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :no-index:
+
+.. autoclass:: ARRLS
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :no-index:
+
+.. autoclass:: CoIRSVM
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :no-index:
+
+.. autoclass:: CoIRLS
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :no-index:
+
+.. autoclass:: GSDA
+ :members:
+ :undoc-members:
+ :show-inheritance:
+ :no-index:
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 20b5b87..90ee5fd 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -17,7 +17,9 @@ Kale-Linear API
.. toctree::
:maxdepth: 2
+ api_embed
api_transformers
+ api_predict
api_estimators
api_utilities
@@ -31,7 +33,8 @@ Project
.. toctree::
:maxdepth: 1
- GitHub repository
+ Read the Docs (PyKale subproject)
+ GitHub repository
Indices and Tables
------------------
diff --git a/kalelinear/__init__.py b/kalelinear/__init__.py
index b3408be..a5bc0f5 100644
--- a/kalelinear/__init__.py
+++ b/kalelinear/__init__.py
@@ -1,9 +1,19 @@
"""
kalelinear.
-A Transfer Learning Python package
+Learning harmonized or individualized models from multi-source/multi-view data in linear or reproducing kernel Hilbert spaces (RKHS).
"""
-__version__ = "0.0.1"
-__author__ = "Shuo Zhou"
-__credits__ = "Machine Learning Group, Department of Computer Science, the University of Sheffield"
+from importlib import import_module
+
+__version__ = "0.1.0a1"
+
+__all__ = ["transformer", "estimator", "embed", "predict"]
+
+
+def __getattr__(name):
+ if name in __all__:
+ module = import_module(f"{__name__}.{name}")
+ globals()[name] = module
+ return module
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
diff --git a/kalelinear/embed.py b/kalelinear/embed.py
new file mode 100644
index 0000000..a9f59b3
--- /dev/null
+++ b/kalelinear/embed.py
@@ -0,0 +1,5 @@
+"""Embedding models exposed with a PyKale-style API."""
+
+from kalelinear.transformer import BDA, JDA, MIDA, MPCA, TCA
+
+__all__ = ["TCA", "JDA", "BDA", "MIDA", "MPCA"]
diff --git a/kalelinear/predict.py b/kalelinear/predict.py
new file mode 100644
index 0000000..316142a
--- /dev/null
+++ b/kalelinear/predict.py
@@ -0,0 +1,5 @@
+"""Predictive models exposed with a PyKale-style API."""
+
+from kalelinear.estimator import ARRLS, ARSVM, CoIRLS, CoIRSVM, GSDA, LapRLS, LapSVM
+
+__all__ = ["ARSVM", "ARRLS", "CoIRSVM", "CoIRLS", "GSDA", "LapSVM", "LapRLS"]
diff --git a/setup.py b/setup.py
index ea3008b..1c42d1b 100644
--- a/setup.py
+++ b/setup.py
@@ -70,12 +70,14 @@ def read(*names, **kwargs):
name="kalelinear",
version="0.1.0a1",
description="Non-deep knowledge-aware machine learning from multiple sources/views in Python",
- url="https://github.com/pykale/kale-linear",
+ long_description=read("README.md"),
+ long_description_content_type="text/markdown",
+ url="https://github.com/pykale/linear",
author="The PyKale team",
author_email="pykale-group@sheffield.ac.uk",
project_urls={
- "Bug Tracker": "https://github.com/pykale/kale-linear/issues",
- "Source": "https://github.com/pykale/kale-linear",
+ "Bug Tracker": "https://github.com/pykale/linear/issues",
+ "Source": "https://github.com/pykale/linear",
},
license="MIT License",
packages=find_packages(exclude=("tests*", "examples*", "docs*")),
diff --git a/tests/__init__.py b/tests/__init__.py
index a8e8108..b3ab380 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1 +1 @@
-"""Test package for kale-linear."""
+"""Test package for kalelinear."""
diff --git a/tests/test_public_api.py b/tests/test_public_api.py
new file mode 100644
index 0000000..b431f3b
--- /dev/null
+++ b/tests/test_public_api.py
@@ -0,0 +1,48 @@
+import sys
+
+import kalelinear
+from kalelinear import embed, estimator, predict, transformer
+
+
+def test_embed_module_exposes_transformers():
+ assert embed.TCA is transformer.TCA
+ assert embed.JDA is transformer.JDA
+ assert embed.BDA is transformer.BDA
+ assert embed.MIDA is transformer.MIDA
+ assert embed.MPCA is transformer.MPCA
+
+
+def test_predict_module_exposes_estimators():
+ assert predict.ARSVM is estimator.ARSVM
+ assert predict.ARRLS is estimator.ARRLS
+ assert predict.CoIRSVM is estimator.CoIRSVM
+ assert predict.CoIRLS is estimator.CoIRLS
+ assert predict.GSDA is estimator.GSDA
+ assert predict.LapSVM is estimator.LapSVM
+ assert predict.LapRLS is estimator.LapRLS
+
+
+def test_lazy_modules_are_cached_on_package():
+ assert kalelinear.transformer is transformer
+ assert kalelinear.estimator is estimator
+ assert kalelinear.embed is embed
+ assert kalelinear.predict is predict
+
+
+def test_lazy_attribute_load_triggers_getattr():
+ # Remove cached entries to simulate a cold attribute access through __getattr__.
+ # A plain `from kalelinear import embed` bypasses __getattr__ via submodule
+ # fallback, so this is the only way to actually exercise the lazy-load path.
+ for name in ("embed", "predict"):
+ kalelinear.__dict__.pop(name, None)
+ sys.modules.pop(f"kalelinear.{name}", None)
+
+ loaded_embed = kalelinear.embed
+ assert loaded_embed is sys.modules["kalelinear.embed"]
+
+ loaded_predict = kalelinear.predict
+ assert loaded_predict is sys.modules["kalelinear.predict"]
+
+ # Second access must return the same cached object without re-importing.
+ assert kalelinear.embed is loaded_embed
+ assert kalelinear.predict is loaded_predict