From 44d663d1768f7a05b14cf60bbe1652a934502f13 Mon Sep 17 00:00:00 2001 From: Dennis Eichhorn Date: Sun, 14 Jun 2020 14:54:43 +0200 Subject: [PATCH] implement article affinity analysis --- .../Marketing/ArticleCorrelationAffinity.php | 110 ++++++++++++++++++ .../ArticleCorrelationAffinityTest.php | 71 +++++++++++ 2 files changed, 181 insertions(+) create mode 100644 Business/Marketing/ArticleCorrelationAffinity.php create mode 100644 tests/Business/Marketing/ArticleCorrelationAffinityTest.php diff --git a/Business/Marketing/ArticleCorrelationAffinity.php b/Business/Marketing/ArticleCorrelationAffinity.php new file mode 100644 index 000000000..21e4d556c --- /dev/null +++ b/Business/Marketing/ArticleCorrelationAffinity.php @@ -0,0 +1,110 @@ + $quantity) { + if (!\in_array($item, $possibleItems)) { + $possibleItems[] = $item; + } + } + } + + // create the random variables + foreach ($orders as $items) { + foreach ($possibleItems as $item) { + $this->items[$item][] = $items[$item]; + } + } + + // create the affinity table + foreach ($possibleItems as $item1) { + foreach ($possibleItems as $item2) { + if ($item1 !== $item2 &&!isset($this->affinity[$item1][$item2]) && !isset($this->affinity[$item2][$item1])) { + $this->affinity[$item1][$item2] = Correlation::bravaisPersonCorrelationCoefficientPopulation($this->items[$item1], $this->items[$item2]); + $this->affinity[$item2][$item1] = $this->affinity[$item1][$item2]; + } + } + } + + // sort correlations + foreach ($possibleItems as $item) { + \arsort($this->affinity[$item]); + } + } + + /** + * Get the affinity between items + * + * @param mixed $item Item to check for possible affinities + * @param int $resultSize How many top matches should be returned + * + * @return array + * + * @since 1.0.0 + */ + public function getAffinity($item, int $resultSize = 0) : array + { + if (!isset($this->affinity[$item])) { + return []; + } + + return $resultSize < 1 ? $this->affinity[$item] : \array_slice($this->affinity[$item], 0, $resultSize); + } +} diff --git a/tests/Business/Marketing/ArticleCorrelationAffinityTest.php b/tests/Business/Marketing/ArticleCorrelationAffinityTest.php new file mode 100644 index 000000000..9f53e484a --- /dev/null +++ b/tests/Business/Marketing/ArticleCorrelationAffinityTest.php @@ -0,0 +1,71 @@ + 1, 'B' => 1, 'C' => 0, 'D' => 0], + ['A' => 0, 'B' => 1, 'C' => 0, 'D' => 0], + ['A' => 1, 'B' => 1, 'C' => 0, 'D' => 0], + ['A' => 1, 'B' => 0, 'C' => 0, 'D' => 1], + ['A' => 0, 'B' => 0, 'C' => 0, 'D' => 0], + ['A' => 1, 'B' => 1, 'C' => 0, 'D' => 0], + ['A' => 1, 'B' => 0, 'C' => 1, 'D' => 0], + ['A' => 0, 'B' => 0, 'C' => 1, 'D' => 0], + ['A' => 1, 'B' => 1, 'C' => 0, 'D' => 0], + ['A' => 1, 'B' => 1, 'C' => 0, 'D' => 0], + ['A' => 0, 'B' => 1, 'C' => 0, 'D' => 0], + ['A' => 0, 'B' => 1, 'C' => 0, 'D' => 0], + ['A' => 1, 'B' => 1, 'C' => 0, 'D' => 0], + ['A' => 0, 'B' => 0, 'C' => 0, 'D' => 0], + ['A' => 0, 'B' => 0, 'C' => 0, 'D' => 0], + ]; + + $aff = new ArticleCorrelationAffinity($orders); + + self::assertEqualsWithDelta( + [ + 'A' => 0.3273, + 'C' => -0.4803, + 'D' => -0.3273, + ], + $aff->getAffinity('B'), + 0.001 + ); + + self::assertEqualsWithDelta( + [ + 'A' => 0.3273, + 'D' => -0.3273, + ], + $aff->getAffinity('B', 2), + 0.001 + ); + } +}