Skip to content

Different backend support with Ibis ๐Ÿชฝ

icanexplain is implemented with Ibis. This means that it is framework agnostic, and can work with different backends. This example shows how to use it with DuckDB.

import ibis
import icanexplain as ice

products_df = ice.datasets.load_product_footprints()
con = ibis.connect("duckdb://example.ddb")
con.create_table(
    "products", products_df, overwrite=True
)
DatabaseTable: example.main.products
  year       int64
  category   string
  product_id string
  footprint  float64
  units      int64
con = ibis.connect("duckdb://example.ddb")
con.list_tables()
['products']
ibis.options.interactive = True
products = con.table("products")
products.head()
โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”“
โ”ƒ year  โ”ƒ category โ”ƒ product_id โ”ƒ footprint โ”ƒ units โ”ƒ
โ”กโ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”ฉ
โ”‚ int64 โ”‚ string   โ”‚ string     โ”‚ float64   โ”‚ int64 โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  2021 โ”‚ DRESS    โ”‚ 848be709   โ”‚     96.04 โ”‚   803 โ”‚
โ”‚  2021 โ”‚ DRESS    โ”‚ 658f92b3   โ”‚     58.15 โ”‚  3367 โ”‚
โ”‚  2021 โ”‚ DRESS    โ”‚ 3a26f323   โ”‚     82.94 โ”‚   240 โ”‚
โ”‚  2021 โ”‚ DRESS    โ”‚ 6221dca6   โ”‚     85.94 โ”‚   432 โ”‚
โ”‚  2021 โ”‚ DRESS    โ”‚ 46864ac5   โ”‚     84.99 โ”‚   816 โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
explainer = ice.SumExplainer(
    fact='footprint',
    count='units',
    group='category',
    period='year'
)
explanation = explainer(products)
explanation
โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“
โ”ƒ year  โ”ƒ category โ”ƒ inner         โ”ƒ mix           โ”ƒ
โ”กโ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ
โ”‚ int64 โ”‚ string   โ”‚ float64       โ”‚ float64       โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  2022 โ”‚ DRESS    โ”‚  3.931932e+06 โ”‚ -1.881370e+07 โ”‚
โ”‚  2022 โ”‚ JACKET   โ”‚ -1.510008e+07 โ”‚ -9.238617e+07 โ”‚
โ”‚  2022 โ”‚ PANTS    โ”‚  4.002506e+07 โ”‚  5.295190e+07 โ”‚
โ”‚  2022 โ”‚ SHIRT    โ”‚ -1.484809e+06 โ”‚ -5.791456e+06 โ”‚
โ”‚  2022 โ”‚ SWEATER  โ”‚ -2.676209e+07 โ”‚  1.181504e+07 โ”‚
โ”‚  2022 โ”‚ TSHIRT   โ”‚  6.650940e+06 โ”‚ -2.311836e+07 โ”‚
โ”‚  2023 โ”‚ DRESS    โ”‚ -4.078094e+06 โ”‚ -1.240339e+07 โ”‚
โ”‚  2023 โ”‚ JACKET   โ”‚ -6.793317e+06 โ”‚ -4.924036e+07 โ”‚
โ”‚  2023 โ”‚ PANTS    โ”‚ -1.636299e+07 โ”‚ -2.295608e+08 โ”‚
โ”‚  2023 โ”‚ SHIRT    โ”‚  8.920908e+05 โ”‚ -4.019144e+06 โ”‚
โ”‚     โ€ฆ โ”‚ โ€ฆ        โ”‚             โ€ฆ โ”‚             โ€ฆ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
type(explanation)
ibis.expr.types.relations.Table
explanation.execute().style.format()
  year category inner mix
0 2022 DRESS 3931932.447552 -18813695.617552
1 2022 JACKET -15100081.026506 -92386166.203493
2 2022 PANTS 40025058.515251 52951900.074743
3 2022 SHIRT -1484809.008950 -5791455.871050
4 2022 SWEATER -26762091.196715 11815043.806715
5 2022 TSHIRT 6650940.137541 -23118359.127541
6 2023 DRESS -4078094.357618 -12403387.412381
7 2023 JACKET -6793316.568952 -49240364.221049
8 2023 PANTS -16362993.150075 -229560842.809919
9 2023 SHIRT 892090.812023 -4019143.772023
10 2023 SWEATER -5701391.450394 -113050731.029606
11 2023 TSHIRT -11503906.840478 -83913226.849522
ibis.to_sql(explanation)
SELECT
  *
FROM (
  SELECT
    "t9"."year",
    "t9"."category",
    "t9"."count_lag" * (
      "t9"."mean" - "t9"."mean_lag"
    ) AS "inner",
    (
      "t9"."count" - "t9"."count_lag"
    ) * "t9"."mean" AS "mix"
  FROM (
    SELECT
      "t8"."category",
      "t8"."year",
      "t8"."mean",
      "t8"."count",
      LAG("t8"."mean", 1) OVER (PARTITION BY "t8"."category" ORDER BY "t8"."year" ASC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS "mean_lag",
      LAG("t8"."count", 1) OVER (PARTITION BY "t8"."category" ORDER BY "t8"."year" ASC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS "count_lag"
    FROM (
      SELECT
        "t7"."category",
        "t7"."year",
        COALESCE("t7"."mean", 0) AS "mean",
        COALESCE("t7"."count", 0) AS "count"
      FROM (
        SELECT
          "t3"."category",
          "t4"."year",
          "t6"."mean",
          "t6"."count"
        FROM (
          SELECT DISTINCT
            "t0"."category"
          FROM "products" AS "t0"
        ) AS "t3"
        CROSS JOIN (
          SELECT DISTINCT
            "t0"."year"
          FROM "products" AS "t0"
        ) AS "t4"
        LEFT OUTER JOIN (
          SELECT
            "t0"."category",
            "t0"."year",
            SUM("t0"."footprint" * "t0"."units") / SUM("t0"."units") AS "mean",
            SUM("t0"."units") AS "count"
          FROM "products" AS "t0"
          GROUP BY
            1,
            2
        ) AS "t6"
          ON "t3"."category" = "t6"."category" AND "t4"."year" = "t6"."year"
      ) AS "t7"
    ) AS "t8"
  ) AS "t9"
  ORDER BY
    "t9"."year" ASC,
    "t9"."category" ASC
) AS "t10"
WHERE
  "t10"."year" IS NOT NULL
  AND "t10"."category" IS NOT NULL
  AND "t10"."inner" IS NOT NULL
  AND "t10"."mix" IS NOT NULL