Skip to content

Commit 7eaa346

Browse files
authored
Merge pull request #23 from lias-laboratory/21-add-possibility-to-add-callable-or-other-metrics-within-the-class
21 add possibility to add callable or other metrics within the class. \fix #21
2 parents 85c0474 + cbd0904 commit 7eaa346

File tree

14 files changed

+736
-105
lines changed

14 files changed

+736
-105
lines changed

.coverage

0 Bytes
Binary file not shown.

.github/workflows/build_wheels.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ on:
1616
jobs:
1717
run_pytest:
1818
name: Run tests on min and max Python versions
19-
runs-on: self-hosted
19+
runs-on: ubuntu-latest
2020
strategy:
2121
fail-fast: true
2222
matrix:
@@ -61,7 +61,7 @@ jobs:
6161

6262
build_sdist:
6363
name: Build source distribution
64-
runs-on: self-hosted
64+
runs-on: ubuntu-latest
6565
needs: run_pytest
6666
steps:
6767
- uses: actions/checkout@v4

.github/workflows/pr_build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717

1818
build_test_sdist:
1919
name: Test source distribution
20-
runs-on: self-hosted
20+
runs-on: ubuntu-latest
2121
needs: run_pytest
2222
strategy:
2323
fail-fast: true

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
jobs:
88
pytest:
99
name: Run pytest
10-
runs-on: self-hosted
10+
runs-on: ubuntu-latest
1111
strategy:
1212
fail-fast: true
1313
matrix:

CHANGELOG.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,33 @@
11
# Changelog
22

3+
All notable changes to this project will be documented in this file.
4+
5+
## [1.4.0] - 2025-06-19
6+
7+
### Contributors
8+
9+
- [@quentinhaenn](Quentin Haenn) - Main developer and maintainer
10+
11+
### Added
12+
13+
- Added support for custom MDS solvers in the `RadiusClustering` class.
14+
- Updated the documentation to include examples of using custom MDS solvers.
15+
- Added more examples and tutorials to the documentation.
16+
17+
### Changed
18+
19+
- Improved documentation and examples for the `RadiusClustering` class.
20+
- Updated the README to reflect the new features and improvements in version 1.4.0
21+
- Updated the test cases to ensure compatibility with the new features.
22+
- Refactored the main codebase to improve readability and maintainability.
23+
- Prepared the codebase for future adds of MDS solvers and/or clustering algorithms.
24+
325
## [1.3.0] - 2025-06-18
426

27+
### Contributors
28+
29+
- [@quentinhaenn](Quentin Haenn) - Main developer and maintainer
30+
531
### Added
632

733
- Full test coverage for the entire codebase.
@@ -17,3 +43,21 @@
1743
- Updated all the attributes in the `RadiusClustering` class to fit `scikit-learn` standards and conventions.
1844
- Updated the tests cases to reflect the changes in the `RadiusClustering` class.
1945
- Updated README and documentation to reflect the new `radius` parameter and the deprecation of `threshold`.
46+
47+
## [1.2.0] - 2024-10
48+
49+
### Contributors
50+
51+
- [@quentinhaenn](Quentin Haenn) - Main developer and maintainer
52+
- [@mickaelbaron](Mickaël Baron) - Contributor and maintainer
53+
54+
### Added
55+
56+
- Added CI/CD pipelines with GitHub Actions for automated testing and deployment.
57+
- Added package metadata for better integration with PyPI.
58+
- Added a badge for the GitHub Actions workflow status in the README.
59+
- Added a badge for the Python version supported in the README.
60+
- Added a badge for the code style (Ruff) in the README.
61+
- Added a badge for the license in the README.
62+
- Added CI/CD pipelines for PyPI deployment (including test coverage, compiling extensions and wheels, and uploading to PyPI).
63+
- Resolving issues with compiling Cython extensions on Windows and MacOS.

README.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,24 @@ Radius clustering is a Python package that implements clustering under radius co
1717
- Compatible with scikit-learn's API for clustering algorithms
1818
- Supports radius-constrained clustering
1919
- Provides options for exact and approximate solutions
20+
- Easy to use and integrate with existing Python data science workflows
21+
- Includes comprehensive documentation and examples
22+
- Full test coverage to ensure reliability and correctness
23+
- Supports custom MDS solvers for flexibility in clustering approaches
24+
- Provides a user-friendly interface for clustering tasks
25+
26+
> [!CAUTION]
27+
> **Deprecation Notice**: The `threshold` parameter in the `RadiusClustering` class has been deprecated. Please use the `radius` parameter instead for specifying the radius for clustering. It is planned to be completely removed in version 2.0.0. The `radius` parameter is now the standard way to define the radius for clustering, aligning with our objective of making the parameters' name more intuitive and user-friendly.
28+
29+
> [!NOTE]
30+
> **NEW VERSIONS**: The package is currently under active development for new features and improvements, including some refactoring and enhancements to the existing codebase. Backwards compatibility is not guaranteed, so please check the [CHANGELOG](CHANGELOG.md) for details on changes and updates.
31+
32+
## Roadmap
33+
34+
- [x] Version 1.4.0:
35+
- [x] Add support for custom MDS solvers
36+
- [x] Improve documentation and examples
37+
- [x] Add more examples and tutorials
2038

2139
## Installation
2240

@@ -38,7 +56,7 @@ from radius_clustering import RadiusClustering
3856
X = np.random.rand(100, 2) # Generate random data
3957

4058
# Create an instance of MdsClustering
41-
rad_clustering = RadiusClustering(manner="approx", threshold=0.5)
59+
rad_clustering = RadiusClustering(manner="approx", radius=0.5)
4260

4361
# Fit the model to the data
4462
rad_clustering.fit(X)
@@ -109,5 +127,4 @@ The Radius Clustering work has been funded by:
109127

110128
- [1] [An iterated greedy algorithm for finding the minimum dominating set in graphs](https://www.sciencedirect.com/science/article/pii/S0378475422005055)
111129
- [2] [An exact algorithm for the minimum dominating set problem](https://dl.acm.org/doi/abs/10.24963/ijcai.2023/622)
112-
113-
130+
- [3] [Clustering under radius constraint using minimum dominating set](https://link.springer.com/chapter/10.1007/978-3-031-62700-2_2)

docs/source/api.rst

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
API Reference
22
=============
33

4-
.. automodule:: radius_clustering
4+
This page documents the implementation details of the `radius_clustering` package.
5+
6+
RadiusClustering Class
7+
----------------------
8+
9+
.. autoclass:: radius_clustering.RadiusClustering
10+
:members:
11+
:undoc-members:
12+
:show-inheritance:
13+
14+
Algorithms Module
15+
-----------------
16+
.. automodule:: radius_clustering.algorithms
517
:members:
618
:undoc-members:
719
:show-inheritance:

docs/source/usage.rst

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
Usage
22
=====
33

4-
Here's a basic example of how to use Radius Clustering:
4+
This page provides a quick guide on how to use the `radius_clustering` package for clustering tasks. The package provides a simple interface for performing radius-based clustering on datasets based on the Minimum Dominating Set (MDS) algorithm.
5+
6+
This page is divided into three main sections:
7+
1. **Basic Usage**: A quick example of how to use the `RadiusClustering` class and perform clustering with several parameters.
8+
2. **Custom Dissimilarity Function**: How to use a custom dissimilarity function with the `RadiusClustering` class.
9+
3. **Custom MDS Solver**: How to implement a custom MDS solver for more advanced clustering tasks, eventually with less guarantees on the results.
10+
11+
12+
Basic Usage
13+
-----------------
14+
15+
The `RadiusClustering` class provides a straightforward way to perform clustering based on a specified radius. You can choose between an approximate or exact method for clustering, depending on your needs.
16+
17+
Here's a basic example of how to use Radius Clustering with the `RadiusClustering` class, using the approximate method:
518

619
.. code-block:: python
720
@@ -22,4 +35,97 @@ Here's a basic example of how to use Radius Clustering:
2235
# Get cluster labels
2336
labels = rad.labels_
2437
25-
print(labels)
38+
print(labels)
39+
40+
Similarly, you can use the exact method by changing the `manner` parameter to `"exact"`:
41+
.. code-block:: python
42+
# [...] Exact same code as above
43+
rad = RadiusClustering(manner="exact", radius=0.5) #change this parameter
44+
# [...] Exact same code as above
45+
46+
Custom Dissimilarity Function
47+
-----------------------------
48+
49+
The main reason behind the `radius_clustering` package is that users eventually needs to use a dissimilarity function that is not a metric (or distance) function. Plus, sometimes context requires a domain-specific dissimilarity function that is not provided by default, and needs to be implemented by the user.
50+
51+
To use a custom dissimilarity function, you can pass it as a parameter to the `RadiusClustering` class. Here's an example of how to do this:
52+
.. code-block:: python
53+
54+
from radius_clustering import RadiusClustering
55+
import numpy as np
56+
57+
# Generate random data
58+
X = np.random.rand(100, 2)
59+
60+
# Define a custom dissimilarity function
61+
def dummy_dissimilarity(x, y):
62+
return np.linalg.norm(x - y) + 0.1 # Example: add a constant to the distance
63+
64+
# Create an instance of MdsClustering with the custom dissimilarity function
65+
rad = RadiusClustering(manner="approx", radius=0.5, metric=dummy_dissimilarity)
66+
67+
# Fit the model to the data
68+
rad.fit(X)
69+
70+
# Get cluster labels
71+
labels = rad.labels_
72+
73+
print(labels)
74+
75+
76+
.. note::
77+
The custom dissimilarity function will be passed to scikit-learn's `pairwise_distances` function, so it should be compatible with the expected input format and return type. See the scikit-learn documentation for more details on how to implement custom metrics.
78+
79+
Custom MDS Solver
80+
-----------------
81+
82+
The two default solvers provided by the actual implementation of the `radius_clustering` package are focused on exactness (or proximity to exactness) of the results of a NP-hard problem. So, they may not be suitable for all use cases, especially when performance is a concern.
83+
If you have your own implementation of a Minimum Dominating Set (MDS) solver, you can use it with the `RadiusClustering` class ny using the :py:func:'RadiusClustering.set_solver' method. It will check that the solver is compatible with the expected input format and return type, and will use it to perform clustering.
84+
85+
.. versionadded:: 1.4.0
86+
The :py:func:`RadiusClustering.set_solver` method was added to allow users to set a custom MDS solver.
87+
It is *NOT* backward compatible with previous versions of the package, as it comes with new structure and methods to handle custom solvers.
88+
89+
Here's an example of how to implement a custom MDS solver and use it with the `RadiusClustering` class, using NetworkX implementation of the dominating set problem :
90+
91+
.. code-block:: python
92+
93+
from radius_clustering import RadiusClustering
94+
import time
95+
import numpy as np
96+
import networkx as nx
97+
98+
# Generate random data
99+
X = np.random.rand(100, 2)
100+
101+
# Define a custom MDS solver using NetworkX
102+
def custom_mds_solver(n, edges, nb_edges, random_state=None):
103+
start = time.time()
104+
graph = nx.Graph(edges)
105+
centers = list(nx.algorithms.dominating_set(graph))
106+
centers.sort()
107+
end = time.time()
108+
return centers, end - start
109+
110+
# Create an instance of MdsClustering with the custom MDS solver
111+
rad = RadiusClustering(manner="approx", radius=0.5)
112+
rad.set_solver(custom_mds_solver)
113+
114+
# Fit the model to the data
115+
rad.fit(X)
116+
117+
# Get cluster labels
118+
labels = rad.labels_
119+
120+
print(labels)
121+
122+
.. note::
123+
The custom MDS solver should accept the same parameters as the default solvers, including the number of points `n`, the edges of the graph `edges`, the number of edges `nb_edges`, and an optional `random_state` parameter for reproducibility. It should return a list of centers and the time taken to compute them.
124+
The `set_solver` method will check that the custom solver is compatible with the expected input format and return type, and will use it to perform clustering.
125+
If the custom solver is not compatible, it will raise a `ValueError` with a descriptive message.
126+
127+
.. attention::
128+
We cannot guarantee that the custom MDS solver will produce the same results as the default solvers, especially if it is not purposely designed to solve the Minimum Dominating Set problem but rather just finds a dominating set. The results may vary depending on the implementation and the specific characteristics of the dataset.
129+
As an example, a benchmark of our solutions and a custom one using NetworkX is available in the `Example Gallery` section of the documentation, which shows that the custom solver may produce different results than the default solvers, especially in terms of the number of clusters and the time taken to compute them (see :ref:`sphx_glr_auto_examples_plot_benchmark_custom.py`).
130+
However, it can be useful for specific use cases where performance is a concern or when you have a custom implementation that fits your needs better.
131+

0 commit comments

Comments
 (0)