continue impl. of distributions/stochastics/statistics

This commit is contained in:
Dennis Eichhorn 2020-05-04 22:39:21 +02:00
parent 131701195f
commit 4ec4e95819
10 changed files with 201 additions and 20 deletions

View File

@ -48,7 +48,7 @@ final class Correlation
*/ */
public static function bravaisPersonCorrelationCoefficient(array $x, array $y) : float public static function bravaisPersonCorrelationCoefficient(array $x, array $y) : float
{ {
return MeasureOfDispersion::empiricalCovariance($x, $y) / (MeasureOfDispersion::standardDeviation($x) * MeasureOfDispersion::standardDeviation($y)); return MeasureOfDispersion::empiricalCovariance($x, $y) / (MeasureOfDispersion::standardDeviationSample($x) * MeasureOfDispersion::standardDeviationSample($y));
} }
/** /**

View File

@ -79,11 +79,11 @@ final class MeasureOfDispersion
throw new ZeroDivisionException(); throw new ZeroDivisionException();
} }
return self::standardDeviation($values) / $mean; return self::standardDeviationSample($values) / $mean;
} }
/** /**
* Calculage standard deviation. * Calculate standard deviation of sample.
* *
* Example: ([4, 5, 9, 1, 3]) * Example: ([4, 5, 9, 1, 3])
* *
@ -96,7 +96,7 @@ final class MeasureOfDispersion
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function standardDeviation(array $values, float $mean = null) : float public static function standardDeviationSample(array $values, float $mean = null) : float
{ {
$mean = $mean !== null ? $mean : Average::arithmeticMean($values); $mean = $mean !== null ? $mean : Average::arithmeticMean($values);
$sum = 0.0; $sum = 0.0;
@ -108,6 +108,32 @@ final class MeasureOfDispersion
return \sqrt($sum / (\count($values) - 1)); return \sqrt($sum / (\count($values) - 1));
} }
/**
* Calculate standard deviation of entire population
*
* Example: ([4, 5, 9, 1, 3])
*
* @latex \sigma = \sqrt{\sigma^{2}} = \sqrt{Var(X)}
*
* @param array<int, int|float> $values Values
* @param float $mean Mean
*
* @return float
*
* @since 1.0.0
*/
public static function standardDeviationPopulation(array $values, float $mean = null) : float
{
$mean = $mean !== null ? $mean : Average::arithmeticMean($values);
$sum = 0.0;
foreach ($values as $value) {
$sum += ($value - $mean) ** 2;
}
return \sqrt($sum / \count($values));
}
/** /**
* Calculage sample variance. * Calculage sample variance.
* *

View File

@ -139,4 +139,24 @@ final class HypergeometricDistribution
return (($N - 1) * $N ** 2 * ($N * ($N + 1) - 6 * $K * ($N - $K) - 6 * $n * ($N - $n)) + 6 * $n * $K * ($N - $K) * ($N - $n) * (5 * $N - 6)) return (($N - 1) * $N ** 2 * ($N * ($N + 1) - 6 * $K * ($N - $K) - 6 * $n * ($N - $n)) + 6 * $n * $K * ($N - $K) * ($N - $n) * (5 * $N - 6))
/ ($n * $K * ($N - $K) * ($N - $n) * ($N - 2) * ($N - 3)); / ($n * $K * ($N - $K) * ($N - $n) * ($N - 2) * ($N - 3));
} }
/**
* Hypergeometric-Distribution
*
* @param int $sampleSuccesses Amount of sample successes
* @param int $samples Sample size
* @param int $populationSuccesses Amount of population successes
* @param int $population Population size
*
* @return float
*
* @since 1.0.0
*/
public static function dist(int $sampleSuccesses, int $samples, int $populationSuccesses, int $population) : float
{
// Each multiplication calculates the total amount of possible group combinations based on a total amount of items.
return (int) (\round(Functions::fact($populationSuccesses) / Functions::fact($populationSuccesses - $sampleSuccesses)) / Functions::fact($sampleSuccesses)
* \round(Functions::fact($population - $populationSuccesses) / Functions::fact($population - $populationSuccesses - ($samples - $sampleSuccesses))) / Functions::fact($samples - $sampleSuccesses)
* \round(Functions::fact($population) / Functions::fact($population - $samples)) / Functions::fact($samples));
}
} }

View File

@ -173,4 +173,20 @@ final class LogNormalDistribution
[0, 1 / (2 * $sigma ** 2)], [0, 1 / (2 * $sigma ** 2)],
]; ];
} }
/**
* Log-Normal-Distribution
*
* @param float $value Value
* @param float $mean Mean
* @param float $standardDeviation Standard deviation
*
* @return float
*
* @since 1.0.0
*/
public static function dist(float $value, float $mean, float $standardDeviation) : float
{
return NormalDistribution::dist((\log($value) - $mean) / $standardDeviation, 0.0, 1.0, true);
}
} }

View File

@ -14,6 +14,8 @@ declare(strict_types=1);
namespace phpOMS\Math\Stochastic\Distribution; namespace phpOMS\Math\Stochastic\Distribution;
use phpOMS\Math\Functions\Functions;
/** /**
* Normal distribution. * Normal distribution.
* *
@ -109,6 +111,8 @@ final class NormalDistribution
* *
* @return float * @return float
* *
* @todo: compare with Functions::getErf($x);
*
* @since 1.0.0 * @since 1.0.0
*/ */
private static function erf(float $x) : float private static function erf(float $x) : float
@ -245,4 +249,23 @@ final class NormalDistribution
{ {
return 0; return 0;
} }
/**
* Normal-Distribution
*
* @param float $value Value
* @param float $mean Mean
* @param float $standardDeviation Standard deviation
* @param bool $isCumulative Cumulative
*
* @return float
*
* @since 1.0.0
*/
public static function dist(float $value, float $mean, float $standardDeviation, bool $isCumulative = true) : float
{
return $isCumulative
? 0.5 * (1 + Functions::getErf(($value - $mean) / $standardDeviation * \sqrt(2)))
: 1 / (\sqrt(2 * \M_PI) * $standardDeviation) * \exp (-\pow($value - $mean, 2) / (2 * $standardDeviation * $standardDeviation));
}
} }

View File

@ -191,4 +191,31 @@ final class PoissonDistribution
{ {
return \pow($lambda, -1); return \pow($lambda, -1);
} }
/**
* Poisson-Distribution
*
* @param float $value Value
* @param float $mean Mean
* @param bool $isCumulative Cumulative
*
* @return float
*
* @since 1.0.0
*/
public static function dist(float $value, float $mean, bool $isCumulative = true) : float
{
if (!$isCumulative) {
return \exp(-$mean) * \pow($mean, $value) / Functions::fact((int) \floor($value));
}
$sum = 0.0;
$limit = \floor($value);
for ($i = 0; $i <= $limit; ++$i) {
$sum += \pow($mean, $i) / Functions::fact($i);
}
return \exp(-$mean) * $sum;
}
} }

View File

@ -159,4 +159,57 @@ final class TDistribution
{ {
return $nu < 5 && $nu > 2 ? \PHP_FLOAT_MAX : 6 / ($nu - 4); return $nu < 5 && $nu > 2 ? \PHP_FLOAT_MAX : 6 / ($nu - 4);
} }
/**
* T-Distribution
*
* @param float $value Value
* @param int $degrees Degrees of freedom
* @param int $tails Tails (1 or 2)
*
* @return float
*
* @since 1.0.0
*/
public static function dist(float $value, int $degrees, int $tails = 2) : float
{
if ($value < 0.0 || $degrees < 1 || $tails < 1 || $tails > 2) {
return 0.0;
}
/**
* "AS 3" by B E Cooper of the Atlas Computer Laboratory
* Ellis Horwood Ltd.; W. Sussex, England
*/
$term = $degrees;
$theta = \atan2($value, \sqrt($term));
$cos = \cos($theta);
$sin = \sin($theta);
$sum = 0.0;
if ($degrees % 2 === 1) {
$i = 3;
$term = $cos;
} else {
$i = 2;
$term = 1;
}
$sum = $term;
while ($i < $degrees) {
$term *= $cos ** 2 * ($i - 1) / $i;
$sum += $term;
$i += 2;
}
$sum *= $sin;
if ($degrees % 2 === 1) {
$sum = 2 / M_PI * ($sum + $theta);
}
$t = 0.5 * (1 + $sum);
return $tails === 1 ? 1 - \abs($t) : 1 - \abs(1 - $t - $t);
}
} }

View File

@ -101,4 +101,23 @@ final class WeibullDistribution
return $gamma * (1 - 1 / $k) + \log($lambda / $k) + 1; return $gamma * (1 - 1 / $k) + \log($lambda / $k) + 1;
} }
/**
* Weibull-Distribution
*
* @param float $value Value
* @param float $alpha Alpha
* @param float $beta Beta
* @param bool $isCumulative Cumulative
*
* @return float
*
* @since 1.0.0
*/
public static function dist(float $value, float $alpha, float $beta, bool $isCumulative = true) : float
{
return $isCumulative
? 1 - \exp(-\pow($value / $beta, $alpha))
: $alpha / \pow($beta, $alpha) * \pow($value, $alpha - 1) * \exp(-\pow($value / $beta, $alpha));
}
} }

View File

@ -14,6 +14,9 @@ declare(strict_types=1);
namespace phpOMS\Math\Stochastic\Distribution; namespace phpOMS\Math\Stochastic\Distribution;
use phpOMS\Math\Statistic\Average;
use phpOMS\Math\Statistic\MeasureOfDispersion;
/** /**
* ZTest * ZTest
* *
@ -38,26 +41,20 @@ final class ZTest
/** /**
* Test hypthesis. * Test hypthesis.
* *
* @param float $dataset Value observed * @param array $data Data
* @param float $expected Expected value * @param float $alpha Alpha / Observed dataset size
* @param float $total Observed dataset size * @param null|float $sigma Sigma / Significance
* @param float $significance Significance
* *
* @return bool * @return float
* *
* @since 1.0.0 * @since 1.0.0
*/ */
public static function testHypothesis(float $dataset, float $expected, float $total, float $significance = 0.95) : bool public static function testHypothesis(array $data, float $alpha, float $sigma = null) : float
{ {
$z = ($dataset - $expected) / \sqrt($expected * (1 - $expected) / $total); if ($sigma === null) {
return MeasureOfDispersion::standardDeviationSample($data);
$zSignificance = 0.0;
foreach (self::TABLE as $key => $value) {
if ($significance === $value) {
$zSignificance = (float) $key;
}
} }
return $z > -$key && $z < $key; return 1 - NormalDistribution::dist((Average::arithmeticMean($data) - $alpha) / ($sigma / \sqrt(\count($data))), 0.0, 1.0, true);
} }
} }

View File

@ -36,9 +36,9 @@ class MeasureOfDispersionTest extends \PHPUnit\Framework\TestCase
* @testdox The standard deviation is correctly calculated * @testdox The standard deviation is correctly calculated
* @group framework * @group framework
*/ */
public function testStandardDeviation() : void public function testStandardDeviationSample() : void
{ {
self::assertEqualsWithDelta(2.160246, MeasureOfDispersion::standardDeviation([1, 2, 3, 4, 5, 6, 7]), 0.01); self::assertEqualsWithDelta(2.160246, MeasureOfDispersion::standardDeviationSample([1, 2, 3, 4, 5, 6, 7]), 0.01);
} }
/** /**