Skip to content

Commit

Permalink
Merge pull request #97 from firefly-cpp/84-cli
Browse files Browse the repository at this point in the history
🧑‍💻added `niaaml` CLI
  • Loading branch information
firefly-cpp authored Jun 12, 2024
2 parents 62229b3 + f45afac commit 47de5bc
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 5 deletions.
Binary file added .github/images/niaaml_cli_help.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/images/niaaml_cli_infer_help.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/images/niaaml_cli_optimize_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<p align="center">
<a href="https://github.com/firefly-cpp/NiaAML?tab=readme-ov-file#-installation">📦 Installation</a> •
<a href="https://github.com/firefly-cpp/NiaAML?tab=readme-ov-file#-graphical-user-interface">💻 Graphical User Interface</a> •
<a href="https://github.com/firefly-cpp/NiaAML?tab=readme-ov-file#-command-line-interface">🧑‍💻 Command Line Interface</a> •
<a href="https://github.com/firefly-cpp/NiaAML?tab=readme-ov-file#-api">📮 API</a> •
<a href="https://github.com/firefly-cpp/NiaAML?tab=readme-ov-file#-implemented-components">✨ Implemented Components</a> •
<a href="https://github.com/firefly-cpp/NiaAML?tab=readme-ov-file#-optimization-process-and-parameter-tuning">💪 Optimization Process And Parameter Tuning</a> •
Expand Down Expand Up @@ -117,6 +118,22 @@ $ nix-shell -p python311Packages.niaaml

There is a simple Graphical User Interface for the NiaAML package available [here](https://github.com/lukapecnik/NiaAML-GUI).

## 🧑‍💻 Command Line Interface

We also provide a CLI for quick pipeline optimizations and inference from the terminal without the need to write custom scripts.

When you install the package as instructed above, you will already have access to the `niaaml` command with sub-commands `optimize` and `infer`

For usage information, add the `--help` flag:

![niaaml help](.github/images/niaaml_cli_help.png)

![niaaml infer help](.github/images/niaaml_cli_infer_help.png)

An example Invocation of `optimize`:

![niaaml optimize example](.github/images/niaaml_cli_optimize_example.png)

## 📮 API

There is a simple API for remote work with NiaAML package available [here](https://github.com/alenrajsp/NiaAML-API).
Expand Down
2 changes: 2 additions & 0 deletions niaaml/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from niaaml.pipeline import Pipeline
from niaaml.pipeline_component import PipelineComponent
from niaaml.logger import Logger
from niaaml import cli

__all__ = [
"classifiers",
Expand All @@ -26,6 +27,7 @@
"Pipeline",
"PipelineComponent",
"Logger",
"cli",
]

__project__ = "niaaml"
Expand Down
104 changes: 104 additions & 0 deletions niaaml/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"""🧑‍💻 command line interface for NiaAML"""

from pathlib import Path
from typing import Optional

from loguru import logger
import pandas as pd
import typer
from typing_extensions import Annotated

from niaaml import PipelineOptimizer, Pipeline
from niaaml.data.csv_data_reader import CSVDataReader


app = typer.Typer(
help="🌳 a command line interface for NiaAML.",
no_args_is_help=True
)


@app.command()
def optimize(
data_csv_file: Path,
has_header: bool = True,
ignore_columns: list[int] = [],
classifiers: list[str] = ['AdaBoost', 'Bagging', 'MultiLayerPerceptron', 'RandomForest', 'ExtremelyRandomizedTrees', 'LinearSVC'],
feature_selection_algorithms: list[str] = ['SelectKBest', 'SelectPercentile', 'ParticleSwarmOptimization', 'VarianceThreshold'],
feature_transform_algorithms: list[str] = ['Normalizer', 'StandardScaler'],
categorical_features_encoder: Annotated[Optional[str], typer.Option()] = "OneHotEncoder",
imputer: Annotated[Optional[str], typer.Option()] = None,
fitness_name: str = 'Accuracy',
pipeline_population_size: int = 15,
inner_population_size: int = 15,
number_of_pipeline_evaluations: int = 100,
number_of_inner_evaluations: int = 100,
optimization_algorithm: str = 'ParticleSwarmAlgorithm',
inner_optimization_algorithm: Annotated[Optional[str], typer.Option()] = None,
result_file: Path = Path("pipeline.ppln"),
) -> None:
"""🦾 optimizes a NiaAML pipeline on a given dataset."""
# 📄 load and setup data
logger.info(f"📄 reading `{data_csv_file}`")
data_reader = CSVDataReader(
src=str(data_csv_file),
has_header=has_header,
contains_classes=True,
ignore_columns=ignore_columns
)

# 🦾 setup pipeline
logger.info("🦾 start the optimization process ...")
pipeline_optimizer = PipelineOptimizer(
data=data_reader,
classifiers=classifiers,
feature_selection_algorithms=feature_selection_algorithms,
feature_transform_algorithms=feature_transform_algorithms,
categorical_features_encoder=categorical_features_encoder,
imputer=imputer,
)

# 📈 optimize pipeline
pipeline = pipeline_optimizer.run(fitness_name, pipeline_population_size, inner_population_size, number_of_pipeline_evaluations, number_of_inner_evaluations, optimization_algorithm, inner_optimization_algorithm)

# 💾 save pipeline
logger.success(f"💾 saving optimized pipeline to `{result_file}`")
pipeline.export(result_file)

@app.command()
def infer(
data_csv_file: Path,
has_header: bool = True,
ignore_columns: list[int] = [],
pipeline_file: Path = Path("pipeline.ppln"),
predictions_csv_file: Path = Path("preds.csv"),
) -> None:
"""🔮 use an optimized NiaAML pipeline to make predictions."""
# 💾 load pipeline
pipeline = Pipeline.load(pipeline_file)

# 📄 load and setup data
logger.info(f"📄 reading `{data_csv_file}`")
reader = CSVDataReader(
src=str(data_csv_file),
has_header=has_header,
contains_classes=True,
ignore_columns=ignore_columns
)
reader._read_data()
x: pd.DataFrame = reader._x

# 🔮 make predictions
logger.info(f"🔮 using `{pipeline_file}` to make predictions on the data")
x['preds'] = pipeline.run(x)

# 💾 save predictions
logger.success(f"💾 saving predictions to `{predictions_csv_file}`")
x.to_csv(predictions_csv_file)

def main():
"""🚪 typer entry point for the CLI."""
app()

if __name__ == "__main__":
main()
120 changes: 116 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "NiaAML"
version = "2.0.0"
version = "2.1.0"
description = "Python automated machine learning framework"
license = "MIT"
authors = ["Luka Pečnik <[email protected]>", "Iztok Fister Jr. <[email protected]>", "Laurenz Farthofer <[email protected]>"]
Expand All @@ -16,12 +16,17 @@ include = [
{ path="COMPONENTS.md", format="sdist" }
]

[tool.poetry.scripts]
niaaml = "niaaml.cli:main"

[tool.poetry.dependencies]
python = "^3.9"
numpy = "^1.19.1"
scikit-learn = "^1.1.2"
niapy = "^2.0.5"
pandas = "^2.1.1"
typer = "^0.12.3"
loguru = "^0.7.2"

[tool.poetry.dev-dependencies]
sphinx = "^3.3.1"
Expand Down

0 comments on commit 47de5bc

Please sign in to comment.