@tidyjs/tidy 2.6.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,137 @@
1
+ # Slice
2
+
3
+ Subset rows by position, value, or random sampling.
4
+
5
+ ```js
6
+ import { tidy, slice, sliceHead, sliceTail, sliceMin, sliceMax, sliceSample } from '@tidyjs/tidy';
7
+ ```
8
+
9
+ ---
10
+
11
+ <!-- keywords: slice, range, index, subset rows -->
12
+ ## slice
13
+
14
+ Keep rows in a given index range (uses `Array.prototype.slice` semantics).
15
+
16
+ **Signature:** `slice<T>(start: number, end?: number)`
17
+ **Goes inside:** `tidy(data, slice(...))`
18
+
19
+ ### Parameters
20
+ - **start** `number` -- start index (inclusive). Negative values count from the end.
21
+ - **end** `number` (optional) -- end index (exclusive). If omitted, slices to the end.
22
+
23
+ ### Example
24
+ ```js
25
+ const data = [{ v: 1 }, { v: 2 }, { v: 3 }, { v: 4 }, { v: 5 }];
26
+
27
+ tidy(data, slice(1, 3));
28
+ // output: [{ v: 2 }, { v: 3 }]
29
+ ```
30
+
31
+ ---
32
+
33
+ <!-- keywords: head, first n, top rows, limit -->
34
+ ## sliceHead
35
+
36
+ Keep the first N rows.
37
+
38
+ **Signature:** `sliceHead<T>(n: number)`
39
+ **Goes inside:** `tidy(data, sliceHead(...))`
40
+
41
+ ### Parameters
42
+ - **n** `number` -- number of rows to keep from the start.
43
+
44
+ ### Example
45
+ ```js
46
+ tidy(data, sliceHead(2));
47
+ // output: [{ v: 1 }, { v: 2 }]
48
+ ```
49
+
50
+ ---
51
+
52
+ <!-- keywords: tail, last n, bottom rows -->
53
+ ## sliceTail
54
+
55
+ Keep the last N rows.
56
+
57
+ **Signature:** `sliceTail<T>(n: number)`
58
+ **Goes inside:** `tidy(data, sliceTail(...))`
59
+
60
+ ### Parameters
61
+ - **n** `number` -- number of rows to keep from the end.
62
+
63
+ ### Example
64
+ ```js
65
+ tidy(data, sliceTail(2));
66
+ // output: [{ v: 4 }, { v: 5 }]
67
+ ```
68
+
69
+ ---
70
+
71
+ <!-- keywords: min, smallest, bottom n, order by ascending -->
72
+ ## sliceMin
73
+
74
+ Keep the N rows with the smallest values for a given key.
75
+
76
+ **Signature:** `sliceMin<T>(n: number, orderBy: string | string[] | Comparator<T>)`
77
+ **Goes inside:** `tidy(data, sliceMin(...))`
78
+
79
+ ### Parameters
80
+ - **n** `number` -- number of rows to keep.
81
+ - **orderBy** `string | string[] | ((a, b) => number)` -- key name(s) to sort ascending by, or a custom comparator function.
82
+
83
+ ### Example
84
+ ```js
85
+ const data = [
86
+ { name: 'a', score: 50 },
87
+ { name: 'b', score: 10 },
88
+ { name: 'c', score: 30 },
89
+ { name: 'd', score: 80 },
90
+ ];
91
+
92
+ tidy(data, sliceMin(2, 'score'));
93
+ // output: [{ name: 'b', score: 10 }, { name: 'c', score: 30 }]
94
+ ```
95
+
96
+ ---
97
+
98
+ <!-- keywords: max, largest, top n, order by descending -->
99
+ ## sliceMax
100
+
101
+ Keep the N rows with the largest values for a given key.
102
+
103
+ **Signature:** `sliceMax<T>(n: number, orderBy: string | string[] | Comparator<T>)`
104
+ **Goes inside:** `tidy(data, sliceMax(...))`
105
+
106
+ ### Parameters
107
+ - **n** `number` -- number of rows to keep.
108
+ - **orderBy** `string | string[] | ((a, b) => number)` -- key name(s) to sort descending by, or a custom comparator function.
109
+
110
+ ### Example
111
+ ```js
112
+ tidy(data, sliceMax(2, 'score'));
113
+ // output: [{ name: 'd', score: 80 }, { name: 'a', score: 50 }]
114
+ ```
115
+
116
+ ---
117
+
118
+ <!-- keywords: sample, random, shuffle -->
119
+ ## sliceSample
120
+
121
+ Keep a random sample of N rows.
122
+
123
+ **Signature:** `sliceSample<T>(n: number, options?: { replace?: boolean })`
124
+ **Goes inside:** `tidy(data, sliceSample(...))`
125
+
126
+ ### Parameters
127
+ - **n** `number` -- number of rows to sample.
128
+ - **options.replace** `boolean` -- if `true`, sample with replacement (same row can appear multiple times). Default: `false`.
129
+
130
+ ### Example
131
+ ```js
132
+ tidy(data, sliceSample(2));
133
+ // output: 2 randomly selected rows (without replacement)
134
+
135
+ tidy(data, sliceSample(5, { replace: true }));
136
+ // output: 5 rows sampled with replacement (may include duplicates)
137
+ ```
@@ -0,0 +1,528 @@
1
+ # Summarize API Reference
2
+
3
+ > Functions for aggregating data: tidy verbs that reduce collections, and summary helpers that compute single values.
4
+
5
+ ---
6
+
7
+ ## Tidy Verbs (pipeline functions)
8
+
9
+ These go inside a `tidy()` call: `tidy(data, summarize({...}))`.
10
+
11
+ ---
12
+
13
+ <!-- keywords: summarize, summarise, aggregate, reduce, group summary, spec -->
14
+ ## summarize
15
+
16
+ Reduces all items to a single summary row based on a spec of summary functions.
17
+
18
+ **Signature:** `summarize(spec, options?)`
19
+ **Goes inside:** `tidy()` pipeline (or `groupBy()` export functions)
20
+
21
+ ### Parameters
22
+ - `spec` -- `Record<string, (items: T[]) => any>` -- object mapping output keys to summary functions
23
+ - `options?` -- `{ rest?: (key: keyof T) => (items: T[]) => any }` -- `rest` applies a summary function to all keys not in `spec`
24
+
25
+ ### Example
26
+ ```js
27
+ import { tidy, summarize, sum, mean, n } from '@tidyjs/tidy';
28
+
29
+ const data = [
30
+ { group: 'a', value: 10 },
31
+ { group: 'a', value: 20 },
32
+ { group: 'b', value: 30 },
33
+ ];
34
+
35
+ tidy(data, summarize({
36
+ total: sum('value'),
37
+ avg: mean('value'),
38
+ count: n(),
39
+ }))
40
+ // output:
41
+ // [{ total: 60, avg: 20, count: 3 }]
42
+ ```
43
+
44
+ ---
45
+
46
+ <!-- keywords: summarizeAll, summarise all, apply to all columns -->
47
+ ## summarizeAll
48
+
49
+ Applies one summary function to every column.
50
+
51
+ **Signature:** `summarizeAll(summaryFn)`
52
+ **Goes inside:** `tidy()` pipeline
53
+
54
+ ### Parameters
55
+ - `summaryFn` -- `(key: keyof T) => (items: T[]) => any` -- a summary key function (e.g., `sum`, `mean`)
56
+
57
+ ### Example
58
+ ```js
59
+ import { tidy, summarizeAll, sum } from '@tidyjs/tidy';
60
+
61
+ const data = [
62
+ { x: 1, y: 10 },
63
+ { x: 2, y: 20 },
64
+ ];
65
+
66
+ tidy(data, summarizeAll(sum))
67
+ // output:
68
+ // [{ x: 3, y: 30 }]
69
+ ```
70
+
71
+ ---
72
+
73
+ <!-- keywords: summarizeIf, summarise if, conditional columns, predicate -->
74
+ ## summarizeIf
75
+
76
+ Applies a summary function only to columns whose values match a predicate.
77
+
78
+ **Signature:** `summarizeIf(predicateFn, summaryFn)`
79
+ **Goes inside:** `tidy()` pipeline
80
+
81
+ ### Parameters
82
+ - `predicateFn` -- `(vector: T[keyof T][]) => boolean` -- receives all values for a column; return `true` to include
83
+ - `summaryFn` -- `(key: keyof T) => (items: T[]) => any` -- summary key function to apply
84
+
85
+ ### Example
86
+ ```js
87
+ import { tidy, summarizeIf, sum } from '@tidyjs/tidy';
88
+
89
+ const data = [
90
+ { str: 'foo', value: 3 },
91
+ { str: 'bar', value: 7 },
92
+ ];
93
+
94
+ tidy(data, summarizeIf(
95
+ (vector) => vector.every(v => typeof v === 'number'),
96
+ sum
97
+ ))
98
+ // output:
99
+ // [{ value: 10 }]
100
+ ```
101
+
102
+ ---
103
+
104
+ <!-- keywords: summarizeAt, summarise at, specific columns, named keys -->
105
+ ## summarizeAt
106
+
107
+ Applies a summary function to specific named columns.
108
+
109
+ **Signature:** `summarizeAt(keys, summaryFn)`
110
+ **Goes inside:** `tidy()` pipeline
111
+
112
+ ### Parameters
113
+ - `keys` -- `(keyof T)[]` -- array of column names to summarize
114
+ - `summaryFn` -- `(key: keyof T) => (items: T[]) => any` -- summary key function to apply
115
+
116
+ ### Example
117
+ ```js
118
+ import { tidy, summarizeAt, sum } from '@tidyjs/tidy';
119
+
120
+ const data = [
121
+ { a: 1, b: 10, c: 100 },
122
+ { a: 2, b: 20, c: 200 },
123
+ ];
124
+
125
+ tidy(data, summarizeAt(['a', 'b'], sum))
126
+ // output:
127
+ // [{ a: 3, b: 30 }]
128
+ ```
129
+
130
+ ---
131
+
132
+ <!-- keywords: count, group count, tally by key, frequency -->
133
+ ## count
134
+
135
+ Counts items per group for given keys. Shorthand for `groupBy(key, [tally()])`.
136
+
137
+ **Signature:** `count(groupKeys, options?)`
138
+ **Goes inside:** `tidy()` pipeline
139
+
140
+ ### Parameters
141
+ - `groupKeys` -- `string | string[] | accessor | accessor[]` -- key(s) to group by
142
+ - `options?` -- `{ name?: string, sort?: boolean, wt?: string }`
143
+ - `name` -- output column name (default `'n'`)
144
+ - `sort` -- if `true`, sorts descending by count
145
+ - `wt` -- key to use as weight (sums that column instead of counting)
146
+
147
+ ### Example
148
+ ```js
149
+ import { tidy, count } from '@tidyjs/tidy';
150
+
151
+ const data = [
152
+ { color: 'red' },
153
+ { color: 'red' },
154
+ { color: 'blue' },
155
+ ];
156
+
157
+ tidy(data, count('color', { sort: true }))
158
+ // output:
159
+ // [{ color: 'red', n: 2 }, { color: 'blue', n: 1 }]
160
+ ```
161
+
162
+ ---
163
+
164
+ <!-- keywords: tally, count items, row count, weighted count -->
165
+ ## tally
166
+
167
+ Counts items in the current group (or all items). Use inside `groupBy` exports or standalone.
168
+
169
+ **Signature:** `tally(options?)`
170
+ **Goes inside:** `tidy()` pipeline (commonly inside `groupBy()` export functions)
171
+
172
+ ### Parameters
173
+ - `options?` -- `{ name?: string, wt?: string }`
174
+ - `name` -- output column name (default `'n'`)
175
+ - `wt` -- key to use as weight (sums that column instead of counting)
176
+
177
+ ### Example
178
+ ```js
179
+ import { tidy, tally, groupBy } from '@tidyjs/tidy';
180
+
181
+ const data = [
182
+ { group: 'a', value: 10 },
183
+ { group: 'a', value: 20 },
184
+ { group: 'b', value: 30 },
185
+ ];
186
+
187
+ tidy(data, tally())
188
+ // output:
189
+ // [{ n: 3 }]
190
+
191
+ tidy(data, tally({ wt: 'value' }))
192
+ // output:
193
+ // [{ n: 60 }]
194
+ ```
195
+
196
+ ---
197
+
198
+ <!-- keywords: total, total row, append summary, grand total -->
199
+ ## total
200
+
201
+ Like `summarize`, but appends the summary as a total row while keeping all original rows.
202
+
203
+ **Signature:** `total(summarizeSpec, mutateSpec)`
204
+ **Goes inside:** `tidy()` pipeline
205
+
206
+ ### Parameters
207
+ - `summarizeSpec` -- `Record<string, (items: T[]) => any>` -- summary functions (same as `summarize` spec)
208
+ - `mutateSpec` -- `Record<string, (items: T[]) => any>` -- mutations to apply to the total row (e.g., set a label)
209
+
210
+ ### Example
211
+ ```js
212
+ import { tidy, total, sum } from '@tidyjs/tidy';
213
+
214
+ const data = [
215
+ { group: 'a', value: 10 },
216
+ { group: 'b', value: 20 },
217
+ ];
218
+
219
+ tidy(data, total({ value: sum('value') }, { group: () => 'Total' }))
220
+ // output:
221
+ // [
222
+ // { group: 'a', value: 10 },
223
+ // { group: 'b', value: 20 },
224
+ // { group: 'Total', value: 30 },
225
+ // ]
226
+ ```
227
+
228
+ ---
229
+
230
+ <!-- keywords: totalAll, total all columns -->
231
+ ## totalAll
232
+
233
+ Like `total`, but applies one summary function to all columns.
234
+
235
+ **Signature:** `totalAll(summaryFn, mutateSpec)`
236
+ **Goes inside:** `tidy()` pipeline
237
+
238
+ ### Parameters
239
+ - `summaryFn` -- `(key: keyof T) => (items: T[]) => any` -- summary key function
240
+ - `mutateSpec` -- mutations for the total row
241
+
242
+ ---
243
+
244
+ <!-- keywords: totalIf, total conditional columns -->
245
+ ## totalIf
246
+
247
+ Like `total`, but applies summary only to columns matching a predicate.
248
+
249
+ **Signature:** `totalIf(predicateFn, summaryFn, mutateSpec)`
250
+ **Goes inside:** `tidy()` pipeline
251
+
252
+ ### Parameters
253
+ - `predicateFn` -- `(vector: T[keyof T][]) => boolean` -- column predicate
254
+ - `summaryFn` -- summary key function
255
+ - `mutateSpec` -- mutations for the total row
256
+
257
+ ---
258
+
259
+ <!-- keywords: totalAt, total specific columns -->
260
+ ## totalAt
261
+
262
+ Like `total`, but applies summary to specific named columns.
263
+
264
+ **Signature:** `totalAt(keys, summaryFn, mutateSpec)`
265
+ **Goes inside:** `tidy()` pipeline
266
+
267
+ ### Parameters
268
+ - `keys` -- `(keyof T)[]` -- columns to summarize
269
+ - `summaryFn` -- summary key function
270
+ - `mutateSpec` -- mutations for the total row
271
+
272
+ ---
273
+
274
+ ## Summary Functions (aggregation helpers)
275
+
276
+ These go inside `summarize()`, `total()`, or `mutateWithSummary()` specs.
277
+
278
+ They accept a **string key** or **accessor function**: `sum('value')` or `sum((d) => d.value)`.
279
+ They return `(items: T[]) => number|any` -- a function that reduces an array to a single value.
280
+
281
+ ---
282
+
283
+ <!-- keywords: sum, total, add, aggregate sum, conditional sum, predicate -->
284
+ ## sum
285
+
286
+ Computes the sum of values for a key. Uses d3-array `fsum` for floating-point precision.
287
+
288
+ **Signature:** `sum(key, options?)`
289
+ **Goes inside:** `summarize()`, `total()`, `mutateWithSummary()` spec
290
+
291
+ ### Parameters
292
+ - `key` -- `string | (d: T, index: number, array: Iterable<T>) => number`
293
+ - `options?` -- `{ predicate?: (d: T, index: number, array: Iterable<T>) => boolean }` -- only sum items matching predicate
294
+
295
+ ### Example
296
+ ```js
297
+ tidy(data, summarize({
298
+ value: sum('value'),
299
+ fooOnly: sum('value', { predicate: d => d.str === 'foo' }),
300
+ }))
301
+ // input: [{ str: 'foo', value: 3 }, { str: 'bar', value: 7 }]
302
+ // output: [{ value: 10, fooOnly: 3 }]
303
+ ```
304
+
305
+ ---
306
+
307
+ <!-- keywords: mean, average, avg, arithmetic mean -->
308
+ ## mean
309
+
310
+ Computes the arithmetic mean. Uses `fsum` internally for precision.
311
+
312
+ **Signature:** `mean(key)`
313
+ **Goes inside:** `summarize()`, `total()`, `mutateWithSummary()` spec
314
+
315
+ ### Parameters
316
+ - `key` -- `string | (d: T, index: number, array: Iterable<T>) => number`
317
+
318
+ ### Example
319
+ ```js
320
+ tidy(data, summarize({ avg: mean('value') }))
321
+ // input: [{ value: 3 }, { value: 1 }, { value: 7 }]
322
+ // output: [{ avg: 3.667 }]
323
+ ```
324
+
325
+ ---
326
+
327
+ <!-- keywords: median, middle value, 50th percentile -->
328
+ ## median
329
+
330
+ Computes the median value (via d3-array).
331
+
332
+ **Signature:** `median(key)`
333
+ **Goes inside:** `summarize()`, `total()`, `mutateWithSummary()` spec
334
+
335
+ ### Parameters
336
+ - `key` -- `string | (d: T, index: number, array: Iterable<T>) => number`
337
+
338
+ ### Example
339
+ ```js
340
+ tidy(data, summarize({ med: median('value') }))
341
+ // input: [{ value: 3 }, { value: 1 }, { value: 7 }]
342
+ // output: [{ med: 3 }]
343
+ ```
344
+
345
+ ---
346
+
347
+ <!-- keywords: min, minimum, smallest -->
348
+ ## min
349
+
350
+ Returns the minimum value (via d3-array).
351
+
352
+ **Signature:** `min(key)`
353
+ **Goes inside:** `summarize()`, `total()`, `mutateWithSummary()` spec
354
+
355
+ ### Parameters
356
+ - `key` -- `string | (d: T, index: number, array: Iterable<T>) => number`
357
+
358
+ ### Example
359
+ ```js
360
+ tidy(data, summarize({ lo: min('value') }))
361
+ // input: [{ value: 3 }, { value: 1 }, { value: 7 }]
362
+ // output: [{ lo: 1 }]
363
+ ```
364
+
365
+ ---
366
+
367
+ <!-- keywords: max, maximum, largest, highest -->
368
+ ## max
369
+
370
+ Returns the maximum value (via d3-array).
371
+
372
+ **Signature:** `max(key)`
373
+ **Goes inside:** `summarize()`, `total()`, `mutateWithSummary()` spec
374
+
375
+ ### Parameters
376
+ - `key` -- `string | (d: T, index: number, array: Iterable<T>) => number`
377
+
378
+ ### Example
379
+ ```js
380
+ tidy(data, summarize({ hi: max('value') }))
381
+ // input: [{ value: 3 }, { value: 1 }, { value: 7 }]
382
+ // output: [{ hi: 7 }]
383
+ ```
384
+
385
+ ---
386
+
387
+ <!-- keywords: n, count, length, number of items, row count, predicate count -->
388
+ ## n
389
+
390
+ Counts the number of items. Takes no key argument.
391
+
392
+ **Signature:** `n(options?)`
393
+ **Goes inside:** `summarize()`, `total()`, `mutateWithSummary()` spec
394
+
395
+ ### Parameters
396
+ - `options?` -- `{ predicate?: (d: T, index: number, array: Iterable<T>) => boolean }` -- only count items matching predicate
397
+
398
+ ### Example
399
+ ```js
400
+ tidy(data, summarize({
401
+ count: n(),
402
+ countFoo: n({ predicate: d => d.str === 'foo' }),
403
+ }))
404
+ // input: [{ str: 'foo', value: 3 }, { str: 'foo', value: 1 }, { str: 'bar', value: 7 }]
405
+ // output: [{ count: 3, countFoo: 2 }]
406
+ ```
407
+
408
+ ---
409
+
410
+ <!-- keywords: nDistinct, distinct count, unique values, count unique, cardinality -->
411
+ ## nDistinct
412
+
413
+ Counts the number of distinct values for a key. By default includes `null` but excludes `undefined`.
414
+
415
+ **Signature:** `nDistinct(key, options?)`
416
+ **Goes inside:** `summarize()`, `total()`, `mutateWithSummary()` spec
417
+
418
+ ### Parameters
419
+ - `key` -- `string | (d: T, index: number, array: Iterable<T>) => any`
420
+ - `options?` -- `{ includeNull?: boolean, includeUndefined?: boolean }` -- defaults: `includeNull: true`, `includeUndefined: false`
421
+
422
+ ### Example
423
+ ```js
424
+ tidy(data, summarize({ numStr: nDistinct('str') }))
425
+ // input: [{ str: 'foo' }, { str: 'foo' }, { str: 'bar' }]
426
+ // output: [{ numStr: 2 }]
427
+ ```
428
+
429
+ ---
430
+
431
+ <!-- keywords: first, first value, head, pick first -->
432
+ ## first
433
+
434
+ Returns the value of a key from the first item in the collection.
435
+
436
+ **Signature:** `first(key)`
437
+ **Goes inside:** `summarize()`, `total()`, `mutateWithSummary()` spec
438
+
439
+ ### Parameters
440
+ - `key` -- `string | (d: T) => any`
441
+
442
+ ### Example
443
+ ```js
444
+ tidy(data, summarize({ str: first('str'), value: sum('value') }))
445
+ // input: [{ str: 'foo', value: 3 }, { str: 'bar', value: 7 }]
446
+ // output: [{ str: 'foo', value: 10 }]
447
+ ```
448
+
449
+ ---
450
+
451
+ <!-- keywords: last, last value, tail, pick last -->
452
+ ## last
453
+
454
+ Returns the value of a key from the last item in the collection.
455
+
456
+ **Signature:** `last(key)`
457
+ **Goes inside:** `summarize()`, `total()`, `mutateWithSummary()` spec
458
+
459
+ ### Parameters
460
+ - `key` -- `string | (d: T) => any`
461
+
462
+ ### Example
463
+ ```js
464
+ tidy(data, summarize({ str: last('str'), value: sum('value') }))
465
+ // input: [{ str: 'foo', value: 3 }, { str: 'bar', value: 7 }]
466
+ // output: [{ str: 'bar', value: 10 }]
467
+ ```
468
+
469
+ ---
470
+
471
+ <!-- keywords: deviation, standard deviation, stdev, spread, dispersion -->
472
+ ## deviation
473
+
474
+ Computes the standard deviation (via d3-array).
475
+
476
+ **Signature:** `deviation(key)`
477
+ **Goes inside:** `summarize()`, `total()`, `mutateWithSummary()` spec
478
+
479
+ ### Parameters
480
+ - `key` -- `string | (d: T, index: number, array: Iterable<T>) => number`
481
+
482
+ ### Example
483
+ ```js
484
+ tidy(data, summarize({ stdev: deviation('value') }))
485
+ // input: [{ value: 3 }, { value: 1 }, { value: 3 }, { value: 1 }, { value: 7 }]
486
+ // output: [{ stdev: 2.449 }]
487
+ ```
488
+
489
+ ---
490
+
491
+ <!-- keywords: variance, var, spread, dispersion squared -->
492
+ ## variance
493
+
494
+ Computes the variance (via d3-array).
495
+
496
+ **Signature:** `variance(key)`
497
+ **Goes inside:** `summarize()`, `total()`, `mutateWithSummary()` spec
498
+
499
+ ### Parameters
500
+ - `key` -- `string | (d: T, index: number, array: Iterable<T>) => number`
501
+
502
+ ### Example
503
+ ```js
504
+ tidy(data, summarize({ v: variance('value') }))
505
+ // input: [{ value: 3 }, { value: 1 }, { value: 3 }, { value: 1 }, { value: 7 }]
506
+ // output: [{ v: 6 }]
507
+ ```
508
+
509
+ ---
510
+
511
+ <!-- keywords: meanRate, weighted mean, rate, ratio, numerator denominator -->
512
+ ## meanRate
513
+
514
+ Computes a weighted mean rate by summing numerator and denominator independently, then dividing. Avoids bias from averaging pre-computed rates.
515
+
516
+ **Signature:** `meanRate(numerator, denominator)`
517
+ **Goes inside:** `summarize()`, `total()`, `mutateWithSummary()` spec
518
+
519
+ ### Parameters
520
+ - `numerator` -- `string | (d: T, index: number, array: Iterable<T>) => number`
521
+ - `denominator` -- `string | (d: T, index: number, array: Iterable<T>) => number`
522
+
523
+ ### Example
524
+ ```js
525
+ tidy(data, summarize({ rate: meanRate('hits', 'attempts') }))
526
+ // input: [{ hits: 3, attempts: 10 }, { hits: 7, attempts: 10 }]
527
+ // output: [{ rate: 0.5 }]
528
+ ```