mirror of
https://github.com/Karaka-Management/phpOMS.git
synced 2026-01-20 13:28:42 +00:00
implemented pagerank algorithm
This commit is contained in:
parent
9947c203fb
commit
ad2634e32a
133
Business/Marketing/PageRank.php
Normal file
133
Business/Marketing/PageRank.php
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
<?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;
|
||||
|
||||
/**
|
||||
* PageRank algorithm
|
||||
*
|
||||
* @package phpOMS\Business\Marketing
|
||||
* @license OMS License 1.0
|
||||
* @link https://orange-management.org
|
||||
* @since 1.0.0
|
||||
*/
|
||||
final class PageRank
|
||||
{
|
||||
/**
|
||||
* Damping value
|
||||
*
|
||||
* @var float
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private float $damping = 0.85;
|
||||
|
||||
/**
|
||||
* Page rank
|
||||
*
|
||||
* @var array<mixed, float>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $pageRanks = [];
|
||||
|
||||
/**
|
||||
* Relation array
|
||||
*
|
||||
* Array of elements where every element has an array of incoming links/relations
|
||||
*
|
||||
* @var array[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $relations = [];
|
||||
|
||||
/**
|
||||
* Amount of outgoing links from an element
|
||||
*
|
||||
* @var int[]
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private array $outgoing = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array[] $relations Relations between elements (keys => link from, array => link to)
|
||||
* @param bool $isUnique Only consider unique relations
|
||||
* @param float $damping Damping value
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct(array $relations, bool $isUnique = true, float $damping = 0.85)
|
||||
{
|
||||
$this->damping = $damping;
|
||||
|
||||
foreach ($relations as $key => $relation) {
|
||||
$this->outgoing[$key] = \count($relation);
|
||||
|
||||
if (!isset($this->relations[$key])) {
|
||||
$this->relations[$key] = [];
|
||||
}
|
||||
|
||||
foreach ($relation as $linkTo) {
|
||||
if (!isset($this->relations[$linkTo])) {
|
||||
$this->relations[$linkTo] = [];
|
||||
}
|
||||
|
||||
if (!isset($this->outgoing[$linkTo])) {
|
||||
$this->outgoing[$linkTo] = 0;
|
||||
}
|
||||
|
||||
if (!$isUnique || !\in_array($key, $this->relations[$linkTo])) {
|
||||
$this->relations[$linkTo][] = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcualte the rank based on a start rank for the different elements
|
||||
*
|
||||
* A different start rank for different elements might make sense if the elements are not uniform from the very beginning
|
||||
*
|
||||
* @param int $iterations Algorithm iterations
|
||||
* @param null|array<mixed, float> $startRank Start rank for an element
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function calculateRanks(int $iterations = 20, array $startRank = null) : array
|
||||
{
|
||||
if ($startRank !== null) {
|
||||
$this->pageRanks = $startRank;
|
||||
} else {
|
||||
foreach ($this->relations as $key => $relation) {
|
||||
$this->pageRanks[$key] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $iterations; ++$i) {
|
||||
foreach ($this->relations as $key => $relation) {
|
||||
$PR = 0.0;
|
||||
|
||||
foreach ($relation as $linkFrom) {
|
||||
$PR += $this->pageRanks[$linkFrom] / $this->outgoing[$linkFrom];
|
||||
}
|
||||
|
||||
$this->pageRanks[$key] = 1 - $this->damping + $this->damping * $PR;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->pageRanks;
|
||||
}
|
||||
}
|
||||
77
tests/Business/Marketing/PageRankTest.php
Normal file
77
tests/Business/Marketing/PageRankTest.php
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<?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\PageRank;
|
||||
|
||||
/**
|
||||
* @testdox phpOMS\tests\Business\Marketing\PageRankTest: Page rank algorithm
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class PageRankTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
/**
|
||||
* @testdox Test the correctness of the page rank algorithm
|
||||
* @group framework
|
||||
*/
|
||||
public function testPageRank() : void
|
||||
{
|
||||
$relations = [
|
||||
'A' => ['B', 'C'],
|
||||
'B' => ['C'],
|
||||
'C' => ['A'],
|
||||
'D' => ['C'],
|
||||
];
|
||||
|
||||
$ranking = new PageRank($relations, true);
|
||||
|
||||
self::assertEqualsWithDelta(
|
||||
[
|
||||
'A' => 1.49,
|
||||
'B' => 0.78,
|
||||
'C' => 1.58,
|
||||
'D' => 0.15,
|
||||
],
|
||||
$ranking->calculateRanks(20, null),
|
||||
0.01
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testdox Test the correctness of the page rank algorithm with custom damping and starting values
|
||||
* @group framework
|
||||
*/
|
||||
public function testPageRankCustomDampingAndStart() : void
|
||||
{
|
||||
$relations = [
|
||||
'A' => ['B', 'C'],
|
||||
'B' => ['C'],
|
||||
'C' => ['A'],
|
||||
];
|
||||
|
||||
$ranking = new PageRank($relations, true, 0.5);
|
||||
|
||||
self::assertEqualsWithDelta(
|
||||
[
|
||||
'A' => 1.0769,
|
||||
'B' => 0.769,
|
||||
'C' => 1.1538,
|
||||
],
|
||||
$ranking->calculateRanks(20, ['A' => 1.0, 'B' => 1.0, 'C' => 1.0]),
|
||||
0.01
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user