UNPKG

als-statistics

Version:

A powerful and lightweight JavaScript library for descriptive statistics, regression, clustering, outlier detection, and noise analysis using a flexible table/column architecture.

677 lines (472 loc) โ€ข 20.1 kB
# als-statistics **als-statistics** is a fast and lightweight JavaScript library for statistical analysis, outlier detection, regression, clustering, and time series operations. It is designed to work seamlessly in both **Node.js** and **browser** environments, providing an intuitive and consistent API for both quick data exploration and advanced analytical workflows. ## โœจ Key Features - ๐Ÿ“Š **Flexible Table Structure** โ€” Easily manipulate tabular data with automatic type detection. - ๐Ÿ”ข **Two Column Types** โ€” `RatioColumn` for numeric operations and `Column` for strings. - ๐Ÿ” **Built-in Filtering** โ€” Filter rows at the column or table level using `filterRowsBy`, `filterRows`, and more. - ๐Ÿ“ˆ **Descriptive & Inferential Statistics** โ€” Includes mean, variance, confidence intervals, correlation, regression, and more. - โš™๏ธ **Utility Tools** โ€” Use standalone helpers like `range`, `newTable`, `newColumn`, and built-in regression functions. - ๐Ÿ“ฆ **Universal Compatibility** โ€” Supports both CommonJS and ESM imports, as well as browser-ready bundling. --- ## Installation ### Via npm ```bash npm install als-statistics ``` ### Browser Usage Include the script in your HTML: ```html <script src="node_modules/als-statistics/statistics.js"></script> <script> const { newColumn } = Statistics; const col = newColumn([1, 2, 3]); console.log(col.mean); // 2 </script> ``` ## ๐Ÿš€ Quick Start: Plug and Play **als-statistics** allows you to explore data either directly (with standalone columns/tables) or by organizing it inside a `Statistics` instance for multi-table workflows. ### ๐Ÿ“ฆ Standalone Columns Create numeric or categorical columns on the fly: ```js const {newColumn} = require("als-statistics"); // Ratio (numeric) column const numbers = newColumn([1, 2, 3, 4, 5]); console.log(numbers.mean); // 3 console.log(numbers.median); // 3 // Categorical (string) column const categories = newColumn(["A", "B", "A", "C"]); console.log(categories.frequencies); // { A: 2, B: 1, C: 1 } ``` > `Statistics.newColumn(values)` automatically detects the type: > - Numbers โ†’ `RatioColumn`: full statistical toolkit. > - Strings โ†’ `Column`: ideal for frequency counts. --- ### ๐Ÿงฎ Standalone Tables Tables let you manage multiple columns in a structured way. ```js const table = Statistics.newTable({ Numbers: [10, 20, 30, 40], Labels: ["X", "Y", "Z", "W"] }); console.log(table.columns["Numbers"].mean); // 25 console.log(table.columns["Labels"].frequencies); // { X: 1, Y: 1, Z: 1, W: 1 } ``` > Tables automatically assign `Column` or `RatioColumn` types based on values. > Use `.columns[colName]` to access each column. โœจ Tables also support: - Dynamic filtering - Cloning with or without filters - Column-level comparisons - Transposing rows into columns - Aggregating metrics (`descriptive`) --- ### ๐Ÿ” Row Filtering Filter rows at both **column** and **table** levels: ```js // Filter where Numbers โ‰ค 20 table.filterRowsBy("Numbers", v => v > 20); console.log(table.columns["Numbers"].values); // [10, 20] console.log(table.columns["Labels"].values); // ["X", "Y"] // Further filter the Numbers column directly const col = table.columns["Numbers"]; col.filterRowsBy(v => v === 10); console.log(col.values); // [20] console.log(table.columns["Labels"].values); // ["Y"] // Reset all filters table.clearAllRowsFilters(); ``` > โš ๏ธ Filters are **exclusion-based**: the predicate returns **true to exclude** a row. > To keep values instead, use `v => !condition`. --- ### ๐Ÿ“š Using a Statistics Instance Group and analyze multiple tables together: ```js const stats = new Statistics(); const t1 = stats.addTable("Table1", { Data: [1, 2, 3] }); const t2 = stats.addTable("Table2", { Data: [4, 5, 6] }); // Aggregate metrics across tables const means = stats.descriptive("mean"); console.log(means.columns["Table1"].values[0]); // 2 console.log(means.columns["Table2"].values[0]); // 5 ``` > You can also apply filters globally using: > - `stats.filterRows(indexes)` > - `stats.clearAllRowsFilters()` --- ## ๐Ÿ“Š Working with Columns The `Column` and `RatioColumn` classes represent the two main types of data: **categorical** and **numeric**. Each supports filtering, statistics, and derived metrics. > โœ… Columns can now be **empty** (`[]`) โ€” all methods handle them gracefully and return default values like `0`, `NaN`, or `[]`. --- ### `Column` (Categorical Data) - **Use For:** Strings, labels, categories. - **Created By:** - `Statistics.newColumn(["A", "B", "A"])` - `table.addColumn("Name", ["A", "B", "A"])` #### ๐Ÿ”ง Key Properties & Methods: | Feature | Description | |----------------------------|-----------------------------------------------------------------------------| | `values` | Array of current values (after filters). | | `n` | Number of unfiltered values. | | `frequencies` | Object with counts of each unique value. | | `relativeFrequencies` | Object with proportions (relative frequencies). | | `sorted` | Alphabetically sorted values. | | `percentile(p)` | Percentile by index, e.g., `50` is median (treats values as ordered). | | `median`, `q1`, `q3` | Predefined percentiles (50th, 25th, 75th). | | `count(fn, filtered=true)` | Number of values satisfying a condition. | | `filterRows(indexes)` | Exclude rows by their indexes. | | `filterRowsBy(fn)` | Exclude rows where `fn(value, index)` returns `true`. | | `clearRowsFilters()` | Remove all filters. | | `clone(filtered = true)` | Create a filtered or unfiltered copy of the column. | #### ๐Ÿงช Example: ~~~js const col = Statistics.newColumn(["A", "B", "A", "C"]); col.filterRowsBy(v => v === "B"); // Exclude "B" console.log(col.values); // ["A", "A", "C"] console.log(col.frequencies); // { A: 2, C: 1 } ~~~ --- ### `RatioColumn` (Numeric Data) - **Use For:** Numbers (measurements, ratings, etc.). - **Created By:** - `Statistics.newColumn([1, 2, 3])` - `table.addColumn("Scores", [1, 2, 3])` #### ๐Ÿ“ Basic Statistics: | Method | Description | |---------------------|-----------------------------------------| | `sum`, `mean` | Total and average of values. | | `min`, `max`, `range` | Extremes and spread. | #### ๐Ÿ“Š Variability Metrics: - **Population**: - `variancePopulation`, `stdDevPopulation` - `skewnessPopulation`, `kurtosisPopulation` - **Sample**: - `varianceSample`, `stdDevSample` - `skewnessSample`, `kurtosisSample` #### ๐Ÿ“ Dispersion: - `cv`: Coefficient of Variation - `relativeDispersion`: StdDev / Median - `iqr`: Interquartile range #### ๐Ÿ” Advanced Metrics: - `geometricMean`, `harmonicMean`, `flatness` - `sumOfSquares`: ฮฃ(xยฒ) - `normalizedValues`: Min-max scaling to [0, 1] - `zScores`: Standardized values (z = (x - ฮผ) / ฯƒ) - `confidenceInterval95`: `{ low, high, width }` โ€” 95% CI around the mean - `spectralPowerDensityArray`, `spectralPowerDensityMetric`: Noise structure indicators - `noiseStability`: Simple noise estimator #### ๐Ÿงญ New Tools: | Method | Description | |--------------------------------|-----------------------------------------------------------------------------| | `xValues` | Automatically generates `[1, 2, ..., n]` for regression or plotting. | | `regressionSlope(customX?)` | Calculates slope (ฮฒ) vs. `xValues` or custom X-axis. | > `regressionSlope` uses covariance and variance internally. Returns `0` if X is constant. #### โš ๏ธ Outlier Detection: - `outliersIQR`: Outliers using interquartile method. - `outliersZScore(threshold = 3)`: Outliers based on z-scores. #### ๐Ÿงช Example: ~~~js const col = Statistics.newColumn([1, 2, 3, 100]); col.filterRowsBy(v => v > 10); // Exclude 100 console.log(col.mean); // 2 console.log(col.outliersIQR); // [] console.log(col.regressionSlope()); // 1 (if x = [1, 2, 3]) ~~~ --- โœ… Both `Column` and `RatioColumn` support row-level filtering and full integration with `Table` and `Statistics`. # ๐Ÿ“‰ regressionSlope() Calculates the slope of the best-fit line through a numeric column. ## ๐Ÿ”น Signature ~~~js column.regressionSlope(customX = null) ~~~ ## ๐Ÿ”น Description Returns the slope of the regression line between: - `this` column (Y) - `customX` or the default `xValues = [1, 2, ..., n]` ## ๐Ÿ”น Example ~~~js const col = Statistics.newColumn([2, 4, 6]); console.log(col.regressionSlope()); // 2 ~~~ If `customX` is not provided, `[1, 2, 3]` is used. ## Noise Analysis Analyze noise in numeric data: ```js const col = Statistics.newColumn([1, 2, 3, 100]); const noise = col.noice(); console.log(noise.noiseByZ(0.1)); // false (outlier present) ``` --- ## ๐Ÿ“‹ Working with Tables Tables allow you to manage multiple columns, filter data, create new computed columns, perform statistical comparisons โ€” and now also run **linear regression** directly. --- ### ๐Ÿ› ๏ธ Creating a Table and Adding Columns You can initialize a table with or without data: ```js const table = Statistics.newTable(); table.addColumn("Scores", [10, 20, 30, 40]); table.addColumn("Grades", ["A", "B", "C", "D"]); ``` Or create with data immediately: ```js const table = Statistics.newTable({ Scores: [10, 20, 30, 40], Grades: ["A", "B", "C", "D"] }); ``` > Column types (`RatioColumn` or `Column`) are auto-detected. --- ### โž• Adding Rows ```js table.addRow({ Scores: 50, Grades: "F" }); // Adds to the end table.addRow({ Scores: 5, Grades: "A+" }, 0); // Inserts at index 0 ``` Returns `true` if successful, `false` if structure or types donโ€™t match. --- ### ๐Ÿ” Row Filtering ```js // Exclude specific rows by index table.filterRows([1]); console.log(table.columns["Scores"].values); // [10, 30, 40] // Filter by values using column-level filter table.clearAllRowsFilters(); table.filterRowsBy("Scores", v => v > 20); console.log(table.columns["Scores"].values); // [10, 20] console.log(table.columns["Grades"].values); // ["A", "B"] // Reset filters table.clearAllRowsFilters(); ``` --- ### ๐Ÿงฎ Computing New Columns Use any logic to generate new columns: ```js table.compute(({ Scores }) => Scores * 2, "Doubled"); console.log(table.columns["Doubled"].values); // [20, 40, 60, 80] ``` > Uses the row-wise structure: `({ Col1, Col2 }) => ...` --- ### ๐Ÿ”Ž Filtering with `.where(...)` Returns matching row indexes (ignoring filtered rows): ```js const indexes = table.where(({ Scores }) => Scores > 15); console.log(indexes); // [1, 2, 3] if "Scores" > 15 ``` --- ### ๐Ÿ” Transposing the Table Turns rows into columns: ```js const transposed = table.transpose(); console.log(transposed.columns["0"].values); // [10, "A"] ``` --- ### ๐Ÿ“ˆ Running Linear Regression Perform regression right from the table: ```js const model = table.linearRegression("Scores", ["Doubled"]).calculate(); console.table(model.result); ``` - `table.linearRegression(y, x)` is a shortcut for `new LinearRegression(...)` - Supports `.mediator(...)`, `.moderator(...)`, and `.calculate()` chaining --- ### ๐Ÿ“Š Aggregating Metrics (Descriptive) ```js const means = table.descriptive("mean"); console.log(means.columns["Scores"].values[0]); // e.g. 25 ``` Any column-level metric is supported, like `"stdDevSample"`, `"cv"`, `"flatness"`, etc. --- ### ๐Ÿงช Comparing Two Columns ```js const comp = table.compare("Scores", "Doubled"); console.log(comp.correlationSample); // e.g. 1.0 ``` Returns a `Comparative` object, which supports: - `correlationSample`, `correlationPopulation` - `covarianceSample`, `covariancePopulation` - `pearsonSample`, `pearsonPopulation` - `twoSampleTTest()` --- ### ๐Ÿ“ฆ Cloning Tables You can duplicate the table with filters and/or selected columns: ```js // Clone with all columns and current row filters const fullClone = table.clone(true); console.log(fullClone.columns["Scores"].values); // [10, 20, 30, 40] // Clone with selected columns const selectedClone = table.clone(true, ["Scores"]); // Only "Scores" console.log(selectedClone.columns["Scores"].values); // [10, 20, 30, 40] console.log(selectedClone.columns["Grades"]); // undefined // Clone excluding columns const excludedClone = table.clone(true, ["-Grades"]); // All except "Grades" console.log(excludedClone.columns["Scores"].values); // [10, 20, 30, 40] console.log(excludedClone.columns["Grades"]); // undefined // Clone with regex filter table.addColumn("Scores2", [1, 2, 3, 4]); const regexClone = table.clone(true, [/^Scores/]); // Columns starting with "Scores" console.log(regexClone.columns["Scores"].values); // [10, 20, 30, 40] console.log(regexClone.columns["Scores2"].values); // [1, 2, 3, 4] ``` - **Options for `clone(filtered, columnFilter)`:** - `filtered`: `true` (keep row filters) or `false` (use original data). - `columnFilter`: Array of filters: - `"Name"`: Include this column. - `"-Name"`: Exclude this column (if no includes specified). - `/pattern/`: Include columns matching the regex. - **Note:** If explicit includes (e.g., `"A"`) are used, exclusions (e.g., `"-B"`) are ignored. --- ### ๐Ÿงน Removing Columns ```js table.deleteColumn("Grades"); console.log(table.columns["Grades"]); // undefined ``` --- ### ๐Ÿš€ Available Methods | Method | Description | |--------------------------------|--------------------------------------------------------------| | `addColumn(name, values)` | Adds new column with auto-detection. | | `addRow(obj, index?)` | Appends or inserts a row. | | `compute(fn, name?)` | Computes a new column. | | `compare(col1, col2)` | Returns statistical comparison object. | | `filterRows(indexes)` | Excludes rows by index. | | `filterRowsBy(name, fn)` | Filters rows based on column values. | | `clearAllRowsFilters()` | Removes all filters. | | `clone(filtered, filterCols)` | Returns new table with selected rows/columns. | | `descriptive(metric)` | Returns a new table with a summary metric per column. | | `transpose()` | Flips rows and columns. | | `where(fn)` | Returns indexes of matching rows. | | `dbscan(eps, minPts)` | Runs DBSCAN clustering on columns. | | `hdbscan(minPts)` | Runs HDBSCAN clustering (hierarchical). | | `linearRegression(y, x?)` | Returns a new `LinearRegression` instance for the table. | --- ## ๐Ÿ“Š DBSCAN Clustering `dbscan(eps, minPts)` identifies clusters of correlated numeric columns using DBSCAN (Density-Based Spatial Clustering of Applications with Noise). ### ๐Ÿ”น Parameters - `eps` (default: `0.4`) โ€” maximum distance between columns to be considered neighbors. - `minPts` (default: `3`) โ€” minimum number of neighbors to form a dense region (cluster). ### ๐Ÿ”น Usage ```js const table = Statistics.newTable({ A: [1, 2, 3], B: [10, 20, 30], C: [5, 10, 15] }); const dbscan = table.dbscan(0.5, 2); console.log(dbscan.labels); // Example: [1, 1, -1] console.log(dbscan.clusters); // Array of clustered Table instances ``` ### ๐Ÿ”น Output - `labels`: Array assigning a cluster ID or `-1` for noise to each column. - `clusters`: Array of new `Table` instances, one per cluster. ### ๐Ÿ”น How It Works - Measures correlation between numeric columns. - Builds pairwise distances. - Expands clusters around dense areas. ## ๐Ÿ“ Cronbach's Alpha Cronbachโ€™s Alpha measures internal consistency โ€” how closely related a set of numeric items are. ### ๐Ÿ”น Use Cases - Questionnaires and surveys - Psychometric analysis - Testing item reliability ### ๐Ÿ”น Usage ```js const table = Statistics.newTable({ Q1: [4, 5, 3, 4, 5], Q2: [3, 4, 2, 3, 4], Q3: [5, 3, 4, 5, 2] }); const alpha = table.cronbachAlpha; console.log(alpha.alpha); // Example: 0.74 ``` ### ๐Ÿ”น Item Deletion Diagnostics ```js console.log(alpha.perColumn); // { Q1: 0.65, Q2: 0.68, Q3: 0.71 } ``` ### ๐Ÿ”น Notes - Requires 2+ numeric columns. - If all responses are identical, `alpha = 0`. ## ๐Ÿ“Š Pearson Correlation Measures the linear correlation (Pearsonโ€™s r) between two numeric columns. ### ๐Ÿ”น Usage ```js const table = Statistics.newTable({ X: [10, 20, 30], Y: [15, 25, 35] }); const correlation = table.compare("X", "Y").pearsonSample; console.log(correlation.r); // 1.0 (perfect correlation) console.log(correlation.p); // 0.0 (significant) ``` ### ๐Ÿ”น Interpretation - `r` close to 1 or -1: strong correlation - `p < 0.05`: statistically significant ### ๐Ÿ”น Access - `.pearsonSample` โ€” uses sample variance - `.pearsonPopulation` โ€” uses population variance ## ๐Ÿ“ˆ Linear Regression `LinearRegression` performs multiple linear regression on `Table` data. ### ๐Ÿ”น Key Features - Multiple predictors - Intercept term - Mediator and moderator support - Coefficients, p-values, Rยฒ - Interaction terms (X*Z) ### ๐Ÿ”น Example ```js const table = Statistics.newTable({ X: [1, 2, 3, 4, 5], Y: [2, 4, 6, 8, 10] }); const model = table.linearRegression("Y", ["X"]).calculate(); console.table(model.result); // Expect Intercept โ‰ˆ 0, X Coefficient โ‰ˆ 2 ``` ### ๐Ÿ”น With Mediator ```js table.linearRegression("Y", ["X"]) .mediator("M") .calculate(); ``` ### ๐Ÿ”น With Moderator ```js table.linearRegression("Y", ["X"]) .moderator("Z") .calculate(); ``` ### ๐Ÿ”น Output ```js model.result // { // Variable: ['Intercept', 'X', ...], // Coefficient: [...], // StdError: [...], // pValue: [...] // } ``` ### html table ```js table.linearRegression("Y", ["X"]).htmlTable ``` ### ๐Ÿ”น Notes - Internally uses matrix algebra - Throws if predictors are constant or if matrix is singular ## Managing Multiple Tables with `Statistics` Use `Statistics` to group tables: ```js const stats = new Statistics(); stats.addTable("Sales").addColumn("Revenue", [100, 200, 300]); stats.addTable("Costs").addColumn("Expenses", [50, 100, 150]); stats.filterRows([1]); // Filters all tables const statsMeans = stats.descriptive("mean"); console.log(statsMeans.columns["Sales"].values[0]); // 200 ``` - **Methods:** - `filterRows(indexes)`: Applies to all tables. - `clearRowsFilters(indexes)`, `clearAllRowsFilters()`: Clears filters across tables. --- ## Utilities - **`Statistics.range(start, end, step)`**: Generates an array of numbers. ```js const r = Statistics.range(1, 5, 2); // [1, 3] ```