中文自然语言处理分析
和拉丁语系不同,亚洲语言是不用空格分开每个有意义的词的。而当我们进行自然语言处理的时候,大部分情况下,词汇是我们对句子和文章理解的基础,因此需要一个额外的分词工具去把完整的文本中分解成粒度更细的词。
1.1 关键词提取
1.1.1 基于 TF-IDF 算法的关键词抽取
import jieba.analyse
- jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
- sentence 为待提取的文本,无需分词
- topK 为返回几个 TF/IDF 权重最大的关键词,默认值为 20
- withWeight 为是否一并返回关键词权重值,默认值为 False
- allowPOS 仅包括指定词性的词,默认值为空,即不筛选
以科技新闻为例:
import jieba.analyse as analyse
import pandas as pd
df = pd.read_csv("/jhub/students/data/course11/项目2/origin_data/technology_news.csv", encoding='utf-8')
df = df.dropna()
lines=df.content.values.tolist()
content = "".join(lines)
keywords = analyse.extract_tags(content, topK=30, withWeight=False, allowPOS=())
print(keywords)
1.1.2 基于 TextRank 算法的关键词抽取
- jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=(‘ns’, ‘n’, ‘vn’, ‘v’)) 直接使用,接口相同,注意默认过滤词性。
- jieba.analyse.TextRank() 新建自定义 TextRank 实例
算法论文: TextRank: Bringing Order into Texts
基本思想:
- 将待抽取关键词的文本进行分词
- 以固定窗口大小(默认为5,通过span属性调整),词之间的共现关系,构建图
- 计算图中节点的PageRank,注意是无向带权图
用TextRank提取来提取关键词,用PageRank的思想来解释它:
- 如果一个单词出现在很多单词后面的话,那么说明这个单词比较重要
- 一个TextRank值很高的单词后面跟着的一个单词,那么这个单词的TextRank值会相应地因此而提高
import jieba.analyse as analyse
import pandas as pd
df = pd.read_csv("/jhub/students/data/course11/项目2/origin_data/military_news.csv", encoding='utf-8')
df = df.dropna()
lines=df.content.values.tolist()
content = "".join(lines)
print(" ".join(analyse.textrank(content, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v')))) # ("ns", "n", "vn", "v"))表示词性为地名、名词、动名词、动词
print("---------------------我是分割线----------------")
print(" ".join(analyse.textrank(content, topK=20, withWeight=False, allowPOS=('ns', 'n'))))
由实验结果,可以发现:
- TextRank与TFIDF均严重依赖于分词结果——如果某词在分词时被切分成了两个词,那么在做关键词提取时无法将两个词黏合在一起(TextRank有部分黏合效果,但需要这两个词均为关键词)。因此是否添加标注关键词进自定义词典,将会造成准确率、召回率大相径庭。
- TextRank的效果并不优于TFIDF。
- TextRank虽然考虑到了词之间的关系,但是仍然倾向于将频繁词作为关键词。
此外,由于TextRank涉及到构建词图及迭代计算,所以提取速度较慢。
1.2 LDA主题模型
首先我们要把文本内容处理成固定的格式,一个包含句子的list,list中每个元素是分词后的词list。类似下面这个样子。
[[第,一,条,新闻,在,这里],[第,二,条,新闻,在,这里],[这,是,在,做, 什么],…]
from gensim import corpora, models, similarities
import gensim
1.2.1 载入停用词
import pandas as pd
stopwords=pd.read_csv("/jhub/students/data/course11/项目2/origin_data/stopwords.txt",index_col=False,quoting=3,sep="\t",names=['stopword'], encoding='utf-8')
stopwords=stopwords['stopword'].values
1.2.2 转换成合适的格式
import jieba
df = pd.read_csv("/jhub/students/data/course11/项目2/origin_data/technology_news.csv", encoding='utf-8')
df = df.dropna()
lines=df.content.values.tolist()
sentences=[]
for line in lines:
try:
segs=jieba.lcut(line)
segs = list(filter(lambda x:len(x)>1, segs))
segs = list(filter(lambda x:x not in stopwords, segs))
sentences.append(list(segs))
except Exception as e:
print(line)
continue
# 处理完格式为[[第,一,条,新闻,在,这里],[第,二,条,新闻,在,这里],[这,是,在,做, 什么],...]
print(sentences[:2])
# 看一眼
for word in sentences[5]:
print(word)
注意:python2和python3的区别,python2直接segs = list(filter(lambda x:len(x)>1, segs))
即可,不需要加list。
1.2.3 词袋模型
dictionary = corpora.Dictionary(sentences) # 根据现有数据生成词典
print(dictionary)
corpus = [dictionary.doc2bow(sentence) for sentence in sentences] # 对每句话,统计每个词语的频数,组成词袋模型
corpus[5] # 第5句话的词袋表示,意思为字典中index为21的词语出现了1次,index为25的词语出现了1次…………index为138的词语出现1次
1.2.4 LDA建模
# lda训练 corpus=转化为词袋的词语列表 id2word=词典 num_topics=主题数量
lda = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=20)
``
`
我们查一下20个主题中的第3号分类,其中最常出现的头5个单词是:
```python
print(lda.print_topic(3, topn=5))
我们把所有的主题打印出来看看
for topic in lda.print_topics(num_topics=20, num_words=4):
print(topic[1])
我们可以对新加入的文本,进行简单主题分类:
lda.get_document_topics(bow)
其中bow为新文本的词袋。如:
text5 = ['徐立', '商汤', '科技', 'CEO', '谈起', '本次', '参展', '谈到', '成立', '刚刚', '两年', '创业', '公司', '参展', '展示', '最新', '人工智能', '技术', '产品', '表达', '人工智能', '理解', '人工智能', '特定', '领域', '超越', '人类', '广泛应用', '标志', 'Master', '胜利', '围棋', '世界', '开拓', '局面', '不谋而合']
bow = dictionary.doc2bow(text5)
ndarray = lda.inference([bow])[0]
print(''.join(text5))
for e, value in enumerate(ndarray[0]):
print('主题%d推断值%.2f' % (e, value))