Embedding理解+代码

Embedding

主要思想

把世界万物变成一个向量,让计算机看这个向量,再进行处理
万物都可嵌入

Word2vec

主要思想

就是把每个单词变成一个向量,并且这个向量还保留了单词的语义关系
example:man<->woman,queen<->king
在这里插入图片描述

两种模型:

CBOWSkip-gram(用处广)

目的:

把每个词都用向量表示,同时还保留他们之间语义关系
在这里插入图片描述

算法

一、定义超参数

学习率、训练次数、窗口尺寸、嵌入(embedding)尺寸
以下是窗口为二的滑动窗口
在这里插入图片描述

二、将语料库转换one-hot编码表示

在这里插入图片描述

三、模型训练

1、目标词的one-hot编码传入神经网络模型中训练,最后得到输出结果
在这里插入图片描述
2、训练得到的输出结果运用softmax函数归一化处理
在这里插入图片描述

3、处理后的结果和相邻窗口的单词one-hot编码分别做差得到各自的误差
4、将各自误差相加得到总误差
在这里插入图片描述
5、交叉熵损失函数处理
在这里插入图片描述

6、通过对参数求偏导,梯度下降方法求更新的参数,反向传播更新权重矩阵
7、最终求得更新迭代过后输入层到隐藏层的权重矩阵即为对应词的embedding词向量
在这里插入图片描述

代码手动实现 skip-gram模型

一、数据准备

 #准备语料库
    text="natural language processing and machine learning is fun and exciting"
 #分词处理
    corpus=[[word for word in text.split()]]

二、定义超参数

 #准备超参数
    settings = {
        'window_size': 2,  # 窗口大小(目标单词的左边和右边最近的2个单词被视为上下文单词)
        'n': 10,  # 单词嵌入维度,取决于词汇库大小,也是隐藏层大小
        'epochs': 50,  # 训练次数
        'learning_rate': 0.01  # 学习率
    }

三、定义word2vec模型

class word2vec():
 def __init__(self):
        self.n = settings['n']
        self.lr = settings['learning_rate']
        self.epochs = settings['epochs']
        self.window = settings['window_size']
数据清洗及生成词汇表

为后续把数据放入神经网络做准备
在函数train_data内部,我们进行以下操作:

self.v_count: 词汇表的长度(注意,词汇表指的就是语料库中不重复的单词的数量)

self.words_list: 在词汇表中的单词组成的列表

self.word_index: 以词汇表中单词为key,索引为value的字典数据

self.index_word: 以索引为key,以词汇表中单词为value的字典数据

for循环给用one-hot表示的每个目标词和其的上下文词添加到train_data中,one-hot编码用的是word2onehot函数。

    def train_data(self,settings,corpus):
        #先对语料库进行去重,得到去重后的每个词语对应的个数 返回的是一个字典
        word_counts=defaultdict(int)
        for row in corpus:
            for word in row:   #这里的word是二维数组里的单词
                word_counts[word]+=1

        # 计算有多少个不同的单词
        self.v_count = len(word_counts.keys())
        #去重后单词放入列表
        self.words_list=list(word_counts.keys())
        #做成 单词:索引(这里要提出i,word两个参数 所以用enumerate)
        self.word_index=dict((word,i) for i,word in enumerate(self.words_list))
        #做成 索引:单词
        self.index_word = dict((i,word) for i, word in enumerate(self.words_list))
        
        #开始存入目标及窗口范围内的词语
        train_data=[]
        for sentence in corpus:
            sent_len = len(sentence)
            for i, word in enumerate(sentence):
                w_target=self.word2onehot(sentence[i])
                #保存窗口范围内的词语
                w_context=[]
                for j in range(i-self.window,i+self.window):
                    if j != i and j <= sent_len - 1 and j >= 0:
                        w_context.append(self.word2onehot(sentence[j]))
                train_data.append([w_target,w_context])#这里就是最终存入神经网络输出层的格式
        return np.array(train_data)  
        
    #定义Onehot函数
    def word2onehot(self,word):
        #初始化都是0
        word_vec=[0 for i in range(0,self.v_count)]
        #找到传入单词在句子中的索引
        word_index=self.word_index[word]
        #将对应位置改为1
        word_vec[word_index]=1
        return word_vec
训练模型
    #训练模型
    def train(self,train_data):
        #定义权重矩阵

        self.w1=np.random.uniform(-1,1,(self.v_count,self.n))
        self.w2=np.random.uniform(-1,1,(self.n,self.v_count))

        #迭代训练
        for i in range(self.epochs):
            self.loss=0
            for w_t,w_c in train_data:
                #将目标词语进入前向传递
                y_pred,h,u=self.forward_pass(w_t)

                #将窗口误差相加
                EI=np.sum([np.subtract(y_pred,word) for word in w_c],axis=0)

                #反向传播
                self.backprop(EI,h,w_t)

                #计算误差
                self.loss += -np.sum([u[word.index(1)] for word in w_c]) + len(w_c) * np.log(np.sum(np.exp(u)))
            print('Epoch:', i, "Loss:", self.loss)

    def forward_pass(self,x):
        h=np.dot(x,self.w1)
        u=np.dot(h,self.w2)
        y_c=self.softmax(u)
        return y_c,h,u
    def softmax(self,x):
        e_x=np.exp(x-np.max(x))
        return e_x/e_x.sum(axis=0)
    def backprop(self,e,h,x):
        dl_dw2 = np.outer(h, e)
        dl_dw1 = np.outer(x, np.dot(self.w2, e.T))
        self.w1 = self.w1 - (self.lr * dl_dw1)
        self.w2 = self.w2 - (self.lr * dl_dw2)

四、 获取词向量和相似词

# 获取词向量
    def word_vec(self, word):
        w_index = self.word_index[word]
        v_w = self.w1[w_index]
        return v_w

    #获取相似词
    def vec_sim(self,word,top_n):
        v_w1=self.word_vec(word)
        word_sim={}

        for i in range(self.v_count):
            v_w2=self.w1[i]
            theta_sum=np.dot(v_w1,v_w2)
            theta_den=np.linalg.norm(v_w1)*np.linalg.norm(v_w2)
            theta=theta_sum/theta_den

            word=self.index_word[i]
            word_sim[word]=theta
        words_sorted=sorted(word_sim.items(),key=lambda kv:kv[1],reverse=True)
        for word,sim in words_sorted[:top_n]:
            print(word,sim)

完整代码

import numpy as np
import math
from collections import defaultdict

#定义模型
class word2vec():
    def __init__(self):
        self.n = settings['n']
        self.lr = settings['learning_rate']
        self.epochs = settings['epochs']
        self.window = settings['window_size']

    #定义训练数据函数(一个目标词,以及窗口范围内的词语 把他们都转化为one-hot编码)

    #清洗数据
    def train_data(self,settings,corpus):
        #先对语料库进行去重,得到去重后的每个词语对应的个数 返回的是一个字典
        word_counts=defaultdict(int)
        for row in corpus:
            for word in row:   #这里的word是二维数组里的单词
                word_counts[word]+=1

        # 计算有多少个不同的单词
        self.v_count = len(word_counts.keys())
        #去重后单词放入列表
        self.words_list=list(word_counts.keys())
        #做成 单词:索引(这里要提出i,word两个参数 所以用enumerate)
        self.word_index=dict((word,i) for i,word in enumerate(self.words_list))
        #做成 索引:单词
        self.index_word = dict((i,word) for i, word in enumerate(self.words_list))

    #开始存入目标及窗口范围内的词语
        train_data=[]
        for sentence in corpus:
            sent_len = len(sentence)
            for i, word in enumerate(sentence):
                w_target=self.word2onehot(sentence[i])
                #保存窗口范围内的词语
                w_context=[]
                for j in range(i-self.window,i+self.window):
                    if j != i and j <= sent_len - 1 and j >= 0:
                        w_context.append(self.word2onehot(sentence[j]))
                train_data.append([w_target,w_context])
        return np.array(train_data)

    #定义Onehot函数
    def word2onehot(self,word):
        #初始化都是0
        word_vec=[0 for i in range(0,self.v_count)]
        #找到传入单词在句子中的索引
        word_index=self.word_index[word]
        #将对应位置改为1
        word_vec[word_index]=1
        return word_vec

    #训练模型
    def train(self,train_data):
        #定义权重矩阵

        self.w1=np.random.uniform(-1,1,(self.v_count,self.n))
        self.w2=np.random.uniform(-1,1,(self.n,self.v_count))

        #迭代训练
        for i in range(self.epochs):
            self.loss=0
            for w_t,w_c in train_data:
                #将目标词语进入前向传递
                y_pred,h,u=self.forward_pass(w_t)

                #将窗口误差相加
                EI=np.sum([np.subtract(y_pred,word) for word in w_c],axis=0)

                #反向传播
                self.backprop(EI,h,w_t)

                #计算误差
                self.loss += -np.sum([u[word.index(1)] for word in w_c]) + len(w_c) * np.log(np.sum(np.exp(u)))
            print('Epoch:', i, "Loss:", self.loss)

    def forward_pass(self,x):
        h=np.dot(x,self.w1)
        u=np.dot(h,self.w2)
        y_c=self.softmax(u)
        return y_c,h,u
    def softmax(self,x):
        e_x=np.exp(x-np.max(x))
        return e_x/e_x.sum(axis=0)
    def backprop(self,e,h,x):
        dl_dw2 = np.outer(h, e)
        dl_dw1 = np.outer(x, np.dot(self.w2, e.T))
        self.w1 = self.w1 - (self.lr * dl_dw1)
        self.w2 = self.w2 - (self.lr * dl_dw2)

    # 获取词向量
    def word_vec(self, word):
        w_index = self.word_index[word]
        v_w = self.w1[w_index]
        return v_w

    #获取相似词
    def vec_sim(self,word,top_n):
        v_w1=self.word_vec(word)
        word_sim={}

        for i in range(self.v_count):
            v_w2=self.w1[i]
            theta_sum=np.dot(v_w1,v_w2)
            theta_den=np.linalg.norm(v_w1)*np.linalg.norm(v_w2)
            theta=theta_sum/theta_den

            word=self.index_word[i]
            word_sim[word]=theta
        words_sorted=sorted(word_sim.items(),key=lambda kv:kv[1],reverse=True)
        for word,sim in words_sorted[:top_n]:
            print(word,sim)


"""
word_counts:  {'natural': 1, 'language': 1, 'processing': 1, 'and': 2, 'machine': 1, 
'learning': 1, 'is': 1, 'fun': 1, 'exciting': 1}
words_list:   ['natural', 'language', 'processing', 'and', 'machine', 'learning', 'is', 'fun', 'exciting']
"""
if __name__ == '__main__':

    #准备超参数
    settings = {
        'window_size': 2,  # 窗口大小(目标单词的左边和右边最近的2个单词被视为上下文单词)
        'n': 10,  # 单词嵌入维度,取决于词汇库大小,也是隐藏层大小
        'epochs': 50,  # 训练次数
        'learning_rate': 0.01  # 学习率
    }

    #准备语料库
    text="natural language processing and machine learning is fun and exciting"

    #分词处理
    corpus=[[word for word in text.split()]]
    # print(corpus)
    """
    [['natural', 'language', 'processing', 'and', 'machine', 'learning', 'is', 'fun', 'and', 'exciting']]
    """

    #模型实例化
    w2v=word2vec()
    train_data=w2v.train_data(settings,corpus)
    w2v.train(train_data)

    print(w2v.word_vec("machine"))
    print(w2v.vec_sim("machine",3))






Item2vec

Word2vec诞生后,Embedding思想从自然语言处理领域扩散到了所有机器学习领域。

主要思想

将物品转化为向量,保留物品之间的语义关系

相比于Word2vec利用“词序列”生成词Embedding。Item2vec利用“物品序列”构造物品Embedding。物品之间两两计算cosine相似度即为商品的相似度。

Item2vec摒弃了时间窗口的概念,认为序列中任意两个物品都相关,除此之外模型与skip-gram完全一致

运用

通过矩阵分解产生了用户隐向量和物品隐向量,从Embedding的角度看待矩阵分解,则用户隐向量和物品隐向量就是用户Embedding向量和物品Embedding向量。
item embedding: 利用用户行为序列,采用word2vec思想,生成每个item的Embedding
user embedding:由历史item embedding平均或聚类得到。

局限性

只能利用序列型数据,在处理互联网场景下大量的网络化数据时往往捉襟见肘,由此出现了
Graph Embedding


Deepwalk-基础的Graph Embedding算法

主要思想

解决的是图嵌入问题,把图节点转成n维向量
其中原图中相近的节点,嵌入后依然相近
能够在向量种反映出原图中结构信息,连接信息。
在这里插入图片描述

算法

通过在图里像醉汉一样随机游走,生成一连串随机游走序列,每个序列都类似一句话,其中序列里的每个节点都类似word2vec里的单词。

为何需要随机游走?
图本身非常复杂,我们只能用海量的随机游走序列来捕捉图的信息和模式

可直接套用word2vec种skip-gram方法(中间节点预测相邻节点)可以捕获相邻的关联信息最后迭代优化生成的每个节点的词嵌入向量表。最终能反映出每个节点的相似关系
在这里插入图片描述
在这里插入图片描述

其中word2vec里假设相邻单词是相关的,deepwalk假设在随机游走序列里相邻的节点是相关的

代码

维基百科词条图嵌入
在这里插入图片描述
在这里插入图片描述
通过网站爬取,保存到了tsv文件内构成数据集
在这里插入图片描述

数据集:
https://s3-ap-south-1.amazonaws.com/av-blog-media/wp-content/uploads/2019/11/space_data.zip

#图数据挖掘
import networkx as nx
#数据分析
import pandas as pd
import numpy as np
#随机数
import random
#进度条
from tqdm import tqdm
#降维模块
from sklearn.decomposition import PCA
#word2vec模块
from gensim.models import Word2Vec
import warnings
warnings.filterwarnings('ignore')
#可视化模块
import matplotlib.pyplot as plt
#自然语言处理
from gensim.models import Word2Vec
#降维算法
from sklearn.decomposition import PCA

#获取数据
df = pd.read_csv("space_data.tsv",sep='\t')  #分隔符是\t
print(df.head())

############################################## 构建无向图 ###################################################
G=nx.from_pandas_edgelist(df,"source","target",edge_attr=True,create_using=nx.Graph())#edge_attr: edge属性的列名称 nx.Graph()无向图
# print(len(G)) #生成的节点数

all_nodes=list(G.nodes())  #将无向图的所有节点放入列表中
print(all_nodes)

################################ 构建生成随机游走节点序列的函数(输入起始节点和路径长度,生成随机游走序列)###############
def get_randomwalk(node,path_length):
    random_walk=[node]
    for i in range(path_length-1):
        temp=list(G.neighbors(node))           #汇总邻接节点

        random_node=random.choice(temp)        #随机选择一个邻接节点
        random_walk.append(random_node)        #将此邻接节点放入列表内
        node=random_node                       #最后从此邻接节点当作第二次的初始节点
    return random_walk
# print(get_randomwalk('space exploration',4))

###################################### 对每个节点都去做生成随机游走序列 ############################################
gamma=10 #每个节点作为起始节 点生成随机游走序列个数
walk_length=5 #随机游走序列最大长度

random_walks=[]
for n in tqdm(all_nodes):   #遍历每个节点
    for i in range(gamma):  #每个节点作为起始节点生成gamma个随机游走序列
        random_walks.append(get_randomwalk(n,walk_length))
print(len(random_walks))
# print(random_walks[2])

############################################ 训练word2vec模型 #################################################
model=Word2Vec(
    vector_size=256, #embedding维数
    window=4,        #窗口宽度
    sg=1,            #skip-gram模型
    hs=0,            #不加分层softmax
    negative=10,     #负样本采样
    alpha=0.03,      #学习率
    min_alpha=0.0007,#最小学习率
    seed=14          #随机数种子
)
#用随机游走序列构建词汇表
model.build_vocab(random_walks,progress_per=2)
#训练
model.train(random_walks,total_examples=model.corpus_count,epochs=50,report_delay=1)
#查看某个节点的Embedding
# print(model.wv.get_vector('space exploration'))
#找相似词语
# print(model.wv.similar_by_word('in-space propulsion technologies'))

################################# PCA降维可视化 (256维(高维能捕获更丰富的信息)是看不到的只能转化为2维)#################
X=model.wv.vectors
#将Embedding用PCA降维到2维
pca=PCA(n_components=2)
embed_2d=pca.fit_transform(X)
print(embed_2d.shape)

plt.figure(figsize=(14,14))
plt.scatter(embed_2d[:,0],embed_2d[:,1])
plt.show()

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
t-sne(t-Distributed Stochastic Neighbor Embedding)数据可视化是一种常用的降维算法,用于将高维数据映射到低维空间中,以便于数据的可视化展示。 在MATLAB中,我们可以使用已有的工具箱或自己编写程序来实现t-sne数据可视化。以下是一种用MATLAB编写程序的示例: 1. 导入数据:首先,我们需要导入待处理的高维数据。可以使用`load`函数或其他读取数据的函数将数据加载到MATLAB中。 2. 数据预处理:针对不同的数据类型和目的,我们可能需要对数据进行预处理。例如,可以进行归一化、去除异常值或缺失值等操作。 3. t-sne降维:接下来,使用`tSNE`函数进行降维。该函数可以设置不同的参数,如迭代次数、学习率、初始维度、输出维度等。例如,可以使用以下代码将数据降维到2维: ``` rng('default'); % 设置随机种子,保证结果可复现 tsne_result = tsne(data, 'NumDimensions', 2); ``` 4. 数据可视化:最后,使用MATLAB的绘图函数将降维后的数据可视化。常见的绘图函数包括`scatter`、`scatter3`、`plot`等。例如,可以使用以下代码将降维后的数据绘制成散点图: ``` scatter(tsne_result(:, 1), tsne_result(:, 2)); ``` 以上就是一个简单的t-sne数据可视化MATLAB程序的示例。根据具体的数据和需求,可能需要进行更多的参数配置和绘图设置。使用MATLAB的这些基本步骤,可以轻松实现t-sne数据可视化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值