UNPKG

nipals-pca

Version:

A NIPALS implementation of PCA that handles missing values

169 lines (124 loc) 4.83 kB
const chai = require('chai'); const {expect} = chai; chai.use(require('chai-roughly')); const { Dataset } = require('../src/Dataset'); const { PCA } = require('../src/pca'); var fs = require('fs'); var Papa = require('papaparse'); let inputMatrixPromise = parseExampleInput(fs.readFileSync('test/data/iris/IRIS.csv', 'utf8')); let mv_inputMatrixPromise = parseExampleInput(fs.readFileSync('test/data/iris/IRIS_mv.csv', 'utf8')); let meansPromise = parseExampleInput(fs.readFileSync('test/data/iris/irisMeanValues.txt', 'utf8')); let stdPromise = parseExampleInput(fs.readFileSync('test/data/iris/irisStdValues.txt', 'utf8')); let mv_meansPromise = parseExampleInput(fs.readFileSync('test/data/iris/irisMeanValues_mv.txt', 'utf8')); let mv_stdPromise = parseExampleInput(fs.readFileSync('test/data/iris/irisStdValues_mv.txt', 'utf8')); let scoresPromise = parseExampleInput(fs.readFileSync('test/data/iris/irisT.txt', 'utf8')); let loadingsPromise = parseExampleInput(fs.readFileSync('test/data/iris/irisP.txt', 'utf8')); let mv_scoresPromise = parseExampleInput(fs.readFileSync('test/data/iris/IRIS_mv_T.txt', 'utf8')); let mv_loadingsPromise = parseExampleInput(fs.readFileSync('test/data/iris/IRIS_mv_P.txt', 'utf8')); describe('Test Dataset creation and normalization', () => { let jsonMatrix; let means,stdevs; let dataset; before(async ()=>{ jsonMatrix = await inputMatrixPromise; //remove last column jsonMatrix.map(r => r.splice(-1, 1)); dataset = new Dataset(jsonMatrix); means = await meansPromise; means = means.map(([value])=>parseFloat(value)); stdevs = await stdPromise; stdevs = stdevs.map(([value])=>1/parseFloat(value)) }); it('Check centering', () => { expect(means).to.roughly(0.001).deep.equal(dataset.means); }) it('Check UV scaling', () => { expect(stdevs).to.roughly(0.001).deep.equal(dataset.stdevs); }) }) describe('Test PCA', () => { let pca; before(async ()=>{ let components = 3; jsonMatrix = await parseExampleInput(fs.readFileSync('test/data/iris/IRIS.csv', 'utf8')); //remove last column jsonMatrix.map(r => r.splice(-1, 1)); dataset = new Dataset(jsonMatrix); scores = await scoresPromise; scores.splice(0,1); scores = scores.map(row=>row.slice(1,components+1).map(v=>parseFloat(v))); loadings = await loadingsPromise; loadings.splice(0,1); loadings = loadings.map(row=>row.slice(1,components+1).map(v=>parseFloat(v))); pca = new PCA(dataset,components); pca.fit(); }); let tolerance = 0.001; for (let a = 0; a < 3; a++) { it(`PCA loadings and scores are correct for component ${a+1}`, () => { expect(loadings.map(row=>Math.abs(row[a]))).to.roughly(tolerance).deep.equal(pca.P.getColumn(a).map(v=>Math.abs(v))); expect(scores.map(row=>Math.abs(row[a]))).to.roughly(tolerance).deep.equal(pca.T.getColumn(a).map(v=>Math.abs(v))); }) } }) describe('Test MV Dataset creation and normalization', () => { let jsonMatrix; let means,stdevs; let dataset; before(async ()=>{ jsonMatrix = await mv_inputMatrixPromise; //remove last column jsonMatrix.map(r => r.splice(0, 1)); dataset = new Dataset(jsonMatrix); means = await mv_meansPromise; means = means.map(([value])=>parseFloat(value)); stdevs = await mv_stdPromise; stdevs = stdevs.map(([value])=>1/parseFloat(value)) }); it('Check centering', () => { expect(means).to.roughly(0.001).deep.equal(dataset.means); }) it('Check UV scaling', () => { expect(stdevs).to.roughly(0.001).deep.equal(dataset.stdevs); }) }) describe('Test PCA with missing values', () => { let pca; before(async ()=>{ let components = 3; jsonMatrix = await parseExampleInput(fs.readFileSync('test/data/iris/IRIS_mv.csv', 'utf8')); //remove last column jsonMatrix.map(r => r.splice(0, 1)); dataset = new Dataset(jsonMatrix); scores = await mv_scoresPromise; scores.splice(0,1); scores = scores.map(row=>row.slice(1,components+1).map(v=>parseFloat(v))); loadings = await mv_loadingsPromise; loadings.splice(0,1); loadings = loadings.map(row=>row.slice(1,components+1).map(v=>parseFloat(v))); pca = new PCA(dataset,components); pca.fit(); }); let tolerance = 0.001; for (let a = 0; a < 3; a++) { it(`PCA loadings and scores are correct for component ${a+1}`, () => { expect(loadings.map(row=>Math.abs(row[a]))).to.roughly(tolerance).deep.equal(pca.P.getColumn(a).map(v=>Math.abs(v))); expect(scores.map(row=>Math.abs(row[a]))).to.roughly(tolerance).deep.equal(pca.T.getColumn(a).map(v=>Math.abs(v))); }) } }) function parseExampleInput(file) { return new Promise((resolve, reject) => { Papa.parse(file, { header: false, skipEmptyLines: true, complete(results, file) { let data = results.data; resolve(data) }, error(err, file) { reject(err) } }) }) }