赞
踩
为了训练自身对于自然语言识别的理解我计算获得了文本各个段落与全文的相似度,各段落和全文的关键词。段落关键词,全文关键词和摘要,多重信息有效得帮助读者了解文本内容和主题。以下是效果图。
|
|
|
|
首先是段落关键词和全文关键词,获取全文和段落关键词的步骤为读入文本,切词和去除停用词。
- LingYu=[]#领域词表
- for i in range(2100,12000):
- try:
- openfile1=r"C:\Users\tony5\Desktop\nlp\{}.txt".format(i)#教育类文本1
- writingfile1=r"C:\Users\tony5\Desktop\nlp\pythonjson{}.json".format(i)
- a=GetArticle_and_Paragraph_KeyWord(openfile1,writingfile1,LingYu)
- except:
- continue
由于我的训练文本集当中的序号并不连续所以我采用try,except语法跳过不存在的序号将所有文本读入。同时由于我采用的训练文本兼有GBK形式的编码和utf-8编码的文档所以我均采用utf-8的形式打开。
- def GetArticle_and_Paragraph_KeyWord(openfile,writingfile,LingYu):#主调函数
- # 读取文本数据
- file = open(openfile,'r',encoding = 'utf-8')
- outfile = open(writingfile,'w',encoding = 'utf-8')
- whole=""#去除了停用词之后的以词形式保存的文章
- wordbank=[]#以词语形式保存的每一段段落的词
- linebank=[]#以句子形式保存的文章
- #获得段落关键词
- stopwords,whole,linebank = ReadArticle_SeperateWords_And_Usejieba(file, outfile, whole, wordbank,linebank)
- #获得全文关键词
- LingYu.extend(WholeArticleKeyWord(outfile, whole,stopwords))
- #算出每一段与全文的相似度
- Similiarity_And_ParagrathRank(wordbank,whole,outfile)
- #获得摘要
- Get_ZhaiYao(linebank, whole,outfile)
- return whole#主调函数
文本分割函数ReadArticle_SeperateWords_And_Usejieba()为文本预处理的主要函数,其主要目的就是得到各个段落的关键词,将文本分割成句子,分割成段落,和分割成词语的形式保存,建立总词库的目的在于为计算全文关键词和抽取式摘要作准备。首先我通过句号分割将文本按照句子保存在了lineBank中。文本分割我使用了极为流行的自然语言处理包jieba分词。经过这一步骤我将文本以一个一个词的形式保存在wordbank列表中。但是我发现结巴自身确实是带有停用词的词库的,但是jieba.lcut并不会调用,其只会在jieba.analyse函数计算关键词的时候使用。因而我自己建立了停用词在阅读的结巴分词的出的词表的时候将停用词去除。然后调用Use_Jieba()函数计算的到各段落的关键词。同时为了将结果清晰得保存在json文件中,我将其将jieba分词返回的元组列表转换成字典。
- def ReadArticle_SeperateWords_And_Usejieba(file, outfile, whole, wordbank,linebank):
- seperated_words=['my seperated words',]
- str=""
- for line in file.readlines():
- if line == '\n':
- continue
- line=line.strip()
- if len(line)!=0:
- for word in line:
- str=str+word
- if(word=="。"):
- linebank.append(str)
- str=""
- fenci_text = jieba.lcut(line)
- stopwords = {}.fromkeys([ line.rstrip() for line in open(r'C:\Users\tony5\Desktop\nlp\stop_words_zh.txt') ])
- final = ""
- for word in fenci_text:
- if word not in stopwords:
- if (word != "。" and word != ",") :
- final = final + " " + word
- seperated_words.append(word)
- whole = whole+word
- wordbank.append(final)
- Use_Jieba(final,outfile)
- return stopwords,whole,linebank
- #切词去停用词,调用Use—Jieba函数返回各个段落的关键词写入json里,切句子将文章按照句子保存在linebank里,获得总词表存在whole里用来为计算全文关键词作准备
- def Use_Jieba(final,outfile):
-
- a=jieba.analyse.extract_tags(final, topK = 10, withWeight = True, allowPOS = ())
- mydict=Translate_Into_dict(a)
- outfile.write("\n该段落的关键词\n")
- b=jieba.analyse.extract_tags(final, topK = 10,allowPOS = ())
- json.dump(b,outfile,ensure_ascii=False)
- json.dump(mydict,outfile,ensure_ascii=False, indent=4) #将去除停用词的文本取关键词并写入json
经过上述步骤通过循环已经获得了whole变量里面已经存储了全文所有词,对其进行关键词提取即可获得全文关键词。
- def WholeArticleKeyWord(outfile,whole,stopwords):
- #计算全文关键词并写入json
- fenci_text = jieba.lcut(whole)
- final = ""
- for word in fenci_text:
- if word not in stopwords:
- if (word != "。" and word != ","and word !="-") :
- final = final + " " + word
- article=jieba.analyse.extract_tags(final, topK = 50, withWeight = True, allowPOS = ())
- WArticle=jieba.analyse.extract_tags(final, topK = 50, withWeight = False, allowPOS = ())
- mydict=Translate_Into_dict(article)
- outfile.write("\n全文的关键词\n")
- json.dump(mydict,outfile,ensure_ascii=False, indent=4)#计算全文关键词并写入json
- return fenci_text
接下来我便计算了段落和文章的关系。我采用的方法是利用sklearn计算各个段落与全文相似性,得到各个段落词库与全文词库之间的相似度,并根据与全文的相关性进行排序。这里提取段落TF-IDF和TF特征值两种方法进行段落与文本的相似性计算。
- def tf_similarity(s1, s2):
- def add_space(s):
- return ' '.join(list(s))
-
- # 将字中间加入空格
- s1, s2 = add_space(s1), add_space(s2)
- # 转化为TF矩阵
- cv = CountVectorizer(tokenizer=lambda s: s.split())
- corpus = [s1, s2]
- vectors = cv.fit_transform(corpus).toarray()
- # 计算TF系数
- return np.dot(vectors[0], vectors[1]) / (norm(vectors[0]) * norm(vectors[1])) # 计算并返回两个字符串的TF系数
-
- def tfidf_similarity(s1, s2):
- def add_space(s):
- return ' '.join(list(s))
-
- # 将字中间加入空格
- s1, s2 = add_space(s1), add_space(s2)
- # 转化为TF矩阵
- cv = TfidfVectorizer(tokenizer=lambda s: s.split())
- corpus = [s1, s2]
- vectors = cv.fit_transform(corpus).toarray()
- # 计算TF系数
- return np.dot(vectors[0], vectors[1]) / (norm(vectors[0]) * norm(vectors[1])) # 计算并返回两个字符串的TF-IDF系数
TfidfVectorizer 和CountVectorizer类会将文本中的词语转换为词频逆偏频矩阵或词频矩阵,矩阵元素a[i][j] 表示j词在i类文本下的逆偏频或词频
Corpus是预料库,每一行一个文档,由于我是将两串字符串进行比较所以第一行就是第一个字符串第二行就是第二个字符串。
fit_tansform:是一个适配的过程,用于train,得到一个统一的转换的规则的模型;然后将数据进行转换,比如测试数据按照训练数据同样的模型进行转换,得到特征向量;学习词汇表和idf,返回文档词矩。
最后通过计算得到tf-idf系数或者tf系数,既可以通过这一系数来了解两个字符串得相似程度,由此就可以通过让全文总词库作为第二个字符串将各个段落词库作为第一个字符串,经过计算就可以得到各个段落与全文的相似度。将每一段与其权重保存在一个字典中,按照权值进行排序即可得到每一段与全文之间的相似度。
- def Similiarity_And_ParagrathRank(wordbank,whole,outfile):
- quanzhong={}
- k=0
- for i in wordbank:
- a=tf_similarity(i, whole)
- b=tfidf_similarity(i, whole)
- if(k!=0):
- quanzhong.setdefault("段落{}与全文的相似度".format(k),(("tf系数",a),("tfidf系数",b)))
- else:
- quanzhong.setdefault("标题与全文的相似度".format(k),(("tf系数",a),("tfidf系数",b)))
- k=k+1
- outfile.write("\n每段与全文的相似度\n")
- json.dump(quanzhong,outfile,ensure_ascii=False, indent=4)
- zuida={}
- k=0
- for i in wordbank:
- b=tfidf_similarity(i, whole)
- zuida.setdefault(b,"第{}段".format(k))
- k=k+1
- zuida=dict(sorted(zuida.items(),reverse=True))
- outfile.write("\n根据tfidf系数将其从大到小排序,第零段为标题\n")
- json.dump(zuida,outfile,ensure_ascii=False, indent=4)#计算的出每一段落包括标题与全文的相似度,从高到低排序并写入json
抽取式摘要是自动文摘的一种形式是自然语言处理的重要步骤。抽取式摘要的关键问题是如何有效的从文章当中抽取出重要性高的若干句子。现有的抽取式文摘主要通过人们通过统计简单直观的文本特征,比如词频、句子的位置、线索词和标题等从文档中识别重要的句子组成摘要,或者基于外部语义资源对文章句子进行语义理解。我采用的方法式通过统计简单直观的文本特征来获取摘要。
我选择的文本特征是用上文所提到的相似性计算方法计算所得全文每一句话与全文词向量的相似度。经过排序选择相似度最高的5句话作为全文摘要。
- def Get_ZhaiYao(linebank, whole,outfile):
- linesimility=[]
- for item in linebank:
- linesimility.append(tf_similarity(item, whole))
- juzi={}
- k=0
- for item in linesimility:
- juzi.setdefault(item,k)
- k=k+1
- juzi=dict(sorted(juzi.items(),reverse=True))
- sortedline=[]
- for key in juzi:
- sortedline.append(juzi[key])
- zhaiyao="文章摘要: "
- for i in range(0,5):
- zhaiyao=zhaiyao+linebank[i]
- zhaiyao=zhaiyao+'\n'
- print(zhaiyao)
- outfile.write("\n文章摘要\n")
- json.dump(zhaiyao,outfile,ensure_ascii=False)#根据句子在全文中的重要性排序选择关联度最高的5句句子形成摘要
计算机不如同人类可以有效得通过文本集的几篇文本快速想到可以象征这一类文本的名字。我尝试了两个方法,第一个方法是通过建立领域词表去除总词库关键词后提取关键词,我经过尝试建立遍历该类型的文章建立领域词表并提取领域词表的关键词是最有效的方法。对于领域词表的建立我的思路是领域词表中的词必须能充分代表这一类别,所以我建立了包含所有文章词语的全总语料库,建立了这一类型文章词语的领域词库,去除了领域词表中与全部总语料库中较常见的关键词。对此求关键词效果相对直接通过领域词表球的关键词效果更佳。
- Ciku=''
- for str in LingYu:
- if word not in Zong:
- Ciku=Ciku+str
- Cikujs=r"C:\Users\tony5\Desktop\nlp\Cikuyujson.json"
- Cikujs = open(Cikujs,'w',encoding = 'utf-8')
- article=jieba.analyse.extract_tags(Ciku, topK = 50, withWeight = True, allowPOS = ())
- WArticle=jieba.analyse.extract_tags(Ciku, topK = 50, withWeight = False, allowPOS = ())
- mydict=Translate_Into_dict(article)
- Cikujs.write("\n词库的关键词\n")
- json.dump(Ciku,Cikujs,ensure_ascii=False, indent=4)#计算全文关键词并写入json
- print(Ciku)
第二个方法是主题模型是一种统计模型用于发现文档集合中出现的抽象“主题”。主题建模是一种常用的文本挖掘工具,用于在文本体中发现隐藏的语义结构。
LDA也称三层贝叶斯概率模型,包含词、主题和文档三层结构;利用文档中单词的共现关系来对单词按主题聚类,得到“文档-主题”和“主题-单词”2个概率分布。以下是代码实现。
- def LDA_model(words_list):
- # 构造词典
- # Dictionary()方法遍历所有的文本,为每个不重复的单词分配一个单独的整数ID,同时收集该单词出现次数以及相关的统计信息
- dictionary = corpora.Dictionary(words_list)
- print(dictionary)
- print('打印查看每个单词的id:')
- print(dictionary.token2id) # 打印查看每个单词的id
-
- # 将dictionary转化为一个词袋
- # doc2bow()方法将dictionary转化为一个词袋。得到的结果corpus是一个向量的列表,向量的个数就是文档数。
- # 在每个文档向量中都包含一系列元组,元组的形式是(单词 ID,词频)
- corpus = [dictionary.doc2bow(words) for words in words_list]
- print('输出每个文档的向量:')
- print(corpus) # 输出每个文档的向量
-
- # LDA主题模型
- # num_topics -- 必须,要生成的主题个数。
- # id2word -- 必须,LdaModel类要求我们之前的dictionary把id都映射成为字符串。
- # passes -- 可选,模型遍历语料库的次数。遍历的次数越多,模型越精确。但是对于非常大的语料库,遍历太多次会花费很长的时间。
- lda_model = models.ldamodel.LdaModel(corpus=corpus, num_topics=2, id2word=dictionary, passes=10)
- return lda_model
-
- lda_model = LDA_model(Ciku)
- topic_words = lda_model.print_topics(num_topics=2, num_words=5)
- print(topic_words)
两个方法进行一下比较
两个方法求得的关键词差别不大,进一步的比较分析我将会在下一学期的时间内继续进行。本次计算思维实训让我收获良多,在本次实训过程中我自学学会了python语言,加深了对于自然语言处理的理解和认实,初步了解了Lda三层贝叶斯概率模型,锻炼了编程能力。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。