from bs4 import BeautifulSoup import os, re, warnings, pickle, jieba, numpy as np, pandas as pd from gensim.models import KeyedVectors import traceback, logging from tkinter.messagebox import * import tkinter, functools from scipy.spatial.distance import pdist """ initial parameters: num_words 只使用前2599999个中文词做测试----目前作为测试,生产过程可以全部使用 在这个预训练词向量模型中,一共有大约260万词汇量 embedding_dim 词向量数----该值是基于sgns.zhihu.bigram中的维度来设定 path_checkpoint 建立一个权重的存储点 SAVE_HTML_FILE_PATH 保存html的文件路径 save_excel 最后预测完成所生成的excel文件 similarity_value 比较两个句子的相似程度 取值0-1 值越小越代表相似度越低 high_weight_sentence 高权重句子分类后的excel表名称 sentiment_hot_code 3 6 9 12 (一般聊天, app和群内问题, 知识点问题, 机构评价老师评判) """ """ analysis principle: first-> 得到的数据通过sgns.zhihu.bigram 得到该句子的向量(每一个单词词向量累加 ) second-> 归一化处理所有数据 third-> 使用模型预测 """ num_words = 2599999 embedding_dim = 300 path_checkpoint = 'Model' save_html_file_path = 'datas' # 本次采用的是 sgns.zhihu.bigram 词向量模型 大家可以网上下载 word_vector_model = 'sgns.zhihu.bigram' save_excel = '预测后的分类.xlsx' high_weight_sentence = 'highWeightSentence.xlsx' similarity_value = 0.7 sentiment_hot_code = 6 # 忽略一些 deprecate 警告 warnings.filterwarnings("ignore") # 将所有维度保存成字典 字典是{'句子内容':[句子维度, 句子分类]} all_of_sentence_dimension_dictionary = {} def use_BeautifulSoup_invoke_html_file_contents_final_writeTo_excel(): dir_contains_file = os.listdir(save_html_file_path) all_data_reverseTo_dic = {'sentiments': [], 'content': [], } # 打开模型 with open(path_checkpoint, 'rb') as file: model = pickle.load(file) print('*****************************************************') print('Invoke WordVector') cn_model = KeyedVectors.load_word2vec_format(word_vector_model, binary=False, unicode_errors="ignore") for flag, i in enumerate(dir_contains_file): # 拼接正常的文件地址 file_path = save_html_file_path + '/' + i # 打开文件,read() with open(file_path, 'rb') as o: binary_datas = o.read() # 再利用BeautifulSoup进行html节点拆分,通过搜索'pre'元素得到想要的聊天内容 print('*****************************************************') print('Parsing HTML Tree Constructor -> id (%d) page' % flag) initial_text = BeautifulSoup(binary_datas, 'lxml').select('pre') # 将得到的'pre'标签内的所有数据进行遍历 for j in initial_text: # 将dom树中的数据提取成字符串 extract_text = j.text.strip() if '@' in extract_text: # 第一步处理 由于微信中@后边一般都是人名,对语言数据起到噪点作用,需要提前剔除。 first_execute_text = ''.join(re.split(r'@.+', ''.join(re.split(r'@.+ +', ''.join(re.split(r'@.+\u2005+', extract_text)) ) ) ) ) # 保留正常文字,剔除符号 execute_after_text = ''.join(re.findall('[\u4e00-\u9fa5a-zA-Z0-9]+', first_execute_text, re.S)) # 如果遇到空字符串或带有XML字眼的str都是不需要的文字 # 则继续遍历 if execute_after_text == '' or 'xml' in execute_after_text: continue # 将需要预测的语言和词向量模型以及模型传入 sentiment = predict_sentiment(execute_after_text, cn_model, model) all_data_reverseTo_dic['sentiments'].append(sentiment) all_data_reverseTo_dic['content'].append(execute_after_text) elif 'http' in extract_text or 'xml' in extract_text: continue else: execute_after_text = ''.join(re.findall('[\u4e00-\u9fa5a-zA-Z0-9]+', extract_text, re.S)) if execute_after_text == '': continue # 使用预测方法将语句预测出情感并添加到字典中 sentiment = predict_sentiment(execute_after_text, cn_model, model) all_data_reverseTo_dic['sentiments'].append(sentiment) all_data_reverseTo_dic['content'].append(execute_after_text) # 保存数据 all_of_datas_and_cosine_similarity_after_compared_collection_dictionary = {} # 遍历循环所有句子的维度并将句子维度一一对比 for key, values in zip(all_of_sentence_dimension_dictionary.keys(), all_of_sentence_dimension_dictionary.values()): # 设置一个counts得分 cosine_similarity_compara_result_counts = 0 if values[1] == sentiment_hot_code: for j in all_of_sentence_dimension_dictionary.values(): # 比较句子维度的余弦值 if j[1] == sentiment_hot_code: cosine_similarity_value = 1 - pdist(np.vstack([values[0], j[0]]), 'cosine') # 如果一一列举时,两个句子的余弦相似度大于similarity_value说明两句子相似程度非常高,则把余弦得分+1 if cosine_similarity_value >= similarity_value: cosine_similarity_compara_result_counts += 1 # 将余弦值大于0.7的 cosine_similarity_compara_result_counts (计数) 插入到字典 # 该字典是 用每一个句子和其他句子比较,将余弦值大于similarity_value的记录。该字典的K是该句子,V是 [匹配后于其他句子余弦相似度比值大于similarity_value的个数, 该句子的分类(3是闲聊,6是app问题,9是专业问题,12是机构和老师赞贬)] all_of_datas_and_cosine_similarity_after_compared_collection_dictionary[key] = \ [cosine_similarity_compara_result_counts, values[1]] # 利用排序工具将一个对象按照我们自定义的规则进行排列 for t in sorted({k:v for k, v in all_of_datas_and_cosine_similarity_after_compared_collection_dictionary.items() if v[1] == 6}.items(), key=functools.cmp_to_key(custmor_Sort) ): print(t) pd.DataFrame(all_data_reverseTo_dic).to_excel(save_excel) print('*****************************************************') print('All of Work Complete, Save A .xlsx file was %s' % save_excel) """ Tools Method """ # 预测情绪 def predict_sentiment(text, cn_model, model): # 分词 cut = jieba.cut(text) # 创建一个变量来保存所有句子 sentence_vector = None for i, word in enumerate(cut): try: # 1. 很有可能得是: 一个词在词向量中并无对应,所以要try catch # 2. cn_model[word].copy() 得原因是 该情况瞎numpy 返回的数据类型只支持读不支持写 会抛出ValueError: output array is read-only # 所以使用cn_model[word].copy() 复制一份,在内存中独立占据空间,这样就可以操作了。 # 或者 使用 sentence_vector = sentence_vector + cn_model[word] if sentence_vector is None: sentence_vector = cn_model[word].copy() else: # 词组 维度累加 得到一个最终句子的维度 sentence_vector += cn_model[word].copy() except KeyError: continue if sentence_vector is not None: # 归一化处理 sentence_vector_max = sentence_vector.max() sentence_vector_min = sentence_vector.min() new_sentence_vector = \ np.array([(i - sentence_vector_min) / (sentence_vector_max - sentence_vector_min) for i in sentence_vector]) result = model.predict([new_sentence_vector]) # 将一个句子对应一个维度 all_of_sentence_dimension_dictionary[text] = [sentence_vector, result[0]] return result[0] elif sentence_vector is None: # 如果句子维度是空的话,直接产生一个(300,)维度的数组,填补到句子维度中 new_sentence_vector = np.zeros(embedding_dim, ) result = model.predict([new_sentence_vector]) # 将一个句子对应 [一个维度, 一个分类] all_of_sentence_dimension_dictionary[text] = [new_sentence_vector, result[0]] return result[0] # 个人定义的比较工具 def custmor_Sort(x, y): return y[1][0] - x[1][0] if __name__ == '__main__': # try: use_BeautifulSoup_invoke_html_file_contents_final_writeTo_excel()