main.js (4174B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2020 The Stdlib Authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 'use strict'; 20 21 // MODULES // 22 23 var setReadOnly = require( '@stdlib/utils/define-read-only-property' ); 24 var isNonNegativeIntegerArray = require( '@stdlib/assert/is-nonnegative-integer-array' ); 25 var isMatrixLike = require( '@stdlib/assert/is-matrix-like' ); 26 var isArrayArray = require( '@stdlib/assert/is-array-array' ); 27 var array = require( '@stdlib/ndarray/array' ); 28 var incrmin = require( './../../incr/min' ); 29 var gsum = require( '@stdlib/blas/ext/base/gsum' ); 30 var min = require( '@stdlib/math/base/special/min' ); 31 var copy = require( '@stdlib/utils/copy' ); 32 var chisqCDF = require( './../../base/dists/chisquare/cdf' ); 33 var prettyPrint = require( './print.js' ); 34 var defaults = require( './defaults.json' ); 35 var sumByDimension = require( './sum.js' ); 36 var outer = require( './outer.js' ); 37 var absdiff = require( './absdiff.js' ); 38 var validate = require( './validate.js' ); 39 40 41 // MAIN // 42 43 /** 44 * Performs a chi-square independence test. 45 * 46 * @param {(ndarray|ArrayArray)} x - two-way table of cell counts 47 * @param {Options} [options] - function options 48 * @param {number} [options.alpha=0.05] - significance level 49 * @param {boolean} [options.correct=true] - boolean indicating whether to use Yates' continuity correction when provided a 2x2 contingency table 50 * @throws {TypeError} first argument must be an array of arrays or ndarray-like object with dimension two 51 * @returns {Object} test results 52 * 53 * @example 54 * 55 * @example 56 * var x = [ [ 20, 30 ], [ 30, 20 ] ]; 57 * var out = chi2test( x ); 58 * // returns { 'rejected': false, 'alpha': 0.05, 'pValue': ~0.072, ... } 59 */ 60 function chi2test( x, options ) { 61 var absDiff; 62 var colSums; 63 var rowSums; 64 var minAbs; 65 var yates; 66 var means; 67 var param; 68 var nrow; 69 var ncol; 70 var opts; 71 var pval; 72 var stat; 73 var err; 74 var out; 75 var N; 76 var i; 77 78 if ( isArrayArray( x ) ) { 79 x = array( x ); 80 } 81 if ( !isMatrixLike( x ) ) { 82 throw new TypeError( 'invalid argument. First argument `x` must be an array of arrays or ndarray-like object with dimension two. Value: `' + x + '`.' ); 83 } 84 if ( !isNonNegativeIntegerArray( x.data ) ) { 85 throw new TypeError( 'invalid argument. First argument `x` must contain nonnegative integers. Value: `' + x + '`.' ); 86 } 87 opts = copy( defaults ); 88 if ( arguments.length > 1 ) { 89 err = validate( opts, options ); 90 if ( err ) { 91 throw err; 92 } 93 } 94 N = gsum( x.length, x.data, 1 ); 95 nrow = x.shape[ 0 ]; 96 ncol = x.shape[ 1 ]; 97 98 colSums = sumByDimension( x, 1 ); 99 rowSums = sumByDimension( x, 2 ); 100 means = outer( rowSums, colSums ); 101 for ( i = 0; i < means.length; i++ ) { 102 means.data[ i ] /= N; 103 } 104 absDiff = absdiff( x, means ); 105 106 if ( opts.correct && nrow === 2 && ncol === 2 ) { 107 // Apply Yates' continuity correction: 108 minAbs = incrmin(); 109 for ( i = 0; i < absDiff.length; i++ ) { 110 minAbs( absDiff[ i ] ); 111 } 112 yates = min( 0.5, minAbs() ); 113 for ( i = 0; i < absDiff.length; i++ ) { 114 absDiff[ i ] -= yates; 115 } 116 } 117 for ( i = 0; i < absDiff.length; i++ ) { 118 absDiff[ i ] *= absDiff[ i ]; 119 absDiff[ i ] /= means.data[ i ]; 120 } 121 stat = gsum( absDiff.length, absDiff, 1 ); 122 param = ( nrow - 1 ) * ( ncol - 1 ); 123 pval = 1 - chisqCDF( stat, param ); 124 125 out = {}; 126 setReadOnly( out, 'rejected', pval <= opts.alpha ); 127 setReadOnly( out, 'alpha', opts.alpha ); 128 setReadOnly( out, 'pValue', pval ); 129 setReadOnly( out, 'df', param ); 130 setReadOnly( out, 'expected', means ); 131 setReadOnly( out, 'statistic', stat ); 132 setReadOnly( out, 'method', 'Chi-square independence test' ); 133 setReadOnly( out, 'print', prettyPrint( out ) ); 134 return out; 135 } 136 137 138 // EXPORTS // 139 140 module.exports = chi2test;