NLP自然语言 之 TF-IDF(二)

前言

前面一篇文章我们了解到了如何基于余弦相似度的计算方式去评估两个句子或者文章的相似程度。那么本篇我们就从一篇文章中提取当中的关键词,来获取一篇文章所要表达的意思。即TF-IDF

TF(词频)

一个词在文档(文章)中出现的次数

  • 假设一个词很重要应该会在文档(文章)中多次出现
  • 过滤掉停用词(的、是、在等),停用词必须过滤,对结果毫无帮助
  • 假设一个词比较少见,但是它在这篇文章中多次出现,那么它很可能就反应出这篇文章的特性,也就是我们需要的关键字

或者

IDF(反文档频率)

在词频的基础上赋予每一个词的权重,进一步体现该词的重要性(计算权重)

  • 最常见的词(“的”,“是”,“在”等)给与最小权重,或者过滤
  • 较常见的词(“国内”,“中国“等)给与较小权重
  • 较少见的词(“养殖”,“维基”等)给与较大权重

TF-IDF公式

某个词对文中重要性越高,该值就越大,于是排在前面的几个词就是这篇文章的关键词

TF-IDF整体代码实现(获取一篇文章中的关键字)

代码思路:

  • 根据文件获取停用词
  • 循环目录读取对应的文件
  • 计算每个文件当中所有词的词频
  • 计算所有文件所有词的idf(反文档频率)
  • 计算一篇文章中的tf-idf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# coding=utf-8
import os
import math

dir_path = "data"
doc_dict = dict()
index = 0

# 获取停用词
stopWords = set()
lines = open("stop-word", 'r')
for line in lines:
if len(line.strip()) == 0:
continue
stopWords.add(line.strip())

# 循环读取目录下所有文件,组装数据。计算每篇文章中词的词频
# doc_dict['doc_name',doc_dict['word','tf']]
for file_name in os.listdir(dir_path):
file_path = dir_path + "/" + file_name
index += 1
word_dict = dict()
# 每篇文章的总词数
sum_cnt = 0
# 循环每行读取文章
for line in open(file_path, 'r'):
if len(line.strip()) == 0:
continue
for word in line.strip().split(" "):
if len(word.strip()) == 0:
continue
if word in stopWords:
continue
if word_dict.get(word, -1) == -1:
word_dict[word] = 1
else:
word_dict[word] += 1
sum_cnt += 1
# 计算每篇文章中每个词的词频
for word in word_dict.keys():
tmp = word_dict[word] / float(sum_cnt)
word_dict[word] = tmp
# print "%s %f %d" % (word, word_dict[word], sum_cnt)
doc_dict[file_name] = word_dict

doc_num = float(index)

# 统计每篇文章中的词在几篇文章中出现,用于计算idf
# doc_dict['word','in_doc_num']
doc_freq = dict()
for doc in doc_dict:
for word in doc_dict[doc].keys():
if doc_freq.get(word, -1) == -1:
doc_freq[word] = 1
else:
doc_freq[word] += 1

# 套idf公式计算每个词的idf
for word in doc_freq.keys():
doc_freq[word] = math.log(doc_num/float(doc_freq[word]+1))
# print "%s %f" % (word, doc_freq[word])

# 找出一篇文章中的关键字,倒序
for doc in doc_dict:
doc_word_list = []
for word in doc_dict[doc].keys():
# tf * idf
doc_word_list.append((word, doc_dict[doc][word] * doc_freq[word]))
doc_word_list.sort(key=lambda x:x[1], reverse = True)
if doc == '1597auto.seg.cln.txt':
for x in doc_word_list:
print "%s,%f" % (x[0], x[1])
1
2
3
4
5
6
7
8
9
1597auto.seg.cln.txt 这篇文章中的关键词如下 top 8
宁波,0.060776
英尺,0.030984
磅,0.025818
群,0.025640
保养,0.024436
奥迪,0.021913
车友,0.018964
冲击感,0.016728

总结

  • 优点:简单快速,结果比较符合实际情况
  • 缺点:单纯以“词频”做衡量标准,不够全面,有时候重要的词可能出现的次数并不多。这种算法无法体现词的位置信息,出现位置靠前的词与靠后的词都被视为相同的重要性,这是不正确的。(一种解决办法是,将文章中的第一段和每一段的第一句话给与较大的权重)

代码:https://github.com/lishijia/py-data-demo/tree/master/nlp

NLP自然语言 之 余弦相似度 (一 Python代码实现)

参考链接

分享到 评论