打开网易新闻 查看更多图片

情感分析是一个必不可少的工具,用于许多不同的任务,包括从基于tweets预测股市情绪,到预测客户自动生成响应。Google的Word2Vec运行良好,但有一个很大的问题,它需要大量的数据集。当谷歌训练Word2Vec网络时,它使用了数千个它有特殊访问权限的文档。如果要找到、规范化并使用足够的质量数据来让程序正常工作,那将非常难操作,我无法在自己的项目中实现这一点。

经过一段时间的思考,提出了一种将单词转换成向量的技术,是使用了与Google使用的Word2Vec方法完全不同的概念。

概念

让我们回到我们的最终目标:将一个单词转换成向量。向量作为程序的直接输出是有困难的,这是由于需要在系统中训练两个同等权重的变量。所以我们的最终输出是一个单数值。此值仍将转换为向量,第一个值为-1或1(表示积极或消极情绪),第二个值为任意值(表示情绪的大小)。

如果我们为每个单词生成一个值,可以使用梯度下降来改变这个值,以计算出每个单词相关的情绪。

如何执行反向传播?简单,对tweet中每个单词的所有值Sigmoid,输出0到1之间的值,0为负,1为正。

代码

步骤1 |先决条件:

importosfrompandasimportread_csvimportstringimportnumpyasnp

这些库是程序工作所必需的。

步骤2 |访问数据集:

os.chdir(r'XXXXXX')csv=read_csv('stock_data.csv')csv

将XXXXX更改为存储数据集的目录。你可以从这个链接得到股票情绪数据集:https://www.kaggle.com/yash612/stockmarket-sentiment-dataset 。

步骤3 |准备数据集步骤

X=csv['Text'].valuesy=csv['Sentiment'].valuesnp.unique(y)X[5]

提取数据集的X和y值很简单,因为它在数据集中的形式类似。

步骤4 |清理数据集

counter=0foriinrange(len(y)):ify[i]!=1:counter+=1y[i]=0new_X=[]foriinrange(len(X)):try:words=X[i].split()counter=0whileTrue:upper=Falseforwordinwords:ifword.isupper()or'https'inwordorword[0]=='#'ornot(word.isalpha()):words.remove(word)upper=Trueifupper==False:breakcounter+=1foriinrange(len(words)):words[i]=words[i].lower()new_X.append(words)except:passX=new_Xflatten=lambdat:[itemforsublistintforiteminsublist]all_words=flatten(X)unique=list(np.unique(all_words))unique.sort()vectors=np.random.randn(len(unique),1)

我已经从数据集中删除了链接、标签和公司名称,以防止模型只会从公司目前的表现中获取情绪。

还需要生成一个唯一单词的列表,这样向量就可以按索引分配了。

步骤5 |向量化、传播和训练:

defsigmoid(x):return1/(1+np.exp(-x))defsigmoid_p(x):returnsigmoid(x)*(1-sigmoid(x))defpredict_sentiment(tweet):sentiment=1forwordintweet:index=unique.index(word)sentiment*=vectors[index]sentiment=sigmoid(sentiment)returnsentimentdefadjust_vectors(pred_sentiment,true_sentiment,tweet):dloss_dpred=2*(true_sentiment-pred_sentiment)dloss_dvec=[]vectors_iq=[]vectors_index=[]forwordintweet:index=unique.index(word)vectors_iq.append(vectors[index])vectors_index.append(index)product=np.prod(vectors_iq)foriinrange(len(vectors_iq)):dloss_dvec.append(sigmoid_p(product)/vectors_iq[i])foriinrange(len(vectors_index)):vectors[i]-=dloss_dvec[i]*0.1returnvectorsforepochinrange(100):print('EPOCH',str(epoch+1))foriinrange(len(X)):pred_sentiment=predict_sentiment(new_X[i])vectors=adjust_vectors(pred_sentiment,y[i],new_X[i])

基本上,根据tweet中的其他词计算梯度,可以正确地改变向量,从而在预测推特情绪时获得更高的准确率。

步骤6 |观察向量

打开网易新闻 查看更多图片

importrandomfrommatplotlibimportpyplotaspltnum=5foriinrange(num):random_num=random.randint(0,len(vectors)-1)vec=vectors[random_num]ifvec<0:vec_y=-1else:vec_y=1vec_X=vec/vec_yword=unique[random_num]plt.plot(vec_X,vec_y,'o')plt.annotate(word,(vec_X,vec_y))

这个程序可以让我们看到传染病的严重程度和情绪,观察程序的结果可以得到不同结论。在对数据集进行清理和规范化处理之后,可以对结果进行改进,观察结果并发现错误。

结论

如果你仍然不相信使用向量能够计算单词,请考虑向量的这个属性:向量有一个大小,可以使用毕达哥拉斯定理计算出来,我们所看到的所有向量都是相对于原点的。

如果我们认为X轴代表情绪的严重程度,而y轴代表积极/消极,原点是完全中性的。通过计算向量的大小,它可以计算出意见偏离原点的程度,或者意见有多极端。

以下是计算此值的函数:

defcalculate_magnitude(vec):ifvec<0:vec_y=-1else:vec_y=1vec_X=vec/vec_ysum_value=vec_X**2+vec_y**2returnnp.sqrt(sum_value)calculate_magnitude(vectors[100])