0
# Quantiles and Ranges
1
2
Functions for calculating percentiles, quartiles, and range statistics.
3
4
## Core Imports
5
6
```typescript
7
import {
8
quantile,
9
quantileSorted,
10
quantileRank,
11
quantileRankSorted,
12
interquartileRange,
13
medianAbsoluteDeviation,
14
min,
15
max,
16
extent,
17
minSorted,
18
maxSorted,
19
extentSorted
20
} from "simple-statistics";
21
```
22
23
## Quantile Functions
24
25
### quantile { .api }
26
27
```typescript { .api }
28
function quantile(values: number[], p: number): number;
29
function quantile(values: number[], p: number[]): number[];
30
```
31
32
Calculates quantiles (percentiles) from a dataset. Automatically sorts the data.
33
34
**Parameters:**
35
- `values: number[]` - Array of numeric values
36
- `p: number | number[]` - Quantile(s) to calculate (0-1 range)
37
38
**Returns:** `number | number[]` - Quantile value(s)
39
40
**Common Quantiles:**
41
- 0.25 = 25th percentile (Q1)
42
- 0.50 = 50th percentile (median, Q2)
43
- 0.75 = 75th percentile (Q3)
44
45
```typescript
46
import { quantile } from "simple-statistics";
47
48
const testScores = [65, 70, 75, 80, 85, 90, 95];
49
50
// Single quantile
51
const median = quantile(testScores, 0.5); // 80
52
const q1 = quantile(testScores, 0.25); // 70
53
const q3 = quantile(testScores, 0.75); // 90
54
55
// Multiple quantiles at once
56
const quartiles = quantile(testScores, [0.25, 0.5, 0.75]);
57
// [70, 80, 90]
58
59
console.log(`Q1: ${q1}, Median: ${median}, Q3: ${q3}`);
60
```
61
62
### quantileSorted { .api }
63
64
```typescript { .api }
65
function quantileSorted(values: number[], p: number): number;
66
function quantileSorted(values: number[], p: number[]): number[];
67
```
68
69
Optimized quantile calculation for pre-sorted arrays.
70
71
**Parameters:**
72
- `values: number[]` - Pre-sorted array of numeric values
73
- `p: number | number[]` - Quantile(s) to calculate (0-1 range)
74
75
**Returns:** `number | number[]` - Quantile value(s)
76
77
```typescript
78
import { quantileSorted } from "simple-statistics";
79
80
// Data must be pre-sorted
81
const sortedScores = [65, 70, 75, 80, 85, 90, 95];
82
const percentiles = quantileSorted(sortedScores, [0.1, 0.5, 0.9]);
83
// [67, 80, 93] - 10th, 50th, 90th percentiles
84
```
85
86
## Quantile Ranks
87
88
### quantileRank { .api }
89
90
```typescript { .api }
91
function quantileRank(values: number[], value: number): number;
92
```
93
94
Calculates what percentile a specific value represents in the dataset.
95
96
**Parameters:**
97
- `values: number[]` - Array of numeric values
98
- `value: number` - Value to find the rank for
99
100
**Returns:** `number` - Quantile rank (0-1 range)
101
102
```typescript
103
import { quantileRank } from "simple-statistics";
104
105
const classScores = [60, 65, 70, 75, 80, 85, 90, 95];
106
const studentScore = 80;
107
108
const rank = quantileRank(classScores, studentScore); // 0.625
109
const percentile = Math.round(rank * 100); // 63rd percentile
110
111
console.log(`Score of ${studentScore} is at the ${percentile}th percentile`);
112
```
113
114
### quantileRankSorted { .api }
115
116
```typescript { .api }
117
function quantileRankSorted(values: number[], value: number): number;
118
```
119
120
Optimized quantile rank calculation for pre-sorted arrays.
121
122
## Range Statistics
123
124
### interquartileRange (alias: iqr) { .api }
125
126
```typescript { .api }
127
function interquartileRange(values: number[]): number;
128
```
129
130
Calculates the interquartile range (Q3 - Q1), a robust measure of spread.
131
132
**Parameters:**
133
- `values: number[]` - Array of numeric values
134
135
**Returns:** `number` - IQR value
136
137
**Use Cases:**
138
- Robust measure of variability (less sensitive to outliers than standard deviation)
139
- Box plot construction
140
- Outlier detection (values beyond Q1-1.5×IQR or Q3+1.5×IQR)
141
142
```typescript
143
import { interquartileRange, quantile } from "simple-statistics";
144
145
const salaries = [35000, 40000, 45000, 50000, 55000, 60000, 120000]; // One outlier
146
147
const iqr = interquartileRange(salaries); // 15000
148
const q1 = quantile(salaries, 0.25); // 42500
149
const q3 = quantile(salaries, 0.75); // 57500
150
151
console.log(`IQR: $${iqr.toLocaleString()}`);
152
console.log(`Middle 50% of salaries: $${q1.toLocaleString()} - $${q3.toLocaleString()}`);
153
154
// Outlier detection
155
const lowerFence = q1 - 1.5 * iqr; // 20000
156
const upperFence = q3 + 1.5 * iqr; // 80000
157
158
const outliers = salaries.filter(salary => salary < lowerFence || salary > upperFence);
159
console.log(`Outliers: $${outliers.map(s => s.toLocaleString()).join(', ')}`); // $120,000
160
```
161
162
### medianAbsoluteDeviation (alias: mad) { .api }
163
164
```typescript { .api }
165
function medianAbsoluteDeviation(values: number[]): number;
166
```
167
168
Calculates the median absolute deviation, another robust measure of variability.
169
170
**Parameters:**
171
- `values: number[]` - Array of numeric values
172
173
**Returns:** `number` - MAD value
174
175
**Formula:** MAD = median(|xi - median(x)|)
176
177
```typescript
178
import { medianAbsoluteDeviation, median } from "simple-statistics";
179
180
const responseTime = [120, 125, 130, 135, 200]; // One slow response
181
182
const medianTime = median(responseTime); // 130ms
183
const mad = medianAbsoluteDeviation(responseTime); // 5ms
184
185
console.log(`Median response: ${medianTime}ms`);
186
console.log(`MAD: ${mad}ms`);
187
// MAD is less affected by the 200ms outlier than standard deviation would be
188
```
189
190
## Min/Max and Extent
191
192
### min { .api }
193
194
```typescript { .api }
195
function min(values: number[]): number;
196
```
197
198
Finds the minimum value in an array.
199
200
### max { .api }
201
202
```typescript { .api }
203
function max(values: number[]): number;
204
```
205
206
Finds the maximum value in an array.
207
208
### extent { .api }
209
210
```typescript { .api }
211
function extent(values: number[]): [number, number];
212
```
213
214
Returns both minimum and maximum as a tuple.
215
216
**Parameters:**
217
- `values: number[]` - Array of numeric values
218
219
**Returns:** `[number, number]` - Tuple containing [minimum, maximum]
220
221
```typescript
222
import { min, max, extent } from "simple-statistics";
223
224
const temperatures = [-5, 0, 12, 18, 25, 30];
225
226
const minTemp = min(temperatures); // -5
227
const maxTemp = max(temperatures); // 30
228
const tempRange = extent(temperatures); // [-5, 30]
229
230
console.log(`Temperature range: ${tempRange[0]}°C to ${tempRange[1]}°C`);
231
console.log(`Temperature span: ${tempRange[1] - tempRange[0]}°C`);
232
```
233
234
### Sorted Array Optimizations
235
236
For pre-sorted arrays, use these optimized versions:
237
238
```typescript { .api }
239
function minSorted(values: number[]): number;
240
function maxSorted(values: number[]): number;
241
function extentSorted(values: number[]): [number, number];
242
```
243
244
Optimized extent calculation for pre-sorted arrays.
245
246
**Parameters:**
247
- `values: number[]` - Pre-sorted array of numeric values
248
249
**Returns:** `[number, number]` - Tuple containing [minimum, maximum]
250
251
```typescript
252
import { minSorted, maxSorted, extentSorted } from "simple-statistics";
253
254
// Pre-sorted data
255
const sortedPrices = [9.99, 12.50, 15.75, 22.00, 35.99];
256
257
const cheapest = minSorted(sortedPrices); // 9.99
258
const mostExpensive = maxSorted(sortedPrices); // 35.99
259
const priceRange = extentSorted(sortedPrices); // [9.99, 35.99]
260
```
261
262
## Usage Examples
263
264
### Performance Analysis Dashboard
265
266
```typescript
267
import { quantile, interquartileRange, quantileRank } from "simple-statistics";
268
269
// Website response times (ms)
270
const responseTimes = [
271
45, 52, 48, 67, 55, 50, 47, 53, 49, 51, 46, 54, 48, 52, 50,
272
49, 47, 53, 51, 48, 50, 65, 58, 44, 56, 49, 52, 47, 53, 150 // One slow outlier
273
];
274
275
// Calculate performance metrics
276
const percentiles = quantile(responseTimes, [0.5, 0.95, 0.99]);
277
const [median, p95, p99] = percentiles;
278
279
const iqr = interquartileRange(responseTimes);
280
const slaThreshold = 100; // 100ms SLA
281
const slaPercentile = quantileRank(responseTimes, slaThreshold);
282
283
console.log("Performance Dashboard:");
284
console.log(`Median response time: ${median}ms`);
285
console.log(`95th percentile: ${p95}ms`);
286
console.log(`99th percentile: ${p99}ms`);
287
console.log(`IQR: ${iqr}ms`);
288
console.log(`SLA compliance: ${(slaPercentile * 100).toFixed(1)}% under ${slaThreshold}ms`);
289
290
// Alerting based on percentiles
291
if (p95 > 80) {
292
console.log("🚨 Alert: 95th percentile exceeds 80ms threshold");
293
}
294
```
295
296
### Salary Band Analysis
297
298
```typescript
299
import { quantile, quantileRank, interquartileRange } from "simple-statistics";
300
301
// Company salary data
302
const salaries = [
303
45000, 48000, 52000, 55000, 58000, 62000, 65000, 68000, 72000, 75000,
304
78000, 82000, 85000, 90000, 95000, 100000, 110000, 120000, 150000, 200000
305
];
306
307
// Define salary bands using quartiles
308
const salaryBands = quantile(salaries, [0.25, 0.5, 0.75]);
309
const [q1, median, q3] = salaryBands;
310
311
console.log("Salary Band Analysis:");
312
console.log(`Entry Level (0-25th): Up to $${q1.toLocaleString()}`);
313
console.log(`Mid Level (25-50th): $${q1.toLocaleString()} - $${median.toLocaleString()}`);
314
console.log(`Senior Level (50-75th): $${median.toLocaleString()} - $${q3.toLocaleString()}`);
315
console.log(`Executive (75th+): $${q3.toLocaleString()}+`);
316
317
// Individual salary analysis
318
const candidateSalary = 87000;
319
const candidatePercentile = quantileRank(salaries, candidateSalary);
320
321
console.log(`\nCandidate Analysis:`);
322
console.log(`Salary: $${candidateSalary.toLocaleString()}`);
323
console.log(`Percentile: ${Math.round(candidatePercentile * 100)}th`);
324
325
if (candidatePercentile > 0.75) {
326
console.log("Band: Executive Level");
327
} else if (candidatePercentile > 0.5) {
328
console.log("Band: Senior Level");
329
} else if (candidatePercentile > 0.25) {
330
console.log("Band: Mid Level");
331
} else {
332
console.log("Band: Entry Level");
333
}
334
```
335
336
### Outlier Detection
337
338
```typescript
339
import { quantile, interquartileRange, medianAbsoluteDeviation } from "simple-statistics";
340
341
// Stock price changes (%)
342
const priceChanges = [
343
-2.1, -1.5, -0.8, 0.2, 0.5, 1.2, 1.8, 2.3, -1.2, 0.8,
344
1.5, -0.5, 2.1, -1.8, 0.3, 1.1, -15.2, 2.5, -0.9, 1.7 // -15.2% is outlier
345
];
346
347
// IQR method for outlier detection
348
const [q1, q3] = quantile(priceChanges, [0.25, 0.75]);
349
const iqr = interquartileRange(priceChanges);
350
const lowerFence = q1 - 1.5 * iqr;
351
const upperFence = q3 + 1.5 * iqr;
352
353
const iqrOutliers = priceChanges.filter(change =>
354
change < lowerFence || change > upperFence
355
);
356
357
// MAD method for outlier detection (more robust)
358
const mad = medianAbsoluteDeviation(priceChanges);
359
const median = quantile(priceChanges, 0.5);
360
const madThreshold = 3; // 3 MADs from median
361
362
const madOutliers = priceChanges.filter(change =>
363
Math.abs(change - median) > madThreshold * mad
364
);
365
366
console.log("Outlier Detection Results:");
367
console.log(`IQR method: ${iqrOutliers.length} outliers: ${iqrOutliers.map(x => x.toFixed(1)).join(', ')}%`);
368
console.log(`MAD method: ${madOutliers.length} outliers: ${madOutliers.map(x => x.toFixed(1)).join(', ')}%`);
369
console.log(`Normal range (IQR): ${lowerFence.toFixed(1)}% to ${upperFence.toFixed(1)}%`);
370
```