Skip to content

Commit

Permalink
Clean up cohort normalization math
Browse files Browse the repository at this point in the history
  • Loading branch information
JonCrawford committed Jun 12, 2023
1 parent eab69c0 commit 566d4a5
Show file tree
Hide file tree
Showing 35 changed files with 142 additions and 63 deletions.
18 changes: 10 additions & 8 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
repos:
- repo: https://github.com/dbt-checkpoint/dbt-checkpoint
rev: v1.0.0
rev: v1.1.0
hooks:
- id: dbt-docs-generate
- id: check-script-semicolon
files: ^models
- id: check-model-has-properties-file
- id: check-script-has-no-table-name
files: ^models
- id: unify-column-description
- id: generate-model-properties-file
args: ["--properties-file", "/models/{schema}/{name}.yml", "--"]
# - id: unify-column-description
# - id: check-column-name-contract
# args: [--pattern, "(is|has|do)_.*", --dtype, boolean]
- id: check-model-has-all-columns
name: Check columns - mart
files: ^models/mesa/mart
name: Check columns - marts
files: ^models/mesa/marts
- id: check-model-has-tests
files: ^models/mesa/mart
files: ^models/mesa/marts
args: ["--test-cnt", "1", "--"]
- id: check-model-columns-have-desc
files: ^models/mesa/mart
# - id: check-model-columns-have-desc
# files: ^models/mesa/marts

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
Expand All @@ -28,6 +30,6 @@ repos:
- id: trailing-whitespace
exclude: ^.bumpversion.cfg
- repo: https://github.com/pre-commit/mirrors-prettier
rev: "v3.0.0-alpha.4"
rev: "v3.0.0-alpha.6"
hooks:
- id: prettier
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ The application's models are structured into 3 types & folders.

- staging: The initial import of raw source data with filtering and slight formatting.
- intermdiate: intermediary formatting and supporting models that are not business user-facing.
- mart: The finalized production-ready business insight models.
- marts: The finalized production-ready business insight models.

## Oddities & Gotchas

Expand Down
8 changes: 7 additions & 1 deletion dbt_project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ models:
# +on_schema_change: "sync_all_columns"
# +unique_key: shop_subdomain
mesa:
mart:
marts:
step_runs:
+on_schema_change: "sync_all_columns"
+cluster_by: ["shop_subdomain"]
Expand Down Expand Up @@ -145,6 +145,12 @@ models:
staging:
+schema: support

dbt_project_evaluator:
marts:
structure:
fct_model_naming_conventions:
+enabled: false

tests:
shoppad:
mesa:
Expand Down
3 changes: 3 additions & 0 deletions models/generic/staging/stg_constellation_users.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ WITH constellation_users AS (
SELECT
COALESCE(uuid, id) AS shop_subdomain,
createdat AS first_in_constellation_at_utc,
{{ pacific_timestamp('first_in_constellation_at_utc') }} AS first_in_constellation_at_pt,
first_in_constellation_at_pt::DATE AS first_in_constellation_on_pt,
date_trunc('week', first_in_constellation_on_pt) AS constellation_cohort_week,
COALESCE(updatedat, createdat, uuid_ts) AS updated_at,
analytics_gmv,
analytics_orders,
Expand Down
1 change: 1 addition & 0 deletions models/generic/staging/stg_shop_infos.sql
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ WITH flattened_table AS (

FROM {{ source_table }}
WHERE uuid IS NOT NULL
AND DATA != '[]'
QUALIFY ROW_NUMBER() OVER (PARTITION BY shop_subdomain ORDER BY created_at DESC) = 1
),

Expand Down
File renamed without changes.
File renamed without changes.
12 changes: 12 additions & 0 deletions models/mesa/mart/_shops.yml → models/mesa/marts/_shops.yml
Original file line number Diff line number Diff line change
Expand Up @@ -438,3 +438,15 @@ models:
description: The timestamp of the Shop's last email conversion.
- name: first_in_constellation_at_utc
description: The timestamp of the Shop's first install in the constellation.
- name: first_in_constellation_on_pt
description: The date of the Shop's first install in the constellation apart from MESA.
meta:
metabase.display_name: First In Constellation On (PT)
- name: first_in_constellation_at_pt
description: The timestamp of the Shop's first install in the constellation apart from MESA.
meta:
metabase.display_name: First In Constellation At (PT)
- name: constellation_cohort_week
description: The week of the Shop's first install in the constellation apart from MESA.
meta:
metabase.display_name: Constellation Cohort Week
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,5 @@ models:
description: Whether the workflow has been deleted by the Shop.
tests:
- not_null
- name: setup
description: The stage of a template-wizard workflow setup process.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,9 @@ models:
description: Whether the shop completed the wizard on this day.
- name: workflows_created_without_wizard_count
description: The number of workflows created without using the wizard on this day.
- name: is_in_trial
description: Whether the shop is in a trial on this day.
- name: is_shopify_zombie_plan
description: Whether the shop is on a zombie plan on this day.
- name: mesa_plan_identifier
description: The Mesa plan identifier for the shop on this day.
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,23 @@ models:
description:
The percentage of users who first installed in the given month and
have enabled a workflow within the first six months.
- name: shopify_unlimited_plan_count
description: The number of users who have a Shopify Unlimited plan.
- name: shopify_basic_plan_count
description: The number of users who have a Shopify Basic plan.
- name: shopify_trial_plan_count
description: The number of users who have a Shopify Trial plan.
- name: shopify_unlimited_plan_pct
description: The percentage of users who have a Shopify Unlimited plan.
- name: shopify_professional_plan_pct
description: The percentage of users who have a Shopify Professional plan.
- name: shopify_shopify_plus_plan_pct
description: The percentage of users who have a Shopify Plus plan.
- name: shopify_professional_plan_count
description: The number of users who have a Shopify Professional plan.
- name: shopify_trial_plan_pct
description: The percentage of users who have a Shopify Trial plan.
- name: shopify_basic_plan_pct
description: The percentage of users who have a Shopify Basic plan.
- name: shopify_shopify_plus_plan_count
description: The number of users who have a Shopify Plus plan.
Original file line number Diff line number Diff line change
Expand Up @@ -373,13 +373,13 @@ models:
description:
The percentage of users who first installed in the given week and
have enabled a workflow within the first six months.
- name: non_mesa_shop_count
- name: last_period_avg_constellation_cohort_size
description: The number of new installed Shops but are not in the Mesa
segment.
- name: shopify_shopify_plus_plan_count
description: The number of users who have a Shopify Plus plan.
- name: non_mesa_mql_count
description: The number of MQLs who are not in the Mesa segment.
- name: avg_constellation_mql_count
description: The number of MQLs who are not in the Mesa segment averaged over trailing 4 weeks.
- name: shopify_trial_plan_count
description: The number of users who have a trial plan.
- name: shopify_trial_plan_pct
Expand All @@ -392,37 +392,39 @@ models:
description: The percentage of users who have a Basic plan.
- name: shopify_basic_plan_count
description: The number of Mesa users who have a Basic plan.
- name: one_week_non_mesa_mql_growth_rate
- name: avg_constellation_mql_count_growth
description: The percentage of non-MESA MQL shops in the constellation for the given week compared to the week prior.
- name: prior_one_week_non_mesa_customer_count
description: The number of non-MESA new customer app installs in the prior week.
- name: last_period_avg_constellation_cohort_size
description: The rolling average number of non-MESA new customer app installs in the prior week.
- name: shopify_unlimited_plan_pct
description: The percentage of users who have an Unlimited plan.
- name: one_week_mesa_growth_rate
- name: mesa_growth_rate
description: The percentage of new customer MESA installs for the given week compared to the week prior.
- name: one_week_mql_growth_rate
- name: mql_growth_rate
description: The percentage of new customer MQL MESA installs for the given week compared to the week prior.
- name: shopify_unlimited_plan_count
description: The number of users who have an Unlimited plan
- name: prior_one_week_mql_count
description: The number of MQLs in the prior week.
- name: prior_one_week_non_mesa_mql_count
description: The number of non-MESA MQL shops in the constellation in the prior week.
- name: avg_constellation_cohort_size
description: The number of non-MESA MQL shops in the constellation averaged over the last 4 weeks.
- name: shopify_shopify_plus_plan_pct
description: The percentage of users who have a Shopify Plus plan.
- name: mql_count
description: The number of MQLs that installed MESA in the given week.
- name: one_week_non_mesa_growth_rate
description: The percentage of non-MESA new customer app installs for the given week compared to the week prior.
- name: avg_constellation_cohort_size_growth
description: The percentage of non-MESA new customer app installs averaged over the last 4 weeks.
- name: prior_one_week_new_customer_count
description: The number of new customer MESA app installs in the prior week.
- name: one_week_normalized_customer_count
- name: normalized_customer_count
description: The number of new customer MESA installs for the given week normalized by the number of growth rate of the constellation.
- name: normalized_growth_rate
- name: normalized_customer_growth
description: The grwoth rate of MESA normalized by the growth rate of the constellation.
- name: double_normalized_growth_rate
description: The MESA normalized insall count multipled by the normalized growth rate of the constellation.
- name: prior_one_week_normalized_mql_count
description: The number of MQLs in the prior week normalized by the number of growth rate of the constellation.
- name: one_week_normalized_mql_count
- name: normalized_mql_count
description: The number of MQLs in the given week normalized by the number of growth rate of the constellation.
- name: last_period_avg_constellation_mql_count
description: Last week's number of MQLs who are not in the Mesa segment averaged over trailing 4 weeks.
- name: avg_constellation_mql_pct
description: The percentage of MQLs who are not in the Mesa segment averaged over trailing 4 weeks.
- name: normalized_mql_growth
description: The growth rate of MQLs normalized by the growth rate of the constellation.
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,52 @@ models:
- name: monthly_cohort_performance
description: "This table breaks paying shops into cohorts based on when they starrted to pay and into monthly revenue performance"
tests:
- dbt_expectations.expect_compound_columns_to_be_unique:
column_list:
- first_month
- active_month
- dbt_expectations.expect_compound_columns_to_be_unique:
column_list:
- first_month
- active_month
columns:
- name: first_month
description: "The first month the Shop paid us."
tests:
- not_null
- not_null

- name: active_month
description: "The month of the performance."
tests:
- not_null
- not_null

- name: months_since_first
description: "The number of the period after the first paying month."
tests:
- not_null
- not_null

- name: shops
description: "The count of Shops that paid this month."
tests:
- not_null
- not_null

- name: cohort_num_users
description: "The total count of the cohort's Shops at the beginning"
tests:
- not_null
- not_null

- name: retained_pctg
description: "The percent of Shops that paid this month compared to the total cohort."
tests:
- not_null
- not_null

- name: inc_amt
description: "The revenue of this cohort in this month."
tests:
- not_null
- not_null

- name: cum_amt
description: "The sum total of all cohort revenue up through this period."
tests:
- not_null
- not_null

- name: cum_amt_per_user
description: "The average revenue per Shop in this cohort up to this period."
tests:
- not_null
- not_null
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -147,17 +147,45 @@ mql_counts AS (
GROUP BY 1
),

non_mesa_installs AS (
weekly_constellation_installs AS (
SELECT
date_trunc('week', updated_at) AS cohort_week,
COUNT(*) AS non_mesa_shop_count,
COUNT_IF(is_mql) AS non_mesa_mql_count
FROM {{ ref('int_shop_infos') }}
constellation_cohort_week,
COUNT(stg_constellation_users.*) AS constellation_cohort_size,
COUNT_IF(stg_constellation_users.is_mql) AS constellation_mql_count
FROM {{ ref('stg_constellation_users') }}
LEFT OUTER JOIN shops USING (shop_subdomain)
WHERE shop_subdomain NOT IN (SELECT * FROM {{ ref('staff_subdomains') }})
GROUP BY 1
),

constellation_comparison_groups AS (
SELECT
constellation_cohort_week AS cohort_week,
AVG(constellation_cohort_size)
OVER (ORDER BY constellation_cohort_week ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)
AS avg_constellation_cohort_size,
AVG(constellation_mql_count)
OVER (ORDER BY constellation_cohort_week ROWS BETWEEN 3 PRECEDING AND CURRENT ROW)
AS avg_constellation_mql_count,
avg_constellation_mql_count / avg_constellation_cohort_size
AS avg_constellation_mql_pct
FROM weekly_constellation_installs
),

decorated_constellation_comparison_groups AS (
SELECT
*,
LAG(avg_constellation_cohort_size)
OVER (ORDER BY cohort_week) AS last_period_avg_constellation_cohort_size,
LAG(avg_constellation_mql_count)
OVER (ORDER BY cohort_week) AS last_period_avg_constellation_mql_count,
avg_constellation_cohort_size / last_period_avg_constellation_cohort_size - 1
AS avg_constellation_cohort_size_growth,
avg_constellation_mql_count / last_period_avg_constellation_mql_count - 1
AS avg_constellation_mql_count_growth
FROM constellation_comparison_groups
),

shopify_plan_counts AS (
SELECT
cohort_week
Expand All @@ -178,37 +206,31 @@ final AS (
total_ltv_revenue / NULLIF(has_enabled_a_workflow_count, 0) AS lifetime_value_enabled_workflow,
total_ltv_revenue / NULLIF(is_activated_count, 0) AS lifetime_value_activated,

{# Rest of Constellation Growth #}
LAG(non_mesa_shop_count) OVER (ORDER BY cohort_week) AS prior_one_week_non_mesa_customer_count,
1.0 * cohort_size / NULLIF(prior_one_week_non_mesa_customer_count, 0) -1 AS one_week_non_mesa_growth_rate,

{# Rest of Constellation MQL Growth #}
LAG(non_mesa_mql_count) OVER (ORDER BY cohort_week) AS prior_one_week_non_mesa_mql_count,
1.0 * non_mesa_mql_count / NULLIF(prior_one_week_non_mesa_mql_count, 0) - 1 AS one_week_non_mesa_mql_growth_rate,

{# MESA Install Growth #}
LAG(cohort_size) OVER (ORDER BY cohort_week) AS prior_one_week_new_customer_count,
1.0 * cohort_size / NULLIF(prior_one_week_new_customer_count, 0) - 1 AS one_week_mesa_growth_rate,
1.0 * prior_one_week_non_mesa_customer_count / (1 + NULLIF(one_week_non_mesa_growth_rate, 0)) AS one_week_normalized_customer_count,
cohort_size / NULLIF(prior_one_week_new_customer_count, 0) - 1 AS mesa_growth_rate,
cohort_size * NULLIF(1 - avg_constellation_cohort_size_growth, 0) AS normalized_customer_count,
mesa_growth_rate * NULLIF(1 - avg_constellation_cohort_size_growth, 0) AS normalized_customer_growth,

{# MESA MQL Growth #}
LAG(mql_count) OVER (ORDER BY cohort_week) AS prior_one_week_mql_count,
1.0 * mql_count / NULLIF(prior_one_week_mql_count, 0) - 1 AS one_week_mql_growth_rate,
1.0 * mql_count / NULLIF(1 + one_week_non_mesa_mql_growth_rate, 0) AS one_week_normalized_mql_count
mql_count / NULLIF(prior_one_week_mql_count, 0) - 1 AS mql_growth_rate,
mql_count * NULLIF(1 - avg_constellation_mql_count_growth, 0) AS normalized_mql_count,
mql_growth_rate * NULLIF(1 - avg_constellation_mql_count_growth, 0) AS normalized_mql_growth

{# MESA MQL Growth #}
FROM workflow_setup_counts
LEFT JOIN workflows_created_time_buckets USING (cohort_week)
LEFT JOIN workflows_enabled_time_buckets USING (cohort_week)
LEFT JOIN shopify_plan_counts USING (cohort_week)
LEFT JOIN plan_upgrade_counts USING (cohort_week)
LEFT JOIN mql_counts USING (cohort_week)
LEFT JOIN non_mesa_installs USING (cohort_week)
LEFT JOIN decorated_constellation_comparison_groups USING (cohort_week)
)

SELECT
*,
LAG(one_week_normalized_mql_count) OVER (ORDER BY cohort_week) AS prior_one_week_normalized_mql_count,
1.0 * mql_count / NULLIF(prior_one_week_normalized_mql_count, 0) - 1 AS normalized_growth_rate,
1.0 * one_week_normalized_mql_count / NULLIF(prior_one_week_normalized_mql_count, 0) - 1 AS double_normalized_growth_rate
*
FROM final
WHERE cohort_week < date_trunc('week', CURRENT_DATE())
ORDER BY cohort_week DESC
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions models/mesa/staging/stg_step_runs.sql
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ decorated_step_runs AS (
'request',
'uuid',
'priority',
"__HEVO__SOURCE_MODIFIED_AT",
] %}
SELECT
_id AS step_run_id,
Expand Down
2 changes: 2 additions & 0 deletions packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ packages:
version: 0.1.1
- package: dbt-labs/codegen
version: 0.9.0
- package: dbt-labs/dbt_project_evaluator
version: 0.6.2

0 comments on commit 566d4a5

Please sign in to comment.