refactor: silence linter
[e-mobility-charging-stations-simulator.git] / src / utils / StatisticUtils.ts
1 /**
2 * Computes the average of the given data set.
3 *
4 * @param dataSet - Data set.
5 * @returns The average of the given data set.
6 * @internal
7 */
8 export const average = (dataSet: number[]): number => {
9 if (Array.isArray(dataSet) && dataSet.length === 0) {
10 return 0
11 } else if (Array.isArray(dataSet) && dataSet.length === 1) {
12 return dataSet[0]
13 }
14 return dataSet.reduce((accumulator, nb) => accumulator + nb, 0) / dataSet.length
15 }
16
17 /**
18 * Computes the median of the given data set.
19 *
20 * @param dataSet - Data set.
21 * @returns The median of the given data set.
22 * @internal
23 */
24 export const median = (dataSet: number[]): number => {
25 if (Array.isArray(dataSet) && dataSet.length === 0) {
26 return 0
27 } else if (Array.isArray(dataSet) && dataSet.length === 1) {
28 return dataSet[0]
29 }
30 const sortedDataSet = dataSet.slice().sort((a, b) => a - b)
31 return (
32 (sortedDataSet[(sortedDataSet.length - 1) >> 1] + sortedDataSet[sortedDataSet.length >> 1]) / 2
33 )
34 }
35
36 // TODO: use order statistics tree https://en.wikipedia.org/wiki/Order_statistic_tree
37 export const nthPercentile = (dataSet: number[], percentile: number): number => {
38 if (percentile < 0 && percentile > 100) {
39 throw new RangeError('Percentile is not between 0 and 100')
40 }
41 if (Array.isArray(dataSet) && dataSet.length === 0) {
42 return 0
43 }
44 const sortedDataSet = dataSet.slice().sort((a, b) => a - b)
45 if (percentile === 0 || sortedDataSet.length === 1) {
46 return sortedDataSet[0]
47 }
48 if (percentile === 100) {
49 return sortedDataSet[sortedDataSet.length - 1]
50 }
51 const percentileIndexBase = (percentile / 100) * (sortedDataSet.length - 1)
52 const percentileIndexInteger = Math.floor(percentileIndexBase)
53 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
54 if (sortedDataSet[percentileIndexInteger + 1] != null) {
55 return (
56 sortedDataSet[percentileIndexInteger] +
57 (percentileIndexBase - percentileIndexInteger) *
58 (sortedDataSet[percentileIndexInteger + 1] - sortedDataSet[percentileIndexInteger])
59 )
60 }
61 return sortedDataSet[percentileIndexInteger]
62 }
63
64 /**
65 * Computes the sample standard deviation of the given data set.
66 *
67 * @param dataSet - Data set.
68 * @param dataSetAverage - Average of the data set.
69 * @returns The sample standard deviation of the given data set.
70 * @see https://en.wikipedia.org/wiki/Unbiased_estimation_of_standard_deviation
71 * @internal
72 */
73 export const stdDeviation = (
74 dataSet: number[],
75 dataSetAverage: number = average(dataSet)
76 ): number => {
77 if (Array.isArray(dataSet) && dataSet.length === 0) {
78 return 0
79 } else if (Array.isArray(dataSet) && dataSet.length === 1) {
80 return 0
81 }
82 return Math.sqrt(
83 dataSet.reduce((accumulator, num) => accumulator + Math.pow(num - dataSetAverage, 2), 0) /
84 (dataSet.length - 1)
85 )
86 }