{ "cells": [ { "cell_type": "markdown", "id": "eb5834d3-94b4-468d-803e-0b008c10ac29", "metadata": {}, "source": [ "# Using Featuristic With scikit-learn Pipelines\n", "\n", "Featuristic is compatible with scikit-learn's powerful `Pipeline` class. This functionality allows you to organize and apply a sequence of data processing steps effortlessly within scikit-learn. With the `Pipeline`, you can chain together various transformers provided by Featuristic or other scikit-learn-compatible libraries. \n", "\n", "These transformers can include feature generation, feature selection, data scaling, and any other preprocessing steps required to prepare your data for modeling.\n", "\n", "By leveraging the `Pipeline` class in conjunction with Featuristic, you can streamline your data preprocessing workflow, ensuring consistency and reproducibility. This allows you to construct complex data processing pipelines with ease, and combine Featuristic with model development.\n", "\n", "Let's take a look at a simple example using the `cars` dataset." ] }, { "cell_type": "code", "execution_count": 1, "id": "bb06d8de-d1e2-4ad0-b386-3c287589a09d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.0.1\n" ] } ], "source": [ "from sklearn.linear_model import LinearRegression\n", "from sklearn.model_selection import cross_val_score, train_test_split\n", "from sklearn.pipeline import Pipeline\n", "import featuristic as ft\n", "import numpy as np\n", "\n", "np.random.seed(8888)\n", "\n", "print(ft.__version__)" ] }, { "cell_type": "markdown", "id": "2cad1914-1776-485b-b1a6-5dc3c78ce993", "metadata": {}, "source": [ "### Load the Data" ] }, { "cell_type": "code", "execution_count": 2, "id": "e8ddeb97-7128-4bc8-a265-d62bbde070cc", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
displacementcylindershorsepowerweightaccelerationmodel_yearorigin
0307.08130.0350412.0701
1350.08165.0369311.5701
2318.08150.0343611.0701
3304.08150.0343312.0701
4302.08140.0344910.5701
\n", "
" ], "text/plain": [ " displacement cylinders horsepower weight acceleration model_year \\\n", "0 307.0 8 130.0 3504 12.0 70 \n", "1 350.0 8 165.0 3693 11.5 70 \n", "2 318.0 8 150.0 3436 11.0 70 \n", "3 304.0 8 150.0 3433 12.0 70 \n", "4 302.0 8 140.0 3449 10.5 70 \n", "\n", " origin \n", "0 1 \n", "1 1 \n", "2 1 \n", "3 1 \n", "4 1 " ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X, y = ft.fetch_cars_dataset()\n", "\n", "X.head()" ] }, { "cell_type": "code", "execution_count": 3, "id": "c1cf8c11-05a1-4e35-aee5-459607855ac1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 18.0\n", "1 15.0\n", "2 18.0\n", "3 16.0\n", "4 17.0\n", "Name: mpg, dtype: float64" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y.head()" ] }, { "cell_type": "markdown", "id": "1e31d83a-5ed1-4e38-bc5a-663609f142fe", "metadata": {}, "source": [ "### Split the Data in Train and Test" ] }, { "cell_type": "code", "execution_count": 4, "id": "8b4eeb07-c15f-407f-99d6-de7c82c028da", "metadata": {}, "outputs": [], "source": [ "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)" ] }, { "cell_type": "markdown", "id": "d33849ff-567d-41aa-a97a-f0431bb14839", "metadata": {}, "source": [ "### Objective Function\n", "\n", "We define a custom objective function to pass into the Genetic Feature Selection algorithm. The output of this will be minimized to find the optimal subset of features." ] }, { "cell_type": "code", "execution_count": 5, "id": "6704f5e5-9d26-4be6-8ef4-5d2df3068bf0", "metadata": {}, "outputs": [], "source": [ "def objective(X, y):\n", " model = LinearRegression()\n", " scores = cross_val_score(model, X, y, cv=3, scoring=\"neg_mean_absolute_error\")\n", " return -scores.mean()" ] }, { "cell_type": "markdown", "id": "add0e65f-8b04-4799-afd4-4947a293a772", "metadata": {}, "source": [ "### Fit a scikit-learn Pipeline Containing Featuristic" ] }, { "cell_type": "code", "execution_count": 6, "id": "8846e305-9321-4387-b1bf-a4fe94b11428", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Creating new features...: 74%|███████████▊ | 74/100 [00:15<00:05, 4.75it/s]\n", "Pruning feature space...: 100%|██████████████████| 5/5 [00:00<00:00, 498.46it/s]\u001b[A\n", "Creating new features...: 74%|███████████▊ | 74/100 [00:15<00:05, 4.74it/s]\n", "Optimising feature selection...: 52%|█████▏ | 26/50 [00:05<00:05, 4.39it/s]\n" ] } ], "source": [ "pipe = Pipeline(\n", " steps=[\n", " (\n", " \"genetic_feature_synthesis\",\n", " ft.GeneticFeatureSynthesis(\n", " num_features=5,\n", " population_size=200,\n", " max_generations=100,\n", " early_termination_iters=25,\n", " parsimony_coefficient=0.035,\n", " n_jobs=1,\n", " ),\n", " ),\n", " (\n", " \"genetic_feature_selector\",\n", " ft.GeneticFeatureSelector(\n", " objective,\n", " population_size=200,\n", " max_generations=50,\n", " early_termination_iters=25,\n", " n_jobs=-1,\n", " ),\n", " ),\n", " (\n", " \"model\",\n", " LinearRegression()\n", " )\n", " ]\n", ")\n", "\n", "model = pipe.fit(X_train, y_train)" ] }, { "cell_type": "code", "execution_count": 7, "id": "ba1ced6a-4c28-455e-8729-4a42cb08bc55", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([13.23930437, 35.40219719, 27.26035025, 26.25423477, 28.24773002,\n", " 19.10148319, 36.15024042, 23.33185658, 31.19121816, 22.29169501])" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "preds = model.predict(X_test)\n", "\n", "preds[:10]" ] }, { "cell_type": "markdown", "id": "946e4317-dc65-471c-8019-7b12444227a5", "metadata": {}, "source": [ "## Accessing Featuristic Inside the Pipeline\n", "\n", "We can still access the individual Featuristic steps via the pipeline's `named_steps` functionality. For example, to look at the formulas used for the feature engineering or to plot the genetic algorithm's history." ] }, { "cell_type": "code", "execution_count": 8, "id": "0661e5aa-2efb-4fd7-9624-15314c5a21a4", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nameformulafitness
0feature_1abs(abs(abs((abs(abs(abs(abs(abs(abs(abs(abs(a...-0.874683
1feature_8abs(abs(((cos(((abs(horsepower) / weight) - (s...-0.847227
2feature_4abs(abs((abs(abs(abs(abs(abs(abs(abs(abs(abs(a...-0.860441
3feature_5abs(abs(abs(abs(abs((((cube(horsepower) / (cub...-0.852704
4feature_0abs(abs((model_year / abs(weight))))-0.880479
\n", "
" ], "text/plain": [ " name formula fitness\n", "0 feature_1 abs(abs(abs((abs(abs(abs(abs(abs(abs(abs(abs(a... -0.874683\n", "1 feature_8 abs(abs(((cos(((abs(horsepower) / weight) - (s... -0.847227\n", "2 feature_4 abs(abs((abs(abs(abs(abs(abs(abs(abs(abs(abs(a... -0.860441\n", "3 feature_5 abs(abs(abs(abs(abs((((cube(horsepower) / (cub... -0.852704\n", "4 feature_0 abs(abs((model_year / abs(weight)))) -0.880479" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "gfs = pipe.named_steps[\"genetic_feature_synthesis\"]\n", "\n", "gfs.get_feature_info().head()" ] }, { "cell_type": "code", "execution_count": 9, "id": "4234ae88-ae78-46e6-bc81-e7e7e0933f2a", "metadata": {}, "outputs": [ { "data": { "image/png": "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TEzU2LFjFRkZKUnaunWrJk+efMZjMzMz5e3tXa09LVq0UNeuXZWZmWnf5uvrW+37mJGRIZvNppiYmGrnKykpUYsWLc5ZsysIL46wz/NCeAEAWSwO374xS9WtjyoWi6XatqrbKxUVFSouLtaIESP0xBNPnHaeyMhI7d692+Hr79+/X9dcc43uvPNO/f3vf1doaKi+/vprTZw4UaWlpfbwcqY6a3uDZNGiRbrrrru0YsUKvfPOO7r//vu1evVqXXzxxWratKnDNf+vpk2b2r9PklRcXCwvLy+lp6fLy8ur2r5nCn51iQG7jrDPsMvTRgDQUPXp00c//PCD2rdvr86dO1d7BQQEqFOnTvLx8dHGjRvtxxw9elQ7d+486znT09NVUVGhefPm6eKLL1ZMTIwOH677XqvevXtr7ty5+uabb3TBBRfozTfflFTZ8/TFF1+c8ZjY2FiVl5dXa88vv/yirKwsxcXF1Xgtm82mvLy8075PERERdduw/0F4cUTV2kbM8wIADdbUqVOVn5+vG264QWlpadqzZ49WrlypW2+9VTabTYGBgZo4caLuuecerVmzRtu2bdOECRNqfGy4c+fOKisr08KFC7V371795z//0QsvvFBnNe/bt09z585VSkqKDhw4oFWrVmnXrl2KjY2VJD344IN666239OCDDyozM1MZGRn2nqUuXbpo5MiRmjx5sr7++mt99913uummm9S6dWuNHDnyrNeMiYlRUlKSxo8frw8++ED79u1TamqqkpOT9cknn9RZ286E8OII5nkBgAYvKipKGzZskM1m0+DBg9WjRw/NmDFDISEh9oDy5JNP6vLLL9eIESOUmJioyy67TH379j3rOXv16qWnn35aTzzxhC644AItWbJEycnJdVazv7+/duzYoTFjxigmJkZTpkzR1KlTdfvtt0uqHLS8dOlSffTRR7rwwgt15ZVXKjU11X78okWL1LdvX11zzTWKj4+XYRj69NNPT7uN9b8WLVqk8ePHa9asWeratatGjRqltLQ0tW3bts7adiY8beSITa9Ky++Wul0jjav5sTUAaEhqekoEqK26etqInhdHMM8LAACmI7w4gvACADBJYGDgWV9Vc9g0Fjwq7Qj7mBfCCwDAs7Zu3XrWz1q3bu25Qs4DhBdH0PMCADBJ586dzS7hvMFtI0fYF2bkaSMAjVNFRYXZJaAe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ANQrhBcAAFCvEF4AAEC9QnippWeffVbt27dXkyZNNGDAAKWmpppdUp1av369RowYoaioKFksFv33v/+t9rlhGPrb3/6myMhINW3aVImJidq1a5c5xdaB5ORkXXTRRWrWrJnCw8M1atQoZWVlVdvn1KlTmjp1qlq0aKHAwECNGTNGR44cMali1z3//PPq2bOnffKq+Ph4ffbZZ/bPG1p7z+Txxx+XxWLRjBkz7NsaWrsfeughWSyWaq9u3brZP29o7a1y6NAh3XTTTWrRooWaNm2qHj16aNOmTfbPG9rvsPbt25/2c7ZYLJo6daqkhvtzrkJ4qYV33nlHM2fO1IMPPqjNmzerV69eGjJkyGnrN9Vnx48fV69evfTss8+e8fN//OMfWrBggV544QVt3LhRAQEBGjJkiE6dOuXhSuvGunXrNHXqVH377bdavXq1ysrKNHjwYB0/fty+z913362PP/5YS5cu1bp163T48GFde+21JlbtmjZt2ujxxx9Xenq6Nm3apCuvvFIjR47UDz/8IKnhtfd/paWl6d///rd69uxZbXtDbHf37t2Vk5Njf3399df2zxpie48ePapLL71UPj4++uyzz7R9+3bNmzdPzZs3t+/T0H6HpaWlVfsZr169WpJ03XXXSWqYP+dqDJxT//79jalTp9q/ttlsRlRUlJGcnGxiVe4jyVi2bJn964qKCiMiIsJ48skn7dsKCgoMPz8/46233jKhwrqXl5dnSDLWrVtnGEZl+3x8fIylS5fa98nMzDQkGSkpKWaVWeeaN29uvPzyyw2+vceOHTO6dOlirF692hg4cKAxffp0wzAa5s/5wQcfNHr16nXGzxpiew3DMO69917jsssuO+vnjeF32PTp041OnToZFRUVDfbn/Hv0vJxDaWmp0tPTlZiYaN9mtVqVmJiolJQUEyvznH379ik3N7fa9yA4OFgDBgxoMN+DwsJCSZUzQ0tSenq6ysrKqrW5W7duatu2bYNos81m09tvv63jx48rPj6+wbd36tSpuvrqq6u1T2q4P+ddu3YpKipKHTt2VFJSkrKzsyU13PZ+9NFH6tevn6677jqFh4erd+/eeumll+yfN/TfYaWlpXrjjTd02223yWKxNNif8+8RXs7h559/ls1mU6tWraptb9WqlXJzc02qyrOq2tlQvwcVFRWaMWOGLr30Ul1wwQWS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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "gfs.plot_history()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.6" } }, "nbformat": 4, "nbformat_minor": 5 }