2009-05-30 3 views
4

У меня есть две функции PHP для вычисления отношения между двумя текстами. Они оба используют модель мешков слов, но check2() выполняется намного быстрее. В любом случае обе функции дают одинаковые результаты. Зачем? check1() использует один большой массив словаря, содержащий ВСЕ слова - как описано в сумке словной модели. check2() не использует один большой массив, а массив, содержащий только слова одного текста. Поэтому check2() не должен работать, но это не так. Почему обе функции дают одинаковые результаты?Сумка слов модель: 2 PHP-функции, те же результаты: Почему?

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; 
} 

Надеюсь, вы можете мне помочь. Заранее спасибо!

+0

Я рад, что вы нашли человека, который мог бы это объяснить:) Хорошее улучшение от werner тоже! береги себя! – 0scar

ответ

3

Обе функции реализуют практически тот же алгоритм, но в то время как первый делает это прямолинейно, второй из них немного более умный и пропускает часть ненужной работы.

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] 
6

, так как вы, кажется, обеспокоены производительности, вот оптимизированную версию алгоритма в вашей функции 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)); 
} 
+0

Большое спасибо, Вернер. Вы правы, ваша версия еще быстрее, чем самая быстрая из двух моих версий. К сожалению, я попросил причину, почему работают и другие функции. Поэтому я должен выбрать ответ Рене Саарсо как лучший, так как он отлично ответил на мой вопрос. Но ты мне тоже помог. Благодаря! :) – caw

+0

+1 для показа красиво быстрого кода! – 0scar

+0

Почему он дает 70, когда оба массива на 100% одинаковы? –

Смежные вопросы