Skip to content

Commit

Permalink
feat: Add P75 quantile (#27409)
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaeelaudibert authored Jan 9, 2025
1 parent 022d623 commit 3539cce
Show file tree
Hide file tree
Showing 14 changed files with 56 additions and 7 deletions.
2 changes: 1 addition & 1 deletion frontend/src/lib/components/InsightLabel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function MathTag({ math, mathProperty, mathHogQL, mathGroupTypeIndex }: MathTagP
if (math === 'unique_group' && mathGroupTypeIndex != undefined) {
return <LemonTag>Unique {aggregationLabel(mathGroupTypeIndex).plural}</LemonTag>
}
if (math && ['sum', 'avg', 'min', 'max', 'median', 'p90', 'p95', 'p99'].includes(math || '')) {
if (math && ['sum', 'avg', 'min', 'max', 'median', 'p75', 'p90', 'p95', 'p99'].includes(math)) {
return (
<>
<LemonTag>{mathDefinitions[math]?.name || capitalizeFirstLetter(math)}</LemonTag>
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3906,6 +3906,7 @@
"min_count_per_actor",
"max_count_per_actor",
"median_count_per_actor",
"p75_count_per_actor",
"p90_count_per_actor",
"p95_count_per_actor",
"p99_count_per_actor"
Expand Down Expand Up @@ -9099,7 +9100,7 @@
"type": "object"
},
"PropertyMathType": {
"enum": ["avg", "sum", "min", "max", "median", "p90", "p95", "p99"],
"enum": ["avg", "sum", "min", "max", "median", "p75", "p90", "p95", "p99"],
"type": "string"
},
"PropertyOperator": {
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/scenes/cohorts/CohortFilters/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ export const FIELD_VALUES: Record<FieldOptionsType, FieldValues> = {
[PropertyMathType.Median]: {
label: 'Median',
},
[PropertyMathType.P75]: {
label: '75th percentile',
},
[PropertyMathType.P90]: {
label: '90th percentile',
},
Expand Down
19 changes: 19 additions & 0 deletions frontend/src/scenes/trends/mathsLogic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,19 @@ export const PROPERTY_MATH_DEFINITIONS: Record<PropertyMathType, MathDefinition>
),
category: MathCategory.PropertyValue,
},
[PropertyMathType.P75]: {
name: '75th percentile',
shortName: '75th percentile',
description: (
<>
Event property 75th percentile.
<br />
<br />
For example 100 events captured with property <code>amount</code> equal to 101..200, result in 175.
</>
),
category: MathCategory.PropertyValue,
},
[PropertyMathType.P90]: {
name: '90th percentile',
shortName: '90th percentile',
Expand Down Expand Up @@ -315,6 +328,12 @@ export const COUNT_PER_ACTOR_MATH_DEFINITIONS: Record<CountPerActorMathType, Mat
description: <>Event count per actor 50th percentile.</>,
category: MathCategory.EventCountPerActor,
},
[CountPerActorMathType.P75]: {
name: '75th percentile',
shortName: '75th percentile',
description: <>Event count per actor 75th percentile.</>,
category: MathCategory.EventCountPerActor,
},
[CountPerActorMathType.P90]: {
name: '90th percentile',
shortName: '90th percentile',
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3652,6 +3652,7 @@ export enum PropertyMathType {
Minimum = 'min',
Maximum = 'max',
Median = 'median',
P75 = 'p75',
P90 = 'p90',
P95 = 'p95',
P99 = 'p99',
Expand All @@ -3662,6 +3663,7 @@ export enum CountPerActorMathType {
Minimum = 'min_count_per_actor',
Maximum = 'max_count_per_actor',
Median = 'median_count_per_actor',
P75 = 'p75_count_per_actor',
P90 = 'p90_count_per_actor',
P95 = 'p95_count_per_actor',
P99 = 'p99_count_per_actor',
Expand Down
1 change: 1 addition & 0 deletions posthog/api/documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ class PersonPropertiesSerializer(serializers.Serializer):
- `min`: min of a numeric property.
- `max`: max of a numeric property.
- `median`: median of a numeric property.
- `p75`: 75th percentile of a numeric property.
- `p90`: 90th percentile of a numeric property.
- `p95` 95th percentile of a numeric property.
- `p99`: 99th percentile of a numeric property.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ def select_aggregation(self) -> ast.Expr:
return self._math_func("max", None)
elif self.series.math == "median":
return self._math_quantile(0.5, None)
elif self.series.math == "p75":
return self._math_quantile(0.75, None)
elif self.series.math == "p90":
return self._math_quantile(0.9, None)
elif self.series.math == "p95":
Expand Down Expand Up @@ -106,6 +108,7 @@ def is_count_per_actor_variant(self):
"min_count_per_actor",
"max_count_per_actor",
"median_count_per_actor",
"p75_count_per_actor",
"p90_count_per_actor",
"p95_count_per_actor",
"p99_count_per_actor",
Expand Down Expand Up @@ -247,6 +250,8 @@ def _actors_inner_select_query(
math_func = self._math_func("max", ["total"])
elif self.series.math == "median_count_per_actor":
math_func = self._math_quantile(0.5, ["total"])
elif self.series.math == "p75_count_per_actor":
math_func = self._math_quantile(0.75, ["total"])
elif self.series.math == "p90_count_per_actor":
math_func = self._math_quantile(0.9, ["total"])
elif self.series.math == "p95_count_per_actor":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,15 @@
[PropertyMathType.MIN, "$browser"],
[PropertyMathType.MAX, "$browser"],
[PropertyMathType.MEDIAN, "$browser"],
[PropertyMathType.P75, "$browser"],
[PropertyMathType.P90, "$browser"],
[PropertyMathType.P95, "$browser"],
[PropertyMathType.P99, "$browser"],
[CountPerActorMathType.AVG_COUNT_PER_ACTOR, None],
[CountPerActorMathType.MIN_COUNT_PER_ACTOR, None],
[CountPerActorMathType.MAX_COUNT_PER_ACTOR, None],
[CountPerActorMathType.MEDIAN_COUNT_PER_ACTOR, None],
[CountPerActorMathType.P75_COUNT_PER_ACTOR, None],
[CountPerActorMathType.P90_COUNT_PER_ACTOR, None],
[CountPerActorMathType.P95_COUNT_PER_ACTOR, None],
[CountPerActorMathType.P99_COUNT_PER_ACTOR, None],
Expand Down Expand Up @@ -79,13 +81,15 @@ def test_all_cases_return(
[PropertyMathType.MIN, False],
[PropertyMathType.MAX, False],
[PropertyMathType.MEDIAN, False],
[PropertyMathType.P75, False],
[PropertyMathType.P90, False],
[PropertyMathType.P95, False],
[PropertyMathType.P99, False],
[CountPerActorMathType.AVG_COUNT_PER_ACTOR, True],
[CountPerActorMathType.MIN_COUNT_PER_ACTOR, True],
[CountPerActorMathType.MAX_COUNT_PER_ACTOR, True],
[CountPerActorMathType.MEDIAN_COUNT_PER_ACTOR, True],
[CountPerActorMathType.P75_COUNT_PER_ACTOR, True],
[CountPerActorMathType.P90_COUNT_PER_ACTOR, True],
[CountPerActorMathType.P95_COUNT_PER_ACTOR, True],
[CountPerActorMathType.P99_COUNT_PER_ACTOR, True],
Expand Down
4 changes: 4 additions & 0 deletions posthog/hogql_queries/insights/trends/test/test_trends.py
Original file line number Diff line number Diff line change
Expand Up @@ -4094,6 +4094,10 @@ def test_max_filtering(self):
def test_median_filtering(self):
self._test_math_property_aggregation("median", values=range(101, 201), expected_value=150)

@also_test_with_materialized_columns(["some_number"])
def test_p75_filtering(self):
self._test_math_property_aggregation("p75", values=range(101, 201), expected_value=175)

@also_test_with_materialized_columns(["some_number"])
def test_p90_filtering(self):
self._test_math_property_aggregation("p90", values=range(101, 201), expected_value=190)
Expand Down
4 changes: 2 additions & 2 deletions posthog/management/commands/compare_hogql_insights.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ def handle(self, *args, **options):
# len(insights)
for insight in insights[0:500]:
for event in insight.filters.get("events", []):
if event.get("math") in ("median", "p90", "p95", "p99"):
if event.get("math") in ("median", "p75", "p90", "p95", "p99"):
event["math"] = "sum"
for event in insight.filters.get("actions", []):
if event.get("math") in ("median", "p90", "p95", "p99"):
if event.get("math") in ("median", "p75", "p90", "p95", "p99"):
event["math"] = "sum"
try:
print( # noqa: T201
Expand Down
8 changes: 5 additions & 3 deletions posthog/models/entity/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,26 @@
"monthly_active",
"unique_group",
"unique_session",
# TODO: When we are finally on Python 3.11+, inline the below as *PROPERTY_MATH_FUNCTIONS.keys()
"hogql",
# Equivalent to *PROPERTY_MATH_FUNCTIONS.keys(),
"sum",
"min",
"max",
"avg",
"median",
"p75",
"p90",
"p95",
"p99",
# TODO: When we are finally on Python 3.11+, inline the below as *COUNT_PER_ACTOR_MATH_FUNCTIONS.keys()
# Equivalent to *COUNT_PER_ACTOR_MATH_FUNCTIONS.keys()
"min_count_per_actor",
"max_count_per_actor",
"avg_count_per_actor",
"median_count_per_actor",
"p75_count_per_actor",
"p90_count_per_actor",
"p95_count_per_actor",
"p99_count_per_actor",
"hogql",
]


Expand Down
4 changes: 4 additions & 0 deletions posthog/queries/test/test_trends.py
Original file line number Diff line number Diff line change
Expand Up @@ -3611,6 +3611,10 @@ def test_max_filtering(self):
def test_median_filtering(self):
self._test_math_property_aggregation("median", values=range(101, 201), expected_value=150)

@also_test_with_materialized_columns(["some_number"])
def test_p75_filtering(self):
self._test_math_property_aggregation("p75", values=range(101, 201), expected_value=175)

@also_test_with_materialized_columns(["some_number"])
def test_p90_filtering(self):
self._test_math_property_aggregation("p90", values=range(101, 201), expected_value=190)
Expand Down
2 changes: 2 additions & 0 deletions posthog/queries/trends/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"min": "min",
"max": "max",
"median": "quantile(0.50)",
"p75": "quantile(0.75)",
"p90": "quantile(0.90)",
"p95": "quantile(0.95)",
"p99": "quantile(0.99)",
Expand All @@ -43,6 +44,7 @@
"min_count_per_actor": "min",
"max_count_per_actor": "max",
"median_count_per_actor": "quantile(0.50)",
"p75_count_per_actor": "quantile(0.75)",
"p90_count_per_actor": "quantile(0.90)",
"p95_count_per_actor": "quantile(0.95)",
"p99_count_per_actor": "quantile(0.99)",
Expand Down
2 changes: 2 additions & 0 deletions posthog/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ class CountPerActorMathType(StrEnum):
MIN_COUNT_PER_ACTOR = "min_count_per_actor"
MAX_COUNT_PER_ACTOR = "max_count_per_actor"
MEDIAN_COUNT_PER_ACTOR = "median_count_per_actor"
P75_COUNT_PER_ACTOR = "p75_count_per_actor"
P90_COUNT_PER_ACTOR = "p90_count_per_actor"
P95_COUNT_PER_ACTOR = "p95_count_per_actor"
P99_COUNT_PER_ACTOR = "p99_count_per_actor"
Expand Down Expand Up @@ -1290,6 +1291,7 @@ class PropertyMathType(StrEnum):
MIN = "min"
MAX = "max"
MEDIAN = "median"
P75 = "p75"
P90 = "p90"
P95 = "p95"
P99 = "p99"
Expand Down

0 comments on commit 3539cce

Please sign in to comment.