Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ jobs:
uv run pytest benchmarks/ \
--benchmark-only \
--benchmark-json pytest-benchmark-sample.json \
--benchmark-time-unit=s \
--no-cov

- name: Upload benchmark artifact
Expand Down
31 changes: 30 additions & 1 deletion examples/README.rst
Original file line number Diff line number Diff line change
@@ -1,2 +1,31 @@
A few examples with significant test cases
that show how to use the orbital library.
that show how to use the orbital library.

scikit-learn (``pipeline_*.py``)
---------------------------------

- ``pipeline_lineareg.py`` -- Linear Regression
- ``pipeline_logisticreg.py`` -- multiclass Logistic Regression
- ``pipeline_lasso.py`` -- Lasso Regression
- ``pipeline_elasticnet.py`` -- Elastic Net Regression
- ``pipeline_decision_tree_classifier.py`` -- Decision Tree Classifier
- ``pipeline_decision_tree_regressor.py`` -- Decision Tree Regressor
- ``pipeline_randforest_classifier.py`` -- Random Forest Classifier
- ``pipeline_boosted_tree_classifier.py`` -- Gradient Boosted Tree multiclass Classifier
- ``pipeline_boosted_tree_binary_classifier.py`` -- Gradient Boosted Tree binary Classifier
- ``pipeline_boosted_tree_regressor.py`` -- Gradient Boosted Tree Regressor
- ``pipeline_mlp_classifier.py`` -- MLP binary Classifier (``MLPClassifier``)
- ``pipeline_mlp_regressor.py`` -- MLP Regressor (``MLPRegressor``, ``tanh`` activation)

PyTorch (``pytorch_*.py``)
---------------------------

- ``pytorch_fraud_detector.py`` -- binary classification (fraud detection)
- ``pytorch_maintenance_classifier.py`` -- multiclass classification (predictive maintenance)
- ``pytorch_demand_regressor.py`` -- regression (demand forecasting)

Other
-----

- ``minimal.py`` -- smallest possible pipeline
- ``simple_tree_regressor.py`` -- Decision Tree Regressor without ibis
17 changes: 11 additions & 6 deletions examples/pipeline_boosted_tree_binary_classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

PRINT_SQL = int(os.environ.get("PRINT_SQL", "0"))
ASSERT = int(os.environ.get("ASSERT", "0"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1")) or ASSERT
BACKEND = os.environ.get("BACKEND", "duckdb").lower()

if BACKEND not in {"duckdb", "sqlite"}:
Expand Down Expand Up @@ -99,11 +99,18 @@ def categorize_price_binary(price: float) -> str:
con.create_table("DATA_TABLE", obj=data_sample)


def main():
# Convert the model to an execution pipeline
def translate_to_orbital():
orbital_pipeline = orbital.parse_pipeline(model, features=features)
print(orbital_pipeline)
ibis_table = ibis.memtable(data_sample).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
return orbital_pipeline, ibis_expression


orbital_pipeline, ibis_expression = translate_to_orbital()


def main():
if PRINT_SQL:
sql = orbital.export_sql("DATA_TABLE", orbital_pipeline, dialect=BACKEND)
print(f"\nGenerated Query for {BACKEND.upper()}:")
Expand All @@ -119,12 +126,10 @@ def main():
print(f"Probabilities: {sklearn_probabilities}")

print("\nPrediction with Ibis")
ibis_table = ibis.memtable(data_sample).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
ibis_result = con.execute(ibis_expression)
print(ibis_result)

if ASSERT and PREDICT_WITH_LIBRARY:
if ASSERT:
assert np.array_equal(sklearn_predictions, ibis_result["output_label"]), "Predictions do not match!"

# Binary classification should produce exactly 2 probability columns
Expand Down
23 changes: 17 additions & 6 deletions examples/pipeline_boosted_tree_classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

PRINT_SQL = int(os.environ.get("PRINT_SQL", "0"))
ASSERT = int(os.environ.get("ASSERT", "0"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1")) or ASSERT
BACKEND = os.environ.get("BACKEND", "duckdb").lower()

if BACKEND not in {"duckdb", "sqlite"}:
Expand Down Expand Up @@ -110,11 +110,24 @@ def categorize_price(price: float) -> str:
con.create_table("DATA_TABLE", obj=data_sample)


def main():
# Convert the model to an execution pipeline
def translate_to_orbital():
orbital_pipeline = orbital.parse_pipeline(model, features=features)
print(orbital_pipeline)
ibis_table = ibis.memtable(data_sample).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
return orbital_pipeline, ibis_expression


# Sqlite can't execute this query (see the FIXME in main below); translate()
# alone already takes tens of seconds for this pipeline regardless of
# backend, so skip building it here too instead of paying that cost only
# to then skip execution in main().
orbital_pipeline = ibis_expression = None
if BACKEND != "sqlite":
orbital_pipeline, ibis_expression = translate_to_orbital()


def main():
if BACKEND == "sqlite":
# FIXME: Sqlite currently can't handle the boosted tree classifier SQL
print("Skipping sqlite as it can't handle the query")
Expand All @@ -134,12 +147,10 @@ def main():
print(target)

print("\nPrediction with Ibis")
ibis_table = ibis.memtable(data_sample).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
ibis_target = con.execute(ibis_expression)
print(ibis_target)

if ASSERT and PREDICT_WITH_LIBRARY:
if ASSERT:
assert np.array_equal(target, ibis_target["output_label"]), "Predictions do not match!"
print("\nPredictions match!")

Expand Down
16 changes: 11 additions & 5 deletions examples/pipeline_boosted_tree_regressor.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

PRINT_SQL = int(os.environ.get("PRINT_SQL", "0"))
ASSERT = int(os.environ.get("ASSERT", "0"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1")) or ASSERT
BACKEND = os.environ.get("BACKEND", "duckdb").lower()

if BACKEND not in {"duckdb", "sqlite"}:
Expand Down Expand Up @@ -100,10 +100,18 @@
con.create_table("DATA_TABLE", obj=data_sample)


def main():
def translate_to_orbital():
orbital_pipeline = orbital.parse_pipeline(model, features=features)
print(orbital_pipeline)
ibis_table = ibis.memtable(data_sample).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
return orbital_pipeline, ibis_expression


orbital_pipeline, ibis_expression = translate_to_orbital()


def main():
if PRINT_SQL:
sql = orbital.export_sql("DATA_TABLE", orbital_pipeline, dialect=BACKEND)
print(f"\nGenerated Query for {BACKEND.upper()}:")
Expand All @@ -117,12 +125,10 @@ def main():
print(target)

print("\nPrediction with Ibis")
ibis_table = ibis.memtable(data_sample).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
ibis_target = con.execute(ibis_expression)["variable"].to_numpy()
print(ibis_target)

if ASSERT and PREDICT_WITH_LIBRARY:
if ASSERT:
assert np.allclose(target, ibis_target), "Predictions do not match!"
print("\nPredictions match!")

Expand Down
20 changes: 13 additions & 7 deletions examples/pipeline_decision_tree_classifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

PRINT_SQL = int(os.environ.get("PRINT_SQL", "0"))
ASSERT = int(os.environ.get("ASSERT", "0"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1")) or ASSERT
BACKEND = os.environ.get("BACKEND", "duckdb").lower()

if BACKEND not in {"duckdb", "sqlite"}:
Expand Down Expand Up @@ -107,11 +107,19 @@ def categorize_area(a: float) -> str:
con.create_table("DATA_TABLE", obj=example_data)


def main():
print("orbital Features:", features)

def translate_to_orbital():
orbital_pipeline = orbital.parse_pipeline(pipeline, features=features)
print(orbital_pipeline)
ibis_table = ibis.memtable(example_data).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
return orbital_pipeline, ibis_expression


orbital_pipeline, ibis_expression = translate_to_orbital()


def main():
print("orbital Features:", features)

if PRINT_SQL:
sql = orbital.export_sql("DATA_TABLE", orbital_pipeline, dialect=BACKEND)
Expand All @@ -121,8 +129,6 @@ def main():
print(con.raw_sql(sql).fetchall())

print("\nPrediction with Ibis")
ibis_table = ibis.memtable(example_data).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
ibis_target = con.execute(ibis_expression)
print(ibis_target)

Expand All @@ -132,7 +138,7 @@ def main():
target = pipeline.predict(test_df)
print(target)

if ASSERT and PREDICT_WITH_LIBRARY:
if ASSERT:
assert np.array_equal(target, ibis_target["output_label"]), "Predictions do not match!"
print("\nPredictions match!")

Expand Down
21 changes: 13 additions & 8 deletions examples/pipeline_decision_tree_regressor.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

PRINT_SQL = int(os.environ.get("PRINT_SQL", "0"))
ASSERT = int(os.environ.get("ASSERT", "0"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1")) or ASSERT
BACKEND = os.environ.get("BACKEND", "duckdb").lower()

if BACKEND not in {"duckdb", "sqlite"}:
Expand Down Expand Up @@ -87,12 +87,19 @@
con.create_table("DATA_TABLE", obj=example_data)


def main():
print("orbital Features:", features)

# Convert the pipeline to SQL with Orbital
def translate_to_orbital():
orbital_pipeline = orbital.parse_pipeline(pipeline, features=features)
print(orbital_pipeline)
ibis_table = ibis.memtable(example_data).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
return orbital_pipeline, ibis_expression


orbital_pipeline, ibis_expression = translate_to_orbital()


def main():
print("orbital Features:", features)

if PRINT_SQL:
sql = orbital.export_sql("DATA_TABLE", orbital_pipeline, dialect=BACKEND)
Expand All @@ -108,12 +115,10 @@ def main():
print(target)

print("\nPrediction with Ibis")
ibis_table = ibis.memtable(example_data).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
ibis_target = con.execute(ibis_expression)["variable"].to_numpy()
print(ibis_target)

if ASSERT and PREDICT_WITH_LIBRARY:
if ASSERT:
assert np.allclose(target, ibis_target), "Predictions do not match!"
print("\nPredictions match!")

Expand Down
16 changes: 11 additions & 5 deletions examples/pipeline_elasticnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

PRINT_SQL = int(os.environ.get("PRINT_SQL", "0"))
ASSERT = int(os.environ.get("ASSERT", "0"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1")) or ASSERT
BACKEND = os.environ.get("BACKEND", "duckdb").lower()

if BACKEND not in {"duckdb", "sqlite"}:
Expand Down Expand Up @@ -68,10 +68,18 @@
con.create_table("DATA_TABLE", obj=example_data)


def main():
def translate_to_orbital():
orbital_pipeline = orbital.parse_pipeline(pipeline, features=features)
print(orbital_pipeline)
ibis_table = ibis.memtable(example_data).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
return orbital_pipeline, ibis_expression


orbital_pipeline, ibis_expression = translate_to_orbital()


def main():
if PRINT_SQL:
sql = orbital.export_sql("DATA_TABLE", orbital_pipeline, dialect=BACKEND)
print(f"\nGenerated Query for {BACKEND.upper()}:")
Expand All @@ -80,8 +88,6 @@ def main():
print(con.raw_sql(sql).fetchall())

print("\nPrediction with Ibis")
ibis_table = ibis.memtable(example_data).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
ibis_target = con.execute(ibis_expression)["variable"].to_numpy()
print(ibis_target)

Expand All @@ -90,7 +96,7 @@ def main():
target = pipeline.predict(example_data.to_pandas())
print(target)

if ASSERT and PREDICT_WITH_LIBRARY:
if ASSERT:
assert np.allclose(target, ibis_target), "Predictions do not match!"
print("\nPredictions match!")

Expand Down
16 changes: 11 additions & 5 deletions examples/pipeline_lasso.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

PRINT_SQL = int(os.environ.get("PRINT_SQL", "0"))
ASSERT = int(os.environ.get("ASSERT", "0"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1"))
PREDICT_WITH_LIBRARY = int(os.environ.get("PREDICT_WITH_LIBRARY", "1")) or ASSERT
BACKEND = os.environ.get("BACKEND", "duckdb").lower()

if BACKEND not in {"duckdb", "sqlite"}:
Expand Down Expand Up @@ -65,10 +65,18 @@
con.create_table("DATA_TABLE", obj=example_data)


def main():
def translate_to_orbital():
orbital_pipeline = orbital.parse_pipeline(pipeline, features=features)
print(orbital_pipeline)
ibis_table = ibis.memtable(example_data).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
return orbital_pipeline, ibis_expression


orbital_pipeline, ibis_expression = translate_to_orbital()


def main():
if PRINT_SQL:
sql = orbital.export_sql("DATA_TABLE", orbital_pipeline, dialect=BACKEND)
print(f"\nGenerated Query for {BACKEND.upper()}:")
Expand All @@ -77,8 +85,6 @@ def main():
print(con.raw_sql(sql).fetchall())

print("\nPrediction with Ibis")
ibis_table = ibis.memtable(example_data).alias("DATA_TABLE")
ibis_expression = orbital.translate(ibis_table, orbital_pipeline)
ibis_target = con.execute(ibis_expression)["variable"].to_numpy()
print(ibis_target)

Expand All @@ -87,7 +93,7 @@ def main():
target = pipeline.predict(example_data.to_pandas())
print(target)

if ASSERT and PREDICT_WITH_LIBRARY:
if ASSERT:
assert np.allclose(target, ibis_target), "Predictions do not match!"
print("\nPredictions match!")

Expand Down
Loading
Loading