optuml 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.
- optuml-0.1.0/LICENSE +21 -0
- optuml-0.1.0/PKG-INFO +247 -0
- optuml-0.1.0/README.md +228 -0
- optuml-0.1.0/optimum/__init__.py +0 -0
- optuml-0.1.0/optimum/optuml.py +152 -0
- optuml-0.1.0/optuml.egg-info/PKG-INFO +247 -0
- optuml-0.1.0/optuml.egg-info/SOURCES.txt +13 -0
- optuml-0.1.0/optuml.egg-info/dependency_links.txt +1 -0
- optuml-0.1.0/optuml.egg-info/requires.txt +5 -0
- optuml-0.1.0/optuml.egg-info/top_level.txt +2 -0
- optuml-0.1.0/pyproject.toml +3 -0
- optuml-0.1.0/setup.cfg +4 -0
- optuml-0.1.0/setup.py +29 -0
- optuml-0.1.0/tests/__init__.py +0 -0
- optuml-0.1.0/tests/test_optimizer.py +108 -0
optuml-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 filips
|
|
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.
|
optuml-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: optuml
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Hyperparameter optimization for multiple machine learning algorithms using Optuna, with Scikit-learn API
|
|
5
|
+
Home-page: https://github.com/filipsPL/optuml
|
|
6
|
+
Author: Filip S.
|
|
7
|
+
Author-email: filip.ursynow@gmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.6
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: optuna
|
|
15
|
+
Requires-Dist: scikit-learn
|
|
16
|
+
Requires-Dist: catboost
|
|
17
|
+
Requires-Dist: xgboost
|
|
18
|
+
Requires-Dist: numpy
|
|
19
|
+
|
|
20
|
+
# OptuML: Hyperparameter Optimization for Multiple Machine Learning Algorithms using Optuna
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
⣰⡁ ⡀⣀ ⢀⡀ ⣀⣀ ⡎⢱ ⣀⡀ ⣰⡀ ⡀⢀ ⡷⢾ ⡇ ⠄ ⣀⣀ ⣀⡀ ⢀⡀ ⡀⣀ ⣰⡀ ⡎⢱ ⣀⡀ ⣰⡀ ⠄ ⣀⣀ ⠄ ⣀⣀ ⢀⡀ ⡀⣀
|
|
24
|
+
⢸ ⠏ ⠣⠜ ⠇⠇⠇ ⠣⠜ ⡧⠜ ⠘⠤ ⠣⠼ ⠇⠸ ⠧⠤ ⠇ ⠇⠇⠇ ⡧⠜ ⠣⠜ ⠏ ⠘⠤ ⠣⠜ ⡧⠜ ⠘⠤ ⠇ ⠇⠇⠇ ⠇ ⠴⠥ ⠣⠭ ⠏
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`OptuML` is a Python module that provides hyperparameter optimization for several machine learning algorithms using the [Optuna](https://optuna.org/) framework. The module supports a variety of algorithms and allows easy hyperparameter tuning through a scikit-learn-like API.
|
|
28
|
+
|
|
29
|
+
[](https://github.com/filipsPL/optuml/actions/workflows/python-package.yml)
|
|
30
|
+
|
|
31
|
+
- [OptuML: Hyperparameter Optimization for Multiple Machine Learning Algorithms using Optuna](#optuml-hyperparameter-optimization-for-multiple-machine-learning-algorithms-using-optuna)
|
|
32
|
+
- [Quick start](#quick-start)
|
|
33
|
+
- [Features](#features)
|
|
34
|
+
- [Installation](#installation)
|
|
35
|
+
- [Prerequisites](#prerequisites)
|
|
36
|
+
- [Installation](#installation-1)
|
|
37
|
+
- [Usage](#usage)
|
|
38
|
+
- [Basic Example](#basic-example)
|
|
39
|
+
- [Available Algorithms](#available-algorithms)
|
|
40
|
+
- [Example of Optimizing Different Algorithms](#example-of-optimizing-different-algorithms)
|
|
41
|
+
- [Custom Scoring and Direction](#custom-scoring-and-direction)
|
|
42
|
+
- [Controlling Verbosity](#controlling-verbosity)
|
|
43
|
+
- [API Reference](#api-reference)
|
|
44
|
+
- [`Optimizer`](#optimizer)
|
|
45
|
+
- [Parameters:](#parameters)
|
|
46
|
+
- [Methods:](#methods)
|
|
47
|
+
- [Contributing](#contributing)
|
|
48
|
+
- [Running Tests](#running-tests)
|
|
49
|
+
- [Contact](#contact)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## Quick start
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from OptuML import Optimizer
|
|
56
|
+
|
|
57
|
+
# Instantiate the optimizer for SVM
|
|
58
|
+
optimizer = Optimizer(algorithm="SVM", n_trials=50, cv=3, scoring="accuracy", verbose=True)
|
|
59
|
+
|
|
60
|
+
# Fit the optimizer to the training data
|
|
61
|
+
optimizer.fit(X_train, y_train)
|
|
62
|
+
|
|
63
|
+
# Predict on the test set
|
|
64
|
+
y_pred = optimizer.predict(X_test)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
## Features
|
|
69
|
+
|
|
70
|
+
- **Multiple Algorithms**: Supports hyperparameter optimization for the following algorithms:
|
|
71
|
+
- Support Vector Machine (SVM)
|
|
72
|
+
- k-Nearest Neighbors (kNN)
|
|
73
|
+
- Random Forest
|
|
74
|
+
- CatBoost
|
|
75
|
+
- XGBoost
|
|
76
|
+
- Logistic Regression
|
|
77
|
+
- Decision Tree
|
|
78
|
+
- **Optuna Framework**: Leverages Optuna for powerful hyperparameter search.
|
|
79
|
+
- **Maximize or Minimize**: Allows setting the optimization direction (`maximize` or `minimize`).
|
|
80
|
+
- **Scikit-learn API**: Provides a consistent interface for `fit()`, `predict()`, `predict_proba()`, and `score()` methods.
|
|
81
|
+
- **Control Output**: Optionally run Optuna with verbose logging (`verbose=True`) or in silent mode (`verbose=False`).
|
|
82
|
+
- **Cross-validation**: Easily integrate cross-validation with custom scoring metrics (e.g., accuracy, ROC AUC).
|
|
83
|
+
|
|
84
|
+
## Installation
|
|
85
|
+
|
|
86
|
+
### Prerequisites
|
|
87
|
+
|
|
88
|
+
Ensure that the following Python packages are installed:
|
|
89
|
+
|
|
90
|
+
- `optuna`
|
|
91
|
+
- `scikit-learn`
|
|
92
|
+
- `catboost`
|
|
93
|
+
- `xgboost`
|
|
94
|
+
- `numpy`
|
|
95
|
+
|
|
96
|
+
You can install the required packages via `pip`:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pip install optuna scikit-learn catboost xgboost numpy
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Installation
|
|
103
|
+
|
|
104
|
+
Just fetch the `optuml.py` [file from the repo](optuml.py) and put it in the directory with your script.
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
## Usage
|
|
108
|
+
|
|
109
|
+
### Basic Example
|
|
110
|
+
|
|
111
|
+
Here’s how you can use the `Optimizer` class to optimize hyperparameters for different machine learning algorithms using the **Iris** dataset:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from sklearn.datasets import load_iris
|
|
115
|
+
from sklearn.model_selection import train_test_split
|
|
116
|
+
from sklearn.metrics import accuracy_score
|
|
117
|
+
from OptuML import Optimizer
|
|
118
|
+
|
|
119
|
+
# Load the Iris dataset
|
|
120
|
+
X, y = load_iris(return_X_y=True)
|
|
121
|
+
|
|
122
|
+
# Convert to a binary classification problem
|
|
123
|
+
X = X[y != 2]
|
|
124
|
+
y = y[y != 2]
|
|
125
|
+
|
|
126
|
+
# Split the dataset into training and test sets
|
|
127
|
+
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
|
|
128
|
+
|
|
129
|
+
# Instantiate the optimizer for SVM
|
|
130
|
+
optimizer = Optimizer(algorithm="SVM", n_trials=50, cv=3, scoring="accuracy", verbose=True, random_state=42)
|
|
131
|
+
|
|
132
|
+
# Fit the optimizer to the training data
|
|
133
|
+
optimizer.fit(X_train, y_train)
|
|
134
|
+
|
|
135
|
+
# Predict on the test set
|
|
136
|
+
y_pred = optimizer.predict(X_test)
|
|
137
|
+
|
|
138
|
+
# Calculate the accuracy
|
|
139
|
+
accuracy = accuracy_score(y_test, y_pred)
|
|
140
|
+
print(f"Accuracy: {accuracy}")
|
|
141
|
+
|
|
142
|
+
# Print the best hyperparameters found during optimization
|
|
143
|
+
print(f"Best Hyperparameters: {optimizer.best_params_}")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Available Algorithms
|
|
147
|
+
|
|
148
|
+
The `Optimizer` class supports the following algorithms. You can specify the `algorithm` parameter to choose which one to use:
|
|
149
|
+
|
|
150
|
+
- `"SVM"` (Support Vector Machine)
|
|
151
|
+
- `"kNN"` (k-Nearest Neighbors)
|
|
152
|
+
- `"RandomForest"` (Random Forest)
|
|
153
|
+
- `"CatBoost"` (CatBoost Classifier)
|
|
154
|
+
- `"XGBoost"` (XGBoost Classifier)
|
|
155
|
+
- `"LogisticRegression"` (Logistic Regression)
|
|
156
|
+
- `"DecisionTree"` (Decision Tree Classifier)
|
|
157
|
+
|
|
158
|
+
### Example of Optimizing Different Algorithms
|
|
159
|
+
|
|
160
|
+
You can iterate over different algorithms and optimize hyperparameters for each one:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
algorithms = ['SVM', 'kNN', 'RandomForest', 'CatBoost', 'XGBoost', 'LogisticRegression', 'DecisionTree']
|
|
164
|
+
|
|
165
|
+
for algorithm in algorithms:
|
|
166
|
+
print(f"Optimizing {algorithm}")
|
|
167
|
+
optimizer = Optimizer(algorithm=algorithm, n_trials=50, cv=3, scoring="accuracy", verbose=False, random_state=42)
|
|
168
|
+
optimizer.fit(X_train, y_train)
|
|
169
|
+
|
|
170
|
+
# Predict and calculate accuracy
|
|
171
|
+
y_pred = optimizer.predict(X_test)
|
|
172
|
+
accuracy = accuracy_score(y_test, y_pred)
|
|
173
|
+
print(f"Accuracy for {algorithm}: {accuracy}")
|
|
174
|
+
print(f"Best Hyperparameters for {algorithm}: {optimizer.best_params_}")
|
|
175
|
+
print("="*60)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Custom Scoring and Direction
|
|
179
|
+
|
|
180
|
+
You can also optimize for different scoring metrics like ROC AUC or use the `direction` parameter to **minimize** or **maximize** the objective:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
# Instantiate the optimizer for RandomForest with ROC AUC optimization
|
|
184
|
+
optimizer = Optimizer(algorithm="RandomForest", n_trials=50, cv=3, scoring="roc_auc", direction="maximize", verbose=True, random_state=42)
|
|
185
|
+
|
|
186
|
+
# Fit the optimizer to the training data
|
|
187
|
+
optimizer.fit(X_train, y_train)
|
|
188
|
+
|
|
189
|
+
# Predict probabilities and calculate ROC AUC
|
|
190
|
+
y_proba = optimizer.predict_proba(X_test)
|
|
191
|
+
roc_auc = roc_auc_score(y_test, y_proba[:, 1])
|
|
192
|
+
print(f"ROC AUC: {roc_auc}")
|
|
193
|
+
|
|
194
|
+
# Print the best hyperparameters
|
|
195
|
+
print(f"Best Hyperparameters: {optimizer.best_params_}")
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Controlling Verbosity
|
|
199
|
+
|
|
200
|
+
You can control the verbosity of Optuna's output by using the `verbose` parameter:
|
|
201
|
+
|
|
202
|
+
- Set `verbose=True` to enable detailed Optuna logging.
|
|
203
|
+
- Set `verbose=False` to suppress logging and run the optimizer silently.
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
optimizer = Optimizer(algorithm="SVM", n_trials=50, cv=3, scoring="accuracy", verbose=True, random_state=42)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## API Reference
|
|
210
|
+
|
|
211
|
+
### `Optimizer`
|
|
212
|
+
|
|
213
|
+
#### Parameters:
|
|
214
|
+
|
|
215
|
+
- **`algorithm`** (`str`): The machine learning algorithm to optimize. Options are `'SVM'`, `'kNN'`, `'RandomForest'`, `'CatBoost'`, `'XGBoost'`, `'LogisticRegression'`, `'DecisionTree'`.
|
|
216
|
+
- **`direction`** (`str`, default `"maximize"`): Direction of optimization. Can be `"maximize"` or `"minimize"`.
|
|
217
|
+
- **`verbose`** (`bool`, default `False`): If `True`, Optuna logging will be enabled. If `False`, the optimizer will run silently.
|
|
218
|
+
- **`n_trials`** (`int`, default `100`): Number of optimization trials to run.
|
|
219
|
+
- **`timeout`** (`float`, optional): Maximum time (in seconds) for the optimization process.
|
|
220
|
+
- **`cv`** (`int`, default `5`): Number of cross-validation folds.
|
|
221
|
+
- **`scoring`** (`str`, default `"accuracy"`): Scoring metric to use during cross-validation.
|
|
222
|
+
- **`random_state`** (`int`, optional): Seed for random number generation.
|
|
223
|
+
|
|
224
|
+
#### Methods:
|
|
225
|
+
|
|
226
|
+
- **`fit(X, y)`**: Fit the model using hyperparameter optimization.
|
|
227
|
+
- **`predict(X)`**: Make predictions using the best model found during optimization.
|
|
228
|
+
- **`predict_proba(X)`**: Predict class probabilities (if supported by the model).
|
|
229
|
+
- **`score(X, y)`**: Score the model using the test data.
|
|
230
|
+
- **`optimization_time()`**: Get the total time taken for optimization.
|
|
231
|
+
|
|
232
|
+
## Contributing
|
|
233
|
+
|
|
234
|
+
Contributions to the project are welcome! Please feel free to submit issues or pull requests on GitHub. You can also fork the repository and make your changes.
|
|
235
|
+
|
|
236
|
+
## Running Tests
|
|
237
|
+
|
|
238
|
+
You can run unit tests using `pytest`:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
pip install pytest
|
|
242
|
+
pytest
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Contact
|
|
246
|
+
|
|
247
|
+
If you have any questions or feedback, feel free to open an issue on GitHub.
|
optuml-0.1.0/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# OptuML: Hyperparameter Optimization for Multiple Machine Learning Algorithms using Optuna
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
⣰⡁ ⡀⣀ ⢀⡀ ⣀⣀ ⡎⢱ ⣀⡀ ⣰⡀ ⡀⢀ ⡷⢾ ⡇ ⠄ ⣀⣀ ⣀⡀ ⢀⡀ ⡀⣀ ⣰⡀ ⡎⢱ ⣀⡀ ⣰⡀ ⠄ ⣀⣀ ⠄ ⣀⣀ ⢀⡀ ⡀⣀
|
|
5
|
+
⢸ ⠏ ⠣⠜ ⠇⠇⠇ ⠣⠜ ⡧⠜ ⠘⠤ ⠣⠼ ⠇⠸ ⠧⠤ ⠇ ⠇⠇⠇ ⡧⠜ ⠣⠜ ⠏ ⠘⠤ ⠣⠜ ⡧⠜ ⠘⠤ ⠇ ⠇⠇⠇ ⠇ ⠴⠥ ⠣⠭ ⠏
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
`OptuML` is a Python module that provides hyperparameter optimization for several machine learning algorithms using the [Optuna](https://optuna.org/) framework. The module supports a variety of algorithms and allows easy hyperparameter tuning through a scikit-learn-like API.
|
|
9
|
+
|
|
10
|
+
[](https://github.com/filipsPL/optuml/actions/workflows/python-package.yml)
|
|
11
|
+
|
|
12
|
+
- [OptuML: Hyperparameter Optimization for Multiple Machine Learning Algorithms using Optuna](#optuml-hyperparameter-optimization-for-multiple-machine-learning-algorithms-using-optuna)
|
|
13
|
+
- [Quick start](#quick-start)
|
|
14
|
+
- [Features](#features)
|
|
15
|
+
- [Installation](#installation)
|
|
16
|
+
- [Prerequisites](#prerequisites)
|
|
17
|
+
- [Installation](#installation-1)
|
|
18
|
+
- [Usage](#usage)
|
|
19
|
+
- [Basic Example](#basic-example)
|
|
20
|
+
- [Available Algorithms](#available-algorithms)
|
|
21
|
+
- [Example of Optimizing Different Algorithms](#example-of-optimizing-different-algorithms)
|
|
22
|
+
- [Custom Scoring and Direction](#custom-scoring-and-direction)
|
|
23
|
+
- [Controlling Verbosity](#controlling-verbosity)
|
|
24
|
+
- [API Reference](#api-reference)
|
|
25
|
+
- [`Optimizer`](#optimizer)
|
|
26
|
+
- [Parameters:](#parameters)
|
|
27
|
+
- [Methods:](#methods)
|
|
28
|
+
- [Contributing](#contributing)
|
|
29
|
+
- [Running Tests](#running-tests)
|
|
30
|
+
- [Contact](#contact)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## Quick start
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from OptuML import Optimizer
|
|
37
|
+
|
|
38
|
+
# Instantiate the optimizer for SVM
|
|
39
|
+
optimizer = Optimizer(algorithm="SVM", n_trials=50, cv=3, scoring="accuracy", verbose=True)
|
|
40
|
+
|
|
41
|
+
# Fit the optimizer to the training data
|
|
42
|
+
optimizer.fit(X_train, y_train)
|
|
43
|
+
|
|
44
|
+
# Predict on the test set
|
|
45
|
+
y_pred = optimizer.predict(X_test)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
## Features
|
|
50
|
+
|
|
51
|
+
- **Multiple Algorithms**: Supports hyperparameter optimization for the following algorithms:
|
|
52
|
+
- Support Vector Machine (SVM)
|
|
53
|
+
- k-Nearest Neighbors (kNN)
|
|
54
|
+
- Random Forest
|
|
55
|
+
- CatBoost
|
|
56
|
+
- XGBoost
|
|
57
|
+
- Logistic Regression
|
|
58
|
+
- Decision Tree
|
|
59
|
+
- **Optuna Framework**: Leverages Optuna for powerful hyperparameter search.
|
|
60
|
+
- **Maximize or Minimize**: Allows setting the optimization direction (`maximize` or `minimize`).
|
|
61
|
+
- **Scikit-learn API**: Provides a consistent interface for `fit()`, `predict()`, `predict_proba()`, and `score()` methods.
|
|
62
|
+
- **Control Output**: Optionally run Optuna with verbose logging (`verbose=True`) or in silent mode (`verbose=False`).
|
|
63
|
+
- **Cross-validation**: Easily integrate cross-validation with custom scoring metrics (e.g., accuracy, ROC AUC).
|
|
64
|
+
|
|
65
|
+
## Installation
|
|
66
|
+
|
|
67
|
+
### Prerequisites
|
|
68
|
+
|
|
69
|
+
Ensure that the following Python packages are installed:
|
|
70
|
+
|
|
71
|
+
- `optuna`
|
|
72
|
+
- `scikit-learn`
|
|
73
|
+
- `catboost`
|
|
74
|
+
- `xgboost`
|
|
75
|
+
- `numpy`
|
|
76
|
+
|
|
77
|
+
You can install the required packages via `pip`:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
pip install optuna scikit-learn catboost xgboost numpy
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Installation
|
|
84
|
+
|
|
85
|
+
Just fetch the `optuml.py` [file from the repo](optuml.py) and put it in the directory with your script.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## Usage
|
|
89
|
+
|
|
90
|
+
### Basic Example
|
|
91
|
+
|
|
92
|
+
Here’s how you can use the `Optimizer` class to optimize hyperparameters for different machine learning algorithms using the **Iris** dataset:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from sklearn.datasets import load_iris
|
|
96
|
+
from sklearn.model_selection import train_test_split
|
|
97
|
+
from sklearn.metrics import accuracy_score
|
|
98
|
+
from OptuML import Optimizer
|
|
99
|
+
|
|
100
|
+
# Load the Iris dataset
|
|
101
|
+
X, y = load_iris(return_X_y=True)
|
|
102
|
+
|
|
103
|
+
# Convert to a binary classification problem
|
|
104
|
+
X = X[y != 2]
|
|
105
|
+
y = y[y != 2]
|
|
106
|
+
|
|
107
|
+
# Split the dataset into training and test sets
|
|
108
|
+
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
|
|
109
|
+
|
|
110
|
+
# Instantiate the optimizer for SVM
|
|
111
|
+
optimizer = Optimizer(algorithm="SVM", n_trials=50, cv=3, scoring="accuracy", verbose=True, random_state=42)
|
|
112
|
+
|
|
113
|
+
# Fit the optimizer to the training data
|
|
114
|
+
optimizer.fit(X_train, y_train)
|
|
115
|
+
|
|
116
|
+
# Predict on the test set
|
|
117
|
+
y_pred = optimizer.predict(X_test)
|
|
118
|
+
|
|
119
|
+
# Calculate the accuracy
|
|
120
|
+
accuracy = accuracy_score(y_test, y_pred)
|
|
121
|
+
print(f"Accuracy: {accuracy}")
|
|
122
|
+
|
|
123
|
+
# Print the best hyperparameters found during optimization
|
|
124
|
+
print(f"Best Hyperparameters: {optimizer.best_params_}")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Available Algorithms
|
|
128
|
+
|
|
129
|
+
The `Optimizer` class supports the following algorithms. You can specify the `algorithm` parameter to choose which one to use:
|
|
130
|
+
|
|
131
|
+
- `"SVM"` (Support Vector Machine)
|
|
132
|
+
- `"kNN"` (k-Nearest Neighbors)
|
|
133
|
+
- `"RandomForest"` (Random Forest)
|
|
134
|
+
- `"CatBoost"` (CatBoost Classifier)
|
|
135
|
+
- `"XGBoost"` (XGBoost Classifier)
|
|
136
|
+
- `"LogisticRegression"` (Logistic Regression)
|
|
137
|
+
- `"DecisionTree"` (Decision Tree Classifier)
|
|
138
|
+
|
|
139
|
+
### Example of Optimizing Different Algorithms
|
|
140
|
+
|
|
141
|
+
You can iterate over different algorithms and optimize hyperparameters for each one:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
algorithms = ['SVM', 'kNN', 'RandomForest', 'CatBoost', 'XGBoost', 'LogisticRegression', 'DecisionTree']
|
|
145
|
+
|
|
146
|
+
for algorithm in algorithms:
|
|
147
|
+
print(f"Optimizing {algorithm}")
|
|
148
|
+
optimizer = Optimizer(algorithm=algorithm, n_trials=50, cv=3, scoring="accuracy", verbose=False, random_state=42)
|
|
149
|
+
optimizer.fit(X_train, y_train)
|
|
150
|
+
|
|
151
|
+
# Predict and calculate accuracy
|
|
152
|
+
y_pred = optimizer.predict(X_test)
|
|
153
|
+
accuracy = accuracy_score(y_test, y_pred)
|
|
154
|
+
print(f"Accuracy for {algorithm}: {accuracy}")
|
|
155
|
+
print(f"Best Hyperparameters for {algorithm}: {optimizer.best_params_}")
|
|
156
|
+
print("="*60)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Custom Scoring and Direction
|
|
160
|
+
|
|
161
|
+
You can also optimize for different scoring metrics like ROC AUC or use the `direction` parameter to **minimize** or **maximize** the objective:
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
# Instantiate the optimizer for RandomForest with ROC AUC optimization
|
|
165
|
+
optimizer = Optimizer(algorithm="RandomForest", n_trials=50, cv=3, scoring="roc_auc", direction="maximize", verbose=True, random_state=42)
|
|
166
|
+
|
|
167
|
+
# Fit the optimizer to the training data
|
|
168
|
+
optimizer.fit(X_train, y_train)
|
|
169
|
+
|
|
170
|
+
# Predict probabilities and calculate ROC AUC
|
|
171
|
+
y_proba = optimizer.predict_proba(X_test)
|
|
172
|
+
roc_auc = roc_auc_score(y_test, y_proba[:, 1])
|
|
173
|
+
print(f"ROC AUC: {roc_auc}")
|
|
174
|
+
|
|
175
|
+
# Print the best hyperparameters
|
|
176
|
+
print(f"Best Hyperparameters: {optimizer.best_params_}")
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Controlling Verbosity
|
|
180
|
+
|
|
181
|
+
You can control the verbosity of Optuna's output by using the `verbose` parameter:
|
|
182
|
+
|
|
183
|
+
- Set `verbose=True` to enable detailed Optuna logging.
|
|
184
|
+
- Set `verbose=False` to suppress logging and run the optimizer silently.
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
optimizer = Optimizer(algorithm="SVM", n_trials=50, cv=3, scoring="accuracy", verbose=True, random_state=42)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## API Reference
|
|
191
|
+
|
|
192
|
+
### `Optimizer`
|
|
193
|
+
|
|
194
|
+
#### Parameters:
|
|
195
|
+
|
|
196
|
+
- **`algorithm`** (`str`): The machine learning algorithm to optimize. Options are `'SVM'`, `'kNN'`, `'RandomForest'`, `'CatBoost'`, `'XGBoost'`, `'LogisticRegression'`, `'DecisionTree'`.
|
|
197
|
+
- **`direction`** (`str`, default `"maximize"`): Direction of optimization. Can be `"maximize"` or `"minimize"`.
|
|
198
|
+
- **`verbose`** (`bool`, default `False`): If `True`, Optuna logging will be enabled. If `False`, the optimizer will run silently.
|
|
199
|
+
- **`n_trials`** (`int`, default `100`): Number of optimization trials to run.
|
|
200
|
+
- **`timeout`** (`float`, optional): Maximum time (in seconds) for the optimization process.
|
|
201
|
+
- **`cv`** (`int`, default `5`): Number of cross-validation folds.
|
|
202
|
+
- **`scoring`** (`str`, default `"accuracy"`): Scoring metric to use during cross-validation.
|
|
203
|
+
- **`random_state`** (`int`, optional): Seed for random number generation.
|
|
204
|
+
|
|
205
|
+
#### Methods:
|
|
206
|
+
|
|
207
|
+
- **`fit(X, y)`**: Fit the model using hyperparameter optimization.
|
|
208
|
+
- **`predict(X)`**: Make predictions using the best model found during optimization.
|
|
209
|
+
- **`predict_proba(X)`**: Predict class probabilities (if supported by the model).
|
|
210
|
+
- **`score(X, y)`**: Score the model using the test data.
|
|
211
|
+
- **`optimization_time()`**: Get the total time taken for optimization.
|
|
212
|
+
|
|
213
|
+
## Contributing
|
|
214
|
+
|
|
215
|
+
Contributions to the project are welcome! Please feel free to submit issues or pull requests on GitHub. You can also fork the repository and make your changes.
|
|
216
|
+
|
|
217
|
+
## Running Tests
|
|
218
|
+
|
|
219
|
+
You can run unit tests using `pytest`:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
pip install pytest
|
|
223
|
+
pytest
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Contact
|
|
227
|
+
|
|
228
|
+
If you have any questions or feedback, feel free to open an issue on GitHub.
|
|
File without changes
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import optuna
|
|
2
|
+
from sklearn.svm import SVC
|
|
3
|
+
from sklearn.neighbors import KNeighborsClassifier
|
|
4
|
+
from sklearn.ensemble import RandomForestClassifier
|
|
5
|
+
from sklearn.linear_model import LogisticRegression
|
|
6
|
+
from sklearn.tree import DecisionTreeClassifier
|
|
7
|
+
from sklearn.model_selection import cross_val_score
|
|
8
|
+
from sklearn.base import BaseEstimator, ClassifierMixin
|
|
9
|
+
from catboost import CatBoostClassifier
|
|
10
|
+
from xgboost import XGBClassifier
|
|
11
|
+
import time
|
|
12
|
+
import warnings
|
|
13
|
+
|
|
14
|
+
class Optimizer(BaseEstimator, ClassifierMixin):
|
|
15
|
+
def __init__(self, algorithm="SVM", direction="maximize", verbose=False, n_trials=100, timeout=None, cv=5, scoring="accuracy", random_state=None):
|
|
16
|
+
"""
|
|
17
|
+
Initializes the optimizer with the following parameters:
|
|
18
|
+
:param algorithm: Machine learning algorithm to optimize. Options are 'SVM', 'kNN', 'RandomForest', 'CatBoost', 'XGBoost', 'LogisticRegression', 'DecisionTree'.
|
|
19
|
+
:param direction: Optimization direction, either 'maximize' (default) or 'minimize'.
|
|
20
|
+
:param verbose: If True, enables Optuna verbose logging.
|
|
21
|
+
:param n_trials: Number of trials for Optuna optimization (default 100)
|
|
22
|
+
:param timeout: Maximum time allowed for optimization (in seconds)
|
|
23
|
+
:param cv: Number of cross-validation folds (default 5)
|
|
24
|
+
:param scoring: Scoring method for cross-validation (default "accuracy")
|
|
25
|
+
:param random_state: Random state for reproducibility (default None)
|
|
26
|
+
"""
|
|
27
|
+
self.algorithm = algorithm
|
|
28
|
+
self.direction = direction
|
|
29
|
+
self.verbosity = verbose
|
|
30
|
+
self.n_trials = n_trials
|
|
31
|
+
self.timeout = timeout
|
|
32
|
+
self.cv = cv
|
|
33
|
+
self.scoring = scoring
|
|
34
|
+
self.random_state = random_state
|
|
35
|
+
self.best_params_ = None
|
|
36
|
+
self.best_estimator_ = None
|
|
37
|
+
self.study_time_ = None
|
|
38
|
+
|
|
39
|
+
# Set Optuna logging verbosity
|
|
40
|
+
if verbose:
|
|
41
|
+
optuna.logging.set_verbosity(optuna.logging.INFO)
|
|
42
|
+
else:
|
|
43
|
+
optuna.logging.set_verbosity(optuna.logging.WARNING)
|
|
44
|
+
|
|
45
|
+
# Suppress XGBoost warnings about label encoder
|
|
46
|
+
warnings.filterwarnings('ignore', category=UserWarning, message="`use_label_encoder` is deprecated")
|
|
47
|
+
|
|
48
|
+
def _objective(self, trial, X, y):
|
|
49
|
+
"""Objective function for Optuna optimization"""
|
|
50
|
+
if self.algorithm == "SVM":
|
|
51
|
+
C = trial.suggest_float("C", 1e-5, 1e2, log=True)
|
|
52
|
+
gamma = trial.suggest_float("gamma", 1e-5, 1e1, log=True)
|
|
53
|
+
kernel = trial.suggest_categorical("kernel", ["linear", "rbf", "poly", "sigmoid"])
|
|
54
|
+
if kernel == "poly":
|
|
55
|
+
degree = trial.suggest_int("degree", 2, 5)
|
|
56
|
+
else:
|
|
57
|
+
degree = 3
|
|
58
|
+
model = SVC(C=C, gamma=gamma, kernel=kernel, degree=degree, random_state=self.random_state, probability=True)
|
|
59
|
+
|
|
60
|
+
elif self.algorithm == "kNN":
|
|
61
|
+
n_neighbors = trial.suggest_int("n_neighbors", 1, 20)
|
|
62
|
+
weights = trial.suggest_categorical("weights", ["uniform", "distance"])
|
|
63
|
+
p = trial.suggest_int("p", 1, 2)
|
|
64
|
+
model = KNeighborsClassifier(n_neighbors=n_neighbors, weights=weights, p=p)
|
|
65
|
+
|
|
66
|
+
elif self.algorithm == "RandomForest":
|
|
67
|
+
n_estimators = trial.suggest_int("n_estimators", 10, 200)
|
|
68
|
+
max_depth = trial.suggest_int("max_depth", 2, 32, log=True)
|
|
69
|
+
min_samples_split = trial.suggest_int("min_samples_split", 2, 20)
|
|
70
|
+
min_samples_leaf = trial.suggest_int("min_samples_leaf", 1, 20)
|
|
71
|
+
model = RandomForestClassifier(n_estimators=n_estimators, max_depth=max_depth,
|
|
72
|
+
min_samples_split=min_samples_split, min_samples_leaf=min_samples_leaf,
|
|
73
|
+
random_state=self.random_state)
|
|
74
|
+
|
|
75
|
+
elif self.algorithm == "CatBoost":
|
|
76
|
+
learning_rate = trial.suggest_float("learning_rate", 1e-5, 1.0, log=True)
|
|
77
|
+
depth = trial.suggest_int("depth", 4, 10)
|
|
78
|
+
l2_leaf_reg = trial.suggest_float("l2_leaf_reg", 1e-5, 10.0, log=True)
|
|
79
|
+
model = CatBoostClassifier(learning_rate=learning_rate, depth=depth, l2_leaf_reg=l2_leaf_reg,
|
|
80
|
+
verbose=0, random_state=self.random_state)
|
|
81
|
+
|
|
82
|
+
elif self.algorithm == "XGBoost":
|
|
83
|
+
eta = trial.suggest_float("eta", 1e-5, 1.0, log=True)
|
|
84
|
+
max_depth = trial.suggest_int("max_depth", 2, 32)
|
|
85
|
+
subsample = trial.suggest_float("subsample", 0.5, 1.0)
|
|
86
|
+
colsample_bytree = trial.suggest_float("colsample_bytree", 0.5, 1.0)
|
|
87
|
+
model = XGBClassifier(eta=eta, max_depth=max_depth, subsample=subsample,
|
|
88
|
+
colsample_bytree=colsample_bytree, random_state=self.random_state, use_label_encoder=False)
|
|
89
|
+
|
|
90
|
+
elif self.algorithm == "LogisticRegression":
|
|
91
|
+
C = trial.suggest_float("C", 1e-5, 1e2, log=True)
|
|
92
|
+
solver = trial.suggest_categorical("solver", ["liblinear", "saga", "lbfgs"])
|
|
93
|
+
model = LogisticRegression(C=C, solver=solver, random_state=self.random_state)
|
|
94
|
+
|
|
95
|
+
elif self.algorithm == "DecisionTree":
|
|
96
|
+
max_depth = trial.suggest_int("max_depth", 2, 32)
|
|
97
|
+
min_samples_split = trial.suggest_int("min_samples_split", 2, 20)
|
|
98
|
+
min_samples_leaf = trial.suggest_int("min_samples_leaf", 1, 20)
|
|
99
|
+
model = DecisionTreeClassifier(max_depth=max_depth, min_samples_split=min_samples_split,
|
|
100
|
+
min_samples_leaf=min_samples_leaf, random_state=self.random_state)
|
|
101
|
+
|
|
102
|
+
# Perform cross-validation and return the mean score
|
|
103
|
+
return cross_val_score(model, X, y, cv=self.cv, scoring=self.scoring).mean()
|
|
104
|
+
|
|
105
|
+
def fit(self, X, y):
|
|
106
|
+
"""Fit the chosen ML model with hyperparameter optimization"""
|
|
107
|
+
study = optuna.create_study(direction=self.direction, sampler=optuna.samplers.TPESampler(seed=self.random_state))
|
|
108
|
+
|
|
109
|
+
start_time = time.time()
|
|
110
|
+
study.optimize(lambda trial: self._objective(trial, X, y), n_trials=self.n_trials, timeout=self.timeout)
|
|
111
|
+
self.study_time_ = time.time() - start_time
|
|
112
|
+
|
|
113
|
+
self.best_params_ = study.best_params
|
|
114
|
+
|
|
115
|
+
# Choose the best estimator based on the algorithm
|
|
116
|
+
if self.algorithm == "SVM":
|
|
117
|
+
self.best_estimator_ = SVC(**self.best_params_, random_state=self.random_state, probability=True)
|
|
118
|
+
elif self.algorithm == "kNN":
|
|
119
|
+
self.best_estimator_ = KNeighborsClassifier(**self.best_params_)
|
|
120
|
+
elif self.algorithm == "RandomForest":
|
|
121
|
+
self.best_estimator_ = RandomForestClassifier(**self.best_params_, random_state=self.random_state)
|
|
122
|
+
elif self.algorithm == "CatBoost":
|
|
123
|
+
self.best_estimator_ = CatBoostClassifier(**self.best_params_, verbose=0, random_state=self.random_state)
|
|
124
|
+
elif self.algorithm == "XGBoost":
|
|
125
|
+
self.best_estimator_ = XGBClassifier(**self.best_params_, random_state=self.random_state, use_label_encoder=False)
|
|
126
|
+
elif self.algorithm == "LogisticRegression":
|
|
127
|
+
self.best_estimator_ = LogisticRegression(**self.best_params_, random_state=self.random_state)
|
|
128
|
+
elif self.algorithm == "DecisionTree":
|
|
129
|
+
self.best_estimator_ = DecisionTreeClassifier(**self.best_params_, random_state=self.random_state)
|
|
130
|
+
|
|
131
|
+
self.best_estimator_.fit(X, y)
|
|
132
|
+
|
|
133
|
+
return self
|
|
134
|
+
|
|
135
|
+
def predict(self, X):
|
|
136
|
+
"""Make predictions using the best estimator"""
|
|
137
|
+
return self.best_estimator_.predict(X)
|
|
138
|
+
|
|
139
|
+
def predict_proba(self, X):
|
|
140
|
+
"""Predict class probabilities using the best estimator."""
|
|
141
|
+
if hasattr(self.best_estimator_, "predict_proba"):
|
|
142
|
+
return self.best_estimator_.predict_proba(X)
|
|
143
|
+
else:
|
|
144
|
+
raise AttributeError("This model does not support probability estimates.")
|
|
145
|
+
|
|
146
|
+
def score(self, X, y):
|
|
147
|
+
"""Return the score of the model on the test data based on the selected scoring method"""
|
|
148
|
+
return self.best_estimator_.score(X, y)
|
|
149
|
+
|
|
150
|
+
def optimization_time(self):
|
|
151
|
+
"""Return the time taken for the optimization process"""
|
|
152
|
+
return self.study_time_
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: optuml
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Hyperparameter optimization for multiple machine learning algorithms using Optuna, with Scikit-learn API
|
|
5
|
+
Home-page: https://github.com/filipsPL/optuml
|
|
6
|
+
Author: Filip S.
|
|
7
|
+
Author-email: filip.ursynow@gmail.com
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Requires-Python: >=3.6
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Requires-Dist: optuna
|
|
15
|
+
Requires-Dist: scikit-learn
|
|
16
|
+
Requires-Dist: catboost
|
|
17
|
+
Requires-Dist: xgboost
|
|
18
|
+
Requires-Dist: numpy
|
|
19
|
+
|
|
20
|
+
# OptuML: Hyperparameter Optimization for Multiple Machine Learning Algorithms using Optuna
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
⣰⡁ ⡀⣀ ⢀⡀ ⣀⣀ ⡎⢱ ⣀⡀ ⣰⡀ ⡀⢀ ⡷⢾ ⡇ ⠄ ⣀⣀ ⣀⡀ ⢀⡀ ⡀⣀ ⣰⡀ ⡎⢱ ⣀⡀ ⣰⡀ ⠄ ⣀⣀ ⠄ ⣀⣀ ⢀⡀ ⡀⣀
|
|
24
|
+
⢸ ⠏ ⠣⠜ ⠇⠇⠇ ⠣⠜ ⡧⠜ ⠘⠤ ⠣⠼ ⠇⠸ ⠧⠤ ⠇ ⠇⠇⠇ ⡧⠜ ⠣⠜ ⠏ ⠘⠤ ⠣⠜ ⡧⠜ ⠘⠤ ⠇ ⠇⠇⠇ ⠇ ⠴⠥ ⠣⠭ ⠏
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`OptuML` is a Python module that provides hyperparameter optimization for several machine learning algorithms using the [Optuna](https://optuna.org/) framework. The module supports a variety of algorithms and allows easy hyperparameter tuning through a scikit-learn-like API.
|
|
28
|
+
|
|
29
|
+
[](https://github.com/filipsPL/optuml/actions/workflows/python-package.yml)
|
|
30
|
+
|
|
31
|
+
- [OptuML: Hyperparameter Optimization for Multiple Machine Learning Algorithms using Optuna](#optuml-hyperparameter-optimization-for-multiple-machine-learning-algorithms-using-optuna)
|
|
32
|
+
- [Quick start](#quick-start)
|
|
33
|
+
- [Features](#features)
|
|
34
|
+
- [Installation](#installation)
|
|
35
|
+
- [Prerequisites](#prerequisites)
|
|
36
|
+
- [Installation](#installation-1)
|
|
37
|
+
- [Usage](#usage)
|
|
38
|
+
- [Basic Example](#basic-example)
|
|
39
|
+
- [Available Algorithms](#available-algorithms)
|
|
40
|
+
- [Example of Optimizing Different Algorithms](#example-of-optimizing-different-algorithms)
|
|
41
|
+
- [Custom Scoring and Direction](#custom-scoring-and-direction)
|
|
42
|
+
- [Controlling Verbosity](#controlling-verbosity)
|
|
43
|
+
- [API Reference](#api-reference)
|
|
44
|
+
- [`Optimizer`](#optimizer)
|
|
45
|
+
- [Parameters:](#parameters)
|
|
46
|
+
- [Methods:](#methods)
|
|
47
|
+
- [Contributing](#contributing)
|
|
48
|
+
- [Running Tests](#running-tests)
|
|
49
|
+
- [Contact](#contact)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## Quick start
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
from OptuML import Optimizer
|
|
56
|
+
|
|
57
|
+
# Instantiate the optimizer for SVM
|
|
58
|
+
optimizer = Optimizer(algorithm="SVM", n_trials=50, cv=3, scoring="accuracy", verbose=True)
|
|
59
|
+
|
|
60
|
+
# Fit the optimizer to the training data
|
|
61
|
+
optimizer.fit(X_train, y_train)
|
|
62
|
+
|
|
63
|
+
# Predict on the test set
|
|
64
|
+
y_pred = optimizer.predict(X_test)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
## Features
|
|
69
|
+
|
|
70
|
+
- **Multiple Algorithms**: Supports hyperparameter optimization for the following algorithms:
|
|
71
|
+
- Support Vector Machine (SVM)
|
|
72
|
+
- k-Nearest Neighbors (kNN)
|
|
73
|
+
- Random Forest
|
|
74
|
+
- CatBoost
|
|
75
|
+
- XGBoost
|
|
76
|
+
- Logistic Regression
|
|
77
|
+
- Decision Tree
|
|
78
|
+
- **Optuna Framework**: Leverages Optuna for powerful hyperparameter search.
|
|
79
|
+
- **Maximize or Minimize**: Allows setting the optimization direction (`maximize` or `minimize`).
|
|
80
|
+
- **Scikit-learn API**: Provides a consistent interface for `fit()`, `predict()`, `predict_proba()`, and `score()` methods.
|
|
81
|
+
- **Control Output**: Optionally run Optuna with verbose logging (`verbose=True`) or in silent mode (`verbose=False`).
|
|
82
|
+
- **Cross-validation**: Easily integrate cross-validation with custom scoring metrics (e.g., accuracy, ROC AUC).
|
|
83
|
+
|
|
84
|
+
## Installation
|
|
85
|
+
|
|
86
|
+
### Prerequisites
|
|
87
|
+
|
|
88
|
+
Ensure that the following Python packages are installed:
|
|
89
|
+
|
|
90
|
+
- `optuna`
|
|
91
|
+
- `scikit-learn`
|
|
92
|
+
- `catboost`
|
|
93
|
+
- `xgboost`
|
|
94
|
+
- `numpy`
|
|
95
|
+
|
|
96
|
+
You can install the required packages via `pip`:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pip install optuna scikit-learn catboost xgboost numpy
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Installation
|
|
103
|
+
|
|
104
|
+
Just fetch the `optuml.py` [file from the repo](optuml.py) and put it in the directory with your script.
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
## Usage
|
|
108
|
+
|
|
109
|
+
### Basic Example
|
|
110
|
+
|
|
111
|
+
Here’s how you can use the `Optimizer` class to optimize hyperparameters for different machine learning algorithms using the **Iris** dataset:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from sklearn.datasets import load_iris
|
|
115
|
+
from sklearn.model_selection import train_test_split
|
|
116
|
+
from sklearn.metrics import accuracy_score
|
|
117
|
+
from OptuML import Optimizer
|
|
118
|
+
|
|
119
|
+
# Load the Iris dataset
|
|
120
|
+
X, y = load_iris(return_X_y=True)
|
|
121
|
+
|
|
122
|
+
# Convert to a binary classification problem
|
|
123
|
+
X = X[y != 2]
|
|
124
|
+
y = y[y != 2]
|
|
125
|
+
|
|
126
|
+
# Split the dataset into training and test sets
|
|
127
|
+
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
|
|
128
|
+
|
|
129
|
+
# Instantiate the optimizer for SVM
|
|
130
|
+
optimizer = Optimizer(algorithm="SVM", n_trials=50, cv=3, scoring="accuracy", verbose=True, random_state=42)
|
|
131
|
+
|
|
132
|
+
# Fit the optimizer to the training data
|
|
133
|
+
optimizer.fit(X_train, y_train)
|
|
134
|
+
|
|
135
|
+
# Predict on the test set
|
|
136
|
+
y_pred = optimizer.predict(X_test)
|
|
137
|
+
|
|
138
|
+
# Calculate the accuracy
|
|
139
|
+
accuracy = accuracy_score(y_test, y_pred)
|
|
140
|
+
print(f"Accuracy: {accuracy}")
|
|
141
|
+
|
|
142
|
+
# Print the best hyperparameters found during optimization
|
|
143
|
+
print(f"Best Hyperparameters: {optimizer.best_params_}")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Available Algorithms
|
|
147
|
+
|
|
148
|
+
The `Optimizer` class supports the following algorithms. You can specify the `algorithm` parameter to choose which one to use:
|
|
149
|
+
|
|
150
|
+
- `"SVM"` (Support Vector Machine)
|
|
151
|
+
- `"kNN"` (k-Nearest Neighbors)
|
|
152
|
+
- `"RandomForest"` (Random Forest)
|
|
153
|
+
- `"CatBoost"` (CatBoost Classifier)
|
|
154
|
+
- `"XGBoost"` (XGBoost Classifier)
|
|
155
|
+
- `"LogisticRegression"` (Logistic Regression)
|
|
156
|
+
- `"DecisionTree"` (Decision Tree Classifier)
|
|
157
|
+
|
|
158
|
+
### Example of Optimizing Different Algorithms
|
|
159
|
+
|
|
160
|
+
You can iterate over different algorithms and optimize hyperparameters for each one:
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
algorithms = ['SVM', 'kNN', 'RandomForest', 'CatBoost', 'XGBoost', 'LogisticRegression', 'DecisionTree']
|
|
164
|
+
|
|
165
|
+
for algorithm in algorithms:
|
|
166
|
+
print(f"Optimizing {algorithm}")
|
|
167
|
+
optimizer = Optimizer(algorithm=algorithm, n_trials=50, cv=3, scoring="accuracy", verbose=False, random_state=42)
|
|
168
|
+
optimizer.fit(X_train, y_train)
|
|
169
|
+
|
|
170
|
+
# Predict and calculate accuracy
|
|
171
|
+
y_pred = optimizer.predict(X_test)
|
|
172
|
+
accuracy = accuracy_score(y_test, y_pred)
|
|
173
|
+
print(f"Accuracy for {algorithm}: {accuracy}")
|
|
174
|
+
print(f"Best Hyperparameters for {algorithm}: {optimizer.best_params_}")
|
|
175
|
+
print("="*60)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Custom Scoring and Direction
|
|
179
|
+
|
|
180
|
+
You can also optimize for different scoring metrics like ROC AUC or use the `direction` parameter to **minimize** or **maximize** the objective:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
# Instantiate the optimizer for RandomForest with ROC AUC optimization
|
|
184
|
+
optimizer = Optimizer(algorithm="RandomForest", n_trials=50, cv=3, scoring="roc_auc", direction="maximize", verbose=True, random_state=42)
|
|
185
|
+
|
|
186
|
+
# Fit the optimizer to the training data
|
|
187
|
+
optimizer.fit(X_train, y_train)
|
|
188
|
+
|
|
189
|
+
# Predict probabilities and calculate ROC AUC
|
|
190
|
+
y_proba = optimizer.predict_proba(X_test)
|
|
191
|
+
roc_auc = roc_auc_score(y_test, y_proba[:, 1])
|
|
192
|
+
print(f"ROC AUC: {roc_auc}")
|
|
193
|
+
|
|
194
|
+
# Print the best hyperparameters
|
|
195
|
+
print(f"Best Hyperparameters: {optimizer.best_params_}")
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Controlling Verbosity
|
|
199
|
+
|
|
200
|
+
You can control the verbosity of Optuna's output by using the `verbose` parameter:
|
|
201
|
+
|
|
202
|
+
- Set `verbose=True` to enable detailed Optuna logging.
|
|
203
|
+
- Set `verbose=False` to suppress logging and run the optimizer silently.
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
optimizer = Optimizer(algorithm="SVM", n_trials=50, cv=3, scoring="accuracy", verbose=True, random_state=42)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## API Reference
|
|
210
|
+
|
|
211
|
+
### `Optimizer`
|
|
212
|
+
|
|
213
|
+
#### Parameters:
|
|
214
|
+
|
|
215
|
+
- **`algorithm`** (`str`): The machine learning algorithm to optimize. Options are `'SVM'`, `'kNN'`, `'RandomForest'`, `'CatBoost'`, `'XGBoost'`, `'LogisticRegression'`, `'DecisionTree'`.
|
|
216
|
+
- **`direction`** (`str`, default `"maximize"`): Direction of optimization. Can be `"maximize"` or `"minimize"`.
|
|
217
|
+
- **`verbose`** (`bool`, default `False`): If `True`, Optuna logging will be enabled. If `False`, the optimizer will run silently.
|
|
218
|
+
- **`n_trials`** (`int`, default `100`): Number of optimization trials to run.
|
|
219
|
+
- **`timeout`** (`float`, optional): Maximum time (in seconds) for the optimization process.
|
|
220
|
+
- **`cv`** (`int`, default `5`): Number of cross-validation folds.
|
|
221
|
+
- **`scoring`** (`str`, default `"accuracy"`): Scoring metric to use during cross-validation.
|
|
222
|
+
- **`random_state`** (`int`, optional): Seed for random number generation.
|
|
223
|
+
|
|
224
|
+
#### Methods:
|
|
225
|
+
|
|
226
|
+
- **`fit(X, y)`**: Fit the model using hyperparameter optimization.
|
|
227
|
+
- **`predict(X)`**: Make predictions using the best model found during optimization.
|
|
228
|
+
- **`predict_proba(X)`**: Predict class probabilities (if supported by the model).
|
|
229
|
+
- **`score(X, y)`**: Score the model using the test data.
|
|
230
|
+
- **`optimization_time()`**: Get the total time taken for optimization.
|
|
231
|
+
|
|
232
|
+
## Contributing
|
|
233
|
+
|
|
234
|
+
Contributions to the project are welcome! Please feel free to submit issues or pull requests on GitHub. You can also fork the repository and make your changes.
|
|
235
|
+
|
|
236
|
+
## Running Tests
|
|
237
|
+
|
|
238
|
+
You can run unit tests using `pytest`:
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
pip install pytest
|
|
242
|
+
pytest
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Contact
|
|
246
|
+
|
|
247
|
+
If you have any questions or feedback, feel free to open an issue on GitHub.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
optimum/__init__.py
|
|
6
|
+
optimum/optuml.py
|
|
7
|
+
optuml.egg-info/PKG-INFO
|
|
8
|
+
optuml.egg-info/SOURCES.txt
|
|
9
|
+
optuml.egg-info/dependency_links.txt
|
|
10
|
+
optuml.egg-info/requires.txt
|
|
11
|
+
optuml.egg-info/top_level.txt
|
|
12
|
+
tests/__init__.py
|
|
13
|
+
tests/test_optimizer.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
optuml-0.1.0/setup.cfg
ADDED
optuml-0.1.0/setup.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="optuml", # The name of your package on PyPI
|
|
8
|
+
version="0.1.0", # Start with 0.1.0 for the initial release
|
|
9
|
+
author="Filip S.",
|
|
10
|
+
author_email="filip.ursynow@gmail.com",
|
|
11
|
+
description="Hyperparameter optimization for multiple machine learning algorithms using Optuna, with Scikit-learn API",
|
|
12
|
+
long_description=long_description,
|
|
13
|
+
long_description_content_type="text/markdown",
|
|
14
|
+
url="https://github.com/filipsPL/optuml", # URL to the package's homepage (e.g., GitHub)
|
|
15
|
+
packages=find_packages(),
|
|
16
|
+
classifiers=[
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
],
|
|
21
|
+
python_requires=">=3.6",
|
|
22
|
+
install_requires=[
|
|
23
|
+
"optuna",
|
|
24
|
+
"scikit-learn",
|
|
25
|
+
"catboost",
|
|
26
|
+
"xgboost",
|
|
27
|
+
"numpy"
|
|
28
|
+
],
|
|
29
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from sklearn.datasets import make_classification
|
|
3
|
+
from sklearn.model_selection import train_test_split
|
|
4
|
+
from sklearn.metrics import accuracy_score, roc_auc_score
|
|
5
|
+
from optuml import Optimizer
|
|
6
|
+
|
|
7
|
+
@pytest.fixture
|
|
8
|
+
def binary_classification_data():
|
|
9
|
+
"""Generate a synthetic binary classification dataset."""
|
|
10
|
+
X, y = make_classification(n_samples=300, n_features=5, n_classes=2, random_state=42)
|
|
11
|
+
return train_test_split(X, y, test_size=0.3, random_state=42)
|
|
12
|
+
|
|
13
|
+
@pytest.mark.parametrize("algorithm", ['SVM', 'kNN', 'RandomForest', 'CatBoost', 'XGBoost', 'LogisticRegression', 'DecisionTree'])
|
|
14
|
+
def test_optimizer_accuracy(binary_classification_data, algorithm):
|
|
15
|
+
"""Test accuracy optimization for each supported algorithm."""
|
|
16
|
+
X_train, X_test, y_train, y_test = binary_classification_data
|
|
17
|
+
|
|
18
|
+
# Initialize Optimizer with accuracy optimization
|
|
19
|
+
optimizer = Optimizer(algorithm=algorithm, direction="maximize", verbose=False, n_trials=10, cv=3, scoring="accuracy", random_state=42)
|
|
20
|
+
|
|
21
|
+
# Fit the model
|
|
22
|
+
optimizer.fit(X_train, y_train)
|
|
23
|
+
|
|
24
|
+
# Predict and calculate accuracy
|
|
25
|
+
y_pred = optimizer.predict(X_test)
|
|
26
|
+
accuracy = accuracy_score(y_test, y_pred)
|
|
27
|
+
|
|
28
|
+
# Ensure that accuracy is above a reasonable threshold (e.g., 0.7 for this dataset)
|
|
29
|
+
assert accuracy > 0.7, f"Accuracy for {algorithm} is too low: {accuracy}"
|
|
30
|
+
|
|
31
|
+
# Check if best_params_ is populated
|
|
32
|
+
assert optimizer.best_params_ is not None, f"Best parameters for {algorithm} were not found"
|
|
33
|
+
|
|
34
|
+
# Check if optimization time was recorded
|
|
35
|
+
assert optimizer.optimization_time() > 0, f"Optimization time was not recorded for {algorithm}"
|
|
36
|
+
|
|
37
|
+
@pytest.mark.parametrize("algorithm", ['SVM', 'RandomForest', 'CatBoost', 'XGBoost'])
|
|
38
|
+
def test_optimizer_roc_auc(binary_classification_data, algorithm):
|
|
39
|
+
"""Test ROC AUC optimization for selected algorithms that support predict_proba."""
|
|
40
|
+
X_train, X_test, y_train, y_test = binary_classification_data
|
|
41
|
+
|
|
42
|
+
# Initialize Optimizer with ROC AUC optimization
|
|
43
|
+
optimizer = Optimizer(algorithm=algorithm, direction="maximize", verbose=False, n_trials=10, cv=3, scoring="roc_auc", random_state=42)
|
|
44
|
+
|
|
45
|
+
# Fit the model
|
|
46
|
+
optimizer.fit(X_train, y_train)
|
|
47
|
+
|
|
48
|
+
# Predict probabilities and calculate ROC AUC
|
|
49
|
+
y_proba = optimizer.predict_proba(X_test)
|
|
50
|
+
roc_auc = roc_auc_score(y_test, y_proba[:, 1])
|
|
51
|
+
|
|
52
|
+
# Ensure that ROC AUC is above a reasonable threshold (e.g., 0.7 for this dataset)
|
|
53
|
+
assert roc_auc > 0.7, f"ROC AUC for {algorithm} is too low: {roc_auc}"
|
|
54
|
+
|
|
55
|
+
# Check if best_params_ is populated
|
|
56
|
+
assert optimizer.best_params_ is not None, f"Best parameters for {algorithm} were not found"
|
|
57
|
+
|
|
58
|
+
# Check if optimization time was recorded
|
|
59
|
+
assert optimizer.optimization_time() > 0, f"Optimization time was not recorded for {algorithm}"
|
|
60
|
+
|
|
61
|
+
def test_optimizer_direction_minimize(binary_classification_data):
|
|
62
|
+
"""Test the 'minimize' direction in the optimizer for accuracy."""
|
|
63
|
+
X_train, X_test, y_train, y_test = binary_classification_data
|
|
64
|
+
|
|
65
|
+
# Initialize Optimizer to minimize accuracy (artificial test, not practical)
|
|
66
|
+
optimizer = Optimizer(algorithm="SVM", direction="minimize", verbose=False, n_trials=10, cv=3, scoring="accuracy", random_state=42)
|
|
67
|
+
|
|
68
|
+
# Fit the model
|
|
69
|
+
optimizer.fit(X_train, y_train)
|
|
70
|
+
|
|
71
|
+
# Predict and calculate accuracy
|
|
72
|
+
y_pred = optimizer.predict(X_test)
|
|
73
|
+
accuracy = accuracy_score(y_test, y_pred)
|
|
74
|
+
|
|
75
|
+
# Check that the minimization didn't yield absurdly high accuracy (should be reasonable)
|
|
76
|
+
assert accuracy < 1.0, f"Minimization should not result in perfect accuracy: {accuracy}"
|
|
77
|
+
|
|
78
|
+
# def test_optimizer_verbose_flag(binary_classification_data, capsys):
|
|
79
|
+
# """Test that verbose flag controls Optuna logging output."""
|
|
80
|
+
# X_train, X_test, y_train, y_test = binary_classification_data
|
|
81
|
+
|
|
82
|
+
# # Initialize Optimizer with verbose=True
|
|
83
|
+
# optimizer = Optimizer(algorithm="SVM", direction="maximize", verbose=True, n_trials=5, cv=3, scoring="accuracy", random_state=42)
|
|
84
|
+
|
|
85
|
+
# # Fit the model
|
|
86
|
+
# optimizer.fit(X_train, y_train)
|
|
87
|
+
|
|
88
|
+
# # Capture the stdout output
|
|
89
|
+
# captured = capsys.readouterr()
|
|
90
|
+
|
|
91
|
+
# # Check that the output contains Optuna log info (verbose=True should produce output)
|
|
92
|
+
# assert "Trial" in captured.out, "Verbose output should include trial information but it was missing."
|
|
93
|
+
|
|
94
|
+
# def test_optimizer_silent_mode(binary_classification_data, capsys):
|
|
95
|
+
# """Test that the optimizer runs silently when verbose=False."""
|
|
96
|
+
# X_train, X_test, y_train, y_test = binary_classification_data
|
|
97
|
+
|
|
98
|
+
# # Initialize Optimizer with verbose=False
|
|
99
|
+
# optimizer = Optimizer(algorithm="SVM", direction="maximize", verbose=False, n_trials=5, cv=3, scoring="accuracy", random_state=42)
|
|
100
|
+
|
|
101
|
+
# # Fit the model
|
|
102
|
+
# optimizer.fit(X_train, y_train)
|
|
103
|
+
|
|
104
|
+
# # Capture the stdout output
|
|
105
|
+
# captured = capsys.readouterr()
|
|
106
|
+
|
|
107
|
+
# # Check that the output does not contain Optuna log info (verbose=False should produce no output)
|
|
108
|
+
# assert "Trial" not in captured.out, "Verbose output should be suppressed but it was displayed."
|