UNPKG

als-statistics

Version:

Modular JS statistics toolkit for Node.js and the browser: descriptive stats, correlations (Pearson/Spearman/Kendall), t-tests & ANOVA (Student/Welch), reliability (Cronbach’s alpha), regression (linear/logistic), clustering (DBSCAN/HDBSCAN), and table/co

87 lines (79 loc) 3.11 kB
import Column from '../../column/index.js' export class TableData { static Column = Column #colValues = []; #columns = {}; #colNames = []; #n = 0; constructor(data, options={}) { this.options = options if(data) this.#init(data) } #init(data) { if (data instanceof TableData) data = data.columns const entries = Array.isArray(data) && data.every(v => typeof v === 'string') ? data.map(name => ([name, []])) : Object.entries(data) if(entries.length === 0) return entries.forEach(([n, v]) => this.#addData(v, n)) const allExcludes = Array.from(new Set(this.#colValues.map(({ invalid }) => invalid).flat())) this.#colValues.forEach(col => { const indecesToRemove = allExcludes.filter(i => !col.invalid.includes(i)) col.values = col.values.filter((v, i) => !indecesToRemove.includes(i)) }) this.alignColumns() } get n() { return this.#n } get k() { return this.#colValues.length } get colValues() { return this.#colValues } get columns() { return this.#columns } get colNames() { return this.#colNames } alignColumns() { if(this.options.alignColumns === false) return this.#n = Math.min(...this.#colValues.map(({ n }) => n)) this.#colValues.forEach(column => { if (column.n !== this.#n) column.values = column.values.slice(0, this.#n) }) } #addData(values, name, labels) { const column = new Column(values, name, labels) const colName = name || column.name this.#columns[colName] = column this.#colValues.push(this.#columns[colName]) this.#colNames.push(colName) } #fixRow(row) { const colValues = Array.isArray(row) ? row : this.colNames.map(n => row[n]) .filter(v => typeof v === 'number' && !isNaN(v) && isFinite(v)) if(colValues.length < this.k) throw new Error(`One of values is not acceptable`) return colValues } addRow(row,index) { const colValues = this.#fixRow(row) this.colValues.forEach((col,i) => col.insertAt(index,colValues[i])) this.#n++ return this } addRows(rows,index) { // TODO this method not tested const columns = this.colNames.map(v => ([])) rows.forEach(row => { this.#fixRow(row).forEach((v,i) => columns[i].push(v)) }); columns.forEach((col,i) => { this.colValues[i].insertAt(index,...col) this.#n++ }) return this } deleteRow(index) { if(index > this.n-1) throw new Error(`index not exists`) this.colValues.forEach(col => col.deleteValue(index)) this.#n-- } addColumn(name, data, labels) { this.#addData(data, name, labels); this.alignColumns(); return this.#columns[name] } deleteColumn(name) { if (!this.#columns[name]) return this delete this.#columns[name]; this.#colNames = this.#colNames.filter(k => k !== name) this.#colValues = this.#colValues.filter((s) => s.name !== name) return this; } }