Metadata-Version: 2.4
Name: wknn_1
Version: 0.1.0
Summary: scikit-learn compatible weighted k-Nearest-Neighbours regressor
Project-URL: Homepage, https://example.com/your-username/wknn_1
Project-URL: Repository, https://example.com/your-username/wknn_1
Author-email: Your Name <you@example.com>
License: MIT
License-File: LICENSE
Keywords: knn,machine-learning,regression,scikit-learn,weighted-knn
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Requires-Python: <3.15,>=3.8
Requires-Dist: numpy>=1.21
Requires-Dist: scikit-learn>=1.0
Description-Content-Type: text/markdown

# wknn_1

A scikit-learn compatible **weighted k-Nearest-Neighbours regressor**.

> This README documents how to run, develop and deploy the library, with usage
> examples. A richer version with links to the underlying scientific papers
> will follow.

## Features

- Drop-in scikit-learn estimator (`BaseEstimator` + `RegressorMixin`): works
  with `Pipeline`, `clone`, `GridSearchCV`, `get_params`/`set_params`, `score`.
- Flexible `weights` parameter:
  - **named** standard functions: `linear` (default), `inverse`/`distance`,
    `exponential`, `gaussian`, `uniform`;
  - a **custom callable**;
  - a **`MixedWeightFunction`** with a *different formula per predictor
    dimension* (e.g. linear decrease on dim 0, exponential growth on dim 1);
  - a **per-rank weight vector** (list or ndarray, coerced to numpy).
- Standard weight functions standardize their inputs internally (centering /
  scaling / normalization), so they are robust to non-standardized data.
- Predictors and responses must be `numpy.ndarray`; anything else raises an
  informative `InvalidInputError`.
- Save / load trained weights in **npz**, **pickle** and **json** to move a
  trained model between machines.
- `refit` for retraining and `delete` for tearing the model down (state +
  on-disk files + metadata) — handy after training on the wrong data.
- Fully typed (`py.typed` ships with the package). Python 3.8 – 3.14.

## Install & run (uv)

```bash
# from the project root, in the uv-managed virtual environment
uv sync                       # create .venv and install deps + dev tools
uv run python -c "import wknn_1; print(wknn_1.__version__)"
```

## Quick start

```python
import numpy as np
from wknn_1 import WKNNRegressor

X = np.random.default_rng(0).normal(size=(200, 3))
y = X @ np.array([2.0, -1.5, 0.5])

model = WKNNRegressor(n_neighbors=8, weights="linear").fit(X[:160], y[:160])
preds = model.predict(X[160:])
print(model.score(X[160:], y[160:]))
```

### Per-dimension (mixed) weighting

```python
import numpy as np
from wknn_1 import WKNNRegressor, MixedWeightFunction

mixed = MixedWeightFunction(
    [lambda d: np.clip(1.0 - d, 0.0, None),  # linear decrease on dim 0
     lambda d: np.exp(d)],                   # exponential growth on dim 1
    aggregate="product",
)
model = WKNNRegressor(n_neighbors=6, weights=mixed).fit(X2d, y)
```

### Per-rank weight vector

```python
# the i-th nearest neighbour always gets weight vec[i]
model = WKNNRegressor(n_neighbors=4, weights=[1.0, 0.5, 0.25, 0.1]).fit(X, y)
```

### Custom callable

```python
def gaussian_kernel(deltas):           # deltas: (..., k, n_features)
    dist = np.sqrt((deltas ** 2).sum(axis=-1))
    return np.exp(-(dist ** 2))         # -> (..., k)

model = WKNNRegressor(weights=gaussian_kernel).fit(X, y)
```

### Save, transfer, load, retrain, delete

```python
model.save_weights("model.npz")               # or .pkl / .json
restored = WKNNRegressor().load_weights("model.npz")

model.refit(X_new, y_new)                      # retrain from scratch
model.delete()                                 # wipe state + files + metadata
```

> Custom callable weight functions cannot be stored in `npz`/`json`; use
> `pickle`, or re-supply the callable via `set_params(weights=...)` after load.

### Extending the standard functions

```python
from wknn_1 import register_weight_function, StandardWeightFunction

register_weight_function(
    "epanechnikov",
    lambda: StandardWeightFunction("linear", normalize=True),
)
WKNNRegressor(weights="epanechnikov")
```

## Development

```bash
uv run ruff check .          # lint
uv run ruff format .         # format
uv run pytest                # tests
```

## Deploy

```bash
uv build                     # builds sdist + wheel into dist/
# uv publish                 # later: upload to PyPI after testing
```

## Project layout

```
src/wknn_1/
  estimator.py        WKNNRegressor (composes the mixins below)
  validation.py       numpy-only input checks
  preprocessing.py    standardization helpers
  persistence.py      npz / pickle / json save & load
  weights/            base, standard, mixed/fixed/rank, registry
  mixins/             validation / preprocessing / prediction / persistence
tests/                pytest suite
```
