diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index ab65b3e..ed67f43 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -9,10 +9,10 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest, windows-latest] - php: [8.1, 8.2, 8.3] + php: [8.1, 8.2, 8.3, 8.4] exclude: - os: windows-latest - php: [8.1, 8.3] + php: [8.1, 8.2, 8.4] name: P${{ matrix.php }} - ${{ matrix.os }} diff --git a/.github/workflows/static-code-analysis.yml b/.github/workflows/static-code-analysis.yml index bc4dd5a..7b5e41b 100644 --- a/.github/workflows/static-code-analysis.yml +++ b/.github/workflows/static-code-analysis.yml @@ -9,7 +9,7 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - php: [8.1] + php: [8.3] stability: [prefer-stable] name: P${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }} diff --git a/.phpunit.cache/test-results b/.phpunit.cache/test-results new file mode 100644 index 0000000..f430c79 --- /dev/null +++ b/.phpunit.cache/test-results @@ -0,0 +1 @@ +{"version":"pest_2.36.0","defects":[],"times":{"P\\Tests\\StatisticTest::__pest_evaluable_it_calculates_variance":0,"P\\Tests\\StatisticTest::__pest_evaluable_it_can_calculate_statistics_again":0.001,"P\\Tests\\StatisticTest::__pest_evaluable_it_can_distinct_numeric_array":0,"P\\Tests\\StatisticTest::__pest_evaluable_it_can_calculate_mean":0.001,"P\\Tests\\StatisticTest::__pest_evaluable_it_can_valuesToString":0,"P\\Tests\\StatisticTest::__pest_evaluable_it_calculates_geometric_mean":0.001,"P\\Tests\\StatisticTest::__pest_evaluable_it_can_calculate_statistics_again_and_again":0.001,"P\\Tests\\StatisticTest::__pest_evaluable_it_can_calculate_statistics":0.001,"P\\Tests\\StatisticTest::__pest_evaluable_it_calculates_pvariance":0,"P\\Tests\\StatisticTest::__pest_evaluable_it_can_calculate_mean_again":0,"P\\Tests\\StatisticTest::__pest_evaluable_it_calculates_Population_standard_deviation":0.001,"P\\Tests\\StatisticTest::__pest_evaluable_it_calculates_Sample_standard_deviation":0.001,"P\\Tests\\StatisticTest::__pest_evaluable_it_can_strip_zeros":0,"P\\Tests\\StatisticTest::__pest_evaluable_it_calculates_harmonic_mean":0,"P\\Tests\\ArchTest::__pest_evaluable_constructor":0,"P\\Tests\\ArchTest::__pest_evaluable_to_be_final":0.052,"P\\Tests\\ArchTest::__pest_evaluable_ensures_no_debugging":0.102,"P\\Tests\\ArchTest::__pest_evaluable_make":0.012,"P\\Tests\\FrequenciesTest::__pest_evaluable_it_can_calculate_cumulative_relative_frequencies":0,"P\\Tests\\FrequenciesTest::__pest_evaluable_it_can_calculate_thirdQuartile":0,"P\\Tests\\FrequenciesTest::__pest_evaluable_it_can_calculate_frequencies":0,"P\\Tests\\FrequenciesTest::__pest_evaluable_it_can_calculate_cumulative_frequencies":0,"P\\Tests\\FrequenciesTest::__pest_evaluable_it_can_calculate_relative_frequencies":0,"P\\Tests\\FrequenciesTest::__pest_evaluable_it_can_calculate_firstQuartile":0,"P\\Tests\\MathTest::__pest_evaluable_it_is_odd__static_":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Dynamic_operation_with_external_dataset#('median', [1, 3, 5], 3)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Dynamic_operation_with_external_dataset#('mean', [-1.0, 2.5, 3.25, \u2026], 2.625)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Dynamic_operation_with_external_dataset#('medianLow', [1, 3, 5, \u2026], 3)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Dynamic_operation_with_external_dataset#('median', [1, 3, 5, \u2026], 4)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Dynamic_operation_with_external_dataset#('mean', [1, 2, 3, \u2026], 2.8)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Dynamic_operation_with_external_dataset#('medianLow', [1, 3, 5], 3)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Mean":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Mean_dataset#([1, 2, 3, \u2026], 2.8)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Mean_dataset#([-1.0, 2.5, 3.25, \u2026], 2.625)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Dynamic_operation#('medianLow', [1, 3, 5, \u2026], 3)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Dynamic_operation#('medianLow', [1, 3, 5], 3)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Dynamic_operation#('mean', [-1.0, 2.5, 3.25, \u2026], 2.625)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Dynamic_operation#('median', [1, 3, 5], 3)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Dynamic_operation#('median', [1, 3, 5, \u2026], 4)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Dynamic_operation#('mean', [1, 2, 3, \u2026], 2.8)":0,"P\\Tests\\StatDatasetTest::__pest_evaluable__Calculating_Stat_operation__\u2192_it_Mean_chain_expect":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_mode__static_":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_Population_standard_deviation__static_":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_linear_regression__static_":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_correlation__wrong_usage__static_":0.001,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_linear_regression_with_not_valid_input__static_":0.001,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_Sample_standard_deviation__static_":0.001,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_first_quartiles__static_":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_geometric_mean__static_":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_multimode__static_":0.001,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_quantiles__static_":0.001,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_pvariance__static_":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_covariance__wrong_usage__static_":0.001,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_median_high__static_":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_median_low__static_":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_covariance__static_":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_mean__static_":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_correlation__static_":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_median__static_":0.001,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_variance__static_":0,"P\\Tests\\StatTest::__pest_evaluable_it_calculates_harmonic_mean__static_":0,"P\\Tests\\FreqTest::__pest_evaluable_it_can_calculate_grouped_frequency_table_by_size__static_":0.001,"P\\Tests\\FreqTest::__pest_evaluable_it_can_calculate_freq_table__static_":0.005,"P\\Tests\\FreqTest::__pest_evaluable_it_can_calculate_relativefreq_table__static_":0.001,"P\\Tests\\FreqTest::__pest_evaluable_it_can_calculate_grouped_frequency_table__static_":0.003,"P\\Tests\\StatFromCsvTest::__pest_evaluable_it_parse_CSV":0.043}} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c01de6..99be3b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 1.0.1 - 2024-11-21 + +- Welcome PHP 8.4 + ## 1.0.0 - 2023-12-26 - Fixed `median()` function to handle unsorted data by @keatis diff --git a/composer.json b/composer.json index af07cf3..605611a 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^8.1" + "php": "^8.1|^8.2|^8.3|^8.4" }, "require-dev": { "laravel/pint": "^1.13", diff --git a/examples/frequencies.php b/examples/frequencies.php index 84bc2ba..2bd77d4 100644 --- a/examples/frequencies.php +++ b/examples/frequencies.php @@ -29,7 +29,7 @@ */ $s = Statistics::make( - [98, 90, 70, 18, 92, 92, 55, 83, 45, 95, 88, 76] + [98, 90, 70, 18, 92, 92, 55, 83, 45, 95, 88, 76], ); $a = $s->frequencies(); print_r($a); diff --git a/examples/stat.php b/examples/stat.php index bf033d3..aef7524 100644 --- a/examples/stat.php +++ b/examples/stat.php @@ -6,11 +6,11 @@ use HiFolks\Statistics\Stat; $freq = Freq::frequencies( - ['red', 'blue', 'blue', 'red', 'green', 'red', 'red'] + ['red', 'blue', 'blue', 'red', 'green', 'red', 'red'], ); var_dump($freq); $mode = Stat::mode( - ['red', 'blue', 'blue', 'red', 'green', 'red', 'red'] + ['red', 'blue', 'blue', 'red', 'green', 'red', 'red'], ); var_dump($mode); diff --git a/examples/stat_methods.php b/examples/stat_methods.php index 5069f89..6da7125 100644 --- a/examples/stat_methods.php +++ b/examples/stat_methods.php @@ -38,7 +38,7 @@ // 1.3720238095238095 [$slope, $intercept] = Stat::linearRegression( [1971, 1975, 1979, 1982, 1983], - [1, 2, 3, 4, 5] + [1, 2, 3, 4, 5], ); // 0.31 // -610.18 diff --git a/src/Stat.php b/src/Stat.php index 1109ffd..279b075 100644 --- a/src/Stat.php +++ b/src/Stat.php @@ -41,6 +41,10 @@ public static function mean(array $data): int|float|null if (self::count($data) === 0) { throw new InvalidDataInputException('The data must not be empty.'); } + // @phpstan-ignore-next-line + if (!empty(array_filter($data, 'is_string'))) { + throw new InvalidDataInputException('The data array contains a string.'); + } $sum = array_sum($data); return $sum / self::count($data); @@ -70,7 +74,7 @@ public static function median(array $data, string $medianType = self::MEDIAN_TYP return match ($medianType) { self::MEDIAN_TYPE_LOW => ($data[$index - 1]), self::MEDIAN_TYPE_HIGH => $data[$index], - default => ($data[$index - 1] + $data[$index]) / 2 + default => ($data[$index - 1] + $data[$index]) / 2, }; } @@ -174,7 +178,7 @@ public static function quantiles(array $data, int $n = 4, ?int $round = null): a $count = self::count($data); if ($count < 2 || $n < 1) { throw new InvalidDataInputException( - 'The size of the data must be greater than 2 and the number of quantiles must be greater than 1.' + 'The size of the data must be greater than 2 and the number of quantiles must be greater than 1.', ); } @@ -393,12 +397,12 @@ public static function covariance(array $x, array $y): false|float $countY = count($y); if ($countX !== $countY) { throw new InvalidDataInputException( - 'Covariance requires that both inputs have same number of data points.' + 'Covariance requires that both inputs have same number of data points.', ); } if ($countX < 2) { throw new InvalidDataInputException( - 'Covariance requires at least two data points.' + 'Covariance requires at least two data points.', ); } $meanX = self::mean($x); @@ -409,13 +413,13 @@ public static function covariance(array $x, array $y): false|float $valueX = $x[$pos]; if (!is_numeric($valueX)) { throw new InvalidDataInputException( - 'Covariance requires numeric data points.' + 'Covariance requires numeric data points.', ); } $valueY = $y[$pos]; if (!is_numeric($valueY)) { throw new InvalidDataInputException( - 'Covariance requires numeric data points.' + 'Covariance requires numeric data points.', ); } $diffX = $valueX - $meanX; @@ -448,12 +452,12 @@ public static function correlation(array $x, array $y): false|float $countY = count($y); if ($countX !== $countY) { throw new InvalidDataInputException( - 'Correlation requires that both inputs have same number of data points.' + 'Correlation requires that both inputs have same number of data points.', ); } if ($countX < 2) { throw new InvalidDataInputException( - 'Correlation requires at least two data points.' + 'Correlation requires at least two data points.', ); } $meanX = self::mean($x); @@ -472,7 +476,7 @@ public static function correlation(array $x, array $y): false|float $b = sqrt($bx * $by); if ($b == 0) { throw new InvalidDataInputException( - 'Correlation, at least one of the inputs is constant.' + 'Correlation, at least one of the inputs is constant.', ); } @@ -494,12 +498,12 @@ public static function linearRegression(array $x, array $y): array $countY = count($y); if ($countX !== $countY) { throw new InvalidDataInputException( - 'Linear regression requires that both inputs have same number of data points.' + 'Linear regression requires that both inputs have same number of data points.', ); } if ($countX < 2) { throw new InvalidDataInputException( - 'Linear regression requires at least two data points.' + 'Linear regression requires at least two data points.', ); } $sumX = array_sum($x); @@ -514,7 +518,7 @@ public static function linearRegression(array $x, array $y): array $denominator = (($countX * $sumXX) - ($sumX * $sumX)); if ($denominator === 0) { throw new InvalidDataInputException( - 'Linear regression, the inputs is constant.' + 'Linear regression, the inputs is constant.', ); } $slope = (($countX * $sumXY) - ($sumX * $sumY)) / $denominator; diff --git a/src/Statistics.php b/src/Statistics.php index 4bbc4c5..e681cd4 100755 --- a/src/Statistics.php +++ b/src/Statistics.php @@ -29,7 +29,7 @@ class Statistics * @param array $values */ public function __construct( - array $values = [] + array $values = [], ) { $this->values = array_values($values); $this->originalArray = $values; diff --git a/tests/FreqTest.php b/tests/FreqTest.php index 7c31539..20ffc2f 100644 --- a/tests/FreqTest.php +++ b/tests/FreqTest.php @@ -4,69 +4,69 @@ it('can calculate freq table (static)', function () { expect( - Freq::frequencies([1, 2, 3, 4, 4]) + Freq::frequencies([1, 2, 3, 4, 4]), )->toMatchArray([4 => 2, 3 => 1, 1 => 1, 2 => 1]); expect( - Freq::frequencies([]) + Freq::frequencies([]), )->toMatchArray([]); $result = Freq::frequencies(['red', 'blue', 'blue', 'red', 'green', 'red', 'red']); expect( - $result + $result, )->toMatchArray(['red' => 4, 'blue' => 2, 'green' => 1]); expect( - $result + $result, )->toHaveCount(3); expect( - $result['red'] + $result['red'], )->toEqual(4); expect( - $result['blue'] + $result['blue'], )->toEqual(2); expect( - $result['green'] + $result['green'], )->toEqual(1); $result = Freq::frequencies([2.1, 2.7, 1.4, 2.45], true); expect( - $result + $result, )->toMatchArray([2 => 3, 1 => 1]); expect( - $result + $result, )->toHaveCount(2); }); it('can calculate relativefreq table (static)', function () { expect( - Freq::relativeFrequencies([1, 2, 3, 4, 4]) + Freq::relativeFrequencies([1, 2, 3, 4, 4]), )->toMatchArray([4 => 40, 3 => 20, 1 => 20, 2 => 20]); expect( - Freq::relativeFrequencies([]) + Freq::relativeFrequencies([]), )->toMatchArray([]); $result = Freq::relativeFrequencies(['red', 'blue', 'blue', 'red', 'green', 'red', 'red'], 2); expect( - $result + $result, )->toMatchArray(['red' => 57.14, 'blue' => 28.57, 'green' => 14.29]); expect( - $result + $result, )->toHaveCount(3); expect( - $result['red'] + $result['red'], )->toEqual(57.14); expect( - $result['blue'] + $result['blue'], )->toEqual(28.57); expect( - $result['green'] + $result['green'], )->toEqual(14.29); $result = Freq::relativeFrequencies([2.1, 2.7, 1.4, 2.45], true); expect( - $result + $result, )->toMatchArray([2 => 75, 1 => 25]); expect( - $result + $result, )->toHaveCount(2); }); @@ -75,54 +75,54 @@ 13, 14, 14, 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, ]; $table = Freq::frequencyTable($data, 7); expect( - $table + $table, )->toHaveCount(6); expect( - $table + $table, )->toMatchArray([1 => 3, 4 => 6, 7 => 10, 10 => 5, 13 => 5, 16 => 9]); expect( - array_sum($table) + array_sum($table), )->toEqual(count($data)); $table = Freq::frequencyTable($data, 6); expect( - $table + $table, )->toHaveCount(6); expect( - $table + $table, )->toMatchArray([1 => 3, 4 => 6, 7 => 10, 10 => 5, 13 => 5, 16 => 9]); expect( - array_sum($table) + array_sum($table), )->toEqual(count($data)); $table = Freq::frequencyTable($data, 8); expect( - $table + $table, )->toHaveCount(6); expect( - $table + $table, )->toMatchArray([1 => 3, 4 => 6, 7 => 10, 10 => 5, 13 => 5, 16 => 9]); expect( - array_sum($table) + array_sum($table), )->toEqual(count($data)); $table = Freq::frequencyTable($data, 3); expect( - $table + $table, )->toHaveCount(3); expect( - $table + $table, )->toMatchArray([1 => 9, 7 => 15, 13 => 14]); expect( - array_sum($table) + array_sum($table), )->toEqual(count($data)); $table = Freq::frequencyTable($data); expect( - $table + $table, )->toHaveCount(18); expect( - $table + $table, )->toMatchArray([1 => 3, 2 => 0, 3 => 0, 4 => 2, 5 => 3, 6 => 1, 7 => 1, 8 => 3, 9 => 6, 10 => 2, 11 => 1, 12 => 2, 13 => 1, 14 => 2, 15 => 2, 16 => 4, 17 => 3, 18 => 2, ]); }); @@ -132,34 +132,34 @@ 13, 14, 14, 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, ]; $table = Freq::frequencyTableBySize($data, 4); expect( - $table + $table, )->toHaveCount(5); expect( - $table + $table, )->toMatchArray([1 => 5, 5 => 8, 9 => 11, 13 => 9, 17 => 5]); expect( - array_sum($table) + array_sum($table), )->toEqual(count($data)); $table = Freq::frequencyTableBySize($data, 5); expect( - $table + $table, )->toHaveCount(4); expect( - $table + $table, )->toMatchArray([1 => 8, 6 => 13, 11 => 8, 16 => 9]); expect( - array_sum($table) + array_sum($table), )->toEqual(count($data)); $table = Freq::frequencyTableBySize($data, 8); expect( - $table + $table, )->toHaveCount(3); expect( - $table + $table, )->toMatchArray([1 => 13, 9 => 20, 17 => 5]); expect( - array_sum($table) + array_sum($table), )->toEqual(count($data)); }); diff --git a/tests/FrequenciesTest.php b/tests/FrequenciesTest.php index 3c63542..cd131a8 100644 --- a/tests/FrequenciesTest.php +++ b/tests/FrequenciesTest.php @@ -5,7 +5,7 @@ it('can calculate frequencies', function () { $s = Statistics::make( - [98, 90, 70, 18, 92, 92, 55, 83, 45, 95, 88, 76] + [98, 90, 70, 18, 92, 92, 55, 83, 45, 95, 88, 76], ); $a = $s->frequencies(); expect($a[92])->toEqual(2); @@ -14,7 +14,7 @@ it('can calculate relative frequencies', function () { $s = Statistics::make( - [3, 4, 3, 1] + [3, 4, 3, 1], ); $a = $s->relativeFrequencies(); expect($a[3])->toEqual(50); @@ -24,7 +24,7 @@ it('can calculate cumulative frequencies', function () { $s = Statistics::make( - [3, 4, 3, 1] + [3, 4, 3, 1], ); $a = $s->cumulativeFrequencies(); @@ -35,7 +35,7 @@ it('can calculate cumulative relative frequencies', function () { $s = Statistics::make( - [3, 4, 3, 1] + [3, 4, 3, 1], ); $a = $s->cumulativeRelativeFrequencies(); @@ -46,37 +46,37 @@ it('can calculate firstQuartile', function () { $s = Statistics::make( - [3, 4, 3, 1] + [3, 4, 3, 1], ); $a = $s->firstQuartile(); expect($a)->toEqual(1.5); $s = Statistics::make( - [3, 4, 3] + [3, 4, 3], ); $a = $s->firstQuartile(); expect($a)->toEqual(3); $s = Statistics::make( - [] + [], ); expect(fn() => $s->firstQuartile())->toThrow(InvalidDataInputException::class); }); it('can calculate thirdQuartile', function () { $s = Statistics::make( - [3, 4, 3, 1] + [3, 4, 3, 1], ); $a = $s->thirdQuartile(); expect($a)->toEqual(3.75); $s = Statistics::make( - [3, 4, 3] + [3, 4, 3], ); $a = $s->thirdQuartile(); expect($a)->toEqual(4); $s = Statistics::make( - [] + [], ); expect(fn() => $s->thirdQuartile())->toThrow(InvalidDataInputException::class); }); diff --git a/tests/StatDatasetTest.php b/tests/StatDatasetTest.php index 4cd1572..dafd159 100644 --- a/tests/StatDatasetTest.php +++ b/tests/StatDatasetTest.php @@ -35,11 +35,11 @@ it('Dynamic operation with external dataset', function (string $methodName, array $input, float $result) { expect( - call_user_func("HiFolks\Statistics\Stat::" . $methodName, $input) + call_user_func("HiFolks\Statistics\Stat::" . $methodName, $input), )->toEqual($result); expect( - call_user_func([Stat::class, $methodName], $input) + call_user_func([Stat::class, $methodName], $input), )->toEqual($result); })->with('input1'); }); diff --git a/tests/StatTest.php b/tests/StatTest.php index 5b182df..2caa878 100644 --- a/tests/StatTest.php +++ b/tests/StatTest.php @@ -5,190 +5,190 @@ it('calculates mean (static)', function () { expect( - Stat::mean([1, 2, 3, 4, 4]) + Stat::mean([1, 2, 3, 4, 4]), )->toEqual(2.8); expect( - Stat::mean([-1.0, 2.5, 3.25, 5.75]) + Stat::mean([-1.0, 2.5, 3.25, 5.75]), )->toEqual(2.625); expect( - fn() => Stat::mean([]) + fn() => Stat::mean([]), )->toThrow(InvalidDataInputException::class); }); it('calculates median (static)', function () { expect( - Stat::median([1, 3, 5]) + Stat::median([1, 3, 5]), )->toEqual(3); expect( - Stat::median([1, 3, 5, 7]) + Stat::median([1, 3, 5, 7]), )->toEqual(4); expect( - Stat::median([1001, 999, 998, 1001, 1002]) + Stat::median([1001, 999, 998, 1001, 1002]), )->toEqual(1001); expect( - Stat::median([1001, 999, 998, 1003, 1002, 1003]) + Stat::median([1001, 999, 998, 1003, 1002, 1003]), )->toEqual(1001.5); expect( - Stat::median([1, 3, 5, 7, 9, 11, 13]) + Stat::median([1, 3, 5, 7, 9, 11, 13]), )->toEqual(7); expect( - Stat::median([1, 3, 5, 7, 9, 11]) + Stat::median([1, 3, 5, 7, 9, 11]), )->toEqual(6); expect( - Stat::median([-11, 5.5, -3.4, 7.1, -9, 22]) + Stat::median([-11, 5.5, -3.4, 7.1, -9, 22]), )->toEqual(1.05); expect( - Stat::median([-1, -2, -3, -4, 4, 3, 2, 1]) + Stat::median([-1, -2, -3, -4, 4, 3, 2, 1]), )->toEqual(0); expect( - fn() => Stat::median([]) + fn() => Stat::median([]), )->toThrow(InvalidDataInputException::class); }); it('calculates median low (static)', function () { expect( - Stat::medianLow([1, 3, 5]) + Stat::medianLow([1, 3, 5]), )->toEqual(3); expect( - Stat::medianLow([1, 3, 5, 7]) + Stat::medianLow([1, 3, 5, 7]), )->toEqual(3); expect( - Stat::medianLow([1001, 999, 998, 1003, 1002, 1003]) + Stat::medianLow([1001, 999, 998, 1003, 1002, 1003]), )->toEqual(1001); expect( - fn() => Stat::medianLow([]) + fn() => Stat::medianLow([]), )->toThrow(InvalidDataInputException::class); }); it('calculates median high (static)', function () { expect( - Stat::medianHigh([1, 3, 5]) + Stat::medianHigh([1, 3, 5]), )->toEqual(3); expect( - Stat::medianHigh([1, 3, 5, 7]) + Stat::medianHigh([1, 3, 5, 7]), )->toEqual(5); expect( - Stat::medianHigh([1001, 999, 998, 1003, 1002, 1003]) + Stat::medianHigh([1001, 999, 998, 1003, 1002, 1003]), )->toEqual(1002); expect( - fn() => Stat::medianHigh([]) + fn() => Stat::medianHigh([]), )->toThrow(InvalidDataInputException::class); }); it('calculates mode (static)', function () { expect( - Stat::mode([1, 1, 2, 3, 3, 3, 3, 4]) + Stat::mode([1, 1, 2, 3, 3, 3, 3, 4]), )->toEqual(3); expect( - fn() => Stat::mode([]) + fn() => Stat::mode([]), )->toThrow(InvalidDataInputException::class); expect( - Stat::mode([1, 2, 3]) + Stat::mode([1, 2, 3]), )->toBeNull(); expect( - Stat::mode(['red', 'blue', 'blue', 'red', 'green', 'red', 'red']) + Stat::mode(['red', 'blue', 'blue', 'red', 'green', 'red', 'red']), )->toEqual('red'); }); it('calculates multimode (static)', function () { expect( - Stat::multimode([1, 1, 2, 3, 3, 3, 3, 4]) + Stat::multimode([1, 1, 2, 3, 3, 3, 3, 4]), )->toMatchArray([3]); expect( - Stat::multimode([1, 1, 2, 3, 3, 3, 3, 1, 1, 4]) + Stat::multimode([1, 1, 2, 3, 3, 3, 3, 1, 1, 4]), )->toMatchArray([1, 3]); $result = Stat::multimode(str_split('aabbbbccddddeeffffgg')); expect( - $result + $result, )->toMatchArray(['b', 'd', 'f']); expect( - $result + $result, )->toHaveCount(3); expect( - $result[0] + $result[0], )->toEqual('b'); expect( - $result[1] + $result[1], )->toEqual('d'); expect( - $result[2] + $result[2], )->toEqual('f'); expect( - fn() => Stat::multimode([]) + fn() => Stat::multimode([]), )->toThrow(InvalidDataInputException::class); }); it('calculates Population standard deviation (static)', function () { expect( - Stat::pstdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75]) + Stat::pstdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75]), )->toEqual(0.986893273527251); expect( - Stat::pstdev([1, 2, 4, 5, 8], 4) + Stat::pstdev([1, 2, 4, 5, 8], 4), )->toEqual(2.4495); expect( - fn() => Stat::pstdev([]) + fn() => Stat::pstdev([]), )->toThrow(InvalidDataInputException::class); expect( - Stat::pstdev([1]) + Stat::pstdev([1]), )->toEqual(0); expect( - Stat::pstdev([1, 2, 3, 3], 7) + Stat::pstdev([1, 2, 3, 3], 7), )->toEqual(0.8291562); }); it('calculates Sample standard deviation (static)', function () { expect( - Stat::stdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75]) + Stat::stdev([1.5, 2.5, 2.5, 2.75, 3.25, 4.75]), )->toEqual(1.0810874155219827); expect( - Stat::stdev([1, 2, 2, 4, 6]) + Stat::stdev([1, 2, 2, 4, 6]), )->toEqual(2); expect( - Stat::stdev([1, 2, 4, 5, 8], 4) + Stat::stdev([1, 2, 4, 5, 8], 4), )->toEqual(2.7386); expect( - fn() => Stat::stdev([]) + fn() => Stat::stdev([]), )->toThrow(InvalidDataInputException::class); expect( - fn() => Stat::stdev([1]) + fn() => Stat::stdev([1]), )->toThrow(InvalidDataInputException::class); }); it('calculates variance (static)', function () { expect( - Stat::variance([2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]) + Stat::variance([2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5]), )->toEqual(1.3720238095238095); }); it('calculates pvariance (static)', function () { expect( - Stat::pvariance([0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25]) + Stat::pvariance([0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25]), )->toEqual(1.25); expect( - Stat::pvariance([1, 2, 3, 3]) + Stat::pvariance([1, 2, 3, 3]), )->toEqual(0.6875); }); it('calculates geometric mean (static)', function () { expect( - Stat::geometricMean([54, 24, 36], 2) + Stat::geometricMean([54, 24, 36], 2), )->toEqual(36); expect( - fn() => Stat::geometricMean([]) + fn() => Stat::geometricMean([]), )->toThrow(InvalidDataInputException::class); }); it('calculates harmonic mean (static)', function () { expect( - Stat::harmonicMean([40, 60], round:2) + Stat::harmonicMean([40, 60], round: 2), )->toEqual(48); expect( - Stat::harmonicMean([10, 100, 0, 1]) + Stat::harmonicMean([10, 100, 0, 1]), )->toEqual(0); expect( - Stat::harmonicMean([40, 60], [5, 30]) + Stat::harmonicMean([40, 60], [5, 30]), )->toEqual(56); expect( - Stat::harmonicMean([60, 40], [7, 3], 1) + Stat::harmonicMean([60, 40], [7, 3], 1), )->toEqual(52.2); expect( - fn() => Stat::harmonicMean([]) + fn() => Stat::harmonicMean([]), )->toThrow(InvalidDataInputException::class); }); @@ -210,10 +210,10 @@ expect($q[1])->toEqual(2); expect($q[2])->toEqual(4); expect( - fn() => Stat::quantiles([1]) + fn() => Stat::quantiles([1]), )->toThrow(InvalidDataInputException::class); expect( - fn() => Stat::quantiles([1, 2, 3], 0) + fn() => Stat::quantiles([1, 2, 3], 0), )->toThrow(InvalidDataInputException::class); }); @@ -221,26 +221,26 @@ $q = Stat::firstQuartile([98, 90, 70, 18, 92, 92, 55, 83, 45, 95, 88, 76]); expect($q)->toEqual(58.75); expect( - fn() => Stat::firstQuartile([]) + fn() => Stat::firstQuartile([]), )->toThrow(InvalidDataInputException::class); }); it('calculates covariance (static)', function () { $covariance = Stat::covariance( [1, 2, 3, 4, 5, 6, 7, 8, 9], - [1, 2, 3, 1, 2, 3, 1, 2, 3] + [1, 2, 3, 1, 2, 3, 1, 2, 3], ); expect($covariance)->toEqual(0.75); $covariance = Stat::covariance( [9, 8, 7, 6, 5, 4, 3, 2, 1], - [1, 2, 3, 4, 5, 6, 7, 8, 9] + [1, 2, 3, 4, 5, 6, 7, 8, 9], ); expect($covariance)->toEqual(-7.5); $covariance = Stat::covariance( [1, 2, 3, 4, 5, 6, 7, 8, 9], - [9, 8, 7, 6, 5, 4, 3, 2, 1] + [9, 8, 7, 6, 5, 4, 3, 2, 1], ); expect($covariance)->toEqual(-7.5); }); @@ -249,64 +249,64 @@ expect( fn() => Stat::covariance( [9, 8, 7, 6, 5, 4, 3, 2, 1], - [1, 2, 3, 4, 5, 6, 7, 8] - ) + [1, 2, 3, 4, 5, 6, 7, 8], + ), )->toThrow(InvalidDataInputException::class); expect( fn() => Stat::covariance( [], - [] - ) + [], + ), )->toThrow(InvalidDataInputException::class); expect( fn() => Stat::covariance( [3], - [3] - ) + [3], + ), )->toThrow(InvalidDataInputException::class); expect( fn() => Stat::covariance( ['a', 1], - ['b', 2] - ) + ['b', 2], + ), )->toThrow(InvalidDataInputException::class); expect( fn() => Stat::covariance( [3, 1], - ['b', 2] - ) + ['b', 2], + ), )->toThrow(InvalidDataInputException::class); }); it('calculates correlation (static)', function () { $correlation = Stat::correlation( [1, 2, 3, 4, 5, 6, 7, 8, 9], - [1, 2, 3, 4, 5, 6, 7, 8, 9] + [1, 2, 3, 4, 5, 6, 7, 8, 9], ); expect($correlation)->toBeFloat(); expect($correlation)->toEqual(1); $correlation = Stat::correlation( [1, 2, 3, 4, 5, 6, 7, 8, 9], - [9, 8, 7, 6, 5, 4, 3, 2, 1] + [9, 8, 7, 6, 5, 4, 3, 2, 1], ); expect($correlation)->toBeFloat(); expect($correlation)->toEqual(-1); $correlation = Stat::correlation( [3, 6, 9], - [70, 75, 80] + [70, 75, 80], ); expect($correlation)->toBeFloat(); expect($correlation)->toEqual(1); $correlation = Stat::correlation( [20, 23, 8, 29, 14, 11, 11, 20, 17, 17], - [30, 35, 21, 33, 33, 26, 22, 31, 33, 36] + [30, 35, 21, 33, 33, 26, 22, 31, 33, 36], ); expect($correlation)->toBeFloat(); expect($correlation)->toEqual(0.71); @@ -316,36 +316,36 @@ expect( fn() => Stat::correlation( [9, 8, 7, 6, 5, 4, 3, 2, 1], - [1, 2, 3, 4, 5, 6, 7, 8] - ) + [1, 2, 3, 4, 5, 6, 7, 8], + ), )->toThrow(InvalidDataInputException::class); expect( fn() => Stat::correlation( [], - [] - ) + [], + ), )->toThrow(InvalidDataInputException::class); expect( fn() => Stat::correlation( [3], - [3] - ) + [3], + ), )->toThrow(InvalidDataInputException::class); expect( fn() => Stat::correlation( [3, 1, 2], - [2, 2, 2] - ) + [2, 2, 2], + ), )->toThrow(InvalidDataInputException::class); }); it('calculates linear regression (static)', function () { [$slope, $intercept] = Stat::linearRegression( [1971, 1975, 1979, 1982, 1983], - [1, 2, 3, 4, 5] + [1, 2, 3, 4, 5], ); expect($slope)->toBeFloat(); expect($slope)->toEqual(0.31); @@ -355,7 +355,7 @@ [$slope, $intercept] = Stat::linearRegression( [1971, 1975, 1979, 1982, 1983], - [1, 2, 1, 3, 1] + [1, 2, 1, 3, 1], ); expect($slope)->toBeFloat(); expect($slope)->toEqual(0.05); @@ -370,21 +370,21 @@ expect( fn() => Stat::linearRegression( [3], - [2] - ) + [2], + ), )->toThrow(InvalidDataInputException::class); expect( fn() => Stat::linearRegression( [3, 3, 3, 3], - [2, 1, 1, 1, 1] - ) + [2, 1, 1, 1, 1], + ), )->toThrow(InvalidDataInputException::class); expect( fn() => Stat::linearRegression( [3, 3, 3, 3, 3], - [1, 1, 1, 1, 1] - ) + [1, 1, 1, 1, 1], + ), )->toThrow(InvalidDataInputException::class); }); diff --git a/tests/StatisticTest.php b/tests/StatisticTest.php index 28bee76..50c9dc3 100644 --- a/tests/StatisticTest.php +++ b/tests/StatisticTest.php @@ -5,7 +5,7 @@ it('can calculate statistics', function (): void { $s = Statistics::make( - [98, 90, 70, 18, 92, 92, 55, 83, 45, 95, 88, 76] + [98, 90, 70, 18, 92, 92, 55, 83, 45, 95, 88, 76], ); expect($s->count())->toEqual(12); expect($s->median())->toEqual(85.5); @@ -16,7 +16,7 @@ expect($s->originalArray())->toHaveCount(12); $s = Statistics::make( - [98, 90, 70, 18, 92, 92, 55, 83, 45, 95, 88] + [98, 90, 70, 18, 92, 92, 55, 83, 45, 95, 88], ); expect($s->count())->toEqual(11); expect($s->median())->toEqual(88); @@ -29,7 +29,7 @@ it('can calculate statistics again', function (): void { // https://www.youtube.com/watch?v=6z7B7ADL6Lw&ab_channel=TheMathsProf $s = Statistics::make( - [3, 5, 4, 7, 5, 2] + [3, 5, 4, 7, 5, 2], ); expect($s->count())->toEqual(6); expect($s->mean())->toEqual(13 / 3); @@ -45,7 +45,7 @@ it('can calculate statistics again and again', function (): void { // https://www.purplemath.com/modules/meanmode.htm $s = Statistics::make( - [13, 18, 13, 14, 13, 16, 14, 21, 13] + [13, 18, 13, 14, 13, 16, 14, 21, 13], ); expect($s->count())->toEqual(9); expect($s->mean())->toEqual(15); @@ -58,7 +58,7 @@ expect($s->thirdQuartile())->toEqual(17); $s = Statistics::make( - [1, 2, 4, 7] + [1, 2, 4, 7], ); expect($s->count())->toEqual(4); expect($s->mean())->toEqual(3.5); @@ -71,18 +71,18 @@ it('can strip zeros', function (): void { // https://www.youtube.com/watch?v=6z7B7ADL6Lw&ab_channel=TheMathsProf $s = Statistics::make( - [3, 5, 0, 0.1, 4, 7, 5, 2] + [3, 5, 0, 0.1, 4, 7, 5, 2], )->stripZeroes(); expect($s->count())->toEqual(7); }); it('can calculate mean', function (): void { // https://www.youtube.com/watch?v=6z7B7ADL6Lw&ab_channel=TheMathsProf $s = Statistics::make( - [3, 5, 4, 7, 5, 2] + [3, 5, 4, 7, 5, 2], ); expect($s->count())->toEqual(6); expect($s->mean())->toEqual(13 / 3); $s = Statistics::make( - [] + [], ); expect($s->count())->toEqual(0); expect(fn(): float|int|null => $s->mean())->toThrow(InvalidDataInputException::class); @@ -90,29 +90,29 @@ it('can calculate mean again', function (): void { // https://docs.python.org/3/library/statistics.html#statistics.mean $s = Statistics::make( - [1, 2, 3, 4, 4] + [1, 2, 3, 4, 4], ); expect($s->mean())->toEqual(2.8); $s = Statistics::make( - [-1.0, 2.5, 3.25, 5.75] + [-1.0, 2.5, 3.25, 5.75], ); expect($s->mean())->toEqual(2.625); $s = Statistics::make( - [0.5, 0.75, 0.625, 0.375] + [0.5, 0.75, 0.625, 0.375], ); expect($s->mean())->toEqual(0.5625); $s = Statistics::make( - [3.5, 4.0, 5.25] + [3.5, 4.0, 5.25], ); expect($s->mean())->toEqual(4.25); }); it('can valuesToString', function (): void { $s = Statistics::make( - [1, 2, 3, 4, 4] + [1, 2, 3, 4, 4], ); expect($s->valuesToString(false))->toEqual('1,2,3,4,4'); expect($s->valuesToString(3))->toEqual('1,2,3'); @@ -121,73 +121,73 @@ it('calculates Population standard deviation', function (): void { expect( Statistics::make( - [1.5, 2.5, 2.5, 2.75, 3.25, 4.75] - )->pstdev() + [1.5, 2.5, 2.5, 2.75, 3.25, 4.75], + )->pstdev(), )->toEqual(0.986893273527251); expect( - Statistics::make([1, 2, 4, 5, 8])->pstdev(4) + Statistics::make([1, 2, 4, 5, 8])->pstdev(4), )->toEqual(2.4495); expect( - fn(): float => Statistics::make([])->pstdev() + fn(): float => Statistics::make([])->pstdev(), )->toThrow(InvalidDataInputException::class); expect( - Statistics::make([1])->pstdev() + Statistics::make([1])->pstdev(), )->toEqual(0); expect( - Statistics::make([1, 2, 3, 3])->pstdev(7) + Statistics::make([1, 2, 3, 3])->pstdev(7), )->toEqual(0.8291562); }); it('calculates Sample standard deviation', function (): void { expect( - Statistics::make([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])->stdev() + Statistics::make([1.5, 2.5, 2.5, 2.75, 3.25, 4.75])->stdev(), )->toEqual(1.0810874155219827); expect( - Statistics::make([1, 2, 2, 4, 6])->stdev() + Statistics::make([1, 2, 2, 4, 6])->stdev(), )->toEqual(2); expect( - Statistics::make([1, 2, 4, 5, 8])->stdev(4) + Statistics::make([1, 2, 4, 5, 8])->stdev(4), )->toEqual(2.7386); expect( - fn(): float => Statistics::make([])->stdev() + fn(): float => Statistics::make([])->stdev(), )->toThrow(InvalidDataInputException::class); expect( - fn(): float => Statistics::make([1])->stdev() + fn(): float => Statistics::make([1])->stdev(), )->toThrow(InvalidDataInputException::class); }); it('calculates variance', function (): void { expect( - Statistics::make([2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5])->variance() + Statistics::make([2.75, 1.75, 1.25, 0.25, 0.5, 1.25, 3.5])->variance(), )->toEqual(1.3720238095238095); }); it('calculates pvariance', function (): void { expect( - Statistics::make([0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25])->pvariance() + Statistics::make([0.0, 0.25, 0.25, 1.25, 1.5, 1.75, 2.75, 3.25])->pvariance(), )->toEqual(1.25); expect( - Statistics::make([1, 2, 3, 3])->pvariance() + Statistics::make([1, 2, 3, 3])->pvariance(), )->toEqual(0.6875); }); it('calculates geometric mean', function (): void { expect( - Statistics::make([54, 24, 36])->geometricMean(2) + Statistics::make([54, 24, 36])->geometricMean(2), )->toEqual(36); expect( - Statistics::make([4, 8, 3, 9, 17])->geometricMean(2) + Statistics::make([4, 8, 3, 9, 17])->geometricMean(2), )->toEqual(6.81); expect( - fn(): float => Statistics::make([])->geometricMean() + fn(): float => Statistics::make([])->geometricMean(), )->toThrow(InvalidDataInputException::class); }); it('calculates harmonic mean', function (): void { expect( - Statistics::make([40, 60])->harmonicMean(1) + Statistics::make([40, 60])->harmonicMean(1), )->toEqual(48.0); expect( - fn(): float => Statistics::make([])->harmonicMean() + fn(): float => Statistics::make([])->harmonicMean(), )->toThrow(InvalidDataInputException::class); });