Skip to content

Commit

Permalink
Added neighbourhood support (kNN)
Browse files Browse the repository at this point in the history
Refactored MockDataSet into own class, and added full critics array
  • Loading branch information
seliquity committed Nov 29, 2009
1 parent 5d214a5 commit 5262750
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 35 deletions.
5 changes: 5 additions & 0 deletions Interfaces/UserNeighbourhood.interface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php

interface UserNeighbourhood {
public function userNeighbourhood($userId);
}
44 changes: 44 additions & 0 deletions Neighbourhood/UserNeighbourhoodNN.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

require_once(dirname(__FILE__) . '/../Interfaces/UserNeighbourhood.interface.php');

class UserNeighbourhoodNN implements UserNeighbourhood {
private $_dataSet;
private $_neighbours;
private $_similarity;

public function __construct(DataSet $dataSet,
$neighbours,
UserSimilarity $similarity = null) {
if (!is_integer($neighbours) || $neighbours < 0)
throw new InvalidArgumentException('Neighbours must be numeric and >= 0');

$this->_dataSet = $dataSet;
$this->_neighbours = $neighbours;

if ($similarity) {
$this->_similarity = $similarity;
}
else {
require_once(dirname(__FILE__) . '/../Similarity/PearsonCorrelationSimilarity.class.php');

$this->_similarity = new PearsonCorrelationSimilarity($this->_dataSet);
}
}

public function userNeighbourhood($userId) {
$users = $this->_dataSet->getUserIds();
$scores = array();

foreach ($users as $user) {
if ($user == $userId) continue;

$scores[$user] = $this->_similarity->userSimilarity($userId, $user);
}

arsort($scores, SORT_NUMERIC); // reverse sort

// return top n (key = userId, value = similarity value)
return array_slice($scores, 0, $this->_neighbours, true);
}
}
64 changes: 64 additions & 0 deletions Test/DataSet/MockDataSet.class.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

require_once(dirname(__FILE__) . '/../DataSet/MockDataSet.class.php');

class MockDataSet implements DataSet {
private $_users;

public function __construct() {
$this->_users = array('Lisa Rose' => array('Lady in the Water' => 2.5,
'Snakes on a Plane' => 3.5,
'Just My Luck' => 3.0,
'Superman Returns' => 3.5,
'You, Me and Dupree' => 2.5,
'The Night Listener' => 3.0),

'Gene Seymour' => array('Lady in the Water' => 3.0,
'Snakes on a Plane' => 3.5,
'Just My Luck' => 1.5,
'Superman Returns' => 5.0,
'The Night Listener' => 3.0,
'You, Me and Dupree' => 3.5),

'Michael Phillips' => array('Lady in the Water' => 2.5,
'Snakes on a Plane' => 3.0,
'Superman Returns' => 3.5,
'The Night Listener' => 4.0),

'Claudia Puig' => array('Snakes on a Plane' => 3.5,
'Just My Luck' => 3.0,
'The Night Listener' => 4.5,
'Superman Returns' => 4.0,
'You, Me and Dupree' => 2.5),

'Mick LaSalle' => array('Lady in the Water' => 3.0,
'Snakes on a Plane' => 4.0,
'Just My Luck' => 2.0,
'Superman Returns' => 3.0,
'The Night Listener' => 3.0,
'You, Me and Dupree' => 2.0),

'Jack Matthews' => array('Lady in the Water' => 3.0,
'Snakes on a Plane' => 4.0,
'The Night Listener' => 3.0,
'Superman Returns' => 5.0,
'You, Me and Dupree' => 3.5),

'Toby' => array('Snakes on a Plane' => 4.5,
'You, Me and Dupree' => 1.0,
'Superman Returns' => 4.0));
}

public function getUserIds() { return array_keys($this->_users); }

public function getUserRatingsArray($user) { return $this->_users[$user]; }

public function getItemIds() { }
public function getNumUsers() { }
public function getNumItems() { }
public function isUser($a) { }
public function isItem($a) { }
public function getUser($a) { }
public function getItem($a) { }
public function getItemRatingsArray($a) { }
}
20 changes: 20 additions & 0 deletions Test/Neighbourhood/UserNeighbourhood.test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

require_once(dirname(__FILE__) . '/../settings.php');
require_once(dirname(__FILE__) . '/../../Neighbourhood/UserNeighbourhoodNN.class.php');

class UserNeighbourhoodTest extends CollabFiltrTest {
private $_dataSet;

public function setUp() {
$this->_dataSet = new MockDataSet();
}

public function testNN() {
$userNeighbouurNN = new UserNeighbourhoodNN($this->_dataSet, 3);
$neighbourhood = $userNeighbouurNN->userNeighbourhood('Toby');

$top3 = array('Lisa Rose', 'Mick LaSalle', 'Claudia Puig');
$this->assertEquals(array_keys($neighbourhood), $top3);
}
}
34 changes: 2 additions & 32 deletions Test/Similarity/UserSimilarity.test.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?php

require_once(dirname(__FILE__) . '/../settings.php');
require_once(dirname(__FILE__) . '/../DataSet/MockDataSet.class.php');

require_once(dirname(__FILE__) . '/../../Similarity/PearsonCorrelationSimilarity.class.php');
require_once(dirname(__FILE__) . '/../../Similarity/EuclideanDistanceSimilarity.class.php');

Expand All @@ -24,36 +26,4 @@ public function testEuclidean() {

$this->assertEquals(round($similarity, 6), 0.148148);
}
}

class MockDataSet implements DataSet {
private $_users;

public function __construct() {
$this->_users = array('Lisa Rose' => array('Lady in the Water' => 2.5,
'Snakes on a Plane' => 3.5,
'Just My Luck' => 3.0,
'Superman Returns' => 3.5,
'You, Me and Dupree' => 2.5,
'The Night Listener' => 3.0),

'Gene Seymour' => array('Lady in the Water' => 3.0,
'Snakes on a Plane' => 3.5,
'Just My Luck' => 1.5,
'Superman Returns' => 5.0,
'The Night Listener' => 3.0,
'You, Me and Dupree' => 3.5));
}

public function getUserIds() { }
public function getItemIds() { }
public function getNumUsers() { }
public function getNumItems() { }
public function isUser($a) { }
public function isItem($a) { }
public function getUser($a) { }
public function getItem($a) { }
public function getItemRatingsArray($a) { }

public function getUserRatingsArray($user) { return $this->_users[$user]; }
}
6 changes: 3 additions & 3 deletions apiDesign.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

require_once(dirname(__FILE__) . '/DataSet/FileDataSet.class.php');
require_once(dirname(__FILE__) . '/Similarity/PearsonCorrelationSimilarity.class.php');
require_once(dirname(__FILE__) . '/Neighbourhood/UserNeighbourhoodNN.class.php');

$dataSet = new FileDataSet('/Volumes/Data/Work/Work/Uni/Dissertation/100k.data');

Expand All @@ -18,9 +19,8 @@
$similarity = new PearsonCorrelationSimilarity($dataSet);
#$similarity = new EuclideanDistanceSimilarity();

#$users = new UserNeighbourhoodNN($data);
#$users->setSimilarity($similarity); // dependency injection
#$users->setNeighbours(30);
$userNN = new UserNeighbourhoodNN($data, 30, $similarity);

#
#$recommender = new UserBasedRecommender($data);
#$recommender->setNeighbourhood($users);
Expand Down

0 comments on commit 5262750

Please sign in to comment.