pypu-learn 0.0.1__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.
- pypu_learn-0.0.1/.gitignore +44 -0
- pypu_learn-0.0.1/CHANGELOG.md +26 -0
- pypu_learn-0.0.1/CITATION.cff +14 -0
- pypu_learn-0.0.1/LICENSE +29 -0
- pypu_learn-0.0.1/PKG-INFO +137 -0
- pypu_learn-0.0.1/README.md +108 -0
- pypu_learn-0.0.1/pyproject.toml +135 -0
- pypu_learn-0.0.1/src/pypu/__init__.py +24 -0
- pypu_learn-0.0.1/src/pypu/_version.py +24 -0
- pypu_learn-0.0.1/src/pypu/base.py +184 -0
- pypu_learn-0.0.1/src/pypu/models/__init__.py +42 -0
- pypu_learn-0.0.1/src/pypu/models/naive.py +89 -0
- pypu_learn-0.0.1/src/pypu/utils/__init__.py +6 -0
- pypu_learn-0.0.1/src/pypu/utils/_show_versions.py +27 -0
- pypu_learn-0.0.1/src/pypu/utils/validation.py +120 -0
- pypu_learn-0.0.1/tests/conftest.py +17 -0
- pypu_learn-0.0.1/tests/models/test_naive.py +72 -0
- pypu_learn-0.0.1/tests/test_base.py +54 -0
- pypu_learn-0.0.1/tests/test_model_contract.py +155 -0
- pypu_learn-0.0.1/tests/test_package.py +48 -0
- pypu_learn-0.0.1/tests/test_validation.py +81 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Byte-compiled / cached files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Build artifacts
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.egg
|
|
11
|
+
wheels/
|
|
12
|
+
|
|
13
|
+
# Version file generated by hatch-vcs at build time
|
|
14
|
+
src/pypu/_version.py
|
|
15
|
+
|
|
16
|
+
# Virtual environments
|
|
17
|
+
.venv/
|
|
18
|
+
venv/
|
|
19
|
+
env/
|
|
20
|
+
|
|
21
|
+
# Test, coverage and lint caches
|
|
22
|
+
.pytest_cache/
|
|
23
|
+
.ruff_cache/
|
|
24
|
+
.mypy_cache/
|
|
25
|
+
.coverage
|
|
26
|
+
.coverage.*
|
|
27
|
+
coverage.xml
|
|
28
|
+
htmlcov/
|
|
29
|
+
|
|
30
|
+
# Docs build
|
|
31
|
+
docs/_build/
|
|
32
|
+
site/
|
|
33
|
+
|
|
34
|
+
# Jupyter
|
|
35
|
+
.ipynb_checkpoints/
|
|
36
|
+
|
|
37
|
+
# Editors and OS
|
|
38
|
+
.idea/
|
|
39
|
+
.vscode/
|
|
40
|
+
*.swp
|
|
41
|
+
.DS_Store
|
|
42
|
+
|
|
43
|
+
# Local Claude Code settings (shared settings in .claude/settings.json are kept)
|
|
44
|
+
.claude/settings.local.json
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to PyPU are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project
|
|
6
|
+
uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). While the version is `0.y.z`
|
|
7
|
+
the public API may change between minor versions; such changes are always listed under
|
|
8
|
+
**Changed** or **Removed**.
|
|
9
|
+
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
## [0.0.1] - 2026-11-06
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- Project scaffold: packaging with hatchling and version numbers taken from git tags
|
|
17
|
+
(hatch-vcs), CI on Linux, macOS and Windows for Python 3.11–3.14, and a tag-triggered
|
|
18
|
+
release workflow that publishes to TestPyPI and PyPI.
|
|
19
|
+
- `pypu.base.BasePUClassifier`, the interface shared by all models: `fit(X, s)`,
|
|
20
|
+
`predict_proba`, `decision_function` and `predict`.
|
|
21
|
+
- `pypu.models.NaivePU`, the baseline that treats unlabeled samples as negatives.
|
|
22
|
+
- `pypu.utils.check_pu_labels`, `pypu.utils.check_prior`, `pypu.utils.threshold_from_prior`
|
|
23
|
+
and `pypu.show_versions()`.
|
|
24
|
+
|
|
25
|
+
[Unreleased]: https://github.com/izavits/PyPU/compare/v0.0.1...HEAD
|
|
26
|
+
[0.0.1]: https://github.com/izavits/PyPU/releases/tag/v0.0.1
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use PyPU in your research, please cite it using the metadata below."
|
|
3
|
+
title: "PyPU: Positive-unlabeled learning in Python"
|
|
4
|
+
type: software
|
|
5
|
+
authors:
|
|
6
|
+
- given-names: Ilias
|
|
7
|
+
family-names: Zavitsanos
|
|
8
|
+
repository-code: "https://github.com/izavits/PyPU"
|
|
9
|
+
license: BSD-3-Clause
|
|
10
|
+
keywords:
|
|
11
|
+
- positive-unlabeled learning
|
|
12
|
+
- PU learning
|
|
13
|
+
- machine learning
|
|
14
|
+
- scikit-learn
|
pypu_learn-0.0.1/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, Ilias Zavitsanos
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pypu-learn
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Positive-unlabeled (PU) learning in Python, with a scikit-learn style API.
|
|
5
|
+
Project-URL: Homepage, https://github.com/izavits/PyPU
|
|
6
|
+
Project-URL: Repository, https://github.com/izavits/PyPU
|
|
7
|
+
Project-URL: Issues, https://github.com/izavits/PyPU/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/izavits/PyPU/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Ilias Zavitsanos
|
|
10
|
+
License-Expression: BSD-3-Clause
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: machine-learning,positive-unlabeled,pu-learning,scikit-learn,semi-supervised,weak-supervision
|
|
13
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Requires-Dist: numpy>=1.26
|
|
26
|
+
Requires-Dist: scikit-learn>=1.6
|
|
27
|
+
Requires-Dist: scipy>=1.11
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# PyPU
|
|
31
|
+
|
|
32
|
+
**Positive-unlabeled (PU) learning in Python, with a scikit-learn style API.**
|
|
33
|
+
|
|
34
|
+
[](https://github.com/izavits/PyPU/actions/workflows/ci.yml)
|
|
35
|
+
[](https://pypi.org/project/pypu-learn/)
|
|
36
|
+
[](https://pypi.org/project/pypu-learn/)
|
|
37
|
+
[](https://github.com/izavits/PyPU/blob/main/LICENSE)
|
|
38
|
+
|
|
39
|
+
> **Status: pre-alpha.** The common interface is in place and the methods are being ported.
|
|
40
|
+
> See the [roadmap](https://github.com/izavits/PyPU/blob/main/ROADMAP.md).
|
|
41
|
+
|
|
42
|
+
In PU learning the training data hold some examples labeled positive and many unlabeled
|
|
43
|
+
examples, which are a mix of positives and negatives. No example is labeled negative. This
|
|
44
|
+
happens whenever only one class gets recorded: confirmed frauds, known disease genes, reported
|
|
45
|
+
misstatements, clicked items.
|
|
46
|
+
|
|
47
|
+
PyPU collects PU learning methods behind one interface, in the spirit of
|
|
48
|
+
[PyOD](https://github.com/yzhao062/pyod) for outlier detection: import a model, `fit` it on
|
|
49
|
+
PU data, and predict on new data.
|
|
50
|
+
|
|
51
|
+
## Installation
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install pypu-learn
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The package is imported as `pypu` and needs Python 3.11 or newer. (The PyPI name `pypu`
|
|
58
|
+
belongs to an unrelated project, hence `pypu-learn`.)
|
|
59
|
+
|
|
60
|
+
Until the first release is on PyPI, install from GitHub:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install git+https://github.com/izavits/PyPU.git
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Quick start
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import numpy as np
|
|
70
|
+
from sklearn.datasets import make_classification
|
|
71
|
+
from sklearn.metrics import roc_auc_score
|
|
72
|
+
from sklearn.model_selection import train_test_split
|
|
73
|
+
|
|
74
|
+
from pypu.models import NaivePU
|
|
75
|
+
|
|
76
|
+
# A fully labeled dataset...
|
|
77
|
+
X, y = make_classification(n_samples=2000, weights=[0.8], random_state=0)
|
|
78
|
+
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
|
|
79
|
+
|
|
80
|
+
# ...turned into PU data: label half of the training positives, leave the rest unlabeled.
|
|
81
|
+
rng = np.random.default_rng(0)
|
|
82
|
+
s_train = ((y_train == 1) & (rng.random(len(y_train)) < 0.5)).astype(int)
|
|
83
|
+
|
|
84
|
+
clf = NaivePU(prior=y_train.mean())
|
|
85
|
+
clf.fit(X_train, s_train) # s = 1: labeled positive, s = 0: unlabeled
|
|
86
|
+
|
|
87
|
+
scores = clf.predict_proba(X_test)[:, 1]
|
|
88
|
+
print("ROC AUC:", roc_auc_score(y_test, scores))
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Data utilities that turn labeled datasets into PU data in one call are coming in 0.1.0.
|
|
92
|
+
|
|
93
|
+
## The interface
|
|
94
|
+
|
|
95
|
+
Every model derives from `pypu.base.BasePUClassifier` and is a scikit-learn estimator, so it
|
|
96
|
+
works with `clone`, `Pipeline` and `GridSearchCV`.
|
|
97
|
+
|
|
98
|
+
| Method | Returns |
|
|
99
|
+
| --- | --- |
|
|
100
|
+
| `fit(X, s)` | The fitted model. `s[i] = 1` marks a labeled positive, `s[i] = 0` an unlabeled sample. |
|
|
101
|
+
| `predict_proba(X)` | An `(n_samples, 2)` array; column 1 is the positive-class probability. |
|
|
102
|
+
| `decision_function(X)` | One score per sample; higher means more likely positive. |
|
|
103
|
+
| `predict(X)` | Labels in `{0, 1}`, thresholding the positive-class probability at `threshold_`. |
|
|
104
|
+
|
|
105
|
+
Models that need the class prior π = P(y = 1) take it as a `prior` parameter.
|
|
106
|
+
|
|
107
|
+
## Methods
|
|
108
|
+
|
|
109
|
+
| Model | Description | Status |
|
|
110
|
+
| --- | --- | --- |
|
|
111
|
+
| `NaivePU` | Treats unlabeled samples as negatives; the usual lower bound | available |
|
|
112
|
+
| `IFPU` | Focal-loss PU risk with gradient boosting | planned (0.1.0) |
|
|
113
|
+
| `IFPNU` | Anomaly detector picks reliable negatives, then a focal PNU risk with gradient boosting | planned (0.1.0) |
|
|
114
|
+
| `SAREM` | EM for labels selected at random (SAR) | planned (0.1.0) |
|
|
115
|
+
| `ElkanNoto`, `PUBagging` | Classic PU baselines | planned (0.1.0) |
|
|
116
|
+
| `PUHellingerTree`, `PUHellingerForest` | Hellinger-distance decision trees and forests for PU data | planned (0.2.0) |
|
|
117
|
+
| `NNPU`, `LBE`, `PUe`, `ALMPU` | Neural PU methods (optional PyTorch dependency) | planned (0.3.0) |
|
|
118
|
+
|
|
119
|
+
Also planned: creating PU data from labeled datasets (uniform SCAR selection, KNN-biased and
|
|
120
|
+
other SAR selection mechanisms), class-prior estimation, and PU-specific metrics.
|
|
121
|
+
|
|
122
|
+
## Contributing
|
|
123
|
+
|
|
124
|
+
Contributions are welcome. See
|
|
125
|
+
[CONTRIBUTING.md](https://github.com/izavits/PyPU/blob/main/CONTRIBUTING.md) for the
|
|
126
|
+
development setup, how to add a model, and the release process. Changes are listed in
|
|
127
|
+
[CHANGELOG.md](https://github.com/izavits/PyPU/blob/main/CHANGELOG.md).
|
|
128
|
+
|
|
129
|
+
## Citing
|
|
130
|
+
|
|
131
|
+
If you use PyPU in your research, please cite it; GitHub's "Cite this repository" button uses
|
|
132
|
+
[CITATION.cff](https://github.com/izavits/PyPU/blob/main/CITATION.cff).
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
PyPU is distributed under the
|
|
137
|
+
[BSD 3-Clause License](https://github.com/izavits/PyPU/blob/main/LICENSE).
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# PyPU
|
|
2
|
+
|
|
3
|
+
**Positive-unlabeled (PU) learning in Python, with a scikit-learn style API.**
|
|
4
|
+
|
|
5
|
+
[](https://github.com/izavits/PyPU/actions/workflows/ci.yml)
|
|
6
|
+
[](https://pypi.org/project/pypu-learn/)
|
|
7
|
+
[](https://pypi.org/project/pypu-learn/)
|
|
8
|
+
[](https://github.com/izavits/PyPU/blob/main/LICENSE)
|
|
9
|
+
|
|
10
|
+
> **Status: pre-alpha.** The common interface is in place and the methods are being ported.
|
|
11
|
+
> See the [roadmap](https://github.com/izavits/PyPU/blob/main/ROADMAP.md).
|
|
12
|
+
|
|
13
|
+
In PU learning the training data hold some examples labeled positive and many unlabeled
|
|
14
|
+
examples, which are a mix of positives and negatives. No example is labeled negative. This
|
|
15
|
+
happens whenever only one class gets recorded: confirmed frauds, known disease genes, reported
|
|
16
|
+
misstatements, clicked items.
|
|
17
|
+
|
|
18
|
+
PyPU collects PU learning methods behind one interface, in the spirit of
|
|
19
|
+
[PyOD](https://github.com/yzhao062/pyod) for outlier detection: import a model, `fit` it on
|
|
20
|
+
PU data, and predict on new data.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install pypu-learn
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The package is imported as `pypu` and needs Python 3.11 or newer. (The PyPI name `pypu`
|
|
29
|
+
belongs to an unrelated project, hence `pypu-learn`.)
|
|
30
|
+
|
|
31
|
+
Until the first release is on PyPI, install from GitHub:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install git+https://github.com/izavits/PyPU.git
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick start
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import numpy as np
|
|
41
|
+
from sklearn.datasets import make_classification
|
|
42
|
+
from sklearn.metrics import roc_auc_score
|
|
43
|
+
from sklearn.model_selection import train_test_split
|
|
44
|
+
|
|
45
|
+
from pypu.models import NaivePU
|
|
46
|
+
|
|
47
|
+
# A fully labeled dataset...
|
|
48
|
+
X, y = make_classification(n_samples=2000, weights=[0.8], random_state=0)
|
|
49
|
+
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0)
|
|
50
|
+
|
|
51
|
+
# ...turned into PU data: label half of the training positives, leave the rest unlabeled.
|
|
52
|
+
rng = np.random.default_rng(0)
|
|
53
|
+
s_train = ((y_train == 1) & (rng.random(len(y_train)) < 0.5)).astype(int)
|
|
54
|
+
|
|
55
|
+
clf = NaivePU(prior=y_train.mean())
|
|
56
|
+
clf.fit(X_train, s_train) # s = 1: labeled positive, s = 0: unlabeled
|
|
57
|
+
|
|
58
|
+
scores = clf.predict_proba(X_test)[:, 1]
|
|
59
|
+
print("ROC AUC:", roc_auc_score(y_test, scores))
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Data utilities that turn labeled datasets into PU data in one call are coming in 0.1.0.
|
|
63
|
+
|
|
64
|
+
## The interface
|
|
65
|
+
|
|
66
|
+
Every model derives from `pypu.base.BasePUClassifier` and is a scikit-learn estimator, so it
|
|
67
|
+
works with `clone`, `Pipeline` and `GridSearchCV`.
|
|
68
|
+
|
|
69
|
+
| Method | Returns |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| `fit(X, s)` | The fitted model. `s[i] = 1` marks a labeled positive, `s[i] = 0` an unlabeled sample. |
|
|
72
|
+
| `predict_proba(X)` | An `(n_samples, 2)` array; column 1 is the positive-class probability. |
|
|
73
|
+
| `decision_function(X)` | One score per sample; higher means more likely positive. |
|
|
74
|
+
| `predict(X)` | Labels in `{0, 1}`, thresholding the positive-class probability at `threshold_`. |
|
|
75
|
+
|
|
76
|
+
Models that need the class prior π = P(y = 1) take it as a `prior` parameter.
|
|
77
|
+
|
|
78
|
+
## Methods
|
|
79
|
+
|
|
80
|
+
| Model | Description | Status |
|
|
81
|
+
| --- | --- | --- |
|
|
82
|
+
| `NaivePU` | Treats unlabeled samples as negatives; the usual lower bound | available |
|
|
83
|
+
| `IFPU` | Focal-loss PU risk with gradient boosting | planned (0.1.0) |
|
|
84
|
+
| `IFPNU` | Anomaly detector picks reliable negatives, then a focal PNU risk with gradient boosting | planned (0.1.0) |
|
|
85
|
+
| `SAREM` | EM for labels selected at random (SAR) | planned (0.1.0) |
|
|
86
|
+
| `ElkanNoto`, `PUBagging` | Classic PU baselines | planned (0.1.0) |
|
|
87
|
+
| `PUHellingerTree`, `PUHellingerForest` | Hellinger-distance decision trees and forests for PU data | planned (0.2.0) |
|
|
88
|
+
| `NNPU`, `LBE`, `PUe`, `ALMPU` | Neural PU methods (optional PyTorch dependency) | planned (0.3.0) |
|
|
89
|
+
|
|
90
|
+
Also planned: creating PU data from labeled datasets (uniform SCAR selection, KNN-biased and
|
|
91
|
+
other SAR selection mechanisms), class-prior estimation, and PU-specific metrics.
|
|
92
|
+
|
|
93
|
+
## Contributing
|
|
94
|
+
|
|
95
|
+
Contributions are welcome. See
|
|
96
|
+
[CONTRIBUTING.md](https://github.com/izavits/PyPU/blob/main/CONTRIBUTING.md) for the
|
|
97
|
+
development setup, how to add a model, and the release process. Changes are listed in
|
|
98
|
+
[CHANGELOG.md](https://github.com/izavits/PyPU/blob/main/CHANGELOG.md).
|
|
99
|
+
|
|
100
|
+
## Citing
|
|
101
|
+
|
|
102
|
+
If you use PyPU in your research, please cite it; GitHub's "Cite this repository" button uses
|
|
103
|
+
[CITATION.cff](https://github.com/izavits/PyPU/blob/main/CITATION.cff).
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
PyPU is distributed under the
|
|
108
|
+
[BSD 3-Clause License](https://github.com/izavits/PyPU/blob/main/LICENSE).
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27", "hatch-vcs>=0.4"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
# The distribution name on PyPI. `pypu` is taken (abandoned since 2014); the import name is `pypu`.
|
|
7
|
+
name = "pypu-learn"
|
|
8
|
+
dynamic = ["version"]
|
|
9
|
+
description = "Positive-unlabeled (PU) learning in Python, with a scikit-learn style API."
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
license = "BSD-3-Clause"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
requires-python = ">=3.11"
|
|
14
|
+
authors = [{ name = "Ilias Zavitsanos" }]
|
|
15
|
+
keywords = [
|
|
16
|
+
"pu-learning",
|
|
17
|
+
"positive-unlabeled",
|
|
18
|
+
"semi-supervised",
|
|
19
|
+
"weak-supervision",
|
|
20
|
+
"machine-learning",
|
|
21
|
+
"scikit-learn",
|
|
22
|
+
]
|
|
23
|
+
classifiers = [
|
|
24
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
25
|
+
"Intended Audience :: Science/Research",
|
|
26
|
+
"Intended Audience :: Developers",
|
|
27
|
+
"Operating System :: OS Independent",
|
|
28
|
+
"Programming Language :: Python :: 3",
|
|
29
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
30
|
+
"Programming Language :: Python :: 3.11",
|
|
31
|
+
"Programming Language :: Python :: 3.12",
|
|
32
|
+
"Programming Language :: Python :: 3.13",
|
|
33
|
+
"Programming Language :: Python :: 3.14",
|
|
34
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
35
|
+
]
|
|
36
|
+
dependencies = [
|
|
37
|
+
"numpy>=1.26",
|
|
38
|
+
"scipy>=1.11",
|
|
39
|
+
"scikit-learn>=1.6",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
Homepage = "https://github.com/izavits/PyPU"
|
|
44
|
+
Repository = "https://github.com/izavits/PyPU"
|
|
45
|
+
Issues = "https://github.com/izavits/PyPU/issues"
|
|
46
|
+
Changelog = "https://github.com/izavits/PyPU/blob/main/CHANGELOG.md"
|
|
47
|
+
|
|
48
|
+
[dependency-groups]
|
|
49
|
+
test = [
|
|
50
|
+
"pytest>=8",
|
|
51
|
+
"pytest-cov>=5",
|
|
52
|
+
"pandas>=2", # DataFrame input tests
|
|
53
|
+
]
|
|
54
|
+
dev = [
|
|
55
|
+
{ include-group = "test" },
|
|
56
|
+
"ruff>=0.17",
|
|
57
|
+
"pre-commit>=4",
|
|
58
|
+
"build>=1.2",
|
|
59
|
+
"twine>=6",
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
# ---------------------------------------------------------------- build
|
|
63
|
+
|
|
64
|
+
[tool.hatch.version]
|
|
65
|
+
source = "vcs"
|
|
66
|
+
# Used when building outside a git checkout or before the first commit/tag.
|
|
67
|
+
fallback-version = "0.0.0"
|
|
68
|
+
|
|
69
|
+
[tool.hatch.build.hooks.vcs]
|
|
70
|
+
version-file = "src/pypu/_version.py"
|
|
71
|
+
|
|
72
|
+
[tool.hatch.build.targets.wheel]
|
|
73
|
+
packages = ["src/pypu"]
|
|
74
|
+
|
|
75
|
+
[tool.hatch.build.targets.sdist]
|
|
76
|
+
include = [
|
|
77
|
+
"src/pypu",
|
|
78
|
+
"tests",
|
|
79
|
+
"README.md",
|
|
80
|
+
"CHANGELOG.md",
|
|
81
|
+
"CITATION.cff",
|
|
82
|
+
"LICENSE",
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
# ---------------------------------------------------------------- tests
|
|
86
|
+
|
|
87
|
+
[tool.pytest.ini_options]
|
|
88
|
+
testpaths = ["tests"]
|
|
89
|
+
addopts = ["-ra", "--strict-markers", "--strict-config"]
|
|
90
|
+
xfail_strict = true
|
|
91
|
+
|
|
92
|
+
[tool.coverage.run]
|
|
93
|
+
source = ["pypu"]
|
|
94
|
+
branch = true
|
|
95
|
+
omit = ["*/_version.py"]
|
|
96
|
+
|
|
97
|
+
[tool.coverage.report]
|
|
98
|
+
show_missing = true
|
|
99
|
+
skip_covered = true
|
|
100
|
+
exclude_also = [
|
|
101
|
+
"if TYPE_CHECKING:",
|
|
102
|
+
"raise NotImplementedError",
|
|
103
|
+
"@abstractmethod",
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
# ---------------------------------------------------------------- lint
|
|
107
|
+
|
|
108
|
+
[tool.ruff]
|
|
109
|
+
line-length = 100
|
|
110
|
+
target-version = "py311"
|
|
111
|
+
src = ["src", "tests"]
|
|
112
|
+
|
|
113
|
+
[tool.ruff.lint]
|
|
114
|
+
select = [
|
|
115
|
+
"E", # pycodestyle errors
|
|
116
|
+
"W", # pycodestyle warnings
|
|
117
|
+
"F", # pyflakes
|
|
118
|
+
"I", # isort
|
|
119
|
+
"B", # flake8-bugbear
|
|
120
|
+
"UP", # pyupgrade
|
|
121
|
+
"SIM", # flake8-simplify
|
|
122
|
+
"NPY", # numpy-specific rules
|
|
123
|
+
"RUF", # ruff-specific rules
|
|
124
|
+
"D", # pydocstyle (numpy convention)
|
|
125
|
+
]
|
|
126
|
+
ignore = [
|
|
127
|
+
"D105", # magic methods need no docstring
|
|
128
|
+
"D107", # parameters are documented in the class docstring (scikit-learn style)
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
[tool.ruff.lint.pydocstyle]
|
|
132
|
+
convention = "numpy"
|
|
133
|
+
|
|
134
|
+
[tool.ruff.lint.per-file-ignores]
|
|
135
|
+
"tests/**" = ["D"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""PyPU: positive-unlabeled (PU) learning in Python.
|
|
2
|
+
|
|
3
|
+
PU learning trains a binary classifier from positive examples and unlabeled examples
|
|
4
|
+
(a mix of positives and negatives), without any example labeled negative. PyPU collects
|
|
5
|
+
PU learning methods behind one scikit-learn style interface: every model is fitted with
|
|
6
|
+
``fit(X, s)``, where ``s[i] == 1`` marks a labeled positive and ``s[i] == 0`` an unlabeled
|
|
7
|
+
sample.
|
|
8
|
+
|
|
9
|
+
Subpackages
|
|
10
|
+
-----------
|
|
11
|
+
models
|
|
12
|
+
The PU classifiers, e.g. ``from pypu.models import NaivePU``.
|
|
13
|
+
utils
|
|
14
|
+
Input validation and helpers shared by the models.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from pypu.utils import show_versions
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
from pypu._version import __version__
|
|
21
|
+
except ImportError: # pragma: no cover - only when running from a source tree without installing
|
|
22
|
+
__version__ = "0.0.0+unknown"
|
|
23
|
+
|
|
24
|
+
__all__ = ["__version__", "show_versions"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.0.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 0, 1)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|