最近好幾天都沒有更新博客,因為網絡設置崩了,然后各種扎心,最后還重裝電腦,而且還有一些軟件需要重新安裝或者配置,所以煩了好久,搞好電腦之后,老師又布置了一個任務,個人覺得很有趣--判別學校新聞是否是標題黨
雖然我不覺得老師的方法能夠很好地判別標題黨行為,但是也只能開干了!
第一步:通過爬蟲獲取學校新聞,這一部分已經在之前的文章中寫過,所以不在重復了,有點不同的是,因為從文本中提取內容列會出錯,有少數文章的內容沒有被全部提取,所以我在源代碼的基礎上改變了一下,生成了一個只存放內容的文件content.csv
第二步:(1)對文檔內容進行分詞,並且按照文檔數分別存放在不同的文檔,例如3454篇新聞就用3454份文檔來存放分詞后的內容,但是是可以直接用一個文檔來存放的,每篇文章只在文檔中占一行就行,分詞用結巴,不要用全模式,否則后面選擇的關鍵詞會有很多相同,另外下載百度停用詞表,在停用詞表中的詞語就不要寫入文件中,因為不能成為關鍵詞,如是、的、好
(2)使用TF-IDF算法進行關鍵詞提取,首先套一個循環,循環3454個文檔,然后按行讀取,之后各種燒腦。舉個例子:在文檔A中,有100個分詞后的詞語,通過集合去掉重復的之后還剩下80個,把這80個加到字典中,並且要計算這80個詞語在文檔A中各自出現的次數;然后輪到文檔B,首先判斷文檔B中的分詞詞語有哪些在字典中,在字典中的話就不加進字典,但是值VALUES加1,否則加入字典。這個太難說清楚了,還是自己去看看詳細介紹吧!
(3)根據TF-IDF算法得到每篇新聞權值前三的詞語,並且寫入文件中
第三步:(1)訓練相似度模型:這是個很陌生的知識,但是用了工具就很簡單了,原理就是存儲許多詞語,把他們分為向量,就像網絡一樣連在一起,把距離的遠近作為詞語之間的相似度,缺點就在於無法識別不在模型中的詞語相似度。可以去看看這兩個鏈接,非常詳細:https://blog.csdn.net/kaoyala/article/details/79090156;https://github.com/jsksxs360/Word2Vec
(2)把模型訓練好了之后就簡單了,把標題從新聞中提取出來,然后進行全模式分詞,對於第一個關鍵詞,與分詞后的標題逐個計算相似度,取最大相似度,然后再到第二個關鍵詞,最后把結果寫入文件中
下面附上源碼:
import jieba
import math
import re
def word():
#第一步:文檔預處理:讀取文檔 -> 刪除不需要的字符(如回車符\n、制表符\t、空格等)
# -> 轉換成unicode格式 -> 對文檔分詞 -> 轉換成utf-8格式寫入txt文檔
#讀取文檔
#由於使用TF-IDF方法提取關鍵詞,而且需要分析題目相似度,所以每篇文章生成一個文檔!
with open('content.csv', 'r', newline='', encoding='utf-8')as col:
j = 1
for i in col.readlines():
content=jieba.cut(i,cut_all=False) #結巴分詞精確模式
result=" ".join(content) #把generator轉換為字符串類型
result=re.compile('[\u4e00-\u9fa5]+').findall(result)
# 轉換為列表並且去掉了那些數字3,4英文之類的
list1=[] #存儲去掉空格之后的列表
#導入停用詞表,並進行簡單清洗
list111 = [] #存儲停用詞表
with open('baidustop.txt', 'r', encoding='utf-8')as f:
for i in f.readlines():
i = i.strip() #去掉換行符
list111.append(i)
for i in result:
if len(i)<=1 : #如果是空格或者單個字就去掉不要
continue
elif i in list111: #如果在停用詞表里面就不要
continue
else:
list1.append(i)
# 把分詞結果寫入TXT文檔中
with open('txt/TF-IDF'+str(j)+'.txt','a',encoding='utf-8')as file:
for word in list1:
file.write(word+'\n')
j+=1 #為了文檔名字
def language():
#第二步:使用TF-IDF算法進行關鍵詞提取
dict2={} #存放語料庫,統計一個單詞在多少個文件中存在
for i in range(1,3455):
with open('txt/TF-IDF' + str(i) + '.txt', 'r', encoding='utf-8')as file:
list2=[]
for wd in file.readlines(): #按行讀取
wd=wd.replace('\n','') #去掉換行符
list2.append(wd)
#制作語料庫字典,為了求解IDF
set1=set(list2) #轉換為集合!
for word in set1:
dict2[word]=dict2.get(word,0)+1 #一個文檔中每個單詞最多只能增加1 !
with open('language.txt','a',encoding='utf-8')as f:
for j,k in zip(dict2.keys(),dict2.values()):
f.write(j+':')
f.write(str(k))
f.write('\n')
def TfIdf():
dict3={} #存放語料庫中的鍵值對,生成該字典是為了進行索引
for line in open('language.txt','r+',encoding='utf-8'):
(key, value) = line.strip('\n').split(':') #換行符是用strip去除的,然后通過區分冒號來區分鍵值
dict3[key] = str(value) #把對應的鍵值對存放進dict3字典中
# 根據dict3求解IDF
for q in dict3.keys():
dict3[q] = math.log(3455 / (int(dict3[q]) + 1), 10) # 10是底
for j in range(1,3455): #所有文檔各自遍歷一遍
count = {} #存放每次文檔的單詞和次數
sumdict={} #用來存放TF-IDF算法后的結果
with open('txt/TF-IDF' + str(j) + '.txt', 'r', encoding='utf-8')as file:
for wd in file.readlines(): #按行讀取
# 求解單詞頻率,為了TF
wd=wd.replace('\n','') #去掉換行符
count[wd]=count.get(wd,0)+1 #統計在本文檔中該單詞出現的次數
for k in count.keys():
sumdict[k] = count[k] / sum(count.values()) # TF表示詞條在文檔中出現的頻率
sumdict[k]=sumdict[k]*dict3[k] #此處用sumdict存放TF-IDF值
data=[] #存儲三個最大值
with open('TF-IDF.txt', 'a', encoding='utf-8')as f:
for i in range(3):
data.append(max(sumdict,key=lambda x:sumdict[x])) #根據字典的值查找最大值
f.write(max(sumdict,key=sumdict.get)) #寫入文件中
f.write(' ') #用逗號來分割三個關鍵字
sumdict.pop(max(sumdict,key=sumdict.get)) #刪除最大值
f.write('\n')
if __name__=='__main__':
word()
language()
TfIdf()
from gensim.corpora import WikiCorpus
import jieba
import codecs
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
import multiprocessing
'''
讀取中文wiki語料庫,並解析提取xml中的內容
'''
#將下載的語料轉為文本txt格式
def dataprocess():
space = " "
i = 0
output = open('E:\wiki\chinawiki-articles.txt', 'w', encoding='utf-8')
wiki = WikiCorpus('E:\wiki\zhwiki-latest-pages-articles.xml.bz2', lemmatize=False, dictionary={})
for text in wiki.get_texts():
output.write(space.join(text) + "\n") #分割一個詞之后換行
i = i + 1
if (i % 10000 == 0): #每一萬文章就提示一下
print('Saved ' + str(i) + ' articles')
output.close()
print('Finished Saved ' + str(i) + ' articles')
'''
加載停用詞表
'''
def createstoplist(stoppath):
print('load stopwords...')
stoplist = [line.strip() for line in codecs.open(stoppath, 'r', encoding='utf-8').readlines()]
#fromkeys用於創建一個新字典,以序列seq中元素做字典的鍵,value為字典所有鍵對應的初始值
stopwords = {}.fromkeys(stoplist) #值默認為None
return stopwords
'''
過濾英文
'''
def isAlpha(word):
try: #isalpha() 方法檢測字符串是否只由字母組成。
return word.encode('ascii').isalpha()
except UnicodeEncodeError:
return False
def trans_seg():
stopwords = createstoplist(r'E:\wiki\baidustop.txt')
i = 0
with codecs.open('E:\wiki\seg\chinawiki-segment40.txt', 'w', 'utf-8') as wopen:
print('開始...')
with codecs.open('E:\wiki\zhUTF8\chinawiki-articles-jian.txt', 'r', 'utf-8') as ropen:
for line in ropen.readlines():
line = line.strip() #去掉空格
i += 1
print('line ' + str(i)) #第幾行
text = ''
for char in line.split(): #對每行進行列表分割
if isAlpha(char): #如果是英文就不要
continue
text += char #空格加詞語
# print(text)
words = jieba.cut(text) #默認模式分詞
seg = ''
for word in words:
if word not in stopwords: #如果在停用詞表就不用這個詞
if len(word) > 1 and isAlpha(word) == False: # 去掉長度小於1的詞和英文
if word != '\t': #空格
seg += word + ' '
wopen.write(seg + '\n')
print('結束!')
'''
利用gensim中的word2vec訓練詞向量
'''
def word2vec():
print('Start...')
rawdata='E:\wiki\seg\chinawiki-segment40.txt'
modelpath='E:\wiki\model\chinawikimodel.model'
#vectorpath='E:\word2vec\vector'
model=Word2Vec(LineSentence(rawdata),size=400,window=5,min_count=5,workers=multiprocessing.cpu_count())#參數說明,gensim函數庫的Word2Vec的參數說明
model.save(modelpath)
#model.wv.save_word2vec_format(vectorpath,binary=False)
print("Finished!")
if __name__=='__main__':
# dataprocess()
# trans_seg()
# word2vec()
model= Word2Vec.load('E:\wiki\model\chinawikimodel.model')
# print(model.most_similar('開心',topn=5))
try:
pro=model.similarity('開心', '不存在')
except:
pro=0
print(pro)
'''
計算關鍵詞與題目相似度的流程:加載題目文件與關鍵詞文件--》把題目進行分詞--》把分詞后的結果保存
--》把關鍵詞與分詞題目詞語逐一比較相似度取最大值--》每篇文章得到三個相似度(三個關鍵詞)
前期准備:jieba分詞、wiki中文語料、word2vec模型訓練、詞向量比較相似度
標題文檔:fosu1中提取,關鍵詞文檔:TF-IDF.txt中提取,皆是3454行
'''
import csv
import jieba
from gensim.models import Word2Vec
import re
#加載詞語模型,用來輸出詞語相似度
model= Word2Vec.load('E:\wiki\model\chinawikimodel.model')
list1=[] #存儲分詞后的標題
list2=[] #存儲關鍵詞
list3=[] #存儲相似度
#用with同時打開兩個文件
with open('fosu1.csv','r',newline='',encoding='utf-8')as file1,open('TF-IDF.txt','r',encoding='utf-8')as file2:
read1 = csv.reader(file1) # 讀取文件
title = [row[0] for row in read1] # 獲取標題
for i in title:
i = jieba.cut(i, cut_all=False) #全模式識別名字的效果很差
#雖然使用精確模式有所改變,但是很多名字都不在模型中,所以沒法識別,返回錯誤
tit = ",".join(i)
tit=re.compile('[\u4e00-\u9fa5]+').findall(tit) #只取中文
list1.append(tit)
for j in file2.readlines():
j=j.strip()
j=j.split(' ')
list2.append(j) #關鍵詞
file3=open('similarity.txt','a',encoding='utf-8')
n=0 #第幾個標題
for p,q in zip(list1,list2):
word=" ".join(q)
file3.write(title[n] + ':')
file3.write(word+'|')
for w in range(3):
pro=[] #暫時存儲一個關鍵詞與其他標題分詞的相似度
for i in p:
try: #關鍵詞與他們逐一比較相似度
pro.append(model.similarity(i,q[w]))
except: #有些詞語不在模型詞典中,會報錯
if i==q[w]: #如果詞語不在模型中,但是標題中有相同的詞語,那么就把相似度設為1.0
pro.append(1.0)
else: #否則為0.0
pro.append(0.0)
pro=float('%.2f'%max(pro)) #取相似度最大的為關鍵詞與標題的相似度
file3.write(str(pro)+' ')
file3.write('\n')
n+=1 #標題+1
