rowpipe 2.2.1 → 2.10.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.
- package/README.md +35 -4
- package/dist/analytics/abtest.d.ts +39 -0
- package/dist/analytics/abtest.d.ts.map +1 -0
- package/dist/analytics/abtest.js +266 -0
- package/dist/analytics/abtest.js.map +1 -0
- package/dist/analytics/cluster.d.ts +25 -0
- package/dist/analytics/cluster.d.ts.map +1 -0
- package/dist/analytics/cluster.js +212 -0
- package/dist/analytics/cluster.js.map +1 -0
- package/dist/analytics/cohort.d.ts +22 -0
- package/dist/analytics/cohort.d.ts.map +1 -0
- package/dist/analytics/cohort.js +170 -0
- package/dist/analytics/cohort.js.map +1 -0
- package/dist/analytics/correlation.d.ts +15 -0
- package/dist/analytics/correlation.d.ts.map +1 -0
- package/dist/analytics/correlation.js +116 -0
- package/dist/analytics/correlation.js.map +1 -0
- package/dist/analytics/crosstab.d.ts +27 -0
- package/dist/analytics/crosstab.d.ts.map +1 -0
- package/dist/analytics/crosstab.js +90 -0
- package/dist/analytics/crosstab.js.map +1 -0
- package/dist/analytics/entropy.d.ts +23 -0
- package/dist/analytics/entropy.d.ts.map +1 -0
- package/dist/analytics/entropy.js +180 -0
- package/dist/analytics/entropy.js.map +1 -0
- package/dist/analytics/funnel.d.ts +29 -0
- package/dist/analytics/funnel.d.ts.map +1 -0
- package/dist/analytics/funnel.js +170 -0
- package/dist/analytics/funnel.js.map +1 -0
- package/dist/analytics/ngrams.d.ts +25 -0
- package/dist/analytics/ngrams.d.ts.map +1 -0
- package/dist/analytics/ngrams.js +110 -0
- package/dist/analytics/ngrams.js.map +1 -0
- package/dist/analytics/outliers.d.ts +25 -0
- package/dist/analytics/outliers.d.ts.map +1 -0
- package/dist/analytics/outliers.js +114 -0
- package/dist/analytics/outliers.js.map +1 -0
- package/dist/analytics/pareto.d.ts +36 -0
- package/dist/analytics/pareto.d.ts.map +1 -0
- package/dist/analytics/pareto.js +140 -0
- package/dist/analytics/pareto.js.map +1 -0
- package/dist/analytics/quantiles.d.ts +18 -0
- package/dist/analytics/quantiles.d.ts.map +1 -0
- package/dist/analytics/quantiles.js +62 -0
- package/dist/analytics/quantiles.js.map +1 -0
- package/dist/analytics/regression.d.ts +18 -0
- package/dist/analytics/regression.d.ts.map +1 -0
- package/dist/analytics/regression.js +79 -0
- package/dist/analytics/regression.js.map +1 -0
- package/dist/analytics/rfm.d.ts +41 -0
- package/dist/analytics/rfm.d.ts.map +1 -0
- package/dist/analytics/rfm.js +221 -0
- package/dist/analytics/rfm.js.map +1 -0
- package/dist/analytics/stats.d.ts.map +1 -1
- package/dist/analytics/stats.js +65 -15
- package/dist/analytics/stats.js.map +1 -1
- package/dist/analytics/technical.d.ts +19 -0
- package/dist/analytics/technical.d.ts.map +1 -0
- package/dist/analytics/technical.js +365 -0
- package/dist/analytics/technical.js.map +1 -0
- package/dist/cli/commands/abtest.d.ts +10 -0
- package/dist/cli/commands/abtest.d.ts.map +1 -0
- package/dist/cli/commands/abtest.js +68 -0
- package/dist/cli/commands/abtest.js.map +1 -0
- package/dist/cli/commands/cluster.d.ts +9 -0
- package/dist/cli/commands/cluster.d.ts.map +1 -0
- package/dist/cli/commands/cluster.js +77 -0
- package/dist/cli/commands/cluster.js.map +1 -0
- package/dist/cli/commands/cohort.d.ts +10 -0
- package/dist/cli/commands/cohort.d.ts.map +1 -0
- package/dist/cli/commands/cohort.js +66 -0
- package/dist/cli/commands/cohort.js.map +1 -0
- package/dist/cli/commands/completion.d.ts +5 -0
- package/dist/cli/commands/completion.d.ts.map +1 -0
- package/dist/cli/commands/completion.js +7 -0
- package/dist/cli/commands/completion.js.map +1 -0
- package/dist/cli/commands/concat.d.ts +9 -0
- package/dist/cli/commands/concat.d.ts.map +1 -0
- package/dist/cli/commands/concat.js +62 -0
- package/dist/cli/commands/concat.js.map +1 -0
- package/dist/cli/commands/convert.d.ts +2 -0
- package/dist/cli/commands/convert.d.ts.map +1 -1
- package/dist/cli/commands/convert.js.map +1 -1
- package/dist/cli/commands/corr.d.ts +7 -0
- package/dist/cli/commands/corr.d.ts.map +1 -0
- package/dist/cli/commands/corr.js +70 -0
- package/dist/cli/commands/corr.js.map +1 -0
- package/dist/cli/commands/crosstab.d.ts +11 -0
- package/dist/cli/commands/crosstab.d.ts.map +1 -0
- package/dist/cli/commands/crosstab.js +71 -0
- package/dist/cli/commands/crosstab.js.map +1 -0
- package/dist/cli/commands/entropy.d.ts +9 -0
- package/dist/cli/commands/entropy.d.ts.map +1 -0
- package/dist/cli/commands/entropy.js +71 -0
- package/dist/cli/commands/entropy.js.map +1 -0
- package/dist/cli/commands/explode.d.ts +8 -0
- package/dist/cli/commands/explode.d.ts.map +1 -0
- package/dist/cli/commands/explode.js +61 -0
- package/dist/cli/commands/explode.js.map +1 -0
- package/dist/cli/commands/fetch.d.ts +8 -0
- package/dist/cli/commands/fetch.d.ts.map +1 -0
- package/dist/cli/commands/fetch.js +41 -0
- package/dist/cli/commands/fetch.js.map +1 -0
- package/dist/cli/commands/files.d.ts +1 -1
- package/dist/cli/commands/files.d.ts.map +1 -1
- package/dist/cli/commands/flatten.d.ts +8 -0
- package/dist/cli/commands/flatten.d.ts.map +1 -0
- package/dist/cli/commands/flatten.js +57 -0
- package/dist/cli/commands/flatten.js.map +1 -0
- package/dist/cli/commands/freq.d.ts +10 -0
- package/dist/cli/commands/freq.d.ts.map +1 -0
- package/dist/cli/commands/freq.js +122 -0
- package/dist/cli/commands/freq.js.map +1 -0
- package/dist/cli/commands/funnel.d.ts +11 -0
- package/dist/cli/commands/funnel.d.ts.map +1 -0
- package/dist/cli/commands/funnel.js +69 -0
- package/dist/cli/commands/funnel.js.map +1 -0
- package/dist/cli/commands/fuzzy-join.d.ts +25 -0
- package/dist/cli/commands/fuzzy-join.d.ts.map +1 -0
- package/dist/cli/commands/fuzzy-join.js +85 -0
- package/dist/cli/commands/fuzzy-join.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +8 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +34 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/mask.d.ts +6 -0
- package/dist/cli/commands/mask.d.ts.map +1 -0
- package/dist/cli/commands/mask.js +58 -0
- package/dist/cli/commands/mask.js.map +1 -0
- package/dist/cli/commands/ngrams.d.ts +11 -0
- package/dist/cli/commands/ngrams.d.ts.map +1 -0
- package/dist/cli/commands/ngrams.js +70 -0
- package/dist/cli/commands/ngrams.js.map +1 -0
- package/dist/cli/commands/outliers.d.ts +13 -0
- package/dist/cli/commands/outliers.d.ts.map +1 -0
- package/dist/cli/commands/outliers.js +58 -0
- package/dist/cli/commands/outliers.js.map +1 -0
- package/dist/cli/commands/pareto.d.ts +8 -0
- package/dist/cli/commands/pareto.d.ts.map +1 -0
- package/dist/cli/commands/pareto.js +80 -0
- package/dist/cli/commands/pareto.js.map +1 -0
- package/dist/cli/commands/partition.d.ts +8 -0
- package/dist/cli/commands/partition.d.ts.map +1 -0
- package/dist/cli/commands/partition.js +44 -0
- package/dist/cli/commands/partition.js.map +1 -0
- package/dist/cli/commands/pipeline.d.ts +6 -0
- package/dist/cli/commands/pipeline.d.ts.map +1 -1
- package/dist/cli/commands/pipeline.js +22 -0
- package/dist/cli/commands/pipeline.js.map +1 -1
- package/dist/cli/commands/pivot.d.ts +11 -0
- package/dist/cli/commands/pivot.d.ts.map +1 -0
- package/dist/cli/commands/pivot.js +58 -0
- package/dist/cli/commands/pivot.js.map +1 -0
- package/dist/cli/commands/plot.d.ts +12 -0
- package/dist/cli/commands/plot.d.ts.map +1 -0
- package/dist/cli/commands/plot.js +123 -0
- package/dist/cli/commands/plot.js.map +1 -0
- package/dist/cli/commands/quantiles.d.ts +7 -0
- package/dist/cli/commands/quantiles.d.ts.map +1 -0
- package/dist/cli/commands/quantiles.js +94 -0
- package/dist/cli/commands/quantiles.js.map +1 -0
- package/dist/cli/commands/regression.d.ts +7 -0
- package/dist/cli/commands/regression.d.ts.map +1 -0
- package/dist/cli/commands/regression.js +86 -0
- package/dist/cli/commands/regression.js.map +1 -0
- package/dist/cli/commands/report.d.ts +8 -0
- package/dist/cli/commands/report.d.ts.map +1 -0
- package/dist/cli/commands/report.js +36 -0
- package/dist/cli/commands/report.js.map +1 -0
- package/dist/cli/commands/rfm.d.ts +11 -0
- package/dist/cli/commands/rfm.d.ts.map +1 -0
- package/dist/cli/commands/rfm.js +78 -0
- package/dist/cli/commands/rfm.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +7 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +43 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/split.d.ts +8 -0
- package/dist/cli/commands/split.d.ts.map +1 -0
- package/dist/cli/commands/split.js +43 -0
- package/dist/cli/commands/split.js.map +1 -0
- package/dist/cli/commands/table.d.ts +9 -0
- package/dist/cli/commands/table.d.ts.map +1 -0
- package/dist/cli/commands/table.js +9 -0
- package/dist/cli/commands/table.js.map +1 -0
- package/dist/cli/commands/technical.d.ts +8 -0
- package/dist/cli/commands/technical.d.ts.map +1 -0
- package/dist/cli/commands/technical.js +54 -0
- package/dist/cli/commands/technical.js.map +1 -0
- package/dist/cli/commands/test.d.ts +7 -0
- package/dist/cli/commands/test.d.ts.map +1 -0
- package/dist/cli/commands/test.js +53 -0
- package/dist/cli/commands/test.js.map +1 -0
- package/dist/cli/commands/timeseries.d.ts +11 -0
- package/dist/cli/commands/timeseries.d.ts.map +1 -0
- package/dist/cli/commands/timeseries.js +82 -0
- package/dist/cli/commands/timeseries.js.map +1 -0
- package/dist/cli/commands/unpivot.d.ts +12 -0
- package/dist/cli/commands/unpivot.d.ts.map +1 -0
- package/dist/cli/commands/unpivot.js +59 -0
- package/dist/cli/commands/unpivot.js.map +1 -0
- package/dist/cli/completion.d.ts +5 -0
- package/dist/cli/completion.d.ts.map +1 -0
- package/dist/cli/completion.js +194 -0
- package/dist/cli/completion.js.map +1 -0
- package/dist/cli/index.js +816 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/core/error-handler.d.ts +38 -0
- package/dist/core/error-handler.d.ts.map +1 -0
- package/dist/core/error-handler.js +81 -0
- package/dist/core/error-handler.js.map +1 -0
- package/dist/core/pipeline.d.ts +10 -0
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/pipeline.js +14 -0
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/types.d.ts +4 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/dataops/fetch.d.ts +27 -0
- package/dist/dataops/fetch.d.ts.map +1 -0
- package/dist/dataops/fetch.js +150 -0
- package/dist/dataops/fetch.js.map +1 -0
- package/dist/dataops/generate.d.ts +16 -0
- package/dist/dataops/generate.d.ts.map +1 -0
- package/dist/dataops/generate.js +201 -0
- package/dist/dataops/generate.js.map +1 -0
- package/dist/dataops/mask.d.ts +25 -0
- package/dist/dataops/mask.d.ts.map +1 -0
- package/dist/dataops/mask.js +133 -0
- package/dist/dataops/mask.js.map +1 -0
- package/dist/dataops/report.d.ts +7 -0
- package/dist/dataops/report.d.ts.map +1 -0
- package/dist/dataops/report.js +139 -0
- package/dist/dataops/report.js.map +1 -0
- package/dist/dataops/server.d.ts +10 -0
- package/dist/dataops/server.d.ts.map +1 -0
- package/dist/dataops/server.js +137 -0
- package/dist/dataops/server.js.map +1 -0
- package/dist/dataops/test-runner.d.ts +34 -0
- package/dist/dataops/test-runner.d.ts.map +1 -0
- package/dist/dataops/test-runner.js +128 -0
- package/dist/dataops/test-runner.js.map +1 -0
- package/dist/db/adapters/sqlite.d.ts.map +1 -1
- package/dist/db/adapters/sqlite.js +4 -1
- package/dist/db/adapters/sqlite.js.map +1 -1
- package/dist/diff/engine.d.ts.map +1 -1
- package/dist/diff/engine.js +73 -16
- package/dist/diff/engine.js.map +1 -1
- package/dist/diff/storage/disk-index.d.ts +10 -1
- package/dist/diff/storage/disk-index.d.ts.map +1 -1
- package/dist/diff/storage/disk-index.js +95 -13
- package/dist/diff/storage/disk-index.js.map +1 -1
- package/dist/files/hash.d.ts +9 -2
- package/dist/files/hash.d.ts.map +1 -1
- package/dist/files/hash.js +9 -10
- package/dist/files/hash.js.map +1 -1
- package/dist/files/reader.d.ts.map +1 -1
- package/dist/files/reader.js +17 -10
- package/dist/files/reader.js.map +1 -1
- package/dist/files/types.d.ts +2 -1
- package/dist/files/types.d.ts.map +1 -1
- package/dist/index.d.ts +65 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +66 -1
- package/dist/index.js.map +1 -1
- package/dist/planner/executor.d.ts.map +1 -1
- package/dist/planner/executor.js +17 -0
- package/dist/planner/executor.js.map +1 -1
- package/dist/planner/types.d.ts +11 -0
- package/dist/planner/types.d.ts.map +1 -1
- package/dist/readers/csv.d.ts.map +1 -1
- package/dist/readers/csv.js +206 -164
- package/dist/readers/csv.js.map +1 -1
- package/dist/readers/json.d.ts.map +1 -1
- package/dist/readers/json.js +145 -121
- package/dist/readers/json.js.map +1 -1
- package/dist/readers/jsonl.d.ts.map +1 -1
- package/dist/readers/jsonl.js +51 -31
- package/dist/readers/jsonl.js.map +1 -1
- package/dist/rowpipe +4 -0
- package/dist/transforms/concat.d.ts +26 -0
- package/dist/transforms/concat.d.ts.map +1 -0
- package/dist/transforms/concat.js +57 -0
- package/dist/transforms/concat.js.map +1 -0
- package/dist/transforms/explode.d.ts +14 -0
- package/dist/transforms/explode.d.ts.map +1 -0
- package/dist/transforms/explode.js +81 -0
- package/dist/transforms/explode.js.map +1 -0
- package/dist/transforms/flatten.d.ts +12 -0
- package/dist/transforms/flatten.d.ts.map +1 -0
- package/dist/transforms/flatten.js +65 -0
- package/dist/transforms/flatten.js.map +1 -0
- package/dist/transforms/fuzzy-join.d.ts +53 -0
- package/dist/transforms/fuzzy-join.d.ts.map +1 -0
- package/dist/transforms/fuzzy-join.js +347 -0
- package/dist/transforms/fuzzy-join.js.map +1 -0
- package/dist/transforms/jit-compiler.d.ts.map +1 -1
- package/dist/transforms/jit-compiler.js +103 -14
- package/dist/transforms/jit-compiler.js.map +1 -1
- package/dist/transforms/map.d.ts +6 -2
- package/dist/transforms/map.d.ts.map +1 -1
- package/dist/transforms/map.js +64 -26
- package/dist/transforms/map.js.map +1 -1
- package/dist/transforms/partition.d.ts +35 -0
- package/dist/transforms/partition.d.ts.map +1 -0
- package/dist/transforms/partition.js +150 -0
- package/dist/transforms/partition.js.map +1 -0
- package/dist/transforms/pivot.d.ts +16 -0
- package/dist/transforms/pivot.d.ts.map +1 -0
- package/dist/transforms/pivot.js +194 -0
- package/dist/transforms/pivot.js.map +1 -0
- package/dist/transforms/sort/comparator.d.ts.map +1 -1
- package/dist/transforms/sort/comparator.js +153 -24
- package/dist/transforms/sort/comparator.js.map +1 -1
- package/dist/transforms/sort/external-sort.js +1 -1
- package/dist/transforms/sort/external-sort.js.map +1 -1
- package/dist/transforms/split.d.ts +17 -0
- package/dist/transforms/split.d.ts.map +1 -0
- package/dist/transforms/split.js +88 -0
- package/dist/transforms/split.js.map +1 -0
- package/dist/transforms/timeseries.d.ts +42 -0
- package/dist/transforms/timeseries.d.ts.map +1 -0
- package/dist/transforms/timeseries.js +276 -0
- package/dist/transforms/timeseries.js.map +1 -0
- package/dist/transforms/unpivot.d.ts +14 -0
- package/dist/transforms/unpivot.d.ts.map +1 -0
- package/dist/transforms/unpivot.js +56 -0
- package/dist/transforms/unpivot.js.map +1 -0
- package/dist/ui/chart.d.ts +30 -0
- package/dist/ui/chart.d.ts.map +1 -0
- package/dist/ui/chart.js +91 -0
- package/dist/ui/chart.js.map +1 -0
- package/dist/writers/index.d.ts +1 -0
- package/dist/writers/index.d.ts.map +1 -1
- package/dist/writers/index.js +10 -0
- package/dist/writers/index.js.map +1 -1
- package/dist/writers/table.d.ts +23 -0
- package/dist/writers/table.d.ts.map +1 -0
- package/dist/writers/table.js +156 -0
- package/dist/writers/table.js.map +1 -0
- package/package.json +6 -3
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Row, DataBatch } from "../core/types.js";
|
|
2
|
+
export type CohortInterval = "1d" | "1w" | "1mo" | "1y" | "day" | "week" | "month" | "year";
|
|
3
|
+
export interface CohortOptions {
|
|
4
|
+
userIdCol?: string;
|
|
5
|
+
timeCol?: string;
|
|
6
|
+
interval?: CohortInterval;
|
|
7
|
+
percent?: boolean;
|
|
8
|
+
maxPeriods?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface CohortMatrixResult {
|
|
11
|
+
cohorts: Array<{
|
|
12
|
+
cohort: string;
|
|
13
|
+
total_users: number;
|
|
14
|
+
periods: number[];
|
|
15
|
+
retention_rates: number[];
|
|
16
|
+
}>;
|
|
17
|
+
formattedRows: Row[];
|
|
18
|
+
interval: string;
|
|
19
|
+
maxPeriodIndex: number;
|
|
20
|
+
}
|
|
21
|
+
export declare function computeCohort(batchIterator: AsyncIterable<DataBatch>, options?: CohortOptions): Promise<CohortMatrixResult>;
|
|
22
|
+
//# sourceMappingURL=cohort.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cohort.d.ts","sourceRoot":"","sources":["../../src/analytics/cohort.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5F,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,KAAK,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,eAAe,EAAE,MAAM,EAAE,CAAC;KAC3B,CAAC,CAAC;IACH,aAAa,EAAE,GAAG,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;CACxB;AAyDD,wBAAsB,aAAa,CACjC,aAAa,EAAE,aAAa,CAAC,SAAS,CAAC,EACvC,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,kBAAkB,CAAC,CA2I7B"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
function parseDateToMs(val) {
|
|
2
|
+
if (val === null || val === undefined || val === "")
|
|
3
|
+
return null;
|
|
4
|
+
if (val instanceof Date && !isNaN(val.getTime()))
|
|
5
|
+
return val.getTime();
|
|
6
|
+
if (typeof val === "number" && Number.isFinite(val)) {
|
|
7
|
+
return val < 100_000_000_000 ? Math.floor(val * 1000) : Math.floor(val);
|
|
8
|
+
}
|
|
9
|
+
if (typeof val === "string") {
|
|
10
|
+
const trimmed = val.trim();
|
|
11
|
+
if (!trimmed)
|
|
12
|
+
return null;
|
|
13
|
+
const num = Number(trimmed);
|
|
14
|
+
if (!Number.isNaN(num) && /^\d{10,13}$/.test(trimmed)) {
|
|
15
|
+
return num < 100_000_000_000 ? Math.floor(num * 1000) : Math.floor(num);
|
|
16
|
+
}
|
|
17
|
+
const parsed = Date.parse(trimmed);
|
|
18
|
+
if (!Number.isNaN(parsed)) {
|
|
19
|
+
return parsed;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
function getPeriodKeyAndIndex(ms, interval) {
|
|
25
|
+
const d = new Date(ms);
|
|
26
|
+
const year = d.getUTCFullYear();
|
|
27
|
+
const month = d.getUTCMonth(); // 0-11
|
|
28
|
+
const date = d.getUTCDate();
|
|
29
|
+
const normInterval = interval.toLowerCase();
|
|
30
|
+
if (normInterval === "1d" || normInterval === "day") {
|
|
31
|
+
const key = `${year}-${String(month + 1).padStart(2, "0")}-${String(date).padStart(2, "0")}`;
|
|
32
|
+
const dayIndex = Math.floor(ms / (1000 * 60 * 60 * 24));
|
|
33
|
+
return { key, index: dayIndex };
|
|
34
|
+
}
|
|
35
|
+
if (normInterval === "1w" || normInterval === "week") {
|
|
36
|
+
// Week index from epoch
|
|
37
|
+
const weekIndex = Math.floor(ms / (1000 * 60 * 60 * 24 * 7));
|
|
38
|
+
// Start of week date
|
|
39
|
+
const sowMs = weekIndex * 7 * 24 * 60 * 60 * 1000;
|
|
40
|
+
const sow = new Date(sowMs);
|
|
41
|
+
const key = `W${year}-${String(sow.getUTCMonth() + 1).padStart(2, "0")}-${String(sow.getUTCDate()).padStart(2, "0")}`;
|
|
42
|
+
return { key, index: weekIndex };
|
|
43
|
+
}
|
|
44
|
+
if (normInterval === "1y" || normInterval === "year") {
|
|
45
|
+
return { key: `${year}`, index: year };
|
|
46
|
+
}
|
|
47
|
+
// Default: 1mo / month
|
|
48
|
+
const key = `${year}-${String(month + 1).padStart(2, "0")}`;
|
|
49
|
+
const monthIndex = year * 12 + month;
|
|
50
|
+
return { key, index: monthIndex };
|
|
51
|
+
}
|
|
52
|
+
export async function computeCohort(batchIterator, options = {}) {
|
|
53
|
+
const interval = options.interval || "1mo";
|
|
54
|
+
const maxPeriods = options.maxPeriods ?? 12;
|
|
55
|
+
const isPercent = options.percent ?? true;
|
|
56
|
+
let userIdCol = options.userIdCol;
|
|
57
|
+
let timeCol = options.timeCol;
|
|
58
|
+
// Map: userId -> { minIndex: number, minKey: string, activeIndices: Set<number> }
|
|
59
|
+
const userMap = new Map();
|
|
60
|
+
for await (const batch of batchIterator) {
|
|
61
|
+
if (batch.rows.length === 0)
|
|
62
|
+
continue;
|
|
63
|
+
if (!userIdCol || !timeCol) {
|
|
64
|
+
const firstRow = batch.rows[0];
|
|
65
|
+
const keys = Object.keys(firstRow);
|
|
66
|
+
if (!userIdCol) {
|
|
67
|
+
userIdCol =
|
|
68
|
+
keys.find((k) => /^(user(_?id)?|customer(_?id)?|client(_?id)?|account(_?id)?|uid|id)$/i.test(k)) ??
|
|
69
|
+
keys[0];
|
|
70
|
+
}
|
|
71
|
+
if (!timeCol) {
|
|
72
|
+
timeCol =
|
|
73
|
+
keys.find((k) => /(date|time|timestamp|created_at|event_time|occurred_at)/i.test(k)) ??
|
|
74
|
+
keys[1];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
for (const row of batch.rows) {
|
|
78
|
+
const rawUid = row[userIdCol];
|
|
79
|
+
if (rawUid === null || rawUid === undefined || rawUid === "")
|
|
80
|
+
continue;
|
|
81
|
+
const uid = String(rawUid);
|
|
82
|
+
const ms = parseDateToMs(row[timeCol]);
|
|
83
|
+
if (ms === null)
|
|
84
|
+
continue;
|
|
85
|
+
const { key, index } = getPeriodKeyAndIndex(ms, interval);
|
|
86
|
+
let uEntry = userMap.get(uid);
|
|
87
|
+
if (!uEntry) {
|
|
88
|
+
uEntry = { minIndex: index, minKey: key, activeIndices: new Set() };
|
|
89
|
+
userMap.set(uid, uEntry);
|
|
90
|
+
}
|
|
91
|
+
else if (index < uEntry.minIndex) {
|
|
92
|
+
uEntry.minIndex = index;
|
|
93
|
+
uEntry.minKey = key;
|
|
94
|
+
}
|
|
95
|
+
uEntry.activeIndices.add(index);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Aggregate cohorts
|
|
99
|
+
// Map: cohortKey -> { minIndex: number, users: Set<string>, periodCounts: Map<offset, number> }
|
|
100
|
+
const cohortGroups = new Map();
|
|
101
|
+
let globalMaxOffset = 0;
|
|
102
|
+
for (const [uid, uEntry] of userMap.entries()) {
|
|
103
|
+
let group = cohortGroups.get(uEntry.minKey);
|
|
104
|
+
if (!group) {
|
|
105
|
+
group = {
|
|
106
|
+
minIndex: uEntry.minIndex,
|
|
107
|
+
userIds: new Set(),
|
|
108
|
+
periodCounts: new Map(),
|
|
109
|
+
};
|
|
110
|
+
cohortGroups.set(uEntry.minKey, group);
|
|
111
|
+
}
|
|
112
|
+
group.userIds.add(uid);
|
|
113
|
+
for (const actIdx of uEntry.activeIndices) {
|
|
114
|
+
const offset = actIdx - uEntry.minIndex;
|
|
115
|
+
if (offset >= 0 && offset <= maxPeriods) {
|
|
116
|
+
group.periodCounts.set(offset, (group.periodCounts.get(offset) || 0) + 1);
|
|
117
|
+
if (offset > globalMaxOffset) {
|
|
118
|
+
globalMaxOffset = offset;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Sort cohorts chronologically
|
|
124
|
+
const sortedCohorts = Array.from(cohortGroups.entries()).sort((a, b) => a[1].minIndex - b[1].minIndex);
|
|
125
|
+
const cohortResults = [];
|
|
126
|
+
const formattedRows = [];
|
|
127
|
+
const periodLabelPrefix = interval.startsWith("1d") || interval === "day"
|
|
128
|
+
? "+Day "
|
|
129
|
+
: interval.startsWith("1w") || interval === "week"
|
|
130
|
+
? "+Wk "
|
|
131
|
+
: interval.startsWith("1y") || interval === "year"
|
|
132
|
+
? "+Yr "
|
|
133
|
+
: "+M";
|
|
134
|
+
for (const [cKey, g] of sortedCohorts) {
|
|
135
|
+
const totalUsers = g.userIds.size;
|
|
136
|
+
const periods = [];
|
|
137
|
+
const retentionRates = [];
|
|
138
|
+
const rowObj = {
|
|
139
|
+
cohort: cKey,
|
|
140
|
+
users: totalUsers,
|
|
141
|
+
};
|
|
142
|
+
for (let p = 0; p <= globalMaxOffset; p++) {
|
|
143
|
+
const count = g.periodCounts.get(p) || 0;
|
|
144
|
+
const rate = totalUsers > 0 ? (count / totalUsers) * 100 : 0;
|
|
145
|
+
periods.push(count);
|
|
146
|
+
retentionRates.push(Math.round(rate * 10) / 10);
|
|
147
|
+
const colName = `${periodLabelPrefix}${p}`;
|
|
148
|
+
if (isPercent) {
|
|
149
|
+
rowObj[colName] = count > 0 ? `${(Math.round(rate * 10) / 10).toFixed(1)}%` : "-";
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
rowObj[colName] = count > 0 ? count : "-";
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
cohortResults.push({
|
|
156
|
+
cohort: cKey,
|
|
157
|
+
total_users: totalUsers,
|
|
158
|
+
periods,
|
|
159
|
+
retention_rates: retentionRates,
|
|
160
|
+
});
|
|
161
|
+
formattedRows.push(rowObj);
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
cohorts: cohortResults,
|
|
165
|
+
formattedRows,
|
|
166
|
+
interval,
|
|
167
|
+
maxPeriodIndex: globalMaxOffset,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=cohort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cohort.js","sourceRoot":"","sources":["../../src/analytics/cohort.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DataStream, Row } from "../core/types.js";
|
|
2
|
+
export interface CorrelationMatrixResult {
|
|
3
|
+
columns: string[];
|
|
4
|
+
matrix: Record<string, Record<string, number>>;
|
|
5
|
+
sampleSize: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Computes Pearson correlation matrix across numeric columns in a single streaming pass.
|
|
9
|
+
*/
|
|
10
|
+
export declare function computeCorrelationMatrix(stream: DataStream, targetColumns?: string[]): Promise<CorrelationMatrixResult>;
|
|
11
|
+
/**
|
|
12
|
+
* Converts a correlation matrix result into tabular Rows suitable for table or CSV export.
|
|
13
|
+
*/
|
|
14
|
+
export declare function formatCorrelationRows(result: CorrelationMatrixResult): Row[];
|
|
15
|
+
//# sourceMappingURL=correlation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"correlation.d.ts","sourceRoot":"","sources":["../../src/analytics/correlation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAGxD,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,UAAU,EAClB,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,uBAAuB,CAAC,CA6GlC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,uBAAuB,GAAG,GAAG,EAAE,CAQ5E"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes Pearson correlation matrix across numeric columns in a single streaming pass.
|
|
3
|
+
*/
|
|
4
|
+
export async function computeCorrelationMatrix(stream, targetColumns) {
|
|
5
|
+
let cols = targetColumns ? [...targetColumns] : [];
|
|
6
|
+
let colsDiscovered = Boolean(targetColumns && targetColumns.length > 0);
|
|
7
|
+
let n = 0;
|
|
8
|
+
const means = {};
|
|
9
|
+
const m2 = {};
|
|
10
|
+
const coMoments = {};
|
|
11
|
+
function initCols(discoveredCols) {
|
|
12
|
+
cols = discoveredCols;
|
|
13
|
+
for (const c of cols) {
|
|
14
|
+
means[c] = 0;
|
|
15
|
+
m2[c] = 0;
|
|
16
|
+
coMoments[c] = {};
|
|
17
|
+
for (const c2 of cols) {
|
|
18
|
+
coMoments[c][c2] = 0;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
colsDiscovered = true;
|
|
22
|
+
}
|
|
23
|
+
if (colsDiscovered) {
|
|
24
|
+
initCols(cols);
|
|
25
|
+
}
|
|
26
|
+
for await (const batch of stream) {
|
|
27
|
+
for (const row of batch.rows) {
|
|
28
|
+
if (!colsDiscovered) {
|
|
29
|
+
const numericCols = [];
|
|
30
|
+
for (const [k, v] of Object.entries(row)) {
|
|
31
|
+
if (typeof v === "number" && Number.isFinite(v)) {
|
|
32
|
+
numericCols.push(k);
|
|
33
|
+
}
|
|
34
|
+
else if (v !== null && v !== undefined && v !== "") {
|
|
35
|
+
const parsed = Number(v);
|
|
36
|
+
if (!Number.isNaN(parsed) && Number.isFinite(parsed)) {
|
|
37
|
+
numericCols.push(k);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (numericCols.length > 0) {
|
|
42
|
+
initCols(numericCols);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (cols.length === 0)
|
|
46
|
+
continue;
|
|
47
|
+
// Extract numeric values for this row
|
|
48
|
+
const rowVals = {};
|
|
49
|
+
let rowValid = true;
|
|
50
|
+
for (const c of cols) {
|
|
51
|
+
const val = row[c];
|
|
52
|
+
const num = typeof val === "number" ? val : parseFloat(String(val));
|
|
53
|
+
if (!Number.isFinite(num)) {
|
|
54
|
+
rowValid = false;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
rowVals[c] = num;
|
|
58
|
+
}
|
|
59
|
+
if (!rowValid)
|
|
60
|
+
continue;
|
|
61
|
+
n++;
|
|
62
|
+
const deltaX = {};
|
|
63
|
+
for (const c of cols) {
|
|
64
|
+
const x = rowVals[c];
|
|
65
|
+
deltaX[c] = x - means[c];
|
|
66
|
+
means[c] = means[c] + deltaX[c] / n;
|
|
67
|
+
m2[c] = m2[c] + deltaX[c] * (x - means[c]);
|
|
68
|
+
}
|
|
69
|
+
for (let i = 0; i < cols.length; i++) {
|
|
70
|
+
const c1 = cols[i];
|
|
71
|
+
for (let j = 0; j < cols.length; j++) {
|
|
72
|
+
const c2 = cols[j];
|
|
73
|
+
coMoments[c1][c2] = (coMoments[c1][c2] || 0) + deltaX[c1] * (rowVals[c2] - means[c2]);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const resultMatrix = {};
|
|
79
|
+
for (const c1 of cols) {
|
|
80
|
+
resultMatrix[c1] = {};
|
|
81
|
+
for (const c2 of cols) {
|
|
82
|
+
if (n < 2) {
|
|
83
|
+
resultMatrix[c1][c2] = c1 === c2 ? 1.0 : 0.0;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const var1 = m2[c1] / (n - 1);
|
|
87
|
+
const var2 = m2[c2] / (n - 1);
|
|
88
|
+
const cov = coMoments[c1][c2] / (n - 1);
|
|
89
|
+
if (var1 <= 0 || var2 <= 0) {
|
|
90
|
+
resultMatrix[c1][c2] = c1 === c2 ? 1.0 : 0.0;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
const r = cov / (Math.sqrt(var1) * Math.sqrt(var2));
|
|
94
|
+
resultMatrix[c1][c2] = Math.max(-1, Math.min(1, parseFloat(r.toFixed(4))));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
columns: cols,
|
|
100
|
+
matrix: resultMatrix,
|
|
101
|
+
sampleSize: n,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Converts a correlation matrix result into tabular Rows suitable for table or CSV export.
|
|
106
|
+
*/
|
|
107
|
+
export function formatCorrelationRows(result) {
|
|
108
|
+
return result.columns.map((c1) => {
|
|
109
|
+
const rowObj = { column: c1 };
|
|
110
|
+
for (const c2 of result.columns) {
|
|
111
|
+
rowObj[c2] = result.matrix[c1]?.[c2] ?? 0;
|
|
112
|
+
}
|
|
113
|
+
return rowObj;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=correlation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"correlation.js","sourceRoot":"","sources":["../../src/analytics/correlation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { DataStream, Row } from "../core/types.js";
|
|
2
|
+
export interface CrosstabResult {
|
|
3
|
+
rowCol: string;
|
|
4
|
+
colCol: string;
|
|
5
|
+
rowCategories: string[];
|
|
6
|
+
colCategories: string[];
|
|
7
|
+
counts: Record<string, Record<string, number>>;
|
|
8
|
+
rowTotals: Record<string, number>;
|
|
9
|
+
colTotals: Record<string, number>;
|
|
10
|
+
grandTotal: number;
|
|
11
|
+
chiSquare: number;
|
|
12
|
+
degreesOfFreedom: number;
|
|
13
|
+
}
|
|
14
|
+
export interface CrosstabOptions {
|
|
15
|
+
topRows?: number;
|
|
16
|
+
topCols?: number;
|
|
17
|
+
normalize?: "row" | "col" | "all";
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Computes 2D contingency matrix (crosstab) and Chi-Square statistic.
|
|
21
|
+
*/
|
|
22
|
+
export declare function computeCrosstab(stream: DataStream, rowCol: string, colCol: string, options?: CrosstabOptions): Promise<CrosstabResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Formats a CrosstabResult as tabular rows for table / CSV rendering.
|
|
25
|
+
*/
|
|
26
|
+
export declare function formatCrosstabRows(result: CrosstabResult, normalize?: "row" | "col" | "all"): Row[];
|
|
27
|
+
//# sourceMappingURL=crosstab.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crosstab.d.ts","sourceRoot":"","sources":["../../src/analytics/crosstab.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;CACnC;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAuDzB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,cAAc,EAAE,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,GAAG,EAAE,CAmCnG"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes 2D contingency matrix (crosstab) and Chi-Square statistic.
|
|
3
|
+
*/
|
|
4
|
+
export async function computeCrosstab(stream, rowCol, colCol, options = {}) {
|
|
5
|
+
const counts = {};
|
|
6
|
+
const rowTotals = {};
|
|
7
|
+
const colTotals = {};
|
|
8
|
+
let grandTotal = 0;
|
|
9
|
+
for await (const batch of stream) {
|
|
10
|
+
for (const row of batch.rows) {
|
|
11
|
+
const rVal = String(row[rowCol] ?? "<null>");
|
|
12
|
+
const cVal = String(row[colCol] ?? "<null>");
|
|
13
|
+
if (!counts[rVal])
|
|
14
|
+
counts[rVal] = {};
|
|
15
|
+
counts[rVal][cVal] = (counts[rVal][cVal] || 0) + 1;
|
|
16
|
+
rowTotals[rVal] = (rowTotals[rVal] || 0) + 1;
|
|
17
|
+
colTotals[cVal] = (colTotals[cVal] || 0) + 1;
|
|
18
|
+
grandTotal++;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
// Sort and limit categories
|
|
22
|
+
const sortedRowCats = Object.keys(rowTotals).sort((a, b) => rowTotals[b] - rowTotals[a]);
|
|
23
|
+
const sortedColCats = Object.keys(colTotals).sort((a, b) => colTotals[b] - colTotals[a]);
|
|
24
|
+
const rowCategories = options.topRows ? sortedRowCats.slice(0, options.topRows) : sortedRowCats;
|
|
25
|
+
const colCategories = options.topCols ? sortedColCats.slice(0, options.topCols) : sortedColCats;
|
|
26
|
+
// Compute Chi-Square
|
|
27
|
+
let chiSquare = 0;
|
|
28
|
+
if (grandTotal > 0 && rowCategories.length > 1 && colCategories.length > 1) {
|
|
29
|
+
for (const r of rowCategories) {
|
|
30
|
+
for (const c of colCategories) {
|
|
31
|
+
const observed = counts[r]?.[c] || 0;
|
|
32
|
+
const expected = ((rowTotals[r] || 0) * (colTotals[c] || 0)) / grandTotal;
|
|
33
|
+
if (expected > 0) {
|
|
34
|
+
chiSquare += ((observed - expected) ** 2) / expected;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const degreesOfFreedom = Math.max(0, (rowCategories.length - 1) * (colCategories.length - 1));
|
|
40
|
+
return {
|
|
41
|
+
rowCol,
|
|
42
|
+
colCol,
|
|
43
|
+
rowCategories,
|
|
44
|
+
colCategories,
|
|
45
|
+
counts,
|
|
46
|
+
rowTotals,
|
|
47
|
+
colTotals,
|
|
48
|
+
grandTotal,
|
|
49
|
+
chiSquare: parseFloat(chiSquare.toFixed(4)),
|
|
50
|
+
degreesOfFreedom,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Formats a CrosstabResult as tabular rows for table / CSV rendering.
|
|
55
|
+
*/
|
|
56
|
+
export function formatCrosstabRows(result, normalize) {
|
|
57
|
+
const rows = [];
|
|
58
|
+
for (const r of result.rowCategories) {
|
|
59
|
+
const rowObj = { [result.rowCol]: r };
|
|
60
|
+
const rTotal = result.rowTotals[r] || 0;
|
|
61
|
+
for (const c of result.colCategories) {
|
|
62
|
+
const count = result.counts[r]?.[c] || 0;
|
|
63
|
+
if (normalize === "row") {
|
|
64
|
+
rowObj[c] = rTotal > 0 ? `${((count / rTotal) * 100).toFixed(1)}%` : "0.0%";
|
|
65
|
+
}
|
|
66
|
+
else if (normalize === "col") {
|
|
67
|
+
const cTotal = result.colTotals[c] || 0;
|
|
68
|
+
rowObj[c] = cTotal > 0 ? `${((count / cTotal) * 100).toFixed(1)}%` : "0.0%";
|
|
69
|
+
}
|
|
70
|
+
else if (normalize === "all") {
|
|
71
|
+
rowObj[c] = result.grandTotal > 0 ? `${((count / result.grandTotal) * 100).toFixed(1)}%` : "0.0%";
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
rowObj[c] = count;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
rowObj["Total"] = normalize === "row" ? "100.0%" : rTotal;
|
|
78
|
+
rows.push(rowObj);
|
|
79
|
+
}
|
|
80
|
+
// Add summary total row
|
|
81
|
+
const totalRow = { [result.rowCol]: "Total" };
|
|
82
|
+
for (const c of result.colCategories) {
|
|
83
|
+
const cTotal = result.colTotals[c] || 0;
|
|
84
|
+
totalRow[c] = normalize === "col" ? "100.0%" : cTotal;
|
|
85
|
+
}
|
|
86
|
+
totalRow["Total"] = result.grandTotal;
|
|
87
|
+
rows.push(totalRow);
|
|
88
|
+
return rows;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=crosstab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crosstab.js","sourceRoot":"","sources":["../../src/analytics/crosstab.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Row, DataBatch } from "../core/types.js";
|
|
2
|
+
export interface EntropyOptions {
|
|
3
|
+
targetCol?: string;
|
|
4
|
+
cols?: string | string[];
|
|
5
|
+
bins?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface FeatureImportanceResult {
|
|
8
|
+
feature: string;
|
|
9
|
+
entropy: number;
|
|
10
|
+
information_gain: number;
|
|
11
|
+
gain_ratio: number;
|
|
12
|
+
importance_score: number;
|
|
13
|
+
distinct_values: number;
|
|
14
|
+
}
|
|
15
|
+
export interface EntropyAnalysisResult {
|
|
16
|
+
target_column?: string;
|
|
17
|
+
target_entropy?: number;
|
|
18
|
+
total_samples: number;
|
|
19
|
+
features: FeatureImportanceResult[];
|
|
20
|
+
formattedRows: Row[];
|
|
21
|
+
}
|
|
22
|
+
export declare function computeEntropy(batchIterator: AsyncIterable<DataBatch>, options?: EntropyOptions): Promise<EntropyAnalysisResult>;
|
|
23
|
+
//# sourceMappingURL=entropy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entropy.d.ts","sourceRoot":"","sources":["../../src/analytics/entropy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEvD,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,qBAAqB;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,uBAAuB,EAAE,CAAC;IACpC,aAAa,EAAE,GAAG,EAAE,CAAC;CACtB;AASD,wBAAsB,cAAc,CAClC,aAAa,EAAE,aAAa,CAAC,SAAS,CAAC,EACvC,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,qBAAqB,CAAC,CA2LhC"}
|