Apache Druid 中的实时数据—选择正确的策略
为什么你应该使用卡夫卡索引而不是宁静
Photo by Luke Chesser on Unsplash
在实时数据流中存储数据一直是一个挑战。解决方案取决于您的使用案例。如果你想为每日或每月的分析存储数据,你可以使用分布式文件系统,并在其上运行 Hive 或 Presto 。如果你要运行一些简单的实时分析,你可以将最近的数据存储在 Elasticsearch 中,并运行 Kibana 来获取图表。
Apache Druid 是为了同时解决上述两种用例而设计的。它可以作为每日或每月分析的持久数据存储。它还可以作为快速可查询数据存储,允许您实时推送和检索数据。
然而,早期版本的 Apache druid 的问题是从数据库的流中获取数据。让我们来看看开发人员早先面临的挑战。
平静
宁静是 Apache Druid 提供的摄取实时数据的包。宁静并不完全等同于 JDBC 或卡珊德拉司机。它为您处理分区、复制、服务发现和模式翻转。用户需要关心他需要使用的数据和数据源。
Ingesting realtime data using Tranquility
宁静解决了用户可能面临的许多问题。然而,它也伴随着自身的一系列挑战。
不完全是一次
在某些情况下,宁静会创建重复的记录。它不提供任何一次性的保证。在某些情况下,比如 POST 请求数据超时或者没有收到 ack,宁静会产生重复的记录。
在这种情况下,用户需要承担消除重复数据的责任。如果您正在使用 Apache 超集,它甚至会导致其中的图形不正确。
数据丢失
宁静最关心的问题是数据丢失。有各种情况下,宁静故意或由于错误无法插入数据。官方文件中列出的一些案例是—
- 时间戳超出您配置的窗口周期的事件将被丢弃。
- 如果您遇到的 Druid 中级管理器故障多于您配置的副本数,一些部分索引的数据可能会丢失。
- 如果有一个持续的问题阻止了与 Druid 索引服务的通信,并且重试策略在此期间用尽,或者此期间持续的时间超过了您的 windowPeriod ,一些事件将被丢弃。
- 如果有一个问题阻止了宁静从索引服务接收确认,它将重试批处理,这可能导致重复的事件。
最糟糕的是,在大多数情况下,直到查询时,您才知道您的数据已经被删除。
错误处理
因为宁静守护进程运行在 JVM 内部,所以处理超时之类的错误是应用程序的责任。对于像 Apache Flink 这样的应用程序,如果不能有效地管理其中一个错误,就会导致不必要的重启。
在所有这些问题之上,宁静是为德鲁伊 0.9.2 构建的。将它与当前的 druid 版本 0.16.0 一起使用会产生无法识别的问题。
卡夫卡索引
为了解决上述所有问题,Apache druid 在 0.9.1 版本中添加了 Kafka Indexer。在版本 0.14 之前,索引器一直处于实验状态。
Kafka 索引服务首先根据您指定的配置启动一个管理程序。然后,管理员会定期启动新的索引任务,这些任务负责从 Kafka 消费数据,并将其发布到 Druid 中。
与宁静不同,Kafka 索引任务可以长期运行。在达到最小行数或字节数后,可以发布多个段,而无需启动新任务。
Kafka Indexer in Apache Druid
卡夫卡索引器旨在解决其前辈所面临的各种挑战。
恰好一次语义
Kafka 索引器为用户提供了一次精确的保证。这种保证是可能的,因为 Kafka 0.11.x 提供了对这种语义的现成支持。
发布延迟的数据
Kafka 索引器旨在发布延迟的数据。它不受宁静窗口期的影响。这种能力让用户可以自由地将 Kafka 中特定偏移量的数据回填到 Druid 中。
模式更新
尽管宁静也支持模式更新,但在 Kafka Indexer 中要容易得多。您只需要提交一个包含新模式的 POST 请求,主管将使用更新后的模式生成新任务。你不需要在生产者端做任何改变。
如果您添加了新的列,旧的行将在这些列中显示空值,但是这些行仍然是可查询的。
Kafka 索引器服务解决了开发人员在使用宁静时面临的许多问题。如果你想开始使用 Kafka 索引服务,你可以参考官方 Druid 文档中的 Apache Kafka 摄取。
用概率和火焰推理——我的模型够好吗?
在其核心,概率编程是为了回答关于不确定性的问题。一些非常受欢迎的在线例子讨论了使用概率编程来帮助神经网络,并使它们更有能力处理他们没有训练过的新例子。然而,在本教程中,我将介绍概率编程可以帮助的最基本的功能。
这里的例子在很大程度上摘自扎克·安临来的演讲,他在演讲中介绍了使用 PyMC3 的概率编程。我将使用 Pyro ,因为我看到这个库在未来会起飞,我想探索它更多一点。
示例场景
让我们考虑以下简单的工作流程:
- 获取数据(在这种情况下是一个样本数据集)
- 执行训练/测试分割
- 根据训练数据训练模型
- 测试模型的性能,决定性能好不好
Import required packages
Obtain our data
>>> (70000, 784)
>>> (70000,)
Split the data into train and test
>>> (56000, 784) (14000, 784)
>>> (56000,) (14000,)
Train a decision tree on our train data, and test its performance on the test data
>>> Accuracy is 87.06%
分析
我们可以尝试提高模型的准确性,使其达到 87%以上,甚至采用更强的模型,如 CNN,但有一个稍微不太明显的问题。想想我们如何知道我们有 87%的准确率。
我们的测试集是 14000 个带标签的例子。这是一种真正的奢侈,因为对于一些数据科学问题,我们可能不会遇到这么多标记良好的例子。如果我们只有 100 个例子,而不是 14000 个,会怎么样?
>>> (100, 784) (100,)
Check accuracy again, but only on 100 test observations
>>> Accuracy is 86.00%
我们得到了一个稍低的数字,但仍然是可比的。
也就是说,虽然数字很接近,但相信基于 100 个例子的模型要比相信基于 14000 个例子的模型更难。
直觉上,随着测试集大小的增加,我们对测试集分数的信心也增加了。Pyro 允许我们从数字上估计我们的信心以及我们有多少出错的空间。
烟火模型
Pyro 工作流程非常独特,需要三个组件
- 模拟我们底层模型的模型函数(不是决策树,而是给我们正确或不正确标签的过程)。该功能从先验分布开始
- 当观察到的例子由模型函数产生时,测量它们的似然性的核
- 构建后验分布的采样器
首先我们需要定义我们对 Pyro 的观察。在我们的例子中,我们的观察是我们看到正确和不正确分类的情况。让我们同时考虑小测试集(100 个观测值)和大测试集(14,000 个观测值)。
现在我们必须定义模型函数。该函数接受我们的观察值,并尝试从先验分布中取样,并根据我们的观察值计算先验的可能性。然后,内核会将先验更新为更可能的后验分布。
它看起来不太像,但是在这个模型中发生了两个重要的事件。
- 首先,我们使用“pyro.sample”函数注册一个名为“p”的参数,作为 pyro 的可学习值。使用“pyro.sample”或“pyro.param”将结果值作为可学习值记录在 pyro 的内部存储器(一个特殊的类似字典的对象)中。在我们的例子中,我们已经说过“p”是一个可学习的分布。
- 我们还将每个观察记录为一个可学习的值,它应该符合我们提供给它的观察。
我们将注册该模型的内核(哈密顿蒙特卡罗内核)将查看该模型中定义的所有可学习值,并将尝试调整可学习分布,以便它们增加所提供的观测值的可能性。
我们将使用的采样器(马尔可夫链蒙特卡罗)将运行 HMC 核来寻找后验分布。
>>> Sample: 100%|█████████████████████████████████████████| 200/200 [03:46, 1.13s/it, step size=1.51e+00, acc. prob=0.916]
现在我们已经运行了我们的采样器,我们可以用我们得到的后验概率做几件事。首先,我们可能想把我们定义的概率“p”形象化。我们可以通过从我们的取样器取样来做到这一点。
The posterior distribution for our accuracy score given 100 examples
>>> mean std median 2.5% 97.5% n_eff r_hat
>>> p 0.86 0.04 0.86 0.79 0.93 185.83 1.00
>>> Number of divergences: 0
不是一个很好的结果… 100 次观察并不足以确定一个好的结果。该分布似乎并不集中在一个特定的值上,当我们要求 95%的可信区间时,我们的真实值可以在 79%和 93%之间。对于我们的目的来说,这可能足够准确,也可能不够准确。
让我们看看当我们使用全部 14,000 个观察值时,我们对我们的模型有多大的信心
修改我们的模型
如果我们通过同一个模型运行所有 14,000 个观察值,那么运行时间将会非常长。
这是因为我们在代码中循环遍历每个观察。
Pyro 包含一个更方便的、矢量化的方法来处理我们的模型。
首先,我们重新定义了模型函数,使其不接受任何观察值,而是返回自己的观察值
现在,我们定义了第二个函数,它将模型函数和观察值作为输入,并利用“pyro.poutine”在条件环境中运行模型函数。重要的是,我们在这里的观察值与它们在模型函数中的名称相同(“obs”)。
最后,我们重新运行 MCMC 采样器,但是现在使用我们的条件模型,我们发送我们的模型函数,以及我们的观察,作为参数
>>> Sample: 100%|█████████████████████████████████████████| 200/200 [01:47, 1.86it/s, step size=7.87e-01, acc. prob=0.984]
The posterior distribution for our accuracy score given 14,000 examples
>>> mean std median 2.5% 97.5% n_eff r_hat
>>> p2 0.87 0.00 0.87 0.87 0.87 9.88 1.07
>>> Number of divergences: 0
现在,我们可以在 87%左右得到更紧密的配合。为了比较这两个分布,我们可以把它们画在一起。
The two posterior distributions for our accuracy based on the number of support examples
我希望你们都喜欢阅读这篇关于 Pyro 及其功能的简介。我当然期待尝试新的东西,更多地使用概率编程!
你不应该再考虑数据科学的理由。等等,我有说不应该吗!
“信息是 21 世纪的石油,分析是内燃机。”
大数据 和数据科学的力量正在从根本上改变世界。自从我们进入大数据时代以来,数据科学 已经成为增长最快、价值数百万美元的公司之一。如今一切都被数据淹没了。数据存在于每个数字和电子设备中。无论是电脑、手机、笔记本电脑、相机还是手表。
公司正在收集数据进行分析,并从中得出真知灼见。
当你在购物中心或任何商店购物,或者你去餐馆时,他们会给你一份反馈表让你填写。或者他们要求您对他们提供的产品和服务进行反馈。你提供的反馈或他们收集的反馈只不过是数据。
因此, 数据科学 就是收集数据,分析数据,并借助数据做出决策的过程。它是一个研究领域,涉及借助科学方法和算法从原始数据中提取有意义的见解,然后有效地传达这些见解,从而产生价值。
数据形式:
数据就像冰一样,就像三种形式的冰一样,它有三种状态(一个糟糕的笑话,但会帮助你理解)。😛
数据可以是结构化的、非结构化的和半结构化的:
1)结构化 -
它是用于分析过程的有组织的数据。它是经过处理的数据。例如:关系数据。
2)半结构化-
它有一些组织属性,但是不适合数据库系统。例如:XML/RDF 数据。
3)非结构化-
它是不以任何方式组织的数据,是最灵活的数据形式。例如:Word、PDF、Text。
我想这个形象是如此贴切和不言自明。数据科学是计算机科学、数学和统计学的混合体。一个愿意从事数据科学职业的人需要在数学、计算机编程和统计学方面有坚实的基础。优秀的教育背景,R 或 Python 等各种编程语言的知识,最重要的是,成为一名数据科学家需要时间和努力。
关键组件
随着对数据洞察力的需求不断增加,数据科学对于每个领域都是必要的。以下是数据科学角色的一些关键组成部分:
1)收集和查询数据:数据科学家在流程分析过程中收集、查询和消费数据。他们专注于数据的分析、预测和可视化。数据科学家必须查询数据,不管数据是如何存储的,也不管数据存储在哪里。查询数据包括编写命令从数据存储系统中提取信息。很多时候, SQL (结构化查询语言)就是用来做这个的。
2)从数学模型中获得洞察力:数据科学家的工作需要数学技能,因为理解数据需要数学技能。这些是用来进行预测和决策的技能。数学方法也用于建立模型和生成近似值。
3)将一些技能 和一些统计方法应用于数据科学任务:统计技能和方法对于验证假设和预测未来事件的预测是有用和必要的。了解一些基本的统计方法,如线性回归、相关性、贝叶斯定理和时间序列分析是必不可少的,有助于生成可能的数据结果。
4)编码是游戏的一部分:在使用数据科学时,编码是不可避免的。你需要能够编写代码来指示和指导计算机如何分析和可视化你的数据。虽然 SQL 对于查询数据是必要的,但是诸如【Python】R 等编程语言对于数据的分析和可视化是有用的。
5)将数据科学应用于主题领域:数据科学家需要在他们工作的领域拥有主题专业知识。他们从给定的数据中产生深刻的见解,然后理解这些见解对于他们工作的领域意味着什么。主题专家正在使用数据科学来提高他们在各自行业中的表现:
a)IT 行业 - 工程师在现代建筑设计中使用机器学习。
b)医疗行业 - 临床数据科学家制定治疗计划,并使用医疗保健信息来预测处于风险中的患者未来的健康问题。
c)电子商务 - 营销数据科学家使用回归和相关来预测消费者偏好的变化或消费者从一种产品或服务流失到竞争对手的产品或服务。
6)交流数据见解:作为一名数据科学家,你必须有很强的口头和书面交流技能,并且能够交流这些技能,否则所有的知识和见解对你的组织都没有好处。数据科学家需要在沟通方式和方法上具有创造性和实用性。
所有这些都是好的。但是,我将如何从学习数据科学中受益
1)它永远不会让你感到无聊 —在学习数据科学的过程中,你会被分配很多任务,让你专注于工作,很难对所有这些项目感到厌倦。
你有很多职业选择可以选择——数据管理在所有组织、所有级别都很重要。不仅大型 It 软件公司需要数据科学,银行和金融行业、零售行业、医疗保健行业等也需要数据科学。各种职位可以是分析工程师、分析经理、大数据工程师、业务分析师、数据架构师、数据分析师、数据工程师、数据科学家、数据可视化专家、统计学家。
3)有助于改善沟通 —学习数据科学也是学习如何向第三方传达结果和见解。沟通是你需要努力的事情,它不仅在数据科学领域,而且在任何地方都是一种伟大的品质!
4)巨大的需求 —数据科学是一个需要很多技能的领域,所以很难找到具备所有这些技能的人。数据科学专业人员很有价值,他们的需求也很高。
高薪——随着需求的增加,这是几乎所有国家中收入最高的职业之一。这个职业的工资范围(美国)在 65,000 美元到 150,000 美元之间。
等等!你知道一个数据科学家的 工资 吗?
结论:
所有的公司都有数据,他们只需要弄清楚如何利用这些数据来为自己谋利。利用这些数据的人越来越多,因为今天一切都围绕着客户,让他们能够获得内容是最重要的事情。
数据科学家利用他们在数学、统计、编程和不同学科领域的技能来组织大型数据集。他们运用自己的知识和专业技能来发现隐藏在数据中的解决方案,以应对业务挑战并实现目标。
接收我们的时事通讯
想要了解数据科学的最新动态,并在您的收件箱中收到我们提供的最佳信息吗?这里有几个你可能感兴趣的时事通讯选项。
Photo by Alejandra Cifre González on Unsplash
变量:
每周四,Variable都会带来最好的数据科学:从实践教程和前沿研究到你不想错过的原创功能。
我们的每周文摘:
我们的文摘为您提供个性化的推荐,每周五直接发送到您的收件箱**。**订阅很简单。只需点击左侧矩形中的“关注”按钮,并在您的设置中打开“接收信件”即可关注我们的出版物。
Python 的新近性、频率、货币模型——以及丝芙兰如何使用它来优化他们的谷歌和脸书广告
上次我们使用群组分析方法分析了我们的在线购物者数据集。我们围绕我们的队列数据集发现了一些有趣的观察结果。虽然群组分析为我们提供了长期的客户行为并了解了保留率,但我们还希望能够根据他们的行为对我们的数据进行细分。今天,我们将探索零售商使用的流行的 RFM 模式,如丝芙兰,将店内和网上购买相结合,以细分客户,获得更好的个性化广告内容。我强烈推荐关注丝芙兰博客的数据科学,以获得更深入的数据见解。你也可以看看这篇由 Jimmy Joe 撰写的文章,他在文章中深入探讨了利用 RFM 实现客户终身价值的秘密。
什么是 RFM?
通过 3 个重要特征进行行为细分:
- 最近——自上次购买以来的天数
- 频率——特定时期内的交易数量
- 货币——在给定时间内花费的金额
然后,我们必须按以下方式对这些功能进行分组:
- 百分位数或分位数
- 帕累托法则——80/20
- 商业头脑
我们将对我们的方法实施百分位数分组。
现在让我们继续学习 Python。
这些是我们今天分析所需要的库。稍后,我们将使用 squarify 将我们的分割绘制成树形图。
# Import libraries
import pandas as pd
from datetime import timedelta
import matplotlib.pyplot as plt
import squarify
我们将再次分析我们的在线购物者数据集,但这次是用我们的 RFM 模型。
# Read dataset
online = pd.read_csv('../data.csv', encoding = "ISO-8859-1")# Convert InvoiceDate from object to datetime format
online['InvoiceDate'] = pd.to_datetime(online['InvoiceDate'])
让我们仔细看看我们需要处理的数据。
**Input:**
print('{:,} rows; {:,} columns'
.format(online.shape[0], online.shape[1]))print('{:,} transactions don\'t have a customer id'
.format(online[online.CustomerID.isnull()].shape[0]))print('Transactions timeframe from {} to {}'.format(online['InvoiceDate'].min(),
online['InvoiceDate'].max()))**Output:**
541,909 rows; 8 columns
135,080 transactions don't have a customer id
Transactions timeframe from 2010-12-01 08:26:00 to 2011-12-09 12:50:00**Input:**
# Drop NA values from online
online.dropna()
我们需要做的第一件事是根据最近、频率和货币价值对客户进行分类。为了计算最近,我们将把数据集的最后一个发票日期之后的一天作为快照日期’2011–12–10 12:50:00 '。日期差异将告诉我们最近一次交易是什么时候完成的。这样,我们就可以根据客户 ID 对**‘在线’数据框进行分组,并将其分配给‘数据处理’**进行数据预处理。
# --Group data by customerID--# Create TotalSum column for online dataset
online['TotalSum'] = online['Quantity'] * online['UnitPrice']# Create snapshot date
snapshot_date = online['InvoiceDate'].max() + timedelta(days=1)
print(snapshot_date)# Grouping by CustomerID
data_process = online.groupby(['CustomerID']).agg({
'InvoiceDate': lambda x: (snapshot_date - x.max()).days,
'InvoiceNo': 'count',
'TotalSum': 'sum'})# Rename the columns
data_process.rename(columns={'InvoiceDate': 'Recency',
'InvoiceNo': 'Frequency',
'TotalSum': 'MonetaryValue'}, inplace=True)
让我们看看目前为止的进展。
# Print top 5 rows and shape of dataframe
print(data_process.head())
print('{:,} rows; {:,} columns'
.format(data_process.shape[0], data_process.shape[1]))**Output:**
Recency Frequency MonetaryValue
CustomerID
12346.0 326 2 0.00
12347.0 2 182 4310.00
12348.0 75 31 1797.24
12349.0 19 73 1757.55
12350.0 310 17 334.40
4,372 rows; 3 columns
太好了,我们有 4,372 条客户记录,根据他们购买的最近时间、频率、数量和购买的货币价值进行分组。现在我们可以进入事物的内部,使用。qcut()方法将相对百分位数分配给他们的 RFM 特征。但在此之前,让我们检查一下我们的近因、频率和货币的分布。
**# Plot RFM distributions**
plt.figure(figsize=(12,10))# Plot distribution of R
plt.subplot(3, 1, 1); sns.distplot(data_process['Recency'])# Plot distribution of F
plt.subplot(3, 1, 2); sns.distplot(data_process['Frequency'])# Plot distribution of M
plt.subplot(3, 1, 3); sns.distplot(data_process['MonetaryValue'])# Show the plot
plt.show()
这张图为我们提供了一些非常有趣的见解,以及我们的数据是如何扭曲的。这里需要注意的重要一点是,我们将用分位数对这些值进行分组。然而,当我们在接下来使用 K-Means 检查我们的客户细分时,确保我们将数据调整到均值和标准差的中心是非常重要的。下次会有更多。让我们继续。qcut()为我们的 RFM。
# --Calculate R and F groups--# Create labels for Recency and Frequency
r_labels = range(4, 0, -1); f_labels = range(1, 5)# Assign these labels to 4 equal percentile groups
r_groups = pd.qcut(data_process['Recency'], q=4, labels=r_labels)# Assign these labels to 4 equal percentile groups
f_groups = pd.qcut(data_process['Frequency'], q=4, labels=f_labels)# Create new columns R and F
data_process = data_process.assign(R = r_groups.values, F = f_groups.values)
data_process.head()
我们为 f_labels 创建了一个 4 标签,其中 4 是“最佳”分位数。我们为我们的 f_label 做同样的事情。然后,我们创建新的列“R”和“F ”,并分别为它们分配 r_group 和 f_group 值。
接下来,我们对货币值进行同样的操作,使用。qcut()方法。
# Create labels for MonetaryValue
m_labels = range(1, 5)# Assign these labels to three equal percentile groups
m_groups = pd.qcut(data_process['MonetaryValue'], q=4, labels=m_labels)# Create new column M
data_process = data_process.assign(M = m_groups.values)
最后,有了这 3 个分数,R,F 和 M,我们可以通过将下面的值连接在一起来创建我们的第一个 RFM 线段。让我们将 data_process 数据帧分配给新创建的 rfm 数据帧。
# Concat RFM quartile values to create RFM Segments
def join_rfm(x): return str(x['R']) + str(x['F']) + str(x['M'])
data_process['RFM_Segment_Concat'] = data_process.apply(join_rfm, axis=1)rfm = data_process
rfm.head()
从输出中,您可以看到我们已经准备好将连接的数据段用于分段,但是,等等,还有一个问题…
# Count num of unique segments
rfm_count_unique = rfm.groupby('RFM_Segment_Concat')['RFM_Segment_Concat'].nunique()
print(rfm_count_unique.sum())**Output:** 62
使用 concatenate 方法拥有 62 个不同的段对于任何实际应用来说都很快变得不实用。我们需要一种更简洁的方式来定义我们的细分市场。
合计分数
最直接的方法之一是将我们的分数相加为一个数字,并为每个分数范围定义 RFM 等级。
**# Calculate RFM_Score** rfm['RFM_Score'] = rfm[['R','F','M']].sum(axis=1)
print(rfm['RFM_Score'].head())**Output:**CustomerID
12346.0 3.0
12347.0 12.0
12348.0 8.0
12349.0 10.0
12350.0 4.0
Name: RFM_Score, dtype: float64
我们可以发挥创意,假设每个分数范围意味着什么,但在这个练习中,我将从一些常见的部分名称中获得灵感。
# Define rfm_level function
def rfm_level(df):
if df['RFM_Score'] >= 9:
return 'Can\'t Loose Them'
elif ((df['RFM_Score'] >= 8) and (df['RFM_Score'] < 9)):
return 'Champions'
elif ((df['RFM_Score'] >= 7) and (df['RFM_Score'] < 8)):
return 'Loyal'
elif ((df['RFM_Score'] >= 6) and (df['RFM_Score'] < 7)):
return 'Potential'
elif ((df['RFM_Score'] >= 5) and (df['RFM_Score'] < 6)):
return 'Promising'
elif ((df['RFM_Score'] >= 4) and (df['RFM_Score'] < 5)):
return 'Needs Attention'
else:
return 'Require Activation'# Create a new variable RFM_Level
rfm['RFM_Level'] = rfm.apply(rfm_level, axis=1)# Print the header with top 5 rows to the console
rfm.head()
最后,我们可以根据客户的 RFM 级别对他们进行分组。
# Calculate average values for each RFM_Level, and return a size of each segment
rfm_level_agg = rfm.groupby('RFM_Level').agg({
'Recency': 'mean',
'Frequency': 'mean',
'MonetaryValue': ['mean', 'count']
}).round(1)# Print the aggregated dataset
print(rfm_level_agg)
从这里,我们可以看到很大比例(~60%)的客户处于顶级 RFM 级别。商店必须做一些正确的事情来维持他们的忠诚度!
其余的 40%将需要一些工作。让我们探索使用一些广告来重新定位他们:
- 潜在客户——很有可能进入我们的忠诚客户群,为什么不在他们下次购买时赠送一些赠品,以显示您对他们的重视!
- 有希望——对他们购买的数量和价值表现出有希望的迹象,但距离他们上次从你这里购买已经有一段时间了。让我们针对他们的愿望清单项目和限时优惠折扣。
- 需要关注—初次购买了一些商品,但之后就再也没有见过。是糟糕的客户体验吗?还是产品市场契合度?让我们花一些资源与他们一起建立我们的品牌意识。
- 需要激活——我们的 RFM 模式中表现最差的。他们现在可能已经选择了我们的竞争对手,需要不同的激活策略来赢回他们。
但是在我们结束之前,让我们为我们的数据创建一个漂亮的可视化。
rfm_level_agg.columns = rfm_level_agg.columns.droplevel()
rfm_level_agg.columns = ['RecencyMean','FrequencyMean','MonetaryMean', 'Count']#Create our plot and resize it.
fig = plt.gcf()
ax = fig.add_subplot()
fig.set_size_inches(16, 9)squarify.plot(sizes=rfm_level_agg['Count'],
label=['Can\'t Loose Them',
'Champions',
'Loyal',
'Needs Attention',
'Potential',
'Promising',
'Require Activation'], alpha=.6 )plt.title("RFM Segments",fontsize=18,fontweight="bold")
plt.axis('off')
plt.show()
自然语言处理的最新进展
注意了,变形金刚,伯特还有更多。
在之前的一篇帖子中,我写了 NLP 中最近的两个重要概念——单词嵌入和 RNN 。在这篇文章中,我将介绍 注意 和变压器 的概念,它们已经成为目前 NLP 中大多数最新模型的构建模块。我还将回顾 BERT 在 NLP 中使 的强大概念 的迁移学习变得更加容易
像我之前的帖子一样,我将跳过大部分数学内容,更多地关注直觉理解。原因是——使用过多的符号和等式会让包括我在内的许多人感到厌烦。这实际上对概念理解并不重要,我认为概念理解比理解每一个潜在的数学方程重要得多。
虽然像 Bi-LSTM 这样的 RNN 变体在各种 NLP 任务上表现相当稳定,但仍然存在以下一些关键挑战:
- 缺乏并行性会损害性能 — LSTM 需要按顺序处理给定序列中的输入令牌,因为当前步骤的输出取决于前一步骤的输出。没有办法将这种计算并行化,这带来了训练时间长、不能在非常大的数据集上训练等明显的缺点。
- 学习长期依存关系仍然是一个挑战—虽然与经典的 rnn 相比,LSTMs 更善于从序列中出现过的内容中记住上下文,但从长句子中更早出现的单词中记住上下文仍然是一个挑战,这就是为什么长句子/序列的性能不如短句子/序列的性能。
- 运算次数随距离线性增加— 将两个任意输入或输出位置的信号相关所需的运算次数随位置间的距离线性增加
上述挑战是 2017 年及以后大量工作的动力。注意力的概念解决了上面的挑战#2,而变压器架构解决了挑战# 1 和挑战#3。
需要注意的一点是,虽然注意力和转换者的概念有助于打破 NLP 任务中的既定基准,但这些都是通用技术,可以广泛应用于任何序列到序列任务。例如,变形金刚架构也是打败顶级星际争霸 2职业玩家的 DeepMind 机器人 AlphaStar 的构建模块。
注意力
一般来说,注意力是深度学习中最有影响力的想法之一。虽然这个概念最初是为机器翻译开发的,但它的使用迅速扩展到了许多其他领域。这是由 Dzmitry Bahdanau 等人在这篇有影响力的论文中提出的。
其背后的核心思想是——当执行某个任务时,例如,将句子从一种语言翻译成另一种语言,比如从英语翻译成法语,输出法语句子中的每个单词将由原始输入英语句子中的所有单词(的相关上下文)以不同程度的关注或重要性来通知,而不是由处理整个英语句子生成的单一/恒定上下文。
*考虑以下来自 谷歌博客 *的优秀英语到法语的翻译例子。两个句子中的“它”指的是不同的名词,根据“它”指的是哪个名词,它翻译成法语也不同。
对人来说,很明显,在第一句话中“它”指的是动物,而在第二句话中是指街道
*下图描绘了概念上与(自我)*注意力发生的事情。不是获取整个句子的上下文向量并告知单词“它”的翻译,而是由输入句子中的不同单词告知翻译上下文不同的量,如颜色编码所示(越暗=越重要)
Source: Google Blog
需要注意的一点是——注意模型中的权重不是固定的,像神经网络模型学习的其他参数一样,而是作为输入/隐藏状态的函数来计算的——这就是模型如何知道如何对任何给定句子的输入句子中的相关单词进行适当的强调。
如上所述,注意力的概念通过在每一步使用更合适的上下文(而不是“恒定”上下文,例如基于 LSTM 的编码器-解码器)解决了长期依赖性的问题,但是计算中的非并行性问题仍然存在,因为计算仍然需要顺序进行。有了的关注*,如果有什么不同的话,我们让计算比简单的 LSTMs 更复杂,这就是变压器架构来拯救的地方。*
变压器
Transformer 于 2017 年在这篇开创性论文中推出,作者是来自谷歌的 Vaswani 等人。变压器的网络架构完全基于注意力机制,没有 RNN 或 CNN 单元。以下是该体系结构的一些主要优势:
- 语言翻译任务的高质量结果,超越了以前的基准
- 更高的并行性,需要的培训时间明显减少
- 很好地推广到许多其他任务
Transformer Model Architecture. Source Transformer Paper
上图是变压器的整体架构,乍一看有点吓人。让我们看看架构的高级细节:
- 编码器-解码器架构:它遵循著名的编码器-解码器范例,编码器将输入转换为有用的表示,解码器使用该表示生成输出。在上图中,编码器模块在左边,解码器模块在右边。
- 自动回归:在每一步,模型消耗先前生成的输出作为附加输入
- 没有 RNNs :没有 RNN 单位,只有一堆关注层。
- 多层:每个编码器/解码器由 6 层(模型中的超参数)相同的层组成
- 嵌入:输入/输出嵌入将文本或文字转换成数字。
- 位置编码:位置编码是对原始序列的顺序进行编码,因为我们不再像在 RNN 那样按顺序处理输入,所以它保证了排序的信息不会丢失。
- 多头注意力:有多个注意力层并行运行,以增加多样性(类似于计算机视觉中的多个卷积滤波器)。
- 注意层次:有 3 种注意类型——编码器自我注意、编码器-解码器注意和解码器自我注意。
- 自我关注:在编码器自我关注的情况下(图中左下方的关注块),编码器内的一层试图计算出它应该对(编码器的)前一层的输出给予多少关注,也就是说,试图学习输入中的每个单词与输入中的其他单词的关系/上下文。解码器自我关注(图中右下方的关注块)做了同样的事情,但超过了输出。
- 编码器-解码器注意力:利用编码器-解码器注意力(图中右上角的注意力块),模型计算出输入中的每个单词与输出中的每个单词的相关程度。
有了这些细节,变压器取得的成果令人印象深刻,然而,也有一些需要改进的地方:
- 它只能处理定长句子。
- 需要将较大的句子分解成较小的句子以输入到模型中,这导致“上下文碎片”
BERT —来自变压器的双向编码器表示
首先,一个诚实的坦白——我就是记不住 BERT 的完整形式,不管我读了多少遍,我认为完整形式是从首字母缩略词派生出来的,而不是相反:-)的意思
*BERT 由 Google 的 Jacob 等人提出,是一种基于 *Transformer 的语言表示模型。我认为 BERT 的主要贡献,除了它新颖的双向培训等,还在于它在 NLP 中推广了预培训/ 迁移学习的概念
在我们继续之前,先简单说一下迁移学习。与 NLP 相比,它是深度学习中最优雅的概念之一,在 ComputerVision 中更受欢迎。基本思想是——人们可以在一个通用但相关的任务上训练一个(深度的,即有多个层的)模型,只需在特定于任务的数据上微调最后几层就可以实现出色的性能。
**迁移学习的基本原理是——深度模型中的早期层学习更多的基本模式,例如,学习检测计算机视觉模型中的直线和曲线,而后面的层学习特定于任务的模式,例如学习图片中是否有猫。这种方法的主要好处是——即使在深度学习模型上有适量的数据,你也可以获得很好的性能,这些模型通常非常渴求数据。
以下是关于 BERT 的一些重要细节:
- 双向训练:通过从两个方向看单词来进行联合训练——从左到右和从右到左以获得更好的上下文,其他语言模型通常通过只从一个方向看上下文来进行训练
- 预训练:在巨大的文本尸体(~3B 单词)上进行预训练,因此您只需要微调一个额外的输出层,这是很少的参数(使用您的训练数据),以便在各种任务上获得非常好的性能,如句子分类、问答系统、命名实体识别等,而不必在模型架构中进行太多特定于任务的更改。
- 训练目标:**典型地,语言模型以无监督的方式被训练,目标是在给定单词之前的单词的情况下预测该单词。BERT 接受了两项任务的联合训练——在给定单词左右两边的单词的情况下预测一个单词(有一些关于屏蔽的细节以避免泄漏),以及在给定一个句子的情况下预测下一个句子。后者是不标准的,语言模型通常不直接捕捉句子之间的关系,但这样做有助于像问答系统这样的应用。
- ***模型尺寸:*BERT 论文的作者试验了各种尺寸的 BERT,最著名的是基本型(110M 参数)和大型型(340M 参数)。他们发现,越大越好,即使有相似的模型架构和小的特定任务训练数据,这在很大程度上是由于在巨大的语料库上进行的预训练。
自 2018 年 10 月 BERT 的原始论文以来,已经提出了许多变体和修改。其中最著名的是——脸书·艾的 RoBERTa 和 mBERT,CMU 研究人员的 XLNet 和开放人工智能的 GPT-2。
这就结束了我对 NLP 后期一些令人兴奋的事情的总结,很明显,这个领域发生了如此多的事情,而且速度如此之快。如今,人们可以不费吹灰之力做很多事情,这要归功于该领域的巨头们,他们完成了繁重的工作,并使之变得更加容易。
额外资源
现代计算机视觉的最新进展
超越物体分类的计算机视觉
在过去的 50 年里,计算机已经学会了计数和分类,但直到现在还看不见东西。今天,截至 2019 年,计算机视觉领域正在迅速发展,拥有巨大的潜力来缓解全球范围内从医疗保健差距到移动限制的一切问题。
近年来,我们已经看到在 AlexNet 或类似的基于 CNN 的架构基础上构建的计算机视觉取得了巨大成功。的确,就学习方式而言,这个过程是模仿人脑的;称为神经元的学习单元网络学习如何将输入信号(如房屋的图片)转换为相应的输出信号,如标签“房屋”。关于这方面的更多细节,请看我之前的博客。
在过去的 2-3 年里,我们已经开始在基于深度学习的视觉任务中取得巨大成就,超越了分类。我在这篇博客中提到了其中几个重要的问题。
目标检测
在现有的几种方法中,有两类物体检测技术在现代计算机视觉领域已经流行了 3-4 年
两阶段:基于区域提案
美国有线电视新闻网,快速美国有线电视新闻网,快速美国有线电视新闻网[ 吉尔希克等人 CVPR 2014
- 将整个图像处理到 conv5
- 计算物体的可能位置有些是正确的,大多数是错误的
- 给定单个位置,ROI 汇集模块提取固定长度特征
一阶段:YOLO,固态硬盘,视网膜网
目标检测在这里被框定为一个回归问题。单个神经网络用于直接预测类别和边界框锚,而不需要第二阶段的每个提议的分类操作。
- 不要生成对象建议!
- 通过设计考虑输出空间的微小子集;直接将这一小组盒子分类
- 快速推理,适用于实时目标检测
YOLO 的局限性
- 损失函数在小边界框和大边界框中处理错误是一样的。
- 大盒子里的小错误通常是良性的,但小盒子里的小错误对 IOU 的影响要大得多。
YOLO v3:增量改进
约瑟夫·雷德蒙,阿里·法尔哈迪- 2018
- 这是一个完全卷积的网络
- 没有池化图层,跨距为 2 的卷积图层用于对图像进行缩减像素采样。
- 较新的架构改进了剩余跳跃连接和上采样。
- 最佳部分—在三种不同的比例下进行检测,这有助于解决检测小物体的问题。
- 与先前层连接的上采样层有助于保留有助于检测小对象的细粒度特征。
单级检测和多级检测之间的选择-
Performance on MS-COCO
- 更快的 R-CNN 速度较慢,但更准确
- 固态硬盘和 YOLO 要快得多,但没有那么准确
- 更大/更深的主干/特征提取器网络工作得更好
要进行完整的比较,请查看此— 现代卷积物体检测器的速度/精度权衡 ,Jonathan Huang 等人。艾尔。,2017 年
图象分割法
将像素分组为有意义的或感觉上相似的区域。Keymakr 等公司为视频和图像的复杂分割提供同类最佳的工具和全套服务解决方案。
Mask R-CNN, Kaming He et. al. 2017 [ICCV 2017 Best Paper Award-Marr Prize]
用于实例分割的 Mask-R-CNN
- MaskRCNN 是对更快的 R-CNN 的修改
- 它为更快的 R-CNN 网络增加了一个单独的屏蔽“头”
- 掩码“头”只是一个小的全卷积网络,它为每个区域建议输出一个 m × m 掩码。
- RoIAlign 层已被 RoI Pooling 取代。
- 可以与不同的架构,也 ResNet
- 在 Nvidia Tesla M40 GPU 上以每幅图像 195 毫秒的速度运行
- 也可以用于人体姿态估计
Mask R-CNN 不仅提供了他们的模型优于所有先前模型的证据,而且还进行了各种消融实验,以显示 RoIAlign、分段去耦和全卷积掩模头各自单独提高了准确性。检查纸张了解详情。
深度跟踪
简单地说,在视频的连续帧中定位一个对象称为跟踪。
经典的对象跟踪是通过诸如密集光流的技术实现的:这些算法有助于估计视频帧中每个像素的运动矢量。
稀疏光流:这些算法,如 KLT 特征跟踪器,跟踪图像中几个特征点的位置。
卡尔曼滤波:一种非常流行的信号处理算法,用于根据先验运动信息预测运动物体的位置。
Meanshift 和 Camshift:这些是定位密度函数最大值的算法。它们也用于跟踪。
大多数目标跟踪方法采用“在线”学习。在线方法是昂贵的,必须做出简化的假设来提高效率。由于诸如 Harris 角、HOG 或 SIFT 之类的经典图像特征在不同的自然图像属性变化中都被破坏,例如,Harris 角对于图像的尺度不是不可知的,所以这种经典方法有时会失败。
但最近,已经有作品试图探索使用深度学习功能进行跟踪的就业。
因为效率是关键,所以策略是从大量带标签的离线视频中学习。
D. Held, S. Thrun, and S. Savarese “Learning to Track at 100 FPS with Deep Regression Networks”, ECCV 2016.
它是如何工作的-
两个假设:
1。网络将前一帧与当前帧进行比较,以找到当前帧中的目标对象
。
2。这个网络就像一个本地通用的“目标探测器”,简单地
定位最近的“目标”
MOTS: Multi-Object Tracking and Segmentation — Paul Voigtlaender et. al., CVPR 2019
生成对抗网络
仅仅过了 5 年,人工智能的发展令人难以置信。特别是 2019 年出现的 GAN 架构,如 Google 的 BigGAN 和 NVIDIA 的 StyleGAN 能够生成与真实图像精确区分的图像,因此 眼见为实。
A Style-Based Generator Architecture for Generative Adversarial Networks, NVIDIA, 2019
GAN 由两个连续的网络组成
- 发电机网络
- 鉴别器网络
学习-
- 样本噪声矢量 z
- 使用 z,生成器产生样本 x
- 制作一个批次,其中一半样品是真实的,一半是生成的
- 鉴别者需要预测什么是真的,什么是假的
特别是谈到 StyleGAN,它不是专注于创建更真实的图像,而是提高了 GANs 对生成的图像进行精细控制的能力。
不在架构和损失函数上发展。取而代之的是一套技术,可以与任何 GAN 一起使用,让您可以做各种很酷的事情,如混合图像,在多个层次上改变细节,并执行更高级版本的风格转换。
它采用现有技术,如自适应实例标准化、潜在向量映射网络和恒定学习输入。
Samples for StyleGAN
如果有人说上面的图片都不是真实的,不要怀疑。这些是 StyleGAN 生产的。
关键要点
随着对该技术的进一步研究和完善,计算机视觉的未来将会看到它执行更广泛的功能。计算机视觉技术不仅更容易训练,而且能够比现在更好地识别图像。这也可以与其他技术或其他人工智能子集结合使用,以构建更有效的应用程序。例如,图像字幕应用程序可以与自然语言处理和语音识别相结合,使视觉智能具有交互性。计算机视觉还将在人工通用智能(AGI)和超级智能的发展中发挥重要作用,使它们具有与人类视觉系统一样甚至更好的处理信息的能力。
阅读我的新文章关于压缩大型深度神经网络而不损害准确性。如果你想了解更多关于计算机视觉模型的知识,请深入到 Neptune.ai 博客的主题中
使用机器学习的衰退预测
“次级贷款被遏制住了”——伯南克(2007 年 3 月)
内容
简单地
该项目提出了一种机器学习方法,用于预测美国 6 个月、12 个月和 24 个月的衰退发生率。预测模型使用了一些就业、通胀、利率和市场指标。
定义问题
简单来说:
人们可以通过在经济和市场数据中寻找线索来预测美国未来衰退的时间吗?
这个问题的几个有趣的属性包括:
- 罕见事件预测:衰退很少发生。
- 小数据集:因为我用的是经济数据(更新频率是几个月或者几个季度),所以我只会有几百个数据点可以处理。
- 不平衡类样本:虽然不平衡并没有严重到足以使这个项目成为一个异常检测练习,但是我们仍然必须认识到样本类不平衡,特别是对于误差计算。
This is the most extreme example of class imbalance in the exploratory data set
- **时间序列:**典型的涉及财务数据的项目。这影响了如何进行交叉验证(不应该进行简单的 K 重验证)。
为什么需要解决这个问题?
随着当前牛市的老去,这是一个适时的问题。带着对衰退可能性的良好感觉:
- 政策制定者可以制定对策来降低经济周期下滑的严重程度。
- 市场参与者可以通过采取防御性投资策略来省钱。
主要假设
有两个主要的理论假设在起作用:
1)美国经济衰退表现出标记/早期预警信号。
以单个经济或市场数据序列的形式存在大量衰退“信号”。虽然单独来看,这些信号具有有限的信息价值,但是当它们组合在一起时可能变得更加有用。
2)未来的衰退将与历史衰退相似。
这种假设很不可靠,但可以通过选择在经济形势不断变化的情况下仍保持重要性的功能来缓解。例如,关注制造业数据在历史上可能是相关的,但随着世界走向数字化,这种相关性可能会降低。
别人试过什么?
- 古根海姆合伙公司有两个衰退相关指标:衰退概率模型和衰退仪表板,两者都由经济和市场指标的组合驱动。他们的模型给了我在 3 个不同的时间框架内预测衰退概率的想法。
- 纽约联储预测衰退概率。其局限性在于,它仅提供 12 个月的预测,并且仅依赖于一个变量(10 年期和 3 个月期国债利率之间的利差)。
- 荷兰合作银行有一个衰退概率模型,但也是只基于 1 个变量(10 年期和 1 年期国债利率的利差),且只覆盖一个时间段(17 个月)。
- 富国银行经济学有几个衰退概率模型结合了经济和市场数据。然而,他们只将预测限制在 6 个月的范围内。
模型基准测试/比较
理想情况下,我会将我的模型性能与上面的每个备选方案进行比较。目前,我不能这样做,原因如下:
- **古根海姆模型:**模型性能数据不公开发布。
- 纽约联邦储备银行模型:经过仔细观察,他们的模型被用来回答问题“从现在起 X 个月后美国陷入衰退的概率是多少?”,而我的模型是为了回答问题“美国在未来 X 个月内陷入衰退的可能性有多大?”*。更多细节,请参见下面的如何标记类输出*部分。
- **荷兰合作银行模型:**同样的原因,我不能把我的模型性能与纽约联邦储备银行模型进行比较。此外,Rabobank 模型涵盖了 17 个月的时间段,而我的模型涵盖了 6 个月、12 个月和 24 个月的时间段。
- 富国银行经济模型:模型性能数据未公开发布。
获取数据
获取数据时,我必须考虑一些事情:
- 经济数据以不同的频率发布(每周、每月、每季度等)。).为了对数据点进行时间匹配,我满足于只使用每月采样的数据。因此,所有预测必须每月进行一次。这意味着我不得不放弃使用 GDP 等有价值的数据序列,因为它每季度发布一次。
- 即使只使用月度数据,不同的数据在一个月内也有不同的发布日期。*为了对此进行控制,所有预测都使用截至每月 7 日的最新可用数据进行。*佛瑞德 API 有一个参数可以设置这个限制。编辑(2021 年 1 月):代码现在从每个月的 8 号开始提取数据,以适应更多的时序边缘情况。
- 改变数据历史长度。一些数据是从 1900 年开始发布的,而另一些数据只追溯到几年前。这意味着我必须排除那些没有足够历史记录的潜在有用数据。
- 谈到历史,我需要足够的数据来涵盖尽可能多的衰退。最终,完整的数据集包括了自 1955 年以来的 9 次衰退。
- 经济数据经常被修正。但是弗雷德没有提供原始数字。它只提供了修正后的数据(不管这些修正是在事后进行的)。另一种选择是 ALFRED ,它显示特定“年份”日期的可用数字,但 ALFRED 的致命缺陷是它没有时间序列中每个日期的年份。通过坚持弗雷德最新修订的数据,我做出了一个隐含的假设,即修订是无偏的(即修订同样有可能推动原始数据上升或下降)。
数据源
出于实际原因,我使用了通过 FRED 和 Yahoo Finance 获得的公共领域数据。我没有使用隐藏在付费墙后面的潜在有用的数据,比如美国经济咨询局领先经济指数。
特征选择
功能选择的一些项目特定考虑因素:
- **维度的诅咒。**由于数据集如此之小(只有几百个数据点),最终模型中不能包含太多特征。否则,模型将无法推广到样本外数据。因此,必须根据每个特性提供的增值来仔细选择特性。
- **领域知识是关键。**由于基础过程是复杂的时间序列,自动特征选择方法具有过度拟合先前数据的高风险。因此,特征选择必须以对经济基本面的深刻理解为指导。
首先,先睹为快最终的功能列表。注意它有多小:
Note that only 6 features made it to the final list
我的特征选择过程的概要
- 定义执行探索性数据分析的数据集**(1955 年 8 月至 1972 年 1 月)**以确保与交叉验证期间没有交集。
- 根据经济/理论特征(领域知识),将潜在特征组织成桶。
- 仅使用探索性数据集绘制每个单独特征和每个输出类型(未来 6 个月、未来 12 个月、未来 24 个月)之间的成对相关性**(不要提前查看!).**
- 按顺序从一个要素桶移动到另一个要素桶,以便每个桶在最终数据集中至少有一个要素。对于平局决胜法,选择与已经“接受”到最终数据集中的要素相关性较低的要素。
事情是这样的:
首先,选择 1 个就业特征
- 平民失业率**——**通常情况下,直到事情开始变糟,企业才会开始裁员。因此,失业通常滞后于衰退。
- ****—这是一个更好的起点。由于对更具挑战性的经济环境的预期,企业可能会放缓招聘步伐。
**我考虑了 **3 个月的非农就业变化(%),12 个月的非农就业变化(%),以及 3 个月变化和 12 个月变化的差异。事实证明,3 个月的变化和 12 个月的变化之间的差异是探索性数据集中的最佳预测器(在 3 个候选人中),所以我选择它作为我的就业特征。
选择 1 个货币政策特征
设定联邦基金利率上限是美联储使用的主要货币工具之一。我考虑了实际联邦基金利率**,以及联邦基金利率 12 个月的变化。联邦基金利率的 12 个月变化是两个候选中最好的,所以我选择它作为我的货币政策特征。**
一些人认为,美联储可以通过设定联邦基金利率的界限来影响经济活动。
选择 1 个充气特性
通货膨胀与商业周期的关系更加复杂,因为它可能发生在快速扩张时期,也可能发生在收缩时期(滞胀)。但在通货膨胀和其他特征之间可能存在更高阶的效应,因此无论如何都值得包括在内。
消费者价格指数(CPI)是一个常用的通货膨胀指标。我考虑了 3 个月的 CPI 变动(%),12 个月的 CPI 变动(%),以及 3 个月变动和 12 个月变动的差异。所有候选人与就业特征和货币政策特征的相关性都很低,因此我选择了CPI 的 3 个月变化作为我的通胀特征,因为它与探索性数据集中的输出标签的相关性稍高。
挑选债券市场特征
我很想在这里使用某种类型的信用利差指数(投资级或高收益),但找不到数据可以追溯到 1955 年的信用利差指数。
因此,我开始关注国债利率。国债作为“无风险”资产类别,在全球资产配置框架中扮演着重要角色。国债利率的变化可能表明对经济机会和市场风险的预期发生了变化。
我不受 10 年期国债和 3 个月期国债之间利差的影响,因为收益率曲线斜率在提前预测衰退方面有着良好的历史记录。这种现象有几种理论解释。其中一个解释是,如果投资者认为“糟糕的时期”即将到来,他们就会将资金从高风险资产转移到长期美国国债,以锁定更长时间内的“无风险”回报。
**在选择 10 年期与 3 个月期国债利差作为我的第一个指标后,我考虑了 **3 个月期国债利率(12 个月的变化)、**10 年期与 3 个月期国债利差的 **12 个月的变化、**和 **10 年期国债利率(12 个月的变化)。**我拒绝了前两个候选,因为它们与货币政策特征高度相关(90%)。我决定选择 **10 年期国债利率(12 个月变化)作为我的第二个债券市场特征,因为它可以衡量长期增长预期。
选择一个股票市场特征
股票市场由未来预期的当前贴现驱动,因此被认为是领先指标。我考虑了 S & P 500 指数的 3 个月变化,S & P 500 指数的12 个月变化,以及 S & P 500 指数 3 个月变化和 12 个月变化之间的差异。后两个候选指标都与产出标签高度相关,但我选择了标准普尔 500 指数&的 12 个月变化,因为它更容易解释。
设计测试流程
在设计测试时,我必须考虑一些事情:
时间序列?那么没有 K 倍交叉验证
由于潜在的预测是一个时间序列,因此必须实时进行模型交叉验证和预测(即,仅使用每个时间点的可用数据!).k 倍交叉验证会违反这个原则。
衰退是如何定义的?
美国国家经济研究局(NBER) 商业周期测定委员会命名商业周期的“高峰”和“低谷”日期。我把 NBER 定义的波峰和波谷之间的几个月视为美国的衰退期。但是这里有一个巨大的问题:
NBER 宣称“高峰”和“低谷”的日期是在事实发生几个月后(有时是几年后)!
这意味着不能一次标记一个周期的输出!因此,要部署任何类型的衰退预测器,人们必须在每次正式的 NBER“低谷”公告时(每次衰退结束后的)重新训练模型。因此,在回溯测试中也必须采用同样的方法!**
如果按照这种方法,有 5 个可能的测试运行(峰谷对),每个测试都有 NBER 公告日期:
Link: https://www.nber.org/cycles.html
对于每个测试,训练集从 1955 年 8 月开始**,并且随着每个后续测试变得更长。类似地,每个交叉验证集从 1972 年 1 月开始,并且随着每个后续测试变得更长。**
我如何标记类输出?
乍一看,这似乎很容易:衰退= 1,不衰退= 0。这是真的,但是还不够,因为它属于期望的模型范围。为了确定贴标签的过程,人们必须弄清楚要回答的问题。
难道是:
从现在起 X 个月后,美国陷入衰退的概率有多大?
如果想回答这个问题,就必须预测衰退的开始和结束。在衰退真正结束之前,模型预测的概率应该开始下降。不用说,这是一个非常英勇的任务。
另一个问题是:
美国在未来 X 个月内陷入衰退的可能性有多大?
这个问题预测了衰退的开始,但只是“预测”了衰退的结束。只有在衰退结束后,模型预测的概率才会开始下降。这个任务不太理想,但它仍然允许市场参与者为市场顶部做准备。
因此,所有处于衰退期的月份都将被标记为“1”。此外,X 个月(其中 X = 6 表示 6 个月前的预测值,X = 12 表示 12 个月前的预测值,等等。)也将获得“1”标签。所有其他月份将获得“0”的标签。
试验结果
我考虑了几个模型,并在每个模型上运行了前面提到的 5 个测试。如前所述,所有的交叉验证和预测都是实时进行的(没有作弊!),仅使用在每个历史时间点可用的数据。
考虑的模型
我考虑了以下 6 个单独的模型:K 近邻、正则化线性回归(弹性网)、朴素贝叶斯、支持向量机、高斯过程和 XGBoost。我通过交叉验证错误的网格搜索来调整超参数。如前所述:
对于每次测试,训练集从 1955 年 8 月日开始,并随着每次后续测试而变长。类似地,每个交叉验证集从 1972 年 1 月开始**,并且随着每个后续测试而变长。**
此外,我测试了上述 6 个独立模型中的 2 个整体模型:
- 一个大平均模型,对每个模型的预测进行同等加权
- 一个加权平均模型,根据每个模型的交叉验证误差对每个模型的预测进行加权
**我还通过在每个模型的交叉验证预测上训练线性回归模型来测试堆叠集合。**这种方法产生了恶劣的结果。我直观的解释是,数据集太小,无法训练出强大的堆叠系综。根本没有足够的交叉验证预测可用!
选择误差度量
我应该使用哪种误差度量来量化预测误差?因为这是一个分类问题,所以我想到了准确性、预测/召回率和 F1 分数等指标。然而,这些指标都不太适合这个特定的问题,因为预测的输出类别(“0”或“1”)不像预测的** 出现在每个类别中的概率那样相关!**
**相反,我使用加权的 对数损失 **作为我的误差度量。它考虑了 class =“1”的预测概率与实际类值(“1”或“0”)之间的距离。Log-loss 为预测概率和实际类输出之间的较大差异分配了指数级更重的惩罚。
针对阶层失衡进行调整
****模型训练时:对于部分模型(弹性网、支持向量机、XGBoost),有内置参数设置类权重。我设置这些参数,使得两个类对模型训练的损失函数具有相同的影响。
****在模型交叉验证期间:使用 scikit-learn 的对数损失实现,我可以调整样本类的不平衡(使用“sample_weight”参数),这样两个类对模型交叉验证的总体对数损失值具有相同的影响。
预测平滑
原始概率预测往往不稳定,就像这样:
Predictions before smoothing
因此,我对原始概率预测应用了指数平滑法。我选择了加权因子(用于指数平滑器),使得每个预测的半衰期为 3 个周期:
Predictions after exponential smoothing
最终模型
我最终选择了支持向量机作为最终部署模型。8 个模型(6 个独立模型和 2 个整体)在 3 个时间范围内的对数损失如下:
Remember: the smaller the log-loss, the better
敏锐的读者可能会注意到,支持向量机 (SVM)并没有在所有 3 个时间框架内取得最好的成绩。
为什么我没有选择“表现最佳”的模式?
一个字:讲故事。
具体来说,观察 6 个月时间框架内弹性网、加权平均和支持向量机预测的并排比较:
****弹性净值和加权平均模型比 SVM 得分更高(基于加权对数损失),因为它们通常预测更高的衰退概率!本质上,它们的“假阳性”倾向高于 SVM,而“假阴性”倾向略低于 SVM。
****这种不对称是不选择“最佳表现”模式的关键。即使在长期经济增长期间,表明近期衰退概率较高的模型(弹性网、加权平均)也更容易被怀疑为“危言耸听”,并且更难销售。另一方面,一个模型(SVM)表明,在繁荣时期衰退几率接近 0%,但在衰退时期也会飙升至高水平(尽管没有“危言耸听”的模型那么高),这将更难让人怀疑。
所以我选择了 SVM 模型,不是因为从统计学的角度来看它是“表现最好的”模型,而是因为它讲述了一个更符合人类对经济状况认知的故事!
图表显示了 SVM 模型的预测,每月更新一次。
要通过电子邮件接收模型预测的定期更新,请点击此处。
特别感谢 Jason Brownlee 关于应用机器学习过程的 文章 。
数据分布可视化的方法
可视化
直方图、KDE 图、箱形图和小提琴图等
Photo by Toa Heftiba on Unsplash
作为一名初露头角的数据科学家,我意识到,在项目启动期间,编写第一段代码总是为了了解数据集中一个或几个变量的分布。可视化变量的分布对于立即掌握有价值的参数非常重要,如频率、峰值、偏斜度、中心、模态以及变量和异常值在数据范围内的表现。
带着分享知识的兴奋,我写了这篇关于单变量(单变量)分布的总结解释的博文,分享我从几篇文章和文档中得出的推论。我将提供绘制分布函数的步骤,而不深入理论,并保持我的帖子简单。
我将首先解释使用 Matplotlib 和 Seaborn 库用 Python 可视化数据分布的函数。可视化背后的代码可以在这个笔记本中找到。
为了便于说明,我使用了 Gapminder 寿命预期数据,清理后的版本可以在这个 GitHub 库中找到。
数据集显示了 142 个国家在 1952 年至 2007 年间的出生时预期寿命、人口和人均 GDP。我将绘制出生时的预期寿命,使用:
- 柱状图
- 核密度估计和分布图
- 箱形图
- 博兴图
- 小提琴情节
1)直方图
直方图是显示数据分布的最简单方式。下面是制作直方图的方法:
- 创建桶(箱)通过将数据区域划分成相等的大小,数据中子集的数量就是箱的数量。
- 记录落入每个箱中的数据点的计数。
- 在 x 轴上并排想象每个桶。
- 计数值将显示在 y 轴上,显示每个箱子中有多少物品。
你有了一个全新的直方图!
这是最简单、最直观的方法。然而,一个缺点是决定必要的箱的数量。
在这个图中,我确定了 25 个 bin,这在使用 Matplotlib hist 函数中的bins
参数后似乎是最佳的。
# set the histogram
plt.hist(df.life_expectancy,
range=(df.life_expectancy.min(),
df.life_expectancy.max()+1),
bins=25,
alpha=0.5)
# set title and labels
plt.xlabel(“Life Expectancy”)
plt.ylabel(“Count”)
plt.title(“Histogram of Life Expectancy between 1952 and 2007 in the World”)
plt.show()
Histogram with 25 bins
不同数量的容器会显著改变数据分布的外观。这是同样的数据分布,有 5 个箱,看起来像一个完全不同的数据集,对吗?
Histogram with 5 bins
如果您不想被箱数确定所困扰,那么让我们跳到核密度估计函数和分布图。
2)核密度估计和分布图
核密度估计 (KDE)图通过平滑直方图将您从决定面元大小的麻烦中解救出来。遵循以下逻辑创建 KDE 图:
- 围绕每个数据点绘制一条高斯(正态)曲线。
- 将曲线相加,在每个点创建一个密度。
- 归一化最终曲线,使其下方的面积等于 1,从而得到概率密度函数。以下是这 3 个步骤的直观示例:
Image Source: Histograms and Kernel Density Estimations
您可能认为密度图上的 y 轴只是不同类别之间的相对比较值。
幸运的是,您不必记住并手动应用所有这些步骤。Seaborn 的 KDE 绘图函数为您完成所有这些步骤,只需将您的数据框或 Numpy 数组的列传递给它即可!
# set KDE plot, title and labels
ax = sns.kdeplot(df.life_expectancy, shade=True, color=”b”)
plt.title(“KDE Plot of Life Expectancy between 1952 and 2007 in the World”)
plt.ylabel(“Density”)
如果你想结合直方图和 KDE 图,Seaborn 有另一个很酷的方法在一个图形中显示直方图和 KDE 图:分布图,它绘制 KDE 图,通过改变函数中的hist
参数可以灵活地打开和关闭直方图。
# set distribution plot, title and labels
ax = sns.distplot(df.life_expectancy, hist=True, color=”b”)
plt.title(“Distribution Plot of Life Expectancy between 1952 and 2007 in the World”)
plt.ylabel(“Density”)
Distribution plot with histogram and Kernel Density Estimation function
KDE 图也能够显示不同类别之间的分布:
# create list of continents
continents = df[‘continent’].value_counts().index.tolist() # set kde plot for each continent
for c in continents:
subset = df[df[‘continent’] == c]
sns.kdeplot(subset[“life_expectancy”], label=c, linewidth=2) # set title, x and y labels
plt.title(“KDE Plot of Life Expectancy Among Continents Between 1952 and 2007”)
plt.ylabel(“Density”)
plt.xlabel(“Life Expectancy”)
尽管与直方图相比,KDE 图或分布图需要更多的计算和数学,但通过观察连续的线,更容易理解分布的形态、对称性、偏斜度和中心。一个缺点可能是,缺少关于汇总统计的信息。
如果您希望直观地提供分布的汇总统计数据,那么让我们转到箱线图。
3)箱线图
箱线图显示了包含五个数字的汇总统计数据的数据分布(最小值、第一个四分位数 Q1、第二个四分位数中值、第三个四分位数 Q3、最大值)。下面是绘制它们的步骤:
- 对数据进行排序,以确定最小值、四分位数(第一、第二和第三)和最大值。
- 在第一个四分位数和第三个四分位数之间画一个方框,然后在对应于中间值的方框中画一条垂直线。
- 在盒子外面画一条水平线,把盒子一分为二,把最小值和最大值放在边上。这些线条将成为你的胡须。
- 胡须的末端等于数据的最小值和最大值,如果你看到任何数据,放在一边的小菱形被解释为“异常值”。
手动创建方框图的步骤很简单,但我更喜欢从 Seaborn 方框图功能中获得一些支持。
# set the box plot and title
sns.boxplot(x=”life_expectancy”, data=df, palette=”Set3") plt.title(“Boxplot of Life Expectancy between 1952 and 2007 in the World”)
有几种不同的方法来计算胡须的长度,Seaborn box plot 函数默认从第一个和第三个四分位数延伸 1.5 倍的四分位数间距 (IQR)来确定胡须。因此,任何大于 Q3+(1.5IQR)或小于 Q1-(1.5IQR)的数据点都将被视为异常值。您可以通过调整whis
参数来改变胡须的计算。
像 KDE 图一样,箱线图也适合可视化类别间的分布:
# set the box plot with the ordered continents and title sns.boxplot(x=”continent”, y=”life_expectancy”, data=df,
palette=”Set3",
order=[“Africa”, “Asia”, “Americas”, “Europe”,
“Oceania”])
plt.title(“Boxplot of Life Expectancy Among Continents Between 1952 and 2007”)
盒状图提供了统计数据的故事,一半的数据在那里,通过观察盒状和须状提供了整个范围的数据。另一方面,你不知道盒子外面的数据的故事。这就是为什么一些科学家发表了一篇关于 boxen 图的论文,被称为扩展盒图。
4)博兴图
Boxen 图,或字母值图或扩展盒图,可能是数据分布可视化中最少使用的方法,但它们传达了大型数据集的更多信息。
要创建一个博森情节,我们先来了解一下什么是字母值汇总。字母值汇总是关于连续确定一个排序数据的中间值。
首先,确定所有数据的中间值,并创建两个切片。然后,确定这两个切片的中值,并在达到停止标准或不再有数据需要分离时重复这个过程。
确定的第一个中间值是中值。在第二次迭代中确定的中间值称为四分之一,在第三次迭代中确定的中间值称为八分之一。
现在让我们画一个方框图,并在方框图之外可视化字母值摘要,而不是胡须。换句话说,绘制一个具有对应于切片中间值(八分之一、十六分之一等等)的延长盒边的盒图…)
# set boxen plot and title
sns.boxenplot(x=”life_expectancy”, data=df,palette=”Set3") plt.title(“Boxenplot of Life Expectancy Among Continents Between 1952 and 2007”)
它们在讲述不同类别的数据故事方面也很有效:
# set boxen plot with ordered continents and title sns.boxenplot(x=”continent”, y=”life_expectancy”, data=df,
palette=”Set3",
order=[“Africa”, “Asia”, “Americas”, “Europe”,
“Oceania”])
plt.title(“Boxenplot of Life Expectancy Among Continents Between 1952 and 2007”)
Boxen 图的出现是为了更有效地可视化较大的数据集,它显示了数据在主框之外的分布情况,并更加强调异常值,因为异常值和 IQR 之外的数据在较大的数据集中更为重要。
有两个视角提供了关于数据分布的线索,数据分布的形状和汇总统计。要同时从两个角度解释一个分布,我们先来学煮一些小提琴的剧情。
5)小提琴情节
小提琴情节是盒子情节和 KDE 情节的完美结合。他们提供的汇总统计数据内部是箱形图,分布形状的侧面是 KDE 图。
这是我最喜欢的图,因为数据表达了所有的细节。你还记得我们之前绘制的预期寿命分布图和汇总统计数据吗?Seaborn violin 的剧情功能现在将为我们融合它。
瞧啊!
# set violin plot and title
sns.violinplot(x=”life_expectancy”, data=df, palette=”Set3") plt.title(“Violinplot of Life Expectancy between 1952 and 2007 in the World”)
你可以通过观察边上的分布来观察 70 左右的数据峰值,通过注意里面细长的方框来观察 50 到 70 之间聚集的一半数据点。
这些漂亮的小提琴可以用来可视化分类数据,如果您愿意,可以通过更改inner
参数用点、虚线或线条表示汇总统计数据。
Violin plots with inner set to quartile, point and stick respectively
好处是显而易见的:可视化的形状分布和汇总统计同时进行!
**小提琴剧情加分:**通过设置scale
参数进行计数,还可以显示你在每个类别中有多少数据点,从而强调每个类别的重要性。当我改变scale
的时候,非洲和亚洲扩张了,大洋洲收缩了,结论是大洋洲的数据点较少,而非洲和亚洲的数据点较多。
# set the violin plot with different scale, inner parameter and title
sns.violinplot(x=”continent”, y=”life_expectancy”, data=df,
palette=”Set3",
order=[“Africa”, “Asia”, “Americas”, “Europe”,
“Oceania”],
inner=None, scale=”count”)
plt.title(“Violinplot of Life Expectancy Among Continents Between 1952 and 2007”)
结论
所以,这些关于可视化分布的方法解释了每个图背后的核心思想。有很多选项可以显示单变量或单变量分布。
直方图、KDE 图和分布图很好地解释了数据形态。此外,分布图可以结合直方图和 KDE 图。
箱线图和 boxen 图最适合交流汇总统计数据,boxen 图更适合处理大型数据集,而 violin 图则完全胜任。
他们都是有效的沟通者,并且每个都可以用 Python 中的 Seaborn 库快速构建。您的可视化选择取决于您的项目(数据集)和您想要传递给观众的信息。如果你对这篇文章感到兴奋并想了解更多,你可以查看一下 Seaborn 和 Matplotlib 文档。
最后但同样重要的是,这是我对数据科学的第一篇贡献,我希望你喜欢阅读!我感谢您的建设性反馈,并希望在回复中或在 Twitter 上听到您对这篇博文的看法。
推荐系统第 1 部分——使用协同过滤和混合协同——在 Instacart 数据集上使用 LightFM 库的零售内容
介绍
Recommender systems shown in Amazon
声明:我在正文和代码中交替提到了项目和产品。他们俩是一样的。
当你打开亚马逊等一些在线市场时,你会发现一些推荐,如经常一起购买,买了这个的客户也买了这个,类似的商品,等等。你会在网站上更容易找到你想要的东西。目前,推荐系统广泛用于在线市场,一些零售商正在使用这项技术来改善用户体验、用户保留率和转化率。
在本教程中,我将向您展示如何使用 Instacart 数据集创建一个模拟真实业务问题的产品推荐,适用于“交互”数据丰富的热启动问题。数据集可以在 Kaggle 上找到。我们还希望提供纯协作过滤方法与混合协作-基于内容的方法之间的比较,以解决我们的热启动问题。
在讨论细节之前,我们需要使用 pip 安装 LightFM 库
pip install lightfm
安装完成后,您可以导入所有必要的东西,包括交叉验证术语和指标
importing libraries including standard pandas, numpy, and the lightfm’s model and cross-validation stacks
如何为 LightFM 库准备数据
在使用 LightFM 库时,我们需要一个稀疏矩阵,称为用户-项目交互矩阵。对于混合协作内容推荐的情况,我们还可以考虑项目-特征矩阵:
- 用户-物品互动矩阵定义了用户(客户)与物品(产品)之间的互动,这可以显示为客户投票的电影评级。然而,在零售案例中,我们无法从历史数据中获得明确的评级。在这种情况下,我隐含地将**“购买数量”作为评级考虑在内。如果顾客 A 购买了产品 B 10 次,那么我们可以说顾客 A 给产品 B 的评分是 10。您还可以考虑二进制评分,其中 1 表示客户 A 购买过产品 b,0 表示从未购买过产品 b。用户-项目交互矩阵表示协同过滤对模型**的贡献。
- 物品-特征交互矩阵定义物品的特征。项目到功能可以表示为产品到它的元数据,例如产品的类别、子类别,甚至任何信息。使用 Instacart 的数据集,我会使用“过道”和“部门”作为产品的特征。如果产品 A 位于通道 B,那么我们可以说通道 B 中产品 A 的矩阵元素为 1,否则为 0。这个矩阵可以向模型添加基于内容的贡献。
User-item interaction matrix. User Id represents the customers and product rated represents how many times a specific user id bought the products. The matrix is sparse.
item-feature matrix. Item id represents the products and features refer to the metadata embedded to an item such as category, sub-category, and so on.
使用 Instacart 零售数据集构建矩阵
我们将从 Instacart 市场购物篮分析 Kaggle 竞争(https://www . ka ggle . com/c/insta cart-Market-Basket-Analysis/data)中创建两个矩阵,并形成适用于 LightFM 库的数据集。在此之前,我们需要从 Kaggle 下载所需的数据集,并为我们的推荐系统读取必要的数据集
数据集的显示如下所示:
datasets preview
我们还需要删除aisles
和departments
中带有aisle == missing
或aisle == other
和department == missing
或department == other
的行:
- 构造一个用户-项目交互 矩阵。我们需要考虑到,LightFM 库只能读取一个稀疏的 coo 矩阵,可以使用
scipy.sparse
中的coo_matrix
来构造,其中我们需要将item_id
转换成integer index
。因此,我构建了用户-项目交互矩阵,将user_id
转换为表示矩阵的行的索引**,将转换为列的索引。另外,不要忘记为 user_id 到 index、index 到 user_id、item_id 到 index 和 index 到 item_id 创建字典映射。** - 构建一个项目-特征矩阵。用户-项目交互矩阵也是同样的情况,通过将项目/产品和功能映射到索引中,我们可以尝试将项目/产品 和功能交互转换成稀疏矩阵。
下面显示了矩阵生成器和一些用于索引等的辅助函数
将所有users
、items
和features
分配到列表中
显示在users
、items
和features
列表的下方
displaying users, items (products), and features (departments and aisles)
LightFM 库不能读取未索引的对象,因此我们需要为users
、items
和features
创建映射到它们相应的索引中。
在生成交互矩阵之前,我将 t rain、test 和 product_features 数据准备成它们相应的名称
Showing the table of users with their corresponding purchased products/items. I also regard count as the ratings of the products/items or features
将每个表转换成交互矩阵
导致
Sparse matrices representing interactions of users to products/items and products to features. The non-zero elements consist of product count as the number of products a user has bought
模型选择和交叉验证
在这个问题中,我将通过测量测试数据集的 AUC(范围从 0 到 1)来尝试使用 LightFM 库进行交叉验证。我使用了“WARP”损失函数,它通常在 LightFM 库中提供最佳性能选项。通过使用 Instacart 数据集,我将prior
数据集作为training dataset
,将train
数据集作为testing dataset.
,通过拟合training dataset
并在test dataset
上测试,我们可以尝试评估测试数据集的 AUC 分数。
下面我们尝试使用 LightFM 库对纯协同过滤方法进行交叉验证
上面的输出是
time taken = 118.23 seconds
time taken = 1088.21 seconds
average AUC without adding item-feature interaction = 0.95
从上面的结果中,我们知道,使用我的 8 GB RAM 笔记本电脑,培训大约需要 1 分钟,验证需要 10 分钟。翘曲损失功能可以很慢,但性能非常好。AUC = 0.95 很神奇的告诉我们,Instacart 数据集是一个热启动问题,交易数据丰富。
混合协作——基于内容的,通过添加产品/项目和功能交互,代码如下
上面的输出是
time taken = 154.22 seconds
time taken = 1709.78 seconds
average AUC with adding item-feature interaction = 0.80
从混合情况下记录的 AUC 来看,AUC 比纯协作情况下的 AUC 差。这是一个具有丰富交易数据的热启动问题,纯协作过滤将提供更好的推荐。
请求产品/项目推荐
我们需要通过下面的函数将训练和测试数据集合并成一个
并创建用户到产品的交互矩阵
导致
回来了
time taken = 68.50 seconds
并且询问推荐的类对象由下式给出
使用最终模型调用建议
为用户 2 和用户 10 打印了一些建议
User 2
Known positives:
Organic Turkey Burgers
Wild Albacore Tuna No Salt Added
Cherry Pomegranate Greek Yogurt
Recommended:
Organic Garlic
Organic Baby Spinach
Organic Hass AvocadoUser 10
Known positives:
Cantaloupe
Parsley, Italian (Flat), New England Grown
Seedless Red Grapes
Recommended:
Organic Baby Spinach
Organic Strawberries
Bag of Organic Bananas
结论
LightFM library 可以为交易数据提供混合协作和基于内容的推荐系统。然而,对于热启动问题,纯协同过滤提供了更好的性能。
Github 上完整的 Jupyter 笔记本
文献学
[1] LightFM 文档—https://lyst.github.io/lightfm/docs/home.html
[2] Instacart Kaggle 比赛—【https://www.kaggle.com/c/instacart-market-basket-analysis
[2]推荐系统—学习数据科学的 Python # 3【https://www.youtube.com/watch?v=9gBC9R-msAk
推荐系统系列第 1 部分:构建推荐系统的执行指南
RecSys 系列
学术界和工业界的推荐系统
更新: 本文是我探索学术界和工业界推荐系统系列文章的一部分。查看完整系列: 第一部分 , 第二部分 , 第三部分 , 第四部分 , 第五部分 和
简介
推荐系统的建立是为了预测用户可能喜欢什么,尤其是当有很多选择的时候。他们可以明确地向用户提供这些推荐(例如,亚马逊或网飞,经典的例子),或者他们可能在幕后工作,选择哪些内容浮出水面,而不给用户选择的机会。
不管是哪种方式,“为什么”都很清楚:它们对某些类型的企业至关重要,因为它们可以让用户接触到他们原本可能不会发现的内容,或者让用户保持更长时间的参与。虽然构建一个简单的推荐系统可能非常简单,但真正的挑战是实际构建一个有效的系统,并且企业可以从其输出中看到真正的提升和价值。
可以使用各种技术来构建推荐系统,从简单的(例如,仅基于来自同一用户的其他评级项目)到极其复杂的。复杂的推荐系统利用各种不同的数据源(一个挑战是使用非结构化数据,特别是图像作为输入)和机器学习(包括深度学习)技术。因此,它们非常适合人工智能领域,尤其是无监督学习;随着用户继续消费内容和提供更多数据,这些系统可以被构建来提供越来越好的推荐。
在这篇文章和接下来的文章中,我将介绍推荐系统的创建和训练,因为我目前正在做这个主题的硕士论文。第 1 部分提供了推荐系统的高层次概述,它们是如何构建的,以及它们如何用于改善跨行业的业务。
推荐系统的 2 种类型
有两种主要类型的推荐系统,每种都有不同的子类型。根据目标、受众、平台和您的建议,这些不同的方法可以单独使用,但通常情况下,最好的结果是将它们结合使用:
1 —协同过滤
它主要基于其他人(而不仅仅是被推荐的用户)的输入或动作来做出推荐。
这种类型的推荐系统的变体包括:
- **通过用户相似性:**这种策略包括通过比较用户的活动来创建用户组,并提供在该组其他成员中受欢迎的推荐。在拥有强大而多样的受众的网站上,为信息匮乏的用户快速提供推荐是很有用的。
- **通过关联:**这个是上面提到的一个的特定类型,也称为“看了 X 也看了 y 的用户”,实现这种类型的推荐系统就是查看购买序列或购买组,并显示类似的内容。这种策略对于捕捉与自然补充内容相关的推荐以及在用户生活中的某个时刻是有用的。
2 —基于内容的
基于内容的系统根据用户的购买或消费历史提出建议,通常用户采取的行动(输入)越多,系统就越准确。
更具体类型的基于内容的推荐系统包括:
- **按内容相似度:**作为最基本的基于内容的推荐系统,这种策略包括根据元数据推荐相近的内容。这种方法对于包含大量丰富元数据的目录以及与目录中的产品数量相比流量较低的目录很有意义。
- **通过潜在因素建模:**比内容相似性方法更进一步,这种策略的关键是通过假设以前的选择是某些品味或爱好的指示来推断个人的内在兴趣。以前的策略基于显式的、手动填充的目录元数据,而这种策略依赖于发现隐含的关系。这是通过使用用户的较大交互(例如,观看的电影、购买的物品等)的历史来完成的。)来学习这些口味。
- **通过主题建模:**这是潜在因素建模策略的一种变体,通过分析非结构化文本来检测感兴趣的特定主题,而不是考虑用户的更大动作,来推断用户的兴趣。这对于具有丰富但非结构化的文本信息的用例(比如新闻文章)来说尤其有趣。
- **通过流行内容推广:**这包括根据产品的内在特性突出产品推荐,这些特性可能会引起广泛受众的兴趣:价格、功能、流行度等。该策略还可以考虑内容的新鲜度或年龄,从而能够使用最流行的内容进行推荐。这通常用于新内容占大多数的情况。
建立推荐系统的 6 个步骤
如果您遵循从原始数据到预测的基本步骤,构建一个成功且健壮的推荐系统会相对简单。也就是说,当涉及到推荐系统时,需要考虑一些经常被忽视的细节,为了最有效的过程和最佳的预测,这些细节是值得介绍(或重申)的。
本节将介绍在构建推荐系统的背景下完成数据项目的六个基本步骤。
1 —了解业务
建立推荐系统的第一步是定义项目的目标和参数,这非常简单和关键,但经常被忽视。这肯定会涉及数据团队和业务团队(可能是产品经理、运营团队,甚至是合作伙伴或广告团队,取决于您的产品)之间的讨论和输入。
为了更深入地了解业务需求并在这些团队之间展开讨论,以下是一些需要考虑的特定主题:
- 项目的最终目标是什么?建立推荐系统的目的是直接增加销售额/实现更高的平均购物篮大小/减少浏览时间并使购买更快发生/减少未消费内容的长尾/提高用户参与产品的时间吗?
- *推荐信真的有必要吗?*这可能是一个显而易见的问题,但由于它们的构建和维护成本高昂,因此值得一问。企业是否可以通过静态内容集(如员工/编辑选择或最受欢迎的内容)来推动发现,从而实现其最终目标?
- *什么时候会出现推荐?*如果推荐在多个地方都有意义(例如,在第一次访问应用程序或网站时,以及在购买或消费内容后,在主屏幕上),是否会在两个地方使用相同的系统,或者每个地方的参数和需求不同?
- *有哪些数据可以作为推荐的依据?*在推荐时,登录用户(在这种情况下可能有更多可用数据)与匿名用户(这可能会使构建推荐系统变得复杂)的比例大约是多少?
- *是否有必须首先进行的产品变更?*如果团队希望使用更强大的数据来构建推荐系统,是否必须首先进行产品更改,以便更早地识别用户(例如,邀请他们更快地登录),如果是,从业务角度来看,这些更改是否合理?
- *是否应该对所有内容或产品一视同仁?*也就是说,除了有机推荐之外,业务团队是否希望(或必须)推广特定的产品或内容?
- *如何细分口味相近的用户?*换句话说,如果采用基于用户相似性的模型,你将如何决定什么使用户相似?
2 —获取数据
最好的推荐系统使用万亿字节的数据。所以当涉及到为你的推荐系统收集数据时,一般来说,越多越好。如果当你试图为用户做推荐时,用户是未知的,这可能会很困难,例如,他们没有登录,或者更具挑战性的是,他们是全新的。如果你的业务中大多数用户都是未知的,你可能需要依赖外部数据源或与偏好没有明确联系的一般数据,如人口统计、浏览历史等。
当谈到用户偏好时,有两种反馈:显式和隐式。
- 明确的用户反馈是任何需要用户努力的事情,比如留下一个评论/评级或者发起一个投诉或者产品退货(通常来自客户关系管理、CRM、数据)。
- 相比之下,隐式用户反馈是可以收集的关于用户偏好的信息,而无需他们实际指定那些偏好。例如,过去的购买历史、查看某些优惠、产品或内容所花费的时间、来自社交网络的数据等。
好的推荐系统通常采用这些反馈类型的组合,因为它们各有优缺点。
- 显式反馈可以非常清楚:用户已经如实陈述了他们的偏好、喜欢或不喜欢。但出于同样的原因,它天生就有偏见;用户不知道自己不知道什么(换句话说,他可能喜欢某样东西,但从未尝试过,因此不会将其列为偏好,也不会正常地与该类型的项目或内容进行交互)。
- 相比之下,隐式反馈则相反——它可以揭示用户没有——或者不会——在个人资料中承认的偏好(或者他们的个人资料信息可能已经过时)。另一方面,隐性反馈可能更难理解;仅仅因为一个用户在一个给定的项目上花了时间并不意味着他(她)们喜欢它,所以最好依靠隐含信号的组合来确定偏好。
3 —探索、清理和扩充数据
尤其是在为推荐系统探索和清理数据时,要考虑的一件事是改变用户的口味。根据你的推荐,旧的评论,行动等。,可能不是最相关的推荐依据。考虑只查看更有可能代表用户当前口味的特征,并删除可能不再相关的旧数据,或者添加权重因子,以给予最近的动作比旧动作更大的重要性。
推荐系统的数据集很难处理,因为它们通常是高维的,但同时,许多特征没有任何值也很常见,这使得聚类和离群点检测很困难。
4 —预测排名
考虑到前面步骤中所做的工作,您可能已经构建了一个推荐系统,只需按用户对这些分数进行排名,您就可以推荐产品了。这种策略没有使用机器学习或预测元素,但这完全没问题。对于某些用例,这已经足够了。
但是,如果您确实想构建更复杂的东西,在用户使用推荐的内容之后,有许多子任务可以完成,这些内容可以用来进一步完善系统。有几种方法可以利用混合方法来尝试最高质量的推荐:
- 并排展示来自不同类型系统的建议。
- 并行维护多个算法,其中哪个算法优于另一个算法的决定本身受制于机器学习(例如,多臂 bandit)。
- 使用纯机器学习方法来组合多个推荐系统(逻辑回归或其他加权回归方法)。一个具体的例子是使用不同技术的两个(或更多)推荐的加权平均值。
也有可能不同的模型在产品或网站的不同部分会工作得更好。例如,用户尚未采取行动的主页与用户已经以某种方式点击或消费内容之后的主页。
5 —可视化数据
在推荐系统的环境中,可视化有两个主要目的:
- 当仍处于探索阶段时,可视化可以帮助揭示关于数据集的事情,或者给出关于模型性能的反馈,否则很难看到。
- 将推荐系统放置到位后,可视化可以帮助向业务或产品团队传达有用的信息(例如,哪些内容做得很好但没有被发现,用户口味、内容或通常一起消费的产品之间的相似性等)。)以便他们可以根据这些信息做出更改或决策。
可视化这种类型的数据的主要问题是存在的数据量,这使得很难以有意义的方式消除干扰。但同样,良好的可视化将有助于从大量数据中理解意义,否则很难从中获得有意义的见解。
6 —迭代和部署模型
在开发环境或沙盒中工作的推荐系统没有任何好处。这一切都是为了将系统投入生产,这样您就可以开始看到对您在开始时制定的业务目标的影响。
此外,请记住,你拥有的用于推荐系统的数据越多,它就会变得越好。因此,对于这种类型的数据项目来说,评估性能并继续进行微调是至关重要的,比如添加新的数据源,看看它们是否有积极的影响。
事实上,通过定期监控其性能来确保您的推荐系统能够适应和发展是该过程中最重要的部分之一——一个不能随着时间的推移根据品味或新数据进行适当调整的推荐系统可能不会帮助您最终实现您最初的项目目标,即使该系统最初表现良好。建立一个反馈回路来了解用户是否关心推荐将会很有帮助,并为以后的改进和决策提供一个很好的衡量标准。
如果推荐是你业务的核心,那么不断尝试新事物和发展你创建的初始模型将是一项持续的任务;推荐系统不是你可以创建并抛弃的东西。
挑战
创建一个推荐系统是很重要的,这个系统会随着你拥有的数据量而扩展。如果它是为有限的数据集构建的,并且该数据集不断增长,计算成本将呈指数级增长,系统将无法处理如此大量的数据。为了避免以后不得不重新构建您的推荐系统,您必须从一开始就确保它是为扩展预期的数据量而构建的。
也有可能在花费时间、精力和资源建立推荐系统之后(甚至在拥有足够的数据和良好的初步结果之后),推荐系统只给出非常明显的推荐。避免这个陷阱的关键实际上可以追溯到七个步骤中的第一步:了解业务需求。如果没有足够的内容长尾或者不需要这个系统,也许你需要重新考虑是否需要首先建立一个推荐系统。
最后,人们的口味不会随着时间的推移而一成不变,如果一个推荐系统没有考虑这一事实,它可能永远不会像它应该的那样准确。同样,建立一个不会随着时间的推移而变得更好的推荐系统也存在风险。随着用户不断消费内容,更多的数据可用,你的推荐系统应该更多地了解用户,适应他们的口味。一个不够灵活的推荐系统很快就会过时,达不到它的目的。
未来工作
基本的推荐系统已经存在了一段时间,尽管它们继续变得更加复杂,并被零售和内容巨头完善。但是接下来呢?如果企业希望开发一个真正前沿的系统,他们应该考虑的最新趋势和发展是什么?
环境感知推荐系统代表了一个新兴的实验和研究领域,旨在根据用户在特定时刻的环境提供更加精确的内容。例如,用户是在家还是在路上?使用更大还是更小的屏幕?现在是早上还是晚上?给定关于特定用户的可用数据,上下文感知系统可能能够提供用户在那些场景中更可能采纳的建议。
深度学习已经被世界上一些最大、最强大的推荐系统所使用(比如 YouTube 和 Spotify)。但是,随着数据量继续飙升,越来越多的企业发现自己面对庞大的内容语料库,难以扩展,深度学习将成为事实上的方法,不仅适用于推荐系统,也适用于所有学习问题。
解决冷启动问题也是前沿研究人员开始关注的事情,以便可以对数据很少的项目提出建议。这是一个非常重要的领域,对于有大量内容周转的企业来说,这是一个非常重要的研究领域,这样他们就可以成功地推出销售良好的商品(甚至在他们知道该商品的表现之前)。
结论
推荐系统是向用户展示他们可能没有发现的内容的有效方式,这反过来可以推进更大的商业目标,如增加销售、广告收入或用户参与。但是推荐系统的成功有几个关键点。也就是说,推荐系统首先应该是必要的。
构建一个复杂的系统需要有经验的员工和持续的维护,而一个简单的解决方案就可以了,这是对数据团队资源的浪费,这些资源可以用在其他地方以产生更大的影响。挑战在于建立一个实际上会产生商业影响的系统;建立系统本身不应该是最终目标。
推荐系统也应该是敏捷的。也就是说,适应性强,能够像用户一样进化。将推荐系统投入生产并不是这个过程的最后一步;相反,这是一个持续的演变,看看什么有效,什么无效,思考可能有助于做出更好建议的额外数据源,等等。
现在继续上 推荐系统系列第二部 !
如果你想关注我在推荐系统、深度学习和数据科学新闻方面的工作,你可以查看我的 中的 和GitHub,以及 https://jameskle.com/的其他项目。你也可以在 推特 , 直接发邮件给我 或者 在 LinkedIn 上找我。 注册我的简讯 就在你的收件箱里接收我关于数据科学、机器学习和人工智能的最新想法吧!
推荐系统系列之二:学术研究者应关注的 10 类深度推荐系统
RecSys 系列
深度推荐系统的类别
更新: 本文是我探索学术界和工业界推荐系统系列文章的一部分。查看完整系列: 第一部分 , 第二部分 , 第三部分 , 第四部分 , 第五部分 和
介绍
近年来,基于深度学习的推荐系统的研究出版物数量呈指数级增长。特别是,国际领先的推荐系统会议 RecSys 从 2016 年开始定期组织深度学习研讨会。例如,在几周前在哥本哈根举行的 2019 年会议上,有一个关于深度学习的整类论文,它促进研究并鼓励应用这种方法。
在这篇文章和接下来的文章中,我将介绍推荐系统的创建和训练,因为我目前正在做这个主题的硕士论文。在第 1 部分中,我提供了一个关于推荐系统的高级概述,它们是如何构建的,以及它们如何被用来改善各行各业的业务。第 2 部分很好地回顾了正在进行的关于这些模型的优点、缺点和应用场景的研究活动。这里的大部分评论来自张帅等人进行的令人难以置信的综合调查。艾尔,所以如果你想知道更多细节,请去看看!
为什么深度学习求推荐?
与传统的基于内容和协作过滤的方法相比,基于深度学习的推荐系统有 4 个关键优势:
- 深度学习可以用 ReLU、Sigmoid、Tanh 等非线性激活对数据中的非线性交互进行建模… 这一属性使得捕捉复杂而错综复杂的用户-项目交互模式成为可能。传统的方法如矩阵分解和因式分解机本质上是线性模型。作为许多传统推荐器的基础,这种线性假设过于简单,将极大地限制它们的建模表现力。众所周知,通过改变激活选择和组合,神经网络能够以任意精度逼近任何连续函数。这一特性使得处理复杂的交互模式和精确地反映用户的偏好成为可能。
- **深度学习可以高效地从输入数据中学习底层的解释因素和有用的表示。**一般来说,在现实世界的应用中,可以获得大量关于物品和用户的描述性信息。利用这些信息提供了一种方法来提高我们对项目和用户的理解,从而产生更好的推荐器。因此,将深度神经网络应用于推荐模型中的表示学习是一种自然的选择。使用深度神经网络来辅助表示学习的优点有两方面:(1)减少了手工特征设计的工作量;以及(2)它使得推荐模型能够包括不同种类的内容信息,例如文本、图像、音频甚至视频。
- 深度学习对于顺序建模任务来说是强大的。在机器翻译、自然语言理解、语音识别等任务中。,rnn 和 CNN 扮演着关键的角色。它们在挖掘数据序列结构方面具有广泛的适用性和灵活性。对序列信号建模是挖掘用户行为和项目演化的时间动态的一个重要课题。例如,下一件商品/购物篮预测和基于会话的推荐就是典型的应用。因此,深度神经网络非常适合这种序列模式挖掘任务。
- **深度学习具有高度的灵活性。**现在流行的深度学习框架有很多,包括 TensorFlow、Keras、Caffe、MXnet、DeepLearning4j、PyTorch、the ano……这些工具都是模块化开发的,有活跃的社区/专业支持。良好的模块化使得开发和工程更加高效。例如,很容易将不同的神经结构结合起来,形成强大的混合模型,或者用其他模块替换一个模块。因此,我们可以轻松地构建混合和复合推荐模型,以同时捕捉不同的特征和因素。
为了提供该领域的鸟瞰图,我将根据所采用的深度学习技术的类型对现有模型进行分类。
1 >基于多层感知器的推荐
MLP 是一个前馈神经网络,在输入层和输出层之间有多个隐藏层。您可以将 MLP 解释为非线性变换的堆叠图层,了解等级要素制图表达。这是一个简洁而有效的网络,可以将任何可测量的函数近似到任何期望的精度。因此,它是许多高级方法的基础,并被广泛应用于许多领域。
MLP 可以将非线性转换添加到现有的推荐系统方法中,并将其解释为神经扩展。
- 推荐可以被看作是用户偏好和项目特征之间的双向互动。例如,矩阵分解将评级矩阵分解成低维的用户/项目潜在因素。神经协同过滤是一个代表性的工作,它构建了一个双神经网络来对用户和物品之间的这种双向交互进行建模。
- 深度因式分解机是一个端到端的模型,无缝集成了因式分解机和 MLP。它可以通过深度神经网络对高阶特征交互进行建模,并通过因子分解机器对低阶交互进行建模。
使用 MLP 进行特征表示非常简单且高效,尽管它可能不如自动编码器、CNN 和 RNNs 那样有表现力。
- 广度和深度学习是一个很好的模型,可以解决回归和分类问题,最初是为了 Google Play 中的应用推荐而引入的。宽学习组件是单层感知器,其也可以被视为广义线性模型。深度学习组件是一个 MLP。结合这两种学习技术使得推荐器能够捕获记忆和概括。
- 用于 YouTube 推荐的深度神经网络将推荐任务分为两个阶段:候选生成和候选排名。候选生成网络从所有视频语料库中检索子集。排名网络基于来自候选的最近邻居的分数生成前 n 名列表。
- 协同度量学习用欧氏距离代替矩阵分解的点积,是因为点积不满足距离函数的三角不等式。通过最大化用户和他们不喜欢的项目之间的距离和最小化用户和他们喜欢的项目之间的距离来学习用户和项目嵌入。
2 >基于自动编码器的建议
AE 是一种无监督模型,试图在输出层中重建其输入数据。通常,瓶颈层用作输入数据的显著特征表示。它的几乎所有变体(表示 AE、变化 AE、连接 AE 和边缘化 AE)都可以应用于推荐任务。
AE 可以用来学习瓶颈层的低维特征表示。
- 协同深度学习是一种分层贝叶斯模型,将堆叠去噪自动编码器(SDAE)集成到概率矩阵分解(PMF)中。为了无缝结合深度学习和推荐模型,提出了一个通用贝叶斯深度学习框架,该框架由两个紧密相连的组件组成:感知组件(SDAE)和特定任务组件(PMF)。这使得模型能够平衡边信息和交互历史的影响。
- 协作深度排名是针对前 n 名推荐在成对框架中专门设计的。论文表明,成对模型更适合于排行榜的生成。
- 深度协同过滤是一个用协同过滤模型统一深度学习方法的通用框架。该框架使得利用深度特征学习技术来构建混合协作模型变得更加容易。
AE 可以用来直接在重建层填充用户-物品交互矩阵的空白。
- AutoRec 将用户/项目部分向量作为输入,目的是在输出层重建它们。
- 协同去噪自动编码器主要用于排序预测。CDAE 的输入是用户部分观察到的隐式反馈,可以看作是反映用户对项目兴趣的偏好向量。本文还提出了一种负采样技术,从负集合(用户没有与之交互的项目)中采样一个小的子集,这在不降低排序质量的情况下大大降低了时间复杂度。
- 多 VAE 和多 DAE 提出了一种用于隐式数据推荐的变分自动编码器的变体。本文介绍了一种用于参数估计的原理性贝叶斯推理方法,并显示了比常用的似然函数更好的结果。
3 >基于卷积神经网络的推荐
CNN 基本上是一个具有卷积层和池操作的前馈神经网络。它可以捕捉全局和局部特征,从而大大提高模型的效率和准确性。它在处理非结构化多媒体数据方面非常强大。
CNN 可以用来从图像中提取特征。
- 研究视觉特征对兴趣点推荐的影响,提出一种视觉内容增强的兴趣点推荐系统。该系统通过探索视觉内容和潜在用户/位置因素之间的相互作用,采用基于概率矩阵分解的 CNN 来提取图像特征。
- 用于图像推荐的混合表示的比较深度学习提出了用于图像推荐的使用 CNN 的比较深度学习模型。该网络由两个用于图像表示学习的 CNN 和一个用于用户偏好建模的 MLP 组成。
- ConTagNet 是一个上下文感知标签推荐系统。图像特征由 CNN 学习。上下文表示由两层全连接前馈神经网络处理。2 个神经网络的输出被连接并被输入到 softmax 函数中,以预测候选标签的概率。
CNN 可以用来从文本中提取特征。
- DeepCoNN 采用 2 个并行 CNN 对评论文本中的用户行为和项目属性进行建模。该模型利用 CNN 对评论文本丰富的语义表示,缓解了稀疏性问题,增强了模型的可解释性。它利用单词嵌入技术将评论文本映射到一个低维语义空间,同时保留了单词序列信息。然后,提取的评论表示连续通过具有不同内核的卷积层、最大池层和全连接层。
- 卷积神经网络学习资源自动推荐技术构建 e-learning 资源推荐模型,使用 CNN 从学习资源的文本信息中提取项目特征,如学习材料的介绍和内容。
CNN 可以用来从音频和视频中提取特征。
- 基于深度内容的音乐推荐使用 CNN 从音乐信号中提取特征。卷积内核和池层允许在多个时标上操作。这种基于内容的模型可以缓解音乐推荐的冷启动问题。
- 用于视频理解的协作深度度量学习使用基于 CNN 的著名模型 ResNet 提取音频特征。推荐是在协作度量学习框架中执行的,类似于前面提到的 CML。
CNN 可以应用于香草协同过滤。
- 基于外积的神经协同过滤使用 CNN 来改进神经协同过滤。所谓的 ConvNCF 模型使用外积而不是点积来建模用户-项目交互模式。本文将细胞神经网络应用于外积结果,从而可以捕捉嵌入维度之间的高阶相关性。
- 通过卷积序列嵌入的个性化 Top-N 顺序推荐使用 CNN 呈现顺序推荐,其中一个层次和一个垂直 CNN 用于建模联合级顺序模式和跳过行为,以进行顺序感知推荐。
基于图的 CNN 可以处理推荐任务中的交互。
- 图卷积矩阵完成把推荐问题看作是一个带图 CNN 的链接预测任务。这个框架可以很容易地将用户/项目方面的信息(如社交网络和项目关系)集成到推荐模型中。
- 用于网络规模推荐系统的图形卷积神经网络使用图形 CNN 在 Pinterest 上进行推荐。该模型利用随机游走和图 CNN 从图结构和项目特征信息中生成项目嵌入,非常适合大规模的 web 推荐系统。
4 >基于递归神经网络的推荐
RNN 适用于对序列数据建模。它有循环和记忆来记住以前的计算。包括 LSTM 和 GRU 的 rnn 的变体被部署来克服消失梯度问题。
在基于会话的推荐任务中,RNN 可以处理交互的时间动态和用户行为的序列模式。
- GRU4Rec 是一个基于会话的推荐模型,其中输入是采用 1-of-N 编码的会话的实际状态,其中 N 是项目的数量。如果相应的项目在此会话中处于活动状态,则坐标为 1,否则为 0。输出是每个项目成为会话中下一个项目的可能性。
- 网易中使用深度 R ecurrent 神经网络的个人推荐是一个现实世界电子商务网站的基于会话的推荐模型。它利用基本的 RNNs 根据点击历史来预测用户下一步会买什么。为了最小化计算成本,它只保留有限数量的最新状态,同时将较旧的状态折叠成单个历史状态。这种方法有助于平衡计算成本和预测精度之间的权衡。
- 递归推荐网络是一个基于递归神经网络的非参数推荐模型。它可以模拟商品的季节性演变和用户偏好随时间的变化。它使用两个 LSTM 网络作为构建模块来模拟动态用户/项目状态。
用序列模式学习边信息,RNN 也是一个不错的选择。
- 连续时间的循环协同进化潜在特征过程提出了一个协同进化潜在模型来捕捉用户和项目潜在特征的协同进化本质。用户和项目之间的交互在驱动用户偏好和项目状态的变化中起着重要的作用。为了对历史交互进行建模,作者提出使用 RNNs 来自动学习来自用户和项目特征的漂移、进化和共同进化的影响的表示。
- 询问 GRU 提出使用 GRUs 将文本序列编码到潜在因素模型中。这种混合模式解决了热启动和冷启动问题。此外,作者采用了多任务正则化方法来防止过拟合和缓解训练数据的稀疏性。主要任务是评级预测,而辅助任务是项目元数据(例如标签、流派)预测。
- 面向百万用户的基于嵌入的新闻推荐提出使用 GRUs 对用户浏览历史学习更具表达性的聚合,并使用潜在因素模型推荐新闻文章。与传统的基于单词的方法相比,结果显示了显著的改进。该系统已全面部署到在线生产服务中,每天为超过 1000 万独立用户提供服务。
5 >受限玻尔兹曼机基础推荐
RBM 是一个两层神经网络,由一个可见层和一个隐藏层组成。它可以很容易地堆叠到深层网络中。术语受限表示在可见或隐藏层中没有层内通信。
- 用于协同过滤的受限玻尔兹曼机器是第一个建立在 RBM 上的推荐模型。RBM 的可见单位仅限于二进制值,因此,评级得分以一个热码向量表示,以适应这种限制。每个用户都有一个唯一的 RBM 和一个共享参数,这些参数可以通过对比散度算法来学习。这里的本质是用户通过给出评分来暗示他们的偏好,而不管他们如何给项目评分。
- 一个基于 RBMs 的非 IID 协同过滤框架在一个统一的框架中结合了基于用户和基于项目的 RBM-CF。在这种情况下,可见单位由用户和项目隐藏单位共同决定。
- 项目类别感知的条件限制波尔兹曼基于机器的推荐设计了一种混合 RBM-CF,它结合了项目特征并基于条件 RBM。这里,条件层用二进制项目类型建模,因此用不同的连接权重影响隐藏层和可见层。
6 >基于神经注意力模型的推荐
注意力模型是基于输入序列或输入图像上的软内容寻址来操作的可区分的神经架构。它们受人类视觉注意力的激励,可以从原始输入中过滤掉不含信息的特征,并减少噪声数据的副作用。这种注意机制普遍存在于计算机视觉和自然语言处理领域。
在推荐系统中,我们可以利用注意力机制来过滤掉嘈杂的内容,并选择最具代表性的项目,同时提供良好的可解释性。
- 注意力协同过滤使用注意力协同过滤模型,在潜在因素模型内有两级注意力机制。该模型包括项目级和组件级注意:其中项目级注意选择最具代表性的项目来表征用户;而组件级从多媒体辅助信息中为每个用户捕获最具信息性的特征。
- 基于话题关注度的 LSTM 标签推荐使用基于关注度的 LSTM 模型进行标签推荐。该模型利用 RNNs 和注意机制来捕捉序列属性,并识别微博帖子中的信息词。
- 使用基于注意力的卷积神经网络的 Hashtag 推荐对微博中的同一 hashtag 推荐使用基于注意力的 CNN 模型,作为多标签分类问题处理。该模型由一个全局通道和一个局部注意通道组成:其中全局通道具有卷积和最大池层来编码所有的单词;并且本地频道具有给定窗口大小和阈值的关注层来选择信息词。
7 >神经自回归 基础推荐
神经自回归分布估计(NADE)是建立在自回归模型和前馈神经网络之上的无监督神经网络。它是一个易处理和有效的估计器,用于建模数据分布和密度,可以被认为是一个理想的替代限制玻尔兹曼机器。
根据我的评论,协作过滤的神经自回归方法是唯一一篇提出基于 NADE 的协作过滤模型(CF-NADE)的论文,该模型可以模拟用户评级的分布。
8 >深度强化学习 B 基于推荐
强化学习(RL)基于试错范式,由 5 个部分组成(主体、环境、状态、动作和奖励)。深度神经网络和强化学习的结合形成了深度强化学习,它已经在多个领域(如游戏和自动驾驶汽车)实现了人类水平的性能。深度神经网络使代理能够从原始数据中获取知识,并在没有手工特征和领域试探法的情况下导出有效的表示。
传统上,大多数推荐模型认为推荐过程是静态的,这使得捕捉用户的时间意图和及时响应变得很困难。近年来,深度强化学习已经被应用到个性化推荐中。
- 带有负面反馈的建议通过成对深度强化学习提出了一种称为 DEERS 的东西,用于在顺序交互设置中提供负面和正面反馈的建议。
- 针对页面式推荐的深度强化学习探索了一个名为 DeepPage 的框架,它可以根据用户的实时操作来自适应地优化一个页面的项目。
- DRN:新闻推荐的深度强化学习框架是一个新闻推荐系统,它使用深度强化学习来检测新闻内容和用户偏好的动态变化,融入用户的返回模式,增加推荐的多样性。
9 >敌对网络 基础推荐
对抗网络是一种生成型神经网络,由鉴别器和生成器组成。这两个神经网络通过在极小极大博弈框架中相互竞争来同时训练。
- IRGAN——统一生成式和判别式信息检索模型的极小极大博弈是第一个将 GAN 应用于信息检索领域的模型。具体来说,作者展示了在 3 个信息检索任务中的能力,包括网络搜索、项目推荐和问题回答。
- 针对推荐的对抗性个性化排序提出了一种对抗性个性化排序方法,该方法通过对抗性训练来增强贝叶斯个性化排序。它在最初的 BPR 目标和对手之间玩一个极大极小游戏,增加噪音或排列以最大化 BPR 损失。
- 基于生成对抗网络的异构书目网络个性化引文推荐的表示使用基于 GAN 的表示学习方法用于异构书目网络,可以有效地解决个性化引文推荐任务。
- 神经记忆流式推荐器具有对抗训练的网络为基于记忆网络的流式推荐器生成否定样本。
10 >深混动车型 基础推荐
利用深度神经网络的良好灵活性,可以集成许多神经构建块,以形式化更强大和更具表现力的模型。最近的研究趋势表明,混合模型应该为特定的任务进行合理和仔细的设计。
- 协作式基于知识的嵌入将 CNN 与自动编码器相结合,以提取图像中的特征。它利用不同的嵌入技术利用结构化内容、文本内容和可视内容。
- 使用深度神经网络的对话中的引语推荐是一种 RNNs 和 CNN 的混合模型,用于推荐引语,这需要在给定查询文本或对话的情况下生成一个排序的引语列表。它应用 CNN 从推文中学习重要的本地语义,并将它们映射到分布向量。这些向量然后由 LSTM 处理,以计算目标引用与给定推文对话的相关性。
- 个性化关键帧推荐集成 CNN 和 RNNs 进行视频内的个性化关键帧推荐,其中 CNN 用于从关键帧图像中学习特征表示,RNNs 用于处理文本特征。
- 用于上下文感知引用推荐的神经引用网络在用于引用推荐的编码器-解码器框架中集成了 CNN 和 RNNs。CNN 是从引用上下文中捕获长期依赖关系的编码器,而 RNNs 是在给定所有先前单词以及 CNN 获得的表示的情况下学习被引用论文标题中单词的概率的解码器。
- 协作递归自动编码器利用集成 RNNs 和去噪自动编码器来克服局限性,例如缺乏鲁棒性和缺乏对文本信息序列建模的能力。本文设计了一种称为鲁棒递归网络的广义递归神经网络,并提出了一种称为 CRAE 的分层贝叶斯推荐模型。该模型由编码和解码部分组成,并使用带有 RNNs 的前馈神经层来捕获项目内容的顺序信息。
- 使用递归神经网络的监督强化学习用于动态治疗建议将监督深度强化学习与 RNNs 相结合,用于治疗建议。该框架可以从指示信号和评估信号中学习处方策略。
结论
深度学习在许多领域变得越来越流行,包括自然语言处理、图像和视频处理、计算机视觉和数据挖掘,这是一个显著的现象,因为以前没有这样一种通用的方法用于解决不同类型的计算问题。通过深度学习技术的这些方面,它们不仅能够很好地解决许多领域的复杂问题,而且还形成了这些研究领域的共享词汇和共同基础。深度学习方法甚至有助于这些子领域相互合作,而在过去,由于所用技术的多样性和复杂性,这有点成问题。
本文回顾了基于深度学习的推荐系统方法的现有文献,以帮助新的研究人员建立对该领域的全面理解,这些文献收集在张帅等人的“ 【基于深度学习的推荐系统:调查和新观点 ”调查论文中。主要是,它根据所采用的深度学习技术的类型将当前的文献分为 10 类,我相信这有助于读者建立一个整体的理解。我强烈建议您阅读调查报告,深入了解这些类别。
现在继续上 推荐系统系列第三部 !
如果你想关注我在推荐系统、深度学习和数据科学新闻方面的工作,你可以查看我的 中的 和GitHub,以及 https://jameskle.com/的其他项目。你也可以在 推特 , 直接发邮件给我 ,或者 在 LinkedIn 上找我。 注册我的简讯 就在你的收件箱里接收我关于数据科学、机器学习和人工智能的最新想法吧!
推荐系统系列之三:将改变游戏的深度推荐系统的 6 个研究方向
RecSys 系列
推荐社区的研究方向
更新: 本文是我探索学术界和工业界推荐系统系列文章的一部分。查看完整系列: 第一部分 , 第二部分 , 第三部分 , 第四部分 , 第五部分 和
简介
在过去的几年里,我们已经看到推荐领域发生了巨大的变化,从传统的矩阵分解算法(2009 年 c.f. Netflix 奖)转向了最先进的基于深度学习的方法。目前,我正在一家做视频推荐的初创公司实习,我可以清楚地看到这种运动背后的主要原因:
- 来自用户的信号(例如视图)不是独立分布的观察,而是可以表示为动作序列。使用递归神经网络(RNN)有效地理解和建模这些序列是提高视频推荐系统准确性的关键。
- 视频通常由特征(视频的类别、描述标签)来表征,这些特征可用于导出视频之间的相似性。此外,手表的背景(设备、国家……)对于定制推荐至关重要。在深度学习模型中使用它们作为特征实现了更快的收敛,而且在给定视频没有用户信号可用的冷启动机制中也有帮助。
- 反馈(观看)只能在给定的视频上观察到,当视频已经显示给用户时(强盗反馈)。因此,我不知道如果我为某个用户选择了其他视频会发生什么(反事实推理)。在这种类型的环境中学习需要特殊的范例,例如偏离策略学习或反事实学习,这在强化学习中已经被大量使用。最近,一些作品一直在研究这些环境中基于“深度学习”的模型。
在这篇文章和接下来的文章中,我将介绍推荐系统的创建和训练,因为我目前正在做这个主题的硕士论文。在第 1 部分中,我提供了推荐系统的高层次概述,它们是如何构建的,以及它们如何被用来改善跨行业的业务。在第 2 部分中,我提供了一个关于这些模型的优势和应用场景的正在进行的研究计划的很好的回顾。第 3 部分将通过提出几个可能与推荐系统学者社区相关的研究方向来解决使用基于深度学习的推荐模型的局限性。
弊端
使用深度神经网络进行推荐有哪些弊端?
根据我的研究,有 3 个主要问题:
(1)深度学习的一个常见异议是隐藏的权重和激活难以解释。众所周知,深度学习的行为像黑盒一样,提供可解释的预测似乎是一项非常具有挑战性的任务。
(2)深度学习还需要大量数据来完全支持其丰富的参数化。与视觉和语言等其他领域相比,在推荐系统研究的背景下很容易收集大量数据。
(3)深度学习需要**大范围的超参数调优,**其中是一般机器学习的通病。
为了解决这些问题,最近出现了各种各样的研究计划,在这篇文章中,我将介绍其中的 6 个。
1 —评估方法
在阅读了 RecSys 会议上最近发表的大量文献后,我注意到基线模型和评估数据集的选择相当随意,取决于作者。这方面的一个大问题是分数报告中明显的不一致性,这使得新模型的相对基准极具挑战性。
为什么没有 MNIST 或者 ImageNet 等同于推荐系统?最常用的数据集好像是movie lens;然而,即使在这种情况下,训练和测试分离也是任意的。此外,无法控制推荐系统结果中测试样本的难度(随机、按时间顺序等)。)如果没有设计测试集的适当标准,估计和测量该领域的进展将是一个挑战。
2 —大规模设置的可扩展性
可扩展性对于推荐系统在行业环境中的有用性至关重要。为此,通过探索以下问题,推荐模型肯定会更有效:
- 针对非静态和流式数据(大量传入用户和项目)的增量学习
- 高维张量和多媒体数据源的计算效率
- 随着模型参数呈指数增长,平衡复杂性和可伸缩性
一个有前途的研究领域是使用压缩技术来压缩高维输入数据的嵌入空间,这样可以减少模型学习过程中的计算时间。另一个有前途的方法是提取知识来学习推荐系统中用于推理的紧凑模型。关键的概念是训练一个小的学生模型,从一个大的教师模型中吸收知识。
3 —多任务学习
多任务学习是一种同时解决多个学习任务,同时利用不同任务之间的共性和差异的方法。它已经成功地用于许多计算机视觉和自然语言处理任务。最近的一些作品也将这种技术应用于推荐系统:
- 询问 GRU:深度文本推荐的多任务学习提出了一种利用深度递归神经网络将文本序列编码为潜在向量的方法,该潜在向量是在协同过滤任务上端到端训练的特定门控递归单元(GRUs)。对于科学论文推荐的任务,这产生了具有显著更高准确度的模型。
- 神经生存推荐器提出了一个基于长短期记忆的模型,以估计用户何时会返回网站,以及他们未来的收听行为。这样做的目的是解决及时推荐的问题,即在正确的时间推荐正确的项目。它使用生存分析中的工具进行返回时间预测,并使用指数族进行未来活动分析。
- 为推荐生成抽象提示的神经评分回归提出了一个基于深度学习的框架,名为 NRT,它可以同时预测精确评分并生成具有良好语言质量的抽象提示,模拟用户对电子商务网站的体验和感受。对于抽象提示生成,使用门控递归神经网络将用户和项目的潜在表示“翻译”成简洁的句子。
- 扩展的自动编码器推荐框架及其在电影推荐中的应用采用堆叠式自动编码器提取输入的特征,然后重构输入进行推荐。然后在框架中融合项目和用户的边信息,并使用基于 Huber 函数的正则化来提高推荐性能。
使用基于多任务学习的深度神经网络有许多优点。它有助于通过概括共享的隐藏表示来防止过度拟合。它为解释建议提供了可解释的输出。它隐式地增加了数据,从而缓解了稀疏性问题。最后,我们可以部署跨领域推荐的多任务学习,每个特定的任务为每个领域生成推荐(见下一节)。
4 —域适配
单领域推荐系统只关注一个领域,忽略了用户在其他领域的兴趣,大大加剧了稀疏性和冷启动问题。这些问题的一个切实可行的解决方案是应用领域适应技术,其中模型由从源领域学到的知识来辅助。在这种情况下,一个非常受欢迎和研究充分的主题是迁移学习,它可以通过使用从其他领域转移的知识来改进一个领域的学习任务。一些现有的工作表明了深度学习在捕捉不同领域的共性和差异以及在跨领域平台上生成更好的建议方面的功效。
- 在“推荐系统中跨域用户建模的多视图深度学习方法中,微软研究人员提出了一种基于内容的推荐系统,以解决推荐质量和系统可扩展性两方面的问题。他们使用深度学习方法将用户和项目映射到潜在空间,在该空间中,用户和他们偏好的项目之间的相似性最大化,根据他们的 web 浏览历史和搜索查询,使用丰富的功能集来表示用户。他们还展示了如何通过减少输入的维度和训练数据的数量来使这种基于丰富特征的用户表示可扩展。将不同领域组合到单个学习模型中有助于提高所有领域的推荐质量,以及具有更紧凑和语义更丰富的用户潜在特征向量。
- 在“一个用于跨领域推荐系统的内容增强的协同过滤神经网络”中,微软研究人员提出了一个名为 CCCFNet 的跨领域推荐系统,它可以在一个统一的框架中结合协同过滤和基于内容的过滤,从而克服数据稀疏性问题。
在我看来,这是一个很有前途的研究方向,但对于推荐系统的研究来说,仍然没有得到充分的开发。
5 —可解释性和可解释性
反对深度学习的一个常见论点是,神经网络高度不可解释。因此,基于深度神经网络做出可解释的推荐似乎非常具有挑战性。可解释的深度学习的重要性主要体现在两个方面。
- 第一是向用户做出可解释的预测,让他们理解网络推荐背后的因素。用于评论评级预测的具有双重局部和全局注意力的可解释卷积神经网络提出使用具有双重局部和全局注意力的卷积神经网络(CNN)对用户偏好和项目属性进行建模,这是由 CNN 在提取复杂特征方面的优势所激发的。通过使用来自用户的聚合评论文本和项目的聚合评论文本,他们的模型可以学习每个用户和每个项目的独特特征(嵌入)。这些特征然后被用于预测评级。
- 第二是通过探查权重和激活来了解更多关于模型的信息。潜在关系度量学习通过基于记忆的注意力进行协作排序提出了一种称为潜在关系度量学习的模型,该模型可以学习描述每个用户-项目交互的潜在关系。这有助于减轻现有度量学习方法的潜在几何不灵活性。这不仅实现了更好的性能,还实现了更大程度的建模能力,允许他们的模型扩展到更大数量的交互。
最近,注意力模型在缓解神经模型的不可解释性方面做出了很大贡献。例如,注意力因子分解机器通过神经注意力网络从数据中学习每个特征交互的重要性。注意力权重不仅给出了关于模型内部工作的见解,还能够向用户提供可解释的结果。一般来说,注意力模型既可以提高性能,又可以提供简洁的解释,这进一步推动了它在基于深度学习的推荐系统中的使用。
值得注意的是,模型的可解释性和可解释性强烈依赖于应用领域和内容信息的使用。因此,一个有前途的研究方向将是设计更好的注意机制,例如——会话或生成解释。
6 —联合学习框架
做出准确的推荐,需要对物品特性以及用户的实际需求和喜好有深刻的理解。例如,上下文信息可以根据用户的环境和周围环境定制服务和产品,这有助于缓解冷启动问题。隐式反馈可以表明用户的隐式意图,并补充显式反馈(这是一项资源要求很高的任务)。这种隐式反馈可以从社交媒体和物理世界中收集,深度学习可以处理这些数据源,同时带来更多机会来推荐具有非结构化数据(如文本、视觉、音频和视频特征)的多样化项目。
此外,深度学习可以极大地帮助自动化特征工程,这目前需要在推荐研究社区中进行人工干预。还有一个额外的优势是,在野外从自由文本、图像或数据中学习表示,而不必设计复杂的特征工程管道。
最近一个叫做联合表示学习的框架能够学习用户和物品的多模态表示。在该框架中,采用每种类型的信息源(评论文本、产品图像、数字评级等)来基于可用的(深度)表示学习架构学习相应的用户和项目表示。来自不同来源的表示与一个额外的层集成,以获得用户和项目的联合表示。最后,使用成对学习将每个源和联合表示作为一个整体来训练,以对前 N 个推荐进行排序。通过将用户和项目表示为离线嵌入,并使用简单的向量乘法进行在线排名得分计算,与学习复杂预测网络进行在线计算的推荐的其他深度学习方法相比,JRL 还具有快速在线预测的优势。因此,另一个有前途的研究方向是在端到端的管道中设计更好的归纳偏差,这可以对不同模态的数据进行推理,以获得更好的推荐性能。
结论
深度学习在计算机科学的所有子领域都变得越来越流行,例如自然语言处理、图像和视频处理、计算机视觉和数据挖掘,这是一个值得注意的现象,因为以前没有这样一种通用的方法用于解决不同类型的计算问题。通过深度学习技术的这一方面,它们不仅能够在许多领域中修复复杂的问题,而且还形成了这些研究领域的共享词汇和共同基础。深度学习方法甚至有助于这些子领域相互合作,而在过去,由于所用技术的多样性和复杂性,这有点成问题。
尽管深度学习在推荐系统领域的应用有望取得重大和令人鼓舞的成果,但可解释性和可扩展性等挑战仍有待改进,并保证未来的工作。就个人而言,我对用于推荐商品的领域适应技术非常感兴趣,并希望看到 RecSys 的 ImageNet 时刻。请继续关注本系列未来的博客文章,深入了解这些模型如何工作的本质细节。
现在继续上 推荐系统第四部 !
如果你想关注我在推荐系统、深度学习和数据科学新闻方面的工作,你可以查看我的Medium和GitHub,以及 https://jameskle.com/的其他项目。也可以在 推特 , 直接发邮件给我 ,或者 在 LinkedIn 上找我。 注册我的简讯 就在你的收件箱里接收我关于数据科学、机器学习和人工智能的最新想法吧!
具有强化学习的推荐系统
哈佛数据科学顶点项目,2019 年秋季
团队成员:赵小菲,,钱丰
对于 Spotify 等服务提供商来说,推荐系统可能是一项至关重要的竞争优势,因为 Spotify 主要通过用户订阅来发展业务。准确的推荐有助于改善用户体验,增强客户忠诚度。
传统的推荐方法包括使用监督学习对用户-项目交互进行建模,如分类、基于记忆的用户历史内容过滤等等。这些想法忽略了连续时间步的依赖性。受强化学习在其他领域(如玩 Atari 游戏)的进展的启发,我们应用了一种最先进的模型,即深度确定性梯度策略(DDPG),将音乐推荐建模为一个顺序决策过程。在这个设置中,DDPG 学习者的动作是从一个巨大的库中选择的一首歌曲。通过使用一组连续特征来表示每首歌曲,并随后将动作空间从离散扩展到连续,我们的代理成功地扩大了它可以容纳的候选歌曲的数量,同时保持了令人满意的推荐准确性和多样性。
数据
我们使用“音乐流会话数据集”(MSSD) ,最初是由 Spotify 为一项比赛发布的。数据集包含收听会话数据和歌曲特征的查找表。
数据结构
上面是我们现有数据的结构图。我们有两个数据文件:一个文件包含多行会话,另一个文件包含多行轨迹要素。曲目是歌曲,会话是单个用户收听的一系列曲目。Spotify 将会话的最大长度限制为 20。
在会话内部,记录轨迹之间和轨迹内部的动作。曲目之间的动作包括:skip_very_briefly、skip_briefly、mostly _ played _ before _ skip、no_skip,指示用户从一个曲目转移到下一个曲目的模式。一首歌内的动作主要有 move_forward、move_backward、no_move,表示用户在听一首曲目时的行为;以及指示用户暂停行为的 no_pause_before_play、short_pause_before_play、long_pause_before_play。上述响应可以被解释为每个音轨上的用户偏好。
我们也有每个曲目的特征数据,这些特征由 Spotify 通过手动或自动方式给出。这些特征包括声音、节拍、舞蹈性等。并且在[0,1]之间变化。我们可以将这些特性整合到我们的模型中。
数据采样
MSSD 是一个巨大的数据集,有超过 2000 万首歌曲和 1700 万个会话,包括大约 600 GB 的数据。为了使我们的模型适应这个数据集,我们选取了歌曲和会话的子集,如下所述。
要选择 MSSD 的一个子集,我们需要执行以下操作:首先,我们对会话数据进行采样,然后,我们对会话跟踪数据进行采样。在原始数据中,我们决定从数据中抽取 10 万个会话作为样本。由于数据被分成 10 个大小相似的 zip 文件,我们需要从每个 zip 文件中抽取 1 万个会话作为样本。每个 zip 文件由 N 个数据文件组成,因此我们需要从每个数据文件中抽取 10k/N 千个会话。由于每个数据文件包含不同数量的会话,我们需要以不同的概率从每个数据文件中进行采样。例如,如果数据文件$ f1 中有 中有 中有M$个会话,我们以 10k/NM 的概率随机接受文件 f1 中的每个会话。
在对所有会话进行采样后,我们需要找出出现在采样数据中的所有轨迹。如果数据的大小很小,这可能很容易:我们可以使用一组数据结构来找到一组轨道 id。然而,由于数据的大小太大,无法存储在内存中,我们决定使用数据库(Macbook Air 2014 上的 Mysql)来让数据库为我们维护树结构。使用数据库,我们可以很容易地找到我们需要的曲目。
我们从 300 多个数据文件中统一采样,并将数据减少到 106,375 个会话(376MB)和 281,185 个磁道(167MB)。
模型概述
强化学习模型有以下组成部分:主体、环境、状态、奖励函数、价值函数和政策。为了简化问题,我们假设一个假想的用户,他的经验来自所有实际用户。我们的推荐器模型将成为系统的代理,为这个假设的用户处理歌曲,跳过/不跳过推荐。用户表现为系统的环境,根据系统的状态响应系统的建议。用户反馈决定了我们的奖励,即只有用户不跳过才得一分。行动的代理人是宋推荐的。我们的状态被定义为过去 5 个步骤的歌曲特征和相应的用户反应,不包括当前步骤。所以,反馈和行动一起给了我们下一个状态。代理的目标是学习一个策略,在 15 个步骤中最大化累积奖励。我们将预测的长度设置为 15,以避免冷启动,也就是说,在没有足够的历史记录时进行预测,假设我们的原始会话长度为 20,历史记录长度为 5。
更正式地说,数学定义如下:
Model Pipeline
自动编码器
概观
我们的数据首先通过一个由两部分组成的自动编码器:一个数字压缩器和一个时间压缩器。每个数据点最初是 5×21,对应于 5 首歌曲的 20 个歌曲特征和观察到的用户动作(跳过/不跳过)。我们用前馈自动编码器压缩 20 首歌曲特征,该编码器将输入转换成 5×8。我们在最后将用户响应连接起来,得到这个 5 x 9。然后,我们将该潜在表示输入到 LSTM 自动编码器,该编码器沿着时间维度压缩成 1×9 维度的单个向量。
履行
在训练过程中,我们首先构建一个自动编码器,并在歌曲特征数据集上对其进行训练。
然后我们固定编码层和解码层,并用 LSTM 时间压缩器连接它们。编码层负责预处理数字特征,解码层负责将时间解码器的输出扩展到最大长度。
时间压缩器尝试将 5 x 9 输入压缩为 1 x 9,然后解码为 5 x 9。为了适应混合型数据,我们使用两个时间解码器,一个使用 MSE 损失来恢复数值,另一个使用交叉熵损失来恢复二进制用户跳过行为。最终损失是这两个损失的线性组合,分配的权重影响这两个任务中的模型性能。尽管使用了两个解码器,它们共享一个长度为 9 的潜在表示作为输入。在预测过程中,增加了一个步骤,即数值解码器获取时间解码器的输出,并恢复数值特征的原始维数。
可能的延期
以前的“数字压缩器”不是只压缩数字特征,而是压缩歌曲特征和二进制用户响应,为了与“数字压缩器”相区别,我们称之为“组合压缩器”。通过从我们的时间压缩器中释放压缩分类响应的负担,可以进一步改进这种结构。在这个项目中,我们必须将组合压缩器与时间压缩器连接起来。
结果
Table 1: Results of the autoencoders
我们的数字特征被标准化为在 0 到 1 之间。从 1×9 潜在值重构 5×20 的 MSE 是 0.0111,大约是特征范围的 1%。重构二元用户行为的准确率为 88.89%。训练数值压缩器的 MSE 是 0.0016。所有统计数据都是在测试集上计算的。最后两行是实验组合压缩机的性能统计。实验性组合压缩器具有在测试集上检索二进制用户跳过行为一次的准确度,以及在 0.0064 处略微增加的数值重构 MSE。
强化学习
结构
- 状态:时间压缩器的潜在向量。长度为 9 的状态包含前五首歌曲的信息和相应的用户响应。
- 动作:数值压缩器的潜在向量。动作是推荐歌曲。为了降低维数,我们使用长度为 8 的歌曲特征的潜在表示。
- 奖励:不跳概率和推荐多样性之和。
- 代理:策略功能和 Q 功能。
环境
当给定一对状态和动作时,环境理应回报。然而,在这个问题中,我们无法观察到实时的用户响应。我们要做的是使用现有的数据来估计跳过/不跳过行为。
深度确定性政策梯度
DDPG(Deep Deterministic Policy Gradient)是深度确定性政策梯度(Deep Deterministic Policy Gradient)的缩写,是一种无模型的政策外行动者批评算法,结合了 DPG 和 DQN。最初的 DQN 在离散空间中工作,DDPG 在学习确定性政策的同时,用演员-评论家框架将其扩展到连续行动空间。
该算法中有四个神经网络:演员、评论家、演员目标和评论家目标。行动者网络学习策略函数,而批评家网络近似 Q 函数。
结果
由于我们的模型需要前五首歌曲的信息,代理将为每个会话提供 15 个推荐。因此我们每集跑 15 步。
推荐系统可以从我们截断的音乐会话中累积的最高分数是 15。不跳过行为占据了整个数据的 34%,相当于基准分数 5 左右。正如我们从左图中看到的,在仅仅几百集的训练中,我们的代理达到了大约 11 的分数,展示了比基准好得多的性能。右边是多样性得分。如果当前动作和前一个动作之间的距离超过某个阈值(0.4 倍标准差),我们得到的多样性得分为 1,否则为 0。这是为每一步计算的,因此最高分也是 15。从剧情可以看出,一开始我们的经纪人倾向于推荐类似的歌曲。但在大约 300 集之后,它学会了考虑推荐的多样性。
结论
在这个项目中,我们成功地使用强化学习来捕捉用户-歌曲交互以及当前和过去决策之间的时间依赖性。未来的研究可以通过放宽许多简化的假设来扩展我们的发现:首先,不是假设一个单一的假设用户,而是进行客户分层,并将这一变量纳入模型。第二,我们可以考虑自会话开始以来的完整用户历史,而不是在五点截断历史。此外,我们可以通过将实验组合压缩器连接到时间压缩器和下游 DDPG 代理来测试它是否优于当前模型。
在训练方面,由于计算资源和时间的限制,我们正在分别训练不同的模型组件。这将是一个好主意,训练模型端到端,使潜在的可能更适合强化学习任务。最后,在我们研究的基础上,可能最重要的改进是为强化学习代理提供一个真实的环境。我们当前的数据集高度偏向于跳过行为(未跳过率为 34%),可能无法反映真实的客户行为。因此,与使用数据集(600G)模拟环境不同,让模型投入生产的更好方法是招募一些参与者来测试他们对建议的反应。这样代理可以充分挖掘推荐空间,做出更可信的推荐。
承认
我们要向 Javier Zazo 致以最诚挚的谢意,他是我们的导师,强化学习方面的专家,也是我们的好朋友,他总是给我们提出宝贵的建议,鼓励我们继续前进。297R 研究项目的负责人 Pavlos Protopapas,使这一难忘的研究之旅成为可能的导师,以及 Spotify 高级研究员兼数据科学家 Aparna Kumar,一位出色的支持经理。
该研究项目隶属于 IACS 297R 研究项目。
原载于https://sophieyanzhao . github . io。
大规模推荐系统——让 Grab 的日常应用变得超级棒
这篇文章最初发表在这里作为 Grab 的工程博客的一部分。来看看我们更多的精彩作品吧。
Grab 是东南亚领先的 superapp ,提供高使用率的日常服务,如打车、送餐、支付等等。我们的目标是让人们更好地获得对他们来说重要的服务,提供更多价值和便利,因此我们一直在扩展我们的生态系统,以包括账单支付、酒店预订、旅行规划和视频,未来还会有更多。我们希望为我们的客户提供更好的服务——不仅仅是通过将 Grab 应用程序与有用的功能和服务打包,而是通过为他们每个人提供独一无二的个性化体验。
为了实现我们的超级应用雄心,我们与合作伙伴合作,他们和我们一样,希望帮助推动东南亚向前发展。
我们与合作伙伴的许多协作工作都可以在 Grab Feed 中看到。在这里,我们以聚合的方式传播关于 Grab 和我们合作伙伴的各种类型的内容,为整体用户体验增加价值。这是提要的样子:
Waiting for the next promo? Check the Feed.
Looking for news and entertainment? Check the Feed.
Want to know if it’s a good time to book a car? CHECK. THE. FEED.
随着我们继续向 Grab Feed 添加更多的卡片、服务和大量内容,我们的用户可能会发现更难找到与他们相关的信息。因此,我们努力确保我们的平台能够根据最适合用户的资料来区分和显示信息。这又回到了我们一直以来关注的焦点——客户,这也是我们如此重视为每个客户提供个性化的 Grab 体验的原因。
为了在像东南亚这样高度多样化的市场中脱颖而出,我们利用我们数据的深度来了解用户想要看到什么样的信息以及他们应该在什么时候看到这些信息。在本文中,我们将讨论 Grab Feed 的推荐逻辑和策略,以及它的未来路线图。
启动你的引擎
We offer a lot of great services.
我们在这里试图解决的问题被称为建议问题。简单来说,这个问题是关于推断消费者向其推荐内容和服务的偏好。在 Grab Feed 中,我们有不同类型的内容,我们希望向不同类型的消费者展示,我们的挑战是确保每个人都能获得高质量的内容。
为了解决这个问题,我们建立了一个推荐引擎,这是一个建议用户应该考虑消费的内容类型的系统。为了提出建议,我们需要了解三个因素:
- 用户。根据用户如何使用 Grab 应用,我们可以推断出很多关于用户的信息,例如他们乘坐的次数,他们喜欢点的食物类型,他们购买的电影优惠券,他们玩过的游戏,等等。这些信息让我们有机会更好地了解用户的偏好,使我们能够将他们的个人资料与相关和合适的内容相匹配。
- 物品。这些都是内容的特点。我们考虑内容的类型(例如视频、游戏、奖励)和可消费性(例如购买、观看、兑换)。我们还考虑其他元数据,如商家的营业时间、奖励积分和兴趣点的 GPS 坐标。
- 语境。这与用户消费我们内容的环境有关。它可以是一天中的时间、用户的位置或者当前的提要类别。
使用来自所有这些因素的信号,我们建立一个模型,向用户返回一组排序的卡片。在接下来的几节中会有更多的介绍。
了解我们的用户
从上述信号中解读用户偏好本身就是一个挑战。这里需要注意的是,我们一直处于实验状态。缓慢但肯定的是,我们正在继续微调如何测量内容偏好。也就是说,我们关注两个领域:
- 动作。我们坚信,并非所有的互动都是平等的。喜欢一张牌其实就代表你喜欢吗?你喜欢事物的速度和你的朋友一样吗?交易呢,那些更受青睐?提要为用户向平台提供反馈引入了许多方法。这些事件包括喜欢、点击、滑动、浏览、交易和行动号召。
根据不同的型号,我们可以采取稍微不同的方法。我们可以了解每个事件的重要性,并将它们聚合起来以获得预期的评级,或者我们可以预测每个事件的概率并据此进行排名。 - 新近度。旧的交互可能没有新的有用。提要是一个不断发展的产品,我们用户的偏好也是如此。未能衰减旧交互的权重会给我们提供对用户不再有意义的推荐。
优化体验
An overview of our recommendation strategy architecture
构建一个可行的推荐引擎需要几个阶段。通过迭代工作,我们能够创建一些核心推荐策略来产生最终模型,以确定内容与用户的相关性。我们将在这一部分讨论每个策略。
- 人气。这种策略被称为趋势推荐。我们在一个滚动的时间窗口内捕获在线点击流事件,并汇总这些事件,向用户展示在那个时间点每个人都喜欢什么。倾听群众通常是一种有效的策略,但是这种特殊的策略还可以通过为新的 feed 用户提供建议来帮助我们解决冷启动问题。
- 用户最爱。我们知道我们的用户有不同的品味,用户会比其他用户有更多的内容。在这个策略中,我们捕捉到了个人参与度和用户不断变化的偏好。
- 协同过滤。构建我们的日常超级应用的一个关键目标是让用户体验不同的服务。为了实现可发现性,我们研究相似的用户,以发现他们可能拥有的一组相似的偏好,然后我们可以使用这些偏好来指导我们向其他用户展示什么。
- 习惯性行为。有时用户只想做一件特定的事情,我们不希望他们只是为了做这件事而一直向下滚动。我们已经建立了习惯性的建议来解决这个问题。因此,如果用户总是在午餐时使用 feed 滚动食物选择,或者在周日早上瞥一眼乘车高峰(双关语),我们仍然会覆盖他们。
- 深度推荐。我们已经向您展示了我们如何使用订阅源数据来推动整个平台的使用。但是如何利用平台数据来驱动用户反馈行为呢?通过嵌入我们多个业务部门的用户活动,我们还能够利用这些数据和点击流来确定每个用户的内容偏好。
我们应用所有这些策略,通过选择或聚合来找出服务于用户的最佳推荐。这些决定是通过对用户的定期实验和研究来决定的。
总是在学习
我们不断学习和重新学习我们的用户。有很多方法可以理解行为,也有很多不同的方法可以整合不同的策略,因此我们一直在迭代这些方法,以在应用程序上提供最个性化的体验。
为了识别用户的偏好和最佳策略展示,我们利用我们的实验平台向不同的用户展示我们的推荐引擎的不同配置。为了监控我们的推荐质量,我们使用互动、点击率和参与率等在线指标和 Recall@Kand 归一化折扣累积收益(NDCG)等离线指标来衡量影响。
未来的工作
通过我们建立这个推荐平台的经验,我们意识到这个空间足够大,并且有很多可以持续建立的部分。为了不断改进,我们已经在以下项目上开展工作:
- 业务和技术指标的多目标优化
- 为超参数优化构建自动化管道
- 结合在线学习进行实时模型更新
- 面向用户个性化推荐策略的多臂土匪
- 替换系统,让利益相关者更好地理解系统
结论
Grab 是东南亚发展最快的公司之一。随着其业务、合作伙伴关系和产品的不断增长,超级应用的房地产问题只会越来越大。在本帖中,我们将讨论如何通过构建一个理解用户并为每个用户提供个性化体验的推荐系统来解决这个问题。这个系统(包括美国)继续从我们用户的反馈中学习和迭代,为他们提供最好的版本。
如果你有任何反馈、建议或其他好主意,请随时拨打justin.bolilia@grab.com联系我。有兴趣自己研究这些技术吗?查看我们的职业页面。
现实世界中的推荐系统
设计和构建推荐系统管道的过程概述。
选择太少不好,但选择太多会导致瘫痪
你听说过著名的 果酱实验 吗?2000 年,来自哥伦比亚和斯坦福大学的心理学家希娜·艾扬格和马克·莱珀根据他们的实地实验进行了一项研究。在平常的一天,消费者在当地食品市场的一家高档杂货店购物时,会看到一个展示 24 种果酱的试吃摊位。另一天,同一个摊位只展示了 6 种果酱。进行这个实验是为了判断哪个摊位会获得更多的销售,人们认为更多种类的果酱会吸引更多的人来到柜台,从而获得更多的生意。然而,观察到一个奇怪的现象。虽然有 24 个果酱的柜台产生了更多的兴趣,但与 6 个果酱的柜台相比,它们的销售转化率相当低(大约低 10 倍)。
Image Source: [The Paradox of Choice](http://The Paradox of Choice)
刚刚发生了什么?嗯,看起来很多选择看起来确实很吸引人,但是这种选择过多有时可能会给顾客带来困惑和阻碍。因此,即使在线商店可以获得数百万件商品,如果没有良好的推荐系统,这些选择可能弊大于利。
在我上一篇关于推荐系统的文章中,我们对推荐系统的非凡世界有一个概述。现在让我们更深入地了解一下它的体系结构和与推荐系统相关的各种术语。
推荐系统概述以及它们如何提供一种有效的定向营销形式。
towardsdatascience.com](/the-remarkable-world-of-recommender-systems-bff4b9cbe6a7)
术语和架构
让我们来看一些与推荐系统相关的重要术语。
项目/文件
这些是系统推荐的实体,如网飞上的电影、Youtube 上的视频和 Spotify 上的歌曲。
查询/上下文
系统利用一些信息来推荐上述项目,并且这些信息构成了查询。查询还可以是以下内容的组合:
- 用户信息,可能包括用户 id 或用户之前交互过的项目。
- 一些额外的环境,如用户的设备、用户的位置等。
嵌入
嵌入是将分类特征表示为连续值特征的一种方式。换句话说,嵌入是高维向量到称为嵌入空间的低维空间的平移。在这种情况下,要推荐的查询或项目必须映射到嵌入空间。许多推荐系统依赖于学习适当的 嵌入 查询和项目的表示。
这里有一个关于推荐系统的很好的资源,值得一读。我在上面总结了一下,但是你可以详细研究一下,它给出了一个整体的建议,尤其是从谷歌的角度。
机器学习中的推荐系统介绍
developers.google.com](https://developers.google.com/machine-learning/recommendation/)
架构概述
推荐系统的常见架构包括以下三个基本组件:
1.候选生成
这是推荐系统的第一阶段,从用户过去的活动中获取事件作为输入,并从大型语料库中检索一小部分(数百个)视频。主要有两种常见的候选生成方法:
- 基于内容的过滤
基于内容的过滤包括根据项目本身的属性推荐项目。系统推荐与用户过去喜欢的项目相似的项目。
- 协同过滤
协同过滤依赖于用户-项目交互,并且依赖于相似用户喜欢相似事物的概念,例如购买了这个项目的顾客也购买了这个项目。
2.得分
这构成了第二阶段,其中另一个模型进一步对候选人进行排名和评分,通常以 10 为标度。例如,在 Youtube 的情况下,排名网络通过使用描述视频和用户的丰富特征集根据期望的目标函数给每个视频分配分数来完成这项任务。得分最高的视频被呈现给用户,按照他们的得分排序。
3.重新排名
在第三阶段,系统考虑额外的约束,以确保多样性、新鲜度和公平性。例如,系统移除用户先前明确不喜欢的内容,并且还考虑网站上的任何新项目。
The overall structure of a typical recommendation system
相似性度量
如何识别一个项目与另一个项目是否相似?事实证明,基于内容的过滤技术和协作过滤技术都采用了某种相似性度量。让我们来看两个这样的指标。
考虑两部电影——电影 1 和电影 2 属于两种不同的类型。让我们在 2D 图上画出电影,如果电影不属于某个类型,则赋值 0,如果电影属于该类型,则赋值 1。
这里,电影 1(1,1)属于类型 1 和类型 2,而电影 2 只属于类型 2(1,0)。这些位置可以被认为是向量,这些向量之间的角度告诉我们很多关于它们的相似性。
余弦相似性
它是两个向量夹角的余弦值,similarity(movie1,movie2) = cos(movie1,movie2) = cos 45
约为 0.7。余弦相似度 1 表示最高相似度,而余弦相似度值 0 表示没有相似度。
点积
两个向量的点积是角度的余弦乘以范数的乘积,即similarity(movie1,movie2) = ||movie1|| ||movie 2|| cos(movie1,movie2).
推荐管道
典型的推荐系统管道包括以下五个阶段:
A typical recommender system pipeline
假设我们正在构建一个电影推荐系统。该系统没有用户或电影的先验知识,而只有用户通过他们给出的评级与电影的交互。这是一个由电影 ID、用户 ID 和电影分级组成的数据帧。
Movie rating Dataframe
因为我们只有收视率,没有其他的,我们将使用协同过滤推荐系统。
1.预处理
- 效用矩阵转换
我们需要首先将电影分级数据帧转换成用户项目矩阵,也称为效用矩阵。
矩阵的每个单元都由用户对电影给出的评级填充。这个矩阵通常被表示为一个稀疏矩阵,因为由于缺少对该特定电影的任何分级,许多单元是空的。如果数据稀疏,协同过滤就不能很好地工作,所以我们需要计算矩阵的稀疏度。
如果稀疏值大约为 0.5 或更大,那么协同过滤可能不是最好的解决方案。这里需要注意的另一个要点是,空单元格实际上代表新用户和新电影。因此,如果有高比例的新用户,那么我们可能会考虑使用一些其他的推荐方法,如基于内容的过滤或混合过滤。
- 正常化
总会有一些用户过于积极(总是给出 4 或 5 分)或过于消极(把所有事情都评为 1 或 2 分)。因此,我们需要将评分标准化,以考虑用户和项目的偏见。这可以通过取平均值归一化来实现。
Source: Normalisation the Ratings
2.模特培训
数据经过预处理后,我们需要开始模型构建过程。矩阵分解是协同过滤中常用的技术,尽管还有其他方法,如邻域法。以下是涉及的步骤:
- 对用户-项目矩阵进行因子分解,得到 2 个潜在因子矩阵——用户因子矩阵和项目因子矩阵。
用户评级是由人类生成的电影的特征。这些特征是我们认为重要的可以直接观察到的东西。然而,也有一些不能直接观察到的特征,但在评级预测中也很重要。这些隐藏特征被称为潜在特征。
A simplified illustration of the latent factor approach
潜在特征可以被认为是用户和项目之间交互的基础特征。本质上,我们不清楚每个潜在特征代表什么,但是可以假设一个特征可能代表用户喜欢喜剧电影,而另一个潜在特征可能代表用户喜欢动画电影等等。
- 从这两个潜在矩阵的内积预测缺失评分。
潜在因素这里由 **K 表示。**这个重构的矩阵填充原始用户-项目矩阵中的空单元,因此未知的评级现在是已知的。
但是我们如何实现上面显示的矩阵分解呢?事实证明,有很多方法可以做到这一点,使用下面的方法之一:
- 交替最小二乘法
- 随机梯度下降(SGD)
- 奇异值分解
3.超参数优化
在调整参数之前,我们需要选择一个评估指标。对于推荐者来说,一个流行的评估标准是 K 处的精度,其中查看前 K 个推荐,并计算这些推荐中有多大比例与用户实际相关。
因此,我们的目标是找到在 K 处给出最佳精度的参数,或者任何其他想要优化的评估指标。一旦找到参数,我们可以重新训练我们的模型,以获得我们的预测评级,我们可以使用这些结果来生成我们的建议。
4.后加工
然后,我们可以对所有预测的评级进行排序,并为用户获得前 N 名推荐。我们还想排除或过滤掉用户之前已经交互过的项目。就电影而言,推荐一部用户以前看过或以前不喜欢的电影是没有意义的。
5.估价
我们之前已经讨论过这一点,但是让我们在这里更详细地讨论一下。评估任何推荐系统的最佳方式是在野外测试它。像 A/B 测试这样的技术是最好的,因为人们可以从真实的用户那里得到真实的反馈。然而,如果这是不可能的,那么我们不得不求助于一些离线评估。
在传统的机器学习中,我们分割原始数据集来创建训练集和验证集。然而,这并不适用于推荐模型,因为如果我们在单独的用户群上训练我们的所有数据,并在另一个用户群上验证它,那么该模型将不起作用。所以对于推荐者,我们实际上随机屏蔽了矩阵中的一些已知评分。然后,我们通过机器学习预测这些屏蔽的评级,然后将预测的评级与实际评级进行比较。
Evaluating recommenders Offline
前面我们谈到了精度作为一种评估指标。以下是一些可以使用的其他方法。
Python 库
有许多专门为推荐目的而创建的 Python 库。以下是最受欢迎的:
- 惊喜:Pythonscikit构建和分析推荐系统。
- 隐式 :隐式数据集的快速 Python 协同过滤。
- light FM:Python 实现了许多流行的隐式和显式反馈推荐算法。
- pyspark.mlib .推荐 : Apache Spark 的机器学习 API。
结论
在本文中,我们以缩小选择范围的方式讨论了推荐的重要性。我们还介绍了设计和构建推荐系统管道的过程。Python 实际上让这个过程变得更简单,因为它为此提供了对许多专门库的访问。尝试使用一个来构建您自己的个性化推荐引擎。
参考
使用紫外线分解的推荐系统
快速浏览 Jure Leskovec、Anand Rajaraman 和 Jeffrey Ullman 的大规模数据集挖掘第 9 章
如今,几乎每个行业都在使用无数推荐系统的例子。大多数人在高层次上理解推荐系统试图达到的目的。然而,没有多少人了解它们在更深层次上是如何工作的。这就是 Leskovec、Rajaraman 和 Ullman 在他们的书的第 9 章【大规模数据集的挖掘】中深入探讨的内容。
今天使用的推荐系统的一个很好的例子是网飞。只要你登录网飞,就会看到各种各样的板块,比如“现在趋势”或“新发布”,但还有一个板块的标题是“你的最佳选择”。这一部分使用了一个复杂的公式来估算你最喜欢哪部电影。这个公式考虑了你以前欣赏过的电影,以及其他像你一样的人也欣赏过的电影。
这暗示了推荐系统的两个主要领域:基于内容的系统和协作系统。我们将在本文中更深入地探讨这些领域,但是,我想对每个领域做一个快速总结。基于内容的系统使用项目间的相似性。在网飞的例子中,一个基于内容的系统将关注电影之间的相似性,例如类型、导演、演员等。协作系统关注不同用户之间的相似性。再次以我们的网飞为例,假设有两个用户,他们彼此看过所有相同的电影,并且对每部电影的评价完全相同。如果他们中的一个人看了一部新电影,并将它评为 4 级,那么可以想象另一个人也会将这部电影评为 4 级。这两种技术是理解现代推荐系统如何工作的基础。
在互联网时代之前,一切都是在实体店买卖的。这些商店不可能为每一个进门的人量身定做商品。他们只能吸引大众。换句话说,他们的策略是非个人的,完全由畅销书或最受欢迎的商品驱动。想象一下 20 世纪 60 年代的唱片店。由于空间的限制,他们一次只能储存有限数量的专辑。为了最大化销售,他们会储存最有可能吸引最多人的专辑。然而,会有许多对音乐有独特品味的人不会被“迎合大众”的策略所服务。
将这家 20 世纪 60 年代的唱片店与 2019 年的 Spotify 相比较。Spotify 有一个 1960 年的唱片店没有的问题。Spotify 不可能向用户展示其曲库中所有可用的歌曲。Spotify 被迫开发一种方法来估计个人最有可能喜欢哪些歌曲。这是每个在线零售商都有的问题。无论在线零售商销售什么类型的产品,他们都需要开发一种方法,向每个客户成功推荐他们的大量选择。在竞争激烈的在线零售世界中,一家未能建立准确推荐系统的在线公司将处于巨大的劣势。
效用矩阵
Figure 1 (Mining of Massive Datasets — pg 308)
理解推荐系统的第一步是理解什么是效用矩阵以及它是如何构成的。效用矩阵是每个 用户的 对他们看过和/或评价过的每个 项目 的享受程度的集合。在我们的网飞例子中,我们可以想象这将会是什么样子。假设我们有来自四个网飞用户的评论:A、B、C 和 D,分别针对五部不同的电影:哈利波特 1、2 和 3、暮光之城和星球大战 1、2 和 3(见图 1)。我们的四个用户都没有看过每部电影,所以我们的表中有许多空白。这些空白单元格是我们作为一家公司想要预测的,以便知道我们应该向我们的每个用户推荐哪些电影。实际上,这个矩阵将是巨大的,包含数千列(电影)和数百万行(用户)。该矩阵也将非常稀疏,因为大多数用户不会看到网飞上数以千计的电影中的大多数。
基于内容的推荐
Figure 2 (Mining of Massive Datasets — pg 308)
正如我们前面简要提到的,基于内容的推荐关注项目之间的相似性。物品的相似性可以是任何东西。在我们的网飞例子中,它可以是流派、运行时间、提名/奖项、演员、导演、父母评级等。让我们选择一个简单的例子,我们只关注一个相似之处:电影系列。在我们的例子中,我们有两个不同的电影系列:哈利波特和星球大战,每个系列都有三部不同的电影。
在基于内容的推荐中,该示例中的用户 A 对于剩余的两部哈利波特电影将被给予预期评级 4,而对于剩余的两部星球大战电影将被给予预期评级 1。然而,我们可以想象,如果我们添加更多的项目相似性,而不仅仅是电影系列,这将变得更加复杂。让我们快速看一下用户 b。我们的电影系列基于内容的推荐会告诉我们所有星球大战电影的预期评级是什么?不是很多,对吧?也许如果我们有除了电影系列之外的额外功能,在《星球大战》电影和用户 B 看过的其他电影之间可能会有一些其他的相似之处。
协作推荐
同样,正如我们上面简要提到的,协作推荐系统关注用户之间的相似性。看看我们在网飞的四个用户的例子,假设不同的用户会以不同的尺度给每部电影打分是现实的。例如,某人可能只给电影打 3 到 5 分,而另一个人可能主要打 1 到 3 分。为了说明这种用户差异,我们希望在进行协作推荐时标准化效用矩阵。这种常态化会把每个人的评分系统放在同一个标尺上。
Figure 3 (Mining of Massive Datasets — pg 324)
为了标准化数据,我们首先找到每个用户的平均电影评级。然后我们创建一个新的矩阵,对于每个用户,我们从每个提供的电影评分中减去用户的平均评分。具有负分的电影是对于该特定用户具有低于平均分数的电影,而正分表示用户对该电影的评价高于他们的平均分数。上图显示了我们四个用户的标准化评分。用户 A 的平均得分为 3.33 (4、5 和 1)。当我们从提供的三个分数中去掉 3.33,我们得到 0.67 (2/3),1.67 (5/3)和-2.33 (-7/3)。
我想强调一下我们在这里所做的。在原始矩阵中,用户 A 和 C 都将电影评为 4 级。用户 A 将 HP 1 评级为 4,而用户 C 将 SW1 评级为 4。然而,在我们的归一化矩阵中,我们可以看到这些值不再相同。用户 A 在 2/3 处拥有 HP1,而用户 C 在 1/3 处拥有 SW 1。这是因为用户 C 与用户 A 相比具有更高的平均分,这意味着来自用户 C 的低分与来自用户 A 的低分相比具有更大的权重
既然每个人的评分都在同一等级上,我们就可以准确地比较用户之间的相似性。我们这样做的方法是通过计算任意两个用户的余弦值。大余弦意味着我们测量的角度小,反之亦然。因为角度表示用户之间的相似性,所以大余弦(小角度)意味着被测量的两个用户之间存在小差异。
Figure 4 — A and C — (Mining of Massive Datasets — pg 324)
让我们来看一下计算余弦的公式。首先,我们选择两个用户进行比较。作为一个例子,我们将比较用户 A 和 c。接下来,我们找到两个用户都提交了评级的所有电影。从我们的矩阵中可以看到,这恰好是两部电影:TW 和 SW1。然后,我们将每个用户的电影评分相乘,并将乘积相加,得到我们的分子。分母获取用户 A 的每个评分,对评分求平方,然后在求平方根之前将用户 A 的所有评分相加。它对用户 C 再次这样做,然后将两个结果相乘得到分母。我们可以看到用户 A 和 C 的余弦值为-0.559,这意味着他们对电影的品味相反。
Figure 5 — A and B — (Mining of Massive Datasets — pg 323)
让我们看看用户 A 是否更类似于用户 B 或用户 c。我们知道用户 A 和 c 之间的余弦。所以我们只是重复上面的步骤,但这次是在 A 和 B 之间。只有一部电影用户 A 和 B 都评级(HP 1)。因此,我们的分子只有一次乘法。我们看到用户 A 和 B 之间的余弦值为 0.092。记住,余弦值越高,用户越相似。基于此,我们可以有把握地得出这样的结论:用户 A 与用户 B 的相似度高于用户 c。如果我们将用户 A 与新用户 X 进行比较,得到余弦值为 0.099,则用户 A 与用户 X 的相似度甚至高于用户 B。
紫外线分解
最广泛接受的估计用户评级的形式之一是 UV 分解方法。为了展示这种方法是如何工作的,让我们看看下面图 6 中的效用矩阵。我们仍然可以假设行是各种用户,列是各种电影,但是这一次只缺少两个评级值。
Figure 6 (Mining of Massive Datasets — pg 328)
UV 分解的第一步是确定可以对我们的用户和电影进行类似分类的维度数量。在我们的例子中,我们将把我们的维数设置为 2,但这可以更大。然后,我们利用上面的矩阵,创建两个新矩阵:用户矩阵(U)和项目矩阵(V)。U 矩阵将是 5 乘 2(对于 5 个用户和 2 个维度),而 V 矩阵将是 2 乘 5(对于 2 个维度和 5 部电影)。这两个新矩阵(U 和 V)用随机数填充(现在我们用 1 填充),然后将它们相乘以创建另一个矩阵,其大小与原始效用矩阵相同(5x 5)。我们的目标是逐步改变 U 和 V 矩阵中的数字,使新矩阵尽可能接近原始效用矩阵。
Figure 7 (Mining of Massive Datasets — pg 329)
为了测量 U 和 V 的每次增量调整的成功,我们计算两个矩阵之间的 RMSE(均方根误差)。RMSE 越小,两个矩阵越接近(或越相似)。因此,我们希望找到插入 U 和 V 的最佳值,这将导致两个 5x 5 矩阵之间的最低 RMSE。参见下面的附录部分,详细了解 RMSE 的计算以及矩阵乘法的工作原理。
一旦我们找到了使 RMSE 最小化的 U 和 V 矩阵的值的组合,我们就可以找到原始效用矩阵中缺失评级的估计值。
摘要
Leskovec、Rajaraman 和 Ullman 涵盖的内容比上面讨论的更多,但是我想涵盖推荐系统的三个主要主题。基于内容的推荐系统只关注项目间的相似性,而协同推荐系统主要关注用户间的相似性。UV 分解是一种很好的方法,它使用 U 和 V 矩阵来寻找矩阵中缺失值的最佳估计值。
附录
矩阵乘法
在进行 RMSE 计算之前,让我们先来看看矩阵乘法是如何工作的。当我们将 U (5 x 2)乘以 V (2 x 5)时,实际上发生了什么?我们如何得到填充了 2 的 5×5 矩阵呢?
首先,矩阵乘法的顺序很重要。第一矩阵中列的数量必须等于第二矩阵中行的数量。在我们的例子中,U 有 2 列,V 有 2 行,所以我们很好。下一个技巧是,输出矩阵将具有与第一个矩阵相同数量的行,以及与第二个矩阵相同数量的列。在我们的例子中,U 有 5 行,V 有 5 列,所以得到的矩阵是 5 乘 5。
现在,我们如何填充 5x 5 矩阵?让我们举一个不同的例子,这将使解释矩阵乘法更容易,这里是我们的 U 和 V 矩阵:
Figure 8
为了计算 5 乘 5 矩阵的左上值,我们取 U (3)的左上值,并将其乘以 V (5)的左上值。然后我们取 U (4)的右上值,再乘以 V (7)的左下值。所以公式看起来是:(3 x 5) + (4 x 7) = 43 。这是我们的矩阵:
Figure 9
为了填充 5 乘 5 矩阵的第一行,我们继续使用 U 矩阵的第一行,但是对于 V 矩阵,我们每次移动一列。所以 43 右边的数字将是:(3 x 8) + (4 x 4) = 40 ,以此类推。这又是我们的矩阵:
Figure 10
为了填充行,我们重复上面的过程,但是我们向下移动 U 行。所以 43 以下的值会是:(2 x 5) + (8 x 7) = 66 。40 以下的值将是(2 x 8) + (8 x 4) = 48 ,以此类推。这是我们 5x 5 矩阵的最终结果:
Figure 11
RMSE 计算
简单回顾一下,RMSE 用于 UV 分解,以比较原始矩阵(具有实际用户评级)和新计算的矩阵(通过计算 U x V)之间的差异大小。下面是初始设置的样子:
Figure 12 (Mining of Massive Datasets — pg 328–329)
问题是,我们如何衡量这些矩阵有多相似?我们用 RMSE 做这个。如果我们想计算上述两个矩阵之间的 RMSE,第一步是从原始矩阵中减去计算矩阵的每个值。结果看起来像这样:
Figure 13
我们在这里所做的只是从我们的原始矩阵中减去我们计算出的矩阵(2s 的矩阵)中的值。所以左上角的 3 是 5 减 2 得来的。下一步是对这个新矩阵中的每个值求平方,得到以下结果:
Figure 14
一旦我们对矩阵中的每个值进行平方,我们就将每一行加在一起(例如,我们将对 9 + 0 + 4 + 4 + 1 求和得到 18,依此类推。结果如下所示:
Figure 15
步骤的最终组合是:1)对这个 5 乘 1 矩阵中的所有值求和,2)除以从我们的原始效用矩阵提供的评级总数(在我们的情况下,这将是 5×5-2,即 23,因为我们的原始效用矩阵中有两个空白),3)取这个结果的平方根,该值就是 RMSE。因此,这是我们示例的最后 3 个步骤的视觉效果:
Figure 16 (23 = 5 x 5 - 2)
3.26 的平方根是 1.81,所以我们原来的效用矩阵和 2s 的矩阵之间的 RMSE 是 1.81 。
引用的作品
Jure Leskovec,Anand Rajaraman,Jeffrey D. Ullman。海量数据集的挖掘。2014.【http://infolab.stanford.edu/~ullman/mmds/book.pdf