{
 "id": "kpi_pack",
 "title": "A weekly KPI report: how did the last full week go?",
 "question": "How did the last full week of the data go: revenue, orders, customers and cancellations, against the week before and the same week a year earlier?",
 "source": {
  "name": "UCI Online Retail II",
  "publisher": "Chen, D. (2012), UCI Machine Learning Repository",
  "url": "https://archive.ics.uci.edu/dataset/502/online+retail+ii",
  "license": "CC BY 4.0",
  "as_of": "December 2011",
  "rows_raw": 1067371,
  "rows_used": 1021254,
  "caveat": "A UK online gift retailer selling mostly to wholesale customers. It trades Sunday to Friday (one Saturday, Dec 5, 2009, has invoices), and the weeks before Christmas are its busiest."
 },
 "windows": {
  "week_start": "2011-11-28",
  "week_end": "2011-12-04",
  "prior_start": "2011-11-21",
  "prior_end": "2011-11-27",
  "ly_start": "2010-11-29",
  "ly_end": "2010-12-05",
  "chart_first": "2011-09-12",
  "data_first": "2009-12-01",
  "data_last": "2011-12-09 12:50:00",
  "partial_week_start": "2011-12-05",
  "lookback_days": 364,
  "min_mover": 1000
 },
 "kpis": [
  {
   "key": "net_revenue",
   "label": "Net revenue",
   "kind": "gbp",
   "card": true,
   "week": 306115.06,
   "prior": 295233.31,
   "ly": 309029.05,
   "vs_prior": 3.7,
   "vs_ly": -0.9
  },
  {
   "key": "gross",
   "label": "Sales before cancellations",
   "kind": "gbp",
   "card": false,
   "week": 309381.73,
   "prior": 302392.22,
   "ly": 317195.43,
   "vs_prior": 2.3,
   "vs_ly": -2.5
  },
  {
   "key": "orders",
   "label": "Orders",
   "kind": "int",
   "card": true,
   "week": 663,
   "prior": 616,
   "ly": 652,
   "vs_prior": 7.6,
   "vs_ly": 1.7
  },
  {
   "key": "aov",
   "label": "Average order value (before cancellations)",
   "kind": "gbp2",
   "card": true,
   "week": 466.64,
   "prior": 490.9,
   "ly": 486.5,
   "vs_prior": -4.9,
   "vs_ly": -4.1
  },
  {
   "key": "customers",
   "label": "Identified customers",
   "kind": "int",
   "card": true,
   "week": 514,
   "prior": 492,
   "ly": 465,
   "vs_prior": 4.5,
   "vs_ly": 10.5
  },
  {
   "key": "new_customers",
   "label": "New customers (identified)",
   "kind": "int",
   "card": false,
   "week": 44,
   "prior": 60,
   "ly": 54,
   "vs_prior": -26.7,
   "vs_ly": -18.5
  },
  {
   "key": "repeat_share",
   "label": "Repeat-customer share (of identified customers)",
   "kind": "share",
   "card": true,
   "week": 91.4,
   "prior": 87.8,
   "ly": 88.4,
   "vs_prior": 3.6,
   "vs_ly": 3.0
  },
  {
   "key": "cancel_inv_share",
   "label": "Cancellation invoices, % of all invoices",
   "kind": "share",
   "card": true,
   "week": 14.5,
   "prior": 9.0,
   "ly": 12.5,
   "vs_prior": 5.5,
   "vs_ly": 2.0
  },
  {
   "key": "cancel_value_share",
   "label": "Cancelled value, % of sales before cancellations",
   "kind": "share",
   "card": true,
   "week": 1.1,
   "prior": 2.4,
   "ly": 2.6,
   "vs_prior": -1.3,
   "vs_ly": -1.5
  },
  {
   "key": "units",
   "label": "Units sold",
   "kind": "int",
   "card": true,
   "week": 156350,
   "prior": 154803,
   "ly": 156788,
   "vs_prior": 1.0,
   "vs_ly": -0.3
  },
  {
   "key": "no_id_share",
   "label": "Lines with no customer id, % of sales lines",
   "kind": "share",
   "card": false,
   "week": 27.0,
   "prior": 24.1,
   "ly": 23.9,
   "vs_prior": 2.9,
   "vs_ly": 3.1
  }
 ],
 "numbers": {
  "no_id_share": 27.0,
  "lines": 18298,
  "lines_no_id": 4947,
  "gross": 309381.73,
  "cancelled": 3266.67,
  "cancel_invoices": 112,
  "repeat_customers": 470,
  "products_in_week": 2272,
  "products_either_week": 2602,
  "facts": {
   "repeat_week_is_12wk_high": true,
   "cancel_prior_is_12wk_low": true,
   "nl_fall_over_uk_gain_pct": 57.6
  },
  "countries_in_week": 14,
  "uk_share_week": 90.7,
  "rank12": 9,
  "rank12_ly": 10,
  "products_meeting_rule": 57,
  "countries_meeting_rule": 11,
  "ly_orders": 652,
  "ly_cancelled": 8166.38,
  "weeks_in_data": 106,
  "empty_weeks": [
   "2009-12-28",
   "2010-12-27"
  ],
  "saturday_dates": [
   "2009-12-05"
  ],
  "partial_week": {
   "gross": 483725.13,
   "cancelled": 172781.77,
   "orders": 509,
   "cancel_invoices": 79,
   "last_day": "2011-12-09"
  }
 },
 "chart12": [
  {
   "week_start": "2011-09-12",
   "net_revenue": 222269.79,
   "net_revenue_ly": 160890.59,
   "orders": 360,
   "repeat_share": 83.4,
   "cancel_inv_share": 17.2,
   "cancel_value_share": 0.7,
   "customers": 301
  },
  {
   "week_start": "2011-09-19",
   "net_revenue": 319745.94,
   "net_revenue_ly": 235861.58,
   "orders": 463,
   "repeat_share": 80.2,
   "cancel_inv_share": 15.8,
   "cancel_value_share": 2.7,
   "customers": 383
  },
  {
   "week_start": "2011-09-26",
   "net_revenue": 202358.82,
   "net_revenue_ly": 287114.44,
   "orders": 441,
   "repeat_share": 85.8,
   "cancel_inv_share": 14.4,
   "cancel_value_share": 2.0,
   "customers": 374
  },
  {
   "week_start": "2011-10-03",
   "net_revenue": 300307.48,
   "net_revenue_ly": 254361.31,
   "orders": 488,
   "repeat_share": 77.6,
   "cancel_inv_share": 17.0,
   "cancel_value_share": 3.4,
   "customers": 389
  },
  {
   "week_start": "2011-10-10",
   "net_revenue": 204251.49,
   "net_revenue_ly": 305222.49,
   "orders": 448,
   "repeat_share": 84.4,
   "cancel_inv_share": 13.0,
   "cancel_value_share": 7.7,
   "customers": 360
  },
  {
   "week_start": "2011-10-17",
   "net_revenue": 259053.85,
   "net_revenue_ly": 232404.11,
   "orders": 446,
   "repeat_share": 80.2,
   "cancel_inv_share": 12.4,
   "cancel_value_share": 2.0,
   "customers": 364
  },
  {
   "week_start": "2011-10-24",
   "net_revenue": 234202.83,
   "net_revenue_ly": 202217.12,
   "orders": 519,
   "repeat_share": 84.7,
   "cancel_inv_share": 12.3,
   "cancel_value_share": 3.5,
   "customers": 419
  },
  {
   "week_start": "2011-10-31",
   "net_revenue": 288344.46,
   "net_revenue_ly": 274381.82,
   "orders": 527,
   "repeat_share": 85.0,
   "cancel_inv_share": 13.6,
   "cancel_value_share": 1.5,
   "customers": 441
  },
  {
   "week_start": "2011-11-07",
   "net_revenue": 350123.4,
   "net_revenue_ly": 359397.51,
   "orders": 634,
   "repeat_share": 87.0,
   "cancel_inv_share": 13.5,
   "cancel_value_share": 2.1,
   "customers": 514
  },
  {
   "week_start": "2011-11-14",
   "net_revenue": 369129.47,
   "net_revenue_ly": 342743.77,
   "orders": 687,
   "repeat_share": 87.7,
   "cancel_inv_share": 13.0,
   "cancel_value_share": 1.1,
   "customers": 569
  },
  {
   "week_start": "2011-11-21",
   "net_revenue": 295233.31,
   "net_revenue_ly": 286262.18,
   "orders": 616,
   "repeat_share": 87.8,
   "cancel_inv_share": 9.0,
   "cancel_value_share": 2.4,
   "customers": 492
  },
  {
   "week_start": "2011-11-28",
   "net_revenue": 306115.06,
   "net_revenue_ly": 309029.05,
   "orders": 663,
   "repeat_share": 91.4,
   "cancel_inv_share": 14.5,
   "cancel_value_share": 1.1,
   "customers": 514
  }
 ],
 "movers": {
  "products_up": [
   [
    "Rabbit night light",
    "23084",
    9246.92,
    5078.57,
    4168.35
   ],
   [
    "Vintage doily jumbo bag red",
    "23582",
    3406.58,
    642.48,
    2764.1
   ],
   [
    "Cook with wine metal sign",
    "21166",
    2417.11,
    24.96,
    2392.15
   ],
   [
    "Heart of wicker large",
    "22470",
    2694.89,
    425.25,
    2269.64
   ],
   [
    "No singing metal sign",
    "82600",
    2200.58,
    18.9,
    2181.68
   ]
  ],
  "products_down": [
   [
    "Chilli lights",
    "79321",
    1717.92,
    4960.25,
    -3242.33
   ],
   [
    "Pink 3 piece mini dots cutlery set",
    "84997D",
    494.0,
    2067.9,
    -1573.9
   ],
   [
    "Spotty bunting",
    "23298",
    583.6,
    2070.64,
    -1487.04
   ],
   [
    "Party bunting",
    "47566",
    735.83,
    2152.79,
    -1416.96
   ],
   [
    "Black record cover frame",
    "21137",
    735.8,
    2071.47,
    -1335.67
   ]
  ],
  "countries_up": [
   [
    "United Kingdom",
    277739.02,
    259185.03,
    18553.99
   ],
   [
    "Japan",
    3651.6,
    0.0,
    3651.6
   ],
   [
    "France",
    7464.53,
    4480.91,
    2983.62
   ],
   [
    "Finland",
    1709.05,
    270.0,
    1439.05
   ],
   [
    "Norway",
    2843.29,
    1696.78,
    1146.51
   ]
  ],
  "countries_down": [
   [
    "Netherlands",
    104.0,
    10798.24,
    -10694.24
   ],
   [
    "Spain",
    170.74,
    3483.96,
    -3313.22
   ],
   [
    "Italy",
    -197.8,
    2453.8,
    -2651.6
   ],
   [
    "Germany",
    4599.23,
    5871.22,
    -1271.99
   ]
  ]
 },
 "detail": {
  "first_week": "2011-09-05",
  "weeks": 13,
  "product_rows": 4984,
  "products": 412,
  "country_rows": 199,
  "keep_min": 500
 },
 "sample_queries": [
  {
   "label": "The last 12 full weeks, with the change from the week before",
   "sql": "-- The last 12 full weeks (Monday to Sunday), with the change from the week before (Live SQL table: Dec 2010 to Dec 2011)\nWITH w AS (\n    SELECT date_trunc('week', invoice_date)::DATE AS week_start,\n           sum(line_revenue) AS net_revenue,\n           count(DISTINCT invoice) FILTER (WHERE NOT is_cancelled) AS orders,\n           sum(line_revenue) FILTER (WHERE NOT is_cancelled) / count(DISTINCT invoice) FILTER (WHERE NOT is_cancelled) AS avg_order_value,\n           count(DISTINCT customer_id) FILTER (WHERE NOT is_cancelled) AS customers,\n           100.0 * count(DISTINCT invoice) FILTER (WHERE is_cancelled) / count(DISTINCT invoice) AS cancel_invoice_pct\n    FROM retail_orders\n    WHERE invoice_date >= DATE '2011-09-05' AND invoice_date < DATE '2011-12-05'\n    GROUP BY 1\n)\nSELECT week_start,\n       round(net_revenue) AS net_revenue_gbp,\n       round(100.0 * (net_revenue / lag(net_revenue) OVER (ORDER BY week_start) - 1), 1) AS vs_week_before_pct,\n       orders,\n       round(avg_order_value) AS avg_order_value_gbp,\n       customers,\n       round(cancel_invoice_pct, 1) AS cancel_invoice_pct\nFROM w\nORDER BY week_start DESC\nLIMIT 12",
   "live_output": {
    "columns": [
     "week_start",
     "net_revenue_gbp",
     "vs_week_before_pct",
     "orders",
     "avg_order_value_gbp",
     "customers",
     "cancel_invoice_pct"
    ],
    "rows": [
     [
      "2011-11-28",
      306115.0,
      3.7,
      663,
      467.0,
      514,
      14.5
     ],
     [
      "2011-11-21",
      295233.0,
      -20.0,
      616,
      491.0,
      492,
      9.0
     ],
     [
      "2011-11-14",
      369129.0,
      5.4,
      687,
      543.0,
      569,
      13.0
     ],
     [
      "2011-11-07",
      350123.0,
      21.4,
      634,
      564.0,
      514,
      13.5
     ],
     [
      "2011-10-31",
      288344.0,
      23.1,
      527,
      555.0,
      441,
      13.6
     ],
     [
      "2011-10-24",
      234203.0,
      -9.6,
      519,
      468.0,
      419,
      12.3
     ],
     [
      "2011-10-17",
      259054.0,
      26.8,
      446,
      593.0,
      364,
      12.4
     ],
     [
      "2011-10-10",
      204251.0,
      -32.0,
      448,
      494.0,
      360,
      13.0
     ],
     [
      "2011-10-03",
      300307.0,
      48.4,
      488,
      637.0,
      389,
      17.0
     ],
     [
      "2011-09-26",
      202359.0,
      -36.7,
      441,
      468.0,
      374,
      14.4
     ],
     [
      "2011-09-19",
      319746.0,
      43.9,
      463,
      710.0,
      383,
      15.8
     ],
     [
      "2011-09-12",
      222270.0,
      20.0,
      360,
      622.0,
      301,
      17.2
     ]
    ]
   }
  },
  {
   "label": "Biggest rises and falls by product against the week before",
   "sql": "-- Biggest rises and falls in net revenue by product, Nov 28 to Dec 4, 2011 against the week before (Live SQL table; stock codes, no descriptions)\nWITH p AS (\n    SELECT upper(stock_code) AS code,\n           coalesce(sum(line_revenue) FILTER (WHERE invoice_date BETWEEN DATE '2011-11-28' AND DATE '2011-12-04'), 0) AS this_week,\n           coalesce(sum(line_revenue) FILTER (WHERE invoice_date BETWEEN DATE '2011-11-21' AND DATE '2011-11-27'), 0) AS week_before\n    FROM retail_orders\n    GROUP BY 1\n), r AS (\n    SELECT *, this_week - week_before AS change,\n           row_number() OVER (ORDER BY this_week - week_before DESC, code) AS up_rank,\n           row_number() OVER (ORDER BY this_week - week_before, code) AS down_rank\n    FROM p\n    WHERE this_week >= 1000 OR week_before >= 1000          -- the size rule: at least 1,000 in either week\n)\nSELECT code, round(this_week) AS this_week_gbp, round(week_before) AS week_before_gbp, round(change) AS change_gbp\nFROM r\nWHERE up_rank <= 5 OR down_rank <= 5\nORDER BY change DESC",
   "live_output": {
    "columns": [
     "code",
     "this_week_gbp",
     "week_before_gbp",
     "change_gbp"
    ],
    "rows": [
     [
      "23084",
      9247.0,
      5079.0,
      4168.0
     ],
     [
      "23582",
      3407.0,
      642.0,
      2764.0
     ],
     [
      "21166",
      2417.0,
      25.0,
      2392.0
     ],
     [
      "22470",
      2695.0,
      425.0,
      2270.0
     ],
     [
      "82600",
      2201.0,
      19.0,
      2182.0
     ],
     [
      "21137",
      736.0,
      2071.0,
      -1336.0
     ],
     [
      "47566",
      736.0,
      2153.0,
      -1417.0
     ],
     [
      "23298",
      584.0,
      2071.0,
      -1487.0
     ],
     [
      "84997D",
      494.0,
      2068.0,
      -1574.0
     ],
     [
      "79321",
      1718.0,
      4960.0,
      -3242.0
     ]
    ]
   }
  }
 ],
 "live_table": {
  "rows": 531205,
  "first": "2010-12-01",
  "last": "2011-12-09"
 },
 "cleaning": [
  "Dropped non-product stock codes (POST, DOT, M, m, D, BANK CHARGES, AMAZONFEE, C2, PADS, CRUK, ADJUST, ADJUST2, S, B, TEST001/002, gift card vouchers) that represent postage, fees, manual adjustments, and test rows rather than real merchandise.",
  "Dropped rows with price <= 0 (6,207 rows); nearly all of these have no Customer ID and are internal adjustments, not customer sales.",
  "Dropped negative-quantity rows on invoices that do not start with 'C' (3,457 rows); a true return in this dataset is a cancellation invoice (prefix 'C').",
  "Removed 34,035 exact duplicate line items (after the rules above).",
  "Weeks run Monday to Sunday and are dated by the invoice line's date. The data begins on Tuesday Dec 1, 2009 and ends on Friday Dec 9, 2011 at 12:50, so the first week (from Nov 30, 2009) and the last (from Dec 5, 2011) are partial; the report is for the last full week, Nov 28 to Dec 4, 2011.",
  "Every change is against one of two weeks: the week before (Nov 21 to 27, 2011) or the same week of 2010 (Nov 29 to Dec 5, 2010, 52 weeks earlier).",
  "A cancellation is dated on the day of the cancellation invoice, not on the day of the order it cancels, so a week's cancellations can undo earlier weeks' orders."
 ],
 "checks": [
  "The cleaning reproduces the live Online retail page: 1,067,371 source rows and 1,021,254 after cleaning; the last invoice is Dec 9, 2011 at 12:50.",
  "Every figure in the charts, cards and findings was recomputed by separate code (verify_kpi.py: plain Python reading the original UCI zip, with no DuckDB and no intermediate files) and matches, week by week, product by product and country by country.",
  "The two queries below were run on the Live SQL table (13 months) in DuckDB 1.5.5. The weeks they cover are inside that table, so their figures are the full-history figures on this page, to the pound."
 ]
}