TF-IDF(词频-逆向文档频率),想要达到的目的是用语料中的词语,来代表这个语料想要表达的意思。其作用可用于对文档提取关键词,关键字。其思想用中文来表达其实很直观,什么样的词语能够代表一个文档呢,最极端的状况当然是这个词在所有的文档集合中,只出现在这个文档,而其他文档是没有出现过的。
这里面涉及到了两个量的计算 TF=某次在文档集合中出现的次数/文档集合中的总词数目 ,因为要表达出频数,所以需要除以总次数。 IDF=log(语料库中的文档数/(包含该词的文档数+1))。TF-IDF = TF*IDF。可以看出,当某词出现的次数越多时,TF则越大;而当包含该词的文档数越少时(加1是为了防止分母为0),IDF的值就越大(语料库中文档数一定),因此当某词的TF-IDF越大时,这个词就越能够代表这篇文章。
为什么会想到用TF-IDF来做酒店名称的匹配呢。项目中一开始我用普通的正则表达式去匹配,发现效果不好,一些显性看上去是同一个酒店的,却匹配不出来。像如下例子:佛山7天酒店(南海大道7号店),佛山7天快捷酒店(南海大道店),像这种直接去构造.佛.山.7.天.快.捷.酒.店.南.海.大.道.店.这样的正则表达式是匹配不出来的,因为多了一些快捷酒店之类的字眼。所以就想通过TF-IDF,提取酒店名称中的关键字,再将关键字按顺序用.连接在一起,以达到更好的匹配效果。如提取关键字后,后一个酒店名称的关键字是[‘7天’,’南海大道’],拼接之后 .*7天.南海大道.*,通过这个样式就可以达到匹配得效果。下面利用gensim来简单快捷地实现这个功能(但实际上用gensim是在绕圈圈的)。整个代码如下所示。
def hotel_name_tfidf():
jieba.load_userdict('hotel.txt') #导入文件
hotel_name = pd.read_csv('hotel_name.txt')#利用pandas导入文件
hotel_name_list = hotel_name['hotel_name'].tolist()#类型转换
hotel_name_list_clean =[hotel_name1.replace('(','') for hotel_name1 in hotel_name_list]#简单清洗名称
hotel_name_fenci = [jieba.lcut(hotel_name2) for hotel_name2 in hotel_name_list_clean]#结巴分词
#精彩由此开始
dictionary = corpora.Dictionary(hotel_name_fenci)#一
corpus = [dictionary.doc2bow(text) for text in hotel_name_fenci]#二
tfidf = models.TfidfModel(corpus)#三
i=0
result = []
for name in hotel_name_fenci:
str=''
hotel_name_2_index = dict([(w,dictionary.token2id[w]) for w in name])#四
for x in hotel_name_2_index.keys():#四
if dict(tfidf[corpus[i]])[hotel_name_2_index[x]] >0.26:#四
str = str +'.*'+ x
result.append(str)
i = i+ 1
return result
- 1
一处解释:首先利用gensim的corpora.Dictionary的方法,将整个语料中的酒店名称分词后结果转换为 {index:word}的一个列表,形如[{0:’酒店’},{1:’快捷酒店’}…….]
二处解释:这里用到了dictionary.doc2bow(text)的方法,是根据之前创建的dictionary,将一个text(这里既是指酒店名称分词后的结果)转换为(index,该词在该text中的词频),注意这里的词频是指在当前那个text中的词频,形如[(0,1),(2,2),(3,1)…]
三处解释:models.TfidfModel(corpus) 这个方法就很直接了,就是计算每个text中每个词的tf-idf的值。形如[(0,0.14),(1,0.23),(7,0.34)….]。到这一步,可以说已经完成了计算。但是这样的表达非常不直观啊。最理想的表达是表现成[{‘佛山’:0.14},{‘7天’:0.34},{‘酒店’:0.06}…],所以有了以下的解释,分几步完成。
四处解释:dictionary.token2id[w] token2id 这个方法返回的是{word:index}的效果,而w在这里表现的就是word,所以这里的作用是将某一条的text转换为[{word:index}…]的形式,如[{‘佛山’:5},{‘7天’:10},{‘酒店’:0}]。hotel_name_2_index.keys()是获取上面这个list中的字典的索引,及‘佛山’,‘7天’,‘酒店’。dict(tfidf[corpus[i]])[hotel_name_2_index[x]] tfidf[corpus[i]]得到的是语料中第i个酒店名称中词的tf-idf值,hotel_name_2_index[x]得到的是某个词对应的在字典中的索引,两者结合就得到了如上的效果!就是[{‘佛山’:0.14},{‘7天’:0.34},{‘酒店’:0.06}…]这样~。
然后将转换的结果,根据一定的阈值,选择出相对重要的词语,然后用.*拼接在一起,就可以作为样式去匹配了。这里还有一个问题,就是阈值是怎么设置,其实一开始不想设阈值,而是取tf-idf最大的3个值,不过后来偷懒了就先这样,这个后面还可以研究一下阈值的问题。
谢谢各位看官!!