Metadata-Version: 2.4
Name: mlkit
Version: 0.1.0
Summary: Machine Learning Toolkit: a small, readable NumPy toolkit with a fit/predict API, classic models, preprocessing and metrics.
Author: nehz
License-Expression: MIT
Keywords: machine learning,regression,classification,clustering,numpy
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Education
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
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 :: Artificial Intelligence
Classifier: Typing :: Typed
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.22
Provides-Extra: test
Requires-Dist: pytest>=7; extra == "test"
Dynamic: license-file

# mlkit

**Machine Learning Toolkit**: a small, readable machine learning library built on NumPy.

mlkit has the familiar `fit` / `predict` / `transform` estimator interface and a
handful of classic algorithms, each implemented in a few dozen lines of plain
NumPy. Use it to learn how the algorithms work, to teach them, or for small
projects where a large ML stack is too much. NumPy is its only dependency.

## Features

- **Estimator API**: `fit`, `predict`, `transform`, `score`, `get_params` / `set_params`, `clone`
- **Linear models**: `LinearRegression` (least squares), `Ridge` (L2, closed form), `LogisticRegression` (multinomial, gradient descent, optional L2)
- **Neighbours**: `KNeighborsClassifier`, `KNeighborsRegressor` (uniform or inverse-distance weights)
- **Clustering**: `KMeans` (k-means++ seeding, multiple restarts, reproducible via `random_state`)
- **Preprocessing**: `StandardScaler`, `MinMaxScaler` (both with `inverse_transform`)
- **Model selection**: `train_test_split`, `KFold`, `cross_val_score`
- **Metrics**: accuracy, confusion matrix, precision / recall / F1 (binary and macro), MSE, MAE, R²
- **Datasets**: `make_blobs`, `make_regression` synthetic generators
- Input validation with clear errors, and `NotFittedError` when an estimator is used before `fit`
- Type hints throughout (ships `py.typed`)

## Installation

```bash
pip install mlkit
```

From a source checkout:

```bash
python3 -m venv .venv
.venv/bin/pip install -e ".[test]"
.venv/bin/python -m pytest
```

Requires Python 3.9+ and NumPy 1.22+.

## Quickstart

```python
from mlkit import KMeans, LinearRegression, LogisticRegression, StandardScaler, train_test_split
from mlkit.datasets import make_blobs, make_regression
from mlkit.metrics import accuracy_score, r2_score

# Classification: scale the features, then fit a logistic regression
X, y = make_blobs(n_samples=300, centers=3, random_state=0)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=0)

scaler = StandardScaler().fit(X_train)
clf = LogisticRegression(learning_rate=0.5, max_iter=2000)
clf.fit(scaler.transform(X_train), y_train)
print("accuracy:", accuracy_score(y_test, clf.predict(scaler.transform(X_test))))

# Regression
X, y, true_coef = make_regression(n_samples=200, n_features=3, noise=0.5, random_state=1)
reg = LinearRegression().fit(X, y)
print("R^2:", r2_score(y, reg.predict(X)), "coef:", reg.coef_)

# Clustering
km = KMeans(n_clusters=3, random_state=0).fit(X_train)
print("inertia:", km.inertia_, "labels:", km.labels_[:10])
```

Cross-validation:

```python
from mlkit import KFold, KNeighborsClassifier, cross_val_score

scores = cross_val_score(KNeighborsClassifier(n_neighbors=5), X_train, y_train,
                         cv=KFold(n_splits=5, shuffle=True, random_state=0))
print(scores.mean())
```

## API overview

All estimators subclass `mlkit.BaseEstimator`. Hyper-parameters are the
constructor arguments. Learned attributes end in `_` and exist only after
`fit`. Every `fit` returns `self`. Calling `predict` or `transform` before `fit`
raises `mlkit.NotFittedError`.

### `mlkit` (top level)

| Name | Description |
| --- | --- |
| `BaseEstimator` | Base class with `get_params()`, `set_params(**params)`, and a readable `repr` |
| `NotFittedError` | Raised when an estimator is used before `fit` |
| `clone(estimator)` | New unfitted estimator with the same hyper-parameters |
| `__version__` | `"0.1.0"` |

### `mlkit.linear_model`

| Class | Parameters | Methods | Fitted attributes |
| --- | --- | --- | --- |
| `LinearRegression` | `fit_intercept=True` | `fit(X, y)`, `predict(X)`, `score(X, y)` (R²) | `coef_`, `intercept_` |
| `Ridge` | `alpha=1.0`, `fit_intercept=True` | `fit`, `predict`, `score` (R²) | `coef_`, `intercept_` |
| `LogisticRegression` | `learning_rate=0.1`, `max_iter=1000`, `tol=1e-6`, `alpha=0.0`, `fit_intercept=True` | `fit`, `predict`, `predict_proba`, `decision_function`, `score` (accuracy) | `classes_`, `coef_` (n_classes × n_features), `intercept_`, `n_iter_` |

### `mlkit.neighbors`

| Name | Parameters | Methods / notes |
| --- | --- | --- |
| `KNeighborsClassifier` | `n_neighbors=5`, `weights="uniform"` \| `"distance"` | `fit`, `predict`, `predict_proba`, `kneighbors(X)`, `score` (accuracy); `classes_` |
| `KNeighborsRegressor` | `n_neighbors=5`, `weights="uniform"` \| `"distance"` | `fit`, `predict`, `kneighbors(X)`, `score` (R²) |
| `pairwise_distances(A, B)` | | Euclidean distance matrix of shape `(len(A), len(B))` |

### `mlkit.cluster`

| Class | Parameters | Methods | Fitted attributes |
| --- | --- | --- | --- |
| `KMeans` | `n_clusters=8`, `n_init=10`, `max_iter=300`, `tol=1e-6`, `random_state=None` | `fit(X)`, `predict(X)`, `fit_predict(X)`, `transform(X)` (distances to centroids) | `cluster_centers_`, `labels_`, `inertia_`, `n_iter_` |

### `mlkit.preprocessing`

| Class | Parameters | Methods | Fitted attributes |
| --- | --- | --- | --- |
| `StandardScaler` | `with_mean=True`, `with_std=True` | `fit`, `transform`, `fit_transform`, `inverse_transform` | `mean_`, `scale_` |
| `MinMaxScaler` | `feature_range=(0.0, 1.0)` | `fit`, `transform`, `fit_transform`, `inverse_transform` | `data_min_`, `data_max_` |

### `mlkit.model_selection`

| Name | Signature |
| --- | --- |
| `train_test_split` | `train_test_split(*arrays, test_size=0.25, shuffle=True, random_state=None)` returns `[a_train, a_test, b_train, b_test, ...]` |
| `KFold` | `KFold(n_splits=5, shuffle=False, random_state=None)`; `.split(X)` yields `(train_idx, test_idx)` |
| `cross_val_score` | `cross_val_score(estimator, X, y, *, cv=5, scoring=None)` returns an array of per-fold scores (`scoring` is `metric(y_true, y_pred)`; it defaults to `estimator.score`) |

### `mlkit.metrics`

| Function | Notes |
| --- | --- |
| `accuracy_score(y_true, y_pred)` | Fraction of exact matches |
| `confusion_matrix(y_true, y_pred, labels=None)` | `C[i, j]`: true `labels[i]` predicted as `labels[j]` |
| `precision_score(y_true, y_pred, *, average="binary", pos_label=1)` | `average` is `"binary"` or `"macro"`. A zero denominator gives 0.0 |
| `recall_score(...)` | Same arguments as `precision_score` |
| `f1_score(...)` | Same arguments as `precision_score` |
| `mean_squared_error(y_true, y_pred)` | |
| `mean_absolute_error(y_true, y_pred)` | |
| `r2_score(y_true, y_pred)` | Coefficient of determination |

### `mlkit.datasets`

| Function | Returns |
| --- | --- |
| `make_blobs(n_samples=100, n_features=2, centers=3, cluster_std=1.0, random_state=None)` | `(X, y)` |
| `make_regression(n_samples=100, n_features=3, noise=0.0, bias=0.0, random_state=None)` | `(X, y, coef)` |

### `mlkit.base`

Contains the `ClassifierMixin`, `RegressorMixin`, `TransformerMixin` and
`ClusterMixin` mixins for writing your own estimators, plus the validation
helpers `check_array`, `check_X_y` and `check_is_fitted`.

## Scope and limitations

mlkit puts clarity ahead of speed. k-NN uses brute-force distances, and
logistic regression uses plain full-batch gradient descent, so scale your
features first. It is not a replacement for scikit-learn on large datasets.

## License

MIT
