目录
实验目的:
加深对汉语文本信息处理基础理论及方法的认识和了解,锻炼和提高分析问题、解决问题的能力。通过对具体项目的任务分析、数据准备、算法设计和编码实现以及测试评价几个环节的练习,基本掌握实现一个自然语言处理系统的基本过程。
实验要求:
基于Word2Vec的文本表示
实验内容及原理:
实验说明:
该子任务使用gensim工具包中的Word2Vec模型。
要求熟练掌握工具包安装、数据读取、模型训练、参数调整、结果保存、模型加载以及词向量获取相关内容。
主要流程如下:
1)gensim安装(https://radimrehurek.com/gensim/) 。请自行配置pip和anaconda环境,可使用以下两种方式进行安装。
pip安装:Run in your terminal (recommended)
pip install --upgrade gensim
conda安装: Run in your Anaconda Prompt
conda install -c conda-forge gensim
2)详细阅读word2vec模型的说明文档
(https://radimrehurek.com/gensim/models/word2vec. html),了解各函数的基本使用方法和参数意义。
3)对给定的实验数据进行分词,不需要去除停用词。
4)加载分词后的实验数据,分别使用cbow和skip-gram两种模型将所有词汇训练成词向量,维度N=64。
5)将训练好的词向量模型保存到文件中。
6)重新加载已经训练完成的模型,输入任意在训练集中的词汇wi可以输出其词向量wi表示。
7)对给定语料库内的所有的句子,将其分词后从(5)中已经训练完成的模型中获取其所有词汇的词向量表示。利用实验五的方法,计算句子S中每个词汇wi的tfidf值并进行归一化(归一化可使用公式Eq.1) ,以该归一化tfidf值作为wi的权重对句子的所有词向量wi表示进行加权求和,作为该句子的向量表示(公式Eq.2)。以“句子id类别标签(pos为1,neg为0)向量表示”的形式存在文件当中。
实验数据:
实验数据采用htl_del_4000宾馆情感分析数据进行处理,所有数据已按照情感极性划分为褒(pos)贬(neg)两类,各2000篇,每个文本文件为一篇文章,实验数据需要先进行分词,分词方法不限。
参考代码:
import csv
import gensim
import jieba
import numpy as np
import os
from gensim.models import word2vec
content = open('./cn_stopwords.txt', 'r',encoding='utf-8').read()
#转化为CSV文件
def ToCSV(file1,file2):
with open(file1, 'w', newline='', encoding='utf-8') as cf:
writer = csv.writer(cf)
writer.writerow(["id", "标签","向量"])
with open(file2, 'r', encoding='utf-8') as f:
l = f.readlines()
for s in l:
l1 = s.split(' ') # l1[0]为文档id,l1[1]为标签,l1[2:]为向量
writer.writerow([l1[0], l1[1],l1[2:]])
def funn(): #对给定的数据进行分词
# 当前文件的路径
dir = os.path.dirname(__file__)
# 拼接文件路径
neg_folder = os.path.join(dir, './htl_del_4000/' + "neg")
pos_folder = os.path.join(dir, './htl_del_4000/' + "pos")
# 遍历所有文件
neg_li = os.listdir(neg_folder) # li储存neg的句子文本
pos_li = os.listdir(pos_folder) # li_1储存pos的句子文本
with open("./临时.txt","w+",encoding="utf-8") as file:
num_neg=0
num_pos=0
for x in neg_li:
with open("./htl_del_4000/neg/"+x,"r", encoding="gbk", errors='ignore') as f:
content=f.read()
num_neg+=1
words=[]
# words=jieba.cut(content)
words_split=" ".join(jieba.cut(content)).split()
# words=" ".join(words_split)
for w in words_split:
# if w not in stop_words:
words.append(w)
words=" ".join(words)
# print(words)
file.writelines(words+"\n")
for x in pos_li:
with open("./htl_del_4000/pos/"+x,"r", encoding="gbk", errors='ignore') as f:
content=f.read()
num_pos+=1
words=[]
# words=jieba.cut(content)
words_split=" ".join(jieba.cut(content)).split()
# words=" ".join(words_split)
for w in words_split:
# if w not in stop_words: #不去除停用词可以注释掉
words.append(w)
words=" ".join(words)
# print(words)
file.writelines(words+"\n")
return num_neg,num_pos
def Get_WordVector():
#用word2vec建立词向量
sens = word2vec.LineSentence("./临时.txt")
# sens:句子,min_count:词频小于设定值的词扔掉,window:一次取的词数,size:词向量的维度,sg:使用CBOW/Skip,hs:若为1采用树优化,worker:CPU并行数量,iter:最大迭代次数
model_CBOW = gensim.models.word2vec.Word2Vec(sens, min_count=0, window=5,vector_size=64, sg=0, hs=0, negative=5, workers=8, epochs=200) #用CBOW处理
model_skipgram = gensim.models.word2vec.Word2Vec(sens, min_count=0, window=5,vector_size=64, sg=1, hs=0, negative=5, workers=8, epochs=200) #用skip-gram处理
#保存为txt
model_CBOW.wv.save_word2vec_format("词向量(cbow).txt",binary=False)
model_skipgram.wv.save_word2vec_format("词向量(skip-gram).txt",binary=False)
def calw(docs):
tfidf=[]
words_stats = {}
docs_num = len(docs)
for ws in docs: #ws=sentense
for w in ws: #w=words
if w not in words_stats:
words_stats[w] = {}
words_stats[w]['df'] = 0
words_stats[w]['idf'] = 0
# words_stats[w]['cf'] += 1
for w in set(ws):
words_stats[w]['df'] += 1
for w, winfo in words_stats.items():
words_stats[w]['idf'] = np.log((1. + docs_num) / (1. + winfo['df']))
tfidf.append(words_stats[w]['idf'])
return tfidf
def ca(docs):
tfidf=[]
words_stats = {}
docs_num = len(docs)
for ws in docs: #ws=sentense
for w in ws: #w=words
w=''
return tfidf
#softmax归一化函数
def softmax(x):
e_x = np.exp(x)
return e_x / e_x.sum()
def final():
docs = []
num_of_files = 0
for x in l1: # 文件挨个计算
with open("./htl_del_4000/neg/" + x, "r", encoding="gbk", errors='ignore') as f:
content = f.read()
words = jieba.cut(content)
num_sentense = 0
temp_doc = [x.replace(".", '').replace('neg', '').replace('txt', '') + "-" + str(num_sentense),
"0"] # 1表示pos;0表示neg(num_sentense的0表示该文档下的第一个句子)
for i in words:
if i == "。" or i == ";" or i == ".":
num_sentense += 1
temp_doc.append(i)
docs.append(temp_doc)
temp_doc = [x.replace(".", '').replace('neg', '').replace('txt', '') + "-" + str(num_sentense), "0"]
num_of_files += 1
continue
elif i != "\r" and i != "\r\n" and i != "\n":
temp_doc.append(i)
else:
if len(temp_doc) > 3:
docs.append(temp_doc)
num_of_files += 1
num_of_files_1 = 0
for x in l2:
with open("./htl_del_4000/pos/" + x, "r", encoding="gbk", errors='ignore') as f1:
content = f1.read()
words = jieba.cut(content)
num_sentense = 0
temp_doc = [x.replace(".", '').replace('pos', '').replace('txt', '') + "-" + str(num_sentense),
"1"] # 1表示pos;0表示neg(num_sentense的0表示该文档下的第一个句子)
for i in words:
if i == "。" or i == ";" or i == ".":
num_sentense += 1
temp_doc.append(i)
docs.append(temp_doc)
temp_doc = [x.replace(".", '').replace('pos', '').replace('txt', '') + "-" + str(num_sentense), "1"]
num_of_files_1 += 1
continue
elif i != "\r" and i != "\r\n" and i != "\n":
temp_doc.append(i)
else:
if len(temp_doc) > 3:
docs.append(temp_doc)
num_of_files_1 += 1
return docs
def prosm(sen_docs, file):
tfidf = []
for sentense in sen_docs:
if len(sentense)<4: #因为文档中有"..."出现,所以上一步会有空列表出现,这一步把他们都去掉
continue
x = calw(sentense[2:])
res = softmax(x)
tfidf.append(sentense[:2] + (res * np.array(x)).tolist()) #(res * np.array(x)).tolist()加权求和得到句子的表示向量
with open(file, "w+", encoding="utf-8") as f:
for sentense in range(len(tfidf)):
for value in range(len(tfidf[sentense])):
f.write(str(tfidf[sentense][value]))
if (value != (len(tfidf[sentense]) - 1)):
f.write(' ')
f.write('\n')
if __name__=="__main__":
funn()
Get_WordVector()#建立词向量
# 将数据加载到列表
fname1 = 'neg'
fname2 = 'pos'
# 当前文件的路径
dir = os.path.dirname(__file__)
x = 200
softmax(x)
# 拼接文件路径
f1 = os.path.join(dir, './htl_del_4000/' + fname1)
f2 = os.path.join(dir, './htl_del_4000/', fname2)
# 遍历所有文件
l1 = os.listdir(f1) # l1储存neg的句子文本
l2 = os.listdir(f2) # l2储存pos的句子文本
l1.sort()
l2.sort()
docs=final()
calw(docs)
ca(docs)
prosm(docs,"表示.txt")
ToCSV("Word2Vec.csv", "表示.txt")
print("任务完成!")
实验结果:
1.词向量
2.文本表示