64 lines
1.7 KiB
Text
64 lines
1.7 KiB
Text
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace Classifier\Lib\Discriminant;
|
||
|
|
|
||
|
|
class AlertClassifier
|
||
|
|
{
|
||
|
|
/** @var array<string,int> */
|
||
|
|
private $dictionary;
|
||
|
|
|
||
|
|
/** @var int */
|
||
|
|
private $threshold;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param array<string,int> $dictionary eg: [
|
||
|
|
* 'alerte' => 50, 'population' => 30 ...
|
||
|
|
* ]
|
||
|
|
* @param int $threshold Le score à partir duquel on est "sûr" à 100%
|
||
|
|
*/
|
||
|
|
public function __construct(array $dictionary, int $threshold = 100)
|
||
|
|
{
|
||
|
|
$this->dictionary = $dictionary;
|
||
|
|
$this->threshold = $threshold;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param string[] $cleanWords
|
||
|
|
* @return float Indice de confiance entre 0 et 1
|
||
|
|
*/
|
||
|
|
public function getConfidenceScore(array $cleanWords): float
|
||
|
|
{
|
||
|
|
$totalScore = 0;
|
||
|
|
|
||
|
|
foreach ($this->dictionary as $keyword => $weight) {
|
||
|
|
$bestMatch = 0;
|
||
|
|
|
||
|
|
foreach ($cleanWords as $word) {
|
||
|
|
$distance = levenshtein($keyword, $word);
|
||
|
|
|
||
|
|
// * Calcul du ratio de similitude (0 à 1)
|
||
|
|
$maxLen = max(strlen($keyword), strlen($word));
|
||
|
|
if ($maxLen === 0) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$similarity = 1 - ($distance / $maxLen);
|
||
|
|
|
||
|
|
// * On ne garde que si c'est très proche (ex: > 80%)
|
||
|
|
if ($similarity > 0.8) {
|
||
|
|
$bestMatch = max($bestMatch, $similarity);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// * Ajout du poids pondéré par la qualité de la correspondance
|
||
|
|
$totalScore += ($bestMatch * $weight);
|
||
|
|
}
|
||
|
|
|
||
|
|
// * Normalisation : on plafonne à 1 (100%)
|
||
|
|
$confidence = $totalScore / $this->threshold;
|
||
|
|
return min(1.0, $confidence);
|
||
|
|
}
|
||
|
|
}
|