{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collecting seaborn\r\n",
      "  Downloading seaborn-0.12.2-py3-none-any.whl (293 kB)\r\n",
      "\u001B[2K     \u001B[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001B[0m \u001B[32m293.3/293.3 kB\u001B[0m \u001B[31m7.9 MB/s\u001B[0m eta \u001B[36m0:00:00\u001B[0m00:01\u001B[0m\r\n",
      "\u001B[?25hCollecting matplotlib\r\n",
      "  Downloading matplotlib-3.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (11.6 MB)\r\n",
      "\u001B[2K     \u001B[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001B[0m \u001B[32m11.6/11.6 MB\u001B[0m \u001B[31m60.1 MB/s\u001B[0m eta \u001B[36m0:00:00\u001B[0m00:01\u001B[0m00:01\u001B[0m\r\n",
      "\u001B[?25hRequirement already satisfied: pandas in /home/azalea/.conda/envs/311/lib/python3.11/site-packages (1.5.3)\r\n",
      "Requirement already satisfied: numpy in /home/azalea/.conda/envs/311/lib/python3.11/site-packages (1.24.2)\r\n",
      "Requirement already satisfied: tqdm in /home/azalea/.conda/envs/311/lib/python3.11/site-packages (4.65.0)\r\n",
      "Collecting rapidjson\r\n",
      "  Downloading rapidjson-1.0.0-py3-none-any.whl (1.2 kB)\r\n",
      "Collecting contourpy>=1.0.1\r\n",
      "  Downloading contourpy-1.0.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (299 kB)\r\n",
      "\u001B[2K     \u001B[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001B[0m \u001B[32m300.0/300.0 kB\u001B[0m \u001B[31m42.0 MB/s\u001B[0m eta \u001B[36m0:00:00\u001B[0m\r\n",
      "\u001B[?25hCollecting cycler>=0.10\r\n",
      "  Downloading cycler-0.11.0-py3-none-any.whl (6.4 kB)\r\n",
      "Collecting fonttools>=4.22.0\r\n",
      "  Downloading fonttools-4.39.3-py3-none-any.whl (1.0 MB)\r\n",
      "\u001B[2K     \u001B[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001B[0m \u001B[32m1.0/1.0 MB\u001B[0m \u001B[31m69.5 MB/s\u001B[0m eta \u001B[36m0:00:00\u001B[0m\r\n",
      "\u001B[?25hCollecting kiwisolver>=1.0.1\r\n",
      "  Downloading kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB)\r\n",
      "\u001B[2K     \u001B[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001B[0m \u001B[32m1.4/1.4 MB\u001B[0m \u001B[31m63.2 MB/s\u001B[0m eta \u001B[36m0:00:00\u001B[0m\r\n",
      "\u001B[?25hRequirement already satisfied: packaging>=20.0 in /home/azalea/.conda/envs/311/lib/python3.11/site-packages (from matplotlib) (23.0)\r\n",
      "Requirement already satisfied: pillow>=6.2.0 in /home/azalea/.conda/envs/311/lib/python3.11/site-packages (from matplotlib) (9.4.0)\r\n",
      "Requirement already satisfied: pyparsing>=2.3.1 in /home/azalea/.conda/envs/311/lib/python3.11/site-packages (from matplotlib) (3.0.9)\r\n",
      "Requirement already satisfied: python-dateutil>=2.7 in /home/azalea/.conda/envs/311/lib/python3.11/site-packages (from matplotlib) (2.8.2)\r\n",
      "Requirement already satisfied: pytz>=2020.1 in /home/azalea/.conda/envs/311/lib/python3.11/site-packages (from pandas) (2022.7.1)\r\n",
      "Requirement already satisfied: six>=1.5 in /home/azalea/.conda/envs/311/lib/python3.11/site-packages (from python-dateutil>=2.7->matplotlib) (1.16.0)\r\n",
      "Installing collected packages: rapidjson, kiwisolver, fonttools, cycler, contourpy, matplotlib, seaborn\r\n",
      "Successfully installed contourpy-1.0.7 cycler-0.11.0 fonttools-4.39.3 kiwisolver-1.4.4 matplotlib-3.7.1 rapidjson-1.0.0 seaborn-0.12.2\r\n"
     ]
    }
   ],
   "source": [
    "!pip install seaborn matplotlib pandas numpy tqdm rapidjson"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-04-03T09:42:13.735175Z",
     "end_time": "2023-04-03T09:42:28.796233Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [],
   "source": [
    "from __future__ import annotations\n",
    "\n",
    "import matplotlib\n",
    "import rapidjson as json\n",
    "import os\n",
    "from collections import Counter\n",
    "from pathlib import Path\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "from pandas import DataFrame as DF\n",
    "from matplotlib import pyplot as plt\n",
    "import seaborn as sns"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-04-03T09:42:33.692594Z",
     "end_time": "2023-04-03T09:42:34.664945Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 640x480 with 1 Axes>",
      "image/png": "[encoded data, 17584 characters]"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fm = matplotlib.font_manager\n",
    "fm._get_fontconfig_fonts.cache_clear()\n",
    "sns.set(context='notebook', style='ticks', font='Source Han Sans CN', rc={'axes.unicode_minus': False})\n",
    "plt.rcParams[\"font.sans-serif\"] = [\"Source Han Sans CN\"] #设置字体\n",
    "plt.rcParams[\"axes.unicode_minus\"] = False #该语句解决图像中的“-”负号的乱码问题\n",
    "\n",
    "def test_font():\n",
    "    df = DF([{'name': '中文', 'value': 1}, {'name': '喵嗚', 'value': 2}])\n",
    "    sns.barplot(data=df, x='name', y='value')\n",
    "    plt.show()\n",
    "\n",
    "test_font()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-04-03T09:42:47.369662Z",
     "end_time": "2023-04-03T09:42:47.633426Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "start_time": "2023-04-03T09:42:57.123275Z",
     "end_time": "2023-04-03T09:43:48.116854Z"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Loading data: 100%|██████████| 135206/135206 [00:00<00:00, 185481.57it/s]\n",
      "Loading json: 100%|██████████| 135205/135205 [00:49<00:00, 2705.04it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "一共有 135205 個訂單\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "from hypy_utils.tqdm_utils import tq, pmap, smap\n",
    "\n",
    "\n",
    "def _helper(p: Path):\n",
    "    return json.loads(p.read_text())\n",
    "\n",
    "def load_data():\n",
    "    dir = Path('index-data')\n",
    "    files = [(dir / f) for f in tq(os.listdir(dir), 'Loading data') if f.endswith('.json')]\n",
    "    return pmap(_helper, files, desc='Loading json')\n",
    "\n",
    "\n",
    "data = load_data()\n",
    "print(f'一共有 {len(data)} 個訂單')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "outputs": [],
   "source": [
    "delivery = json.loads(Path('data/delivery.json').read_text())\n",
    "delivery: dict[int, dict] = {d['id']: d for d in delivery}\n",
    "\n",
    "for d in data:\n",
    "    d['route'] = d['delivery_name'] + ' to ' + d['area_name']\n",
    "    d['duration'] = ((d['receive_time'] - d['pay_time']) / 60 / 60 / 24) if d['receive_time'] != 0 else None\n",
    "    d['real_package_price'] = float(d['real_package_price'])\n",
    "    d['package_price'] = float(d['package_price'])\n",
    "    d['price_diff'] = d['package_price'] - d['real_package_price']\n",
    "\n",
    "    # d['delivery'] = delivery.get(d['delivery_id']) or {'id': d['delivery_id'], 'name': 'Unknown'}"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-04-03T09:43:55.301846Z",
     "end_time": "2023-04-03T09:43:59.965436Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "所有運輸：\n",
      "> 總訂單量： 135205\n",
      "> 時間中數： 20.51 天\n",
      "> 平均時間： 39.59 天\n",
      "> 時間分佈：\n"
     ]
    },
    {
     "data": {
      "text/plain": "<Figure size 640x480 with 1 Axes>",
      "image/png": "[encoded data, 9564 characters]"
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": "<Figure size 640x480 with 1 Axes>",
      "image/png": "[encoded data, 7972 characters]"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def overall_stats():\n",
    "    durations = [d[\"duration\"] for d in data if d[\"duration\"]]\n",
    "\n",
    "    print('所有運輸：')\n",
    "    print(f'> 總訂單量： {len(data)}')\n",
    "    print(f'> 時間中數： {np.median(durations):.2f} 天')\n",
    "    print(f'> 平均時間： {np.mean(durations):.2f} 天')\n",
    "    print(f'> 時間分佈：')\n",
    "\n",
    "    sns.boxplot(x=durations)\n",
    "    plt.show()\n",
    "    sns.boxplot(x=[d for d in durations if d < 80])\n",
    "    plt.show()\n",
    "\n",
    "overall_stats()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-04-03T09:44:21.771663Z",
     "end_time": "2023-04-03T09:44:22.250463Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "總共有送往 99 個國家的訂單\n",
      "集運目的國家統計： 前 30 國家的訂單數\n"
     ]
    },
    {
     "data": {
      "text/plain": "<Figure size 600x800 with 1 Axes>",
      "image/png": "[encoded data, 61572 characters]"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def bars(lst: list[tuple[str, int]]):\n",
    "    plt.figure(figsize=(6, 8))\n",
    "    sns.barplot(x=[v for k, v in lst], y=[k for k, v in lst], orient='h')\n",
    "    plt.xticks(rotation=90)\n",
    "    plt.grid()\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "def country_stats():\n",
    "    countries = sorted(Counter([d['area_name'] for d in data]).items(), key=lambda x: -x[1])\n",
    "    print(f'總共有送往 {len(countries)} 個國家的訂單')\n",
    "    countries = countries[:30]\n",
    "    print('集運目的國家統計： 前 30 國家的訂單數')\n",
    "    bars(countries)\n",
    "\n",
    "\n",
    "country_stats()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-04-03T09:44:47.609827Z",
     "end_time": "2023-04-03T09:44:48.180899Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "正在分析送往全球的訂單數據...\n",
      "總共有 155 個快遞公司\n",
      "前 50 快遞公司的訂單數（圖1）和運輸時間天數（圖2,3）\n"
     ]
    },
    {
     "data": {
      "text/plain": "<Figure size 1200x1333.33 with 3 Axes>",
      "image/png": "[encoded data, 322788 characters]"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from matplotlib.figure import Figure\n",
    "\n",
    "from matplotlib.axes import Axes\n",
    "\n",
    "\n",
    "def route_stats(country: str | None = None, count: int = 30):\n",
    "    cdata = data\n",
    "    if country is not None:\n",
    "        cdata = [d for d in data if d['area_name'] == country]\n",
    "        print(f'正在分析送往 {country} 的訂單數據...')\n",
    "    else:\n",
    "        print('正在分析送往全球的訂單數據...')\n",
    "\n",
    "    routes = sorted(Counter([d['delivery_name'].strip() for d in cdata]).items(), key=lambda x: -x[1])\n",
    "    print(f'總共有 {len(routes)} 個快遞公司')\n",
    "    routes = routes[:count]\n",
    "    print(f'前 {count} 快遞公司的訂單數（圖1）和運輸時間天數（圖2,3）')\n",
    "    # bars(names)\n",
    "\n",
    "    df = []\n",
    "    for route, cnt in routes:\n",
    "        orders = [d for d in data if d['delivery_name'] == route]\n",
    "        durations = [d['duration'] for d in orders if d['duration']]\n",
    "        df.append({\n",
    "            'Route': route,\n",
    "            'Order Count': cnt,\n",
    "            'Median Duration (days)': np.median(durations) if durations else 0,\n",
    "            'Durations': durations,\n",
    "            # 'Avg Price (USD/kg)': np.mean([d['real_package_price'] / d['final_weight'] for d in orders])\n",
    "        })\n",
    "    df = DF(df)\n",
    "\n",
    "    fig, ax = plt.subplots(ncols=3, figsize=(12, 8 / 30 * count), sharey='all')\n",
    "    fig: Figure\n",
    "    ax: list[Axes]\n",
    "\n",
    "    sns.barplot(x='Order Count', y='Route', data=df, ax=ax[0], orient='h')\n",
    "    sns.boxplot(data=df.Durations, ax=ax[1], orient='h')\n",
    "    sns.barplot(x='Median Duration (days)', y='Route', data=df, ax=ax[2], orient='h')\n",
    "    ax[1].set_xlabel('Duration Distribution (days)')\n",
    "    ax[1].set_xlim(0, 90)\n",
    "    for a in ax:\n",
    "        a.grid()\n",
    "    # ax[0].yaxis.set_ticks(list(df.Route))\n",
    "    plt.show()\n",
    "\n",
    "\n",
    "route_stats(count=50)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-04-03T09:48:18.958438Z",
     "end_time": "2023-04-03T09:48:31.070662Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "正在分析送往 加拿大 的訂單數據...\n",
      "總共有 66 個快遞公司\n",
      "前 50 快遞公司的訂單數（圖1）和運輸時間天數（圖2,3）\n"
     ]
    },
    {
     "data": {
      "text/plain": "<Figure size 1200x1333.33 with 3 Axes>",
      "image/png": "[encoded data, 304084 characters]"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "route_stats('加拿大', count=50)\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-04-03T09:48:52.447143Z",
     "end_time": "2023-04-03T09:48:58.155815Z"
    }
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
