{ "cells": [ { "cell_type": "markdown", "id": "9997a387", "metadata": {}, "source": [ "# Лабораторная работа: Эволюционные алгоритмы для задачи оптимизации розничной цены" ] }, { "cell_type": "markdown", "id": "fbcde77d", "metadata": {}, "source": [ "## 1. Определение задачи оптимизации\n", "\n", "Цель — определить оптимальную розничную цену на товар, при которой прибыль будет максимальной, учитывая переменные из датасета:\n", "- закупочную стоимость (`unit_price`),\n", "- стоимость логистики (`freight_price`),\n", "- объём продаж (`qty`).\n", "\n", "Тип задачи — **максимизация** функции прибыли:\n" ] }, { "cell_type": "markdown", "id": "92e9e640", "metadata": {}, "source": [ "## 2. Набор данных\n", "\n", "Датасет: `retail_price.csv` \n", "Отфильтрованы значения по конкретному товару — `bed1`.\n", "\n", "Выделены поля:\n", "- `unit_price` — закупочная цена,\n", "- `freight_price` — доставка,\n", "- `qty` — проданное количество,\n", "- `total_price` — общая выручка,\n", "- `lag_price` — цена продажи в предыдущем месяце (ориентир).\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "6c041d79", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " lag_price cost qty profit\n", "0 45.90 61.050000 1 -15.10\n", "1 45.95 58.883333 3 -38.80\n", "2 45.95 60.790000 6 -89.04\n", "3 45.95 60.237500 4 -57.15\n", "4 45.95 61.050000 2 -30.20\n" ] } ], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "\n", "df = pd.read_csv('../static/retail_price.csv')\n", "product_data = df[df[\"product_id\"] == \"bed1\"].copy()\n", "\n", "product_data[\"cost\"] = product_data[\"unit_price\"] + product_data[\"freight_price\"]\n", "product_data[\"profit\"] = product_data[\"total_price\"] - product_data[\"cost\"] * product_data[\"qty\"]\n", "\n", "print(product_data[[\"lag_price\", \"cost\", \"qty\", \"profit\"]].head())\n" ] }, { "cell_type": "markdown", "id": "be42a431", "metadata": {}, "source": [ "## 3. Структура хромосомы\n", "\n", "Хромосома — возможная цена продажи.\n", "\n", "Ген — число с плавающей точкой (тип `float`) в диапазоне от 50 до 250 (на основе наблюдаемых цен конкурентов).\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "a0fbbea3", "metadata": {}, "outputs": [], "source": [ "price_min = 50\n", "price_max = 250\n" ] }, { "cell_type": "markdown", "id": "c64b3159", "metadata": {}, "source": [ "## 4. Генерация начальной популяции\n", "\n", "Популяция — набор возможных цен.\n" ] }, { "cell_type": "code", "execution_count": 5, "id": "28313ddf", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Пример популяции: [ 50.41371951 50.48087187 148.54284113 106.27111405 179.03501848\n", " 134.91448339 113.71686216 140.57834704 106.41741383 193.22289117]\n" ] } ], "source": [ "import numpy as np\n", "\n", "def generate_population(pop_size, price_min=50, price_max=250):\n", " return np.random.uniform(price_min, price_max, size=pop_size)\n", "\n", "population = generate_population(10)\n", "print(\"Пример популяции:\", population)\n" ] }, { "cell_type": "markdown", "id": "a05d507e", "metadata": {}, "source": [ "## 5. Фитнес-функция\n", "\n", "Фитнес — средняя прибыль при заданной цене:" ] }, { "cell_type": "code", "execution_count": 6, "id": "14ba56f8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Фитнес для 100.0: 396.354375006875\n" ] } ], "source": [ "def fitness(price, cost, qty):\n", " profit = (price - cost) * qty\n", " return profit.mean()\n", "\n", "cost = product_data[\"cost\"].values\n", "qty = product_data[\"qty\"].values\n", "\n", "print(\"Фитнес для 100.0:\", fitness(100.0, cost, qty))\n" ] }, { "cell_type": "markdown", "id": "843f11f8", "metadata": {}, "source": [ "## 6. Оператор кроссинговера\n", "\n", "Простой арифметический кроссовер:\n" ] }, { "cell_type": "code", "execution_count": 9, "id": "42170c5c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Пример кроссовера: 140.17469125275707\n" ] } ], "source": [ "def crossover(parent1, parent2):\n", " alpha = np.random.rand()\n", " child = alpha * parent1 + (1 - alpha) * parent2\n", " return child\n", "\n", "print(\"Пример кроссовера:\", crossover(100, 150))\n" ] }, { "cell_type": "markdown", "id": "7817ed00", "metadata": {}, "source": [ "Алгоритм взял двух родителей с ценами 41.5 и 43.0. \n", "Потомок получил цену 42.25 — точно посередине. \n", "Это отражает идею \"смешения черт\" двух решений." ] }, { "cell_type": "markdown", "id": "7e94e0c9", "metadata": {}, "source": [ "## 7. Операторы мутации\n", "\n", "- Мутация 1: добавление случайного смещения.\n", "- Мутация 2: замена на случайное значение.\n" ] }, { "cell_type": "code", "execution_count": 10, "id": "b16fd3c9", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Мутация 1: 100.00798577997959\n", "Мутация 2: 123.77219890881597\n" ] } ], "source": [ "def mutation_1(price):\n", " return price + np.random.uniform(-5, 5)\n", "\n", "def mutation_2(price, price_min=50, price_max=250):\n", " return np.random.uniform(price_min, price_max)\n", "\n", "print(\"Мутация 1:\", mutation_1(100.0))\n", "print(\"Мутация 2:\", mutation_2(100.0))\n" ] }, { "cell_type": "markdown", "id": "a803c415", "metadata": {}, "source": [ "## 8. Генетический алгоритм\n", "\n", "Реализация основного ГА:\n" ] }, { "cell_type": "code", "execution_count": 11, "id": "f62d5f8d", "metadata": {}, "outputs": [], "source": [ "def genetic_algorithm(cost, qty, generations=20, pop_size=10):\n", " population = generate_population(pop_size)\n", " best_scores = []\n", "\n", " for gen in range(generations):\n", " scores = [fitness(p, cost, qty) for p in population]\n", " best_scores.append(max(scores))\n", " parents = sorted(zip(scores, population), reverse=True)[:2]\n", " new_population = []\n", "\n", " for _ in range(pop_size):\n", " child = crossover(parents[0][1], parents[1][1])\n", " if np.random.rand() < 0.5:\n", " child = mutation_1(child)\n", " else:\n", " child = mutation_2(child)\n", " child = np.clip(child, price_min, price_max)\n", " new_population.append(child)\n", "\n", " population = new_population\n", "\n", " return population, best_scores\n" ] }, { "cell_type": "markdown", "id": "76941121", "metadata": {}, "source": [ "## 9. Влияние параметров на сходимость\n", "\n", "Визуализируем, как меняется фитнес по поколениям.\n" ] }, { "cell_type": "code", "execution_count": 12, "id": "3b4aa232", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAHHCAYAAABeLEexAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAS2ZJREFUeJzt3QucTeX++PHv3JlxT0i5JpIQKlFuCancu5ATJ6JT/FU6Kqdy6XKEbpLT5VfhdBQpl6LjUK5JQomQIqWTWzeGGWbGzP6/vg9rn71n9ozZM2uvvfbsz/v12systWbtNc/es/d3f5/v8zwxHo/HIwAAAFEsNtwXAAAAEG4ERAAAIOoREAEAgKhHQAQAAKIeAREAAIh6BEQAACDqERABAICoR0AEAACiHgERAACIegREAAAg6hEQwXG7d++WO++8U+rWrSulSpWScuXKyZVXXilTpkyR48ePh/vyAABRKD7cF4DosnjxYrnpppskKSlJBgwYIBdffLFkZmbKJ598IqNGjZJt27bJq6++Gu7LBABEmRgWd4VT9uzZI02aNJHzzjtPli9fLuecc47f/l27dpmA6Z577gnbNQIAohNdZnDMpEmT5NixY/L666/nCYZUvXr1vMHQ9OnTJSYmRt544w2/Y/7+97+b7R9++KF3W1pamtx///1So0YNk3lq0KCBPP300xIo1l+5cqX5+UA3X+PGjcuzTa+9WrVqZruex9K+fXuzrWfPnnnuT7sGdZ9mwnwFc83/+te/5PLLL5fk5GSpWLGitG3bVpYuXWr21a5dO9/fR2+6X/3www/me72PYFk/G+im12Y5fPiw3Hvvvd7fSR/PiRMnSk5OTp5zBboObSNtS18ZGRkyduxYcy49p577gQceMNstBf3+erPOaT32vo+duv766812fcwt+jO5r8W69hkzZvht/+abb+TGG2+USpUqmS7gSy+9VN5///08v5+2z3333WceE/1d9IOBZkl//fXXfK9v37595ng9pz7/LIcOHZLBgwdL1apVzX02bdpUZs6cWaTH7fvvvzdZW71+fY5dccUV5oNJYejf6dVXXy1VqlQxv9NFF10kL730UsBj8/vbs56jBR2jN80iW7788kvp2rWr6W4vU6aMdOzYUT777DO/+9PHSX9u9erV5u/wrLPOMsdrm//xxx9+x+o1/PnPf/bbNnfu3IB/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0KFwX1rES0tLM+2pAWcgkyZNkhdeeEFefvllWb9+vaSkpJi21z80BG/VqlXmBeqzzz6TZcuWmUUYO3fubB4Hy3333ScffPCBzJ071xyvS+H07t07rNcdqXTWfH1j3rRpk2zcuFGuvvpq6dGjh2zbts3sp61DY8OGDfLKK6+YYNQX7W2/Ro0ayf79+723Tz75JPTtrcPuER6XX365Z9iwYd7vs7OzPdWrV/dMmDAhrNdV0ujTfP78+d7vc3JyPNWqVfNMnjzZu+3w4cOepKQkz9tvvx2mqyxZDh06ZNp91apV3vZNSEjwzJ0713vMjh07zDHr1q0L45WWHBUrVvS89tprtHWIHD161HPBBRd4li1b5mnXrp3nnnvuMdtpb/uNHTvW07Rp04D7QtneZIjCJDMz03y6064a3/XS9Pt169aF9dpKuj179siBAwf82l7XudEuS9reHkeOHDH/V6pUyfyvz3XNGvm2uabAa9asSZsXU3Z2tsyePdtk47TrjLYODc2AXn/99X7tqmjv0NASBi15qFu3rvTv31/27t0b8vZmcdcw+fXXX80LWdWqVf226/fffPNN2K4rGmgwpAK1vbUPRZeTk2PqK6688kq5+OKLzTZt18TERKlQoYLfsbR50W3dutUEQNrNq3UU8+fPl4suukg2b95MW9tMA04ta9Aus9x4bttPP5zOmDFDGjRoYLrLxo8fL23atJGvv/46pO1NQATA9k/S+sLl2+cP++mbhQY/mo179913ZeDAgaaeAvb66aef5J577jG1cTr4BaHXtWtX79dar6UBUq1ateSdd94xg2BChS6zMKlcubLExcXlqYzX76tVqxa264oGVvvS9vYbPny4LFq0SFasWGEKfy3artpNfPjwYb/jafOi00/J9erVkxYtWphRfjqIYMqUKbS1zbSLRge6NG/eXOLj481NA08dlKFfa2aC9g4tzQbVr19fdu3aFdLnNwFRGF/M9IXs448/9utq0O81DY7QqVOnjvnD8W371NRUM9qMti8arV3XYEi7bZYvX27a2Jc+1xMSEvzaXIfla10AbW4Pff3IyMigrW3WsWNH0z2p2Tjrdumll5q6Futr2ju0jh07Jrt37zbTpIT0+V2skmwUy+zZs83IphkzZni2b9/uGTp0qKdChQqeAwcOhPvSSsSIkC+//NLc9Gn+7LPPmq9//PFHs/+pp54ybb1w4ULPli1bPD169PDUqVPHc/z48XBfekS66667POXLl/esXLnSs3//fu8tPT3de8xf/vIXT82aNT3Lly/3bNy40dOqVStzQ/AeeughM4Jvz5495vmr38fExHiWLl1q9tPWoeU7ykzR3va6//77zWuJPr/Xrl3rueaaazyVK1c2o1dD2d4ERGE2depU88AmJiaaYfifffZZuC+pRFixYoUJhHLfBg4c6B16/+ijj3qqVq1qgtKOHTt6du7cGe7LjliB2lpv06dP9x6jwebdd99thocnJyd7evXqZYImBG/QoEGeWrVqmdeNs88+2zx/rWBI0dbOBkS0t71uueUWzznnnGOe3+eee675fteuXSFv7xj9p/gJLQAAgMhFDREAAIh6BEQAACDqERABAICoR0AEAACiHgERAACIegREAAAg6hEQAQCAqEdABAAAoh4BEQDH/PnPf5aYmJh8b7kXbAQApxAQAXDUtddeK/v37/e7vffee+G+LABRjoAIgKOSkpKkWrVqfrdKlSr5HaMBUqNGjcyxtWvXlmeeecZvv257/vnnvd8/8sgjct5558kPP/xQ6HOocePG5clS9ezZ07tfV4//61//Kueee66kpKRIy5YtZeXKld79M2bMkAoVKvidU69Bz6MroSs9Pnf267bbbjPbFixY4N32008/yc0332zOp+3Ro0cPv98HQGgREAFwlU2bNpnAoG/fvrJ161YTtDz66KMm+AhEA51XXnlFli1bZgKfYM6hSzlq0GRlqvRnfA0fPlzWrVsns2fPli1btshNN91kMlzfffddsX6/999/329bVlaWdOnSRcqWLStr1qyRtWvXSpkyZcx9ZWZmFvm+ABRefBDHAkDIPfvss9KxY0cTwKj69evL9u3bZfLkyaYGyddrr70mjz32mCxfvlwaNmwY9Dk0ECldurTJUin9WrNCau/evTJ9+nTzf/Xq1c02zRYtWbLEbP/73/9epN9v5MiRMmrUKO+1qTlz5khOTo75fTRzpPQ+NFukGabOnTsX6b4AFB4ZIgCusmPHDrnyyiv9tun3mpXJzs72blu4cKHceeedJli5+OKLi3SO1NRU0xUWiGaW9FgNpjRbY91WrVolu3fv9h535MgRv/2accqPdpF9//33cv/99/tt/+qrr2TXrl0mQ2SdR7vNTpw44XdfAEKHDBGAiKTdSppZGTNmjOkSmzBhQtDn2Ldvnzf7k9uxY8ckLi7OdHHp/740YLFoEPPFF194v//555+lffv2ec6n2agHHnhAnnzySZOJyn1fLVq0kFmzZuX5ubPPPjvo3wtA8AiIALiKdn1psONLv9dMjW9g8tBDD8mNN94oNWvWlLZt20rv3r3lsssuK/Q5tItKA5lhw4YFvI5mzZqZDNGhQ4ekTZs2+V5vbGys1KtXz/t9fHzgl9WXXnrJBFJaUJ1b8+bNTXBXpUoVKVeuXL73BSB06DID4CranfTxxx/L448/Lt9++63MnDlTXnzxRVO/48samXb55ZfLvffeK7fffru3APlM59ARXUOGDDHBzi233BLwOjR46t+/vwwYMEDmzZsne/bskc8//9xkohYvXhz07zVp0iRTAG7VCPnS+6lcubIZWaZF1XpfWjs0YsQI+e9//xv0fQEIHgERAFfRbMk777xjRnZpbZB2iWnhdO6Cal/jx483GR/tOivMOaZMmWJqdpYuXWoyTPnRwmYNiDTAatCggRmSv2HDhgJ/Jj8dOnQwt0CSk5Nl9erV5rya6dIM1+DBg00NERkjwBkxHh13CgAAEMXIEAEAgKhHQAQAAKIeAREAAIh6BEQAACDqERABAICoR0AEAACiHgERAACIegREAAAg6hEQAQCAqEdABAAAoh4BEQAAiHoERAAAQKLd/wfUBpQJRV0xyAAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "_, scores = genetic_algorithm(cost, qty, generations=50, pop_size=20)\n", "\n", "import matplotlib.pyplot as plt\n", "plt.plot(scores)\n", "plt.xlabel(\"Поколение\")\n", "plt.ylabel(\"Макс. прибыль\")\n", "plt.title(\"Сходимость генетического алгоритма\")\n", "plt.grid()\n", "plt.show()\n" ] }, { "cell_type": "markdown", "id": "2f79ae03", "metadata": {}, "source": [ "## 10. Обоснование выбора функций\n", "\n", "- Хромосома — цена: естественно моделируется как `float`.\n", "- Кроссовер: обеспечивает плавное смешение стратегий (цен).\n", "- Мутации: имитируют как локальный шум, так и случайный сбой.\n", "- Фитнес — прибыль, что напрямую отражает цель бизнеса.\n", "\n", "Генетический алгоритм эффективен, так как перебор всех цен — ресурсоёмок, а градиент невозможен из-за дискретных qty.\n" ] } ], "metadata": { "kernelspec": { "display_name": "aimvenv", "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.12.10" } }, "nbformat": 4, "nbformat_minor": 5 }