У меня есть две функции PHP для вычисления отношения между двумя текстами. Они оба используют модель мешков слов, но check2 () выполняется намного быстрее. В любом случае обе функции дают одинаковые результаты. Зачем? check1 () использует один большой массив словаря, содержащий ВСЕ слова – как описано в сумке словной модели. check2 () не использует один большой массив, а массив, содержащий только слова одного текста. Поэтому check2 () не должен работать, но это не так. Почему обе функции дают одинаковые результаты?
function check1($terms_in_article1, $terms_in_article2) { global $zeit_check1; $zeit_s = microtime(TRUE); $length1 = count($terms_in_article1); // number of words $length2 = count($terms_in_article2); // number of words $all_terms = array_merge($terms_in_article1, $terms_in_article2); $all_terms = array_unique($all_terms); foreach ($all_terms as $all_termsa) { $term_vector1[$all_termsa] = 0; $term_vector2[$all_termsa] = 0; } foreach ($terms_in_article1 as $terms_in_article1a) { $term_vector1[$terms_in_article1a]++; } foreach ($terms_in_article2 as $terms_in_article2a) { $term_vector2[$terms_in_article2a]++; } $score = 0; foreach ($all_terms as $all_termsa) { $score += $term_vector1[$all_termsa]*$term_vector2[$all_termsa]; } $score = $score/($length1*$length2); $score *= 500; // for better readability $zeit_e = microtime(TRUE); $zeit_check1 += ($zeit_e-$zeit_s); return $score; } function check2($terms_in_article1, $terms_in_article2) { global $zeit_check2; $zeit_s = microtime(TRUE); $length1 = count($terms_in_article1); // number of words $length2 = count($terms_in_article2); // number of words $score_table = array(); foreach($terms_in_article1 as $term){ if(!isset($score_table[$term])) $score_table[$term] = 0; $score_table[$term] += 1; } $score_table2 = array(); foreach($terms_in_article2 as $term){ if(isset($score_table[$term])){ if(!isset($score_table2[$term])) $score_table2[$term] = 0; $score_table2[$term] += 1; } } $score = 0; foreach($score_table2 as $key => $entry){ $score += $score_table[$key] * $entry; } $score = $score/($length1*$length2); $score *= 500; $zeit_e = microtime(TRUE); $zeit_check2 += ($zeit_e-$zeit_s); return $score; }
Я надеюсь, что вы можете мне помочь. Заранее спасибо!
Обе функции реализуют практически тот же алгоритм, но в то время как первый делает это прямолинейно, второй – немного более умный и пропускает часть ненужной работы.
check1 выглядит примерно так:
// loop length(words1) times for each word in words1: freq1[word]++ // loop length(words2) times for each word in words2: freq2[word]++ // loop length(union(words1, words2)) times for each word in union(words1, words2): score += freq1[word] * freq2[word]
Но помните: когда вы умножаете что-то с нулем, вы получите нуль.
Это означает, что подсчет частот слов, которые не входят в оба набора, является пустой тратой времени – мы умножаем частоту на ноль и ничего не добавим к счету.
check2 учитывает это:
// loop length(words1) times for each word in words1: freq1[word]++ // loop length(words2) times for each word in words2: if freq1[word] > 0: freq2[word]++ // loop length(intersection(words1, words2)) times for each word in freq2: score += freq1[word] * freq2[word]
поскольку вы, похоже, обеспокоены производительностью, вот оптимизированная версия алгоритма в вашей функции check2, которая использует некоторые более встроенные функции для повышения скорости.
function check ($terms1, $terms2) { $counts1 = array_count_values($terms1); $totalScore = 0; foreach ($terms2 as $term) { if (isset($counts1[$term])) $totalScore += $counts1[$term]; } return $totalScore * 500 / (count($terms1) * count($terms2)); }