网站整套模板,广东住房建设部官方网站,常州网站建设公司方案,海外网络服务器官网目录 一、新词发现 1.新词发现的衡量标准 ① 内部稳固 ② 外部多变 2.示例 ① 初始化类 NewWordDetect ② 加载语料信息#xff0c;并进行统计 ③ 统计指定长度的词频及其左右邻居字符词频 ④ 计算熵 ⑤ 计算左右熵 编辑 ⑥ 统计词长总数 ⑦ 计算互信息 ⑧ 计算每个词… 目录 一、新词发现 1.新词发现的衡量标准 ① 内部稳固 ② 外部多变 2.示例 ① 初始化类 NewWordDetect ② 加载语料信息并进行统计 ③ 统计指定长度的词频及其左右邻居字符词频 ④ 计算熵 ⑤ 计算左右熵 编辑 ⑥ 统计词长总数 ⑦ 计算互信息 ⑧ 计算每个词的价值 ⑨ 新词检测 编辑 二、挑选重要词 1.数学角度刻画重要词 例 编辑 TF·IDF其他计算方式 2.算法特点 3.算法示例 ① 构建TF·IDF字典 ② 根据tf值和idf值计算tf·idf ③ 计算给定语料库中每个文档的TF-IDF值 ④ 提取每个文本的前top个高频词 ⑤ tf·idf的计算和使用 4.TF·IDF应用 —— 搜索引擎 ① 对于已有的所有网页文本计算每个网页中词的TF·IDF值 ② 对于一个输入query(查询)进行分词 ③ TF·IDF实现简单搜索引擎 5.TF·IDF应用 —— 文本摘要 ① 加载文档数据并计算每个文档的TF·IDF值 ② 计算生成每一篇文章的摘要 ③ 生成文档摘要并将摘要添加到原始文档中 ④ TF·IDF实现简单文本摘要 6.TF·IDF应用 —— 文本相似度计算 ① 加载文档数据并计算TF-IDF值 ② 将文章转换为向量 ③ 文档转换为向量表示 ④ 计算两个向量间的余弦相似度 ⑤ 计算输入文本与语料库所有文档的相似度 ⑥ TF·IDF实现文本相似度计算 7.TF·IDF的优势 ① 可解释性好 ② 计算速度快 ③ 对标注数据依赖小 ④ 可以与很多算法组合使用 8.TF·IDF的劣势 ① 受分词效果影响大 ② 词与词之间没有语义相似度 ③ 没有语序信息 ④ 能力范围有限 ⑤ 样本不均衡会对结果有很大影响 ⑥ 类内样本间分布不被考虑 死亡不是生命的终点被遗忘才是 —— 24.12.21 一、新词发现
词相当于一种固定搭配
1.新词发现的衡量标准
① 内部稳固
词的内部应该是稳固的用内部稳固度衡量
内部稳固度词语中几个字的固定搭配出现的次数除以词语中每个字单独出现的概率的乘积
公式
② 外部多变
词的外部应该是多变的用左右熵衡量
左右熵 将词语外部出现的所有字再除以出现的总词频数得到出现某个字的频率pi代入公式进行求和后取反得到词语两边的左右熵词语的外部两侧出现一个固定字的频率应该较低换句话说词的外部应该是多变的而不是固定的左右熵的值大小可以衡量词的外部值是否多变左右熵的值越大词的外部越多变
用两个指标计算分数根据分数衡量一些文字组合是否是新词
公式 2.示例 ① 初始化类 NewWordDetect
Ⅰ 初始化参数 设置词语最高长度为5个字符 初始化三个字典word_count 统计词频left_neighbor 和 right_neighbor 分别记录每个词的左邻词和右邻词
Ⅱ 加载语料库调用 load_corpus 方法加载语料库数据
Ⅲ 计算指标计算互信息PMI熵以及词的价值
class NewWordDetect:def __init__(self, corpus_path):# 设置词语最高长度 1 - 5 四个字的词语self.max_word_length 5self.word_count defaultdict(int)self.left_neighbor defaultdict(dict)self.right_neighbor defaultdict(dict)self.load_corpus(corpus_path)self.calc_pmi()self.calc_entropy()self.calc_word_values() ② 加载语料信息并进行统计 Ⅰ 打开文件打开并读取指定路径的文件编码为UTF-8
Ⅱ 处理文件对文件中的每一行进行处理去除首尾空白字符
Ⅲ 句子统计对每个句子按不同长度从1到self.max_word_length进行n-gram统计
Ⅳ 计数操作调用self.ngram_count方法进行具体的n-gram计数操作 #加载语料数据并进行统计def load_corpus(self, path):with open(path, encodingutf8) as f:for line in f:sentence line.strip()for word_length in range(1, self.max_word_length):self.ngram_count(sentence, word_length)return③ 统计指定长度的词频及其左右邻居字符词频
Ⅰ 遍历句子通过循环遍历句子中的每个位置提取长度为word_length的子串
Ⅱ 统计词频将提取的子串作为键更新其在self.word_count字典中的计数
Ⅲ 统计左邻居字符如果当前子串有左邻居字符则更新self.left_neighbor字典中该子串对应左邻居字符的计数
Ⅳ 统计右邻居字符如果当前子串有右邻居字符则更新self.right_neighbor字典中该子串对应右邻居字符的计数 #按照窗口长度取词,并记录左邻右邻出现过的字及次数def ngram_count(self, sentence, word_length):for i in range(len(sentence) - word_length 1):word sentence[i:i word_length]self.word_count[word] 1if i - 1 0:char sentence[i - 1]self.left_neighbor[word][char] self.left_neighbor[word].get(char, 0) 1if i word_length len(sentence):char sentence[i word_length]self.right_neighbor[word][char] self.right_neighbor[word].get(char, 0) 1return④ 计算熵 sum()通过 sum(word_count_dict.values()) 计算所有单词的总出现次数
计算熵遍历每个单词的出现次数使用公式 -(c / total) * math.log((c / total), 10) 计算每个单词对熵的贡献并累加这些值
返回熵值将计算得到的熵值返回 #计算熵def calc_entropy_by_word_count_dict(self, word_count_dict):total sum(word_count_dict.values())entropy sum([-(c / total) * math.log((c / total), 10) for c in word_count_dict.values()])return entropy ⑤ 计算左右熵 Ⅰ 初始化空字典初始化两个空字典 self.word_left_entropy 和 self.word_right_entropy
Ⅱ 计算左熵遍历 self.left_neighbor对每个词调用 calc_entropy_by_word_count_dict 计算左熵并存入 self.word_left_entropy
Ⅲ 计算右熵遍历 self.right_neighbor对每个词调用 calc_entropy_by_word_count_dict 计算右熵并存入 self.word_right_entropy #计算左右熵def calc_entropy(self):self.word_left_entropy {}self.word_right_entropy {}for word, count_dict in self.left_neighbor.items():self.word_left_entropy[word] self.calc_entropy_by_word_count_dict(count_dict)for word, count_dict in self.right_neighbor.items():self.word_right_entropy[word] self.calc_entropy_by_word_count_dict(count_dict)⑥ 统计词长总数 Ⅰ 初始化初始化一个默认值为0的字典 self.word_count_by_length
Ⅱ 更新不同词长下的词总数遍历 self.word_count对于每个单词和它的计数根据单词长度更新 self.word_count_by_length #统计每种词长下的词总数def calc_total_count_by_length(self):self.word_count_by_length defaultdict(int)for word, count in self.word_count.items():self.word_count_by_length[len(word)] countreturn ⑦ 计算互信息 Ⅰ 初始化调用 calc_total_count_by_length 方法计算不同长度的词频总数
Ⅱ 初始化 PMI 字典创建一个空字典 self.pmi
Ⅲ 遍历词语遍历 self.word_count 中的每个词语及其出现次数
Ⅳ 计算词语概率计算词语的概率 p_word
Ⅴ 计算字符概率乘积计算组成该词语的每个字符的概率乘积 p_chars
Ⅵ 计算 PMI 值根据公式 math.log(p_word / p_chars, 10) / len(word) 计算 PMI并存入 self.pmi #计算互信息(pointwise mutual information 凝固度)def calc_pmi(self):self.calc_total_count_by_length()self.pmi {}for word, count in self.word_count.items():p_word count / self.word_count_by_length[len(word)]p_chars 1for char in word:p_chars * self.word_count[char] / self.word_count_by_length[1]self.pmi[word] math.log(p_word / p_chars, 10) / len(word)return ⑧ 计算每个词的价值
Ⅰ 初始化初始化 self.word_values 为空字典
Ⅱ 遍历 如果词长度小于2或包含逗号则跳过该词 获取词的PMI值、左熵和右熵若不存在则设为极小值1e-3 使用PMI、左熵和右熵综合评估词的价值公式为 pmi * max(le, re) def calc_word_values(self):self.word_values {}for word in self.pmi:if len(word) 2 or in word:continuepmi self.pmi.get(word, 1e-3)le self.word_left_entropy.get(word, 1e-3)re self.word_right_entropy.get(word, 1e-3)# 通过三个指标综合评估词的价值# self.word_values[word] pmi le re# self.word_values[word] pmi * min(le, re)self.word_values[word] pmi * max(le, re)# self.word_values[word] pmi le * re# self.word_values[word] pmi * le * re ⑨ 新词检测 Ⅰ 初始化创建 NewWordDetect 对象加载语料库
Ⅱ 计算特征计算词语的频率、左右邻词、PMI、左右熵等特征
Ⅲ 排序并输出根据总分对词语进行排序分别输出长度为2、3、4的前十个高分词
import math
from collections import defaultdictclass NewWordDetect:def __init__(self, corpus_path):# 设置词语最高长度 1 - 5 四个字的词语self.max_word_length 5self.word_count defaultdict(int)self.left_neighbor defaultdict(dict)self.right_neighbor defaultdict(dict)self.load_corpus(corpus_path)self.calc_pmi()self.calc_entropy()self.calc_word_values()#加载语料数据并进行统计def load_corpus(self, path):with open(path, encodingutf8) as f:for line in f:sentence line.strip()for word_length in range(1, self.max_word_length):self.ngram_count(sentence, word_length)return#按照窗口长度取词,并记录左邻右邻出现过的字及次数def ngram_count(self, sentence, word_length):for i in range(len(sentence) - word_length 1):word sentence[i:i word_length]self.word_count[word] 1if i - 1 0:char sentence[i - 1]self.left_neighbor[word][char] self.left_neighbor[word].get(char, 0) 1if i word_length len(sentence):char sentence[i word_length]self.right_neighbor[word][char] self.right_neighbor[word].get(char, 0) 1return#计算熵def calc_entropy_by_word_count_dict(self, word_count_dict):total sum(word_count_dict.values())entropy sum([-(c / total) * math.log((c / total), 10) for c in word_count_dict.values()])return entropy#计算左右熵def calc_entropy(self):self.word_left_entropy {}self.word_right_entropy {}for word, count_dict in self.left_neighbor.items():self.word_left_entropy[word] self.calc_entropy_by_word_count_dict(count_dict)for word, count_dict in self.right_neighbor.items():self.word_right_entropy[word] self.calc_entropy_by_word_count_dict(count_dict)#统计每种词长下的词总数def calc_total_count_by_length(self):self.word_count_by_length defaultdict(int)for word, count in self.word_count.items():self.word_count_by_length[len(word)] countreturn#计算互信息(pointwise mutual information 凝固度)def calc_pmi(self):self.calc_total_count_by_length()self.pmi {}for word, count in self.word_count.items():p_word count / self.word_count_by_length[len(word)]p_chars 1for char in word:p_chars * self.word_count[char] / self.word_count_by_length[1]self.pmi[word] math.log(p_word / p_chars, 10) / len(word)returndef calc_word_values(self):self.word_values {}for word in self.pmi:if len(word) 2 or in word:continuepmi self.pmi.get(word, 1e-3)le self.word_left_entropy.get(word, 1e-3)re self.word_right_entropy.get(word, 1e-3)# 通过三个指标综合评估词的价值# self.word_values[word] pmi le re# self.word_values[word] pmi * min(le, re)self.word_values[word] pmi * max(le, re)# self.word_values[word] pmi le * re# self.word_values[word] pmi * le * reif __name__ __main__:nwd NewWordDetect(sample_corpus.txt)value_sort sorted([(word, count) for word, count in nwd.word_values.items()], keylambda x:x[1], reverseTrue)print([x for x, c in value_sort if len(x) 2][:10])print([x for x, c in value_sort if len(x) 3][:10])print([x for x, c in value_sort if len(x) 4][:10])二、挑选重要词
假如一个词在某类文本假设为A类中出现次数很多而在其他类别文本非A类出现很少那么这个词是A类文本的重要词高权重词
反之如果一个词出现在很多领域则其对于任意类别的重要性都很差
是否能够根据一个词来区分其属于哪个领域 1.数学角度刻画重要词
TF · IDF刻画某一个词对于某一领域的重要程度
TF词频某个词在某类别中出现的次数/该类别词的总数
IDF逆文档频率N代表文本总数dfi代表包含词qi的文本中的总数
逆文档频率高 —— 该词很少出现在其他文档 和语料库的文档总数成正比和包含这个词的文档总数成反比
例 TF在某一分类的值越大则TF项在某一分类中更为重要例如a只出现在A文档中则a对A文档的标志性比较大
TF·IDF其他计算方式
TF
IDF
每个词对于每个类别都会得到一个TF·IDF值
TF·IDF高 - 该词对于该领域重要程度高低则相反 2.算法特点
1.tf · idf 的计算非常依赖分词结果如果分词出错统计值的意义会大打折扣
2.每个词对于每篇文档有不同的tf-idf值所以不能脱离数据讨论tf·idf
3.假如只有一篇文本不能计算tf·idf
4.类别数据均衡很重要
5.容易受各种特殊符号影响最好做一些预处理 3.算法示例
① 构建TF·IDF字典
Ⅰ 初始化字典
tf_dict记录每个文档中每个词的出现频率
idf_dict记录每个词出现在多少个文档中
Ⅱ 遍历语料库
对于每篇文档遍历其中的每个词更新tf_dict和idf_dict
Ⅲ 转换idf_dict
将idf_dict中的集合转换为文档数量
Ⅳ 返回结果
返回tf_dict和idf_dict
#统计tf和idf值
def build_tf_idf_dict(corpus):tf_dict defaultdict(dict) #key:文档序号valuedict文档中每个词出现的频率idf_dict defaultdict(set) #key:词 valueset文档序号最终用于计算每个词在多少篇文档中出现过for text_index, text_words in enumerate(corpus):for word in text_words:if word not in tf_dict[text_index]:tf_dict[text_index][word] 0tf_dict[text_index][word] 1idf_dict[word].add(text_index)idf_dict dict([(key, len(value)) for key, value in idf_dict.items()])return tf_dict, idf_dict ② 根据tf值和idf值计算tf·idf
Ⅰ 初始化
创建一个默认字典 tf_idf_dict 来存储每个文本中每个词的TF-IDF值
Ⅱ 遍历文本
遍历输入的 tf_dict其中键是文本索引值是该文本中每个词的词频计数字典
Ⅲ 计算TF
对于每个词计算其在当前文本中的词频TF即该词出现次数除以该文本中所有词的总次数
Ⅳ 计算TF·IDF
根据公式 tf · idf tf * log(D / (idf 1)) 计算TF·IDF值其中 D 是文本总数idf 是逆文档频率
Ⅴ 存储结果
将计算得到的TF-IDF值存入 tf_idf_dict 中
Ⅵ 返回结果
返回包含所有文本中每个词的TF-IDF值的字典
#根据tf值和idf值计算tfidf
def calculate_tf_idf(tf_dict, idf_dict):tf_idf_dict defaultdict(dict)for text_index, word_tf_count_dict in tf_dict.items():for word, tf_count in word_tf_count_dict.items():tf tf_count / sum(word_tf_count_dict.values())#tf-idf tf * log(D/(idf 1))tf_idf_dict[text_index][word] tf * math.log(len(tf_dict)/(idf_dict[word]1))return tf_idf_dict ③ 计算给定语料库中每个文档的TF-IDF值
Ⅰ分词处理
使用jieba.lcut对语料库中的每个文本进行分词
Ⅱ 构建TF和IDF字典
调用build_tf_idf_dict函数生成每个文档的词频TF字典和逆文档频率IDF字典
Ⅲ 计算TF-IDF
调用calculate_tf_idf函数根据TF和IDF字典计算每个文档的TF-IDF值
Ⅳ 返回结果
返回包含每个文档TF-IDF值的字典。
#输入语料 list of string
def calculate_tfidf(corpus):#先进行分词corpus [jieba.lcut(text) for text in corpus]tf_dict, idf_dict build_tf_idf_dict(corpus)tf_idf_dict calculate_tf_idf(tf_dict, idf_dict)return tf_idf_dict ④ 提取每个文本的前top个高频词
Ⅰ 初始化
创建一个空字典topk_dict用于存储结果
Ⅱ 遍历文本
遍历输入的tfidf_dict对每个文本的TF-IDF值进行排序取前top个词存入topk_dict
Ⅲ 打印输出
如果print_word为真则打印当前文本索引、路径及前top个词
Ⅳ 返回结果
返回包含每个文本前top个高频词的字典
#根据tfidf字典显示每个领域topK的关键词
def tf_idf_topk(tfidf_dict, paths[], top10, print_wordTrue):topk_dict {}for text_index, text_tfidf_dict in tfidf_dict.items():word_list sorted(text_tfidf_dict.items(), keylambda x:x[1], reverseTrue)topk_dict[text_index] word_list[:top]if print_word:print(text_index, paths[text_index])for i in range(top):print(word_list[i])print(----------)return topk_dict ⑤ tf·idf的计算和使用
import jieba
import math
import os
import json
from collections import defaultdict
tfidf的计算和使用
#统计tf和idf值
def build_tf_idf_dict(corpus):tf_dict defaultdict(dict) #key:文档序号valuedict文档中每个词出现的频率idf_dict defaultdict(set) #key:词 valueset文档序号最终用于计算每个词在多少篇文档中出现过for text_index, text_words in enumerate(corpus):for word in text_words:if word not in tf_dict[text_index]:tf_dict[text_index][word] 0tf_dict[text_index][word] 1idf_dict[word].add(text_index)idf_dict dict([(key, len(value)) for key, value in idf_dict.items()])return tf_dict, idf_dict#根据tf值和idf值计算tfidf
def calculate_tf_idf(tf_dict, idf_dict):tf_idf_dict defaultdict(dict)for text_index, word_tf_count_dict in tf_dict.items():for word, tf_count in word_tf_count_dict.items():tf tf_count / sum(word_tf_count_dict.values())#tf-idf tf * log(D/(idf 1))tf_idf_dict[text_index][word] tf * math.log(len(tf_dict)/(idf_dict[word]1))return tf_idf_dict#输入语料 list of string
#[xxxxxxxxx, xxxxxxxxxxxxxxxx, xxxxxxxx]
def calculate_tfidf(corpus):#先进行分词corpus [jieba.lcut(text) for text in corpus]tf_dict, idf_dict build_tf_idf_dict(corpus)tf_idf_dict calculate_tf_idf(tf_dict, idf_dict)return tf_idf_dict#根据tfidf字典显示每个领域topK的关键词
def tf_idf_topk(tfidf_dict, paths[], top10, print_wordTrue):topk_dict {}for text_index, text_tfidf_dict in tfidf_dict.items():word_list sorted(text_tfidf_dict.items(), keylambda x:x[1], reverseTrue)topk_dict[text_index] word_list[:top]if print_word:print(text_index, paths[text_index])for i in range(top):print(word_list[i])print(----------)return topk_dictdef main():dir_path rcategory_corpus/corpus []paths []for path in os.listdir(dir_path):path os.path.join(dir_path, path)if path.endswith(txt):corpus.append(open(path, encodingutf8).read())paths.append(os.path.basename(path))tf_idf_dict calculate_tfidf(corpus)tf_idf_topk(tf_idf_dict, paths)if __name__ __main__:main() 4.TF·IDF应用 —— 搜索引擎
① 对于已有的所有网页文本计算每个网页中词的TF·IDF值 Ⅰ 初始化
调用 jieba.initialize() 初始化分词工具
Ⅱ 读取文件
打开指定路径的文件并读取其中的 JSON 数据
Ⅲ 构建语料库
遍历每个文档将标题和内容拼接成一个字符串并添加到语料库列表中
Ⅳ 计算 TF-IDF
调用 calculate_tfidf 函数传入构建好的语料库计算每个文档的 TF-IDF 值
Ⅴ 返回结果
返回计算好的 TF-IDF 字典和语料库
#根据tfidf字典显示每个领域topK的关键词
def tf_idf_topk(tfidf_dict, paths[], top10, print_wordTrue):topk_dict {}for text_index, text_tfidf_dict in tfidf_dict.items():word_list sorted(text_tfidf_dict.items(), keylambda x:x[1], reverseTrue)topk_dict[text_index] word_list[:top]if print_word:print(text_index, paths[text_index])for i in range(top):print(word_list[i])print(----------)return topk_dict ② 对于一个输入query(查询)进行分词
对于文档D计算query中的词在文档D中的TF·IDF值总和作为query和文档的相关性得分
Ⅰ分词查询使用 jieba.lcut 对输入的查询进行分词
Ⅱ 计算得分遍历 tf_idf_dict 中的每篇文档根据查询词在文档中的 TF-IDF 值累加得分
Ⅲ 排序结果将所有文档按得分从高到低排序
Ⅳ 输出结果打印得分最高的前 top 篇文档内容并返回包含所有文档及其得分的结果列表。
def search_engine(query, tf_idf_dict, corpus, top3):query_words jieba.lcut(query)res []for doc_id, tf_idf in tf_idf_dict.items():score 0for word in query_words:score tf_idf.get(word, 0)res.append([doc_id, score])res sorted(res, reverseTrue, keylambda x:x[1])for i in range(top):doc_id res[i][0]print(corpus[doc_id])print(--------------)return res ③ TF·IDF实现简单搜索引擎
import jieba
import math
import os
import json
from collections import defaultdict
from calculate_tfidf import calculate_tfidf, tf_idf_topk基于tfidf实现简单搜索引擎
jieba.initialize()#加载文档数据可以想象成网页数据计算每个网页的tfidf字典
def load_data(file_path):corpus []with open(file_path, encodingutf8) as f:documents json.loads(f.read())for document in documents:corpus.append(document[title] \n document[content])tf_idf_dict calculate_tfidf(corpus)return tf_idf_dict, corpusdef search_engine(query, tf_idf_dict, corpus, top3):query_words jieba.lcut(query)res []for doc_id, tf_idf in tf_idf_dict.items():score 0for word in query_words:score tf_idf.get(word, 0)res.append([doc_id, score])res sorted(res, reverseTrue, keylambda x:x[1])for i in range(top):doc_id res[i][0]print(corpus[doc_id])print(--------------)return resif __name__ __main__:path news.jsontf_idf_dict, corpus load_data(path)while True:query input(请输入您要搜索的内容:)search_engine(query, tf_idf_dict, corpus) 5.TF·IDF应用 —— 文本摘要
抽取式摘要
① 加载文档数据并计算每个文档的TF·IDF值
Ⅰ 初始化调用 jieba.initialize() 初始化分词工具
Ⅱ 读取文件打开并读取文件内容解析为JSON格式的文档列表
Ⅲ 数据处理遍历每个文档确保标题和内容中不包含换行符然后将标题和内容拼接成一个字符串并加入语料库
Ⅳ 计算TF-IDF使用 calculate_tfidf 函数计算语料库的TF-IDF值
Ⅴ 返回结果返回TF-IDF字典和语料库
jieba.initialize()#加载文档数据可以想象成网页数据计算每个网页的tfidf字典
def load_data(file_path):corpus []with open(file_path, encodingutf8) as f:documents json.loads(f.read())for document in documents:assert \n not in document[title]assert \n not in document[content]corpus.append(document[title] \n document[content])tf_idf_dict calculate_tfidf(corpus)return tf_idf_dict, corpus ② 计算生成每一篇文章的摘要
Ⅰ 句子分割将文章按句号、问号、感叹号分割成句子列表
Ⅱ 过滤短文章如果文章少于5个句子返回None因为太短的文章不适合做摘要
Ⅲ 计算句子得分对每个句子进行分词并根据TF-IDF词典计算句子得分
Ⅳ 排序并选择重要句子根据句子得分排序选择得分最高的前top个句子并按原文顺序排列
Ⅴ 返回摘要将选中的句子拼接成摘要返回
#计算每一篇文章的摘要
#输入该文章的tf_idf词典和文章内容
#top为人为定义的选取的句子数量
#过滤掉一些正文太短的文章因为正文太短在做摘要意义不大
def generate_document_abstract(document_tf_idf, document, top3):sentences re.split(||。, document)#过滤掉正文在五句以内的文章if len(sentences) 5:return Noneresult []for index, sentence in enumerate(sentences):sentence_score 0words jieba.lcut(sentence)for word in words:sentence_score document_tf_idf.get(word, 0)sentence_score / (len(words) 1)result.append([sentence_score, index])result sorted(result, keylambda x:x[0], reverseTrue)#权重最高的可能依次是第10第6第3句将他们调整为出现顺序比较合理即3,6,10important_sentence_indexs sorted([x[1] for x in result[:top]])return 。.join([sentences[index] for index in important_sentence_indexs])③ 生成文档摘要并将摘要添加到原始文档中 Ⅰ 初始化结果列表创建一个空列表 res 用于存储最终的结果
Ⅱ 遍历文档通过 tf_idf_dict.items() 遍历每个文档的TF-IDF字典
Ⅲ 分割标题和内容从 corpus 中获取当前文档的内容并按换行符分割为标题和正文
Ⅳ 生成摘要调用 generate_document_abstract 函数生成摘要如果摘要为空则跳过该文档
Ⅴ 更新文档并保存结果将生成的摘要添加到原始文档中并将标题、正文和摘要存入结果列表
Ⅵ 返回结果返回包含所有文档摘要的信息列表
#生成所有文章的摘要
def generate_abstract(tf_idf_dict, corpus):res []for index, document_tf_idf in tf_idf_dict.items():title, content corpus[index].split(\n)abstract generate_document_abstract(document_tf_idf, content)if abstract is None:continuecorpus[index] \n abstractres.append({标题:title, 正文:content, 摘要:abstract})return res ④ TF·IDF实现简单文本摘要
import jieba
import math
import os
import random
import re
import json
from collections import defaultdict
from calculate_tfidf import calculate_tfidf, tf_idf_topk基于tfidf实现简单文本摘要
jieba.initialize()#加载文档数据可以想象成网页数据计算每个网页的tfidf字典
def load_data(file_path):corpus []with open(file_path, encodingutf8) as f:documents json.loads(f.read())for document in documents:assert \n not in document[title]assert \n not in document[content]corpus.append(document[title] \n document[content])tf_idf_dict calculate_tfidf(corpus)return tf_idf_dict, corpus#计算每一篇文章的摘要
#输入该文章的tf_idf词典和文章内容
#top为人为定义的选取的句子数量
#过滤掉一些正文太短的文章因为正文太短在做摘要意义不大
def generate_document_abstract(document_tf_idf, document, top3):sentences re.split(||。, document)#过滤掉正文在五句以内的文章if len(sentences) 5:return Noneresult []for index, sentence in enumerate(sentences):sentence_score 0words jieba.lcut(sentence)for word in words:sentence_score document_tf_idf.get(word, 0)sentence_score / (len(words) 1)result.append([sentence_score, index])result sorted(result, keylambda x:x[0], reverseTrue)#权重最高的可能依次是第10第6第3句将他们调整为出现顺序比较合理即3,6,10important_sentence_indexs sorted([x[1] for x in result[:top]])return 。.join([sentences[index] for index in important_sentence_indexs])#生成所有文章的摘要
def generate_abstract(tf_idf_dict, corpus):res []for index, document_tf_idf in tf_idf_dict.items():title, content corpus[index].split(\n)abstract generate_document_abstract(document_tf_idf, content)if abstract is None:continuecorpus[index] \n abstractres.append({标题:title, 正文:content, 摘要:abstract})return resif __name__ __main__:path news.jsontf_idf_dict, corpus load_data(path)res generate_abstract(tf_idf_dict, corpus)writer open(abstract.json, w, encodingutf8)writer.write(json.dumps(res, ensure_asciiFalse, indent2))writer.close()6.TF·IDF应用 —— 文本相似度计算
① 加载文档数据并计算TF-IDF值
Ⅰ 读取文件从指定路径读取JSON格式的文档数据
Ⅱ 构建语料库将每个文档的标题和内容拼接成一个字符串存入语料库列表
Ⅲ 计算TF-IDF调用calculate_tfidf函数计算语料库的TF-IDF值
Ⅳ 提取重要词调用tf_idf_topk函数提取每篇文档中TF-IDF值最高的前5个词
Ⅴ 构建词汇表将所有文档的重要词去重后存入集合最终转换为列表
Ⅵ 返回结果返回TF-IDF字典、词汇表和语料库。
jieba.initialize()#加载文档数据可以想象成网页数据计算每个网页的tfidf字典
#之后统计每篇文档重要在前10的词统计出重要词词表
#重要词词表用于后续文本向量化
def load_data(file_path):corpus []with open(file_path, encodingutf8) as f:documents json.loads(f.read())for document in documents:corpus.append(document[title] \n document[content])tf_idf_dict calculate_tfidf(corpus)topk_words tf_idf_topk(tf_idf_dict, top5, print_wordFalse)vocab set()for words in topk_words.values():for word, score in words:vocab.add(word)print(词表大小, len(vocab))return tf_idf_dict, list(vocab), corpus ② 将文章转换为向量 Ⅰ 初始化初始化一个长度为词汇表大小的零向量 vector
Ⅱ 分词使用 jieba.lcut 将文章分词为一个词语列表 passage_words
Ⅲ 更新词表遍历词汇表中的每个词计算其在文章中的出现频率并更新到 vector 中
Ⅳ 返回结果返回最终的向量
#passage是文本字符串
#vocab是词列表
#向量化的方式计算每个重要词在文档中的出现频率
def doc_to_vec(passage, vocab):vector [0] * len(vocab)passage_words jieba.lcut(passage)for index, word in enumerate(vocab):vector[index] passage_words.count(word) / len(passage_words)return vector ③ 文档转换为向量表示
Ⅰ 输入参数 corpus一个包含多个文档的列表每个文档是一个字符串 vocab词汇表一个包含所有可能单词的列表
Ⅱ 处理逻辑 使用列表推导式遍历语料库中的每个文档 c调用 doc_to_vec 函数将其转换为向量 doc_to_vec 函数会根据词汇表 vocab 计算文档中每个词的频率并返回一个向量表示 最终返回一个包含所有文档向量的列表 corpus_vectors
#先计算所有文档的向量
def calculate_corpus_vectors(corpus, vocab):corpus_vectors [doc_to_vec(c, vocab) for c in corpus]return corpus_vectors ④ 计算两个向量间的余弦相似度
计算点积通过 zip 函数将两个向量对应元素相乘并求和得到点积 x_dot_y
计算模长分别计算两个向量的模长 sqrt_x 和 sqrt_y
处理特殊情况如果任一向量的模长为0返回0
计算相似度返回点积除以两个模长的乘积并加上一个小常数 1e-7 防止分母为0
#计算向量余弦相似度
def cosine_similarity(vector1, vector2):x_dot_y sum([x*y for x, y in zip(vector1, vector2)])sqrt_x math.sqrt(sum([x ** 2 for x in vector1]))sqrt_y math.sqrt(sum([x ** 2 for x in vector2]))if sqrt_y 0 or sqrt_y 0:return 0return x_dot_y / (sqrt_x * sqrt_y 1e-7)⑤ 计算输入文本与语料库所有文档的相似度 Ⅰ 将输入文本转换为向量调用 doc_to_vec 方法将输入文本 passage 转换为词频向量 input_vec
Ⅱ 计算相似度遍历语料库中的每个文档向量使用 cosine_similarity 方法计算输入向量与每个文档向量的余弦相似度 向量夹角余弦值计算公式
Ⅲ 排序并返回结果将所有相似度分数按降序排列返回前4个最相似的文档索引及其相似度分数
#输入一篇文本寻找最相似文本
def search_most_similar_document(passage, corpus_vectors, vocab):input_vec doc_to_vec(passage, vocab)result []for index, vector in enumerate(corpus_vectors):score cosine_similarity(input_vec, vector)result.append([index, score])result sorted(result, reverseTrue, keylambda x:x[1])return result[:4] ⑥ TF·IDF实现文本相似度计算
#coding:utf8
import jieba
import math
import os
import json
from collections import defaultdict
from calculate_tfidf import calculate_tfidf, tf_idf_topk
基于tfidf实现文本相似度计算
jieba.initialize()#加载文档数据可以想象成网页数据计算每个网页的tfidf字典
#之后统计每篇文档重要在前10的词统计出重要词词表
#重要词词表用于后续文本向量化
def load_data(file_path):corpus []with open(file_path, encodingutf8) as f:documents json.loads(f.read())for document in documents:corpus.append(document[title] \n document[content])tf_idf_dict calculate_tfidf(corpus)topk_words tf_idf_topk(tf_idf_dict, top5, print_wordFalse)vocab set()for words in topk_words.values():for word, score in words:vocab.add(word)print(词表大小, len(vocab))return tf_idf_dict, list(vocab), corpus#passage是文本字符串
#vocab是词列表
#向量化的方式计算每个重要词在文档中的出现频率
def doc_to_vec(passage, vocab):vector [0] * len(vocab)passage_words jieba.lcut(passage)for index, word in enumerate(vocab):vector[index] passage_words.count(word) / len(passage_words)return vector#先计算所有文档的向量
def calculate_corpus_vectors(corpus, vocab):corpus_vectors [doc_to_vec(c, vocab) for c in corpus]return corpus_vectors#计算向量余弦相似度
def cosine_similarity(vector1, vector2):x_dot_y sum([x*y for x, y in zip(vector1, vector2)])sqrt_x math.sqrt(sum([x ** 2 for x in vector1]))sqrt_y math.sqrt(sum([x ** 2 for x in vector2]))if sqrt_y 0 or sqrt_y 0:return 0return x_dot_y / (sqrt_x * sqrt_y 1e-7)#输入一篇文本寻找最相似文本
def search_most_similar_document(passage, corpus_vectors, vocab):input_vec doc_to_vec(passage, vocab)result []for index, vector in enumerate(corpus_vectors):score cosine_similarity(input_vec, vector)result.append([index, score])result sorted(result, reverseTrue, keylambda x:x[1])return result[:4]if __name__ __main__:path news.jsontf_idf_dict, vocab, corpus load_data(path)corpus_vectors calculate_corpus_vectors(corpus, vocab)passage WGTfor corpus_index, score in search_most_similar_document(passage, corpus_vectors, vocab):print(相似文章:\n, corpus[corpus_index].strip())print(得分, score)print(--------------) 7.TF·IDF的优势
① 可解释性好
可以清晰地看到关键词
即使预测结果出错也很容易找到原因
② 计算速度快
分词本身占耗时最多其余为简单统计计算
③ 对标注数据依赖小
可以使用无标注语料完成一部分工作
④ 可以与很多算法组合使用
可以看做是词权重的体现 8.TF·IDF的劣势
① 受分词效果影响大
② 词与词之间没有语义相似度
同义词之间也不会进行关联不会被同等的对待
③ 没有语序信息
TF·IDF本质上是一个词袋模型计算搜索信息中每一个词的TF·IDF值的总和作为搜索信息与文档信息相关性的得分
④ 能力范围有限
无法完成复杂任务如机器翻译和实体挖掘等
深度学习可以处理几乎所有任务只是效果好坏区别同时可以考虑语序、考虑词与词之间的相似度、也不依赖分词的结果
⑤ 样本不均衡会对结果有很大影响
词的总数多少也会影响TF·IDF值的大小影响结果的好坏
⑥ 类内样本间分布不被考虑
将每篇独立的文章混合在一起导致TF·IDF值的计算有误差