zoukankan      html  css  js  c++  java
  • 【转】计算文档相似度(英文)

    转自:http://blog.chinaunix.net/uid-26548237-id-3541783.html

    1、向量空间模型
        向量空间模型作为向量的标识符,是一个用来表示文本文件的代数模型。它应用于信息过滤、信息检索、索引以及相关规则。
        文档和问题都用向量来表示。
        
        每一维都相当于一个独立的词组。如果这个术语出现在文档中,那它在向量中的值就非零。已经有很多不同的方法来计算这些值,这些值叫做(词组)权重。其中一种广为人知的算法就是tf_idf权重。我们是根据应用来定义词组的。典型的词组就是一个单一词、关键词、或者较长的短语。如果字被选为词组,那么向量的维数就是出现在词汇表中不同字的个数。向量运算能通过查询来比较各文档。
        
        通过文档相似度理论的假设,比较每个文档向量和原始查询向量(两个向量的类型是相同的)之间的角度偏差,使得在文档搜索关键词的关联规则是能够计算的。实际上,计算向量之间夹角的余弦比直接计算夹角本身要简单。
        
        其中d2*q是文档向量(即下图中的d2)和查询向量(即下图中的q)的点乘;分母分别为两个向量的模。向量的模通过下面的公式计算:
        
        由于这个模型所考虑的所有向量都是严格非负的,如果其余弦值为零,则表示查询向量和文档向量是正交的,即不符合(换句话说,就是该检索词在文档中没有找到),即两篇文档的相似度为0%。
        
        下面是一个tf-idf权重的例子。
        
        
        优点:
        相对于标准的布尔数学模型,向量空间模型具有如下优点:
        1、基于线性代数的简单模型;
        2、词组的权重不是二元的;
        3、允许计算文档和索引之间的连续相似程度;
        4、允许其根据可能的相关性来进行文件排序;
        5、允许局部匹配;

        局限:
        1、不适用于较长的文件,因为它的相似度值不理想;
        2、检索词组必须与文件中出现的词组精确匹配;
        3、语义敏感度不佳,具有相同的语境但使用不同的词组的文件不能被关联起来;
        4、词组在文档中出现的顺序在向量中间无法表示;
        5、假定词组在统计上是独立的;
        6、权重是直观上获得的而不够正式;

    2、向量空间模型的使用
        下面是利用向量空间模型来计算文件的相似度。以上面讲诉的余弦值Cosine为例,进行实现。
        实现中的权重直接使用的是词出现的频率,另外,这里比较的是英文的相似度。

    1. #include <iostream>
    2. #include <map>
    3. #include <sys/stat.h>
    4. #include <cmath>
    5. using namespace std;
    6. #define ERROR -1
    7. #define OK 0
    8. #define DEBUG
    9. //用于去除文本中的无关紧要的词
    10. //const char delim[] = " .,:;`/\"+i-_(){}[]<>*&^%$#@!?~/|\\=1234567890 \t\n";
    11. const char delim[] = " .,:;'`/\"+-_(){}[]<>*&^%$#@!?~/|\\=1234567890 \t\n";
    12. char *strtolower(char *word)
    13. {
    14.     char *s;
    15.     
    16.     for(= word; *s; s++)
    17.     {
    18.         *= tolower(*s);
    19.     }
    20.     return word;
    21. }
    22. int ReadFile(char *text_name, map<string, int> &word_count)
    23. {
    24.     char *str;
    25.     char *word;
    26.     char *file;
    27.     struct stat sb;
    28.     FILE *fp = fopen(text_name, "r");
    29.     
    30.     if(fp == NULL)
    31.     {
    32.         return ERROR;
    33.     }
    34.     
    35.     if(stat(text_name, &sb))
    36.     {
    37.         return ERROR;
    38.     }
    39.     
    40.     file = (char *)malloc(sb.st_size);
    41.     if(file == NULL)
    42.     {
    43.         fclose(fp);
    44.         return ERROR;
    45.     }
    46.     fread(file, sizeof(char), sb.st_size, fp);
    47.     word = strtok(file, delim);
    48.     
    49.     while(word != NULL)
    50.     {
    51.         //delete the length of word <= 1
    52.         if(strlen(word) <= 1)
    53.         {
    54.             word = strtok(NULL, delim);
    55.             continue;
    56.         }
    57.         
    58.         str = strtolower(strdup(word));
    59.         string tmp = str;
    60.         word_count[tmp]++;
    61.         word = strtok(NULL, delim);
    62.     }
    63. }
    64. int main(int argc, char **argv)
    65. {
    66.     char *text_name_one = "./big.txt";
    67.     //char *text_name_one = "./1.txt";
    68.     char *text_name_two = "./big.txt";
    69.     //char *text_name_two = "./2.txt";
    70.     
    71.     map<string, int> word_count_one;
    72.     map<string, int> word_count_two;
    73.     
    74.     double multi_one = 0.0;
    75.     double multi_two = 0.0;
    76.     double multi_third = 0.0;    
    77.     if(ReadFile(text_name_one, word_count_one) == ERROR)
    78.     {
    79.         cout << "ReadFile() error." << endl;
    80.         return ERROR;
    81.     }
    82. #ifdef DEBUG    
    83.     map<string, int>::iterator map_first = word_count_one.begin();
    84.     for( ; map_first != word_count_one.end(); map_first++)
    85.     {
    86.         cout << map_first->first << " " << map_first->second << endl;
    87.     }
    88. #endif
    89.     if(ReadFile(text_name_two, word_count_two) == ERROR)
    90.     {
    91.         cout << "ReadFile() error." << endl;
    92.         return ERROR;
    93.     }
    94. #ifdef DEBUG    
    95.     map<string, int>::iterator map_second = word_count_two.begin();
    96.     for( ; map_second != word_count_two.end(); map_second++)
    97.     {
    98.         cout << map_second->first << " " << map_second->second << endl;
    99.     }
    100. #endif
    101.     map<string, int>::iterator map_one = word_count_one.begin();
    102.     map<string, int>::iterator map_tmp;
    103.     for( ; map_one != word_count_one.end(); map_one++)
    104.     {
    105.         map_tmp = word_count_two.find(map_one->first);
    106.         if(map_tmp == word_count_two.end())
    107.         {
    108.             multi_two += map_one->second * map_one->second;
    109.             continue;
    110.         }
    111.         multi_one += map_one->second * map_tmp->second;
    112.         multi_two += map_one->second * map_one->second;
    113.         multi_third += map_tmp->second * map_tmp->second;
    114.         word_count_two.erase(map_one->first);    //从2中删除1中具有的
    115.     }
    116.     //检查2中是否仍然有元素
    117.     for(map_tmp = word_count_two.begin(); map_tmp != word_count_two.end(); map_tmp++)
    118.     {
    119.         multi_third += map_tmp->second * map_tmp->second;
    120.     }
    121.     multi_two = sqrt(multi_two);
    122.     multi_third = sqrt(multi_third);
    123.     double result = multi_one / ( multi_two * multi_third);
    124.     cout << "相似度为: " << result * 100 << "%" << endl;
    125.     return 0;
    126. }


        下面进行测试。
        第一、进行检测两个相同的英文文本,文本链接为http://norvig.com/big.txt  
        

        给出了文本中词的部分统计,可以看到,两个相同文本的相似度为100%。
        
        第二、 文本1内容:......this is one!    文本2的内容:()()()......this is two
        
        运行结果与实际手算的结果相同,两个文本的相似度为66.6667%。

        
        
        
        以上只是简单的进行两个英文文本的相似度计算,只是在词条的层次上进行计算,并没有涉及到语义,所以,相对比较简单。
        我对这方面非常感兴趣,还会继续学习其他相关的内容。

        
        理论知识引自:http://zh.wikipedia.org/wiki/%E5%90%91%E9%87%8F%E7%A9%BA%E9%96%93%E6%A8%A1%E5%9E%8B

  • 相关阅读:
    03_ if 练习 _ little2big
    uva 11275 3D Triangles
    uva 12296 Pieces and Discs
    uvalive 3218 Find the Border
    uvalive 2797 Monster Trap
    uvalive 4992 Jungle Outpost
    uva 2218 Triathlon
    uvalive 3890 Most Distant Point from the Sea
    uvalive 4728 Squares
    uva 10256 The Great Divide
  • 原文地址:https://www.cnblogs.com/jackyzzy/p/3011769.html
Copyright © 2011-2022 走看看