From 1e4bb73874e093368c60a380ce1a3b18745a59de Mon Sep 17 00:00:00 2001 From: MaysWind Date: Thu, 16 Apr 2026 01:24:38 +0800 Subject: [PATCH] add mean absolute deviation and median absolute deviation to value metric in insights explorer --- src/core/explorer.ts | 4 ++++ src/lib/math.ts | 26 ++++++++++++++++++++++++++ src/locales/de.json | 2 ++ src/locales/en.json | 2 ++ src/locales/es.json | 2 ++ src/locales/fr.json | 2 ++ src/locales/it.json | 2 ++ src/locales/ja.json | 2 ++ src/locales/kn.json | 2 ++ src/locales/ko.json | 2 ++ src/locales/nl.json | 2 ++ src/locales/pt_BR.json | 2 ++ src/locales/ru.json | 2 ++ src/locales/sl.json | 2 ++ src/locales/ta.json | 2 ++ src/locales/th.json | 2 ++ src/locales/tr.json | 2 ++ src/locales/uk.json | 2 ++ src/locales/vi.json | 2 ++ src/locales/zh_Hans.json | 2 ++ src/locales/zh_Hant.json | 2 ++ src/stores/explorer.ts | 17 +++++++++++++++++ 22 files changed, 85 insertions(+) diff --git a/src/core/explorer.ts b/src/core/explorer.ts index 02bd83ac..b07d3270 100644 --- a/src/core/explorer.ts +++ b/src/core/explorer.ts @@ -324,6 +324,8 @@ export enum TransactionExplorerValueMetricType { SourceAmountMaximum = 'sourceAmountMaximum', SourceAmountRange = 'sourceAmountRange', SourceAmountInterquartileRange = 'sourceAmountInterquartileRange', + SourceAmountMeanAbsoluteDeviation = 'sourceAmountMeanAbsoluteDeviation', + SourceAmountMedianAbsoluteDeviation = 'sourceAmountMedianAbsoluteDeviation', SourceAmountVariance = 'sourceAmountVariance', SourceAmountStandardDeviation = 'sourceAmountStandardDeviation', SourceAmountCoefficientOfVariation = 'sourceAmountCoefficientOfVariation', @@ -359,6 +361,8 @@ export class TransactionExplorerValueMetric implements NameValue { public static readonly SourceAmountMaximum = new TransactionExplorerValueMetric('Maximum Amount', TransactionExplorerValueMetricType.SourceAmountMaximum, true, false, true); public static readonly SourceAmountRange = new TransactionExplorerValueMetric('Range (Max - Min)', TransactionExplorerValueMetricType.SourceAmountRange, true, false, true); public static readonly SourceAmountInterquartileRange = new TransactionExplorerValueMetric('Interquartile Range (Q3 - Q1)', TransactionExplorerValueMetricType.SourceAmountInterquartileRange, true, false, true); + public static readonly SourceAmountMeanAbsoluteDeviation = new TransactionExplorerValueMetric('Mean Absolute Deviation', TransactionExplorerValueMetricType.SourceAmountMeanAbsoluteDeviation, true, false, false); + public static readonly SourceAmountMedianAbsoluteDeviation = new TransactionExplorerValueMetric('Median Absolute Deviation', TransactionExplorerValueMetricType.SourceAmountMedianAbsoluteDeviation, true, false, false); public static readonly SourceAmountVariance = new TransactionExplorerValueMetric('Variance', TransactionExplorerValueMetricType.SourceAmountVariance, false, false, false); public static readonly SourceAmountStandardDeviation = new TransactionExplorerValueMetric('Standard Deviation', TransactionExplorerValueMetricType.SourceAmountStandardDeviation, false, false, false); public static readonly SourceAmountCoefficientOfVariation = new TransactionExplorerValueMetric('Coefficient of Variation', TransactionExplorerValueMetricType.SourceAmountCoefficientOfVariation, false, false, false); diff --git a/src/lib/math.ts b/src/lib/math.ts index 10689d76..92a1ca37 100644 --- a/src/lib/math.ts +++ b/src/lib/math.ts @@ -83,6 +83,32 @@ export function cumulativePercentage(sortedValues: T[], percentageThreshold: return 0; } +export function meanAbsoluteDeviation(values: T[], meanValue: number, valueFn: (item: T) => number): number { + if (values.length < 1) { + return 0; + } + + let sumOfAbsoluteDifferences: number = 0; + + for (const item of values) { + const difference: number = Math.abs(valueFn(item) - meanValue); + sumOfAbsoluteDifferences += difference; + } + + return sumOfAbsoluteDifferences / values.length; +} + +export function medianAbsoluteDeviation(sortedValues: T[], medianValue: number, valueFn: (item: T) => number): number { + if (sortedValues.length < 1) { + return 0; + } + + const absoluteDeviations: number[] = sortedValues.map(item => Math.abs(valueFn(item) - medianValue)); + absoluteDeviations.sort((a, b) => a - b); + + return median(absoluteDeviations, x => x); +} + export function varianceAndStandardDeviation(values: T[], meanValue: number, valueFn: (item: T) => number): { variance: number; standardDeviation: number } { if (values.length < 1) { return { variance: 0, standardDeviation: 0 }; diff --git a/src/locales/de.json b/src/locales/de.json index b1104e76..c5f2a887 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transaktionen für 80% des Betrags", "Range (Max - Min)": "Spanne (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartilsabstand (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Varianz", "Standard Deviation": "Standardabweichung", "Coefficient of Variation": "Variationskoeffizient", diff --git a/src/locales/en.json b/src/locales/en.json index 15731b8e..3fdb4002 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/es.json b/src/locales/es.json index 6dd9ea56..2279563b 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/fr.json b/src/locales/fr.json index 32f5c3ef..38bb9aa1 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/it.json b/src/locales/it.json index 29b0de5a..3bda82f8 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/ja.json b/src/locales/ja.json index 72fd811f..aae5b171 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/kn.json b/src/locales/kn.json index ac39f242..7d0c15f4 100644 --- a/src/locales/kn.json +++ b/src/locales/kn.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/ko.json b/src/locales/ko.json index 04dbfc0f..2c6f1bf5 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/nl.json b/src/locales/nl.json index 23e65070..9c232848 100644 --- a/src/locales/nl.json +++ b/src/locales/nl.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/pt_BR.json b/src/locales/pt_BR.json index 39558efa..98389739 100644 --- a/src/locales/pt_BR.json +++ b/src/locales/pt_BR.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transações para 80% do Valor", "Range (Max - Min)": "Amplitude (Máx - Mín)", "Interquartile Range (Q3 - Q1)": "Intervalo Interquartil (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variância", "Standard Deviation": "Desvio Padrão", "Coefficient of Variation": "Coeficiente de Variação", diff --git a/src/locales/ru.json b/src/locales/ru.json index a2c0a627..4276af5b 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/sl.json b/src/locales/sl.json index 652c9d18..ce40b882 100644 --- a/src/locales/sl.json +++ b/src/locales/sl.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/ta.json b/src/locales/ta.json index 0a691941..c6bb5d16 100644 --- a/src/locales/ta.json +++ b/src/locales/ta.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/th.json b/src/locales/th.json index 06f79de0..4a6ab5e7 100644 --- a/src/locales/th.json +++ b/src/locales/th.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/tr.json b/src/locales/tr.json index 3cad6d3d..f6a28420 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/uk.json b/src/locales/uk.json index 000b4f8e..f4932375 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/vi.json b/src/locales/vi.json index 04891c32..05fd5ee3 100644 --- a/src/locales/vi.json +++ b/src/locales/vi.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "Transactions for 80% of Amount", "Range (Max - Min)": "Range (Max - Min)", "Interquartile Range (Q3 - Q1)": "Interquartile Range (Q3 - Q1)", + "Mean Absolute Deviation": "Mean Absolute Deviation", + "Median Absolute Deviation": "Median Absolute Deviation", "Variance": "Variance", "Standard Deviation": "Standard Deviation", "Coefficient of Variation": "Coefficient of Variation", diff --git a/src/locales/zh_Hans.json b/src/locales/zh_Hans.json index c7d0e8c1..81b503cc 100644 --- a/src/locales/zh_Hans.json +++ b/src/locales/zh_Hans.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "贡献80%金额的交易占比", "Range (Max - Min)": "极差 (最大值 - 最小值)", "Interquartile Range (Q3 - Q1)": "四分位距 (Q3 - Q1)", + "Mean Absolute Deviation": "平均绝对差", + "Median Absolute Deviation": "绝对中位差", "Variance": "方差", "Standard Deviation": "标准差", "Coefficient of Variation": "变异系数", diff --git a/src/locales/zh_Hant.json b/src/locales/zh_Hant.json index b0d8bdbc..45a6f1c6 100644 --- a/src/locales/zh_Hant.json +++ b/src/locales/zh_Hant.json @@ -1823,6 +1823,8 @@ "Transactions for 80% of Amount": "貢獻80%金額的交易占比", "Range (Max - Min)": "極差 (最大值 - 最小值)", "Interquartile Range (Q3 - Q1)": "四分位距 (Q3 - Q1)", + "Mean Absolute Deviation": "平均絕對離差", + "Median Absolute Deviation": "中位數絕對離差", "Variance": "變異數", "Standard Deviation": "標準差", "Coefficient of Variation": "變異係數", diff --git a/src/stores/explorer.ts b/src/stores/explorer.ts index f167a89c..9367ab5c 100644 --- a/src/stores/explorer.ts +++ b/src/stores/explorer.ts @@ -50,6 +50,8 @@ import { percentile, sumMaxN, cumulativePercentage, + meanAbsoluteDeviation, + medianAbsoluteDeviation, varianceAndStandardDeviation, coefficientOfVariation, skewness, @@ -980,6 +982,21 @@ export const useExplorersStore = defineStore('explorers', () => { } else { value = 0; } + } else if (valueMetric === TransactionExplorerValueMetric.SourceAmountMeanAbsoluteDeviation) { + if (allSourceAmountsInDefaultCurrency.length > 0) { + const averageSourceAmountInDefaultCurrency = totalSourceAmountSumInDefaultCurrency / allSourceAmountsInDefaultCurrency.length; + value = Math.trunc(meanAbsoluteDeviation(allSourceAmountsInDefaultCurrency, averageSourceAmountInDefaultCurrency, item => item)); + } else { + value = 0; + } + } else if (valueMetric === TransactionExplorerValueMetric.SourceAmountMedianAbsoluteDeviation) { + if (allSourceAmountsInDefaultCurrency.length > 0) { + allSourceAmountsInDefaultCurrency.sort((a, b) => a - b); + const medianSourceAmountInDefaultCurrency = median(allSourceAmountsInDefaultCurrency, item => item); + value = Math.trunc(medianAbsoluteDeviation(allSourceAmountsInDefaultCurrency, medianSourceAmountInDefaultCurrency, item => item)); + } else { + value = 0; + } } else if (valueMetric === TransactionExplorerValueMetric.SourceAmountVariance || valueMetric === TransactionExplorerValueMetric.SourceAmountStandardDeviation || valueMetric === TransactionExplorerValueMetric.SourceAmountCoefficientOfVariation