怎样在PHP项目中实现相似度计算?

wen java案例 2

本文目录导读:

怎样在PHP项目中实现相似度计算?

  1. 莱文斯坦距离(Levenshtein Distance)
  2. similar_text 函数
  3. 余弦相似度(Cosine Similarity)
  4. Jaccard 相似度
  5. 使用第三方库(推荐)
  6. 完整示例:文本比较系统
  7. 性能优化建议
  8. 选择合适的算法
  9. 注意事项

在PHP项目中实现相似度计算,主要可以通过以下几种常见方法,我会从基础到高级逐步介绍:

莱文斯坦距离(Levenshtein Distance)

PHP内置函数,计算两个字符串之间的编辑距离。

<?php
// 基础用法
$text1 = "hello world";
$text2 = "hallo world";
$distance = levenshtein($text1, $text2);
echo "编辑距离: " . $distance; // 输出: 1
// 转换为相似度百分比
function levenshteinSimilarity($str1, $str2) {
    $distance = levenshtein($str1, $str2);
    $maxLen = max(strlen($str1), strlen($str2));
    if ($maxLen == 0) return 1; // 两个空字符串完全相似
    return 1 - ($distance / $maxLen);
}
echo "相似度: " . levenshteinSimilarity($text1, $text2) * 100 . "%";

similar_text 函数

PHP内置函数,基于字符匹配。

<?php
$text1 = "PHP is great";
$text2 = "PHP is good";
$percent = 0;
similar_text($text1, $text2, $percent);
echo "相似度: " . round($percent, 2) . "%";
// 输出: 66.67%

余弦相似度(Cosine Similarity)

适用于文本向量化后的比较,特别适合TF-IDF场景。

<?php
function cosineSimilarity($text1, $text2) {
    // 分词和获取词频
    $words1 = array_count_values(str_word_count(strtolower($text1), 1));
    $words2 = array_count_values(str_word_count(strtolower($text2), 1));
    // 获取所有唯一词
    $allWords = array_unique(array_merge(array_keys($words1), array_keys($words2)));
    // 构建向量
    $dotProduct = 0;
    $magnitude1 = 0;
    $magnitude2 = 0;
    foreach ($allWords as $word) {
        $count1 = $words1[$word] ?? 0;
        $count2 = $words2[$word] ?? 0;
        $dotProduct += $count1 * $count2;
        $magnitude1 += $count1 * $count1;
        $magnitude2 += $count2 * $count2;
    }
    $magnitude1 = sqrt($magnitude1);
    $magnitude2 = sqrt($magnitude2);
    if ($magnitude1 == 0 || $magnitude2 == 0) return 0;
    return $dotProduct / ($magnitude1 * $magnitude2);
}
$text1 = "I love programming in PHP";
$text2 = "I love coding in PHP";
echo "余弦相似度: " . round(cosineSimilarity($text1, $text2) * 100, 2) . "%";

Jaccard 相似度

基于集合的交集与并集。

<?php
function jaccardSimilarity($text1, $text2) {
    $words1 = array_unique(str_word_count(strtolower($text1), 1));
    $words2 = array_unique(str_word_count(strtolower($text2), 1));
    $intersection = array_intersect($words1, $words2);
    $union = array_unique(array_merge($words1, $words2));
    if (count($union) == 0) return 1;
    return count($intersection) / count($union);
}
$text1 = "the quick brown fox";
$text2 = "the quick brown dog";
echo "Jaccard相似度: " . round(jaccardSimilarity($text1, $text2) * 100, 2) . "%";

使用第三方库(推荐)

使用 PHP NLP Tools

composer require php-nlp-tools/php-nlp-tools
<?php
require_once 'vendor/autoload.php';
use NlpTools\Similarity\CosineSimilarity;
use NlpTools\Similarity\JaccardSimilarity;
// 余弦相似度
$cosine = new CosineSimilarity();
$vector1 = ['php' => 1, 'programming' => 1, 'language' => 1];
$vector2 = ['php' => 1, 'coding' => 1, 'language' => 1];
echo $cosine->similarity($vector1, $vector2); // 0.666...
// Jaccard相似度
$jaccard = new JaccardSimilarity();
$set1 = ['php', 'programming', 'language'];
$set2 = ['php', 'coding', 'language'];
echo $jaccard->similarity($set1, $set2); // 0.5

使用 Text Similarity PHP

composer require yooper/php-text-analysis
<?php
require_once 'vendor/autoload.php';
use PhpTextAnalysis\Similarity\CosineSimilarity;
$similarity = new CosineSimilarity();
$text1 = "The quick brown fox jumps over the lazy dog";
$text2 = "The quick brown fox jumps over the sleeping cat";
$score = $similarity->similarity($text1, $text2);
echo "相似度分数: " . $score;

完整示例:文本比较系统

<?php
class TextSimilarity {
    /**
     * 计算文本相似度
     */
    public function calculateSimilarity($text1, $text2, $method = 'cosine') {
        switch ($method) {
            case 'cosine':
                return $this->cosineSimilarity($text1, $text2);
            case 'jaccard':
                return $this->jaccardSimilarity($text1, $text2);
            case 'levenshtein':
                return $this->levenshteinSimilarity($text1, $text2);
            default:
                throw new InvalidArgumentException("Unknown method: $method");
        }
    }
    /**
     * 文本预处理
     */
    private function preprocess($text) {
        // 转为小写
        $text = strtolower($text);
        // 移除标点符号
        $text = preg_replace('/[^\w\s]/', '', $text);
        // 移除多余空格
        $text = preg_replace('/\s+/', ' ', $text);
        return trim($text);
    }
    /**
     * 获取词频向量
     */
    private function getWordFrequency($text) {
        $words = str_word_count($this->preprocess($text), 1);
        return array_count_values($words);
    }
    private function cosineSimilarity($text1, $text2) {
        $vector1 = $this->getWordFrequency($text1);
        $vector2 = $this->getWordFrequency($text2);
        // 简化实现,使用前述的cosineSimilarity函数
        // ...
    }
    private function jaccardSimilarity($text1, $text2) {
        // 简化实现
        // ...
    }
    private function levenshteinSimilarity($text1, $text2) {
        $distance = levenshtein($text1, $text2);
        $maxLen = max(strlen($text1), strlen($text2));
        return 1 - ($distance / $maxLen);
    }
}
// 使用示例
$similarity = new TextSimilarity();
$text1 = "Natural language processing is fascinating";
$text2 = "Natural language processing is interesting";
echo "余弦相似度: " . $similarity->calculateSimilarity($text1, $text2, 'cosine');

性能优化建议

<?php
// 缓存文本向量
class VectorCache {
    private $cache = [];
    public function getVector($text) {
        $hash = md5($text);
        if (!isset($this->cache[$hash])) {
            $this->cache[$hash] = $this->buildVector($text);
        }
        return $this->cache[$hash];
    }
    private function buildVector($text) {
        // 构建向量逻辑
        // ...
    }
}

选择合适的算法

  • 简短文本(如用户名):莱文斯坦距离
  • 中等长度文本(如句子):余弦相似度 或 Jaccard
  • 长文本比较 (如文章):TF-IDF + 余弦相似度
  • 商品、产品名称:similar_text

注意事项

  1. 中文支持:上述方法主要针对英文,中文需要分词
  2. 性能:大量文本比较时考虑缓存和索引
  3. 精度:根据具体场景选择合适的方法
  4. 内存:处理大规模数据时注意内存使用

如果处理中文文本,建议使用 jieba-php 等分词库进行预处理。

抱歉,评论功能暂时关闭!