diff --git a/homework/m1_numpy.ipynb b/homework/m1_numpy.ipynb new file mode 100644 index 0000000..fcb4076 --- /dev/null +++ b/homework/m1_numpy.ipynb @@ -0,0 +1,382 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "dedf1249", + "metadata": {}, + "source": [ + "\"\"\"\n", + "M1 NumPy 向量化思維 — 課後作業\n", + "================================\n", + "請完成以下每個函式,用 NumPy 向量化寫法(不要 for-loop)。\n", + "完成後 git push,GitHub Actions 會自動批改並顯示成績與解答。\n", + "\n", + "提示:\n", + "- np.array, np.where, np.argsort\n", + "- 布林遮罩: arr[arr > 10]\n", + "- 統計: .sum(), .mean(), .max(), .min()\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "60c0496d", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🟢 送分題(每題 10 分,共 30 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5567ab7e", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "de47a63f", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "import numpy as np\n", + "\n", + "\n", + "\n", + "def green_mean():\n", + " \"\"\"建立 [10, 20, 30, 40, 50],回傳所有元素的平均值 (float)\"\"\"\n", + " # TODO: 你的程式碼\n", + " pass\n", + "\n", + "\n", + "def green_double():\n", + " \"\"\"建立 [10, 20, 30, 40, 50],回傳所有元素乘以 2 的 ndarray\"\"\"\n", + " # TODO: 你的程式碼\n", + " pass\n", + "\n", + "\n", + "def green_filter():\n", + " \"\"\"建立 [10, 20, 30, 40, 50],回傳大於 25 的元素 (ndarray)\"\"\"\n", + " # TODO: 你的程式碼\n", + " pass\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "378063f7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "30.0\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "\n", + "#def green_mean():\n", + " #\"\"\"建立 [10, 20, 30, 40, 50],回傳所有元素的平均值 (float)\"\"\"\n", + " # TODO: 你的程式碼\n", + " \n", + "arr = np.array([10, 20, 30, 40, 50])\n", + "avg_arr = np.mean(arr)\n", + "print(avg_arr)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "d62c7972", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[ 20 40 60 80 100]\n" + ] + } + ], + "source": [ + "#def green_double():\n", + "#\"\"\"建立 [10, 20, 30, 40, 50],回傳所有元素乘以 2 的 ndarray\"\"\"\n", + "# TODO: 你的程式碼\n", + "\n", + "arr = np.array([10, 20, 30, 40, 50])\n", + "twotimes_arr = np.multiply(arr, 2)\n", + "print(twotimes_arr)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "d70bddec", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[30 40 50]\n" + ] + } + ], + "source": [ + "#def green_filter():\n", + " #\"\"\"建立 [10, 20, 30, 40, 50],回傳大於 25 的元素 (ndarray)\"\"\"\n", + " # TODO: 你的程式碼\n", + "arr = np.array([10, 20, 30, 40, 50])\n", + "biggerthan25_arr = arr[arr > 25]\n", + "print(biggerthan25_arr)" + ] + }, + { + "cell_type": "markdown", + "id": "df18d551", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🟡 核心題(每題 15 分,共 45 分)\n", + "# 以下函式會接收從 products.csv 讀出的 prices, stocks 陣列\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "02a97124", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "def yellow_expensive_count(prices):\n", + " \"\"\"回傳單價 > 1000 的商品數量 (int)\"\"\"\n", + " # TODO: 你的程式碼\n", + " pass\n", + "\n", + "\n", + "def yellow_top3_stock_indices(stocks):\n", + " \"\"\"\n", + " 回傳庫存最多的前 3 個商品的索引位置 (ndarray, 由大到小排)\n", + " 提示:np.argsort\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + " pass\n", + "\n", + "\n", + "def yellow_restock_cost(prices, stocks):\n", + " \"\"\"\n", + " 單價 < 500 的商品,每種各進貨 50 個,回傳總花費 (float/int)\n", + " 提示:布林遮罩 + .sum()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + " pass\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "24269aa8", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "df = pd.read_csv(r\"D:\\python_workstation\\iSpan_python-DA-cookbooks\\python-da-homework-2026-main\\python-da-homework-2026-main\\datasets\\ecommerce\\products.csv\")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "e328bf6b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "16" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "\n", + "DATA = pd.read_csv(r\"D:\\python_workstation\\iSpan_python-DA-cookbooks\\python-da-homework-2026-main\\python-da-homework-2026-main\\datasets\\ecommerce\\products.csv\")\n", + "prices = DATA.iloc[:, 3].to_numpy()\n", + "stocks = DATA.iloc[:, 4].to_numpy()\n", + "#def yellow_expensive_count(prices):\n", + "#\"\"\"回傳單價 > 1000 的商品數量 (int)\"\"\"\n", + "# TODO: 你的程式碼\n", + "\n", + "prices \n", + "prices[prices > 1000]\n", + "len(prices[prices > 1000])" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "8f9d602b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([10, 0, 17, 22, 24, 5, 25, 2, 11, 13, 23, 1, 29, 20, 14, 12, 16,\n", + " 28, 21, 27, 19, 15, 4, 9, 26, 6, 18, 3, 8, 7])" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "\n", + "DATA = pd.read_csv(r\"D:\\python_workstation\\iSpan_python-DA-cookbooks\\python-da-homework-2026-main\\python-da-homework-2026-main\\datasets\\ecommerce\\products.csv\")\n", + "prices = DATA.iloc[:, 3].to_numpy()\n", + "stocks = DATA.iloc[:, 4].to_numpy()\n", + "\n", + "#def yellow_top3_stock_indices(stocks):\n", + " #\"\"\"\n", + " #回傳庫存最多的前 3 個商品的索引位置 (ndarray, 由大到小排)\n", + " #提示:np.argsort\n", + " #\"\"\"\n", + "\n", + "\n", + "stocks\n", + "np.argsort(stocks)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "62a610a4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "np.int64(120300)" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#def yellow_restock_cost(prices, stocks):\n", + "# \"\"\"\n", + "#單價 < 500 的商品,每種各進貨 50 個,回傳總花費 (float/int)\n", + "#提示:布林遮罩 + .sum()\n", + "#\"\"\"\n", + "# TODO: 你的程式碼\n", + " \n", + "prices[prices<500] #找出單價小於500的價格\n", + "prices[prices<500] * 50 #每個商品進貨50個\n", + "sum(prices[prices<500] * 50) #總價格" + ] + }, + { + "cell_type": "markdown", + "id": "3fa5a64a", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🔴 挑戰題(25 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b62c2097", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([1312.5, 1202.6, 203. , 426.3, 1075.9, 392.7, 766.5, 1238.3,\n", + " 526.4, 1677.2, 228.9, 219.8, 1292.2, 267.4, 189.7, 1460.9,\n", + " 133.7, 700. , 1132.6, 331.8, 410.9, 558. , 141.3, 1724.4,\n", + " 1386.9, 1329.3, 1755.9, 1935. , 1627. , 1506. ])" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "#def red_double11_prices(prices, stocks):\n", + "#\"\"\"\n", + "#雙 11 定價規則(必須向量化,不能用 for-loop):\n", + "#- 庫存 >= 100:打 7 折\n", + "#- 庫存 20~99:打 9 折\n", + "#- 庫存 < 20:原價\n", + "#回傳每個商品的雙 11 售價 (ndarray)\n", + "#提示:np.where 可以巢狀使用\n", + "#\"\"\"\n", + "\n", + "\n", + "prices_07 = prices[stocks >= 100] *0.7\n", + "prices_09 = prices[(stocks >= 20) & (stocks <= 99)] *0.9\n", + "prices_original = prices[stocks < 20]\n", + "\n", + "# np.concatenate 沿指定軸連接多個陣列\n", + "total_price = np.concatenate([prices_07, prices_09, prices_original])\n", + "total_price\n", + "\n", + " \n", + " " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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 +} diff --git a/homework/m2_pandas_cleaning.ipynb b/homework/m2_pandas_cleaning.ipynb new file mode 100644 index 0000000..bb01c3c --- /dev/null +++ b/homework/m2_pandas_cleaning.ipynb @@ -0,0 +1,502 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "2b540840", + "metadata": {}, + "source": [ + "\"\"\"\n", + "M2 Pandas I/O 與資料清理 — 課後作業\n", + "====================================\n", + "情境:你拿到一份「故意弄髒」的訂單 CSV (orders_raw.csv),\n", + "裡面有欄位名稱空格、金額帶 $ 符號、日期格式錯誤、缺值、重複列。\n", + "請用 Pandas 把它清乾淨。\n", + "\n", + "資料路徑:datasets/ecommerce/orders_raw.csv\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "1b8aaf52", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "id": "07b0ba0c", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🟢 送分題(每題 10 分,共 30 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "fdd659ed", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "<>:7: SyntaxWarning: invalid escape sequence '\\p'\n", + "<>:7: SyntaxWarning: invalid escape sequence '\\p'\n", + "C:\\Users\\highm\\AppData\\Local\\Temp\\ipykernel_7304\\1966798927.py:7: SyntaxWarning: invalid escape sequence '\\p'\n", + " Data = \"D:\\python_workstation\\iSpan_python-DA-cookbooks\\python-da-homework-2026-main\\python-da-homework-2026-main\\datasets\\ecommerce\\orders_raw.csv\"\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", + "
Order_IDcustomer_idProduct_IDqtyorder_dateamount
05064202210264.02025-03-268600
15023202610215.02025-01-051355
25123201310132.02025-09-11$3,538
35118200510281.02025-05-221618
45082202010233.0NaN4431
.....................
2055041201410015.02025-10-038135
2065157200510265.02025-01-0210750
2075134201510125.02025-06-039580
2085135201010074.02025-09-052436
209511320181005NaN2025-08-13870
\n", + "

210 rows × 6 columns

\n", + "
" + ], + "text/plain": [ + " Order_ID customer_id Product_ID qty order_date amount\n", + "0 5064 2022 1026 4.0 2025-03-26 8600\n", + "1 5023 2026 1021 5.0 2025-01-05 1355\n", + "2 5123 2013 1013 2.0 2025-09-11 $3,538\n", + "3 5118 2005 1028 1.0 2025-05-22 1618\n", + "4 5082 2020 1023 3.0 NaN 4431\n", + ".. ... ... ... ... ... ...\n", + "205 5041 2014 1001 5.0 2025-10-03 8135\n", + "206 5157 2005 1026 5.0 2025-01-02 10750\n", + "207 5134 2015 1012 5.0 2025-06-03 9580\n", + "208 5135 2010 1007 4.0 2025-09-05 2436\n", + "209 5113 2018 1005 NaN 2025-08-13 870\n", + "\n", + "[210 rows x 6 columns]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def green_read_csv():\n", + " \"\"\"\n", + " 讀取 orders_raw.csv,回傳原始 DataFrame(不做任何清理)\n", + " 提示:pd.read_csv()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "Data = \"D:\\python_workstation\\iSpan_python-DA-cookbooks\\python-da-homework-2026-main\\python-da-homework-2026-main\\datasets\\ecommerce\\orders_raw.csv\"\n", + "\n", + "raw = pd.read_csv(Data)\n", + "\n", + "raw" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "7377e019", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(210, 6)\n" + ] + } + ], + "source": [ + "def green_shape(df):\n", + " \"\"\"\n", + " 回傳 DataFrame 的 (列數, 欄數) tuple\n", + " 提示:df.shape\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "print(raw.shape)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "4f74c52b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Order_ID int64\n", + "customer_id int64\n", + "Product_ID int64\n", + " qty float64\n", + "order_date str\n", + "amount str\n", + "dtype: object\n" + ] + } + ], + "source": [ + "def green_dtypes(df):\n", + " \"\"\"\n", + " 回傳 DataFrame 的欄位型別 (Series)\n", + " 提示:df.dtypes\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "print(raw.dtypes)" + ] + }, + { + "cell_type": "markdown", + "id": "bd32df6f", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🟡 核心題(每題 15 分,共 45 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "5190a78c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 210 entries, 0 to 209\n", + "Data columns (total 6 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 Order_ID 210 non-null int64 \n", + " 1 customer_id 210 non-null int64 \n", + " 2 Product_ID 210 non-null int64 \n", + " 3 qty 196 non-null float64\n", + " 4 order_date 198 non-null str \n", + " 5 amount 210 non-null str \n", + "dtypes: float64(1), int64(3), str(2)\n", + "memory usage: 10.0 KB\n" + ] + } + ], + "source": [ + "raw.info()" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "92107d78", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['order_id', 'customer_id', 'product_id', 'qty', 'order_date', 'amount']\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "<>:8: SyntaxWarning: invalid escape sequence '\\p'\n", + "<>:8: SyntaxWarning: invalid escape sequence '\\p'\n", + "C:\\Users\\highm\\AppData\\Local\\Temp\\ipykernel_7304\\112280071.py:8: SyntaxWarning: invalid escape sequence '\\p'\n", + " raw = pd.read_csv(\"D:\\python_workstation\\iSpan_python-DA-cookbooks\\python-da-homework-2026-main\\python-da-homework-2026-main\\datasets\\ecommerce\\orders_raw.csv\")\n" + ] + } + ], + "source": [ + "def yellow_clean_columns(df):\n", + " \"\"\"\n", + " 清理欄位名稱:去除前後空白、全部轉小寫\n", + " 回傳清理後的 DataFrame(不要修改原始 df)\n", + " 提示:df.columns.str.strip().str.lower()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "raw = pd.read_csv(\"D:\\python_workstation\\iSpan_python-DA-cookbooks\\python-da-homework-2026-main\\python-da-homework-2026-main\\datasets\\ecommerce\\orders_raw.csv\")\n", + "\n", + "raw.columns = raw.columns.str.strip().str.lower()\n", + "\n", + "print(list(raw.columns))" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "fa52c00b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "float64\n", + "count 210.000000\n", + "mean 3632.457143\n", + "std 2809.327116\n", + "min 157.000000\n", + "25% 1371.750000\n", + "50% 3000.000000\n", + "75% 5748.000000\n", + "max 11980.000000\n", + "Name: amount, dtype: float64\n" + ] + } + ], + "source": [ + "def yellow_clean_amount(df):\n", + " \"\"\"\n", + " 清理 amount 欄位:移除 '$' 和 ',' 符號,轉為 float\n", + " 假設欄位名稱已經是小寫的 'amount'\n", + " 回傳清理後的 DataFrame(不要修改原始 df)\n", + " 提示:.str.replace() + .astype(float)\n", + " \"\"\"\n", + "\n", + "\n", + " # TODO: 你的程式碼\n", + "raw['amount'] = (\n", + " raw['amount']\n", + " .astype(str)\n", + " .str.replace('$', '', regex=False)\n", + " .str.replace(',', '', regex=False)\n", + " .astype(float)\n", + ")\n", + "print(raw['amount'].dtype)\n", + "print(raw['amount'].describe())" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "a5ffaebf", + "metadata": {}, + "outputs": [], + "source": [ + "def yellow_drop_duplicates(df):\n", + " \"\"\"\n", + " 移除完全重複的列,回傳去重後的 DataFrame\n", + " 提示:df.drop_duplicates()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "raw = raw.drop_duplicates()" + ] + }, + { + "cell_type": "markdown", + "id": "0cb924ac", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🔴 挑戰題(25 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "9754ad1b", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "<>:17: SyntaxWarning: invalid escape sequence '\\p'\n", + "<>:17: SyntaxWarning: invalid escape sequence '\\p'\n", + "C:\\Users\\highm\\AppData\\Local\\Temp\\ipykernel_7304\\995615519.py:17: SyntaxWarning: invalid escape sequence '\\p'\n", + " raw = pd.read_csv(\"D:\\python_workstation\\iSpan_python-DA-cookbooks\\python-da-homework-2026-main\\python-da-homework-2026-main\\datasets\\ecommerce\\orders_raw.csv\")\n" + ] + } + ], + "source": [ + "def red_clean_orders(path):\n", + " \"\"\"\n", + " 完整清理 pipeline:一個函式搞定所有清理步驟\n", + " 1. 讀取 CSV\n", + " 2. 欄位名稱:去空白、轉小寫\n", + " 3. amount:移除 '$' ',',轉 float\n", + " 4. order_date:轉為 datetime(無法轉換的設為 NaT)\n", + " 5. 刪除 amount 或 order_date 為空的列\n", + " 6. 移除重複列\n", + "\n", + " 回傳:清理後的 DataFrame\n", + " 提示:pd.to_datetime(errors='coerce')\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + " \n", + "\n", + "raw = pd.read_csv(\"D:\\python_workstation\\iSpan_python-DA-cookbooks\\python-da-homework-2026-main\\python-da-homework-2026-main\\datasets\\ecommerce\\orders_raw.csv\")\n", + "raw.columns = raw.columns.str.strip().str.lower()\n", + "raw['amount'] = (\n", + " raw['amount']\n", + " .astype(str)\n", + " .str.replace('$', '', regex=False)\n", + " .str.replace(',', '', regex=False)\n", + " .astype(float)\n", + ")\n", + "\n", + "raw['order_date'] = pd.to_datetime(raw['order_date'], errors='coerce')\n", + "raw = raw.dropna(subset=['order_date', 'amount'])\n", + "raw = raw.drop_duplicates()\n", + "\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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 +} diff --git a/homework/m3_pandas_advanced.ipynb b/homework/m3_pandas_advanced.ipynb new file mode 100644 index 0000000..0648725 --- /dev/null +++ b/homework/m3_pandas_advanced.ipynb @@ -0,0 +1,867 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "9d185e68", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'\\nM3 Pandas 進階:merge / groupby / RFM — 課後作業\\n=================================================\\n情境:你已經有清理好的訂單資料,現在要合併客戶和商品表,\\n做出有商業價值的分析。\\n\\n資料路徑:\\n - datasets/ecommerce/orders_clean.csv\\n - datasets/ecommerce/customers.csv\\n - datasets/ecommerce/products.csv\\n'" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\"\n", + "M3 Pandas 進階:merge / groupby / RFM — 課後作業\n", + "=================================================\n", + "情境:你已經有清理好的訂單資料,現在要合併客戶和商品表,\n", + "做出有商業價值的分析。\n", + "\n", + "資料路徑:\n", + " - datasets/ecommerce/orders_clean.csv\n", + " - datasets/ecommerce/customers.csv\n", + " - datasets/ecommerce/products.csv\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "88c33281", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n" + ] + }, + { + "cell_type": "markdown", + "id": "3b35b93e", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🟢 送分題(每題 10 分,共 30 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "1a89ec7d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "分析基底: (188, 14)\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", + "
order_idcustomer_nameregionvip_levelproduct_namecategoryamount
05064Victor LinNorthGoldDumbbell 5kgSports8600.0
15023Zoe HuangSouthPlatinumThrow PillowHome1355.0
25123Mia HuangNorthPlatinumCotton T-ShirtClothing3538.0
35118Emma LiuWestBronzeWater BottleSports1618.0
45161Quinn ChenEastSilverCoffee MugHome1846.0
\n", + "
" + ], + "text/plain": [ + " order_id customer_name region vip_level product_name category amount\n", + "0 5064 Victor Lin North Gold Dumbbell 5kg Sports 8600.0\n", + "1 5023 Zoe Huang South Platinum Throw Pillow Home 1355.0\n", + "2 5123 Mia Huang North Platinum Cotton T-Shirt Clothing 3538.0\n", + "3 5118 Emma Liu West Bronze Water Bottle Sports 1618.0\n", + "4 5161 Quinn Chen East Silver Coffee Mug Home 1846.0" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#def green_load_and_merge():\n", + "\n", + "\"\"\"\n", + " 讀取三張表,合併成一張完整的 DataFrame 並回傳\n", + " - orders_clean.csv LEFT JOIN customers.csv ON customer_id\n", + " - 再 LEFT JOIN products.csv ON product_id\n", + " 提示:pd.merge(how='left')\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "\n", + "DATA = '../datasets/ecommerce'\n", + "orders = pd.read_csv(f'{DATA}/orders_clean.csv', parse_dates=['order_date'])\n", + "customers = pd.read_csv(f'{DATA}/customers.csv')\n", + "products = pd.read_csv(f'{DATA}/products.csv')\n", + "\n", + "df = (\n", + " orders\n", + " .merge(customers, on='customer_id', how='left')\n", + " .merge(products, on='product_id', how='left')\n", + ")\n", + "print('分析基底:', df.shape)\n", + "df[['order_id','customer_name','region','vip_level','product_name','category','amount']].head()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "d5d9720b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "188\n" + ] + } + ], + "source": [ + "def green_row_count(df):\n", + " \"\"\"回傳 DataFrame 的列數 (int)\"\"\"\n", + " # TODO: 你的程式碼\n", + "rows = len(df)\n", + "print(rows)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "2007b55b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Index(['order_id', 'customer_id', 'product_id', 'qty', 'order_date', 'amount',\n", + " 'customer_name', 'region', 'signup_date', 'vip_level', 'product_name',\n", + " 'category', 'unit_price', 'stock_qty'],\n", + " dtype='str')" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def green_column_list(df):\n", + " \"\"\"回傳 DataFrame 的所有欄位名稱 (list)\"\"\"\n", + " # TODO: 你的程式碼\n", + "df.columns" + ] + }, + { + "cell_type": "markdown", + "id": "ace602f9", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🟡 核心題(每題 15 分,共 45 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "687fb0c1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "🏆 商品營收排名:\n", + "category\n", + "Books 182244.0\n", + "Sports 176315.0\n", + "Clothing 133841.0\n", + "Electronics 100235.0\n", + "Home 93753.0\n", + "Name: amount, dtype: float64\n" + ] + } + ], + "source": [ + "def yellow_top_category(df):\n", + " \"\"\"\n", + " 哪個商品類別 (category) 的總營收最高?\n", + " 回傳該類別名稱 (str)\n", + " 提示:groupby('category')['amount'].sum()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "cat_rev = df.groupby('category')['amount'].sum().sort_values(ascending=False)\n", + "print('🏆 商品營收排名:')\n", + "print(cat_rev)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "71963f34", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "79\n", + "285982.0\n" + ] + } + ], + "source": [ + "def yellow_gold_vip_stats(df):\n", + " \"\"\"\n", + " Gold VIP 客戶總共下了幾張訂單?總金額多少?\n", + " 回傳 tuple: (訂單數 int, 總金額 float)\n", + " 提示:df[df['vip_level'] == 'Gold']\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "#篩選出gold 客戶資料\n", + "vip_gold = df[df['vip_level'] == 'Gold']\n", + "#vip gold 訂單數量\n", + "gold_rows = len(vip_gold)\n", + "print(gold_rows) #79\n", + "\n", + "#總金額\n", + "vip_gold_total_rev = vip_gold['amount'].sum()\n", + "print(vip_gold_total_rev)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "53796a3e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "region\n", + "East 3318.000000\n", + "North 3738.044776\n", + "South 3786.152778\n", + "West 3340.848485\n", + "Name: amount, dtype: float64\n" + ] + } + ], + "source": [ + "def yellow_region_avg_amount(df):\n", + " \"\"\"\n", + " 計算每個地區 (region) 的平均訂單金額\n", + " 回傳 Series(index=region, values=平均金額)\n", + " 提示:groupby('region')['amount'].mean()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "df\n", + "avg_region_rev = df.groupby('region')['amount'].mean()\n", + "print(avg_region_rev)" + ] + }, + { + "cell_type": "markdown", + "id": "f349baf0", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🔴 挑戰題(25 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "6a3b95c2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2026-04-30 23:46:09.133630\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", + "
customer_idcustomer_nameRecencyFrequencyMonetary
customer_id
2001367Alice Chen367316095.0
2002483Bob Wang483716211.0
2003469Carol Huang4691023007.0
2004463David Chen463739085.0
2005483Emma Liu483834917.0
\n", + "
" + ], + "text/plain": [ + " customer_id customer_name Recency Frequency Monetary\n", + "customer_id \n", + "2001 367 Alice Chen 367 3 16095.0\n", + "2002 483 Bob Wang 483 7 16211.0\n", + "2003 469 Carol Huang 469 10 23007.0\n", + "2004 463 David Chen 463 7 39085.0\n", + "2005 483 Emma Liu 483 8 34917.0" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def red_rfm_top5(df):\n", + " \"\"\"\n", + " RFM 分析:找出最有價值的前 5 位客戶\n", + "\n", + " 計算每位客戶的:\n", + " - R (Recency):最近一次下單日期\n", + " - F (Frequency):訂單總數\n", + " - M (Monetary):消費總金額\n", + "\n", + " 回傳 DataFrame:\n", + " - 欄位:customer_id, customer_name, R, F, M\n", + " - 按 M 由大到小排序\n", + " - 只取前 5 筆\n", + "\n", + " 提示:groupby('customer_id').agg(...)\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "import pandas as pd\n", + "import time \n", + "from datetime import datetime #常與dataframe 搭配使用\n", + " #現在時間\n", + "now = time.strftime(\"%Y-%m-%d\", time.localtime())\n", + "now = datetime.now()\n", + "print(now)\n", + " #從現在到orderdate的距離\n", + "df['date_diff'] = (now-df[\"order_date\"]).dt.days\n", + "\n", + "#recency : 最近一次下單:取天數最少的\n", + "recency = df.groupby(\"customer_id\")[\"date_diff\"].max()\n", + "\n", + " #frequency : 購買頻率\n", + "frequency = df.groupby(\"customer_id\")[\"order_id\"].count()\n", + "\n", + " #Monetary : 總金額\n", + "monetary = df.groupby(\"customer_id\")[\"amount\"].sum() \n", + "\n", + "names = df.groupby(\"customer_id\")[\"customer_name\"].first()\n", + " \n", + "\n", + "\n", + "df_RFM = pd.DataFrame({\n", + " 'customer_id':recency,\n", + " 'customer_name':names,\n", + " 'Recency': recency,\n", + " 'Frequency': frequency,\n", + " 'Monetary': monetary\n", + " })\n", + "\n", + "df_RFM.head()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e2fbaa41", + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \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_idcustomer_idproduct_idqtyorder_dateamountcustomer_nameregionsignup_datevip_levelproduct_namecategoryunit_pricestock_qtyrecencyfrequencymonetary
05064202210264.02025-03-268600.0Victor LinNorth2023-02-27GoldDumbbell 5kgSports215051400 days 23:05:54.249586NaNNaN
15023202610215.02025-01-051355.0Zoe HuangSouth2023-05-16PlatinumThrow PillowHome271150480 days 23:05:54.249586NaNNaN
25123201310132.02025-09-113538.0Mia HuangNorth2023-07-17PlatinumCotton T-ShirtClothing1769174231 days 23:05:54.249586NaNNaN
35118200510281.02025-05-221618.0Emma LiuWest2023-05-18BronzeWater BottleSports1618186343 days 23:05:54.249586NaNNaN
45161201710193.02025-08-201846.0Quinn ChenEast2023-08-11SilverCoffee MugHome1846274253 days 23:05:54.249586NaNNaN
......................................................
1835094202610193.02025-02-135538.0Zoe HuangSouth2023-05-16PlatinumCoffee MugHome1846274441 days 23:05:54.249586NaNNaN
1845041201410015.02025-10-038135.0Nick HuangWest2023-09-28GoldWireless MouseElectronics162712209 days 23:05:54.249586NaNNaN
1855157200510265.02025-01-0210750.0Emma LiuWest2023-05-18BronzeDumbbell 5kgSports215051483 days 23:05:54.249586NaNNaN
1865134201510125.02025-06-039580.0Olivia HuangNorth2023-12-15BronzeClean CodeBooks191681331 days 23:05:54.249586NaNNaN
1875135201010074.02025-09-052436.0Jack LiuSouth2023-03-12PlatinumPython CookbookBooks609258237 days 23:05:54.249586NaNNaN
\n", + "

188 rows × 17 columns

\n", + "
" + ], + "text/plain": [ + " order_id customer_id product_id qty order_date amount customer_name \\\n", + "0 5064 2022 1026 4.0 2025-03-26 8600.0 Victor Lin \n", + "1 5023 2026 1021 5.0 2025-01-05 1355.0 Zoe Huang \n", + "2 5123 2013 1013 2.0 2025-09-11 3538.0 Mia Huang \n", + "3 5118 2005 1028 1.0 2025-05-22 1618.0 Emma Liu \n", + "4 5161 2017 1019 3.0 2025-08-20 1846.0 Quinn Chen \n", + ".. ... ... ... ... ... ... ... \n", + "183 5094 2026 1019 3.0 2025-02-13 5538.0 Zoe Huang \n", + "184 5041 2014 1001 5.0 2025-10-03 8135.0 Nick Huang \n", + "185 5157 2005 1026 5.0 2025-01-02 10750.0 Emma Liu \n", + "186 5134 2015 1012 5.0 2025-06-03 9580.0 Olivia Huang \n", + "187 5135 2010 1007 4.0 2025-09-05 2436.0 Jack Liu \n", + "\n", + " region signup_date vip_level product_name category unit_price \\\n", + "0 North 2023-02-27 Gold Dumbbell 5kg Sports 2150 \n", + "1 South 2023-05-16 Platinum Throw Pillow Home 271 \n", + "2 North 2023-07-17 Platinum Cotton T-Shirt Clothing 1769 \n", + "3 West 2023-05-18 Bronze Water Bottle Sports 1618 \n", + "4 East 2023-08-11 Silver Coffee Mug Home 1846 \n", + ".. ... ... ... ... ... ... \n", + "183 South 2023-05-16 Platinum Coffee Mug Home 1846 \n", + "184 West 2023-09-28 Gold Wireless Mouse Electronics 1627 \n", + "185 West 2023-05-18 Bronze Dumbbell 5kg Sports 2150 \n", + "186 North 2023-12-15 Bronze Clean Code Books 1916 \n", + "187 South 2023-03-12 Platinum Python Cookbook Books 609 \n", + "\n", + " stock_qty recency frequency monetary \n", + "0 51 400 days 23:05:54.249586 NaN NaN \n", + "1 150 480 days 23:05:54.249586 NaN NaN \n", + "2 174 231 days 23:05:54.249586 NaN NaN \n", + "3 186 343 days 23:05:54.249586 NaN NaN \n", + "4 274 253 days 23:05:54.249586 NaN NaN \n", + ".. ... ... ... ... \n", + "183 274 441 days 23:05:54.249586 NaN NaN \n", + "184 12 209 days 23:05:54.249586 NaN NaN \n", + "185 51 483 days 23:05:54.249586 NaN NaN \n", + "186 81 331 days 23:05:54.249586 NaN NaN \n", + "187 258 237 days 23:05:54.249586 NaN NaN \n", + "\n", + "[188 rows x 17 columns]" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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 +} diff --git a/homework/m4_timesseries.ipynb b/homework/m4_timesseries.ipynb new file mode 100644 index 0000000..ddf7bdf --- /dev/null +++ b/homework/m4_timesseries.ipynb @@ -0,0 +1,1114 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "3c9278cc", + "metadata": {}, + "source": [ + "\"\"\"\n", + "M4 時間序列與 EDA — 課後作業\n", + "==============================\n", + "情境:用合併好的訂單資料做時間維度分析,\n", + "產出月報級別的商業洞察。\n", + "\n", + "資料路徑:datasets/ecommerce/orders_enriched.csv\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "042451b9", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "1e06f9ed", + "metadata": {}, + "outputs": [], + "source": [ + "def _load_data():\n", + " \"\"\"輔助函式:讀取並解析日期\"\"\"\n", + " df = pd.read_csv(\"datasets/ecommerce/orders_enriched.csv\",\n", + " parse_dates=[\"order_date\"])\n", + " return df\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "0ca331b5", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🟢 送分題(每題 10 分,共 30 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2c2232f4", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "<>:1: SyntaxWarning: invalid escape sequence '\\p'\n", + "<>:1: SyntaxWarning: invalid escape sequence '\\p'\n", + "C:\\Users\\highm\\AppData\\Local\\Temp\\ipykernel_6616\\2792110316.py:1: SyntaxWarning: invalid escape sequence '\\p'\n", + " df = pd.read_csv(\"D:\\python_workstation\\iSpan_python-DA-cookbooks\\python-da-homework-2026-main\\python-da-homework-2026-main\\datasets\\ecommerce\\orders_enriched.csv\",\n" + ] + } + ], + "source": [ + "df = pd.read_csv(\"D:\\python_workstation\\iSpan_python-DA-cookbooks\\python-da-homework-2026-main\\python-da-homework-2026-main\\datasets\\ecommerce\\orders_enriched.csv\",\n", + " parse_dates=[\"order_date\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "b0893963", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "RangeIndex: 188 entries, 0 to 187\n", + "Data columns (total 14 columns):\n", + " # Column Non-Null Count Dtype \n", + "--- ------ -------------- ----- \n", + " 0 order_id 188 non-null int64 \n", + " 1 customer_id 188 non-null int64 \n", + " 2 product_id 188 non-null int64 \n", + " 3 qty 188 non-null float64 \n", + " 4 order_date 188 non-null datetime64[us]\n", + " 5 amount 188 non-null float64 \n", + " 6 customer_name 188 non-null str \n", + " 7 region 188 non-null str \n", + " 8 signup_date 188 non-null str \n", + " 9 vip_level 188 non-null str \n", + " 10 product_name 188 non-null str \n", + " 11 category 188 non-null str \n", + " 12 unit_price 188 non-null int64 \n", + " 13 stock_qty 188 non-null int64 \n", + "dtypes: datetime64[us](1), float64(2), int64(5), str(6)\n", + "memory usage: 20.7 KB\n" + ] + } + ], + "source": [ + "df.info()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "24c10b10", + "metadata": {}, + "outputs": [], + "source": [ + "#df.set_index('order_date', inplace=True)\n", + "#df" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "8f3d7a39", + "metadata": {}, + "outputs": [], + "source": [ + "def green_avg_by_month():\n", + " \"\"\"\n", + " 計算每個月份 (1~12) 的平均訂單金額\n", + " 回傳 Series(index=月份 1~12, values=平均金額)\n", + " 提示:df['order_date'].dt.month\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "\n", + " df['month'] = df['order_date'].dt.month\n", + "\n", + " monthly_avg = df.groupby('month')['amount'].mean()\n", + "\n", + " return monthly_avg\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "3d632ea8", + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \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_idcustomer_idproduct_idqtyorder_dateamountcustomer_nameregionsignup_datevip_levelproduct_namecategoryunit_pricestock_qty
05064202210264.02025-03-268600.0Victor LinNorth2023-02-27GoldDumbbell 5kgSports215051
15023202610215.02025-01-051355.0Zoe HuangSouth2023-05-16PlatinumThrow PillowHome271150
25123201310132.02025-09-113538.0Mia HuangNorth2023-07-17PlatinumCotton T-ShirtClothing1769174
35118200510281.02025-05-221618.0Emma LiuWest2023-05-18BronzeWater BottleSports1618186
45161201710193.02025-08-201846.0Quinn ChenEast2023-08-11SilverCoffee MugHome1846274
.............................................
1835094202610193.02025-02-135538.0Zoe HuangSouth2023-05-16PlatinumCoffee MugHome1846274
1845041201410015.02025-10-038135.0Nick HuangWest2023-09-28GoldWireless MouseElectronics162712
1855157200510265.02025-01-0210750.0Emma LiuWest2023-05-18BronzeDumbbell 5kgSports215051
1865134201510125.02025-06-039580.0Olivia HuangNorth2023-12-15BronzeClean CodeBooks191681
1875135201010074.02025-09-052436.0Jack LiuSouth2023-03-12PlatinumPython CookbookBooks609258
\n", + "

188 rows × 14 columns

\n", + "
" + ], + "text/plain": [ + " order_id customer_id product_id qty order_date amount customer_name \\\n", + "0 5064 2022 1026 4.0 2025-03-26 8600.0 Victor Lin \n", + "1 5023 2026 1021 5.0 2025-01-05 1355.0 Zoe Huang \n", + "2 5123 2013 1013 2.0 2025-09-11 3538.0 Mia Huang \n", + "3 5118 2005 1028 1.0 2025-05-22 1618.0 Emma Liu \n", + "4 5161 2017 1019 3.0 2025-08-20 1846.0 Quinn Chen \n", + ".. ... ... ... ... ... ... ... \n", + "183 5094 2026 1019 3.0 2025-02-13 5538.0 Zoe Huang \n", + "184 5041 2014 1001 5.0 2025-10-03 8135.0 Nick Huang \n", + "185 5157 2005 1026 5.0 2025-01-02 10750.0 Emma Liu \n", + "186 5134 2015 1012 5.0 2025-06-03 9580.0 Olivia Huang \n", + "187 5135 2010 1007 4.0 2025-09-05 2436.0 Jack Liu \n", + "\n", + " region signup_date vip_level product_name category unit_price \\\n", + "0 North 2023-02-27 Gold Dumbbell 5kg Sports 2150 \n", + "1 South 2023-05-16 Platinum Throw Pillow Home 271 \n", + "2 North 2023-07-17 Platinum Cotton T-Shirt Clothing 1769 \n", + "3 West 2023-05-18 Bronze Water Bottle Sports 1618 \n", + "4 East 2023-08-11 Silver Coffee Mug Home 1846 \n", + ".. ... ... ... ... ... ... \n", + "183 South 2023-05-16 Platinum Coffee Mug Home 1846 \n", + "184 West 2023-09-28 Gold Wireless Mouse Electronics 1627 \n", + "185 West 2023-05-18 Bronze Dumbbell 5kg Sports 2150 \n", + "186 North 2023-12-15 Bronze Clean Code Books 1916 \n", + "187 South 2023-03-12 Platinum Python Cookbook Books 609 \n", + "\n", + " stock_qty \n", + "0 51 \n", + "1 150 \n", + "2 174 \n", + "3 186 \n", + "4 274 \n", + ".. ... \n", + "183 274 \n", + "184 12 \n", + "185 51 \n", + "186 81 \n", + "187 258 \n", + "\n", + "[188 rows x 14 columns]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "7fc18072", + "metadata": {}, + "outputs": [], + "source": [ + "def green_top3_dates():\n", + " \"\"\"\n", + " 找出訂單數最多的前 3 個日期\n", + " 回傳 Series(index=日期, values=訂單數, 由多到少排序)\n", + " 提示:value_counts().head(3)\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + " ts['order_id'].resample('D').count().sort_values(ascending =False).head(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "4ac19c7d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 2025-03-26\n", + "1 2025-01-05\n", + "2 2025-09-11\n", + "3 2025-05-22\n", + "4 2025-08-20\n", + " ... \n", + "183 2025-02-13\n", + "184 2025-10-03\n", + "185 2025-01-02\n", + "186 2025-06-03\n", + "187 2025-09-05\n", + "Name: order_date, Length: 188, dtype: datetime64[us]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def green_date_range():\n", + " \"\"\"\n", + " 回傳資料的日期範圍 tuple: (最早日期, 最晚日期)\n", + " 格式為 pandas Timestamp\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "\n", + "df['order_date']" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "eca9de71", + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \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_idcustomer_idproduct_idqtyorder_dateamountcustomer_nameregionsignup_datevip_levelproduct_namecategoryunit_pricestock_qty
05064202210264.02025-03-268600.0Victor LinNorth2023-02-27GoldDumbbell 5kgSports215051
15023202610215.02025-01-051355.0Zoe HuangSouth2023-05-16PlatinumThrow PillowHome271150
25123201310132.02025-09-113538.0Mia HuangNorth2023-07-17PlatinumCotton T-ShirtClothing1769174
35118200510281.02025-05-221618.0Emma LiuWest2023-05-18BronzeWater BottleSports1618186
45161201710193.02025-08-201846.0Quinn ChenEast2023-08-11SilverCoffee MugHome1846274
.............................................
1835094202610193.02025-02-135538.0Zoe HuangSouth2023-05-16PlatinumCoffee MugHome1846274
1845041201410015.02025-10-038135.0Nick HuangWest2023-09-28GoldWireless MouseElectronics162712
1855157200510265.02025-01-0210750.0Emma LiuWest2023-05-18BronzeDumbbell 5kgSports215051
1865134201510125.02025-06-039580.0Olivia HuangNorth2023-12-15BronzeClean CodeBooks191681
1875135201010074.02025-09-052436.0Jack LiuSouth2023-03-12PlatinumPython CookbookBooks609258
\n", + "

188 rows × 14 columns

\n", + "
" + ], + "text/plain": [ + " order_id customer_id product_id qty order_date amount customer_name \\\n", + "0 5064 2022 1026 4.0 2025-03-26 8600.0 Victor Lin \n", + "1 5023 2026 1021 5.0 2025-01-05 1355.0 Zoe Huang \n", + "2 5123 2013 1013 2.0 2025-09-11 3538.0 Mia Huang \n", + "3 5118 2005 1028 1.0 2025-05-22 1618.0 Emma Liu \n", + "4 5161 2017 1019 3.0 2025-08-20 1846.0 Quinn Chen \n", + ".. ... ... ... ... ... ... ... \n", + "183 5094 2026 1019 3.0 2025-02-13 5538.0 Zoe Huang \n", + "184 5041 2014 1001 5.0 2025-10-03 8135.0 Nick Huang \n", + "185 5157 2005 1026 5.0 2025-01-02 10750.0 Emma Liu \n", + "186 5134 2015 1012 5.0 2025-06-03 9580.0 Olivia Huang \n", + "187 5135 2010 1007 4.0 2025-09-05 2436.0 Jack Liu \n", + "\n", + " region signup_date vip_level product_name category unit_price \\\n", + "0 North 2023-02-27 Gold Dumbbell 5kg Sports 2150 \n", + "1 South 2023-05-16 Platinum Throw Pillow Home 271 \n", + "2 North 2023-07-17 Platinum Cotton T-Shirt Clothing 1769 \n", + "3 West 2023-05-18 Bronze Water Bottle Sports 1618 \n", + "4 East 2023-08-11 Silver Coffee Mug Home 1846 \n", + ".. ... ... ... ... ... ... \n", + "183 South 2023-05-16 Platinum Coffee Mug Home 1846 \n", + "184 West 2023-09-28 Gold Wireless Mouse Electronics 1627 \n", + "185 West 2023-05-18 Bronze Dumbbell 5kg Sports 2150 \n", + "186 North 2023-12-15 Bronze Clean Code Books 1916 \n", + "187 South 2023-03-12 Platinum Python Cookbook Books 609 \n", + "\n", + " stock_qty \n", + "0 51 \n", + "1 150 \n", + "2 174 \n", + "3 186 \n", + "4 274 \n", + ".. ... \n", + "183 274 \n", + "184 12 \n", + "185 51 \n", + "186 81 \n", + "187 258 \n", + "\n", + "[188 rows x 14 columns]" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "markdown", + "id": "583a167a", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🟡 核心題(每題 15 分,共 45 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "3693a203", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "order_date\n", + "2025-01-31 60062.0\n", + "2025-02-28 72367.0\n", + "2025-03-31 55920.0\n", + "2025-04-30 58506.0\n", + "2025-05-31 47879.0\n", + "2025-06-30 50901.0\n", + "2025-07-31 40796.0\n", + "2025-08-31 62706.0\n", + "2025-09-30 50745.0\n", + "2025-10-31 74376.0\n", + "2025-11-30 62533.0\n", + "2025-12-31 49597.0\n", + "Freq: ME, Name: amount, dtype: float64\n" + ] + } + ], + "source": [ + "def yellow_monthly_revenue():\n", + " \"\"\"\n", + " 計算每月總營收\n", + " 回傳 Series(index=月底日期 period, values=總營收)\n", + " 提示:set_index('order_date').resample('ME')['amount'].sum()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "ts = df.set_index('order_date').sort_index()\n", + "\n", + "monthly = ts['amount'].resample('ME').sum()\n", + "print(monthly)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "e3efd8a4", + "metadata": {}, + "outputs": [], + "source": [ + "def yellow_rolling_avg(monthly_revenue):\n", + " \"\"\"\n", + " 計算 3 個月移動平均\n", + " 接收 yellow_monthly_revenue() 的結果作為輸入\n", + " 回傳 Series(同樣 index,values=移動平均,前 2 筆可為 NaN)\n", + " 提示:.rolling(window=3).mean()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + " monthly_revenue = yellow_monthly_revenue()\n", + " three_months_avg = monthly_revenue.rolling(window=3).mean().head(15)\n", + " return three_months_avg\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "888c8800", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "category\n", + "Books 4141.909091\n", + "Sports 4100.348837\n", + "Clothing 3431.820513\n", + "Electronics 3233.387097\n", + "Home 3024.290323\n", + "Name: amount, dtype: float64\n" + ] + } + ], + "source": [ + "#def yellow_category_median(df):\n", + "\"\"\"\n", + "計算每個商品類別 (category) 的訂單金額中位數,由高到低排序\n", + "回傳 Series(index=category, values=中位數)\n", + "提示:groupby + median + sort_values\n", + "\"\"\"\n", + " # TODO: 你的程式碼\n", + "df['month'] = df['order_date'].dt.month\n", + "\n", + "monthly_avg = df.groupby('category')['amount'].mean().sort_values(ascending =False)\n", + "\n", + "print(monthly_avg)" + ] + }, + { + "cell_type": "markdown", + "id": "176708aa", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🔴 挑戰題(25 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3837604", + "metadata": {}, + "outputs": [], + "source": [ + "def red_monthly_report():\n", + " \"\"\"\n", + " 產出月報 DataFrame,每月一列,包含:\n", + " - order_count:當月訂單數\n", + " - revenue:當月總營收\n", + " - active_customers:當月不重複客戶數\n", + " - avg_order_value:客單價(revenue / order_count)\n", + " - revenue_growth:月營收成長率(相對上月的 % 變化)\n", + "\n", + " index 為月份 (period 或 datetime)\n", + " 提示:resample + agg + pct_change\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + " pass\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "b925fe46", + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \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_idcustomer_idproduct_idqtyorder_dateamountcustomer_nameregionsignup_datevip_levelproduct_namecategoryunit_pricestock_qtymonth
05064202210264.02025-03-268600.0Victor LinNorth2023-02-27GoldDumbbell 5kgSports2150513
15023202610215.02025-01-051355.0Zoe HuangSouth2023-05-16PlatinumThrow PillowHome2711501
25123201310132.02025-09-113538.0Mia HuangNorth2023-07-17PlatinumCotton T-ShirtClothing17691749
35118200510281.02025-05-221618.0Emma LiuWest2023-05-18BronzeWater BottleSports16181865
45161201710193.02025-08-201846.0Quinn ChenEast2023-08-11SilverCoffee MugHome18462748
\n", + "
" + ], + "text/plain": [ + " order_id customer_id product_id qty order_date amount customer_name \\\n", + "0 5064 2022 1026 4.0 2025-03-26 8600.0 Victor Lin \n", + "1 5023 2026 1021 5.0 2025-01-05 1355.0 Zoe Huang \n", + "2 5123 2013 1013 2.0 2025-09-11 3538.0 Mia Huang \n", + "3 5118 2005 1028 1.0 2025-05-22 1618.0 Emma Liu \n", + "4 5161 2017 1019 3.0 2025-08-20 1846.0 Quinn Chen \n", + "\n", + " region signup_date vip_level product_name category unit_price \\\n", + "0 North 2023-02-27 Gold Dumbbell 5kg Sports 2150 \n", + "1 South 2023-05-16 Platinum Throw Pillow Home 271 \n", + "2 North 2023-07-17 Platinum Cotton T-Shirt Clothing 1769 \n", + "3 West 2023-05-18 Bronze Water Bottle Sports 1618 \n", + "4 East 2023-08-11 Silver Coffee Mug Home 1846 \n", + "\n", + " stock_qty month \n", + "0 51 3 \n", + "1 150 1 \n", + "2 174 9 \n", + "3 186 5 \n", + "4 274 8 " + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.head()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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 +} diff --git a/homework/m5_visualization.ipynb b/homework/m5_visualization.ipynb new file mode 100644 index 0000000..ced4a3f --- /dev/null +++ b/homework/m5_visualization.ipynb @@ -0,0 +1,1306 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "62f97bb9", + "metadata": {}, + "source": [ + "\"\"\"\n", + "M5 Matplotlib & Seaborn 視覺化 — 課後作業\n", + "==========================================\n", + "情境:把分析結果做成圖表,用視覺化說故事。\n", + "\n", + "資料路徑:datasets/ecommerce/orders_enriched.csv\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "cf3332fe", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib\n", + "matplotlib.use(\"Agg\") # 無 GUI 環境也能跑\n", + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "import seaborn as sns" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "0097f7dd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "資料形狀: (188, 15)\n" + ] + } + ], + "source": [ + "def _load_data():\n", + " \"\"\"輔助函式:讀取資料\"\"\"\n", + "plt.rcParams['axes.unicode_minus'] = False\n", + "sns.set_theme(style='whitegrid')\n", + "\n", + "df = pd.read_csv(\n", + " '../datasets/ecommerce/orders_enriched.csv',\n", + " parse_dates=['order_date'],\n", + ")\n", + "df['month'] = df['order_date'].dt.to_period('M').astype(str)\n", + "print('資料形狀:', df.shape)" + ] + }, + { + "cell_type": "markdown", + "id": "0e70527a", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🟢 送分題(每題 10 分,共 30 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "be6ddbb6", + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \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_idcustomer_idproduct_idqtyorder_dateamountcustomer_nameregionsignup_datevip_levelproduct_namecategoryunit_pricestock_qtymonth
05064202210264.02025-03-268600.0Victor LinNorth2023-02-27GoldDumbbell 5kgSports2150512025-03
15023202610215.02025-01-051355.0Zoe HuangSouth2023-05-16PlatinumThrow PillowHome2711502025-01
25123201310132.02025-09-113538.0Mia HuangNorth2023-07-17PlatinumCotton T-ShirtClothing17691742025-09
35118200510281.02025-05-221618.0Emma LiuWest2023-05-18BronzeWater BottleSports16181862025-05
45161201710193.02025-08-201846.0Quinn ChenEast2023-08-11SilverCoffee MugHome18462742025-08
................................................
1835094202610193.02025-02-135538.0Zoe HuangSouth2023-05-16PlatinumCoffee MugHome18462742025-02
1845041201410015.02025-10-038135.0Nick HuangWest2023-09-28GoldWireless MouseElectronics1627122025-10
1855157200510265.02025-01-0210750.0Emma LiuWest2023-05-18BronzeDumbbell 5kgSports2150512025-01
1865134201510125.02025-06-039580.0Olivia HuangNorth2023-12-15BronzeClean CodeBooks1916812025-06
1875135201010074.02025-09-052436.0Jack LiuSouth2023-03-12PlatinumPython CookbookBooks6092582025-09
\n", + "

188 rows × 15 columns

\n", + "
" + ], + "text/plain": [ + " order_id customer_id product_id qty order_date amount customer_name \\\n", + "0 5064 2022 1026 4.0 2025-03-26 8600.0 Victor Lin \n", + "1 5023 2026 1021 5.0 2025-01-05 1355.0 Zoe Huang \n", + "2 5123 2013 1013 2.0 2025-09-11 3538.0 Mia Huang \n", + "3 5118 2005 1028 1.0 2025-05-22 1618.0 Emma Liu \n", + "4 5161 2017 1019 3.0 2025-08-20 1846.0 Quinn Chen \n", + ".. ... ... ... ... ... ... ... \n", + "183 5094 2026 1019 3.0 2025-02-13 5538.0 Zoe Huang \n", + "184 5041 2014 1001 5.0 2025-10-03 8135.0 Nick Huang \n", + "185 5157 2005 1026 5.0 2025-01-02 10750.0 Emma Liu \n", + "186 5134 2015 1012 5.0 2025-06-03 9580.0 Olivia Huang \n", + "187 5135 2010 1007 4.0 2025-09-05 2436.0 Jack Liu \n", + "\n", + " region signup_date vip_level product_name category unit_price \\\n", + "0 North 2023-02-27 Gold Dumbbell 5kg Sports 2150 \n", + "1 South 2023-05-16 Platinum Throw Pillow Home 271 \n", + "2 North 2023-07-17 Platinum Cotton T-Shirt Clothing 1769 \n", + "3 West 2023-05-18 Bronze Water Bottle Sports 1618 \n", + "4 East 2023-08-11 Silver Coffee Mug Home 1846 \n", + ".. ... ... ... ... ... ... \n", + "183 South 2023-05-16 Platinum Coffee Mug Home 1846 \n", + "184 West 2023-09-28 Gold Wireless Mouse Electronics 1627 \n", + "185 West 2023-05-18 Bronze Dumbbell 5kg Sports 2150 \n", + "186 North 2023-12-15 Bronze Clean Code Books 1916 \n", + "187 South 2023-03-12 Platinum Python Cookbook Books 609 \n", + "\n", + " stock_qty month \n", + "0 51 2025-03 \n", + "1 150 2025-01 \n", + "2 174 2025-09 \n", + "3 186 2025-05 \n", + "4 274 2025-08 \n", + ".. ... ... \n", + "183 274 2025-02 \n", + "184 12 2025-10 \n", + "185 51 2025-01 \n", + "186 81 2025-06 \n", + "187 258 2025-09 \n", + "\n", + "[188 rows x 15 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "4b4e778c", + "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", + "
categoryamount
0Books182244.0
1Clothing133841.0
2Electronics100235.0
3Home93753.0
4Sports176315.0
\n", + "
" + ], + "text/plain": [ + " category amount\n", + "0 Books 182244.0\n", + "1 Clothing 133841.0\n", + "2 Electronics 100235.0\n", + "3 Home 93753.0\n", + "4 Sports 176315.0" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "product_order = df.groupby('category')['amount'].sum().reset_index()\n", + "product_order" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "1f913cc3", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib\n", + "matplotlib.use('TkAgg')\n", + "import matplotlib.pyplot as plt\n", + "#def green_bar_category():\n", + "\"\"\"\n", + "畫出每個商品類別 (category) 的訂單數長條圖\n", + "回傳 matplotlib Figure 物件\n", + "提示:sns.countplot 或 value_counts().plot.bar()\n", + "\"\"\"\n", + "# TODO: 你的程式碼\n", + "product_order = df.groupby('category')['stock_qty'].count().reset_index()\n", + "fig = plt.figure(figsize=(8, 4)) #開空畫布\n", + "sns.countplot(data=df, x='category', palette='viridis', hue='category', legend=False)\n", + "plt.title('order count by category')\n", + "\n", + "\n", + "\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "f0beaaeb", + "metadata": {}, + "outputs": [], + "source": [ + "def green_hist_amount():\n", + " \"\"\"\n", + " 畫出訂單金額 (amount) 的分佈直方圖,分 20 個 bin\n", + " 回傳 matplotlib Figure 物件\n", + " 提示:sns.histplot(bins=20) 或 plt.hist()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "c2b1f30d", + "metadata": {}, + "outputs": [], + "source": [ + "#def green_set_labels():\n", + "\"\"\"\n", + "建立一個簡單的長條圖(內容不限),但必須設定:\n", + "- 圖標題 (title)\n", + "- X 軸標籤 (xlabel)\n", + "- Y 軸標籤 (ylabel)\n", + "回傳 matplotlib Figure 物件\n", + "\"\"\"\n", + " # TODO: 你的程式碼\n", + "region_rev = df.groupby('region')['amount'].sum().sort_values(ascending=False).reset_index()\n", + "plt.figure(figsize=(8, 4)) #開空畫布\n", + "sns.barplot(data=region_rev, x='region', y='amount', palette='viridis', hue='region', legend=False)\n", + "plt.title('Revenue by Region', fontweight='bold')\n", + "plt.xlabel('Region')\n", + "plt.ylabel('Revenue (NT$)')\n", + "\n", + "# 在柱子上標數字\n", + "for i, v in enumerate(region_rev['amount']):\n", + " plt.text(i, v, f'{v:,.0f}', ha='center', va='bottom', fontsize=10)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "535cec10", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🟡 核心題(每題 15 分,共 45 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "0f2e6c4c", + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \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_idcustomer_idproduct_idqtyorder_dateamountcustomer_nameregionsignup_datevip_levelproduct_namecategoryunit_pricestock_qtymonth
05064202210264.02025-03-268600.0Victor LinNorth2023-02-27GoldDumbbell 5kgSports2150512025-03
15023202610215.02025-01-051355.0Zoe HuangSouth2023-05-16PlatinumThrow PillowHome2711502025-01
25123201310132.02025-09-113538.0Mia HuangNorth2023-07-17PlatinumCotton T-ShirtClothing17691742025-09
35118200510281.02025-05-221618.0Emma LiuWest2023-05-18BronzeWater BottleSports16181862025-05
45161201710193.02025-08-201846.0Quinn ChenEast2023-08-11SilverCoffee MugHome18462742025-08
................................................
1835094202610193.02025-02-135538.0Zoe HuangSouth2023-05-16PlatinumCoffee MugHome18462742025-02
1845041201410015.02025-10-038135.0Nick HuangWest2023-09-28GoldWireless MouseElectronics1627122025-10
1855157200510265.02025-01-0210750.0Emma LiuWest2023-05-18BronzeDumbbell 5kgSports2150512025-01
1865134201510125.02025-06-039580.0Olivia HuangNorth2023-12-15BronzeClean CodeBooks1916812025-06
1875135201010074.02025-09-052436.0Jack LiuSouth2023-03-12PlatinumPython CookbookBooks6092582025-09
\n", + "

188 rows × 15 columns

\n", + "
" + ], + "text/plain": [ + " order_id customer_id product_id qty order_date amount customer_name \\\n", + "0 5064 2022 1026 4.0 2025-03-26 8600.0 Victor Lin \n", + "1 5023 2026 1021 5.0 2025-01-05 1355.0 Zoe Huang \n", + "2 5123 2013 1013 2.0 2025-09-11 3538.0 Mia Huang \n", + "3 5118 2005 1028 1.0 2025-05-22 1618.0 Emma Liu \n", + "4 5161 2017 1019 3.0 2025-08-20 1846.0 Quinn Chen \n", + ".. ... ... ... ... ... ... ... \n", + "183 5094 2026 1019 3.0 2025-02-13 5538.0 Zoe Huang \n", + "184 5041 2014 1001 5.0 2025-10-03 8135.0 Nick Huang \n", + "185 5157 2005 1026 5.0 2025-01-02 10750.0 Emma Liu \n", + "186 5134 2015 1012 5.0 2025-06-03 9580.0 Olivia Huang \n", + "187 5135 2010 1007 4.0 2025-09-05 2436.0 Jack Liu \n", + "\n", + " region signup_date vip_level product_name category unit_price \\\n", + "0 North 2023-02-27 Gold Dumbbell 5kg Sports 2150 \n", + "1 South 2023-05-16 Platinum Throw Pillow Home 271 \n", + "2 North 2023-07-17 Platinum Cotton T-Shirt Clothing 1769 \n", + "3 West 2023-05-18 Bronze Water Bottle Sports 1618 \n", + "4 East 2023-08-11 Silver Coffee Mug Home 1846 \n", + ".. ... ... ... ... ... ... \n", + "183 South 2023-05-16 Platinum Coffee Mug Home 1846 \n", + "184 West 2023-09-28 Gold Wireless Mouse Electronics 1627 \n", + "185 West 2023-05-18 Bronze Dumbbell 5kg Sports 2150 \n", + "186 North 2023-12-15 Bronze Clean Code Books 1916 \n", + "187 South 2023-03-12 Platinum Python Cookbook Books 609 \n", + "\n", + " stock_qty month \n", + "0 51 2025-03 \n", + "1 150 2025-01 \n", + "2 174 2025-09 \n", + "3 186 2025-05 \n", + "4 274 2025-08 \n", + ".. ... ... \n", + "183 274 2025-02 \n", + "184 12 2025-10 \n", + "185 51 2025-01 \n", + "186 81 2025-06 \n", + "187 258 2025-09 \n", + "\n", + "[188 rows x 15 columns]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "370ceb93", + "metadata": {}, + "outputs": [], + "source": [ + "def yellow_line_region_trend():\n", + " \"\"\"\n", + " 畫折線圖:比較 North 和 South 兩個地區的月營收趨勢\n", + " - X 軸:月份\n", + " - Y 軸:該月總營收\n", + " - 兩條線,有圖例 (legend)\n", + " 回傳 matplotlib Figure 物件\n", + " 提示:分別 groupby 再 plot,或用 sns.lineplot(hue='region')\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "target_regions = df[df['region'].isin(['North', 'South'])].copy()\n", + "target_regions['month'] = target_regions['order_date'].dt.month\n", + "\n", + "region_rev = target_regions.groupby(['month','region'])['amount'].sum().reset_index()\n", + "\n", + "plt.figure(figsize=(10, 5))\n", + "sns.lineplot(data=region_rev, x='month', y='amount', hue = 'region', marker='o', linewidth=2)\n", + "plt.title('Monthly region Trend', fontsize=14, fontweight='bold')\n", + "plt.xlabel('Month')\n", + "plt.ylabel('total revenue')\n", + "plt.xticks(rotation=45)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "72f9d8bb", + "metadata": {}, + "outputs": [], + "source": [ + "def yellow_box_vip():\n", + " \"\"\"\n", + " 畫箱形圖:比較不同 VIP 等級 (vip_level) 的訂單金額分佈\n", + " 回傳 matplotlib Figure 物件\n", + " 提示:sns.boxplot(x='vip_level', y='amount', data=df)\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "plt.figure(figsize=(9, 5))\n", + "sns.boxplot(data=df, x='vip_level', y='amount', palette='Set2', hue='vip_level', legend=False)\n", + "plt.title('Order Amount Distribution by vip level', fontweight='bold')\n", + "plt.xlabel('vip_level')\n", + "plt.ylabel('Amount')\n", + "plt.xticks(rotation=15)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "a7baffa5", + "metadata": {}, + "outputs": [], + "source": [ + "def yellow_scatter_price_amount():\n", + " \"\"\"\n", + " 畫散佈圖:X=商品單價 (unit_price),Y=訂單金額 (amount)\n", + " 回傳 matplotlib Figure 物件\n", + " 提示:plt.scatter() 或 sns.scatterplot()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "plt.figure(figsize=(9, 5))\n", + "sns.scatterplot(data=df, x='unit_price', y='amount',\n", + " hue='category', alpha=0.6, s=60)\n", + "plt.title('Unit Price vs Order Amount (by Category)', fontweight='bold')\n", + "plt.xlabel('Unit Price')\n", + "plt.ylabel('Order Amount')\n", + "plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left')\n", + "plt.tight_layout()\n", + "plt.show() \n" + ] + }, + { + "cell_type": "markdown", + "id": "45fb614c", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🔴 挑戰題(25 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "d7639a54", + "metadata": {}, + "outputs": [], + "source": [ + "def red_category_dashboard(category=\"Electronics\"):\n", + " \"\"\"\n", + " 針對指定類別,畫 2×2 的 subplot dashboard:\n", + " 1. 左上:該類別月營收趨勢 (折線圖)\n", + " 2. 右上:該類別各地區營收 (長條圖)\n", + " 3. 左下:該類別 Top 5 商品營收 (水平長條圖)\n", + " 4. 右下:該類別訂單金額分佈 (直方圖)\n", + "\n", + " 回傳 matplotlib Figure 物件\n", + " 提示:fig, axes = plt.subplots(2, 2, figsize=(14, 10))\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "fig, axes = plt.subplots(2, 2, figsize=(16, 9))\n", + "fig.suptitle('Electronics Sales Dashboard — 2025', fontsize=16, fontweight='bold')\n", + "\n", + "# (0,0) 月度趨勢\n", + "electronics_df = df[df['category'].str.lower() == 'electronics']\n", + "region_electronics_rev = electronics_df.groupby('region')['amount'].sum().reset_index()\n", + "plt.figure(figsize=(8, 4)) \n", + "sns.lineplot(data=region_electronics_rev, x='region', y='amount', marker='o', ax=axes[0, 0])\n", + "plt.title('Electronics Revenue by Region', fontweight='bold')\n", + "plt.xlabel('Region')\n", + "plt.ylabel('Revenue (NT$)')\n", + "\n", + "# (0,1) 地區排名\n", + "sns.barplot(data=region_electronics_rev, x='region', y='amount', ax=axes[0, 1],\n", + " palette='viridis', hue='region', legend=False)\n", + "axes[0, 1].set_title('electronics_Revenue by Region')\n", + "\n", + "# (1,0) 品類分布\n", + "\n", + "electronics_df = df[df['category'].str.lower() == 'electronics']\n", + "product_rev = electronics_df.groupby('product_name')['amount'].sum().reset_index()\n", + "top5_products = product_rev.sort_values('amount', ascending=False).head(5)\n", + "fig = plt.figure(figsize=(10, 6))\n", + "sns.barplot(\n", + " data=top5_products, \n", + " x='amount', \n", + " y='product_name', \n", + " hue='product_name', \n", + " legend=False\n", + " )\n", + "\n", + "# (1,1) 金額散佈\n", + "sns.scatterplot(data=df, x='category', y='amount',\n", + " hue='category', alpha=0.6, ax=axes[1, 1], legend=False)\n", + "axes[1, 1].set_title('electronics Amount')\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "ac638b9b", + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \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_idcustomer_idproduct_idqtyorder_dateamountcustomer_nameregionsignup_datevip_levelproduct_namecategoryunit_pricestock_qtymonth
05064202210264.02025-03-268600.0Victor LinNorth2023-02-27GoldDumbbell 5kgSports2150513
15023202610215.02025-01-051355.0Zoe HuangSouth2023-05-16PlatinumThrow PillowHome2711501
25123201310132.02025-09-113538.0Mia HuangNorth2023-07-17PlatinumCotton T-ShirtClothing17691749
35118200510281.02025-05-221618.0Emma LiuWest2023-05-18BronzeWater BottleSports16181865
45161201710193.02025-08-201846.0Quinn ChenEast2023-08-11SilverCoffee MugHome18462748
................................................
1835094202610193.02025-02-135538.0Zoe HuangSouth2023-05-16PlatinumCoffee MugHome18462742
1845041201410015.02025-10-038135.0Nick HuangWest2023-09-28GoldWireless MouseElectronics16271210
1855157200510265.02025-01-0210750.0Emma LiuWest2023-05-18BronzeDumbbell 5kgSports2150511
1865134201510125.02025-06-039580.0Olivia HuangNorth2023-12-15BronzeClean CodeBooks1916816
1875135201010074.02025-09-052436.0Jack LiuSouth2023-03-12PlatinumPython CookbookBooks6092589
\n", + "

188 rows × 15 columns

\n", + "
" + ], + "text/plain": [ + " order_id customer_id product_id qty order_date amount customer_name \\\n", + "0 5064 2022 1026 4.0 2025-03-26 8600.0 Victor Lin \n", + "1 5023 2026 1021 5.0 2025-01-05 1355.0 Zoe Huang \n", + "2 5123 2013 1013 2.0 2025-09-11 3538.0 Mia Huang \n", + "3 5118 2005 1028 1.0 2025-05-22 1618.0 Emma Liu \n", + "4 5161 2017 1019 3.0 2025-08-20 1846.0 Quinn Chen \n", + ".. ... ... ... ... ... ... ... \n", + "183 5094 2026 1019 3.0 2025-02-13 5538.0 Zoe Huang \n", + "184 5041 2014 1001 5.0 2025-10-03 8135.0 Nick Huang \n", + "185 5157 2005 1026 5.0 2025-01-02 10750.0 Emma Liu \n", + "186 5134 2015 1012 5.0 2025-06-03 9580.0 Olivia Huang \n", + "187 5135 2010 1007 4.0 2025-09-05 2436.0 Jack Liu \n", + "\n", + " region signup_date vip_level product_name category unit_price \\\n", + "0 North 2023-02-27 Gold Dumbbell 5kg Sports 2150 \n", + "1 South 2023-05-16 Platinum Throw Pillow Home 271 \n", + "2 North 2023-07-17 Platinum Cotton T-Shirt Clothing 1769 \n", + "3 West 2023-05-18 Bronze Water Bottle Sports 1618 \n", + "4 East 2023-08-11 Silver Coffee Mug Home 1846 \n", + ".. ... ... ... ... ... ... \n", + "183 South 2023-05-16 Platinum Coffee Mug Home 1846 \n", + "184 West 2023-09-28 Gold Wireless Mouse Electronics 1627 \n", + "185 West 2023-05-18 Bronze Dumbbell 5kg Sports 2150 \n", + "186 North 2023-12-15 Bronze Clean Code Books 1916 \n", + "187 South 2023-03-12 Platinum Python Cookbook Books 609 \n", + "\n", + " stock_qty month \n", + "0 51 3 \n", + "1 150 1 \n", + "2 174 9 \n", + "3 186 5 \n", + "4 274 8 \n", + ".. ... ... \n", + "183 274 2 \n", + "184 12 10 \n", + "185 51 1 \n", + "186 81 6 \n", + "187 258 9 \n", + "\n", + "[188 rows x 15 columns]" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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 +} diff --git a/homework/m6_plotly_capstone.ipynb b/homework/m6_plotly_capstone.ipynb new file mode 100644 index 0000000..d59d5f2 --- /dev/null +++ b/homework/m6_plotly_capstone.ipynb @@ -0,0 +1,5861 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "970659fd", + "metadata": {}, + "source": [ + "\"\"\"\n", + "M6 Plotly 互動儀表板 & Capstone — 課後作業\n", + "===========================================\n", + "情境:從原始資料到互動式儀表板,完成完整的資料分析 pipeline。\n", + "\n", + "資料路徑:\n", + " - datasets/ecommerce/orders_raw.csv(原始髒資料)\n", + " - datasets/ecommerce/customers.csv\n", + " - datasets/ecommerce/products.csv\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "4fe2a583", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import plotly.express as px\n", + "import plotly.graph_objects as go\n", + "from plotly.subplots import make_subplots\n", + "import plotly.io as pio\n", + "\n", + "pio.templates.default = 'plotly_white' # 乾淨白底\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "20a2a92e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "資料形狀: (188, 14)\n" + ] + } + ], + "source": [ + "df = pd.read_csv(\n", + " '../datasets/ecommerce/orders_enriched.csv',\n", + " parse_dates=['order_date'],\n", + ")\n", + "print('資料形狀:', df.shape)" + ] + }, + { + "cell_type": "markdown", + "id": "3b6a4870", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🟢 送分題(每題 10 分,共 30 分)\n", + "# ============================================================\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "50d016fe", + "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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \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_idcustomer_idproduct_idqtyorder_dateamountcustomer_nameregionsignup_datevip_levelproduct_namecategoryunit_pricestock_qty
05064202210264.02025-03-268600.0Victor LinNorth2023-02-27GoldDumbbell 5kgSports215051
15023202610215.02025-01-051355.0Zoe HuangSouth2023-05-16PlatinumThrow PillowHome271150
25123201310132.02025-09-113538.0Mia HuangNorth2023-07-17PlatinumCotton T-ShirtClothing1769174
35118200510281.02025-05-221618.0Emma LiuWest2023-05-18BronzeWater BottleSports1618186
45161201710193.02025-08-201846.0Quinn ChenEast2023-08-11SilverCoffee MugHome1846274
.............................................
1835094202610193.02025-02-135538.0Zoe HuangSouth2023-05-16PlatinumCoffee MugHome1846274
1845041201410015.02025-10-038135.0Nick HuangWest2023-09-28GoldWireless MouseElectronics162712
1855157200510265.02025-01-0210750.0Emma LiuWest2023-05-18BronzeDumbbell 5kgSports215051
1865134201510125.02025-06-039580.0Olivia HuangNorth2023-12-15BronzeClean CodeBooks191681
1875135201010074.02025-09-052436.0Jack LiuSouth2023-03-12PlatinumPython CookbookBooks609258
\n", + "

188 rows × 14 columns

\n", + "
" + ], + "text/plain": [ + " order_id customer_id product_id qty order_date amount customer_name \\\n", + "0 5064 2022 1026 4.0 2025-03-26 8600.0 Victor Lin \n", + "1 5023 2026 1021 5.0 2025-01-05 1355.0 Zoe Huang \n", + "2 5123 2013 1013 2.0 2025-09-11 3538.0 Mia Huang \n", + "3 5118 2005 1028 1.0 2025-05-22 1618.0 Emma Liu \n", + "4 5161 2017 1019 3.0 2025-08-20 1846.0 Quinn Chen \n", + ".. ... ... ... ... ... ... ... \n", + "183 5094 2026 1019 3.0 2025-02-13 5538.0 Zoe Huang \n", + "184 5041 2014 1001 5.0 2025-10-03 8135.0 Nick Huang \n", + "185 5157 2005 1026 5.0 2025-01-02 10750.0 Emma Liu \n", + "186 5134 2015 1012 5.0 2025-06-03 9580.0 Olivia Huang \n", + "187 5135 2010 1007 4.0 2025-09-05 2436.0 Jack Liu \n", + "\n", + " region signup_date vip_level product_name category unit_price \\\n", + "0 North 2023-02-27 Gold Dumbbell 5kg Sports 2150 \n", + "1 South 2023-05-16 Platinum Throw Pillow Home 271 \n", + "2 North 2023-07-17 Platinum Cotton T-Shirt Clothing 1769 \n", + "3 West 2023-05-18 Bronze Water Bottle Sports 1618 \n", + "4 East 2023-08-11 Silver Coffee Mug Home 1846 \n", + ".. ... ... ... ... ... ... \n", + "183 South 2023-05-16 Platinum Coffee Mug Home 1846 \n", + "184 West 2023-09-28 Gold Wireless Mouse Electronics 1627 \n", + "185 West 2023-05-18 Bronze Dumbbell 5kg Sports 2150 \n", + "186 North 2023-12-15 Bronze Clean Code Books 1916 \n", + "187 South 2023-03-12 Platinum Python Cookbook Books 609 \n", + "\n", + " stock_qty \n", + "0 51 \n", + "1 150 \n", + "2 174 \n", + "3 186 \n", + "4 274 \n", + ".. ... \n", + "183 274 \n", + "184 12 \n", + "185 51 \n", + "186 81 \n", + "187 258 \n", + "\n", + "[188 rows x 14 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "d9db8c45", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "category=%{x}
amount=%{text}", + "legendgroup": "Books", + "marker": { + "color": "#636efa", + "pattern": { + "shape": "" + } + }, + "name": "Books", + "orientation": "v", + "showlegend": true, + "text": { + "bdata": "AAAAACA/BkE=", + "dtype": "f8" + }, + "textposition": "outside", + "texttemplate": "%{text:,.0f}", + "type": "bar", + "x": [ + "Books" + ], + "xaxis": "x", + "y": { + "bdata": "AAAAACA/BkE=", + "dtype": "f8" + }, + "yaxis": "y" + }, + { + "hovertemplate": "category=%{x}
amount=%{text}", + "legendgroup": "Sports", + "marker": { + "color": "#EF553B", + "pattern": { + "shape": "" + } + }, + "name": "Sports", + "orientation": "v", + "showlegend": true, + "text": { + "bdata": "AAAAANiFBUE=", + "dtype": "f8" + }, + "textposition": "outside", + "texttemplate": "%{text:,.0f}", + "type": "bar", + "x": [ + "Sports" + ], + "xaxis": "x", + "y": { + "bdata": "AAAAANiFBUE=", + "dtype": "f8" + }, + "yaxis": "y" + }, + { + "hovertemplate": "category=%{x}
amount=%{text}", + "legendgroup": "Clothing", + "marker": { + "color": "#00cc96", + "pattern": { + "shape": "" + } + }, + "name": "Clothing", + "orientation": "v", + "showlegend": true, + "text": { + "bdata": "AAAAAIhWAEE=", + "dtype": "f8" + }, + "textposition": "outside", + "texttemplate": "%{text:,.0f}", + "type": "bar", + "x": [ + "Clothing" + ], + "xaxis": "x", + "y": { + "bdata": "AAAAAIhWAEE=", + "dtype": "f8" + }, + "yaxis": "y" + }, + { + "hovertemplate": "category=%{x}
amount=%{text}", + "legendgroup": "Electronics", + "marker": { + "color": "#ab63fa", + "pattern": { + "shape": "" + } + }, + "name": "Electronics", + "orientation": "v", + "showlegend": true, + "text": { + "bdata": "AAAAALB4+EA=", + "dtype": "f8" + }, + "textposition": "outside", + "texttemplate": "%{text:,.0f}", + "type": "bar", + "x": [ + "Electronics" + ], + "xaxis": "x", + "y": { + "bdata": "AAAAALB4+EA=", + "dtype": "f8" + }, + "yaxis": "y" + }, + { + "hovertemplate": "category=%{x}
amount=%{text}", + "legendgroup": "Home", + "marker": { + "color": "#FFA15A", + "pattern": { + "shape": "" + } + }, + "name": "Home", + "orientation": "v", + "showlegend": true, + "text": { + "bdata": "AAAAAJDj9kA=", + "dtype": "f8" + }, + "textposition": "outside", + "texttemplate": "%{text:,.0f}", + "type": "bar", + "x": [ + "Home" + ], + "xaxis": "x", + "y": { + "bdata": "AAAAAJDj9kA=", + "dtype": "f8" + }, + "yaxis": "y" + } + ], + "layout": { + "barmode": "relative", + "height": 400, + "legend": { + "title": { + "text": "category" + }, + "tracegroupgap": 0 + }, + "showlegend": false, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "#C8D4E3" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "baxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Revenue by category" + }, + "xaxis": { + "anchor": "y", + "categoryarray": [ + "Books", + "Sports", + "Clothing", + "Electronics", + "Home" + ], + "categoryorder": "array", + "domain": [ + 0, + 1 + ], + "title": { + "text": "category" + } + }, + "yaxis": { + "anchor": "x", + "domain": [ + 0, + 1 + ], + "title": { + "text": "amount" + } + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def green_plotly_bar():\n", + " \"\"\"\n", + " 用 Plotly Express 畫出每個商品類別 (category) 的總營收長條圖\n", + " 資料來源:orders_enriched.csv\n", + " 回傳 plotly Figure 物件\n", + " 提示:px.bar()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "\n", + "category_rev = df.groupby('category', as_index=False)['amount'].sum().sort_values('amount', ascending=False)\n", + "fig = px.bar(category_rev, x='category', y='amount', text='amount',\n", + " color='category', title='Revenue by category')\n", + "fig.update_traces(texttemplate='%{text:,.0f}', textposition='outside')\n", + "fig.update_layout(height=400, showlegend=False)\n", + "fig.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "00af9c96", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "month=%{x}
amount=%{y}", + "legendgroup": "", + "line": { + "color": "#636efa", + "dash": "solid" + }, + "marker": { + "symbol": "circle" + }, + "mode": "lines+markers", + "name": "", + "orientation": "v", + "showlegend": false, + "type": "scatter", + "x": [ + "2025-01", + "2025-02", + "2025-03", + "2025-04", + "2025-05", + "2025-06", + "2025-07", + "2025-08", + "2025-09", + "2025-10", + "2025-11", + "2025-12" + ], + "xaxis": "x", + "y": { + "bdata": "AAAAAMBT7UAAAAAA8KrxQAAAAAAATutAAAAAAECR7EAAAAAA4GDnQAAAAACg2uhAAAAAAIDr40AAAAAAQJ7uQAAAAAAgx+hAAAAAAIAo8kAAAAAAoIjuQAAAAACgN+hA", + "dtype": "f8" + }, + "yaxis": "y" + } + ], + "layout": { + "height": 400, + "legend": { + "tracegroupgap": 0 + }, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "#C8D4E3" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "baxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Monthly Revenue Trend" + }, + "xaxis": { + "anchor": "y", + "domain": [ + 0, + 1 + ], + "title": { + "text": "month" + } + }, + "yaxis": { + "anchor": "x", + "domain": [ + 0, + 1 + ], + "title": { + "text": "amount" + } + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def green_plotly_line():\n", + " \"\"\"\n", + " 用 Plotly Express 畫出月營收趨勢折線圖\n", + " 資料來源:orders_enriched.csv\n", + " 回傳 plotly Figure 物件\n", + " 提示:先 groupby 月份算總營收,再 px.line()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + " \n", + "\n", + "df['month'] = df['order_date'].dt.to_period('M').astype(str)\n", + "monthly = df.groupby('month', as_index=False)['amount'].sum()\n", + "\n", + "fig = px.line(monthly, x='month', y='amount', markers=True,\n", + " title='Monthly Revenue Trend')\n", + "fig.update_layout(height=400)\n", + "fig.show()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "1a34822f", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "domain": { + "x": [ + 0, + 1 + ], + "y": [ + 0, + 1 + ] + }, + "hole": 0.4, + "hovertemplate": "vip_level=%{label}
qty=%{value}", + "labels": [ + "Bronze", + "Gold", + "Platinum", + "Silver" + ], + "legendgroup": "", + "name": "", + "showlegend": true, + "type": "pie", + "values": { + "bdata": "AAAAAABAXUAAAAAAAGBuQAAAAAAAYGNAAAAAAAAATkA=", + "dtype": "f8" + } + } + ], + "layout": { + "height": 400, + "legend": { + "tracegroupgap": 0 + }, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "#C8D4E3" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "baxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "VIP Level qty" + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def green_plotly_pie():\n", + " \"\"\"\n", + " 用 Plotly Express 畫出 VIP 等級 (vip_level) 的訂單數佔比圓餅圖\n", + " 資料來源:orders_enriched.csv\n", + " 回傳 plotly Figure 物件\n", + " 提示:px.pie()\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "vip_qty = df.groupby('vip_level', as_index=False)['qty'].sum()\n", + "fig = px.pie(vip_qty, names='vip_level', values='qty',\n", + " title='VIP Level qty', hole=0.4) # hole=0.4 變成 donut\n", + "fig.update_layout(height=400)\n", + "fig.show()" + ] + }, + { + "cell_type": "markdown", + "id": "0b33c70b", + "metadata": {}, + "source": [ + "\n", + "# ============================================================\n", + "# 🟡 核心題(每題 15 分,共 45 分)\n", + "# ============================================================\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "7a7f2541", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "清理完成:188 筆訂單\n", + "合併後形狀: (188, 14)\n", + "欄位數: 14\n", + " order_id customer_id product_id qty order_date amount customer_name \\\n", + "0 5064 2022 1026 4.0 2025-03-26 8600.0 Victor Lin \n", + "1 5023 2026 1021 5.0 2025-01-05 1355.0 Zoe Huang \n", + "2 5123 2013 1013 2.0 2025-09-11 3538.0 Mia Huang \n", + "3 5118 2005 1028 1.0 2025-05-22 1618.0 Emma Liu \n", + "4 5161 2017 1019 3.0 2025-08-20 1846.0 Quinn Chen \n", + ".. ... ... ... ... ... ... ... \n", + "183 5094 2026 1019 3.0 2025-02-13 5538.0 Zoe Huang \n", + "184 5041 2014 1001 5.0 2025-10-03 8135.0 Nick Huang \n", + "185 5157 2005 1026 5.0 2025-01-02 10750.0 Emma Liu \n", + "186 5134 2015 1012 5.0 2025-06-03 9580.0 Olivia Huang \n", + "187 5135 2010 1007 4.0 2025-09-05 2436.0 Jack Liu \n", + "\n", + " region signup_date vip_level product_name category unit_price \\\n", + "0 North 2023-02-27 Gold Dumbbell 5kg Sports 2150 \n", + "1 South 2023-05-16 Platinum Throw Pillow Home 271 \n", + "2 North 2023-07-17 Platinum Cotton T-Shirt Clothing 1769 \n", + "3 West 2023-05-18 Bronze Water Bottle Sports 1618 \n", + "4 East 2023-08-11 Silver Coffee Mug Home 1846 \n", + ".. ... ... ... ... ... ... \n", + "183 South 2023-05-16 Platinum Coffee Mug Home 1846 \n", + "184 West 2023-09-28 Gold Wireless Mouse Electronics 1627 \n", + "185 West 2023-05-18 Bronze Dumbbell 5kg Sports 2150 \n", + "186 North 2023-12-15 Bronze Clean Code Books 1916 \n", + "187 South 2023-03-12 Platinum Python Cookbook Books 609 \n", + "\n", + " stock_qty \n", + "0 51 \n", + "1 150 \n", + "2 174 \n", + "3 186 \n", + "4 274 \n", + ".. ... \n", + "183 274 \n", + "184 12 \n", + "185 51 \n", + "186 81 \n", + "187 258 \n", + "\n", + "[188 rows x 14 columns]\n" + ] + } + ], + "source": [ + "def yellow_clean_and_merge(orders_raw, customers, products):\n", + " \"\"\"\n", + " 完整 ETL:從髒資料到合併完成的 DataFrame\n", + " 1. 讀取 orders_raw.csv 並清理(欄位名稱、金額、日期、缺值、去重)\n", + " 2. 合併 customers.csv 和 products.csv\n", + " 回傳:合併後的 DataFrame\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "def clean_orders(orders_raw):\n", + " df = pd.read_csv('../datasets/ecommerce/orders_raw.csv')\n", + " df.columns = df.columns.str.strip().str.lower()\n", + " df['amount'] = (\n", + " df['amount'].astype(str)\n", + " .str.replace('$','', regex=False)\n", + " .str.replace(',','', regex=False)\n", + " .astype(float)\n", + " )\n", + " df['order_date'] = pd.to_datetime(df['order_date'], errors='coerce')\n", + " df = df.dropna(subset=['order_date'])\n", + " df['qty'] = df['qty'].fillna(df['qty'].median())\n", + " df = df.drop_duplicates()\n", + " return df\n", + "\n", + "raw_orders = pd.read_csv('../datasets/ecommerce/orders_raw.csv')\n", + "orders = clean_orders(raw_orders)\n", + "print(f'清理完成:{orders.shape[0]} 筆訂單')\n", + "orders.head(3)\n", + "\n", + "customers = pd.read_csv('../datasets/ecommerce/customers.csv')\n", + "products = pd.read_csv('../datasets/ecommerce/products.csv')\n", + "\n", + "enriched = (\n", + " orders\n", + " .merge(customers, on='customer_id', how='left')\n", + " .merge(products, on='product_id', how='left')\n", + ")\n", + "print(f'合併後形狀: {enriched.shape}')\n", + "print(f'欄位數: {len(enriched.columns)}')\n", + "\n", + "print(enriched)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "cd6063dc", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "總營收: 686,388\n", + "總訂單數: 188\n", + "活躍顧客數: 26\n", + "客單價: 3,651\n" + ] + } + ], + "source": [ + "def yellow_kpi_summary(df):\n", + " \"\"\"\n", + " 計算 4 個核心 KPI,回傳 dict:\n", + " {\n", + " \"total_revenue\": float, # 總營收\n", + " \"order_count\": int, # 訂單數\n", + " \"active_customers\": int, # 不重複客戶數\n", + " \"avg_order_value\": float, # 平均客單價\n", + " }\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "\n", + "enriched['month'] = enriched['order_date'].dt.to_period('M').astype(str)\n", + "kpis = {\n", + " '總營收': enriched['amount'].sum(),\n", + " '總訂單數': len(enriched),\n", + " '活躍顧客數': enriched['customer_id'].nunique(),\n", + " '客單價': enriched['amount'].sum() / len(enriched),\n", + "}\n", + "for k, v in kpis.items():\n", + " print(f'{k}: {v:>12,.0f}')" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "bd60d953", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "customdata": [ + [ + "Dumbbell 5kg" + ], + [ + "Water Bottle" + ], + [ + "Running Shoes" + ], + [ + "Jump Rope" + ], + [ + "Jump Rope" + ], + [ + "Water Bottle" + ], + [ + "Dumbbell 5kg" + ], + [ + "Running Shoes" + ], + [ + "Jump Rope" + ], + [ + "Dumbbell 5kg" + ], + [ + "Resistance Band" + ], + [ + "Water Bottle" + ], + [ + "Running Shoes" + ], + [ + "Running Shoes" + ], + [ + "Dumbbell 5kg" + ], + [ + "Water Bottle" + ], + [ + "Water Bottle" + ], + [ + "Water Bottle" + ], + [ + "Water Bottle" + ], + [ + "Jump Rope" + ], + [ + "Jump Rope" + ], + [ + "Water Bottle" + ], + [ + "Resistance Band" + ], + [ + "Jump Rope" + ], + [ + "Yoga Mat" + ], + [ + "Water Bottle" + ], + [ + "Yoga Mat" + ], + [ + "Water Bottle" + ], + [ + "Running Shoes" + ], + [ + "Dumbbell 5kg" + ], + [ + "Jump Rope" + ], + [ + "Running Shoes" + ], + [ + "Dumbbell 5kg" + ], + [ + "Yoga Mat" + ], + [ + "Yoga Mat" + ], + [ + "Dumbbell 5kg" + ], + [ + "Water Bottle" + ], + [ + "Resistance Band" + ], + [ + "Water Bottle" + ], + [ + "Yoga Mat" + ], + [ + "Resistance Band" + ], + [ + "Water Bottle" + ], + [ + "Dumbbell 5kg" + ] + ], + "hovertemplate": "category=Sports
unit_price=%{x}
amount=%{y}
product_name=%{customdata[0]}", + "legendgroup": "Sports", + "marker": { + "color": "#636efa", + "symbol": "circle" + }, + "mode": "markers", + "name": "Sports", + "orientation": "v", + "showlegend": true, + "type": "scatter", + "x": { + "bdata": "ZghSBugD2gHaAVIGZgjoA9oBZghLAlIG6APoA2YIUgZSBlIGUgbaAdoBUgZLAtoBnwdSBp8HUgboA2YI2gHoA2YInwefB2YIUgZLAlIGnwdLAlIGZgg=", + "dtype": "i2" + }, + "xaxis": "x", + "y": { + "bdata": "AAAAAADMwEAAAAAAAEiZQAAAAAAAQI9AAAAAAACgjUAAAAAAAKCdQAAAAAAASKlAAAAAAAD/xEAAAAAAAHCnQAAAAAAAoH1AAAAAAADMsEAAAAAAAO6mQAAAAAAASJlAAAAAAABAn0AAAAAAAHCnQAAAAAAAzLBAAAAAAABIuUAAAAAAAEi5QAAAAAAASLlAAAAAAABIuUAAAAAAAISiQAAAAAAAoH1AAAAAAABImUAAAAAAAFiCQAAAAAAAOJZAAAAAAAB8nkAAAAAAAEiZQAAAAACADcNAAAAAAABImUAAAAAAAIizQAAAAAAAzLBAAAAAAACgjUAAAAAAAIizQAAAAAAAzLBAAAAAAAB8vkAAAAAAAN22QAAAAAAAMrlAAAAAAABIqUAAAAAAAO6mQAAAAAAASLlAAAAAAADdtkAAAAAAAFiiQAAAAAAAmr9AAAAAAAD/xEA=", + "dtype": "f8" + }, + "yaxis": "y" + }, + { + "customdata": [ + [ + "Throw Pillow" + ], + [ + "Coffee Mug" + ], + [ + "Candle Set" + ], + [ + "Throw Pillow" + ], + [ + "Desk Lamp" + ], + [ + "Candle Set" + ], + [ + "Candle Set" + ], + [ + "Plant Pot" + ], + [ + "Throw Pillow" + ], + [ + "Coffee Mug" + ], + [ + "Plant Pot" + ], + [ + "Desk Lamp" + ], + [ + "Candle Set" + ], + [ + "Plant Pot" + ], + [ + "Candle Set" + ], + [ + "Wall Clock" + ], + [ + "Throw Pillow" + ], + [ + "Candle Set" + ], + [ + "Throw Pillow" + ], + [ + "Candle Set" + ], + [ + "Throw Pillow" + ], + [ + "Desk Lamp" + ], + [ + "Coffee Mug" + ], + [ + "Plant Pot" + ], + [ + "Plant Pot" + ], + [ + "Plant Pot" + ], + [ + "Candle Set" + ], + [ + "Throw Pillow" + ], + [ + "Coffee Mug" + ], + [ + "Plant Pot" + ], + [ + "Coffee Mug" + ] + ], + "hovertemplate": "category=Home
unit_price=%{x}
amount=%{y}
product_name=%{customdata[0]}", + "legendgroup": "Home", + "marker": { + "color": "#EF553B", + "symbol": "circle" + }, + "mode": "markers", + "name": "Home", + "orientation": "v", + "showlegend": true, + "type": "scatter", + "x": { + "bdata": "DwE2BycIDwF+AScIJwi/AA8BNge/AH4BJwi/ACcIxQUPAScIDwEnCA8BfgE2B78AvwC/ACcIDwE2B78ANgc=", + "dtype": "i2" + }, + "xaxis": "x", + "y": { + "bdata": "AAAAAAAslUAAAAAAANicQAAAAAAATsBAAAAAAADwkEAAAAAAANidQAAAAAAATqBAAAAAAAB1uEAAAAAAAOiBQAAAAAAA8JBAAAAAAAAHwkAAAAAAAOCHQAAAAAAA4IdAAAAAAIBhxEAAAAAAAOCHQAAAAAAATqBAAAAAAABPsUAAAAAAAPCQQAAAAAAATqBAAAAAAAAslUAAAAAAAE6wQAAAAAAAaIlAAAAAAADgd0AAAAAAAAfCQAAAAAAA4GdAAAAAAADogUAAAAAAANiNQAAAAAAATsBAAAAAAADwcEAAAAAAAKK1QAAAAAAA4GdAAAAAAACitUA=", + "dtype": "f8" + }, + "yaxis": "y" + }, + { + "customdata": [ + [ + "Cotton T-Shirt" + ], + [ + "Cap" + ], + [ + "Cotton T-Shirt" + ], + [ + "Hoodie" + ], + [ + "Sneakers" + ], + [ + "Hoodie" + ], + [ + "Sneakers" + ], + [ + "Denim Jeans" + ], + [ + "Hoodie" + ], + [ + "Hoodie" + ], + [ + "Hoodie" + ], + [ + "Hoodie" + ], + [ + "Hoodie" + ], + [ + "Cotton T-Shirt" + ], + [ + "Scarf" + ], + [ + "Sneakers" + ], + [ + "Sneakers" + ], + [ + "Hoodie" + ], + [ + "Denim Jeans" + ], + [ + "Denim Jeans" + ], + [ + "Denim Jeans" + ], + [ + "Cotton T-Shirt" + ], + [ + "Cap" + ], + [ + "Cap" + ], + [ + "Hoodie" + ], + [ + "Cotton T-Shirt" + ], + [ + "Cap" + ], + [ + "Sneakers" + ], + [ + "Cap" + ], + [ + "Cap" + ], + [ + "Denim Jeans" + ], + [ + "Hoodie" + ], + [ + "Sneakers" + ], + [ + "Cotton T-Shirt" + ], + [ + "Denim Jeans" + ], + [ + "Scarf" + ], + [ + "Cotton T-Shirt" + ], + [ + "Scarf" + ], + [ + "Sneakers" + ] + ], + "hovertemplate": "category=Clothing
unit_price=%{x}
amount=%{y}
product_name=%{customdata[0]}", + "legendgroup": "Clothing", + "marker": { + "color": "#00cc96", + "symbol": "circle" + }, + "mode": "markers", + "name": "Clothing", + "orientation": "v", + "showlegend": true, + "type": "scatter", + "x": { + "bdata": "6QY6AekGXAlHAVwJRwHwAlwJXAlcCVwJXAnpBgUGRwFHAVwJ8ALwAvAC6QY6AToBXAnpBjoBRwE6AToB8AJcCUcB6QbwAgUG6QYFBkcB", + "dtype": "i2" + }, + "xaxis": "x", + "y": { + "bdata": "AAAAAACkq0AAAAAAAHCNQAAAAAAApKtAAAAAAAC4wkAAAAAAAHCEQAAAAAAAuLJAAAAAAACojkAAAAAAAGCtQAAAAAAAuKJAAAAAAAAUvEAAAAAAABS8QAAAAAAAuKJAAAAAAABmx0AAAAAAAKS7QAAAAAAAFKhAAAAAAABwhEAAAAAAAHCUQAAAAAAAuKJAAAAAAACAp0AAAAAAAICnQAAAAAAAgIdAAAAAAACkm0AAAAAAAIiYQAAAAAAAoHNAAAAAAAAUvEAAAAAAAKS7QAAAAAAAiJhAAAAAAACMmUAAAAAAAKCTQAAAAAAAoHNAAAAAAACAl0AAAAAAALiyQAAAAAAAcIRAAAAAAACku0AAAAAAAICnQAAAAAAAFKhAAAAAAACku0AAAAAAABSoQAAAAAAAcIRA", + "dtype": "f8" + }, + "yaxis": "y" + }, + { + "customdata": [ + [ + "ML Primer" + ], + [ + "Data Science Handbook" + ], + [ + "ML Primer" + ], + [ + "Clean Code" + ], + [ + "Data Science Handbook" + ], + [ + "Statistics 101" + ], + [ + "ML Primer" + ], + [ + "Python Cookbook" + ], + [ + "Clean Code" + ], + [ + "Data Science Handbook" + ], + [ + "ML Primer" + ], + [ + "Clean Code" + ], + [ + "Data Science Handbook" + ], + [ + "ML Primer" + ], + [ + "ML Primer" + ], + [ + "Statistics 101" + ], + [ + "Clean Code" + ], + [ + "Python Cookbook" + ], + [ + "Data Science Handbook" + ], + [ + "Python Cookbook" + ], + [ + "Data Science Handbook" + ], + [ + "Statistics 101" + ], + [ + "SQL Guide" + ], + [ + "SQL Guide" + ], + [ + "Data Science Handbook" + ], + [ + "Data Science Handbook" + ], + [ + "Data Science Handbook" + ], + [ + "ML Primer" + ], + [ + "Clean Code" + ], + [ + "SQL Guide" + ], + [ + "Clean Code" + ], + [ + "Statistics 101" + ], + [ + "Statistics 101" + ], + [ + "Data Science Handbook" + ], + [ + "SQL Guide" + ], + [ + "Data Science Handbook" + ], + [ + "Clean Code" + ], + [ + "Clean Code" + ], + [ + "ML Primer" + ], + [ + "Statistics 101" + ], + [ + "Python Cookbook" + ], + [ + "Data Science Handbook" + ], + [ + "Clean Code" + ], + [ + "Python Cookbook" + ] + ], + "hovertemplate": "category=Books
unit_price=%{x}
amount=%{y}
product_name=%{customdata[0]}", + "legendgroup": "Books", + "marker": { + "color": "#ab63fa", + "symbol": "circle" + }, + "mode": "markers", + "name": "Books", + "orientation": "v", + "showlegend": true, + "type": "scatter", + "x": { + "bdata": "RwQBBkcEfAcBBuIFRwRhAnwHAQZHBHwHAQZHBEcE4gV8B2ECAQZhAgEG4gUxAjECAQYBBgEGRwR8BzECfAfiBeIFAQYxAgEGfAd8B0cE4gVhAgEGfAdhAg==", + "dtype": "i2" + }, + "xaxis": "x", + "y": { + "bdata": "AAAAAAAcsUAAAAAAAAS4QAAAAAAAY7VAAAAAAADwnUAAAAAAAAS4QAAAAAAAiJdAAAAAAAAcsUAAAAAAAAijQAAAAAAAdLZAAAAAAAAEuEAAAAAAAGO1QAAAAAAAtsJAAAAAAAAEqEAAAAAAAByhQAAAAAAAHKFAAAAAAACIp0AAAAAAAPC9QAAAAAAACKNAAAAAAAAEmEAAAAAAAIycQAAAAAAABJhAAAAAAACIt0AAAAAAAEyaQAAAAAAA6qVAAAAAAAADskAAAAAAAASYQAAAAAAABJhAAAAAAACqqUAAAAAAAPCdQAAAAAAATJpAAAAAAADwvUAAAAAAAGq9QAAAAAAAiJdAAAAAAAADskAAAAAAAIiRQAAAAAAABLhAAAAAAAB0tkAAAAAAALbCQAAAAAAAY7VAAAAAAACmsUAAAAAAAIycQAAAAAAAA7JAAAAAAAC2wkAAAAAAAAijQA==", + "dtype": "f8" + }, + "yaxis": "y" + }, + { + "customdata": [ + [ + "Webcam HD" + ], + [ + "Power Bank" + ], + [ + "USB-C Cable" + ], + [ + "Webcam HD" + ], + [ + "Power Bank" + ], + [ + "Power Bank" + ], + [ + "Webcam HD" + ], + [ + "Power Bank" + ], + [ + "Power Bank" + ], + [ + "Power Bank" + ], + [ + "USB-C Cable" + ], + [ + "Bluetooth Speaker" + ], + [ + "Laptop Stand" + ], + [ + "Webcam HD" + ], + [ + "USB-C Cable" + ], + [ + "Webcam HD" + ], + [ + "Wireless Mouse" + ], + [ + "Power Bank" + ], + [ + "Laptop Stand" + ], + [ + "Bluetooth Speaker" + ], + [ + "Webcam HD" + ], + [ + "Power Bank" + ], + [ + "Webcam HD" + ], + [ + "Laptop Stand" + ], + [ + "Power Bank" + ], + [ + "USB-C Cable" + ], + [ + "USB-C Cable" + ], + [ + "Wireless Mouse" + ], + [ + "USB-C Cable" + ], + [ + "Bluetooth Speaker" + ], + [ + "Wireless Mouse" + ] + ], + "hovertemplate": "category=Electronics
unit_price=%{x}
amount=%{y}
product_name=%{customdata[0]}", + "legendgroup": "Electronics", + "marker": { + "color": "#FFA15A", + "symbol": "circle" + }, + "mode": "markers", + "name": "Electronics", + "orientation": "v", + "showlegend": true, + "type": "scatter", + "x": { + "bdata": "tgadAFMHtgadAJ0AtgadAJ0AnQBTB2wCIgG2BlMHtgZbBp0AIgFsArYGnQC2BiIBnQBTB1MHWwZTB2wCWwY=", + "dtype": "i2" + }, + "xaxis": "x", + "y": { + "bdata": "AAAAAAAitEAAAAAAAKCDQAAAAACAT8JAAAAAAADYukAAAAAAAHB9QAAAAAAAcH1AAAAAAADYqkAAAAAAAHB9QAAAAAAAoINAAAAAAACgY0AAAAAAgE/CQAAAAAAAOKhAAAAAAAAgckAAAAAAANiaQAAAAAAA+bVAAAAAAADYukAAAAAAAMe/QAAAAAAAoINAAAAAAAAwi0AAAAAAABCdQAAAAAAA2JpAAAAAAACgY0AAAAAAANiqQAAAAAAAMItAAAAAAACIiEAAAAAAAEydQAAAAAAA+bVAAAAAAABsuUAAAAAAAEytQAAAAAAAYJNAAAAAAADHv0A=", + "dtype": "f8" + }, + "yaxis": "y" + } + ], + "layout": { + "height": 450, + "legend": { + "title": { + "text": "category" + }, + "tracegroupgap": 0 + }, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "#C8D4E3" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "baxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Unit Price" + }, + "xaxis": { + "anchor": "y", + "domain": [ + 0, + 1 + ], + "title": { + "text": "unit_price" + } + }, + "yaxis": { + "anchor": "x", + "domain": [ + 0, + 1 + ], + "title": { + "text": "amount" + } + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def yellow_plotly_scatter(df):\n", + " \"\"\"\n", + " 用 Plotly Express 畫互動散佈圖:\n", + " - X:商品單價 (unit_price)\n", + " - Y:訂單金額 (amount)\n", + " - 顏色:商品類別 (category)\n", + " - hover 顯示:商品名稱 (product_name)\n", + " 回傳 plotly Figure 物件\n", + " 提示:px.scatter(hover_data=['product_name'])\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "fig = px.scatter(df, x='unit_price', y='amount',\n", + " color='category', hover_data=['product_name'],\n", + " title='Unit Price')\n", + "fig.update_layout(height=450)\n", + "fig.show()" + ] + }, + { + "cell_type": "markdown", + "id": "6268ef65", + "metadata": {}, + "source": [ + "# ============================================================\n", + "# 🔴 挑戰題(25 分)\n", + "# ============================================================" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "d7d0e155", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\Users\\highm\\AppData\\Local\\Programs\\Python\\Python312\\Lib\\site-packages\\plotly\\graph_objs\\_deprecations.py:378: DeprecationWarning: plotly.graph_objs.Line is deprecated.\n", + "Please replace it with one of the following more specific types\n", + " - plotly.graph_objs.scatter.Line\n", + " - plotly.graph_objs.layout.shape.Line\n", + " - etc.\n", + "\n", + " warnings.warn(\n" + ] + }, + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "mode": "lines+markers", + "name": "Monthly", + "type": "scatter", + "x": [ + "2025-01", + "2025-02", + "2025-03", + "2025-04", + "2025-05", + "2025-06", + "2025-07", + "2025-08", + "2025-09", + "2025-10", + "2025-11", + "2025-12" + ], + "xaxis": "x", + "y": { + "bdata": "AAAAAMBT7UAAAAAA8KrxQAAAAAAATutAAAAAAECR7EAAAAAA4GDnQAAAAACg2uhAAAAAAIDr40AAAAAAQJ7uQAAAAAAgx+hAAAAAAIAo8kAAAAAAoIjuQAAAAACgN+hA", + "dtype": "f8" + }, + "yaxis": "y" + }, + { + "name": "Top Products", + "type": "bar", + "x": [ + "Hoodie", + "Clean Code", + "Water Bottle", + "Dumbbell 5kg", + "Data Science Handbook", + "Candle Set", + "Cotton T-Shirt", + "USB-C Cable", + "ML Primer", + "Coffee Mug" + ], + "xaxis": "x2", + "y": { + "bdata": "AAAAAIA/7UAAAAAAgADtQAAAAACA3OpAAAAAAMA+6kAAAAAA4EPnQAAAAABgZuVAAAAAAKAj4kAAAAAAIGXhQAAAAABACuBAAAAAAICl3kA=", + "dtype": "f8" + }, + "yaxis": "y2" + }, + { + "name": "Region", + "type": "bar", + "x": [ + "East", + "North", + "South", + "West" + ], + "xaxis": "x3", + "y": { + "bdata": "AAAAAADs6UAAAAAAiJIOQQAAAABsoxBBAAAAAIDq+kA=", + "dtype": "f8" + }, + "yaxis": "y3" + }, + { + "domain": { + "x": [ + 0.55, + 1 + ], + "y": [ + 0, + 0.375 + ] + }, + "hole": 0.4, + "labels": [ + "Books", + "Clothing", + "Electronics", + "Home", + "Sports" + ], + "name": "Category", + "type": "pie", + "values": { + "bdata": "AAAAACA/BkEAAAAAiFYAQQAAAACwePhAAAAAAJDj9kAAAAAA2IUFQQ==", + "dtype": "f8" + } + } + ], + "layout": { + "annotations": [ + { + "font": { + "size": 16 + }, + "showarrow": false, + "text": "Monthly Revenue Trend", + "x": 0.225, + "xanchor": "center", + "xref": "paper", + "y": 1, + "yanchor": "bottom", + "yref": "paper" + }, + { + "font": { + "size": 16 + }, + "showarrow": false, + "text": "Top 10 Products", + "x": 0.775, + "xanchor": "center", + "xref": "paper", + "y": 1, + "yanchor": "bottom", + "yref": "paper" + }, + { + "font": { + "size": 16 + }, + "showarrow": false, + "text": "Revenue by Region", + "x": 0.225, + "xanchor": "center", + "xref": "paper", + "y": 0.375, + "yanchor": "bottom", + "yref": "paper" + }, + { + "font": { + "size": 16 + }, + "showarrow": false, + "text": "Category Share", + "x": 0.775, + "xanchor": "center", + "xref": "paper", + "y": 0.375, + "yanchor": "bottom", + "yref": "paper" + } + ], + "height": 750, + "showlegend": false, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "white", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "#C8D4E3", + "linecolor": "#C8D4E3", + "minorgridcolor": "#C8D4E3", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermap": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermap" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "white", + "showlakes": true, + "showland": true, + "subunitcolor": "#C8D4E3" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "white", + "polar": { + "angularaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + }, + "bgcolor": "white", + "radialaxis": { + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "yaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + }, + "zaxis": { + "backgroundcolor": "white", + "gridcolor": "#DFE8F3", + "gridwidth": 2, + "linecolor": "#EBF0F8", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#EBF0F8" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "baxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + }, + "bgcolor": "white", + "caxis": { + "gridcolor": "#DFE8F3", + "linecolor": "#A2B1C6", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "#EBF0F8", + "linecolor": "#EBF0F8", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#EBF0F8", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "E-Commerce Sales Dashboard — 2025" + }, + "xaxis": { + "anchor": "y", + "domain": [ + 0, + 0.45 + ] + }, + "xaxis2": { + "anchor": "y2", + "domain": [ + 0.55, + 1 + ], + "tickangle": 45 + }, + "xaxis3": { + "anchor": "y3", + "domain": [ + 0, + 0.45 + ] + }, + "yaxis": { + "anchor": "x", + "domain": [ + 0.625, + 1 + ] + }, + "yaxis2": { + "anchor": "x2", + "domain": [ + 0.625, + 1 + ] + }, + "yaxis3": { + "anchor": "x3", + "domain": [ + 0, + 0.375 + ] + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def red_dashboard():\n", + " \"\"\"\n", + " Capstone:完整的互動式儀表板\n", + "\n", + " 流程:\n", + " 1. 清理 orders_raw.csv + 合併三張表\n", + " 2. 建立 2×2 subplot dashboard(用 plotly make_subplots):\n", + " - 左上:月營收趨勢 (line)\n", + " - 右上:Top 10 商品營收 (bar)\n", + " - 左下:各地區營收 (bar)\n", + " - 右下:類別營收佔比 (pie/donut)\n", + " 3. 設定整體標題\n", + "\n", + " 回傳 plotly Figure 物件\n", + " 提示:from plotly.subplots import make_subplots\n", + " \"\"\"\n", + " # TODO: 你的程式碼\n", + "monthly = enriched.groupby('month', as_index=False)['amount'].sum()\n", + "top_prod = (enriched.groupby('product_name', as_index=False)['amount']\n", + " .sum().sort_values('amount', ascending=False).head(10))\n", + "region_rev = enriched.groupby('region', as_index=False)['amount'].sum()\n", + "cat_rev = enriched.groupby('category', as_index=False)['amount'].sum()\n", + "\n", + "fig = make_subplots(\n", + " rows=2, cols=2,\n", + " subplot_titles=('Monthly Revenue Trend',\n", + " 'Top 10 Products',\n", + " 'Revenue by Region',\n", + " 'Category Share'),\n", + " specs=[[{'type':'xy'}, {'type':'xy'}],\n", + " [{'type':'xy'}, {'type':'domain'}]],\n", + ")\n", + "\n", + "fig.add_trace(go.Line(x=monthly['month'], y=monthly['amount'],\n", + " mode='lines+markers', name='Monthly'), row=1, col=1)\n", + "fig.add_trace(go.Bar(x=top_prod['product_name'], y=top_prod['amount'],\n", + " name='Top Products'), row=1, col=2)\n", + "fig.add_trace(go.Bar(x=region_rev['region'], y=region_rev['amount'],\n", + " name='Region'), row=2, col=1)\n", + "fig.add_trace(go.Pie(labels=cat_rev['category'], values=cat_rev['amount'],\n", + " name='Category', hole=0.4), row=2, col=2)\n", + "\n", + "fig.update_layout(\n", + " title_text='E-Commerce Sales Dashboard — 2025',\n", + " height=750, showlegend=False,\n", + ")\n", + "fig.update_xaxes(tickangle=45, row=1, col=2)\n", + "fig.show()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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 +}