Implementation of the CHITEST() statistical function (#1960)

* Implementation of the CHITEST() statistical function

* A couple of additional edge case tests (rows = 1, columns = 1)
This commit is contained in:
Mark Baker 2021-03-27 22:04:05 +01:00 committed by GitHub
parent a34dd71cce
commit 67fec4e3fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 2 deletions

View File

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Added
- Implemented the CHITEST() Statistical function.
- Support for ActiveSheet and SelectedCells in the ODS Reader and Writer. [PR #1908](https://github.com/PHPOffice/PhpSpreadsheet/pull/1908)
### Changed

View File

@ -518,12 +518,12 @@ class Calculation
],
'CHITEST' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Functions::class, 'DUMMY'],
'functionCall' => [Statistical\Distributions\ChiSquared::class, 'test'],
'argumentCount' => '2',
],
'CHISQ.TEST' => [
'category' => Category::CATEGORY_STATISTICAL,
'functionCall' => [Functions::class, 'DUMMY'],
'functionCall' => [Statistical\Distributions\ChiSquared::class, 'test'],
'argumentCount' => '2',
],
'CHOOSE' => [

View File

@ -82,4 +82,45 @@ class ChiSquared
return $newtonRaphson->execute($probability);
}
public static function test($actual, $expected)
{
$rows = count($actual);
$actual = Functions::flattenArray($actual);
$expected = Functions::flattenArray($expected);
$columns = count($actual) / $rows;
$countActuals = count($actual);
$countExpected = count($expected);
if ($countActuals !== $countExpected || $countActuals === 1) {
return Functions::NAN();
}
$result = 0.0;
for ($i = 0; $i < $countActuals; ++$i) {
if ($expected[$i] == 0.0) {
return Functions::DIV0();
} elseif ($expected[$i] < 0.0) {
return Functions::NAN();
}
$result += (($actual[$i] - $expected[$i]) ** 2) / $expected[$i];
}
$degrees = self::degrees($rows, $columns);
$result = self::distribution($result, $degrees);
return $result;
}
protected static function degrees(int $rows, int $columns): int
{
if ($rows === 1) {
return $columns - 1;
} elseif ($columns === 1) {
return $rows - 1;
}
return ($columns - 1) * ($rows - 1);
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical;
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
use PHPUnit\Framework\TestCase;
class ChiTestTest extends TestCase
{
/**
* @dataProvider providerCHITEST
*
* @param mixed $expectedResult
* @param mixed $actual
* @param mixed $expected
*/
public function testCHITEST($expectedResult, $actual, $expected): void
{
$result = Statistical\Distributions\ChiSquared::test($actual, $expected);
self::assertEqualsWithDelta($expectedResult, $result, 1E-12);
}
public function providerCHITEST()
{
return require 'tests/data/Calculation/Statistical/CHITEST.php';
}
}

View File

@ -0,0 +1,39 @@
<?php
return [
[
0.0152703571482,
[[112, 76], [85, 95]],
[[100, 85], [70, 90]],
],
[
0.000308192027,
[[58, 35], [11, 25], [10, 23]],
[[45.35, 47.65], [17.56, 18.44], [16.09, 16.91]],
],
[
0.015888560447,
[[58], [11], [10]],
[[45.35], [17.56], [16.09]],
],
[
0.008682970191,
[[58, 35]],
[[45.35, 47.65]],
],
[
'#NUM!',
[[58, 11], [10, 35], [25]],
[[45.35, 17.56], [16.09, 47.65], [18.44, 16.91]],
],
[
'#DIV/0!',
[[112, 76], [85, 95]],
[[100, 0], [70, 90]],
],
[
'#NUM!',
[[112, 76], [85, 95]],
[[100, 85], [-70, 90]],
],
];