X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Futils%2FStatisticUtils.ts;h=501dea7797ec30ecc469604ed1e93697551ad095;hb=8bfa4d2be3f3817654791f166f4aab1b02485005;hp=3f587caaaf46c753d080b1cccc13fab131dacaba;hpb=c7ba22b7e881dc5f0c7f99dfa5d67390bc46fdf6;p=e-mobility-charging-stations-simulator.git diff --git a/src/utils/StatisticUtils.ts b/src/utils/StatisticUtils.ts index 3f587caa..501dea77 100644 --- a/src/utils/StatisticUtils.ts +++ b/src/utils/StatisticUtils.ts @@ -1,74 +1,53 @@ -import { isEmptyArray, isNullOrUndefined } from './Utils'; +import { mean } from 'rambda' -/** - * Computes the average of the given data set. - * - * @param dataSet - Data set. - * @returns The average of the given data set. - * @internal - */ -export const average = (dataSet: number[]): number => { - if (Array.isArray(dataSet) && dataSet.length === 0) { - return 0; - } - if (Array.isArray(dataSet) && dataSet.length === 1) { - return dataSet[0]; - } - return dataSet.reduce((accumulator, nb) => accumulator + nb, 0) / dataSet.length; -}; +export const min = (...args: number[]): number => + args.reduce((minimum, num) => (minimum < num ? minimum : num), Number.POSITIVE_INFINITY) -/** - * Computes the median of the given data set. - * - * @param dataSet - Data set. - * @returns The median of the given data set. - * @internal - */ -export const median = (dataSet: number[]): number => { - if (isEmptyArray(dataSet)) { - return 0; - } - if (Array.isArray(dataSet) === true && dataSet.length === 1) { - return dataSet[0]; - } - const sortedDataSet = dataSet.slice().sort((a, b) => a - b); - return ( - (sortedDataSet[(sortedDataSet.length - 1) >> 1] + sortedDataSet[sortedDataSet.length >> 1]) / 2 - ); -}; +export const max = (...args: number[]): number => + args.reduce((maximum, num) => (maximum > num ? maximum : num), Number.NEGATIVE_INFINITY) // TODO: use order statistics tree https://en.wikipedia.org/wiki/Order_statistic_tree export const nthPercentile = (dataSet: number[], percentile: number): number => { if (percentile < 0 && percentile > 100) { - throw new RangeError('Percentile is not between 0 and 100'); + throw new RangeError('Percentile is not between 0 and 100') } - if (isEmptyArray(dataSet)) { - return 0; + if (Array.isArray(dataSet) && dataSet.length === 0) { + return 0 } - const sortedDataSet = dataSet.slice().sort((a, b) => a - b); + const sortedDataSet = dataSet.slice().sort((a, b) => a - b) if (percentile === 0 || sortedDataSet.length === 1) { - return sortedDataSet[0]; + return sortedDataSet[0] } if (percentile === 100) { - return sortedDataSet[sortedDataSet.length - 1]; + return sortedDataSet[sortedDataSet.length - 1] } - const percentileIndexBase = (percentile / 100) * (sortedDataSet.length - 1); - const percentileIndexInteger = Math.floor(percentileIndexBase); - if (!isNullOrUndefined(sortedDataSet[percentileIndexInteger + 1])) { + const base = (percentile / 100) * (sortedDataSet.length - 1) + const baseIndex = Math.floor(base) + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (sortedDataSet[baseIndex + 1] != null) { return ( - sortedDataSet[percentileIndexInteger] + - (percentileIndexBase - percentileIndexInteger) * - (sortedDataSet[percentileIndexInteger + 1] - sortedDataSet[percentileIndexInteger]) - ); + sortedDataSet[baseIndex] + + (base - baseIndex) * (sortedDataSet[baseIndex + 1] - sortedDataSet[baseIndex]) + ) } - return sortedDataSet[percentileIndexInteger]; -}; + return sortedDataSet[baseIndex] +} -export const stdDeviation = (dataSet: number[], dataSetAverage?: number): number => { - dataSetAverage = dataSetAverage ?? average(dataSet); - const geometricDeviation = dataSet.reduce((accumulator, nb) => { - const deviation = nb - dataSetAverage!; - return accumulator + deviation * deviation; - }, 0); - return Math.sqrt(geometricDeviation / dataSet.length); -}; +/** + * Computes the sample standard deviation of the given data set. + * + * @param dataSet - Data set. + * @param dataSetAverage - Average of the data set. + * @returns The sample standard deviation of the given data set. + * @see https://en.wikipedia.org/wiki/Unbiased_estimation_of_standard_deviation + * @internal + */ +export const stdDeviation = (dataSet: number[], dataSetAverage: number = mean(dataSet)): number => { + if (Array.isArray(dataSet) && (dataSet.length === 0 || dataSet.length === 1)) { + return 0 + } + return Math.sqrt( + dataSet.reduce((accumulator, num) => accumulator + Math.pow(num - dataSetAverage, 2), 0) / + (dataSet.length - 1) + ) +}