通过计算所提供的数据库中的金庸小说的信息熵,熟悉自然语言处理的方法与过程。
1948年,为了解决信息量化的问题,香农从热力学中借用了热熵的概念提出了“信息熵”的概念,把信息中排除了冗余后的平均信息量称为“信息熵”,并给出了计算信息熵的数学表达式。
H ( X ) = ∑ x ∈ χ p ( x ) l o g p ( x ) H(X)=\sum_{x∈χ} p(x)logp(x) H(X)=x∈χ∑p(x)logp(x)
信息论之父克劳德·香农给出的信息熵的三个性质[1]:
jieba.cut
方法接受三个输入参数: 需要分词的字符串;cut_all 参数用来控制是否采用全模式;HMM 参数用来控制是否使用 HMM 模型jieba.cut_for_search
方法接受两个参数:需要分词的字符串;是否使用 HMM 模型。该方法适合用于搜索引擎构建倒排索引的分词,粒度比较细jieba.cut
以及 jieba.cut_for_search
返回的结构都是一个可迭代的 generator,可以使用 for 循环来获得分词后得到的每一个词语(unicode),或者用jieba.lcut
以及 jieba.lcut_for_search
直接返回 listjieba.Tokenizer(dictionary=DEFAULT_DICT)
新建自定义分词器,可用于同时使用不同词典。jieba.dt
为默认分词器,所有全局分词相关函数都是该分词器的映射载入辞典
dict.txt
一样,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。file_name
若为路径或二进制方式打开的文件,则文件必须为 UTF-8 编码。调整词典
add_word(word, freq=None, tag=None)
和 del_word(word)
可在程序中动态修改词典。suggest_freq(segment, tune=True)
可调节单个词语的词频,使其能(或不能)被分出来。基于 TF-IDF 算法的关键词抽取
import jieba.analyse
数据集大小,size: 5457833
信息熵:12.144266718132455
分词结果:
‘只得’, ‘罢了’, ‘好’, ‘在’, ‘双儿’, ‘为’, ‘人’, ‘温柔’, ‘谦和’, ‘和’, ‘六位’, ‘夫人’, ‘个个’, ‘情谊’, ‘甚好’, ‘大家’, ‘也’, ‘不’, ‘妒嫉’, ‘于’, ‘她’, ‘只’, ‘建宁’, ‘建宁公主’, ‘宁公主’, ‘公主’, ‘自忖’, ‘以’, ‘皇上’, ‘御’, ‘妹’, ‘的’, ‘身分’, ‘分金’, ‘金枝’, ‘金枝玉叶’, ‘玉叶’, ‘居然’, ‘还’, ‘及’, ‘不’, ‘上’, ‘一个’, ‘出身’, ‘微贱’, ‘的’, ‘小丫头’, ‘丫头’, ‘心中’, ‘着实’, ‘气恼’, ‘不过’, ‘七位’, ‘夫人’, ‘人平’, ‘平时’, ‘若’, ‘有’, ‘纷争’, ‘其余’, ‘六’, ‘人’, ‘一定’, ‘联盟’, ‘对付’, ‘公主’, ‘建宁’, ‘建宁公主’, ‘宁公主’, ‘公主’, ‘主人’, ‘孤’, ‘势’, ‘单’, ‘韦小’, ‘韦小宝’, ‘小宝’, ‘又’, ‘不对’, ‘她’, ‘回护’, ‘近年’, ‘近年来’, ‘年来’, ‘来气’, ‘气焰’, ‘已’, ‘大为’, ‘收敛’, ‘轻易’, ‘不敢’, ‘启’, ‘次日’, ‘韦小’, ‘韦小宝’, ‘小宝’, ‘命’, ‘双儿’, ‘取出’, ‘郑克’, ‘当年’, ‘在’, ‘通吃岛’, ‘岛上’, ‘血书’, ‘的’, ‘借据’, ‘请’, ‘了’, ‘多隆’, ‘来’, ‘交给’, ‘了’, ‘他’, ‘多隆’, ‘大喜’, ‘说道’, ‘既有’, ‘亲笔’, ‘借据’, ‘咱们’, ‘石头’, ‘头里’, ‘也’, ‘要’, ‘榨出’, ‘他’, ‘油’, ‘来’,
上面随机节选了部分分词结果,整体效果还好,但也有诸如“人平”、“来气”、“通吃岛”、“韦小”等效果很差的分词。
下面是计算词频(TF)、逆文本频率指数(IDF)的结果
白马 8.844901865223905
啸 8.924944572897441
西风 9.618091753457387
碧血 9.618091753457387
碧血剑 10.311238934017332
飞狐 19.236183506914774
外传 8.70180102158323
连城 9.330409681005605
连城诀 10.311238934017332
鹿鼎记 10.02355686156555
三十 8.519479464789276
三十三 9.01195594988707
十三 8.576637878629224
三剑客 10.311238934017332
剑客 9.330409681005605
图 8.63726250044566
射雕 9.463941073630128
英雄 8.519479464789276
英雄传 10.02355686156555
传神 10.02355686156555
神雕侠侣 9.618091753457387
侠侣 9.618091753457387
书剑 9.618091753457387
恩仇 9.01195594988707
恩仇录 9.800413310251342
天龙 9.330409681005605
天龙八部 10.02355686156555
八部 9.800413310251342
侠客 9.330409681005605
侠客行 10.311238934017332
笑傲 9.618091753457387
笑傲江湖 10.02355686156555
傲江湖 10.02355686156555
江湖 8.576637878629224
雪山 8.844901865223905
雪山飞狐 10.02355686156555
倚天 9.618091753457387
天屠龙 9.800413310251342
屠龙 9.463941073630128
屠龙记 9.800413310251342
鸳鸯 8.770793893070183
鸳鸯刀 9.800413310251342
越女剑 9.463941073630128
`
import os
import time
import jieba
import re
from math import log
# 1、递归读取文件
# 2、读取到文件,文件内容转换成文本,使用jieba进行分词
class TraversalFun():
# 1 初始化
def __init__(self, rootDir):
self.rootDir = rootDir
def TraversalDir(self):
return TraversalFun.getCorpus(self, self.rootDir)
def getCorpus(self, rootDir):
corpus = []
r1 = u'[a-zA-Z0-9’!"#$%&\'()*+,-./::;<=>?@,。?★、…【】《》?“”‘’![\\]^_`{|}~]+' # 用户也可以在此进行自定义过滤字符
listdir = os.listdir(rootDir)
for file in listdir:
path = os.path.join(rootDir, file)
if os.path.isfile(path):
# 打印文件地址
#print(os.path.abspath(path))
# 获取文章内容,fromfile主要用来处理数组 pass
# filecontext = np.fromfile(os.path.abspath(path))
with open(os.path.abspath(path), "r", encoding='ANSI') as file:
filecontext = file.read();
#print(filecontext)
# 分词 去掉符号
filecontext = re.sub(r1, '', filecontext)
filecontext = filecontext.replace("\n", '')
filecontext = filecontext.replace(" ", '')
seg_list = jieba.cut(filecontext, cut_all=True)
corpus += seg_list
#print(seg_list)
#print("[精确模式]:" + "/".join(seg_list))
elif os.path.isdir(path):
TraversalFun.AllFiles(self, path)
return corpus
#构造词典,统计每个词的频率,并计算信息熵
def calc_tf(corpus):
# 统计每个词出现的频率
word_freq_dict = dict()
for word in corpus:
if word not in word_freq_dict:
word_freq_dict[word] = 1
word_freq_dict[word] += 1
# 将这个词典中的词,按照出现次数排序,出现次数越高,排序越靠前
word_freq_dict = sorted(word_freq_dict.items(), key=lambda x:x[1], reverse=True)
# 计算TF概率
word_tf = dict()
# 信息熵
shannoEnt = 0.0
# 按照频率,从高到低,开始遍历,并未每个词构造一个id
for word, freq in word_freq_dict:
# 计算p(xi)
prob = freq / len(corpus)
word_tf[word] = prob
shannoEnt -= prob*log(prob, 2)
return word_tf, shannoEnt
if __name__ == "__main__":
startTime = time.time()
tra = TraversalFun("./2")
corpus = tra.TraversalDir()
print("数据集大小,size: " + str(len(corpus)))
print(corpus)
word_tf, shannoEnt = calc_tf(corpus)
print("信息熵:" + str(shannoEnt))
#print("TF: ")
#print(word_tf)
endTime = time.time()
print("\ntotal cost time(s)", (endTime-startTime), 's')
`