本文目录导读:

我来介绍PHP实现Jaccard相似度的几种方法:
基础实现(数组方式)
<?php
/**
* 基础的Jaccard相似度计算
* @param array $set1 第一个集合
* @param array $set2 第二个集合
* @return float 相似度值(0-1)
*/
function jaccardSimilarity(array $set1, array $set2): float {
// 确保元素唯一
$set1 = array_unique($set1);
$set2 = array_unique($set2);
// 计算交集
$intersection = array_intersect($set1, $set2);
$intersectionCount = count($intersection);
// 计算并集
$unionCount = count($set1) + count($set2) - $intersectionCount;
// 处理空集合情况
if ($unionCount === 0) {
return 1.0; // 两个空集合视为相同
}
return $intersectionCount / $unionCount;
}
// 使用示例
$setA = ['apple', 'banana', 'orange', 'grape'];
$setB = ['apple', 'banana', 'kiwi', 'mango'];
$similarity = jaccardSimilarity($setA, $setB);
echo "Jaccard相似度: " . round($similarity, 4) . "\n"; // 输出: 0.3333
文本相似度计算
<?php
/**
* 文本Jaccard相似度计算
* @param string $text1 第一个文本
* @param string $text2 第二个文本
* @param string $delimiter 分词分隔符
* @return float 相似度值
*/
function textJaccardSimilarity(string $text1, string $text2, string $delimiter = ' '): float {
// 分词
$words1 = explode($delimiter, $text1);
$words2 = explode($delimiter, $text2);
// 去除空白和标点
$words1 = array_filter(array_map('trim', $words1));
$words2 = array_filter(array_map('trim', $words2));
return jaccardSimilarity($words1, $words2);
}
// 使用示例
$text1 = "The quick brown fox jumps over the lazy dog";
$text2 = "The quick brown fox jumps over the sleeping cat";
echo "文本相似度: " . round(textJaccardSimilarity($text1, $text2), 4) . "\n";
高级实现(支持权重和多种数据类型)
<?php
class JaccardSimilarityCalculator {
/**
* 计算Jaccard相似度(支持权重)
* @param array $set1
* @param array $set2
* @param array $weights 权重数组(可选)
* @return float
*/
public function weightedJaccard(array $set1, array $set2, array $weights = []): float {
$set1 = array_unique($set1);
$set2 = array_unique($set2);
if (empty($set1) && empty($set2)) {
return 1.0;
}
$intersection = array_intersect($set1, $set2);
$union = array_unique(array_merge($set1, $set2));
if (!empty($weights)) {
return $this->calculateWeighted($intersection, $union, $weights);
}
return count($intersection) / count($union);
}
/**
* 计算加权Jaccard
*/
private function calculateWeighted(array $intersection, array $union, array $weights): float {
$intersectionWeight = 0;
$unionWeight = 0;
foreach ($union as $element) {
$weight = $weights[$element] ?? 1;
$unionWeight += $weight;
if (in_array($element, $intersection)) {
$intersectionWeight += $weight;
}
}
return $unionWeight > 0 ? $intersectionWeight / $unionWeight : 0;
}
/**
* 计算多集合的Jaccard相似度
* @param array ...$sets
* @return float
*/
public function multiSetJaccard(array ...$sets): float {
if (count($sets) < 2) {
return 1.0;
}
$sets = array_map('array_unique', $sets);
// 计算交集(所有集合共有的元素)
$intersection = call_user_func_array('array_intersect', $sets);
// 计算并集(所有集合的元素)
$union = call_user_func_array('array_merge', $sets);
$union = array_unique($union);
return count($union) > 0 ? count($intersection) / count($union) : 0;
}
}
// 使用示例
$calculator = new JaccardSimilarityCalculator();
// 基本使用
$set1 = ['a', 'b', 'c', 'd'];
$set2 = ['a', 'b', 'e', 'f'];
echo "基本相似度: " . $calculator->weightedJaccard($set1, $set2) . "\n";
// 加权使用
$weights = ['a' => 2, 'b' => 1, 'c' => 3];
echo "加权相似度: " . $calculator->weightedJaccard($set1, $set2, $weights) . "\n";
// 多集合
$set3 = ['a', 'b', 'g'];
echo "多集合相似度: " . $calculator->multiSetJaccard($set1, $set2, $set3) . "\n";
性能优化版本(处理大数据集)
<?php
/**
* 高性能Jaccard相似度实现
* 使用哈希表提高效率
*/
class OptimizedJaccard {
/**
* 使用哈希表计算Jaccard相似度
* @param array $set1
* @param array $set2
* @return float
*/
public static function calculate(array $set1, array $set2): float {
// 转换为哈希集合
$hashSet1 = array_flip($set1);
$hashSet2 = array_flip($set2);
$intersectionCount = 0;
// 遍历较小的集合以提高性能
if (count($hashSet1) <= count($hashSet2)) {
foreach ($hashSet1 as $element => $_) {
if (isset($hashSet2[$element])) {
$intersectionCount++;
}
}
} else {
foreach ($hashSet2 as $element => $_) {
if (isset($hashSet1[$element])) {
$intersectionCount++;
}
}
}
$totalUnique = count($hashSet1) + count($hashSet2) - $intersectionCount;
return $totalUnique > 0 ? $intersectionCount / $totalUnique : 1.0;
}
}
// 性能测试
$largeSet1 = range(1, 10000);
$largeSet2 = range(5000, 15000);
$startTime = microtime(true);
$similarity = OptimizedJaccard::calculate($largeSet1, $largeSet2);
$endTime = microtime(true);
echo "相似度: " . round($similarity, 4) . "\n";
echo "执行时间: " . round(($endTime - $startTime) * 1000, 2) . "ms\n";
实用示例:文档推荐系统
<?php
class DocumentRecommender {
private $documents = [];
public function addDocument(string $id, string $content): void {
$this->documents[$id] = $this->tokenize($content);
}
private function tokenize(string $text): array {
// 简单的分词(实际应用中使用更复杂的分词器)
$text = strtolower($text);
$text = preg_replace('/[^\w\s]/', '', $text);
return array_unique(explode(' ', $text));
}
/**
* 查找相似文档
* @param string $docId 文档ID
* @param int $limit 返回结果数量
* @return array 相似度排序的文档列表
*/
public function findSimilar(string $docId, int $limit = 5): array {
if (!isset($this->documents[$docId])) {
return [];
}
$targetTokens = $this->documents[$docId];
$results = [];
foreach ($this->documents as $id => $tokens) {
if ($id === $docId) continue;
$similarity = jaccardSimilarity($targetTokens, $tokens);
$results[$id] = $similarity;
}
// 降序排序
arsort($results);
return array_slice($results, 0, $limit);
}
}
// 使用示例
$recommender = new DocumentRecommender();
$recommender->addDocument('doc1', 'PHP is a popular scripting language for web development');
$recommender->addDocument('doc2', 'Python is versatile for data science and web development');
$recommender->addDocument('doc3', 'JavaScript runs in the browser for interactive web pages');
$similarDocs = $recommender->findSimilar('doc1', 2);
print_r($similarDocs);
注意事项
- 预处理:确保数据已经过适当的清洗和标准化
- 性能优化:对于大规模数据,使用哈希表(array_flip)提高效率
- 内存管理:处理大型数据集时注意内存使用
- 数据稀疏性:Jaccard相似度对稀疏数据敏感,考虑使用余弦相似度作为替代
这些实现可以根据具体需求进行调整和优化。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播