您的位置:首页 > 编程语言

案例+代码详解:用Word2Vec建立你的私人购物助手

2019-08-29 13:02 1526 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/duxinshuxiaobian/article/details/100135617

全文共7812字,预计学习时长16分钟或更长

图片来源:unsplash.com/@pixtolero2

你注意过亚马逊的“为你推荐”功能吗?事实上,此功能是由机器学习驱动的,精准无比。

网飞、谷歌、亚马逊、Flipkart等公司斥巨资完善推荐引擎是有原因的。推荐引擎是强大的获客渠道,并能增强用户体验。

举个例子:登录一个常用的网上商城买躺椅,商城会展示出几百种躺椅。

从传统的两座躺椅到回压躺椅;从可升降躺椅到靠墙躺椅。我们试着点开一个皮革手动躺椅:

 

注意此页面上展现的不同信息。图片左边包含从不同角度拍摄的产品照片。右边展示了产品细节以及相似产品图片。

网站推荐给我们相似的产品,帮消费者节省了手动搜寻和浏览相似扶手椅的时间。

本文将将从一个独特的角度展开展示如何搭建推荐系统,即应用一个NLP概念——Word2vec来进行推荐。

目录

1. word2vec介绍——单词的向量表示

2. 如何生成word2vec词嵌入?

2.1 训练数据

2.2 生成word2vec词嵌入

3. 对非文本数据应用word2vec模型

4. 案例研究:对于网上产品推荐使用word2vec

1. word2vec介绍——单词的向量表示

众所周知,机器处理原始文本数据。实际上,机器几乎不可能处理数据文本之外的其它文本。因此,以向量的形式表示文本一直是所有NLP任务的重要步骤。

其中非常关键的一步是word2vec词嵌入的使用。该方法在2013年被引入NLP领域,完全改变了NLP的前景。

这些嵌入法代表了处理词类比和相似度等任务可达到的最高水准。word2vec嵌入法也能实现King – man +woman ~= Queen(国王–男性 + 女性 ~= 女王等任务),近乎神迹。

现在有两种word2vec模型——连续词袋模型与Skip-Gram模型。本文将使用后者。

首先要了解如何计算word2vec向量或嵌入。

 

2. 如何生成word2vec词嵌入?

word2vec模型是一个单个简单隐藏层的神经网络模型。模型任务用于预测语句中每个单词的临近单词。然而,我们的目标与此完全无关。我们想做的只是知道模型被训练后隐藏层所学习的权重。这些权重可做被用做词嵌入。

下面的例子用于理解word2vec模型是如何工作的。思考以下句子:

 

假设“teleport(传输)”这个词作为输入词。该词拥有规格为2的上下文窗口。这意味着只将此词左右两侧的两个单词作为相近单词。

注意:上下文窗口的规格非固定,可根据需要改变。

现在,任务是逐一选择相近单词(上下文窗口中的单词)并确定词汇表中每个单词被选中的可能性。听起来很容易,对吗?

通过另一个例子来理解这个过程。

2.1 训练数据

需要一个标签数据集来训练神经网络模型。这意味着数据集需要有一组输入,每组都会有相应输出。这时你可能会想问以下问题:

· 何处寻找这样的数据集?

· 该数据集需要包含什么内容?

· 这组数据有多大?

好消息!可以很容易地创建自己的标签数据来训练word2vec模型。如下阐述了如何从文本生成数据集。应用其中的一个句子并创建训练数据。

第一步:黄色高亮单词作为输入,绿色高亮单词为输出。窗口规格为2个单词。将首单词作为输入词。

 

因此,该输入词的训练样本如下所示:

输入

输出

we

must

we

become


第二步:将第二个单词作为输入词。上下文窗口将同时改变。现在的相近单词变成了“we”、“become”和“what”。

 

新的训练样本将附于之前的样本后面,如下所示:

输入

输出

we

must

we

become

must

we

must

become

must

what


重复以上步骤直至最后一个单词。最后,完整的训练数据如下所示:

输入

输出

we

must

we

become

must

we

must

become

must

what

become

we

become

must

become

what

become

we

what

must

what

become

what

we

what

wish

we

become

we

what

we

wish

we

to

wish

what

wish

we

wish

to

wish

teach

to

we

to

wish

to

teach

teach

wish

teach

to


一个句子能生成27个训练样本。太赞了!这是我喜欢处理非结构化数据的原因之一——能让标签数据集从无到有。

2.2 生成word2vec词嵌入

现在假设存在一组句子,用同样的方法提取出一组训练样本。将会得到大量训练数据。

假设该数据集中唯一单词(即只出现一次的单词)的数量是5000,并且希望为每一个单词创建规格为100的单词向量。同时word2vec架构如下所示:

· V=5000(词汇表规格)

· N=100(隐藏单元数量或词嵌入长度)

输入是独热编码向量,输出层是词汇表中各单词成为相近单词的概率。

一旦模型被训练,很容易提取WV x N 矩阵的学习权重,并用以提取单词。

 

如上所示,权重矩阵的规格为5000x100。第一行对应词汇表中的第一个单词,第二行对应第二个,以此类推。

 

这就是通过word2vec生成固定规格的单词向量或单词嵌入的方法。数据集中的相似词会有相似向量,如指向同一方向的向量。比如,“car”和“jeep”两个词有着相似的向量。

 

这是对于NLP中如何应用word2vec模型的简要介绍。

实操之前请回答这个问题:如何将word2vec模型应用于产品推荐等非NLP任务?相信你从读到本文主题就想到了这一点。下面解决此问题。

 

3. 将word2vec模型应用于非文本数据

运用word2vec创建文本向量表示所需的自然语言有什么本质特征?

其本质特征即为文本的序列特质。每个句子或短语都包含单词序列。在没有序列的情况下,读者将难以理解文本。试试解释以下句子:

"these most been languages deciphered written of have already"

这个句子没有序列。读者很难理解句意,因此单词序列对于理解任何自然语言都很重要。此特质让我想到同样拥有序列的数据。

这样的一组数据是电商网站顾客的购物记录。消费者行为通常存在一定模式。比如,参与运动相关活动的人群可能会有如下购买模式:

购买历史

如果每一个产品都能用向量表示,就能很容易地找到相似产品。因此,如果顾客正在网上浏览商品,那么应用两产品之间的向量相似性评分很容易为其推荐相似产品。

然而,如何生成产品的向量表示呢?可以使用word2vec模型生成吗?

当然可以!把顾客购买历史作为输入句子,把商品作为输出单词:

 

进一步处理网上零售数据,运用word2vec嵌入就能构建出一个推荐系统。

4. 案例研究:使用word2vec模型用Python进行网上商品推荐

搭建并理解我们的问题陈述。

需要基于顾客消费历史,在电商网站上为其建立自动推荐特定数量商品的系统。

点击此链接,使用一组网上零售数据集:https://archive.ics.uci.edu/ml/machine-learning-databases/00352/

启动Jupyter Notebook,快速导入所需库并载入数据集。

import pandas as pdimport numpy as npimport randomfrom tqdm import tqdmfrom gensim.
models import Word2Vec import matplotlib.pyplot as plt%matplotlib inlineimport warnings;
warnings.filterwarnings('ignore')
df = pd.read_excel('Online Retail.xlsx')df.head()

以下是对于该数据集某些领域的描述:

1. InvoiceNo: 发票号码,每次交易对应的唯一数字

2. StockCode: 产品/物品编码,每一唯一商品对应的唯一数字

3. Description:产品描述

4. Quantity:每次交易每种产品的数量

5. InvoiceDate: 每次交易生成的日期和时间

6. CustomerID:顾客ID,每位顾客对应的唯一数字。

df.shape

输出: (541909, 8)

该数据集包含541909次交易。这是一个搭建模型的极佳数字。

处理缺失数据

# check for missing valuesdf.isnull().sum()

已有充足数据,接下来去除所有含缺失值的行。

# remove missing valuesdf.dropna(inplace=True)

数据准备

将产品编码转换为线性数据:

df['StockCode']= df['StockCode'].astype(str)

查看数据集中唯一顾客的数量:

custoes = df["CustomerID"].unique().tolist()len(customers)

输出:4372

数据集中有4372个顾客。对于每一个顾客,提取其购买历史。换句话说,有4372个购买顺序。

从数据集中保留一小部分用以验证是很好的做法。因此,将使用90%的顾客数据创建word2vec嵌入。将数据分割。

# shuffle customer ID'srandom.shuffle(customers)
# extract 90% of customer ID'scustomers_train =
[customers[i] for i in range(round(0.9*len(customers)))]
# split data into train and validation settrain_df = df[df['CustomerID'].
isin(customers_train)]validation_df = df[~df['CustomerID'].isin(customers_train)]

将对于数据集中的顾客创建购买顺序,兼顾训练和验证的目的。

# list to capture purchase history of the customerspurchases_train = []
# populate the list with the product codesfor i in tqdm(customers_train):
temp = train_df[train_df["CustomerID"] == i]["StockCode"].tolist()
purchases_train.append(temp)
# listocapture purchase history of the customerspurchases_val = []
# populate the list with the product codesfor i in tqdm(validation_df['CustomerID'].
unique()):    temp = validation_df[validation_df["CustomerID"] == i]["StockCode"].
tolist()    purchases_val.append(temp)

为产品创建word2vec词嵌入

# train word2vec modelmodel = Word2Vec(window = 10, sg = 1, hs = 0,
negative = 10, # for negative sampling
alpha=0.03, min_alpha=0.0007,
seed = 14)model.build_vocab(purchases_train, progress_per=200)model.
train(purchases_train, total_examples = model.corpus_count,
epochs=10, report_delay=1)

因为不再需要训练模型,呼叫 init_sims( )。这会使得模型记忆能力更强。

model.init_sims(replace=True)

查看模型总结:

print(model)

输出:word2vec(词汇=3151,规格=100,透明度=0.03)

本模型有3151个唯一单词,其规格向量各自为100。接下来,提取词汇表中所有单词的向量,将其存储以便取用。

# extract all vectorsX = model[model.wv.vocab]X.shape

输出:(3151,100)

视觉化word2vec词嵌入

视觉化呈现已创建的嵌入总是很有帮助。此处有100个维度的嵌入。我们连4维都不能视觉化呈现,更别提100维了。那究竟该怎么办呢?

将通过UMAP算法把产品嵌入维度从100减少至2。这在维度减少中的应用十分常见。

import umapcluster_embedding = umap.
UMAP(n_neighbors=30, min_dist=0.0,
n_components=2, random_state=42).fit_transform(X)plt.
figure(figsize=(10,9))plt.scatter(cluster_embedding[:, 0],
cluster_embedding[:, 1], s=3,
cmap='Spectral')

上图中每个点都代表一个产品。图上几处聚集的数据点代表相似产品。

开始推荐产品

恭喜!数据集中每一个产品的word2vec嵌入都已完成。现在,需要为特定产品或产品向量推荐相似产品。

首先创建产品ID以及产品描述库,以便于将产品描述和ID相互匹配。

products = train_df[["StockCode", "Description"]]
# remove duplicatesproducts.drop_duplicates(inplace=True, subset='StockCode', keep="last")
# create product-ID and product-description
dictionaryproducts_dict = products.groupby('StockCode')['Description'].
apply(list).to_dict()
# test the dictionaryproducts_dict['84029E']

输出:[‘RED WOOLLY HOTTIE WHITE HEART.’]

以下对该函数进行了定义。将产品向量作为输入,相似性最大的6个产品为输出:

def similar_products(v, n = 6):
# extract most similar products for the input vector
ms = model.similar_by_vector(v, topn= n+1)[1:]
# extract name and similarity score of the similar products
new_ms = []
for j in ms:
pair = (products_dict[j[0]][0], j[1])
new_ms.append(pair)
return new_ms

尝试运行函数,传输产品‘90019A’的向量(‘SILVER M.O.P ORBIT BRACELET’):

similar_products(model['90019A'])

输出:

[(‘SILVER M.O.P ORBIT DROP EARRINGS’, 0.766798734664917),

(‘PINK HEART OF GLASS BRACELET’, 0.7607438564300537),

(‘AMBER DROP EARRINGS W LONG BEADS’, 0.7573930025100708),

(‘GOLD/M.O.P PENDANT ORBIT NECKLACE’, 0.7413625121116638),

(‘ANT COPPER RED BOUDICCA BRACELET’, 0.7289256453514099),

(‘WHITE VINT ART DECO CRYSTAL NECKLAC’, 0.7265784740447998)]

很好!结果关联度很高,且与输入产品匹配度高。然而,输出只是基于单一产品向量。如果要基于多次购物历史推荐产品呢?

一个简单的解决办法是:提取顾客所购买全部产品向量平均值并根据其找到相似产品。将使用如下包含众多产品ID的函数,其输出了一个100维向量,这是输入产品向量之一:

def aggregate_vectors(products):
product_vec = []
for i in products:
try:
product_vec.append(model[i])
except KeyError:
continue
return np.mean(product_vec, axis=0)

注意之前已创建购买顺序的单独列表以便验证。现在将其利用起来。

len(purchases_val[0])

输出:314

第一个已购产品的列表长度为314。将用于验证的产品顺序表输入函数aggregate_vectors。

aggregate_vectors(purchases_val[0]).shape

输出:(100,)

函数输出100个维度。这意味着函数运转正常。现在用此结果得出最相似的产品:

similar_products(aggregate_vectors(purchases_val[0]))

输出:

[(‘PARTY BUNTING’, 0.661663293838501),

(‘ALARM CLOCK BAKELIKE RED ‘, 0.640213131904602),

(‘ALARM CLOCK BAKELIKE IVORY’, 0.6287959814071655),

(‘ROSES REGENCY TEACUP AND SAUCER ‘, 0.6286610960960388),

(‘SPOTTY BUNTING’, 0.6270893216133118),

(‘GREEN REGENCY TEACUP AND SAUCER’, 0.6261675357818604)]

结果显示,系统可根据顾客全部消费历史推荐6个产品。而且,若想根据最后几次购买记录得到推荐,也可以使用相同的函数。

以下仅以近十次购买记录作为输入:

similar_products(aggregate_vectors(purchases_val[0][-10:]))

输出:

[(‘PARISIENNE KEY CABINET ‘, 0.6296610832214355),

(‘FRENCH ENAMEL CANDLEHOLDER’, 0.6204789876937866),

(‘VINTAGE ZINC WATERING CAN’, 0.5855435729026794),

(‘CREAM HANGING HEART T-LIGHT HOLDER’, 0.5839680433273315),

(‘ENAMEL FLOWER JUG CREAM’, 0.5806118845939636)]

可代入不同编码和验证组中的顺序生成不同推荐。

完整代码传送门:https://github.com/prateekjoshi565/recommendation_system/blob/master/recommender_2.ipynb

留言 点赞 关注

我们一起分享AI学习与发展的干货
欢迎关注全平台AI垂类自媒体 “读芯术”

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: