123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- <?php
- namespace MathPHP\Tests\Statistics;
- use MathPHP\Exception;
- use MathPHP\Statistics\KernelDensityEstimation;
- class KernelDensityEstimationTest extends \PHPUnit\Framework\TestCase
- {
- /** @var array 100 Random normally distributed data points */
- private $data = [
- -2.76, -2.59, -2.57, -2.4, -1.9, -1.77, -1.33, -1.27, -1.26, -1.19, -1.13, -1.1, -1.09, -1.05, -1.03,
- -0.9, -0.87, -0.87, -0.85, -0.83, -0.78, -0.71, -0.62, -0.61, -0.6, -0.57, -0.55, -0.51, -0.5, -0.5,
- -0.47, -0.46, -0.46, -0.45, -0.44, -0.32, -0.28, -0.27, -0.25, -0.23, -0.21, -0.21, -0.2, -0.16, -0.15,
- -0.11, -0.094, -0.07, -0.06, -0.04, 0, 0.03, 0.04, 0.06, 0.06, 0.09, 0.1, 0.12, 0.15, 0.15, 0.18, 0.22,
- 0.22, 0.23, 0.24, 0.3, 0.31, 0.34, 0.34, 0.38, 0.38, 0.44, 0.52, 0.53, 0.56, 0.57, 0.61, 0.61, 0.69,
- 0.7, 0.75, 0.79, 0.79, 0.79, 0.8, 0.83, 0.85, 0.99, 1.08, 1.23, 1.23, 1.23, 1.25, 1.29, 1.32, 1.34,
- 1.43, 1.49, 1.62, 1.75
- ];
- /**
- * @test evaluate using default standard normal kernel function
- * @dataProvider dataProviderForKernelDensity
- * @param array $data
- * @param float $x
- * @param float $expected
- */
- public function testDefaultKernelDensity(array $data, float $x, float $expected)
- {
- // Given
- $KDE = new KernelDensityEstimation($data);
- // When
- $estimate = $KDE->evaluate($x);
- // Then
- $this->assertEqualsWithDelta($expected, $estimate, 0.0001);
- }
- /**
- * @return array [data, x, expected]
- */
- public function dataProviderForKernelDensity(): array
- {
- return [
- [ $this->data, 1, 0.236055582 ],
- [ $this->data, .1, 0.421356196 ],
- [ $this->data, -1, 0.232277743 ],
- ];
- }
- /**
- * @test evaluate when setting custom h using default kernel function
- * @dataProvider dataProviderForKernelDensityCustomH
- * @param array $data
- * @param float $h
- * @param float $x
- * @param float $expected
- */
- public function testDefaultKernelDensityCustomH(array $data, float $h, float $x, float $expected)
- {
- // Given
- $KDE = new KernelDensityEstimation($data);
- $KDE->setBandwidth($h);
- // When
- $estimate = $KDE->evaluate($x);
- // Then
- $this->assertEqualsWithDelta($expected, $estimate, 0.0001);
- }
- /**
- * @return array [data, h, x, expected]
- */
- public function dataProviderForKernelDensityCustomH(): array
- {
- $h = count($this->data) ** (-1 / 6);
- return [
- [ $this->data, $h, 1, 0.237991168 ],
- [ $this->data, $h, .1, 0.40525027 ],
- [ $this->data, $h, -1, 0.232226496 ],
- ];
- }
- /**
- * @test Custom kernel function and custom h
- * @dataProvider dataProviderForKernelDensityCustomBoth
- * @param float $h
- * @param callable $kernel
- * @param float $x
- * @param float $expected
- */
- public function testDefaultKernelDensityCustomBoth(float $h, callable $kernel, float $x, float $expected)
- {
- // Given
- $KDE = new KernelDensityEstimation($this->data, $h, $kernel);
- $kernel2 = KernelDensityEstimation::TRICUBE;
- $KDE2 = new KernelDensityEstimation($this->data, $h, $kernel2);
- // When
- $estimate1 = $KDE->evaluate($x);
- $estimate2 = $KDE2->evaluate($x);
- // Then
- $this->assertEqualsWithDelta($expected, $estimate1, 0.0001);
- $this->assertEqualsWithDelta($expected, $estimate2, 0.0001);
- }
- /**
- * @return array [h, kernel, x, expected]
- */
- public function dataProviderForKernelDensityCustomBoth(): array
- {
- $h = 1;
- // Tricube
- $kernel = function ($x) {
- if (\abs($x) > 1) {
- return 0;
- } else {
- return 70 / 81 * ((1 - \abs($x) ** 3) ** 3);
- }
- };
- return [
- [ $h, $kernel, 1, 0.238712304 ],
- [ $h, $kernel, .1, 0.420794741 ],
- [ $h, $kernel, -1, 0.229056709 ],
- ];
- }
- /**
- * @test evaluate using optional kernel functions
- * @dataProvider dataProviderForTestKernels
- * @param string $kernel
- * @param float $x
- * @param float $expected
- */
- public function testKernels(string $kernel, float $x, float $expected)
- {
- // Given
- $KDE = new KernelDensityEstimation($this->data, 1, $kernel);
- // When
- $estimate = $KDE->evaluate($x);
- // Then
- $this->assertEqualsWithDelta($expected, $estimate, 0.0001);
- }
- /**
- * @return array [kernel, x, expected]
- */
- public function dataProviderForTestKernels(): array
- {
- return [
- [KernelDensityEstimation::UNIFORM, 1, .25],
- [KernelDensityEstimation::TRIANGULAR, 1, .235],
- [KernelDensityEstimation::EPANECHNIKOV, 1, .2401905],
- ];
- }
- /**
- * @test Kernel function NORMAL
- * Test data made with scipy.stats.gaussian_kde
- * @dataProvider dataProviderForNormalKde
- * @param float $x
- * @param float $expected
- */
- public function testNormal(float $x, float $expected)
- {
- // Given
- $KDE = new KernelDensityEstimation($this->data);
- $h = 0.3932;
- $KDE->setBandwidth($h);
- $KDE->setKernelFunction(KernelDensityEstimation::NORMAL);
- // When
- $estimate = $KDE->evaluate($x);
- // Then
- $this->assertEqualsWithDelta($expected, $estimate, 0.00001, "Evaluate x = $x");
- }
- /**
- * Test data made with scipy.stats.gaussian_kde
- * @return array (x, expected)
- */
- public function dataProviderForNormalKde(): array
- {
- return [
- [-3.939, 8.60829883e-05],
- [-2.222, 0.04138222],
- [-0.505, 0.36562621],
- [0, 0.43200043],
- [1.212, 0.19113825],
- [2.929, 9.09492454e-05],
- ];
- }
- /**
- * @test Invalid kernel throws an Exception
- */
- public function testBadKernel()
- {
- // Then
- $this->expectException(Exception\BadParameterException::class);
- // When
- $KDE = new KernelDensityEstimation($this->data, 1, 1.0);
- }
- /**
- * @test Unknown built-in kernel throws an Exception
- */
- public function testUnknownBuildInKernel()
- {
- // Given
- $KDE = new KernelDensityEstimation($this->data);
- // Then
- $this->expectException(Exception\BadDataException::class);
- // When
- $KDE->setKernelFunction('DoesNotExist');
- }
- /**
- * @test Invalid bandwidth throws an Exception
- */
- public function testBadSetBandwidth()
- {
- // Given
- $KDE = new KernelDensityEstimation($this->data);
- // Then
- $this->expectException(Exception\OutOfBoundsException::class);
- // When
- $KDE->setBandwidth(-1);
- }
- /**
- * @test Empty data throws an Exception
- */
- public function testEmptyData()
- {
- // Given
- $data = [];
- // Then
- $this->expectException(Exception\BadDataException::class);
- // When
- $KDE = new KernelDensityEstimation([]);
- }
- }
|