基于梯度下降的单词向量化

2020-12-29 15:36:05 浏览数 (2)

磐创AI分享

作者 | Victor Sim

编译 | VK

来源 | Towards Data Science

情感分析是一个必不可少的工具,用于许多不同的任务。这包括从基于tweets预测股市情绪,到预测客户自动生成响应。Google的Word2Vec运行良好,但有一个很大的问题。

它需要大量的数据集。当谷歌训练Word2Vec网络时,它使用了数千个它有特殊访问权限的文档。如果要找到、规范化并使用足够的质量数据来让程序正常工作,那将是一场噩梦,使我无法在自己的项目中实现这一点

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

概念

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

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

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

代码

步骤1 |先决条件:
代码语言:javascript复制
import os
from pandas import read_csv
import string
import numpy as np

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

步骤2 |访问数据集:
代码语言:javascript复制
os.chdir(r'XXXXXX')
csv = read_csv('stock_data.csv')
csv

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

步骤3 |准备数据集步骤
代码语言:javascript复制
X = csv['Text'].values
y = csv['Sentiment'].values

np.unique(y)
X[5]

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

步骤4 |清理数据集
代码语言:javascript复制
counter = 0
for i in range(len(y)):
    if y[i] != 1:
        counter  = 1
        y[i] = 0
        
new_X = []
for i in range(len(X)):
    try:
        words = X[i].split()
        counter = 0
        while True:
            upper = False
            for word in words:
                if word.isupper() or 'https' in word or word[0] == '#' or not(word.isalpha()):
                    words.remove(word)
                    upper = True
            if upper == False:
                break
                counter = 1
        for i in range(len(words)):
            words[i] = words[i].lower()
        new_X.append(words)
    except:
        pass
X = new_X

flatten = lambda t: [item for sublist in t for item in sublist]
all_words = flatten(X)

unique = list(np.unique(all_words))
unique.sort()

vectors = np.random.randn(len(unique),1)

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

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

步骤5 |向量化、传播和训练:
代码语言:javascript复制
def sigmoid(x):
    return 1/(1 np.exp(-x))
    
def sigmoid_p(x):
    return sigmoid(x)*(1 -sigmoid(x))
    
def predict_sentiment(tweet):
    sentiment = 1
    for word in tweet:
        index = unique.index(word)
        sentiment *= vectors[index]
    sentiment = sigmoid(sentiment)
    return sentiment
    
def adjust_vectors(pred_sentiment,true_sentiment,tweet):
    dloss_dpred = 2*(true_sentiment-pred_sentiment)
    dloss_dvec = []
    vectors_iq = []
    vectors_index = []
    for word in tweet:
        index = unique.index(word)
        vectors_iq.append(vectors[index])
        vectors_index.append(index)
    product = np.prod(vectors_iq)
    for i in range(len(vectors_iq)):
        dloss_dvec.append(sigmoid_p(product)/vectors_iq[i])
    for i in range(len(vectors_index)):
        vectors[i] -= dloss_dvec[i] * 0.1
    return vectors
    
for epoch in range(100):
    print('EPOCH',str(epoch 1))
    for i in range(len(X)):
        pred_sentiment = predict_sentiment(new_X[i])
        vectors = adjust_vectors(pred_sentiment,y[i],new_X[i])

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

步骤6 |观察向量
代码语言:javascript复制
import random
from matplotlib import pyplot as plt
num = 5
for i in range(num):
    random_num = random.randint(0,len(vectors)-1)
    vec = vectors[random_num]
    if vec < 0:
        vec_y = -1
    else:
        vec_y = 1
    vec_X = vec/vec_y
    word = unique[random_num]
    
plt.plot(vec_X,vec_y,'o')
    plt.annotate(word,(vec_X,vec_y))

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

结论

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

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

以下是计算此值的函数:

代码语言:javascript复制
def calculate_magnitude(vec):
    if vec < 0:
        vec_y = -1
    else:
        vec_y = 1
    vec_X = vec/vec_y
    sum_value = vec_X**2   vec_y**2
    return np.sqrt(sum_value)
    
calculate_magnitude(vectors[100])

感谢你阅读我的文章!

0 人点赞