implement article affinity analysis

This commit is contained in:
Dennis Eichhorn 2020-06-14 14:54:43 +02:00
parent d556756283
commit 44d663d176
2 changed files with 181 additions and 0 deletions

View File

@ -0,0 +1,110 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package phpOMS\Business\Marketing
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\Business\Marketing;
use phpOMS\Math\Statistic\Correlation;
/**
* Marketing ArticleAffinity
*
* This class provided basic marketing metric calculations
*
* @package phpOMS\Business\Marketing
* @license OMS License 1.0
* @link https://orange-management.org
* @since 1.0.0
*/
final class ArticleCorrelationAffinity
{
/**
* Affinity between items
*
* @var array[]
* @since 1.0.0
*/
private array $affinity = [];
/**
* Item order behaviour (when are which items ordered)
*
* In tearms of the pearson correlation these are our random variables
*
* @var array
* @since 1.0.0
*/
private array $items = [];
/**
* Constructor
*
* @param array[] $orders Array of orders which contains as elements the items ordered in the respective order
* @param bool $considerQuantity NOT_IMPLEMENTED!!! Should the quantity be considered
*
* @since 1.0.0
*/
public function __construct(array $orders, bool $considerQuantity = false)
{
// find all possible items
$possibleItems = [];
foreach ($orders as $items) {
foreach ($items as $item => $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);
}
}

View File

@ -0,0 +1,71 @@
<?php
/**
* Orange Management
*
* PHP Version 7.4
*
* @package tests
* @copyright Dennis Eichhorn
* @license OMS License 1.0
* @version 1.0.0
* @link https://orange-management.org
*/
declare(strict_types=1);
namespace phpOMS\tests\Business\Marketing;
use phpOMS\Business\Marketing\ArticleCorrelationAffinity;
/**
* @testdox phpOMS\tests\Business\Marketing\ArticleCorrelationAffinityTest: Article affinity/correlation
*
* @internal
*/
class ArticleCorrelationAffinityTest extends \PHPUnit\Framework\TestCase
{
/**
* @testdox The highest affinities between articles purchased are calculated correctly
* @group framework
*/
public function testAffinity() : void
{
$orders = [
['A' => 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
);
}
}