"
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "1c3276f0",
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/"
+ },
+ "id": "1c3276f0",
+ "outputId": "8b9efd0a-df20-42e8-99b7-28eb2ae2b3e5"
+ },
+ "outputs": [
+ {
+ "output_type": "stream",
+ "name": "stdout",
+ "text": [
+ "Requirement already satisfied: gurobipy in /usr/local/lib/python3.10/dist-packages (11.0.0)\n"
+ ]
+ }
],
- "text/plain": [
- " p[1] p[2] n[1]\n",
- "0 356.12 197.67 108.0\n",
- "1 358.05 189.68 66.0\n",
- "2 340.79 260.35 130.0\n",
- "3 353.76 133.53 55.0\n",
- "4 341.37 229.80 91.0\n",
- ".. ... ... ...\n",
- "995 357.63 241.54 68.0\n",
- "996 352.58 212.95 87.0\n",
- "997 355.28 189.50 94.0\n",
- "998 369.75 166.33 51.0\n",
- "999 349.31 222.07 114.0\n",
- "\n",
- "[1000 rows x 3 columns]"
+ "source": [
+ "%pip install gurobipy"
]
- },
- "execution_count": 169,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "df = pd.read_csv('https://raw.githubusercontent.com/Gurobi/modeling-examples/master/pricing_competing_products/price_value_data.csv')\n",
- "df"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "b65707ac",
- "metadata": {},
- "source": [
- "### What's in the data?\n",
- "The data contains three columns:\n",
- "1. `p[1]` is the price (in dollars) of the first category (let's call it Category 1).\n",
- "2. `p[2]` is the price (in dollars) of the second category (Category 2).\n",
- "3. `n[1]` is the number of the items sold that are of Category 1. \n",
- "\n",
- "We don't see a column for `n[2]`, which would be the number of items sold that are Category 2. Here is where we make a **pretty big assumption** that we will sell all of the items. This makes our decision to be how to divvy up the limited space we have in order to maximize our revenue. \n",
- "The data was created to have a couple of key characteristics.\n",
- "1. As the price of Category 1 goes up, the number sold should decrease, so `p[1]` and `n[1]` have a negative correlation.\n",
- "2. As the price of Category 2 goes up, the number sold of Category 1 should increase, so `p[2]` and `n[1]` have a positive correlation.\n",
- "\n",
- "The correlation plot of the columns of the data is below. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 170,
- "id": "4cb22fe7",
- "metadata": {
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 451
},
- "id": "4cb22fe7",
- "outputId": "b6e2ddb2-81ca-485c-e5cc-04b65b292ad9"
- },
- "outputs": [
{
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Warning: environment still referenced so free is deferred (Continue to use WLS)\n",
- "Warning: environment still referenced so free is deferred (Continue to use WLS)\n",
- "Warning: environment still referenced so free is deferred (Continue to use WLS)\n"
- ]
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "3024295a",
+ "metadata": {
+ "id": "3024295a"
+ },
+ "outputs": [],
+ "source": [
+ "import gurobipy as gp\n",
+ "from gurobipy import GRB\n",
+ "\n",
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import seaborn as sns\n",
+ "import matplotlib.pyplot as plt\n",
+ "import warnings\n",
+ "from sklearn.model_selection import train_test_split\n",
+ "from sklearn import tree\n",
+ "\n",
+ "warnings.filterwarnings(\"ignore\")"
+ ]
},
{
- "data": {
- "image/png": "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",
- "text/plain": [
- "
"
+ "cell_type": "markdown",
+ "id": "d8c28cfd",
+ "metadata": {
+ "id": "d8c28cfd"
+ },
+ "source": [
+ "## Start with some data analysis\n",
+ "\n",
+ "This data contains prices and sales for two of our competing products and was generated using another script, which can be found [here](). Let's load the data and take a quick look."
]
- },
- "metadata": {},
- "output_type": "display_data"
- }
- ],
- "source": [
- "fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(15, 5))\n",
- "sns.heatmap(df[['p[1]','p[2]','n[1]']].corr(),annot=True, center=0,ax=axes)\n",
- "\n",
- "axes.set_title('Correlations')\n",
- "plt.show()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "a4aa96d4",
- "metadata": {},
- "source": [
- "In this problem, we've assumed that the amount of space we have available for the products is 200 units. In retail, this could be the amount of warehouse space, or for ticketing this could represent the number of seats available."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6e9c6157",
- "metadata": {
- "id": "6e9c6157"
- },
- "source": [
- "### Building regressors to predict sales\n",
- "\n",
- "The prices for each category item will be used to predict the number of Category 1 items sold. Here we build a regression model to form this relationship which will later be used as part of the optimization model. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "a70d5f2c",
- "metadata": {
- "id": "a70d5f2c"
- },
- "outputs": [],
- "source": [
- "from sklearn.compose import make_column_transformer\n",
- "from sklearn.linear_model import LinearRegression\n",
- "from sklearn.pipeline import make_pipeline\n",
- "from sklearn.metrics import r2_score\n",
- "from sklearn.model_selection import train_test_split #importing scikit-learn's function for data splitting\n",
- "from sklearn.ensemble import GradientBoostingRegressor #importing scikit-learn's gradient booster regressor function\n",
- "from sklearn.model_selection import cross_validate #improting scikit-learn's cross validation function"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 171,
- "id": "3095da93",
- "metadata": {
- "colab": {
- "base_uri": "https://localhost:8080/"
},
- "id": "3095da93",
- "outputId": "e6415f1b-34b8-4c25-ebf5-f4d1fa2223e1"
- },
- "outputs": [],
- "source": [
- "X = df[[\"p[1]\",\"p[2]\"]]\n",
- "y = df[\"n[1]\"]\n",
- "# Split the data for training and testing\n",
- "X_train, X_test, y_train, y_test = train_test_split(\n",
- " X, y, train_size=0.75, random_state=1\n",
- ")"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "f8d713c2",
- "metadata": {},
- "source": [
- "First we'll start with a linear regression model. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 172,
- "id": "33f4eaec",
- "metadata": {
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 92
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "eea57a4c",
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 424
+ },
+ "id": "eea57a4c",
+ "outputId": "28a70699-d016-4f52-96e3-bc9badf6e0b0"
+ },
+ "outputs": [
+ {
+ "output_type": "execute_result",
+ "data": {
+ "text/plain": [
+ " p[1] p[2] n[1]\n",
+ "0 356.12 197.67 108.0\n",
+ "1 358.05 189.68 66.0\n",
+ "2 340.79 260.35 130.0\n",
+ "3 353.76 133.53 55.0\n",
+ "4 341.37 229.80 91.0\n",
+ ".. ... ... ...\n",
+ "995 357.63 241.54 68.0\n",
+ "996 352.58 212.95 87.0\n",
+ "997 355.28 189.50 94.0\n",
+ "998 369.75 166.33 51.0\n",
+ "999 349.31 222.07 114.0\n",
+ "\n",
+ "[1000 rows x 3 columns]"
+ ],
+ "text/html": [
+ "\n",
+ "