使用TF-IDF权重比较文档相似度代码示例

TF-IDF算法

  • TF-IDF算法是一种计算文档中每个词项的重要程度的方法,其主要思想在于:如果一个词语在每一个文档中都存在,那么它就不具备区分度,因而会给这样的词语赋予更低的权重。

  • 例如,“的,这,你,我”,诸如此类在每个文档中的词频都很高的词语会被赋予较低的权重。

  • 计算公式:
    T F − I D F i j = T F i j ∗ I D F j TF-IDF_{ij}=TF_{ij}*IDF_j TFIDFij=TFijIDFj
    I D F j = l o g ( 文档的总数 包含词语 j 的文档数目 ) IDF_j=log(\frac{文档的总数}{包含词语j的文档数目}) IDFj=log(包含词语j的文档数目文档的总数)

    我们假设现在有 n n n个文档,要计算每个文档中的每个词语的 T F − I D F TF-IDF TFIDF权重。我们将每个文档进行分词,那么 T F − I D F i j TF-IDF_{ij} TFIDFij就等于第 i i i个文档中的第 j j j个词语的权重, T F i j TF_{ij} TFij就为第 i i i个文档中的第 j j j个词语的出现的次数。逆文档频率 I D F j IDF_j IDFj计算公式如第二条所示,可以看到当包含词语 j j j的文档数目越多时, I D F IDF IDF值越小。

  • 计算公式的改进:

    • 以上公式具有一定缺陷。在长文本与短文本进行对比时,长文本更具有优势,因为它的词语数量较多,因此 T F TF TF值通常更大;在 I D F IDF IDF计算公式中,同样也存在分母为0的可能。因此,对以上公式进行一些改进:
      T F − I D F i j = T F i j ∗ I D F j TF-IDF_{ij}=TF_{ij}*IDF_j TFIDFij=TFijIDFj
      T F i j = 词项 j 在文档 i 中出现的次数 文档 i 的总词语数 TF_{ij}=\frac{词项j在文档i中出现的次数}{文档i的总词语数} TFij=文档i的总词语数词项j在文档i中出现的次数
      I D F j = l o g ( 文档的总数 1 + 包含词语 j 的文档数目 ) IDF_j=log(\frac{文档的总数}{1+包含词语j的文档数目}) IDFj=log(1+包含词语j的文档数目文档的总数)

余弦相似度计算

  • 我们计算得到每个文档的 T F − I D F TF-IDF TFIDF矩阵之后,基于该权重计算两两之间文档的相似度,步骤如下:
    • 将两个文档中的所有词语组成一个词库,并以词库的长度为向量的维度构造两个文档的向量化表示。
    • 遍历词库,当当前遍历到的词语存在于文档1时,在文档1的向量的对应位置填上该词语在文档1中的 T F − I D F TF-IDF TFIDF权重.

完整代码如下:

import jieba
import numpy as np

docs = ["新型互联网大数据技术研究",
        "大数据采集技术与应用方法",
        "一种互联网技术研究方法",
        "计算机系统的分析与设计技术"
        ]


def read_stopwords():
    stopwords = []
    f = open("D:\信息检索与搜索引擎\实验3\stopwords.txt", "r", encoding='utf-8')
    s_list = f.readlines()
    for item in s_list:
        stopwords.append(item.strip())
    return stopwords


def delete_stopwords(word_list, stopword_list):
    new_list = []
    for word in word_list:
        if word not in stopword_list:
            new_list.append(word)
    return new_list


def getFrequency(word_list):
    frequency = {}
    for word in word_list:
        if word not in frequency.keys():
            frequency[word] = 1
        else:
            frequency[word] += 1
    return frequency


def get_all_words(doc_list):
    word_list = set()
    # 获取文档集合中所有的词
    for doc in doc_list:
        for word in doc:
            word_list.add(word)
    return list(word_list)


# 传入两个文档的tf-idf表
def cosine_sim(v1, v2):
    words1 = set(v1.keys())
    words2 = set(v2.keys())
    # 获取两个文档组成的词库
    allwords = words1.union(words2)
    n1 = []
    n2 = []
    # 构造词向量
    for word in allwords:
        if word in v1.keys():
            n1.append(v1[word])
        else:
            n1.append(0)
        if word in v2.keys():
            n2.append(v2[word])
        else:
            n2.append(0)
    # 计算向量内积
    return np.dot(n1, n2)/(np.linalg.norm(n1)*np.linalg.norm(n2))


if __name__ == "__main__":
    stopwords = read_stopwords()
    jieba.load_userdict(r"D:\信息检索与搜索引擎\实验3\user_dict.txt")
    datalist = [delete_stopwords(word_list=list(
        jieba.cut(doc)), stopword_list=stopwords) for doc in docs]
    print(datalist)
    # 词频矩阵
    frequency = [getFrequency(data) for data in datalist]
    # print(frequency)
    # 计算逆文档频率
    words = get_all_words(datalist)
    word_in_doc = dict.fromkeys(words, 0)
    for word in words:
        for doc in datalist:
            if word in doc:
                word_in_doc[word] += 1
    idf = {}
    for word, num in word_in_doc.items():
        idf[word] = np.log10(1+len(docs)/num)
    # print(idf)
    # 计算tf-idf值
    tf_idf = []
    for i in range(len(datalist)):
        tmp = frequency[i]
        for word in datalist[i]:
            tmp[word] = tmp[word]*idf[word]
        tf_idf.append(tmp)
    # print(tf_idf)
    # 特征选择,略
    # 计算余弦相似度
    for i in range(len(datalist)):
        for j in range(i+1, len(datalist)):
            print("文档{}与文档{}的余弦相似度为:{}".format(
                i+1, j+1, cosine_sim(tf_idf[i], tf_idf[j])))

你可能感兴趣的:(tf-idf,python,机器学习)