Skip to content

Instantly share code, notes, and snippets.

@emsifa
Last active November 27, 2022 07:21
Show Gist options
  • Save emsifa/ce2a6d2375a86d414c63ff8123c2db38 to your computer and use it in GitHub Desktop.
Save emsifa/ce2a6d2375a86d414c63ff8123c2db38 to your computer and use it in GitHub Desktop.
PHP Cosine Similarity untuk Sistem Rekomendasi

PHP Cosine Similarity untuk Sistem Rekomendasi

Catatan class PHP sederhana untuk menghitung cosine similarity yang diperuntukan untuk sistem rekomendasi guna mencari tahu seberapa besar kemiripan user A, dan user B berdasarkan rating pada produk yang mereka berikan.

Implementasi class disini dibuat berdasarkan video youtube: https://www.youtube.com/watch?v=BDJmJnrlaO8

Pada video youtube tersebut, data yang digunakan adalah seperti dibawah ini:

M1 M2 M3 M4 M5 M6
User A 3 5
User B 2 3 3 4
User C 5 4 4 5
User D 5 5 2 5 4

Jika diterapkan kedalam array $ratings, maka akan jadi seperti ini:

$ratings = [
    'User A' => [3, null, 5, null, null, null],
    'User B' => [2, 3, null, 3, 4, null],
    'User C' => [5, 4, 4, null, 5, null],
    'User D' => [5, 5, 2, null, 5, 4],
];

null berarti user belum melakukan rating terhadap film tersebut

Dengan data $ratings diatas, jika kita ingin mencari tahu berapa besar tingkat kesamaan User A dan User B, serta User A dan User C. Kita dapat menggunakan kode seperti dibawah ini:

$sim_ab = CosineSimilarity::calc($ratings['User A'], $ratings['User B']); // 0.1669244652224
$sim_ac = CosineSimilarity::calc($ratings['User A'], $ratings['User C']); // 0.66285976669375
<?php
class CosineSimilarity
{
protected $data_a;
protected $data_b;
public function __construct(array $data_a, array $data_b)
{
$this->data_a = $data_a;
$this->data_b = $data_b;
}
/**
* Mengambil nilai similaritas (kesamaan)
* Rentang hasil: 0 - 1
* Rumus: sum(ai * bi) / (root(sum(ai^2)) * root(sum(bi^2)))
*
* @return float
*/
public function calculate(): float
{
$top = $this->getTop();
$div = $this->getDivider();
return $top / $div;
}
/**
* Kalkulasi nilai atas (angka yang mau dibagi)
* Rumus: sum(ai * bi)
*
* @return float
*/
private function getTop(): float
{
$data_a = $this->data_a;
$data_b = $this->data_b;
$sum = 0;
foreach ($data_a as $i => $a) {
$b = isset($data_b[$i]) ? $data_b[$i] : null;
// Jika salah satu dari a atau b nilainya null ...
if (is_null($a) || is_null($b)) {
continue; // ... skip
}
$sum += $a * $b;
}
return $sum;
}
/**
* Kalkulasi nilai pembagi
* Rumus: root(sum(ai^2)) * root(sum(bi^2))
*
* @return float
*/
private function getDivider(): float
{
$data_a = $this->data_a;
$data_b = $this->data_b;
$root_sum_square_a = $this->rootSumSquares($data_a);
$root_sum_square_b = $this->rootSumSquares($data_b);
return $root_sum_square_a * $root_sum_square_b;
}
private function rootSumSquares(array $data): float
{
// Kalkulasi nilai kuadrat masing-masing item dari data
// [1, null, 2] -> [1, 0, 4] (null diubah jadi 0)
$squares = array_map(function($x) {
return is_null($x) ? 0 : $x * $x;
}, $data);
// Summary hasil kuadrat
// [1, 0, 4] -> 5
$sum_squares = array_sum($squares);
// Kembalikan akar dari summary
return sqrt($sum_squares);
}
/**
* Static function untuk menyederhanakan
* pemanggilan fungsi calculate tanpa harus
* inisiasi class terlebih dehulu
*
* @return float
*/
public static function calc(array $data_a, array $data_b): float
{
return (new static($data_a, $data_b))->calculate();
}
}
@wahyu72122
Copy link

untuk mendapatkan nilai nya untuk penjumlahan bagaimana kak ?

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