clustereasy 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shashikant
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.
@@ -0,0 +1,305 @@
1
+ Metadata-Version: 2.4
2
+ Name: clustereasy
3
+ Version: 0.1.0
4
+ Summary: A beginner-friendly, consistent API for K-Means and Agglomerative Clustering on pandas DataFrames.
5
+ Author: Shashikant
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/shashikant-ds636/easycluster
8
+ Project-URL: Issues, https://github.com/shashikant-ds636/easycluster/issues
9
+ Keywords: clustering,kmeans,hierarchical,machine-learning,pandas
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Scientific/Engineering
18
+ Requires-Python: >=3.9
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Requires-Dist: pandas>=1.5
22
+ Requires-Dist: numpy>=1.23
23
+ Requires-Dist: scikit-learn>=1.2
24
+ Requires-Dist: scipy>=1.9
25
+ Requires-Dist: matplotlib>=3.6
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=7; extra == "dev"
28
+ Requires-Dist: build; extra == "dev"
29
+ Requires-Dist: twine; extra == "dev"
30
+ Dynamic: license-file
31
+
32
+ # clustereasy
33
+
34
+ A beginner-friendly, consistent Python API that combines **K-Means** and
35
+ **Agglomerative (Hierarchical) Clustering** on pandas DataFrames into one
36
+ class: `Cluster`.
37
+
38
+ Instead of re-learning different scikit-learn/SciPy calling conventions for
39
+ each algorithm, you get one object with one set of methods for fitting,
40
+ visualizing, evaluating, and exporting results — for both algorithms.
41
+
42
+ ## 1. Why clustereasy
43
+
44
+ - One consistent interface for two different clustering algorithms.
45
+ - Keeps your original DataFrame untouched.
46
+ - Clear, explicit errors instead of silently doing the wrong thing.
47
+ - Advanced users can still pass through scikit-learn parameters.
48
+
49
+ ## 2. Installation
50
+
51
+ Local development install (editable):
52
+
53
+ ```bash
54
+ git clone https://github.com/shashikant-ds636/easycluster.git
55
+ cd easycluster
56
+ pip install -e ".[dev]"
57
+ ```
58
+
59
+ Once published, it will be installable with:
60
+
61
+ ```bash
62
+ pip install clustereasy
63
+ ```
64
+
65
+ ## 3. Requirements
66
+
67
+ - Python >= 3.9
68
+ - pandas >= 1.5
69
+ - numpy >= 1.23
70
+ - scikit-learn >= 1.2
71
+ - scipy >= 1.9
72
+ - matplotlib >= 3.6
73
+
74
+ ## 4. Quick start
75
+
76
+ ```python
77
+ import pandas as pd
78
+ from clustereasy import Cluster
79
+
80
+ df = pd.read_csv("customers.csv")
81
+
82
+ cluster = Cluster(
83
+ data=df,
84
+ features=["Annual Income", "Spending Score"],
85
+ scale=True,
86
+ missing="median",
87
+ )
88
+
89
+ cluster.elbow_method(max_clusters=10)
90
+ cluster.fit_kmeans(n_clusters=4, random_state=42)
91
+ cluster.plot_clusters(x="Annual Income", y="Spending Score")
92
+
93
+ print(cluster.evaluate())
94
+ result_df = cluster.get_clustered_data(column_name="Segment")
95
+ ```
96
+
97
+ ## 5. DataFrame input requirements
98
+
99
+ `Cluster(data=df, features=[...], scale=..., missing=...)`:
100
+
101
+ - `data` must be a non-empty `pandas.DataFrame`. It is never modified.
102
+ - `features`: optional list of column names to cluster on. Defaults to all
103
+ columns. Columns must exist, be unique, and be numeric — clustereasy will
104
+ **not** silently convert text/categorical values into numbers. Encode
105
+ categorical columns yourself first (e.g. `pd.get_dummies`) if you want to
106
+ include them.
107
+ - `missing`: one of `"raise"` (default), `"drop"`, `"mean"`, `"median"`.
108
+ Controls how missing values in the selected features are handled.
109
+ - Infinite values always raise an explicit error — they are never silently
110
+ dropped or converted.
111
+ - `scale`: `False` (default), `True` (same as `"standard"`), or one of
112
+ `"standard"`, `"minmax"`, `"robust"`.
113
+
114
+ ## 6. K-Means tutorial
115
+
116
+ ```python
117
+ cluster = Cluster(data=df, features=["Income", "Score"], scale=True)
118
+
119
+ # Explore how many clusters might make sense
120
+ elbow_table = cluster.elbow_method(max_clusters=10, random_state=42)
121
+
122
+ # Fit
123
+ cluster.fit_kmeans(n_clusters=4, init="k-means++", n_init=10, random_state=42)
124
+
125
+ cluster.cluster_centers() # DataFrame, original feature scale by default
126
+ cluster.inertia() # WCSS for the fitted model
127
+ cluster.predict(new_df) # assign new rows to existing clusters
128
+ ```
129
+
130
+ Supported `fit_kmeans` parameters: `n_clusters`, `init`, `n_init`, `max_iter`,
131
+ `tol`, `random_state`, `algorithm` — all pass straight through to
132
+ scikit-learn's `KMeans`.
133
+
134
+ ## 7. Elbow Method
135
+
136
+ `elbow_method(max_clusters=10, random_state=42, show=True)` fits K-Means for
137
+ k = 1..max_clusters, plots k vs. WCSS (inertia), and returns a DataFrame of
138
+ the results so you can reuse them without refitting.
139
+
140
+ **The elbow is a heuristic**, not a guaranteed optimum — use it together with
141
+ `silhouette_score()` and your domain knowledge, not in isolation.
142
+
143
+ ## 8. Hierarchical Clustering tutorial
144
+
145
+ ```python
146
+ Z = cluster.plot_dendrogram(method="ward", metric="euclidean")
147
+ cluster.fit_agglomerative(n_clusters=3, linkage="ward")
148
+ ```
149
+
150
+ Supported linkage methods: `ward`, `complete`, `average`, `single`.
151
+ `ward` linkage requires `metric="euclidean"` — using any other metric with
152
+ `ward` raises a clear error instead of silently producing wrong results.
153
+
154
+ You can also cluster by distance instead of a fixed cluster count:
155
+
156
+ ```python
157
+ cluster.fit_agglomerative(n_clusters=None, distance_threshold=5.0)
158
+ ```
159
+
160
+ `distance_threshold` and `n_clusters` are mutually exclusive, matching
161
+ scikit-learn's own requirement.
162
+
163
+ **Important:** `AgglomerativeClustering` has no native `predict()` method in
164
+ scikit-learn, and `Cluster.predict()` will raise an explicit error if called
165
+ on an agglomerative model rather than faking support for it.
166
+
167
+ ## 9. Dendrogram interpretation
168
+
169
+ - Each leaf is one observation.
170
+ - Each join (inverted "U") is a merge of two clusters; its height is the
171
+ distance at which they were merged.
172
+ - Cutting the dendrogram horizontally at a given height determines how many
173
+ clusters you get at that distance.
174
+ - For large datasets, pass `truncate_mode="lastp"` with a small `p` to avoid
175
+ an unreadable plot — clustereasy will warn you above ~2000 samples if you
176
+ don't.
177
+
178
+ ## 10. Evaluation metrics and their limitations
179
+
180
+ All metrics below work without ground-truth labels:
181
+
182
+ | Method | Notes |
183
+ |---|---|
184
+ | `silhouette_score()` | Needs 2..n-1 distinct clusters. |
185
+ | `silhouette_samples()` | Per-sample values, same constraints. |
186
+ | `davies_bouldin_score()` | Lower is better. Needs >= 2 clusters. |
187
+ | `calinski_harabasz_score()` | Higher is better. Needs >= 2 clusters. |
188
+ | `inertia()` | K-Means only — not available for Agglomerative models. |
189
+ | `evaluate()` | One DataFrame with every metric applicable to the fitted model. |
190
+
191
+ These are **diagnostic tools**, not proof of a "correct" clustering — always
192
+ sanity-check results against domain knowledge. If a metric can't be computed
193
+ (e.g. only 1 distinct cluster), `evaluate()` shows `NaN` with a note instead
194
+ of crashing; the individual metric methods raise a `ParameterError`.
195
+
196
+ ## 11. Feature scaling and missing-value handling
197
+
198
+ - Distances (and therefore both K-Means and Agglomerative results) are scale
199
+ -sensitive. If your features are on different scales (e.g. income in
200
+ thousands vs. a 1-100 score), set `scale=True`.
201
+ - K-Means cluster centers are available both in the transformed (scaled)
202
+ space (`cluster._model.cluster_centers_`) and inverse-transformed back to
203
+ the original feature scale (`cluster.cluster_centers()`, the default).
204
+ - Missing values are never silently dropped by default — you must choose
205
+ `missing="drop"/"mean"/"median"` explicitly, or clean the data yourself.
206
+
207
+ ## 12. Visualization examples
208
+
209
+ ```python
210
+ cluster.plot_clusters(x="Income", y="Score", show_centers=True)
211
+ cluster.plot_cluster_sizes()
212
+ cluster.plot_silhouette()
213
+ cluster.plot_pca() # for > 2 features; clearly labeled as a 2D projection
214
+ ```
215
+
216
+ `plot_clusters` requires exactly two selected feature columns to display;
217
+ for higher-dimensional data use `plot_pca()` instead, which is explicitly
218
+ labeled as a projection, not the original feature space.
219
+
220
+ ## 13. Cluster labels and DataFrame output
221
+
222
+ ```python
223
+ labels = cluster.get_labels() # pd.Series, original index
224
+ clustered_df = cluster.get_clustered_data("Segment") # original df + label column
225
+ summary = cluster.cluster_summary() # size, proportion, per-feature mean
226
+ ```
227
+
228
+ Cluster IDs (0, 1, 2, ...) are arbitrary identifiers — they carry no
229
+ inherent ranking or meaning.
230
+
231
+ ## 14. Common errors and solutions
232
+
233
+ | Error | Likely cause | Fix |
234
+ |---|---|---|
235
+ | `InputValidationError: not numeric` | Selected a text/categorical column | Encode it first, or exclude it from `features` |
236
+ | `InputValidationError: missing values` | NaNs present, `missing="raise"` (default) | Pass `missing="drop"/"mean"/"median"` |
237
+ | `ParameterError: Ward linkage requires metric='euclidean'` | `linkage="ward"` with another metric | Use `metric="euclidean"` or a different linkage |
238
+ | `NotFittedError` | Called an evaluation/plot/output method before `fit_kmeans`/`fit_agglomerative` | Fit a model first |
239
+ | `ParameterError` on `predict()` | Called `predict()` on an Agglomerative model | Not supported — only K-Means supports `predict()` |
240
+
241
+ ## 15. Computational limitations
242
+
243
+ - Dendrograms require O(n²) memory/time for the distance matrix and are
244
+ impractical much past a few thousand samples.
245
+ - `AgglomerativeClustering` scales worse than `KMeans` for large n.
246
+ - No GPU acceleration; this wraps scikit-learn/SciPy CPU implementations.
247
+
248
+ ## 16. API reference (summary)
249
+
250
+ **Construction:** `Cluster(data, features=None, scale=False, missing="raise")`
251
+
252
+ **K-Means:** `elbow_method`, `fit_kmeans`, `cluster_centers`, `inertia`, `predict`
253
+
254
+ **Agglomerative:** `plot_dendrogram`, `get_linkage_matrix`, `fit_agglomerative`
255
+
256
+ **Shared:** `plot_clusters`, `plot_cluster_sizes`, `plot_silhouette`, `plot_pca`
257
+
258
+ **Evaluation:** `silhouette_score`, `silhouette_samples`, `davies_bouldin_score`,
259
+ `calinski_harabasz_score`, `evaluate`
260
+
261
+ **Output:** `get_labels`, `get_clustered_data`, `cluster_summary`, `elbow_results`
262
+
263
+ ## 17. Testing
264
+
265
+ ```bash
266
+ pip install -e ".[dev]"
267
+ pytest -q
268
+ ```
269
+
270
+ Current suite: **59 tests, all passing**, covering validation, both
271
+ algorithms, visualization, evaluation edge cases, and DataFrame-output
272
+ guarantees (index preservation, immutability, reproducibility).
273
+
274
+ ## 18. Contribution guidelines
275
+
276
+ 1. Fork, branch from `main`.
277
+ 2. Add/update tests for any behavior change.
278
+ 3. Run `pytest -q` before opening a PR.
279
+ 4. Keep public methods documented with docstrings.
280
+
281
+ ## 19. Roadmap
282
+
283
+ - `DBSCAN`, `OPTICS`, `GaussianMixture` support behind the same API.
284
+ - Automatic comparison across multiple `k` / linkage configurations.
285
+ - Model save/load (`joblib`).
286
+ - Export results directly to CSV.
287
+ - Optional connectivity-constrained agglomerative clustering helpers.
288
+
289
+ ## 20. Preparing a PyPI release
290
+
291
+ ```bash
292
+ pip install build twine
293
+ python -m build # creates dist/*.whl and dist/*.tar.gz
294
+ twine check dist/*
295
+ pip install dist/clustereasy-0.1.0-py3-none-any.whl # test locally
296
+ twine upload --repository testpypi dist/* # TestPyPI first
297
+ twine upload dist/* # then real PyPI
298
+ ```
299
+
300
+ Bump the `version` in `pyproject.toml` before each release and update
301
+ `CHANGELOG.md`.
302
+
303
+ ## License
304
+
305
+ MIT — see `LICENSE`.
@@ -0,0 +1,274 @@
1
+ # clustereasy
2
+
3
+ A beginner-friendly, consistent Python API that combines **K-Means** and
4
+ **Agglomerative (Hierarchical) Clustering** on pandas DataFrames into one
5
+ class: `Cluster`.
6
+
7
+ Instead of re-learning different scikit-learn/SciPy calling conventions for
8
+ each algorithm, you get one object with one set of methods for fitting,
9
+ visualizing, evaluating, and exporting results — for both algorithms.
10
+
11
+ ## 1. Why clustereasy
12
+
13
+ - One consistent interface for two different clustering algorithms.
14
+ - Keeps your original DataFrame untouched.
15
+ - Clear, explicit errors instead of silently doing the wrong thing.
16
+ - Advanced users can still pass through scikit-learn parameters.
17
+
18
+ ## 2. Installation
19
+
20
+ Local development install (editable):
21
+
22
+ ```bash
23
+ git clone https://github.com/shashikant-ds636/easycluster.git
24
+ cd easycluster
25
+ pip install -e ".[dev]"
26
+ ```
27
+
28
+ Once published, it will be installable with:
29
+
30
+ ```bash
31
+ pip install clustereasy
32
+ ```
33
+
34
+ ## 3. Requirements
35
+
36
+ - Python >= 3.9
37
+ - pandas >= 1.5
38
+ - numpy >= 1.23
39
+ - scikit-learn >= 1.2
40
+ - scipy >= 1.9
41
+ - matplotlib >= 3.6
42
+
43
+ ## 4. Quick start
44
+
45
+ ```python
46
+ import pandas as pd
47
+ from clustereasy import Cluster
48
+
49
+ df = pd.read_csv("customers.csv")
50
+
51
+ cluster = Cluster(
52
+ data=df,
53
+ features=["Annual Income", "Spending Score"],
54
+ scale=True,
55
+ missing="median",
56
+ )
57
+
58
+ cluster.elbow_method(max_clusters=10)
59
+ cluster.fit_kmeans(n_clusters=4, random_state=42)
60
+ cluster.plot_clusters(x="Annual Income", y="Spending Score")
61
+
62
+ print(cluster.evaluate())
63
+ result_df = cluster.get_clustered_data(column_name="Segment")
64
+ ```
65
+
66
+ ## 5. DataFrame input requirements
67
+
68
+ `Cluster(data=df, features=[...], scale=..., missing=...)`:
69
+
70
+ - `data` must be a non-empty `pandas.DataFrame`. It is never modified.
71
+ - `features`: optional list of column names to cluster on. Defaults to all
72
+ columns. Columns must exist, be unique, and be numeric — clustereasy will
73
+ **not** silently convert text/categorical values into numbers. Encode
74
+ categorical columns yourself first (e.g. `pd.get_dummies`) if you want to
75
+ include them.
76
+ - `missing`: one of `"raise"` (default), `"drop"`, `"mean"`, `"median"`.
77
+ Controls how missing values in the selected features are handled.
78
+ - Infinite values always raise an explicit error — they are never silently
79
+ dropped or converted.
80
+ - `scale`: `False` (default), `True` (same as `"standard"`), or one of
81
+ `"standard"`, `"minmax"`, `"robust"`.
82
+
83
+ ## 6. K-Means tutorial
84
+
85
+ ```python
86
+ cluster = Cluster(data=df, features=["Income", "Score"], scale=True)
87
+
88
+ # Explore how many clusters might make sense
89
+ elbow_table = cluster.elbow_method(max_clusters=10, random_state=42)
90
+
91
+ # Fit
92
+ cluster.fit_kmeans(n_clusters=4, init="k-means++", n_init=10, random_state=42)
93
+
94
+ cluster.cluster_centers() # DataFrame, original feature scale by default
95
+ cluster.inertia() # WCSS for the fitted model
96
+ cluster.predict(new_df) # assign new rows to existing clusters
97
+ ```
98
+
99
+ Supported `fit_kmeans` parameters: `n_clusters`, `init`, `n_init`, `max_iter`,
100
+ `tol`, `random_state`, `algorithm` — all pass straight through to
101
+ scikit-learn's `KMeans`.
102
+
103
+ ## 7. Elbow Method
104
+
105
+ `elbow_method(max_clusters=10, random_state=42, show=True)` fits K-Means for
106
+ k = 1..max_clusters, plots k vs. WCSS (inertia), and returns a DataFrame of
107
+ the results so you can reuse them without refitting.
108
+
109
+ **The elbow is a heuristic**, not a guaranteed optimum — use it together with
110
+ `silhouette_score()` and your domain knowledge, not in isolation.
111
+
112
+ ## 8. Hierarchical Clustering tutorial
113
+
114
+ ```python
115
+ Z = cluster.plot_dendrogram(method="ward", metric="euclidean")
116
+ cluster.fit_agglomerative(n_clusters=3, linkage="ward")
117
+ ```
118
+
119
+ Supported linkage methods: `ward`, `complete`, `average`, `single`.
120
+ `ward` linkage requires `metric="euclidean"` — using any other metric with
121
+ `ward` raises a clear error instead of silently producing wrong results.
122
+
123
+ You can also cluster by distance instead of a fixed cluster count:
124
+
125
+ ```python
126
+ cluster.fit_agglomerative(n_clusters=None, distance_threshold=5.0)
127
+ ```
128
+
129
+ `distance_threshold` and `n_clusters` are mutually exclusive, matching
130
+ scikit-learn's own requirement.
131
+
132
+ **Important:** `AgglomerativeClustering` has no native `predict()` method in
133
+ scikit-learn, and `Cluster.predict()` will raise an explicit error if called
134
+ on an agglomerative model rather than faking support for it.
135
+
136
+ ## 9. Dendrogram interpretation
137
+
138
+ - Each leaf is one observation.
139
+ - Each join (inverted "U") is a merge of two clusters; its height is the
140
+ distance at which they were merged.
141
+ - Cutting the dendrogram horizontally at a given height determines how many
142
+ clusters you get at that distance.
143
+ - For large datasets, pass `truncate_mode="lastp"` with a small `p` to avoid
144
+ an unreadable plot — clustereasy will warn you above ~2000 samples if you
145
+ don't.
146
+
147
+ ## 10. Evaluation metrics and their limitations
148
+
149
+ All metrics below work without ground-truth labels:
150
+
151
+ | Method | Notes |
152
+ |---|---|
153
+ | `silhouette_score()` | Needs 2..n-1 distinct clusters. |
154
+ | `silhouette_samples()` | Per-sample values, same constraints. |
155
+ | `davies_bouldin_score()` | Lower is better. Needs >= 2 clusters. |
156
+ | `calinski_harabasz_score()` | Higher is better. Needs >= 2 clusters. |
157
+ | `inertia()` | K-Means only — not available for Agglomerative models. |
158
+ | `evaluate()` | One DataFrame with every metric applicable to the fitted model. |
159
+
160
+ These are **diagnostic tools**, not proof of a "correct" clustering — always
161
+ sanity-check results against domain knowledge. If a metric can't be computed
162
+ (e.g. only 1 distinct cluster), `evaluate()` shows `NaN` with a note instead
163
+ of crashing; the individual metric methods raise a `ParameterError`.
164
+
165
+ ## 11. Feature scaling and missing-value handling
166
+
167
+ - Distances (and therefore both K-Means and Agglomerative results) are scale
168
+ -sensitive. If your features are on different scales (e.g. income in
169
+ thousands vs. a 1-100 score), set `scale=True`.
170
+ - K-Means cluster centers are available both in the transformed (scaled)
171
+ space (`cluster._model.cluster_centers_`) and inverse-transformed back to
172
+ the original feature scale (`cluster.cluster_centers()`, the default).
173
+ - Missing values are never silently dropped by default — you must choose
174
+ `missing="drop"/"mean"/"median"` explicitly, or clean the data yourself.
175
+
176
+ ## 12. Visualization examples
177
+
178
+ ```python
179
+ cluster.plot_clusters(x="Income", y="Score", show_centers=True)
180
+ cluster.plot_cluster_sizes()
181
+ cluster.plot_silhouette()
182
+ cluster.plot_pca() # for > 2 features; clearly labeled as a 2D projection
183
+ ```
184
+
185
+ `plot_clusters` requires exactly two selected feature columns to display;
186
+ for higher-dimensional data use `plot_pca()` instead, which is explicitly
187
+ labeled as a projection, not the original feature space.
188
+
189
+ ## 13. Cluster labels and DataFrame output
190
+
191
+ ```python
192
+ labels = cluster.get_labels() # pd.Series, original index
193
+ clustered_df = cluster.get_clustered_data("Segment") # original df + label column
194
+ summary = cluster.cluster_summary() # size, proportion, per-feature mean
195
+ ```
196
+
197
+ Cluster IDs (0, 1, 2, ...) are arbitrary identifiers — they carry no
198
+ inherent ranking or meaning.
199
+
200
+ ## 14. Common errors and solutions
201
+
202
+ | Error | Likely cause | Fix |
203
+ |---|---|---|
204
+ | `InputValidationError: not numeric` | Selected a text/categorical column | Encode it first, or exclude it from `features` |
205
+ | `InputValidationError: missing values` | NaNs present, `missing="raise"` (default) | Pass `missing="drop"/"mean"/"median"` |
206
+ | `ParameterError: Ward linkage requires metric='euclidean'` | `linkage="ward"` with another metric | Use `metric="euclidean"` or a different linkage |
207
+ | `NotFittedError` | Called an evaluation/plot/output method before `fit_kmeans`/`fit_agglomerative` | Fit a model first |
208
+ | `ParameterError` on `predict()` | Called `predict()` on an Agglomerative model | Not supported — only K-Means supports `predict()` |
209
+
210
+ ## 15. Computational limitations
211
+
212
+ - Dendrograms require O(n²) memory/time for the distance matrix and are
213
+ impractical much past a few thousand samples.
214
+ - `AgglomerativeClustering` scales worse than `KMeans` for large n.
215
+ - No GPU acceleration; this wraps scikit-learn/SciPy CPU implementations.
216
+
217
+ ## 16. API reference (summary)
218
+
219
+ **Construction:** `Cluster(data, features=None, scale=False, missing="raise")`
220
+
221
+ **K-Means:** `elbow_method`, `fit_kmeans`, `cluster_centers`, `inertia`, `predict`
222
+
223
+ **Agglomerative:** `plot_dendrogram`, `get_linkage_matrix`, `fit_agglomerative`
224
+
225
+ **Shared:** `plot_clusters`, `plot_cluster_sizes`, `plot_silhouette`, `plot_pca`
226
+
227
+ **Evaluation:** `silhouette_score`, `silhouette_samples`, `davies_bouldin_score`,
228
+ `calinski_harabasz_score`, `evaluate`
229
+
230
+ **Output:** `get_labels`, `get_clustered_data`, `cluster_summary`, `elbow_results`
231
+
232
+ ## 17. Testing
233
+
234
+ ```bash
235
+ pip install -e ".[dev]"
236
+ pytest -q
237
+ ```
238
+
239
+ Current suite: **59 tests, all passing**, covering validation, both
240
+ algorithms, visualization, evaluation edge cases, and DataFrame-output
241
+ guarantees (index preservation, immutability, reproducibility).
242
+
243
+ ## 18. Contribution guidelines
244
+
245
+ 1. Fork, branch from `main`.
246
+ 2. Add/update tests for any behavior change.
247
+ 3. Run `pytest -q` before opening a PR.
248
+ 4. Keep public methods documented with docstrings.
249
+
250
+ ## 19. Roadmap
251
+
252
+ - `DBSCAN`, `OPTICS`, `GaussianMixture` support behind the same API.
253
+ - Automatic comparison across multiple `k` / linkage configurations.
254
+ - Model save/load (`joblib`).
255
+ - Export results directly to CSV.
256
+ - Optional connectivity-constrained agglomerative clustering helpers.
257
+
258
+ ## 20. Preparing a PyPI release
259
+
260
+ ```bash
261
+ pip install build twine
262
+ python -m build # creates dist/*.whl and dist/*.tar.gz
263
+ twine check dist/*
264
+ pip install dist/clustereasy-0.1.0-py3-none-any.whl # test locally
265
+ twine upload --repository testpypi dist/* # TestPyPI first
266
+ twine upload dist/* # then real PyPI
267
+ ```
268
+
269
+ Bump the `version` in `pyproject.toml` before each release and update
270
+ `CHANGELOG.md`.
271
+
272
+ ## License
273
+
274
+ MIT — see `LICENSE`.
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "clustereasy"
7
+ version = "0.1.0"
8
+ description = "A beginner-friendly, consistent API for K-Means and Agglomerative Clustering on pandas DataFrames."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.9"
12
+ authors = [{ name = "Shashikant" }]
13
+ keywords = ["clustering", "kmeans", "hierarchical", "machine-learning", "pandas"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Science/Research",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.9",
19
+ "Programming Language :: Python :: 3.10",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Topic :: Scientific/Engineering",
23
+ ]
24
+ dependencies = [
25
+ "pandas>=1.5",
26
+ "numpy>=1.23",
27
+ "scikit-learn>=1.2",
28
+ "scipy>=1.9",
29
+ "matplotlib>=3.6",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ dev = ["pytest>=7", "build", "twine"]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/shashikant-ds636/easycluster"
37
+ Issues = "https://github.com/shashikant-ds636/easycluster/issues"
38
+
39
+ [tool.setuptools.packages.find]
40
+ where = ["src"]
41
+
42
+ [tool.pytest.ini_options]
43
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,15 @@
1
+ """easycluster: a beginner-friendly, consistent API for K-Means and
2
+ Agglomerative Clustering on pandas DataFrames."""
3
+
4
+ from .cluster import Cluster
5
+ from .exceptions import EasyClusterError, InputValidationError, NotFittedError, ParameterError
6
+
7
+ __version__ = "0.1.0"
8
+
9
+ __all__ = [
10
+ "Cluster",
11
+ "EasyClusterError",
12
+ "InputValidationError",
13
+ "NotFittedError",
14
+ "ParameterError",
15
+ ]