python文本处理 – TF-IDF原理及实例演示
代码基于python 3.5.2
简要概述:
TF-IDF(Term Frequency-Inverse Document Frequency, 词频-逆文件频率).
是一种用于资讯检索与资讯探勘的常用加权技术。TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。
简言之:一个词语在某一文本中出现越多,在其他文本中出现越少,越能代表这一文本。
原理解释:
在理解原理之前,先理解其中的几个专有词汇:
语料(corpus):一组原始文本的集合,用于无监督地训练文本主题的隐层结构。语料中不需要人工标注的附加信息。在Gensim中,corpora是文档集的表现形式,也是后续进一步处理的基础。从本质上来说,corpora其实是一种格式或者说约定,其实就是一个二维矩阵。
向量(vector):由一组文本特征构成的列表。是一段文本在Gensim中的内部表达。
词典(dictionary):是所有文档中所有单词的集合,而且记录了各词的出现次数等信息。
词频 (term frequency, TF) :
某一个给定的词语在该文件中出现的次数。这个数字通常会被归一化(一般是词频除以文章总词数), 以防止它偏向长的文件。(同一个词语在长文件里可能会比短文件有更高的词频,而不管该词语重要与否。)
公式:
逆向文件频率 (inverse document frequency, IDF):
IDF的主要思想是:文件夹中包含多份文档,如果包含词条w的文档越少, IDF越大,则说明词条具有很好的类别区分能力。某一特定词语的IDF,可以由总文档数目除以包含该词语之文档的数目,再将得到的商取对数得到。
公式:
实例演示
实例说明
需求说明:货品表_20180529.xlsx文件中数据,与数据库语料库相似度分析,找出文件中数据相对应的语料库中数据的id值
货品表_20180529.xlsx文件中数据
商品名 | 批准文号 | 生产厂商 |
---|---|---|
复方利血平片 | 国药准字H14023613 | 亚宝药业集团股份有限公司 |
富马酸比索洛尔片 | 国药准字H20083008 | 成都苑东药业有限公司 |
琥珀酸美托洛尔缓释片(倍他乐克) | 国药准字J20150044 | 阿斯利康制药有限公司 |
复方罗布麻片I) | 国药准字H14023317 | 山西云鹏制药有限公司 |
坎地沙坦酯片(维尔亚) | 国药准字H20030771 | 重庆圣华曦药业股份有限公司 |
阿替洛尔片 | 国药准字H37023046 | 山东信谊制药有限公司 |
代码演示:
from gensim import corpora, models, similarities
import pandas as pd
import jieba
import pymysql
import logging
import os
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO) gensim中标准日志打印格式
class InfoMatch(object):
def __init__(self):
self.conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
passwd='123456',
db='drug_base',
charset='utf8'
)
self.cur = self.conn.cursor()
def run(self):
# 判断如果有文件就不需要重复读取
if os.path.exists('./tmp/basedata.mm') and os.path.exists('./tmp/basedata.dict'): #判断是否已经将语料字典保存,如果有,则直接读取保存文件,节省运算
corpus = corpora.MmCorpus('./tmp/basedata.mm')
dictionary = corpora.Dictionary.load('./tmp/basedata.dict')
else:
base_data = self.get_base_data()
# 基础数据建立字典
dictionary = corpora.Dictionary(base_data) # 生成字典和向量语料
# 数据未set集合 示例如下,将分解的词条给予固定的编号
# {'甲醚': 19713, 'Z34020679': 79945, 'H51023978': 9391, '油胶': 5818,'Z15021352': 143447, '归羊': 159815, '附桂骨': 122230,....}
corpus = [dictionary.doc2bow(text) for text in base_data] # 基础数据向量化
# 将向量化内容存储到文件中
dictionary.save('./tmp/basedata.dict')
corpora.MmCorpus.serialize('./tmp/basedata.mm', corpus) 数据存储到本地
# 建立tfidf模型
tfidf_model = models.TfidfModel(corpus)
corpus_tfidf = tfidf_model[corpus]
if os.path.exists('./tmp/basedata.lsi'): #判断本地是否有lsi数据
lsi = models.LsiModel.load('./tmp/basedata.lsi')
else:
pass
# 使用LSI模型进行相似度计算
# lsi = models.LsiModel(corpus_tfidf, id2word=dictionary, num_topics=5)
lsi = models.LsiModel(corpus_tfidf, num_topics=5)
lsi.save('./tmp/basedata.lsi')
corpus_lsi = lsi[corpus_tfidf]
# 为LSI模型建立序列号
index = similarities.MatrixSimilarity(corpus_lsi)
# 获取分析数据
raw_data = self.get_test_data()
id_list = []
lsi_list = []
for indexs in raw_data.index:
try:
data = list(raw_data.loc[indexs].values[:]) #将待分析数据分析
test_data = []
for text in data:
if text != 0:
test_data.extend(list(jieba.cut(text)))
test_corpus = dictionary.doc2bow(test_data)
test_corpus_tfidf = tfidf_model[test_corpus]
test_corpus_tfidf_lsi = lsi[test_corpus_tfidf]
sims = index[test_corpus_tfidf_lsi] # 待分析数据的lsi模型在语料库的lsi模型中查找对应的序列号
sort_sims = sorted(enumerate(sims), key=lambda item: -item[1])[0]
id_num = int(sort_sims[0])+1
lsi_num = sort_sims[1]
id_list.append(id_num)
lsi_list.append(lsi_num)
print('第{}行完成匹配'.format(indexs))
except Exception as e:
print('第{}行发生{}错误'.format(indexs, e))
self.save(raw_data, id_list, lsi_list) # 保存数据
def get_base_data(self): #从mysql中提取语料库,使用jieba将语料库分词
try:
sql = "select drugName, licenseNumber, productionEnterprise from controlApp_drugdetailmsg"
self.cur.execute(sql)
base_data = self.cur.fetchall()
list_base_data = []
for data in base_data:
text_data = []
for text in data:
text_data.extend(list(jieba.cut(text)))
list_base_data.append(text_data)
return list_base_data
except Exception as e:
print(e)
finally:
self.conn.close()
def get_test_data(self):
try:
df = pd.read_excel('./货品表_20180529.xlsx') #利用pandas 读取xlsx格式数据,并提取出需相似性对比的数据
df.fillna(0, downcast='infer', inplace=True) #将pandas读取未NAN的值用 0 填充
raw_data = df[['商品名', '批准文号', '生产厂商']]
return raw_data
except Exception as e:
print(e)
def save(self, raw_data, id_list, lsi_list):
# raw_data.reindex(columns=['drugName', 'licenseNumber', 'productionEnterprise', 'matchId'], fill_value=id_list)
raw_data['匹配id'] = id_list
raw_data['匹配值'] = lsi_list
print(raw_data)
raw_data.to_csv('./match.xlsx')
if __name__ == '__main__':
info_match = InfoMatch() #创建实例,并运行run()方法
info_match.run()