{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### Пример использования библиотеки Featuretools для автоматического конструирования признаков\n", "\n", "https://featuretools.alteryx.com/en/stable/getting_started/using_entitysets.html" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Загрузка данных\n", "\n", "За основу был взят набор данных \"Ecommerce Orders Data Set\" из Kaggle\n", "\n", "Используется только 100 первых заказов и связанные с ними объекты\n", "\n", "https://www.kaggle.com/datasets/sangamsharmait/ecommerce-orders-data-analysis" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [], "source": [ "import pandas as pd\n", "import featuretools as ft\n", "from woodwork.logical_types import Categorical, Datetime\n", "\n", "customers = pd.read_csv(\"data/orders/customers.csv\")\n", "sellers = pd.read_csv(\"data/orders/sellers.csv\")\n", "products = pd.read_csv(\"data/orders/products.csv\")\n", "orders = pd.read_csv(\"data/orders/orders.csv\")\n", "orders.fillna({\"order_delivered_carrier_date\": pd.to_datetime(\n", " \"1900-01-01 00:00:00\"\n", ")}, inplace=True)\n", "orders.fillna(\n", " {\"order_delivered_customer_date\": pd.to_datetime(\"1900-01-01 00:00:00\")},\n", " inplace=True,\n", ")\n", "order_items = pd.read_csv(\"data/orders/order_items.csv\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Создание сущностей в featuretools\n", "\n", "Добавление dataframe'ов с данными в EntitySet с указанием параметров: название сущности (таблицы), первичный ключ, категориальные атрибуты (в том числе даты)" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\woodwork\\type_sys\\utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.\n", " pd.to_datetime(\n" ] }, { "data": { "text/plain": [ "Entityset: orders\n", " DataFrames:\n", " customers [Rows: 100, Columns: 5]\n", " sellers [Rows: 87, Columns: 4]\n", " products [Rows: 100, Columns: 9]\n", " orders [Rows: 100, Columns: 8]\n", " order_items [Rows: 115, Columns: 8]\n", " Relationships:\n", " No relationships" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "es = ft.EntitySet(id=\"orders\")\n", "\n", "es = es.add_dataframe(\n", " dataframe_name=\"customers\",\n", " dataframe=customers,\n", " index=\"customer_id\",\n", " logical_types={\n", " \"customer_unique_id\": Categorical,\n", " \"customer_zip_code_prefix\": Categorical,\n", " \"customer_city\": Categorical,\n", " \"customer_state\": Categorical,\n", " },\n", ")\n", "es = es.add_dataframe(\n", " dataframe_name=\"sellers\",\n", " dataframe=sellers,\n", " index=\"seller_id\",\n", " logical_types={\n", " \"seller_zip_code_prefix\": Categorical,\n", " \"seller_city\": Categorical,\n", " \"seller_state\": Categorical,\n", " },\n", ")\n", "es = es.add_dataframe(\n", " dataframe_name=\"products\",\n", " dataframe=products,\n", " index=\"product_id\",\n", " logical_types={\n", " \"product_category_name\": Categorical,\n", " \"product_name_lenght\": Categorical,\n", " \"product_description_lenght\": Categorical,\n", " \"product_photos_qty\": Categorical,\n", " },\n", ")\n", "es = es.add_dataframe(\n", " dataframe_name=\"orders\",\n", " dataframe=orders,\n", " index=\"order_id\",\n", " logical_types={\n", " \"order_status\": Categorical,\n", " \"order_purchase_timestamp\": Datetime,\n", " \"order_approved_at\": Datetime,\n", " \"order_delivered_carrier_date\": Datetime,\n", " \"order_delivered_customer_date\": Datetime,\n", " \"order_estimated_delivery_date\": Datetime,\n", " },\n", ")\n", "es = es.add_dataframe(\n", " dataframe_name=\"order_items\",\n", " dataframe=order_items,\n", " index=\"orderitem_id\",\n", " make_index=True,\n", " logical_types={\"shipping_limit_date\": Datetime},\n", ")\n", "\n", "es" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Настройка связей между сущностями featuretools\n", "\n", "Настройка связей между таблицами на уровне ключей\n", "\n", "Связь указывается от родителя к потомкам (таблица-родитель, первичный ключ, таблица-потомок, внешний ключ)" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Entityset: orders\n", " DataFrames:\n", " customers [Rows: 100, Columns: 5]\n", " sellers [Rows: 87, Columns: 4]\n", " products [Rows: 100, Columns: 9]\n", " orders [Rows: 100, Columns: 8]\n", " order_items [Rows: 115, Columns: 8]\n", " Relationships:\n", " orders.customer_id -> customers.customer_id\n", " order_items.order_id -> orders.order_id\n", " order_items.product_id -> products.product_id\n", " order_items.seller_id -> sellers.seller_id" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "es = es.add_relationship(\"customers\", \"customer_id\", \"orders\", \"customer_id\")\n", "es = es.add_relationship(\"orders\", \"order_id\", \"order_items\", \"order_id\")\n", "es = es.add_relationship(\"products\", \"product_id\", \"order_items\", \"product_id\")\n", "es = es.add_relationship(\"sellers\", \"seller_id\", \"order_items\", \"seller_id\")\n", "\n", "es" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Автоматическое конструирование признаков с помощью featuretools\n", "\n", "Библиотека применят различные функции агрегации к атрибутам таблицы order_items с учетом отношений\n", "\n", "Результат помещается в Dataframe feature_matrix" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\featuretools\\synthesis\\dfs.py:321: UnusedPrimitiveWarning: Some specified primitives were not used during DFS:\n", " agg_primitives: ['any', 'mode']\n", "This may be caused by a using a value of max_depth that is too small, not setting interesting values, or it may indicate no compatible columns for the primitive were found in the data. If the DFS call contained multiple instances of a primitive in the list above, none of them were used.\n", " warnings.warn(warning_msg, UnusedPrimitiveWarning)\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\featuretools\\computational_backends\\feature_set_calculator.py:785: FutureWarning: The provided callable is currently using SeriesGroupBy.mean. In a future version of pandas, the provided callable will be used directly. To keep current behavior pass the string \"mean\" instead.\n", " ).agg(to_agg)\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\featuretools\\computational_backends\\feature_set_calculator.py:785: FutureWarning: The provided callable is currently using SeriesGroupBy.mean. In a future version of pandas, the provided callable will be used directly. To keep current behavior pass the string \"mean\" instead.\n", " ).agg(to_agg)\n", "c:\\Users\\user\\Projects\\python\\mai\\.venv\\Lib\\site-packages\\featuretools\\computational_backends\\feature_set_calculator.py:785: FutureWarning: The provided callable is currently using SeriesGroupBy.mean. In a future version of pandas, the provided callable will be used directly. To keep current behavior pass the string \"mean\" instead.\n", " ).agg(to_agg)\n" ] }, { "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", " \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", " \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", " \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", " \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", "
order_item_idpricefreight_valueHOUR(shipping_limit_date)WEEKDAY(shipping_limit_date)orders.order_statusproducts.product_category_nameproducts.product_name_lenghtproducts.product_description_lenghtproducts.product_photos_qty...orders.customers.customer_cityorders.customers.customer_stateproducts.COUNT(order_items)products.MEAN(order_items.freight_value)products.MEAN(order_items.order_item_id)products.MEAN(order_items.price)sellers.COUNT(order_items)sellers.MEAN(order_items.freight_value)sellers.MEAN(order_items.order_item_id)sellers.MEAN(order_items.price)
orderitem_id
0138.5024.84204deliveredcama_mesa_banho53.0223.01.0...santa luziaPB124.841.038.50221.3401.061.200000
1129.997.3980deliveredtelefonia59.0675.05.0...sao pauloSP17.391.029.9917.3901.029.990000
21110.9921.27211deliveredcama_mesa_banho52.0413.01.0...gravataiRS121.271.0110.99121.2701.0110.990000
3127.9915.10231deliveredtelefonia60.0818.06.0...imbitubaSC115.101.027.99213.9701.026.490000
4149.9016.05132invoicedNaNNaNNaNNaN...santa rosaRS116.051.049.90116.0501.049.900000
..................................................................
110117.9010.9681deliveredcama_mesa_banho55.0122.01.0...jundiaiSP110.961.017.90110.9601.017.900000
111179.998.9194deliveredbeleza_saude59.0492.03.0...sao pauloSP18.911.079.99513.2061.254.590000
1121190.0019.41133deliveredclimatizacao60.03270.04.0...pauliniaSP119.411.0190.00119.4101.0190.000000
1131109.9015.5322deliveredcool_stuff46.0595.02.0...rio de janeiroRJ115.531.0109.90115.5301.0109.900000
114127.9018.30142deliveredalimentos59.0982.01.0...joinvilleSC216.701.027.90316.1901.038.596667
\n", "

115 rows × 43 columns

\n", "
" ], "text/plain": [ " order_item_id price freight_value HOUR(shipping_limit_date) \\\n", "orderitem_id \n", "0 1 38.50 24.84 20 \n", "1 1 29.99 7.39 8 \n", "2 1 110.99 21.27 21 \n", "3 1 27.99 15.10 23 \n", "4 1 49.90 16.05 13 \n", "... ... ... ... ... \n", "110 1 17.90 10.96 8 \n", "111 1 79.99 8.91 9 \n", "112 1 190.00 19.41 13 \n", "113 1 109.90 15.53 2 \n", "114 1 27.90 18.30 14 \n", "\n", " WEEKDAY(shipping_limit_date) orders.order_status \\\n", "orderitem_id \n", "0 4 delivered \n", "1 0 delivered \n", "2 1 delivered \n", "3 1 delivered \n", "4 2 invoiced \n", "... ... ... \n", "110 1 delivered \n", "111 4 delivered \n", "112 3 delivered \n", "113 2 delivered \n", "114 2 delivered \n", "\n", " products.product_category_name products.product_name_lenght \\\n", "orderitem_id \n", "0 cama_mesa_banho 53.0 \n", "1 telefonia 59.0 \n", "2 cama_mesa_banho 52.0 \n", "3 telefonia 60.0 \n", "4 NaN NaN \n", "... ... ... \n", "110 cama_mesa_banho 55.0 \n", "111 beleza_saude 59.0 \n", "112 climatizacao 60.0 \n", "113 cool_stuff 46.0 \n", "114 alimentos 59.0 \n", "\n", " products.product_description_lenght products.product_photos_qty \\\n", "orderitem_id \n", "0 223.0 1.0 \n", "1 675.0 5.0 \n", "2 413.0 1.0 \n", "3 818.0 6.0 \n", "4 NaN NaN \n", "... ... ... \n", "110 122.0 1.0 \n", "111 492.0 3.0 \n", "112 3270.0 4.0 \n", "113 595.0 2.0 \n", "114 982.0 1.0 \n", "\n", " ... orders.customers.customer_city \\\n", "orderitem_id ... \n", "0 ... santa luzia \n", "1 ... sao paulo \n", "2 ... gravatai \n", "3 ... imbituba \n", "4 ... santa rosa \n", "... ... ... \n", "110 ... jundiai \n", "111 ... sao paulo \n", "112 ... paulinia \n", "113 ... rio de janeiro \n", "114 ... joinville \n", "\n", " orders.customers.customer_state products.COUNT(order_items) \\\n", "orderitem_id \n", "0 PB 1 \n", "1 SP 1 \n", "2 RS 1 \n", "3 SC 1 \n", "4 RS 1 \n", "... ... ... \n", "110 SP 1 \n", "111 SP 1 \n", "112 SP 1 \n", "113 RJ 1 \n", "114 SC 2 \n", "\n", " products.MEAN(order_items.freight_value) \\\n", "orderitem_id \n", "0 24.84 \n", "1 7.39 \n", "2 21.27 \n", "3 15.10 \n", "4 16.05 \n", "... ... \n", "110 10.96 \n", "111 8.91 \n", "112 19.41 \n", "113 15.53 \n", "114 16.70 \n", "\n", " products.MEAN(order_items.order_item_id) \\\n", "orderitem_id \n", "0 1.0 \n", "1 1.0 \n", "2 1.0 \n", "3 1.0 \n", "4 1.0 \n", "... ... \n", "110 1.0 \n", "111 1.0 \n", "112 1.0 \n", "113 1.0 \n", "114 1.0 \n", "\n", " products.MEAN(order_items.price) sellers.COUNT(order_items) \\\n", "orderitem_id \n", "0 38.50 2 \n", "1 29.99 1 \n", "2 110.99 1 \n", "3 27.99 2 \n", "4 49.90 1 \n", "... ... ... \n", "110 17.90 1 \n", "111 79.99 5 \n", "112 190.00 1 \n", "113 109.90 1 \n", "114 27.90 3 \n", "\n", " sellers.MEAN(order_items.freight_value) \\\n", "orderitem_id \n", "0 21.340 \n", "1 7.390 \n", "2 21.270 \n", "3 13.970 \n", "4 16.050 \n", "... ... \n", "110 10.960 \n", "111 13.206 \n", "112 19.410 \n", "113 15.530 \n", "114 16.190 \n", "\n", " sellers.MEAN(order_items.order_item_id) \\\n", "orderitem_id \n", "0 1.0 \n", "1 1.0 \n", "2 1.0 \n", "3 1.0 \n", "4 1.0 \n", "... ... \n", "110 1.0 \n", "111 1.2 \n", "112 1.0 \n", "113 1.0 \n", "114 1.0 \n", "\n", " sellers.MEAN(order_items.price) \n", "orderitem_id \n", "0 61.200000 \n", "1 29.990000 \n", "2 110.990000 \n", "3 26.490000 \n", "4 49.900000 \n", "... ... \n", "110 17.900000 \n", "111 54.590000 \n", "112 190.000000 \n", "113 109.900000 \n", "114 38.596667 \n", "\n", "[115 rows x 43 columns]" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "feature_matrix, feature_defs = ft.dfs(\n", " entityset=es,\n", " target_dataframe_name=\"order_items\",\n", " agg_primitives=[\"mean\", \"count\", \"mode\", \"any\"],\n", " trans_primitives=[\"hour\", \"weekday\"],\n", " max_depth=2,\n", ")\n", "\n", "feature_matrix" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Полученные признаки\n", "\n", "Список колонок полученного dataframe'а" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[,\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", " ]" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "feature_defs" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "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.7" } }, "nbformat": 4, "nbformat_minor": 2 }