mirror of
https://github.com/christianvidalwolf-prog/CrazeAnalytix.git
synced 2026-08-03 12:25:22 +02:00
fix(experiments): use exact fractional proportions for overlapping weeks in DiD calculation
This commit is contained in:
@@ -40,6 +40,7 @@ interface ComputedWeeklyMetrics extends WeeklyMetrics {
|
|||||||
cvr: number;
|
cvr: number;
|
||||||
ctr: number;
|
ctr: number;
|
||||||
roas: number;
|
roas: number;
|
||||||
|
fraction?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getISOWeekStart(year: number, week: number): number {
|
function getISOWeekStart(year: number, week: number): number {
|
||||||
@@ -142,9 +143,39 @@ function splitPeriods(
|
|||||||
// We prioritize assigning to 'after' so that we capture all units happening
|
// We prioritize assigning to 'after' so that we capture all units happening
|
||||||
// closely around the experiment dates for accurate reporting.
|
// closely around the experiment dates for accurate reporting.
|
||||||
if (overlapsAfter) {
|
if (overlapsAfter) {
|
||||||
after.push(w);
|
const overlapStart = Math.max(weekStartTs, startTs);
|
||||||
|
const overlapEnd = Math.min(weekEndTs, endTs);
|
||||||
|
const overlapFraction = Math.max(0, Math.min(1, (overlapEnd - overlapStart) / (7 * 86400000)));
|
||||||
|
|
||||||
|
if (overlapFraction > 0) {
|
||||||
|
after.push({
|
||||||
|
...w,
|
||||||
|
units: w.units * overlapFraction,
|
||||||
|
revenue: w.revenue * overlapFraction,
|
||||||
|
sessions: w.sessions * overlapFraction,
|
||||||
|
cost: w.cost * overlapFraction,
|
||||||
|
clicks: w.clicks * overlapFraction,
|
||||||
|
impressions: w.impressions * overlapFraction,
|
||||||
|
fraction: overlapFraction
|
||||||
|
});
|
||||||
|
}
|
||||||
} else if (overlapsBefore) {
|
} else if (overlapsBefore) {
|
||||||
before.push(w);
|
const overlapStart = Math.max(weekStartTs, beforeStartTs);
|
||||||
|
const overlapEnd = Math.min(weekEndTs, beforeEndTs);
|
||||||
|
const overlapFraction = Math.max(0, Math.min(1, (overlapEnd - overlapStart) / (7 * 86400000)));
|
||||||
|
|
||||||
|
if (overlapFraction > 0) {
|
||||||
|
before.push({
|
||||||
|
...w,
|
||||||
|
units: w.units * overlapFraction,
|
||||||
|
revenue: w.revenue * overlapFraction,
|
||||||
|
sessions: w.sessions * overlapFraction,
|
||||||
|
cost: w.cost * overlapFraction,
|
||||||
|
clicks: w.clicks * overlapFraction,
|
||||||
|
impressions: w.impressions * overlapFraction,
|
||||||
|
fraction: overlapFraction
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +185,8 @@ function splitPeriods(
|
|||||||
function avgMetric(data: ComputedWeeklyMetrics[], metric: string): number {
|
function avgMetric(data: ComputedWeeklyMetrics[], metric: string): number {
|
||||||
if (data.length === 0) return 0;
|
if (data.length === 0) return 0;
|
||||||
const sum = data.reduce((s, w) => s + getMetricValue(w, metric), 0);
|
const sum = data.reduce((s, w) => s + getMetricValue(w, metric), 0);
|
||||||
return sum / data.length;
|
const totalFraction = data.reduce((s, w) => s + (w.fraction || 1), 0);
|
||||||
|
return totalFraction > 0 ? sum / totalFraction : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const METRICS = ['units', 'sessions', 'cvr', 'ctr', 'roas', 'revenue', 'acos'];
|
const METRICS = ['units', 'sessions', 'cvr', 'ctr', 'roas', 'revenue', 'acos'];
|
||||||
|
|||||||
Reference in New Issue
Block a user