core/converters/finding.distribution.converter.ts
core/converters/finding.distribution.converter.ts is a file in GovLab Patterns. 139 lines of code and 14 definitions.
import {
DISTRIBUTION_STRINGS,
NULL_MODEL_LABELS,
PREDICTION_METHODS,
} from "#configuration/strings/representation.strings";
import { explanationFinding, makeFinding, reasonOf } from "#core/factories/finding.factory";
import type { DistributionSummary } from "#types/representation.types";
import type { Finding } from "#types/finding.types";
import { ROUNDING } from "#configuration/constants/math.constants";
import { coordinate } from "#core/factories/axis.factory";
import { withSupport } from "#core/converters/finding.converter";
const frequencyFinding = function frequencyFinding(field: string, summary: DistributionSummary): Finding {
const { count, distinct, top, witnesses } = summary;
return explanationFinding({
analysis: "frequency",
explained: DISTRIBUTION_STRINGS.freqExplained(summary.entropyBits.toFixed(ROUNDING.standard)),
field,
name: "frequency",
observation: { count, distinct, top, witnesses },
observed: DISTRIBUTION_STRINGS.freqObserved(String(count), String(distinct)),
ontology: "probability",
representation: "symbolic",
});
};
const uniformityFinding = function uniformityFinding(field: string, summary: DistributionSummary): Finding {
const { chiSquare, dof, pValue, uniform } = summary.uniformity;
const verdict = uniform ? DISTRIBUTION_STRINGS.uniformUniform : DISTRIBUTION_STRINGS.uniformDeparts;
const observed = DISTRIBUTION_STRINGS.uniformObserved(chiSquare.toFixed(ROUNDING.coarse), String(dof));
const explained = DISTRIBUTION_STRINGS.uniformExplained(pValue.toFixed(ROUNDING.fine), verdict);
return makeFinding({
coordinate: coordinate({
analysis: "statistical",
ontology: "probability",
reasoning: "explanation",
representation: "probability",
}),
field,
name: "uniformity",
narrative: reasonOf(observed, explained),
observation: { chiSquare, dof, pValue, uniform },
significance: { nullModel: NULL_MODEL_LABELS.uniformity, pValue, significant: !uniform, statistic: chiSquare },
});
};
const plainFindings = function plainFindings(field: string, summary: DistributionSummary): Finding[] {
return [
explanationFinding({
analysis: "time",
explained: DISTRIBUTION_STRINGS.recencyExplained,
field,
name: "recency",
observation: { overdue: summary.overdue },
observed: DISTRIBUTION_STRINGS.recencyObserved,
ontology: "time",
representation: "symbolic",
}),
explanationFinding({
analysis: "frequency",
explained: DISTRIBUTION_STRINGS.temperatureExplained,
field,
name: "temperature",
observation: { cold: summary.cold, hot: summary.hot },
observed: DISTRIBUTION_STRINGS.temperatureObserved,
ontology: "change",
representation: "number",
}),
explanationFinding({
analysis: "change",
explained: DISTRIBUTION_STRINGS.driftExplained,
field,
name: "drift",
observation: { drift: summary.drift },
observed: DISTRIBUTION_STRINGS.driftObserved,
ontology: "change",
representation: "number",
}),
explanationFinding({
analysis: "complexity",
explained: DISTRIBUTION_STRINGS.complexityExplained,
field,
name: "complexity",
observation: { complexity: summary.complexity },
observed: DISTRIBUTION_STRINGS.complexityObserved,
ontology: "novelty",
representation: "information-theory",
}),
];
};
const seasonalityFinding = function seasonalityFinding(field: string, summary: DistributionSummary): Finding | null {
const { temporal } = summary;
if (temporal === null) {
return null;
}
return explanationFinding({
analysis: "time",
explained: DISTRIBUTION_STRINGS.seasonalityExplained,
field,
name: "seasonality",
observation: { temporal },
observed: DISTRIBUTION_STRINGS.seasonalityObserved(temporal.first, temporal.last),
ontology: "time",
representation: "number",
});
};
const predictionFinding = function predictionFinding(field: string, summary: DistributionSummary): Finding | null {
const [top] = summary.top;
if (!top) {
return null;
}
const [mode] = top;
const explained = DISTRIBUTION_STRINGS.predictionExplained(summary.modeAccuracy.toFixed(ROUNDING.standard));
return makeFinding({
coordinate: coordinate({
analysis: "prediction",
ontology: "probability",
reasoning: "prediction",
representation: "probability",
}),
field,
name: "mode-prediction",
narrative: reasonOf(DISTRIBUTION_STRINGS.predictionObserved(mode), explained),
observation: { accuracy: summary.modeAccuracy, mode },
prediction: { accuracy: summary.modeAccuracy, method: PREDICTION_METHODS.mode },
});
};
export const distributionFindings = function distributionFindings(
field: string,
summary: DistributionSummary,
): Finding[] {
return withSupport(
[
frequencyFinding(field, summary),
uniformityFinding(field, summary),
...plainFindings(field, summary),
seasonalityFinding(field, summary),
predictionFinding(field, summary),
],
summary.count,
);
};