Skip to content

Instantly share code, notes, and snippets.

@diegopso
Created February 3, 2016 02:42
Show Gist options
  • Save diegopso/d41cea26f64667138b0f to your computer and use it in GitHub Desktop.
Save diegopso/d41cea26f64667138b0f to your computer and use it in GitHub Desktop.
Content-Based Recommendation PHP (based on http://www.codediesel.com/php/item-based-collaborative-filtering-php/)
<?php
/**
* PHP item based filtering
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* @package PHP item based filtering
*/
class ContentBasedRecommend extends Recommend
{
const USER_ID = '__USER__';
protected $data;
function __construct($user, $objects)
{
$this->data[self::USER_ID] = $this->processUser($user);
$this->data = array_merge($this->data, $this->processObjects($objects));
}
public function getRecommendation()
{
$result = [];
foreach ($this->data as $k => $v) {
if($k !== self::USER_ID) {
$result[$k] = $this->similarityDistance($this->data, self::USER_ID, $k);
}
}
arsort($result);
return $result;
}
protected function processUser($user)
{
$result = [];
foreach ($user as $tag) {
$result[$tag] = 1.0;
}
return $result;
}
protected function processObjects($objects)
{
$result = [];
foreach ($objects as $object => $tags) {
foreach ($tags as $tag) {
$result[$object][$tag] = 1.0 ;
}
}
return $result;
}
}
<?php
/**
* PHP item based filtering
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* @package PHP item based filtering
*/
require_once 'recommend.php';
require_once 'content_based.php';
$objects = [
'The Matrix' => ['Action', 'Sci-Fi'],
'Lord of The Rings' => ['Adventure', 'Drama', 'Fantasy'],
'Batman' => ['Action', 'Drama', 'Crime'],
'Fight Club' => ['Drama'],
'Pulp Fiction' => ['Drama', 'Crime'],
'Django' => ['Drama', 'Western'],
];
$user = ['Drama', 'Crime'];
$engine = new ContentBasedRecommend($user, $objects);
var_dump($engine->getRecommendation());
<?php
/**
* PHP item based filtering
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* @package PHP item based filtering
*/
class Recommend {
public function similarityDistance($preferences, $person1, $person2)
{
$similar = array();
$sum = 0;
$alpha = 0;
$beta = 0;
foreach($preferences[$person2] as $key=>$value)
{
$alpha += $preferences[$person2][$key] * $preferences[$person2][$key];
}
foreach($preferences[$person1] as $key=>$value)
{
$beta += $preferences[$person1][$key] * $preferences[$person1][$key];
if(array_key_exists($key, $preferences[$person2])) {
$sum += $preferences[$person2][$key] * $preferences[$person1][$key];
}
}
if($alpha === 0 || $beta === 0)
return 0;
return $sum / sqrt($alpha) / sqrt($beta);
}
public function matchItems($preferences, $person)
{
$score = array();
foreach($preferences as $otherPerson=>$values)
{
if($otherPerson !== $person)
{
$sim = $this->similarityDistance($preferences, $person, $otherPerson);
if($sim > 0)
$score[$otherPerson] = $sim;
}
}
array_multisort($score, SORT_DESC);
return $score;
}
public function transformPreferences($preferences)
{
$result = array();
foreach($preferences as $otherPerson => $values)
{
foreach($values as $key => $value)
{
$result[$key][$otherPerson] = $value;
}
}
return $result;
}
public function getRecommendations($preferences, $person)
{
$total = array();
$simSums = array();
$ranks = array();
$sim = 0;
foreach($preferences as $otherPerson=>$values)
{
if($otherPerson != $person)
{
$sim = $this->similarityDistance($preferences, $person, $otherPerson);
}
if($sim > 0)
{
foreach($preferences[$otherPerson] as $key=>$value)
{
if(!array_key_exists($key, $preferences[$person]))
{
if(!array_key_exists($key, $total)) {
$total[$key] = 0;
}
$total[$key] += $preferences[$otherPerson][$key] * $sim;
if(!array_key_exists($key, $simSums)) {
$simSums[$key] = 0;
}
$simSums[$key] += $sim;
}
}
}
}
foreach($total as $key=>$value)
{
$ranks[$key] = $value / $simSums[$key];
}
array_multisort($ranks, SORT_DESC);
return $ranks;
}
}
@dressholic
Copy link

hei, what metode did u use for find similarity, i think that not eucledian in return

@bonaxcrimo
Copy link

what method you use to find similarityDistance?

@gameing71
Copy link

What calculation was used to calculate the similarity distance in this code?

@diegopso
Copy link
Author

diegopso commented Aug 5, 2020

Never received a notification about this '^^

For anyone in the future, I used Cosine.

@nrlsyhmina
Copy link

Hi, can I know what does it mean by

$result[$object][$tag] = 1.0

1.0 for what?

Thank You.

@diegopso
Copy link
Author

@nrlsyhmina If I still remember, the idea is that to represent an object X with the tags a, b, and d, in a universe with the tags a, b, c, d, and e, I put one for the tags that my object has and zero for the rest. So X = (1,1,0,1,0). Somewhere else I check if the key exists and, if not, I put a zero.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment