Cosinus podobieństwo vs odległość Hamming [zamknięty]

Aby obliczyć podobieństwo między dwoma dokumentami, tworzę wektor funkcji zawierający pojęcie częstotliwości. Ale potem, w następnym kroku, nie mogę się zdecydować między "cosinus podobieństwa " i " Odległość Hamminga".

Moje pytanie: Czy masz doświadczenie z tymi algorytmami? Który daje lepsze wyniki?

Poza tym: czy mógłbyś mi powiedzieć, jak kodować Cosinusowe podobieństwo w PHP? Na odległość Hamming, Mam już kod:

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));
}
Nie chcę używać żadnego innego algorytmu. Chciałbym tylko mieć pomoc w podejmowaniu decyzji między obydwoma. [1]} i może ktoś powie coś, jak poprawić algorytmy. Czy uzyskasz lepsze wyniki, jeśli odfiltrowasz słowa stop lub popularne słowa? Mam nadzieję, że mi pomożesz. Z góry dzięki!
Author: caw, 2009-06-03

4 answers

Odległość Hamminga powinna być wykonana między dwoma ciągami o jednakowej długości i z uwzględnieniem kolejności.

Ponieważ Twoje dokumenty są z pewnością różnej długości i jeśli słowa Miejsca się nie liczą, podobieństwo cosinusów jest lepsze (pamiętaj, że w zależności od twoich potrzeb istnieją lepsze rozwiązania). :)

Oto cosinusowa funkcja podobieństwa 2 tablic wyrazów:

function cosineSimilarity($tokensA, $tokensB)
{
    $a = $b = $c = 0;
    $uniqueTokensA = $uniqueTokensB = array();

    $uniqueMergedTokens = array_unique(array_merge($tokensA, $tokensB));

    foreach ($tokensA as $token) $uniqueTokensA[$token] = 0;
    foreach ($tokensB as $token) $uniqueTokensB[$token] = 0;

    foreach ($uniqueMergedTokens as $token) {
        $x = isset($uniqueTokensA[$token]) ? 1 : 0;
        $y = isset($uniqueTokensB[$token]) ? 1 : 0;
        $a += $x * $y;
        $b += $x;
        $c += $y;
    }
    return $b * $c != 0 ? $a / sqrt($b * $c) : 0;
}

Jest szybki (isset() zamiast in_array() jest zabójcą na dużych tablicach).

Jak widać, wyniki nie uwzględniają "wielkości" każdego słowa.

Używam go do wykrywania wielu opublikowanych wiadomości "prawie" wklejonych tekstów. Działa dobrze. :)

Najlepszy link o metrykach podobieństwa łańcuchów : http://www.dcs.shef.ac.uk / ~sam/stringmetrics.html

Dla dalszych ciekawych odczyty:

Http://www.miislita.com/information-retrieval-tutorial/cosine-similarity-tutorial.html http://bioinformatics.oxfordjournals.org/cgi/content/full/22/18/2298

 16
Author: Toto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-17 22:47:36

Chyba, że się mylę, myślę, że masz algorytm w połowie drogi między tymi dwoma algorytmami . Dla odległości Hamminga stosuje się:

function check ($terms1, $terms2) {
    $counts1 = array_count_values($terms1);
    $totalScore = 0;
    foreach ($terms2 as $term) {
        if (isset($counts1[$term])) $totalScore += 1;
    }
    return $totalScore * 500 / (count($terms1) * count($terms2));
}

(zauważ, że dodajesz tylko 1 dla każdego dopasowanego elementu w wektorach tokenów.)

I dla podobieństwa cosinusowego, użyj:

function check ($terms1, $terms2) {
    $counts1 = array_count_values($terms1);
    $counts2 = array_count_values($terms2);
    $totalScore = 0;
    foreach ($terms2 as $term) {
        if (isset($counts1[$term])) $totalScore += $counts1[$term] * $counts2[$term];
    }
    return $totalScore / (count($terms1) * count($terms2));
}

(zauważ, że dodajesz iloczyn liczby Tokenów między dwoma dokumentami.)

Główna różnica między tymi dwoma jest taka, że podobieństwo cosinusów da silniejszy wskaźnik, gdy dwa dokumenty mają to samo słowo wiele razy w dokumentach , podczas gdy odległość Hamminga nie obchodzi, jak często poszczególne żetony pojawiają się .

Edit : właśnie zauważyłem Twoje zapytanie dotyczące usuwania słów funkcyjnych itp. Radzę to, jeśli masz zamiar używać cosinusowego podobieństwa - ponieważ słowa funkcyjne są dość częste (przynajmniej w języku angielskim), możesz wypaczać wynik, nie filtrując ich. Jeśli użyjesz odległości Hamminga, efekt nie będzie tak wielki, ale może nadal być odczuwalne w niektórych przypadkach. Ponadto, jeśli masz dostęp do lemmatizer, zmniejszy to błędy, gdy jeden dokument zawiera "galaktyki", a drugi zawiera" galaktykę", na przykład.

W którąkolwiek stronę pójdziesz, powodzenia!

 9
Author: Mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-03 16:54:02

Przepraszam za zignorowanie faktu, że powiedziałeś, że nie chcesz używać żadnych innych algorytmów, ale poważnie, odległość Levenshteina i odległość Damerau-Levenshteina są o wiele bardziej przydatne niż odległość Hamminga. Oto implementacja d-l distance w PHP , a jeśli nie podoba Ci się natywna funkcja PHP levenshtein(), której myślę, że nie zrobisz, ponieważ ma limit długości, oto wersja bez ograniczeń długości:

function levenshtein_distance($text1, $text2) {
    $len1 = strlen($text1);
    $len2 = strlen($text2);
    for($i = 0; $i <= $len1; $i++)
        $distance[$i][0] = $i;
    for($j = 0; $j <= $len2; $j++)
        $distance[0][$j] = $j;
    for($i = 1; $i <= $len1; $i++)
        for($j = 1; $j <= $len2; $j++)
            $distance[$i][$j] = min($distance[$i - 1][$j] + 1, $distance[$i][$j - 1] + 1, $distance[$i - 1][$j - 1] + ($text1[$i - 1] != $text2[$j - 1]));
    return $distance[$len1][$len2];
}
 5
Author: chaos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-03 16:37:56

Tutaj mój poprawiony kod dla Cosinusowej funkcji odległości wysłany przez Toto

function cosineSimilarity($tokensA, $tokensB)
{
    $a = $b = $c = 0;
    $uniqueTokensA = $uniqueTokensB = array();

    $uniqueMergedTokens = array_unique(array_merge($tokensA, $tokensB));

    foreach ($tokensA as $token) $uniqueTokensA[$token] = 0;
    foreach ($tokensB as $token) $uniqueTokensB[$token] = 0;

    foreach ($uniqueMergedTokens as $token) {
        $x = isset($uniqueTokensA[$token]) ? 1 : 0;
        $y = isset($uniqueTokensB[$token]) ? 1 : 0;
        $a += $x * $y;
        $b += pow($x,2);
        $c += pow($y,2);
    }
    return $b * $c != 0 ? $a / sqrt($b * $c) : 0;
}
 2
Author: LorenzoMarchi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-13 15:10:59