Numpy 中从零开始的多元线性回归
线性回归可能是最简单的“机器学习”算法。我打赌你已经使用过很多次了,可能是通过 Scikit-Learn 或者任何其他为你提供开箱即用解决方案的库。
Photo by Benjamin Davies on Unsplash
但是你有没有问过自己: 模型实际上是如何在幕后工作的?
当然,在简单线性回归的情况下(只有一个特征),你可以用一个简单的公式计算斜率和截距系数,但是这些公式不能转移到多元回归。如果你对简单线性回归一无所知,可以看看这篇文章:
机器学习不必复杂——如果用简单的术语解释的话。
towardsdatascience.com](/simple-linear-regression-from-scratch-in-numpy-871335e14b7a)
今天,我将只关注多元回归,并向您展示如何计算截距和尽可能多的线性代数斜率系数。会有一点数学,但没有手工实现。你应该熟悉像矩阵乘法、矩阵求逆和矩阵转置这样的术语。
如果这些听起来像科幻小说,不要害怕,我再一次为你报道:
学习数据科学的基本线性代数技能—第 1/2 部分
towardsdatascience.com](/linear-algebra-essentials-with-numpy-part-1-af4a867ac5ca)
在那篇文章的底部有一个到第二部分的链接,第二部分介绍了矩阵的一些基本概念。现在让我们快速进入这篇文章的结构:
- 数学落后
- 进口
- 类别定义
- 声明助手函数
- 声明 fit() 函数
- 声明 预测() 函数
- 做预测
- 结论
我知道有很多事情要谈。我会尽量让它简短,希望你能在 10 分钟内看完整篇文章。
好吧,我们开始吧!
数学落后
正如我所说的,会有一些数学。但这并没有你想象的那么复杂。你会有你的特征( X )和目标( y )。这是如何表达模型的:
其中 y 为目标变量的向量, X 为特征矩阵, beta 为你要估计的参数向量,ε为误差项。从数据集中,您需要将特征( X )从目标(【y】)中分离出来,并且还需要添加一个矢量,用于截距(或偏差)项的到 X 。
完成后,您可以通过以下公式获得系数:
你现在可以看到,你需要了解什么是转置,什么是逆,以及如何乘矩阵。好的一面是,你不会手动操作,因为数字已经覆盖了你。
说到数学就差不多了。如果你敢,可以更深入地研究,但这对于本文的完成是不必要的。你现在可以进入下一部分了。
进口
我已经答应你纯 Numpy 实现了对吗? 好吧,你也可以使用 Pandas ,但是只能从 CSV 文件中读取数据,其他的都可以用 Numpy 来完成。
我还导入了 警告 模块,这样笔记本就保持干净了:
现在让我们来看看波士顿住房数据:
这就是导入的大部分内容,接下来让我们做一些编码。
类别定义
我决定用 OOP ( 面向对象编程 )风格实现多元回归(普通最小二乘回归)。
如果你不喜欢 OOP,你可以跳过这一部分,跳到下一部分,在自己的单元格中声明每个函数,但是我建议坚持 OOP 风格。首先,让我们声明一个新类,ordinallyeastsquares:
它还没有做任何事情。现在我们将只声明 init 方法,其余的将在下面的章节中介绍。
我希望用户能够看到回归模型的系数,所以下面是解决这个问题的方法:
关于 init 方法就到此为止,你现在可以继续了。
声明助手函数
如果你花一点时间思考你的模型应该自动为用户做什么,你可能会得到两件事情的列表(或更多):
- 如果只有一个特征,则对特征进行整形( X )
- 将 1 的向量连接到特征矩阵
如果你不这样做,你的模型就会失败。没人喜欢那样。
第一个辅助函数非常简单,你只需要将 X 重塑成任何二维图形:
对于第二个辅助函数,您需要一个向量,其元素数量与您的特征矩阵的一列相同。使用 numpy 你可以生成这个向量并连接它:
如果你想知道函数名前的下划线是什么,这就是在 Python 中声明一个私有方法的方法。 怪异吧?
然而,这几乎是目前的一切。
声明 fit()函数
这是你模型的核心。 fit() 函数将负责训练模型并进行整形和拼接操作(调用之前声明的辅助函数)。
如果 X 是一维的,就要进行整形。然后,二维表示应该与一的向量连接起来。
最后,您可以使用上面讨论的公式来获得系数。请注意我是如何将它们设置为 自系数 的,因为我希望最终用户可以访问它们:
只需再完成一项功能,您就可以开始了!
声明 predict()函数
与前一个一样, 预测() 功能也将是最终用户所必需的。它将用于验证模型并做出新的预测。
让我们深入探究其背后的逻辑。本质上,您希望用户输入被格式化为列表。第一个系数代表截距或偏差项,所有其他系数需要乘以各自的值×。所以想法是同时迭代 new X 和所有系数(不是截距项)并将它们相乘,然后根据结果增加预测:
挺整齐的吧? 好了,事情就是这样,你现在可以用这个类来做一个实例,然后再来做预测。
我们来看看怎么做。
做预测
在本文的前面,我们加载了波士顿住房数据集。现在该构造特征矩阵和目标向量了——或者说白了就是 X 和 y :
您可以像往常一样在这里进行训练测试分割,但是我决定不这样做,只是为了保持文章简洁。创建一个ordinallyeastsquares的实例,并使 X 和 y 符合它——就像您对Scikit-Learn:l
训练结束了。您可以像这样访问系数:
甜蜜吧? 假设你要对第一行 X 做一个预测:
一切正常。或者如果您想对 X 中的每一行进行预测:
是的,一切看起来都很好。你现在可以去计算一些指标,比如 MSE ,但这不是本文的重点。
在你离开之前
尝试手工实现这个普通的最小二乘回归可能是个好主意。我是说用笔和纸。但不是用这个数据集,定义一两个特征和两三个观察值,并尝试手工计算。
这并不难,但是一旦完成,你会对为什么一切都正常运转更有信心。谢天谢地,后面的线性代数概念很简单,可以很快学会。然后,您可以使用 Python 来验证结果。
我希望一切都尽可能的干净,但是如果你有不明白的地方,请随时联系我。
喜欢这篇文章吗?成为 中等会员 继续无限制的学习。如果你使用下面的链接,我会收到你的一部分会员费,不需要你额外付费。
[## 通过我的推荐链接加入 Medium-Dario rade ci
作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…
medium.com](https://medium.com/@radecicdario/membership)
机器学习完全初学者指南:4 行代码中的多元线性回归!
征服多元线性回归的基础(和向后消除!)并用你的数据预测未来!
Photo by PublicDomainPictures via Pixabay
能够预测未来真是太棒了。
你可能想根据你碰巧掌握的其他信息来预测一只股票的表现。
这可能有助于你了解你洗澡的频率和你养了多少只猫与你的寿命有关。
你可能想弄清楚一个男人和另一个男人之间是否有关系。)一天给他妈打三次以上电话,2。)称另一个男人为“老弟”,3。)从未自己洗衣服,离婚率高于平均水平。
多元线性回归可能适合你!
GIF via GIPHY
多元线性回归很有趣,因为它着眼于一堆信息之间的关系。除了查看一个事物如何与另一个事物相关(简单的线性回归),你还可以查看许多不同事物与你想要预测的事物之间的关系。
线性回归模型是数据科学中经常使用的统计模型。这也是机器学习的基本组成部分之一!多元线性回归(MLR/多元回归)是一种统计技术。它可以使用几个变量来预测不同变量的结果。多元回归的目标是模拟自变量和因变量之间的线性关系。它着眼于多个自变量与一个因变量之间的关系。
我假设你对简单线性回归有所了解。如果你不知道,看看这篇关于构建简单线性回归的文章。它会给你一个快速(有趣)的基本步骤。
一个清晰而全面的蓝图,绝对适合任何想要构建简单机器学习模型的人
towardsdatascience.com](/simple-linear-regression-in-four-lines-of-code-d690fe4dba84)
简单线性回归是当你有一个自变量和一个因变量时可以使用的。多元线性回归就是你有一堆不同的自变量的时候可以用的!
多元回归分析有三个主要用途。
- 你可以看看自变量对因变量的影响强度。
- 你可以用它来问如果自变量改变,因变量会改变多少。
- 你也可以用它来预测趋势和未来值。
让我们做那一个!
Image by RondellMelling via Pixabay
我们将保持事情超级简单,以便多元线性回归作为一个整体是有意义的。我想让你知道在现实世界中事情会比这复杂得多。
我该如何开始?
就本文的目的而言,你现在是在为一位风险投资家工作。
恭喜你!
GIF via GIPHY
事情是这样的:你面前有一个包含 50 家公司信息的数据集。您有五列,其中包含这些公司在管理、研发(R&D)和营销方面的支出,它们在各州的位置,以及它们最近一年的利润。这个数据集是匿名的,这意味着我们不知道这些公司的名称或任何其他识别信息。
你被雇来分析这些信息并创建一个模型。你需要告诉雇佣你的人,未来投资什么样的公司最有意义。简单来说,假设你的雇主想根据去年的利润做出这个决定。这意味着利润列是您的因变量。其他列是自变量。
所以你想根据你所拥有的其他类别的信息来了解因变量(利润)。
雇你的人不想投资这些特定的公司。他想用这个数据集中的信息作为样本。这个样本将帮助他了解,基于同样的信息,他所关注的公司中,哪一家未来会表现得更好。
他想投资那些在 R&D 花很多钱的公司吗?营销?他想投资伊利诺伊州的公司吗?你需要帮助他建立一套指导方针。你要帮助他能够说出这样的话,“我对一家总部位于纽约的公司感兴趣,这家公司在管理费用上花费很少,但在研发上花费很多。”
你要想出一个模型,让他能够评估他想在哪里投资,投资哪些公司,以实现利润最大化。
GIF via GIPHY
线性回归对相关性很有用,但是请记住相关性和因果关系不是一回事!你不是说一件事导致另一件事,你是在发现哪些自变量与因变量密切相关。
有一些假设是绝对正确的:
- 因变量和自变量之间存在线性关系。
- 自变量之间的相关性不是很高。
- 你对因变量的观察是独立随机选择的。
- 回归残差呈正态分布。
在继续构建模型之前,您需要检查这些假设是否正确。我们完全跳过了这一步。确保如果你在现实世界中这样做,你不是盲目地跟随这个教程。在构建回归模型时,这些假设必须是正确的!
虚拟变量
如果您不熟悉虚拟变量的概念,请查看这篇关于数据清理和预处理的文章。它有一些简单的代码,我们可以继续复制并粘贴到这里。
如何在几分钟内为机器学习模型成功准备数据
towardsdatascience.com](/the-complete-beginners-guide-to-data-cleaning-and-preprocessing-2070b7d4c6d)
所以我们已经决定“利润”是我们的因变量( y ,其他是我们的自变量( X )。我们也决定了我们想要的是一个线性回归模型。那一栏国家呢?“状态”是一个分类变量,而不是一个数字变量。我们需要自变量是数字,而不是单词。我们该怎么办?
让我们创建一个虚拟变量!
如果您查看 locations 列中的信息,您可能会看到所有被检查的公司都位于两个州。出于解释的目的,假设我们所有的公司都位于纽约或明尼苏达州。这意味着我们要把这一列信息变成两列 1 和 0。(如果你想了解更多关于我们为什么这样做的信息,请查看那篇关于简单线性回归的文章。它解释了为什么这是整理数据的最佳方式。)
那么我们如何填充这些列呢?基本上,我们将把每个状态转换成它自己的列。如果一家公司位于纽约,它将在“纽约”列中有一个 1 ,在“明尼苏达州”列中有一个 0 。如果您使用更多的州,则在纽约列中有一个 1,例如,在“加利福尼亚”列中有一个 0,在“伊利诺伊”列中有一个 0,在阿肯色州列中有一个 0,依此类推。我们将不再使用原来的“位置”栏,因为我们不再需要它了!
这些 1 和 0 基本上就像一个电灯开关。1 表示“开”或“是”,0 表示“关”或“否”
小心虚拟变量陷阱
你永远不会想同时包含两个变量。
这是为什么呢?
你会复制一个变量。第一个变量(d1)始终等于 1 减去第二个变量(d2)。( d1 = 1-d2 )当一个变量预测另一个变量时,称为多重共线性。因此,模型将无法区分 d1 的结果和 d2 的结果。你不能同时拥有常量和两个虚拟变量。如果你有九个变量,包括其中的八个。(如果你有两组虚拟变量,那么你必须对每一组都这样做。)
P 值是多少?
你会想要熟悉 P 值的概念。这肯定会被提出来。
P 值是在零假设为真的情况下,获得与我们一样(或比我们更极端)的样本的概率。
它给你的样品的古怪程度一个值。如果你有一个大的 P 值,那么你可能不会改变对零假设的看法。一个大的值意味着如果假设是真的,得到像你这样的样本一点也不奇怪。随着 P 值变小,你可能应该开始问自己一些问题了。你可能会改变主意,甚至拒绝这个假设。
零假设是指这里正在试验的主张(假设)的官方说法。这是默认的位置,在这里被测试的组之间没有关联。在每个实验中,你都在被测试的群体中寻找效果。不幸的是,各组之间总有可能没有影响(或没有差异)。这种差异的缺乏被称为零假设。
这就像你在做一个不起作用的药物试验。在那次试验中,服用药物的那组人和其他人之间没有区别。差异将为零。
你总是假设零假设是正确的,直到你有证据证明它不是。
让我们继续前进!
我们需要弄清楚哪些栏目我们想保留,哪些栏目我们想放弃。如果你只是在你的模型中加入一些东西,它就不会是一个好的模型。肯定不会靠谱!(此外,在一天结束时,你需要能够向雇佣你创建这个东西的人解释你的模型。你只会想要解释那些实际上能预测一些事情的变量!)
建立多元线性回归模型基本上有五种方法。
- 抛开一切,抱最好的希望
- 反向消除
- 预选
- 双向消除
- 分数比较
你几乎肯定也听说过逐步回归。逐步回归最常用作双向消除的另一种说法(方法 4)。有时当人们使用这个短语时,他们指的是方法 2、3 和 4 的组合。(这也是双向消去法背后的思想。)
方法一(把所有东西都夹进去):好的。这不是这种方法的正式名称(但应该是)。偶尔你需要建立一个模型,你只需要把所有的变量都放进去。你可能有某种先验知识。你可能需要使用一个特定的框架。你可能已经被某个坚持要你这么做的人雇佣了。你可能想为逆向淘汰做准备。这是一个真实的选择,所以我把它包括在这里。
方法二(逆向淘汰):这有几个基本步骤。
- 首先,您需要设置数据将保留在模型中的显著性水平。例如,您可能希望将显著性水平设置为 5% (SL = 0.05)。这很重要,可能会有真正的影响,所以请考虑一下。
- 接下来,您将使用所有可能的预测值来拟合整个模型。
- 您将考虑具有最高 P 值的预测值。如果你的 P 值大于你的显著性水平,你将进入第四步,否则,你就完了!
- 移除具有最高 P 值预测值。
- 在没有预测变量的情况下拟合模型。如果只是去掉变量,就需要重新改装和重建模型。系数和常数将会不同。当你移除一个,它会影响其他的。
- 回到第 3 步,从头开始,继续这样做,直到你达到一个点,甚至最高的 P 值是< SL. Now your model is ready. All of the variables that are left are less than the significance level.
(After we go through these concepts, I’ll walk you through an example of backward elimination so you can see it in action! It’s definitely confusing, but if you really look at what’s going on, you’ll get the hang of it.)
方法 3 (正向选择):这比仅仅反转反向淘汰要复杂得多。
- 选择你的显著性水平(SL = 0.05)。
- 拟合所有可能的简单回归模型,并选择 P 值最低的模型。
- 保留这个变量,并在现有的基础上增加一个额外的预测因子来拟合所有可能的模型。如果我们选择了一个简单的一元线性回归,现在我们将选择所有的二元线性回归。这意味着所有可能的两变量线性回归。
- 找到具有最低 P 值的预测值。如果 P < Sl, go back to step 3. Otherwise, you’re done!
We can stop when P
方法三(双向消去):这种方法结合了前面两种!
- 选择要输入的显著性水平和要保持的显著性水平(SLENTER = 0.05,SLSTAY = 0.05)。
- 执行向前选择的下一步,添加新变量。您需要让您的 P 值小于 SLENTER。
- 现在执行所有的反向消除步骤。变量的 P 值必须小于 SLSTAY 才能保持不变。
- 现在回到第二步,然后前进到第三步,依此类推,直到没有新的变量可以进入,也没有新的变量可以退出。
你完了!
方法 4 (分数比较):在这里,你将会看到所有可能的方法。您将看到所有可能方法的分数对比。这绝对是最耗费资源的做法!
- 选择拟合优度标准(例如,赤池标准)
- 构建所有可能的回归模型
- 选择具有最佳标准的一个
有趣的事实:如果你有 10 列数据,你会得到 1023 个模型。如果你打算走这条路,你最好准备好承诺!
嗯,什么?
如果你刚刚开始学习机器学习、统计学或数据科学,这些看起来会是数量惊人的代码。不是的!
你需要用机器学习模型做的很多事情都已经准备好了,有了令人惊叹的库。你需要做一些困难的事情,决定哪些信息是重要的,以及你想使用什么样的模型。解释结果并能够传达您所构建的内容也取决于您。然而,代码本身是非常可行的。
GIF via GIPHY
让我给你看看!
逆向排除法是开始时最快也是最好的方法,所以在我们建立了快速简单的多元线性回归模型后,这就是我要带你经历的。
首先,让我们准备数据集。假设我们有一个名为“startups.csv”的. csv 文件,其中包含了我们之前讨论过的信息。我们假设它有 50 个公司和列,分别用于 R&D 支出、管理支出、营销支出、公司所在的州(比如纽约州、明尼苏达州和加利福尼亚州),还有一列用于去年的利润。
最好立即导入您的库。
# Importing the libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
现在我们可以复制并粘贴 t hat 数据清理和准备文章中的代码了!我们肯定要将数据集的名称改为我们的名称。我将它命名为“startups.csv”,我们还将调整几个其他的小细节。利润(y)仍然是我们的最后一列,所以我们将继续用[:,:-1]删除它。我们将做一点调整,用[:,4]来抓取我们的自变量。现在我们有一个因变量(y)的向量和一个自变量矩阵,其中包含除利润(X)之外的所有内容。我们想看看两者之间是否存在线性依赖关系!
dataset = pd.read_csv('startups.csv')
X = dataset.iloc[:, :-1].values
y = dataset.iloc[:, 4].values
现在我们需要对分类变量进行编码。我们可以使用标签编码器和一个热编码器来创建虚拟变量。(我们也可以从另一篇文章中复制并粘贴这篇文章!确保你获取了正确的信息,并且没有对因变量进行编码。)您将再次更改点[:,3]和[:,3]中列的索引,并替换一个热编码器中的索引[3]。
from sklearn.preprocessing import LabelEncoder, OneHotEncoder
labelencoder = LabelEncoder()
X[:, 3] = labelencoder.fit_transform(X[:, 3])
onehotencoder = OneHotEncoder(categorical_features = [3])
X = onehotencoder.fit_transform(X).toarray()
你已经准备好了!我们的一列信息现在是三列,每一列对应一个州!
如何避免虚拟变量陷阱?在我们的图书馆里,你实际上不需要这么做!我们选择使用的库已经为您处理好了。但是,如果您想要或需要运行该代码,这很简单!您可以在对数据进行编码后用一行代码来完成。
X=X[:, 1:]
那有什么用?它从 x 中移除第一列。将 1 放在那里意味着我们想要将从索引 1 开始的所有列移动到末尾。你不会走第一列。对于某些库,您需要手动删除一列,以确保数据集不包含冗余。
现在,让我们拆分我们的培训和测试数据。最常见的分割是 80/20 分割,这意味着 80%的数据将用于训练我们的模型,20%将用于测试它。我们在这里做吧!
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
特征缩放呢?
这里我们不需要做特性缩放!图书馆会帮我们处理的。
Photo by Gift Habeshaw on Unsplash
多元线性回归时间!
我们将从 Scikit-Learn 导入线性回归。(这有点道理吧?)
from sklearn.linear_model import LinearRegression
现在我们将介绍我们的回归变量。我们将创建一个 LinearRegression 类的对象,并使该对象适合我们的训练集。我们想把这个应用到我们的 X 列车和 y 列车上。
regressor = LinearRegression()
regressor.fit(X_train, y_train)
现在让我们测试我们的多元线性回归器的性能!
(我们不会在这里绘制图表,因为我们需要五个维度来完成。如果你对用一个简单的线性回归器绘制图表感兴趣,看看这篇关于构建一个简单的线性回归器的文章。)
我们将创建预测向量(y_pred)。我们可以使用带有预测方法的回归量来预测测试集(X_test)的观察值。
y_pred = regressor.predict(X_test)
就是这样!四行代码,你已经建立了一个多元线性回归!
GIF via GIPHY
现在可以看到十个预测利润了!你可以随时用简单的print(y_pred)
打印它们。我们可以很容易地通过看一看预测,然后将它们与实际结果进行比较。如果你看一看,你会发现有些非常准确,其余的非常好。干得好!
我们的因变量和自变量之间肯定存在某种线性相关性。我们可以清楚地看到两者之间有很强的线性关系。
恭喜你!!您现在知道如何用 Python 制作多元线性回归器了!
想继续吗?
事情将变得更具挑战性!
如果一些变量对我们的因变量有很大的影响,而一些在统计上无关紧要,那该怎么办?我们肯定能找出哪些是对因变量影响最大的变量。我们希望找到一组变量,它们都有明确的影响,积极的或消极的。
还是用向后淘汰吧!
我们需要为逆向淘汰准备一些特定的东西。我们需要一个库统计模型,所以让我们导入 statsmodels.formula.api。这需要不断重新键入,时间有点长,所以我们将使用 sm 创建一个快捷方式。
import statsmodels.formula.api as sm
我们需要在自变量的特征矩阵中添加一列 1,因为它与常数一起工作。(我们的模型需要考虑我们的常数 b0。在大多数库中都包含了它,但是在我们使用的统计模型中没有。我们将添加一列 1,这样我们的统计模型将正确理解公式。)
这开始很简单。我们会用。追加是因为我们想追加。
(爱蟒❤️)
我们有特征 x 的矩阵,值参数对我们来说是完美的,因为它是一个数组。我们将输入一个 50 行 1 列的矩阵,里面有 1。我们可以用 Numpy 的 np.ones 创建它,我们需要指定我们想要的行数和列数(50,1)。我们需要将数组转换成整数类型来实现这一点,所以我们将使用。astype(int)。然后我们需要决定是添加一行还是一列(line = 0,column = 1),所以我们说 axis = 1 表示一列!
我们希望该列位于数据集的开头。我们该怎么办?让我们把矩阵 X 加到 50 个一的列上,而不是反过来。我们可以用值= X 来实现。
X = np.append(arr = np.ones((50, 1)).astype(int), values = X, axis = 1)
我们开始吧!
我们想创建一个新的最优特征矩阵(X_opt)。这些特征是具有统计学意义的特征。对利润有很大影响的那些。这将是包含对利润有重大影响的最佳特性团队的矩阵。
我们需要初始化它。我们可以把统计意义不大的变量逐一剔除。我们将通过在每一步移除索引来做到这一点。首先获取 X 中所有列的索引,用逗号分隔[0,1,2,3,4,5]。
如果你回头看看前面的方法,你会发现我们首先需要选择我们的显著性水平,这是我们前面谈到的。然后我们需要符合模型!
我们不会用我们造的回归器。我们正在使用一个新的库,所以现在我们需要一个新的适合我们未来最优矩阵的库。我们将创建一个新的回归变量(上一个来自线性回归库)。我们的新类将是普通最小二乘法(OLS)。我们需要调用这个类并指定一些参数。(你可以在这里查阅官方文档。)对于我们的参数,我们需要一个 endog(我们的因变量)和一个 exog(我们的 X_opt,它只是我们的带有截距的特征(X)矩阵,默认情况下不包括它)。为了适应它,我们将只使用一个. fit()!
X_opt = X[:, [0, 1, 2, 3, 4, 5]]
regressor_OLS = sm.OLS(endog = y, exog = X_opt).fit()
现在我们已经初始化了 X_opt!
现在让我们来看看我们的 P 值!我们如何寻找具有最高 P 值的预测值?我们将获取回归对象并调用函数。总结()。
regressor_OLS.summary()
现在我们可以看到一个表格,里面有一些关于我们模型的非常有用的信息!我们可以看到调整后的 R 平方值和 P 值。p 值越低,自变量相对于因变量就越重要。在这里,我们寻找最高的一个。那很容易看出来。
现在让我们来移除它!
我们可以从上面复制并粘贴我们的代码,并删除索引 2。看起来会像这样:
X_opt = X[:, [0, 1, 3, 4, 5]]
regressor_OLS = sm.OLS(endog = y, exog = X_opt).fit()
regressor_OLS.summary()
只要继续下去,直到你没有任何 P 值高于你选择的 SL 值。请记住,您总是要查看原始矩阵,以便选择正确的索引!您使用的是原始矩阵(X)中的列,而不是 X_opt 中的列。
你可能会得到一个 P 值,非常接近你选择的 SL 值。例如,我们选择 0.050,这里是 0.060。
这是一个困难的情况,因为你选择的值可以是任何值。如果您想完全遵循您的框架,您将需要删除该索引。但是还有其他指标可以帮助我们更好地理解我们是否想要这样做。我们可以添加其他指标,比如一个标准,来帮助我们决定我们是否真的想做这个选择。这里的摘要中也有很多信息,比如 R 平方值,可以帮助我们做出决定。
假设我们逆向剔除,直到最后,我们只剩下 R&D 支出栏的指数。
X_opt = X[:, [0, 1, 3, 4, 5]]
regressor_OLS = sm.OLS(endog = y, exog = X_opt).fit()
regressor_OLS.summary()
X_opt = X[:, [0, 1, 3, 5]]
regressor_OLS = sm.OLS(endog = y, exog = X_opt).fit()
regressor_OLS.summary()
X_opt = X[:, [0, 3, 5]]
regressor_OLS = sm.OLS(endog = y, exog = X_opt).fit()
regressor_OLS.summary()
X_opt = X[:, [0, 3]]
regressor_OLS = sm.OLS(endog = y, exog = X_opt).fit()
regressor_OLS.summary()
如果我们一直小心地遵循我们的模型,这意味着我们现在知道 R&D 支出是我们因变量的一个强有力的预测器!这里的结论是,可以预测利润的影响最大的数据只由一个类别组成:R&D 支出!
你做到了!你用了多元线性回归和逆向淘汰!你发现观察 R&D 的支出会让你对一家公司的利润有最好的了解!
你太棒了!
GIF via GIPHY
和往常一样,如果你用这些信息做了什么很酷的事情,请在下面的回复中让人们知道,或者随时在 LinkedIn 上联系!
感谢阅读!
多元线性回归—使用数学和代码
Photo by 贝莉儿 DANIST on Unsplash
线性回归是预测模型的一种形式,广泛用于许多现实世界的应用中。许多关于线性回归的文章都是基于单个解释变量,并详细解释了最小化均方误差(MSE)以优化最佳拟合参数。在本文中,多个解释变量(自变量)被用来推导 MSE 函数,最后梯度下降技术被用来估计最佳拟合回归参数。具有三个自变量和一个因变量的示例数据集用于构建多元回归模型,在本文的后面部分,提供了 R-code 来对示例数据集进行建模。
多元回归模型
线性回归模型的方程是众所周知的,它表示为:
y = MX+c
其中 y 是模型的输出,称为响应变量, x 是自变量,也称为解释变量。 m 是回归线的斜率, c 表示截距。通常我们得到 x 和 y 的测量值,并尝试通过估计 m 和 c 的最优值来建立模型,以便我们可以通过给定 x 作为输入,使用该模型对y 进行未来预测。
实际上,我们处理的独立变量不止一个,在这种情况下,使用多个输入变量构建线性模型对于准确建模系统以实现更好的预测非常重要。因此,本文对多元回归分析进行了详细介绍。线性回归模型需要矩阵表示来表示多元回归模型,使其更加紧凑,同时便于计算模型参数。我相信读者对矩阵运算和线性代数有基本的了解。然而,在最后一节中,提供了回归分析中使用的矩阵规则,以更新读者的知识。
线性回归的代数形式
假设我们有以下数据显示一个班不同学生的分数。一年中有四次考试的分数,最后一栏是期末考试的分数。从数据中可以看出,期末考试的分数与前三次考试的成绩有某种关系。
这里考虑到前三次考试的分数与期末考试的分数线性相关,我们的第一次观察(表中第一行)的线性回归模型应该如下所示。
152 = a×73+b×80+c×75+d**
其中 a , b , c , d 为模型参数。
等式的右边是回归模型,该模型在使用适当的参数时应该产生等于 152 的输出。但是实际上没有一个模型可以完美地模仿 100%的现实。模型输出和真实观察之间总是存在误差。因此,正确的回归方程可以定义如下:
152 = a×73+b×80+c×75+d×1+E1
其中 e1 为首次观测的预测误差。类似地,对于数据表中的其他行,等式可以写成
185 = a×93+b×88+c×93+d×1E2**
180 = a×89+b×91+c×90+d×1+E3
196 = a×96+b×98+c×100+d×1+E4**
…………………………………………………
…………………………………………………
192 = a×96+b×93+c×95*+d×1+e25***
上述方程可以借助于下面提到的四个不同的矩阵来写。
使用上述四个矩阵,代数形式的线性回归方程可以写成:
Y = xβ+e
为了得到等式的右边,矩阵 X 是乘以向量,乘积加上误差向量 e 。众所周知,如果第一个矩阵的列数等于第二个矩阵的行数,则两个矩阵可以相乘。在这种情况下, X 有 4 列,有 4 行。**
重新排列术语,误差向量表示为:
e = Y - Xβ
现在,很明显,错误, e 是参数的函数,。在下一节中,推导矩阵形式的 MSE,并将其用作优化模型参数的目标函数。**
矩阵形式的 MSE
MSE 的计算方法是将所有观测值的 e 的平方和除以数据表中的观测值数量。数学上:
****
将方程中的 e 替换为 Y — Xβ ,MSE 改写为:
将上述等式展开如下:
上述等式用作成本函数(优化问题中的目标函数),需要最小化该函数以估计我们的回归模型中的最佳拟合参数。需要通过对参数向量求 MSE 函数的导数来估计梯度,并用于梯度下降优化。
MSE 的梯度
如上所述,梯度表示为:
其中, ∇ 是用于梯度的微分算子。使用矩阵。微分规则,我们得到以下方程。
上述矩阵被称为 雅可比矩阵 ,用于梯度下降优化以及学习率( lr )更新模型参数。
梯度下降法
梯度下降法更新模型参数的公式如下所示。
*****【βold】*是初始化的参数向量,在每次迭代中更新,在每次迭代结束时 βold 等同于 βnew 。 lr 是学习率,代表步长,有助于防止超过误差面的最低点。迭代过程继续,直到 MSE 值变小变平。
Illustration of gradient descent method. Source: http://www.claudiobellei.com/2018/01/06/backprop-word2vec/
示例数据
在本节中,使用示例数据集开发了一个多元回归模型。应用梯度下降法估计模型参数abc和 d 。矩阵的值 X 和 Y 从数据中已知,而 β 向量未知,需要估计。最初,计算MSE 和 MSE 的梯度,然后应用梯度下降法使 MSE 最小化。**
r 代码
读取数据并初始化β:
**dataLR <- read.csv("C:\\Users\\Niranjan\\Downloads\\mlr03.csv", header = T)
beta <- c(0,0,0,0) ## beta initialized
beta_T <- t(beta)X = matrix(NA,nrow(dataLR),ncol = 4)X[,1] <- dataLR$EXAM1
X[,2] <- dataLR$EXAM2
X[,3] <- dataLR$EXAM3
X[,4] <- 1XT <- t(X)
y <- as.vector(dataLR$FINAL)
yT <- t(y)**
计算 MSE 并更新β
**mse <- (1/nrow(dataLR))* (yT%*%y - 2 * beta_T%*%XT%*%y + beta_T%*%XT%*%X%*%beta)
betanew <- beta - (lr *(2/nrow(dataLR)) * (XT%*%X%*%beta - XT%*%y))**
参数估计的完整代码
**##multivariate linear regression
dataLR <- read.csv("C:\\Users\\Niranjan\\Downloads\\mlr03.csv", header = T)
beta <- c(0,0,0,0)
beta_T <- t(beta)X = matrix(NA,nrow(dataLR),ncol = 4)X[,1] <- dataLR$EXAM1
X[,2] <- dataLR$EXAM2
X[,3] <- dataLR$EXAM3
X[,4] <- 1XT <- t(X)
y <- as.vector(dataLR$FINAL)
yT <- t(y)iteration <- 1
lr = 0.00001msef = NULL
while (iteration < 10) {
mse <- (1/nrow(dataLR))* (yT%*%y - 2 * beta_T%*%XT%*%y + beta_T%*%XT%*%X%*%beta)
betanew <- beta - (lr *(2/nrow(dataLR)) * (XT%*%X%*%beta - XT%*%y))
msef <- rbind(msef,mse)
beta <- betanew
beta_T <- t(betanew)
iteration <- iteration + 1
}plot(1:length(msef), msef, type = "l", lwd = 2, col = 'red', xlab = 'Iterations', ylab = 'MSE')
grid(nx = 10, ny = 10)print(list(a = beta[1],b = beta[2], c = beta[3], d = beta[4]))**
标绘输出的代码
**library(plot3D)
ymod <- X%*%beta
scatter3D(dataLR$EXAM1,dataLR$EXAM2,dataLR$EXAM3, colvar = ymod,
pch = 17, cex = 2,bty = "g",ticktype = "detailed",phi = 0,lwd=2.5, xlab = "Exam1", ylab = 'Exam2',zlab = 'Exam3')
scatter3D(dataLR$EXAM1,dataLR$EXAM2,dataLR$EXAM3, colvar = dataLR$FINAL,
pch = 16, cex = 2,bty = "g",ticktype = "detailed",phi = 0,lwd=2.5, xlab = "Exam1", ylab = 'Exam2',zlab = 'Exam3',add = T)plot(dataLR$FINAL, ymod, pch = 16, cex = 2, xlab = 'Data', ylab = 'Model')
lines(ymod,ymod, lwd = 4, col = "green", lty = 6)
grid(nx = 10, ny = 10)
legend("topleft",c('Model-Data Points','Best fit line'), lty = c(NA,6), lwd = c(NA,4), col = c("black","green"), pch = c(16,NA))**
输出
MSE 的值急剧减小,六次迭代后,它变得几乎平坦,如下图所示。相应的模型参数是最佳拟合值。
最小化MSE***😗**
MSE change with iterations
优化后的😗***
Optimized model parameters
将计算的最终分数与来自数据的最终分数进行比较。模型效率通过将模型输出与数据中的目标输出进行比较来可视化。决定系数估计为 0.978,以数值评估模型的性能。下图显示了模型和数据之间的比较,其中三个轴用于表示解释变量,如 示例 1、示例 2、示例 3 ,颜色方案用于显示输出变量,即最终得分。
模型输出与数据中目标的比较:
Visualization of model out and target in the data
Comparison between model output and target in the data
基本矩阵规则
通过 REST 对英特尔神经计算机棒进行多进程访问
用 Python 包装器扩展硬件限制
单一过程问题
我开始在我的树莓派机器人上使用英特尔 NCS,这种升级有积极和消极的一面。
积极的一面是 NCS 能够用 Tensorflow 和 OpenCV 替换所有运行在 Raspberry 上的网络。
性能的提高激发了新的目标,但是很快我发现 NCS 不能在两个不同的过程中使用。
E: [ncAPI] [ 926029] resetAll:348 Failed to connect to stalled device, rc: X_LINK_ERROR
E: [ncAPI] [ 933282] ncDeviceOpen:672 Failed to find suitable device, rc: X_LINK_DEVICE_NOT_FOUND
在英特尔支持论坛上的搜索带来了一个类似的问题。
有一个关于供应商文档的参考,它说得很简单:
单个设备不能跨多个进程共享。
这意味着有必要建立一个变通办法。
NCS 服务
所以这个想法是将 NCS 的工作委托给一个专门的服务。
该服务应该提供 REST API 包装 NCS 函数。
NCS API
基本用例非常简单:
- 加载模型
- 进行推理
- 列出加载的模型
- 获取模型的特征
最有趣的场景是推理运行。
通常它返回整个模型的输出——多维张量。
原始张量在某些情况下是有用的,但通常我们需要更具体的数据。
我使用 NCS 对图像进行分类,检测物体和分割道路。
因此,一般用例“运行推理”被扩展为:
- 分类
- 发现
- 段
REST 接口
- POST: /load —加载模型
- POST: /unload/$model —删除模型(从服务内存中,无法从设备中删除)
- GET: /list —列出模型
- GET:/input/shape/$ model-获取模型的形状
- POST: /inference/file/$model —使用来自内存的数据运行推理
- POST: /inference/path/$model —使用文件系统中的数据运行推理
- POST: /classify/file/$model
- POST: /classify/path/$model
- POST: /detect/file/$model
- POST: /detect/path/$model
- POST: /segment/file/$model
- POST: /segment/path/$model
内存与文件系统
有两种方法可以传递图像——通过内存(如果已经有了,可能会有用)或文件系统路径。
当 NCS 服务和客户端运行在同一个 Raspberry Pi 上时,第二种方法会更好。
有一个简短的基准确认(1000 次尝试):
内存:87.5 秒
文件:63.3150 秒
分类
方法/分类将原始推理输出转换成一组对(类,分数):
def get_class_tensor(data):
ret = []
thr = 0.01
while(True):
cls = np.argmax(data)
if data[cls] < thr:
break;
logging.debug(("Class", cls, "score", data[cls]))
c = {"class" : int(cls), "score" : int(100 * data[cls])}
data[cls] = 0
ret.append(c)
return retdef classify(model_id, img):
rc, out = run_inference(model_id, img)
if not rc:
return rc, out
return True, get_class_tensor(out)
侦查
输出检测张量包含一组(类别、概率、归一化坐标),看起来不太可读。
将其转换为简单的表示,同时删除最不可能的选项:
def get_detect_from_tensor(t, rows, cols):
score = int(100 * t[2])
cls = int(t[1])
left = int(t[3] * cols)
top = int(t[4] * rows)
right = int(t[5] * cols)
bottom = int(t[6] * rows)
return {"class" : cls, "score" : score, "x" : left, "y" : top, "w" : (right - left), "h" : (bottom - top)} def build_detection(data, thr, rows, cols):
T = {}
for t in data:
score = t[2]
if score > thr:
cls = int(t[1])
if cls not in T:
T[cls] = get_detect_from_tensor(t, rows, cols)
else:
a = T[cls]
if a["score"] < score:
T[cls] = get_detect_from_tensor(t, rows, cols)
return list(T.values())
分割
分段张量包含模型维度内分类的概率。
将其转换为类别掩码:
def segment(model_id, img):
rc, out = run_inference(model_id, img)
if not rc:
return rc, out
out = np.argmax(out, axis=0)
out = cv.resize(out,(img.shape[1], img.shape[0]), interpolation=cv.INTER_NEAREST)
return True, out
结论
我根据自己的需要开发了在 Raspberry Pi 上运行的服务。
但是没有什么可以阻止在任何其他平台上运行 Python、OpenVino 和 NCS。
链接
【Raspbian 官方 OpenVino 安装指南
解释多协议标签交换(MPLS)
这个博客分为两个部分,第一部分我们将了解 MPLS 到底是什么,第二部分我们将看到如何使用 Golang 制作 MPLS 数据包。
多协议标签交换(MPLS)并不是一项新技术。已经好几年了。你们中的许多人一定熟悉数据是如何以网络数据包的形式在网络中从一个地方传输到另一个地方的。这些数据包包含源 IP 地址和目的 IP 地址。一个包要通过中间的几个路由器,这些路由器包含路由表,它为包提供下一跳信息,并跟随它最终到达目的地。这就是 IP 转发的工作方式。这是第 3 层协议。
MPLS 转发不同于 IP 转发,因为转发不是基于 IP 地址,而是基于数据包上的标签,因此得名标签交换。它是多协议的,因为它支持多种协议,如互联网协议(IP)、异步传输模式(ATM)和帧中继网络协议。我们将在后面看到 MPLS 转发到底是如何完成的。
如果你熟悉计算机网络,你一定知道 TCP/IP 模型有 5 层。MPLS 层位于模型的第 2 层和第 3 层之间,即数据链路层和网络层。这就是为什么它也被称为 2.5 层协议或“垫片”协议。
MPLS 报头是 32 位的。它包含以下信息:-
- 标签:标签字段为 20 位,因此标签可以取从 0 到 2^20–1 的值,或 1048575。但是,前 16 个标签值(即从 0 到 15)由于具有特殊含义,因此可免于正常使用。
- 实验(Exp): 这三个比特被保留作为实验比特。它们用于服务质量(QoS)。
- 栈底(BoS): 一个网络数据包可以有一个以上的 MPLS 标签,这些标签相互堆叠。为了确保哪个 MPLS 标签在栈底,我们有一个 1 比特的 BoS 字段。只有当特定标签位于堆栈底部时,该位才为高(即值 1),否则其值保持为 0。
- 生存时间(TTL): 后 8 位用于生存时间(TTL)。该 TTL 与 IP 报头中的 TTL 具有相同的功能。它的值只是在每一跳减 1。TTL 的作用是当数据包的值变为零时,通过丢弃数据包来避免数据包滞留在网络中。
现在我们将看到典型的 MPLS 网络是什么样子的
MPLS 网络包含标签交换路由器(LSR)。这些路由器能够理解 MPLS 标签,并能够接收和发送带标签的数据包。
MPLS 网络中存在三种标签交换路由器
- 入口 LSR: 这些路由器出现在 MPLS 网络的起点。他们的工作是接收未标记的 IP 数据包,并将标签放在上面。
- 出口 LSR: 这些路由器位于 MPLS 网络的末端。他们的工作是从传入的数据包中弹出标签,并将数据包作为 IP 数据包转发。
- 中间 LSR: 这些路由器存在于上述两个路由器之间。他们的工作是接收带标签的数据包,交换数据包的标签,并将其转发到下一跳。它们负责数据包的 MPLS 转发。
入口和出口也称为边缘路由器
因此,在任何特定的路由器上,标签的推送、弹出或交换这三个步骤中的任何一个都会发生。
标签交换路径(LSP)
标签交换路径(LSP)可以定义为在 MPLS 网络中传输数据包的标签交换路由器(LSR)序列。基本上,LSP 是数据包在传输过程中采用的预定义路径。LSP 中的第一个 LSR 是入口 LSR,类似地,LSP 中的最后一个 LSR 是出口路由器,后面是中间的 LSR。
这里的主要收获是,在 IP 转发中,没有数据包必须遵循的固定路径,而在 MPLS 转发中,我们预定义了路径,即在数据包传输过程中必须遵循的 LSP。
MPLS 转发
因此,结合我们所学的上述概念,现在我们可以很容易地看到 MPLS 数据包是如何在网络中转发的。
当网络数据包进入 MPLS 网络时,入口路由器会在其顶部放置一个标签。该标签对应于分组需要遵循的特定路径,即 LSP。不同的 LSP 对应不同的标签栈。使用不同的协议来分发标签,例如标签分发协议(TDP)、标签分发协议(LDP)和资源预留协议(RSVP)。
与 IP 转发一样,每个路由器都包含一个路由表。类似地,在 MPLS 网络中,每个 LSR 都包含标签转发信息库(LFIB)。这个信息库引导 LSR 用其相应的输出标签交换标签,从而允许分组通过网络传输。这里的主要要点是,路由器只需要看到传入数据包顶部的标签,它不关心数据包内部的 IP 地址(源和目的地),从而允许通过网络进行更快的路由。
以下是 LFIB 中的信息示例
在 LSP 结束时,出口 LSR 弹出信息包的标签,信息包作为普通的 IP 信息包被路由。
这是 MPLS 转发如何发生的高级视图。要深入了解,您可以参考思科 MPLS 基础书籍
制作 MPLS 数据包
继续下一部分,在这里我们将看到如何使用 Golang 制作 MPLS 数据包。为什么是 Golang?因为它是高度可伸缩的,具有内置的并发性和对服务器端编程的强大支持,并且还有一组令人敬畏的库。我们将使用 GoPacket 库来制作这个包。
代码来了
代码是不言自明的,我们为 IP、UDP、有效负载、MPLS 和以太网创建了单独的层,并按照以下顺序将这些层堆叠在一起,然后返回创建的字节对象。
MPLS packet layer stack
如果我们执行上述代码,我们将获得以下输出
c8b302c0b91bc8b302c0b91b88470001114045000023000000000011b6c7010101010101010107d00bb8000f2b157061796c6f616400000000000000
这是数据包形成的输出,我们可以使用在线工具,如 https://hpd.gasmi.net/的或 Wireshark 来解码数据包。
解码上面的包给出了如下预期的结果。
全部代码也可以在我的 Github 库中找到
感谢阅读这篇文章。
更多这样的博客,你可以关注我,这样每当我有新的帖子时,你都会得到通知。
干杯!
还有,我们来连线一下 Twitter , Linkedin , Github 。
使用 Head API 在 TensorFlow 中进行多任务学习
多任务学习的自定义估计器介绍
人类学习的一个基本特征是我们同时学习许多事情。机器学习中的等价思想被称为多任务学习(MTL),,它在实践中变得越来越有用,特别是对于强化学习和自然语言处理。事实上,即使在标准的单任务情况下,也可以设计额外的辅助任务并将其包含在优化过程中以帮助学习。
这篇文章通过展示如何在图像分类基准中解决一个简单的多任务问题来介绍这个领域。重点是 TensorFlow 的一个实验组件,即 Head API ,它通过将神经网络的共享组件从特定任务的组件中分离出来,帮助设计 MTL 的定制估计器。在这个过程中,我们还将有机会讨论 TensorFlow 核心的其他特性,包括 tf.data、tf.image 和自定义估算器。
该教程的代码作为一个完全包含的 Colab 笔记本提供,请随意测试和实验!
内容一览
为了让教程更有趣,我们考虑一个现实的用例,通过重新实现 2014 年的一篇论文(的一部分):通过深度多任务学习进行面部标志检测。问题很简单:给我们一张面部图像,我们需要定位一系列的地标,即图像上的兴趣点(鼻子、左眼、嘴巴……),以及标签,包括人的年龄和性别。每个界标/标签构成图像上的一个单独的任务,并且这些任务是明显相关的(即,想象在知道右眼在哪里的情况下预测左眼的位置)。
Sample images from the dataset (source). The green dots are the landmarks, and each image is also associated with some additional labels, including age and gender.
我们将实现分为三部分:(I)加载图像(使用 tf.data 和TF . image);(ii)根据论文实现卷积网络(使用 TF 的定制估计器);(iii)添加具有头部 API 的 MTL 逻辑。很多东西要看,没时间浪费了!
步骤 0-加载数据集
下载数据集(链接)后,快速检查发现图像被分割在三个不同的文件夹中(AFLW、lfw_5590 和 net_7876)。通过不同的文本文件提供训练和测试分割,每行对应于图像和标签的路径:
The first image and labels from the training dataset. Blue numbers are image locations (from the top left), red numbers are classes (see below).
为简单起见,我们将使用 Pandas 加载文本文件,并将路径 URL 调整为 Unix 标准,例如,对于培训部分:
Data loading in Pandas and scikit-learn.
由于文本文件不是很大,在这种情况下使用 Pandas 稍微容易一些,并且提供了一点灵活性。然而,对于较大的文件,更好的选择是直接使用 tf.data 对象 TextLineDataset 。
步骤 1 —使用 tf.data 和 Dataset 对象
现在我们已经有了数据,我们可以使用 tf.data 来加载它,让它为估计器做好准备!在最简单的情况下,我们可以通过切取熊猫的数据帧来获得我们的批量数据:
Loading data in tf.data from a Pandas’ DataFrame.
以前,使用带有估计器的 tf.data 的一个主要问题是调试数据集相当复杂,必须通过 tf。会话对象。然而,从最新版本来看,即使使用估算器,也可以调试启用了急切执行的数据集。例如,我们可以使用数据集构建 8 个元素的批次,取第一批,并在屏幕上打印所有内容:
Debugging Dataset objects in eager execution.
现在是从路径开始加载图像的时候了!注意,一般来说这不是小事,因为图像可以有许多不同的扩展名、大小,有些是黑白的,等等。幸运的是,我们可以从 TF 教程中获得灵感,利用 tf.image 模块中的工具构建一个简单的函数来封装所有这些逻辑:
Parsing images with the tf.image module.
该函数负责大多数解析问题:
- “通道”参数允许在一行中加载彩色和黑白图像;
- 我们将所有图像的大小调整为我们想要的格式(40x40,与原纸一致);
- 在第 8 行,我们还标准化了我们的地标标签,以表示 0 和 1 之间的相对位置,而不是绝对位置(因为我们调整了所有图像的大小,图像可能有不同的形状)。
我们可以使用数据集的内部“映射”函数将解析函数应用于数据集的每个元素:将此与一些用于训练/测试的附加逻辑放在一起,我们获得了最终的加载函数:
Full data loading function starting from a Pandas’ DataFrame object.
A single image successfully loaded from the dataset.
步骤 2-使用自定义估算器构建卷积网络
下一步,我们想要复制取自原始论文的卷积神经网络(CNN ):
Source: Facial Landmark Detection by Deep Multi-task Learning.
CNN 的逻辑由两部分组成:第一部分是整个图像的通用特征提取器(在所有任务之间共享),而对于每个任务,我们有一个单独的、较小的模型作用于图像的最终特征嵌入。由于下面显而易见的原因,我们将这些更简单的模型中的每一个称为“头”。通过梯度下降同时训练所有头部。
让我们从特征提取部分开始。为此,我们利用 tf.layers 对象来构建我们的主网络:
Implementation of the feature extraction part with tf.layers.
目前,我们将关注单个头部/任务,即估计图像中的鼻子位置。一种方法是使用定制估算器,允许将我们自己的模型实现与标准估算器对象的所有功能相结合。
自定义估算器的一个缺点是它们的代码非常“冗长”,因为我们需要将估算器的整个逻辑(训练、评估和预测)封装到一个函数中:
The code for our first custom estimator.
粗略地说,模型函数接收一个模式参数,我们可以用它来区分我们应该做什么样的操作(例如,培训)。反过来,模型函数通过另一个定制对象(一个 EstimatorSpec )与主估算器对象交换所有信息:
Schematic formulation of custom estimators (source).
这不仅使代码更难阅读,而且上面的大多数代码往往是“样板”代码,只取决于我们面临的特定任务,例如,使用回归问题的均方误差。Head API 是一个实验性的特性,旨在简化这种情况下的代码编写,这是我们的下一个主题。
步骤 3a——用 Head API 重写我们的定制估算器
Head API 的思想是,一旦指定了几个关键项,就可以自动生成主要的预测组件(上面我们的模型函数):特征提取部分、损失和我们的优化算法:
Source: YouTube, The Practitioner’s Guide with TF High Level APIs (TensorFlow Dev Summit 2018).
在某种意义上,这是一个类似于 Keras 的高级接口的想法,但它仍然留有足够的灵活性来定义一系列更有趣的头部,我们很快就会看到。
现在,让我们重写前面的代码,这次使用“回归头”:
Same model as before, using a regression head.
实际上,这两个模型是等价的,但是后者可读性更好,更不容易出错,因为大多数特定于估算器的逻辑现在都封装在头部内部。我们可以使用估计器的“训练”界面训练这两个模型中的任何一个,并开始获得我们的预测:
Example of prediction for our single-task model.
请不要将 Head API(在 tf.contrib 中)与 tf.contrib.learn.head 混淆,后者已被弃用。
步骤 3b —使用多头进行多任务学习
我们终于进入了本教程更有趣的部分:MTL 逻辑。请记住,在最简单的情况下,进行 MTL 相当于在同一个特征提取部件上有“多个头部”,如下图所示:
Source: An Overview of Multi-Task Learning in Deep Neural Networks (Sebastien Ruder).
在数学上,我们可以通过最小化特定任务损失的总和来联合优化所有任务。例如,假设我们有回归部分的损失 L1(每个地标的均方误差),和分类部分的 L2(不同的标签),我们可以通过梯度下降最小化 L = L1 + L2。
在这个(相当长的)介绍之后,您可能不会惊讶 Head API 有一个针对这种情况的特定头,称为多头。根据我们之前的描述,它允许线性组合来自不同压头的多个损耗。在这一点上,我将让代码自己说话:
为了简单起见,我只考虑两个任务:鼻子位置的预测,和面部“姿态”(左侧面,左,正面,右,右侧面)。我们只需要定义两个独立的头部(一个回归头部,一个分类头部),并将它们与 multi_head 对象结合起来。现在添加更多的头只是几行代码的问题!
为了简洁起见,这里省略了对 input 函数的一点修改:您可以在 Colab 笔记本上找到它。
此时的估计量可以用标准方法训练,我们可以同时得到两个预测:
Predictions of our multitask model: node position and pose (frontal in this case).
结束…
我希望你喜欢这个关于 MTL 问题的小介绍:如果你感兴趣,我强烈推荐 Sebastian Ruder 的这篇内容丰富的文章来学习更多关于这个领域的知识。更一般地说,谈论 MTL 是从 TF 框架引入一些有趣概念的完美借口,尤其是 Head APIs。别忘了在 Google Colab 上玩玩完整笔记本!
这篇文章最初以意大利语出现在 https://iaml.it/blog/multitask-learning-tensorflow:的意大利机器学习协会的博客上。
使用无状态神经网络的多变量时间序列预测
用无状态深度学习辅助目标变量的多变量预测。
Photo by Jon Tyson on Unsplash
有辅助变量的时间序列预测
输入法系列。带有时间元素的数据集。这样的数据允许我们思考时间序列的 2 属性的组合:
- 季节性 —在特定时间长度内倾向于反复重复的数据模式。
- 趋势 —这类似于回归,我们正在捕捉系列的全局模式。
- 数据的相关性趋向于以 当前时间为中心,表示过去,接近当前时间的数据影响更大,越接近当前数据未来预测的准确性越好(熵原理)。
这样的组合使得时间序列变得特别。某一时间点的数据取决于之前的数据。直觉上,这是事件的因果本质,比如你正在阅读的单词基于之前的单词有意义。
通常情况下,机器学习只捕捉趋势,这使得训练时间序列上的典型机器学习模型非常昂贵。
用支持变量预测单个变量
N 通常预测一个单变量需要创建一个模型,该模型是以前时间数据的函数。这就是所谓的单变量自回归。
[1]Autoregression formula. (Wikipedia)
上图是一个自回归公式的例子。[1]
我们不会深入研究公式的细节,但请注意 ff 变量:
→ 因变量。目前数据的价值。
→ 自变量。注意之前的数据是变量的给定值。
其余的是提高模型精确度的附加参数和变量。
但是如果我们有额外的与目标变量相关的假设变量呢?这些可以通过适当的建模提高我们需要的目标变量的准确性。
算法和模型
W 一想到时间序列,马上想到 LSTMs、GRUs 等递归神经网络。但是在这种情况下,我们拒绝这样做,而是依靠前馈神经网络。为什么呢?让我们举例说明这两者以及我为什么选择后者:
- 递归神经网络— 这些图的输出反馈到输入。随着推理的进行,网络的输出被存储为状态,准备在下一个时间步进行推理。
RNN and its states through time. Source: https://upload.wikimedia.org/wikipedia/commons/e/ee/Unfold_through_time.png
循环网络试图通过以下方式预测下一个时间步长:
- 在 →实际输入值在时刻
- Xt→RNN 或模型预测的先前状态
利用上述变量,网络通过最小化建模数据和*实际数据之间的误差来实现其预测能力。*但是,请注意,随着 RNN 穿过不同的时态数据,预测模型的误差会增加。
Continuous state transformation worsens the transformation through time.
LSTMs 和 GRUs 似乎解决了这个问题,因为它包含接受或忘记被认为不相关的先前数据的门。然而,这些门和数据转换不能具体控制到时序分析的一个关键方面:各种时间状态如何相互关联。
在下图中,时间步长变成了一个带有激活函数的单元格的向量。因此,捕获的时间步长与目标未来步长之间的关系。
Feedforward network that relates various timesteps vs the next timestep
然后,我们可以针对管道和设计的模型的具体细节,进行适当的实现。
实施
完整的代码实现位于 https://github.com/arjay55/time_series_stateless.git的 Github 上
一、图书馆
这些库主要包括 ff:
- 熊猫→ 进行数据准备
- Scikit-learn (sklearn)和 scipy →用于外部损失功能和缩放
- seaborn → 用于热图可视化
- skopt →包含贝叶斯优化的优化模块。我们将在训练中使用它进行超参数调整。
- TensorFlow →深度学习开源库。我们用的是最新版本, tensorflow-beta1。
二。数据准备
出于数据隐私的考虑,我们将只加载规范化的数据集。
首先,我们加载规范化的数据集。
Snip of the Dataframe. Note the missing data on inflation column
检查数据帧后,我们有 3 列
1。 mutual_unit →这是信托基金单位,可兑换为投资货币。它的价值越高,你的投资回报就越多。
2。这是一个公司中不同公司股票价格的综合指数。
3。通货膨胀 →特定国家的通货膨胀率。
选择这些变量是因为它们代表了一个特定国家的财政状况。
请注意,通货膨胀列有许多空值或空值。一种技术是用假设值填充数据:
1。数据集的最高和最低索引中的线性插值。
2。超越最远指数的 ARIMA 外推。为什么?仅使用 2 个预测步骤来模拟外部部分更容易。
我们将文件保存到一个 csv 文件中,以供另一种编程语言 r 使用。我选择使用它,因为它的*“auto-ARIMA”*函数与 Python 的同类函数相比更流行、更成熟。
我们将有 2 个输出:
1。倒排[2]值到 x 步骤→“倒排”表示向后预测,或者简单地反转时间序列并执行预测。
2。预测值→y步骤→平时预测。
x 和 y 值由函数 get_outernan 确定,而 fill_data 用假定值填充缺失数据。
在 Rstudio 中,我们加载插值膨胀数据集并执行简单的 ARIMA:
- 在预报中,常规 ARIMA 已经完成
- 在“回显”中,注意在时间序列 ts() 函数之前使用 rev() 函数将数据转换为时间序列。
- get get_outernan 函数返回值 (6,15),,其中分别是回测和预测的步数。
三世。数据探索
既然我们已经准备好了用于分析的数据,我们就可以开始研究它们,以检查其数据质量,并使用领域专业知识简化数据。
首先,让我们细化我们的目标。请记住,我们打算预测一个单一的变量。那个变量就是 mutual_unit 。我们有 3 个变量
我们的目的是借助辅助变量预测* 共同 _ 单位 变量,即股票 _ 交易所和*通货膨胀。**
让我们画出三个变量:
Line plots of the three variables
在检查图表时,在互助单位和股票交易所之间可能存在一些相关性。对于通货膨胀,数值有一个支点,从上升到下降*。*
作为附加分析,让我们执行时间步长与时间步长相关性分析。我们将使用热图来查看相关性。
在第一次剪切( correl.py )时,它生成一个热图。
我们可以看到 mutual_unit 具有高度的相关性:
Correlation of mutual_unit to other variables
**注:在撰写本文时,通货膨胀似乎与互助单位负相关。这可能是该股走高,以从通胀上升中复苏。您可以尝试减少感兴趣的时间窗口,这可能会提高模型的准确性。
在我们的模型中,我们需要指定变量的权重。这是代码的第二部分( correl2 )。由于我们使用股票交易和通货膨胀作为辅助变量,它们的权重将产生以下影响:
- **较高的权重意味着与目标变量的相关性较高。
- **降低重量与上述相反。如果指定了更高的权重,那么变量的噪声将会过拟合或使目标变量不太准确。
作为我们模型的权重。相关性的标度如下:
ABS(变量)/SUM(ABS(变量))
其中 VARIABLEx 是相关系数。除以变量的相关系数之和。注意绝对值是在其他计算之前获取的。
computed initial weights of the variables
请注意,这三者的比例大致相同,因为它们与 mutual_unit 具有相关性。
四。预测管道
这是我们应用机器学习进行预测的部分!当然,这并不神奇,这个过程仍然是随机的和数学的。正是它的信息处理技术使得它的预测令人印象深刻。
我们进行的预测类型是回归,我们预测的是连续值。在回归中,我们建模连续值*。在分类中,我们对离散值进行建模。在下图中,某个指标以两种类型表示。在离散或分类中,数值为轻度、中度或重度。在右轴中,指标表示为连续的值。*
Comparison between regression and classification.
数据集的时间处理
我们的数据是一个时间序列,因此,除了它的特征值,还有一个向前移动的时间。虽然我们的数据集包含趋势和季节性,但将数据集截断到滚动窗口中是很重要的。为什么?因为使用整个历史可能会使模型过拟合。
在我们的案例中, 1 个月的窗口期可能就足够了,或者 4 个工作周。这种假设意味着可以使用该窗口对大多数属性进行建模。
N 注:从这一点上,我将提到在下面的实现中使用的函数。
我们还需要定义滚动窗口的范围。在我们的例子中,我们将假设 3 个月的训练数据来表征模型。**
Illustration period of training scope and model scope. The right side of the illustration is the recommended dataset.
Dataset creation using rolling window. Photo credit and source from Huaiqing Wang, Diagram of building up the dataset
我们现在将分割训练和测试数据集:
上面的代码显示了训练和测试数据集的创建。结果是一个已经创建了滚动窗口数据集的时间序列生成器*。*
我们将训练/测试数据集分成 80%/20%。请注意,测试数据的批量大小只有 1,正如我们稍后将会遇到的,测试集将会 1 个与 1 个进行比较,以形成验证错误。**
训练窗口大小为 20 。
模型架构
该模型本质上是顺序的,意味着各层堆叠成一个单输入/单输出而没有任何分支。
Model architecture from TensorBoard
模型从“密集”开始,到“密集 _ 2”层结束。
- 第 1 层(“dense”)简单来说就是一个点乘*,相当于线性向量自回归 (VAR),参数个数可调,增加了复杂度。它不包含随机参数。*
- 第二层(“dense _ 1”)是学习进一步非线性的附加层。
- 接下来的几层分别是,
a. Dropout 层——训练时随机断开某些权重的层。这有助于网络学习逻辑形式的非线性,同时减少过拟合。 b .展平层——将先前的隐藏层置换为输出层的层。输出尺寸等于目标变量的尺寸*。*
*Function: train_evaluate()*
Dropout illustration. Source: Srivastava Nitish, et. al, Dropout: A Simple Way to Prevent Neural Networks from Overfitting (2014), Journal of Machine Learning Research 15
在输入图层上添加时态训练技术
回想一下递归网络仅模拟当前和下一个时间步。如果我们只想要一个自回归模型来描述下一个时间步与前一个时间步的特征呢?(见上图,“将不同时间步长与下一个时间步长相关联的前馈网络”)。然后我们将一个无状态网络,因为它简化了模型。**
另一个重要特征是输入屏蔽*。回想一下,我们的输入形状有 20 个时间步长。我们将不使用这些形状作为输入层形状:*
- 使用所有时间步长可能会导致过度拟合。
- 由于我们正在训练滚动窗口来捕捉季节性,我们将使用输入跳跃来捕捉不同尺度的季节性。
- 更远的时间步长与现值的相关性更小。
Masking the inputs. The timesteps highlighted as gray are masked.
有了这些,我们在输入层只有 11 个输入。可以尝试不同的组合来面膜。
Code snip for code on masking. For full code, you can refer to train_evaluate() function.
超参数调谐
**超参数主要是实例化或训练模型时的可调参数。
作为一个例子,上面的要点实例化了一个“密集”层。那些属于 kwargs 字典的是超参数:
- **‘输入层’是创建的神经元数量。调整这些将直接影响模型适应非线性(欠拟合或过拟合)的能力。
- ’ uni_reg’ 将 L1 正则化应用于该层。参数值越高,调整速度越慢,降低了过拟合的风险。
以下是模型的超参数:
上面的要点是使用名为“ skopt.space ”的库创建的,您可以在其中指定要优化的范围和类别。
之后,我们将整个管道封装到一个函数中,并运行优化函数命令。这就是我们创建一个名为
*train_evaluate(normalized_data, est_period,loss_func,param_record, **kwargs)*
它包含模型创建、验证过程等。你可以随意研究。
现在,到超参数优化命令。
我们正在使用高斯概率贝叶斯优化来优化参数。它本质上映射了优化空间的一个概率模型*。关于开采(疑似值)和勘探(创建真实数据点)之间的导航空间的假设[4]*
Continuous improvement using Bayesian optimization. Source: Gilles Louppe, Manoj Kumar, Bayesian optimization with [skopt](https://scikit-optimize.github.io/notebooks/bayesian-optimization.html) (2016)
测试/验证
测试这个自回归问题有很多组成部分:
- 训练期间的测试集
- 这些是预测 X(t+1)处特征的测试值
2.多步预测的迭代预测
首先,让我们提醒自己我们的目标变量,mutual _ unit。**
为了验证这个变量,需要在 X(t+1)预测这 3 个变量。输入数据被推到左边,然后最新的时间步长数据被替换为预测数据。该过程被迭代以实现在多步骤的迭代。**
Process on how the model forecasts in multi-steps. Xn is real data point where Hn is a predicted value
做到这一点的功能是
***validation()***
**验证函数进行迭代预测,并与相应的测试数据进行比较。注意,只有 mutual_unit 才被拿出来比较。
A code snip on comparing the predicted(y_pred) and actual values(y_true).
现在,向量 y_pred 和 y_true 是未来值。随着时间步长的进一步预测,熵或不可预测性增加。因此,我们将为这些值引入一个折现因子*。在我们的应用中,贴现因子是 0.9。*
Code to create the coefficients for multiplying into future data.
此后,计算平均绝对误差**。这将是衡量模型性能的主要验证指标。
这个 MAE 将作为提前停止的度量。
早期停止应用于我们的验证指标( MAE )以减轻过度拟合的风险。一旦验证误差开始增加时停止。然而,由于验证值被假定为凸*,它具有不完全达到完全最优的风险,因为一旦发现误差的拐点,训练就停止。*
Early stopping illustration. Source: Shubham Jain, An Overview of Regularization Techniques in Deep Learning (with Python code) (2018),
我使用了手动编码的早期停止器,而不是 TensorFlow 的 API,这是因为定制的验证计算加上它更容易编码,而不是找到合适的 API。对象名称是
*class CustomEarlyStopper:
def __init__(self, patience=3, delta=1e-4):
...*
它具有类似的参数,如耐心和增量,作为验证误差增加的容限。
让我们来看看预测值和实际值之间的关系。请注意,预测值在预测值之上有一个正偏移。
Comparison between the predicted(‘mutual_unit_forecast’) and actual(‘mutual_unit’)
定稿
我们现在正在准备用于推理的模型。
- 使用最终参数,我们重新优化模型,以在超参数调整期间达到相同的验证误差。这些可以通过加载优化对象来获得。
在笔记本中,你可以注意到 jump() 和 load() 这两个函数使持久化*(保存到磁盘)。放置这些函数是为了便于在系统中断时使用对象。*
注意:您可以重构代码,以便用最佳超参数优化的模型成为持久的(用户),从而避免如上所述的重新训练。
2.在此之后,捕捉最后一次最优训练的最后一次训练损失*。请注意,这是要应用的培训损失,而不是验证损失。这种技术也可以重构。*
3.最后,我们必须使用整个数据集来训练模型。为了降低过度拟合的风险,我们将从最后训练的模型中获得先前训练损失*。一旦达到目标训练损失,我们将停止模型训练。*
结束语
感谢您的阅读,希望您了解了时间序列预测的基础知识,从数据准备到建模。我很高兴分享这一经历,就像在简单的时间序列预测中学习、发现和应用深度学习一样有趣。
参考
[1] 自回归模型,维基百科
[2]“罗布·J·海德曼”,回播于 R (2014)
[3] 向量自回归,维基百科
[4]吉勒·卢佩,马诺奇·库马尔,贝叶斯优化与 [skopt](https://scikit-optimize.github.io/notebooks/bayesian-optimization.html) (2016)
多元微分学和最优化-第一部分
微分学是寻找给定任务的最优解的强大工具。当我说“最优解”时,我指的是一个给定函数(称为目标函数)的优化结果。这个结果可能是最大值(即,如果你的目标函数描述了你的收入)或最小值(即,如果你的目标函数代表了你的成本)。
优化过程是数据科学中的基础:每个机器学习算法都通过一些优化标准进行优化,以便它将返回最佳结果。也就是说,如果你考虑神经网络,你可以看到最终的输出(即算法的参数集)是在反向传播阶段之后返回的,其目的是用一种称为梯度下降的技术优化系数(你可以在这里阅读关于这种技术的更多信息)。
在这里,我将详细阐述在多元环境中优化背后的数学原理。由于多元微分学涉及许多步骤和概念,我决定将这个主题分成两部分:第一部分将详细介绍一些介绍性的概念,而在第二部分,我将专注于优化过程本身。
顺便说一句,在开始第一部分之前,如果你不熟悉高维空间中的向量和平面,我建议阅读我以前的文章,在那里我提供了关于这方面的视觉和直观的解释。
方向导数和切面
正如预期的那样,我们将研究多元函数。具体来说,我们将从 R 到 R 看到这些函数:
在它们的领域中,表示为如下的表面:
第一部分的目的是找到曲面在给定点 p0 的切面。这是查询该曲面的光滑性或正则性或连续性的第一步(这对于可微性是必要的,因此也是优化过程的可能性)。为此,我们将介绍以下概念:
- 方向导数
- 梯度
- 切线向量
- 切面相切平面
那我们开始吧。
从概念上讲,点 p0 的方向导数是函数在该点沿方向 v 变化的速率,其表达式如下:
要定义它,我们先回忆一下 1 维中导数的定义:
它被定义为当增量趋于零时不同商的极限。结果是计算导数的点处曲线切线的斜率。
从概念上讲,这在我们的多元环境中不会改变。这里,想法是计算不同的商,考虑表面上的一个点 p0 和它的增量,让我们再说一遍,表面上的 pt 。
让我们首先想象这两点:
所以我们想计算:
如你所见,我们需要三个要素:这两个点上的函数值,以及它们之间的增量。
为此,我们可以将曲面 f(x,y)的函数限制在穿过 p0 和 pt 的直线在曲面上的投影。
现在让我们把注意力集中在绿线上,让我们在一个 2 轴空间中检查它:
具体来说,这是一条与方向 v 相交 p0 的直线(与我们的方向导数方向相同)。我们可以很容易的计算出这条直线的参数表达式,得到 pt 的坐标。
此外,我们还可以计算不同商的最后一个成分,即增量。我们可以将其计算为 p0 和 pt 之间的距离(带调整):
因此,方向导数的最终表达式是:
这导致仅在 t 中的限制,而不是多个变量。
现在让我们考虑方向导数的一个特定方向。我说的是向量 v ,它平行于我们的 x 轴,因此它的第二个分量是 0。为了简单起见,让我们考虑第一个分量等于 1(它可以是任何值)。在这种情况下,我们的方向导数变成:
这是 f(x,y)相对于 x 的偏导数的定义。如果我们选择一个平行于 y 轴的方向向量,即 v =(0,1),同样的推理成立:
如果我们把那两个偏导数集合成一个向量,我们就得到所谓的 f(x,y)的梯度。我们可以在函数自然区域的任何一点计算梯度。然而,每一个合成向量都具有与函数的水平线正交的特性。
现在我们已经有了几乎所有寻找切面方程的成分。为此,我们将再次将我们的函数限制在两条坐标线的投影上,然后找到这些曲线的两个切向量,计算包含这两个切向量的平面的方向 d ,最后计算具有方向 d 的平面的方程。
两条坐标线相交的点为 p0 =(x0,y0):
让我们一步一步来,如上图:
- 第一步:我们已经有了我们坐标的前两个分量(x 坐标的 x 自由和 y 固定,y 坐标的 y 自由和 x 固定)。然而,由于我们希望它们在表面上的投影,我们还需要第三个组件,它只是在坐标向量上计算的函数:
- 第二步:由于前面的表达式只不过是两条曲线的方程,我们可以对每个分量对参数 t 求导来计算切向量:
注意,第三个分量分别是 x 和 y 的偏导数(实际上,在第一个系统中 x=t,因此对 w.r.t. t 求微分等于对 w.r.t. x 求微分。这同样适用于第二个系统中的 y)。
- **第三步:**我们需要计算我们的切面的方向 d。因为我们知道 d 必须正交于包含在平面中的所有点(你可以在这里阅读更多关于正交性的内容),并且因为该平面包含上面计算的两个切向量,我们可以推导出 d 必须正交于这两个切向量,因此:
其中伽玛是一个参数。由于我们只需要一个向量作为方向,为了简单起见,我们可以很容易地设置 gamma=1,因此:
- 步骤 4 :现在是计算我们平面的方程的时候了,这个方程可以很容易地用下面的正交条件推导出来:
如果我们检查最后一个表达式,我们可以注意到这是一阶泰勒多项式对曲线近似的二维扩展:
如果你想知道一个曲面的光滑度,那么在一个给定点上该曲面的切平面的存在是一个基本要素。事实上,您可以将 p0 处的光滑性视为通过任何方向到达 p0 的可能性,而不仅仅是对应于偏导数的那些(偏导数的存在不是曲面正则性的充分条件)。
我们优化任务的下一步将是检查曲面的可微性,这是任何优化问题背后的假设。敬请期待第二部!
原载于 2019 年 9 月 1 日http://datasciencechalktalk.com。
多元微分学和最优化-第二部分
在我之前的文章中,我介绍了一些概念,如果我们想在多元环境中设置一个优化问题,这些概念是必要的。
在这里,我们将首先讨论如何检查曲面的平滑度(这是部署优化任务的主要假设),然后我们将了解如何在多元环境中寻找局部/全局最大值/最小值。
光滑性和可微性
用一种非常直观的方式,我们可以说一个曲面是光滑的,如果它既没有洞,也没有角,也没有跳跃。这与一维空间中连续性的概念相同,但扩展到了多元环境中。
更具体地说,指出一个曲面在一个点 p0 上可微意味着我们可以以任何我们想要的方式到达那个点,而不仅仅是通过偏导数。这意味着存在一个与 p0 相切的平面,该平面可以逼近 p0 的一个邻域(最好:任何一个邻域)中的曲面。
让我们用下面的表面来形象化这个概念:
根据定义,曲面上和切面上的点 p0 的值是相同的。另一方面,挑一个接近 p0 的点,姑且说 p 吧,我们可以看到 p 在表面上的值和在平面上的值是不一样的:我们将这种差异称为误差。因此,我们可以将曲面在一般点 p 上的近似表示如下:
其思想是,如果相对于 p0 和 p 之间的距离,误差可以忽略不计,则该平面是该表面的良好近似。换句话说,我们希望误差是距离的一个小的 o ,因此:
很好,现在我们可以开始优化程序了。
最佳化
正如预期的那样,从现在起我们将考虑给定的可微性:这将是我们强有力的假设。话虽如此,让我们首先想象一下我们想要解决的问题:
这个想法是找到我们表面的最大值和最小值,我们可以从一个基本定理开始,费马定理:
“若 f(x,y)在其自然域上可微,则每个最优点都有一个水平切面”。
所以如果我们看看切面的方程:
这意味着红色部分必须等于零,这样平面才是水平的。这意味着函数的梯度(其分量是偏导数)必须等于 0 向量:
因此,通过设置梯度等于零,我们挑选了所有的候选最佳点。然而,我们该如何对它们进行分类呢?为此,我们需要二阶泰勒多项式,然后研究红色量的符号:
如果它是正的,这意味着曲面的函数在其周围各处取大于 p0 的值,因此 p0 是局部最小值。另一方面,如果数量是负的,这意味着该函数在其周围各处取比 p0 低的值,因此 p0 是局部最大值。
我们可以很容易地研究该量的符号,因为它是具有代表性矩阵的二次型:
这就是所谓的海森矩阵。因此,我们可以说,如果在 p0 处评估的 H 是正定的, p0 是局部最小值;如果 H 是负定的, p0 是局部最大值;如果是不定的, p0 不是一个最优点。只要 H 是非奇异矩阵(因此它的行列式必须不等于 0),一切都成立。
优化是数据科学中的一个基本概念,可以采用许多不同的技术。然而,背后的想法总是相同的:选择一个目标函数(在机器学习算法的情况下,它由损失函数表示,因此优化意味着最小化)并将问题设置为多元环境。
当然,预建的算法会为你做所有的计算,然而重要的是要放弃直觉,因为即使是自我学习的算法也需要调整(或者至少初始化)。
原载于 2019 年 9 月 1 日http://datasciencechalktalk.comT22。
基于随机森林的多元时间序列预测
A Pocket Watch. It looks cool doesn’t it. Very hipster-ish.
介绍
在我之前的帖子(了解实体嵌入及其应用 ) [1]中,我谈到了使用实体嵌入来解决预测问题——基本上是使用表示为向量的表格数据,并将其作为基于神经网络的模型的输入来解决预测问题。
不过这一次,我将通过一种叫做随机森林的不同技术来做同样的事情。
由于我不打算让这篇文章成为关于 Random Forest 的教程,任何热衷于深入研究这个问题的感兴趣的读者可以在这里【2】正在编写的优秀机器学习书籍中了解更多信息。如果你以某种方式幻想自己是机器学习的完全初学者,并想了解决策树及其与随机森林的关系,请查看泰坦尼克号数据集上的教程。[3]
不过,我将谈论的是我如何使用随机森林建立一个多元预测模型,以及随之而来的一些考虑因素。
为了将事情放入背景中,我的新任务要求我建立一个模型,能够预测我们未来几个月的网络流量,使用多个变量,这些变量可能对预测有任何影响,也可能没有任何影响。虽然我不能透露正在使用的变量(出于明显的原因),但它本质上是一个 web 流量时间序列数据,包含流量、用户行为、人口统计和一些外部特征等常见特征。
为什么随机森林?
我选择使用随机森林(RF)主要是因为我必须处理的任务要求我能够解释模型并提供预测。因为典型的神经网络几乎是一个黑箱(我不确定注意力机制是否能给出特征重要性…可能是我看的论文还不够多…),我决定这次不用了。
在现有的各种统计机器学习技术中,我选择了 RF,因为它比其他技术更健壮,更容易训练。
但是,在依赖 scikit-learn 随机森林特征重要性时需要谨慎。在[8]中,作者声称由于计算方式的不同,结果中可能会出现偏差。为了让我们对此有所了解,考虑一下他们使用 Kaggle 的 Two 适马连接:租赁列表查询中的数据构建分类器的例子
Image from [8]. Figure 1(a) depicts feature importance from a model that predicts rent prices, while Figure1(b) is a model that predicts interest level.
上图描述了基于两种不同模型的特性重要性图表。左图来自一个试图预测租金价格的模型,右图来自一个预测利率水平的模型。与此同时,使用随机数生成器生成random
变量,以描述随机性并指出任何不重要的特征(直觉是任何排名低于random
的特征都应被视为垃圾)。
正如我们在图 1(a)中看到的,random
是排名最低的——这是有道理的。虽然浴室的数量是最重要的特征看起来很奇怪,但我们现在暂时不考虑它(也许他们真的关心卫生和其他)。对于我们这些实际上已经购买或租赁过房产的人来说,通常的直觉是,位置是决定房价的最重要的因素。
在图 2(a)中,我们可以看到random
在某种程度上高于bedrooms
和bathrooms
。所以不知何故,我们随机产生的数字被认为具有预测能力。奇怪…(这就结束了我演示 RF 特性重要性如何产生偏差的简短尝试)。
有关上述示例和建议解决方案的更多详细信息,请参见【8】。他们也有一些优点,说明为什么线性模型可能不是通过回归系数提供特征重要性的最佳方法。
我们建议对所有模型使用排列重要性,包括线性模型,因为我们可以在很大程度上避免模型参数解释的任何问题。解释回归系数需要极大的细心和专业知识;地雷包括没有标准化输入数据,在使用 Lasso 或 Ridge 正则化时正确解释系数,以及避免高度相关的变量(如 country 和 country_name)。要了解更多关于解释回归系数的困难,请参阅 Leo brei man(Random Forests 的创始人之一)的统计建模:两种文化 (2001)。
因此另一个+ve 用于使用随机森林。
为什么不是 ARIMA?
我确实考虑过使用 ARIMA,而且事实上已经就这个问题进行了一个简短的研究,以考虑它是否适合这项任务。然而,最终我认识到,它主要适用于建立单变量(单变量)模型。
如果这个问题是单变量的,我可能会使用脸书的 Prophet [4]软件包来帮助我。用我们的流量数据进行测试一点也不困难,而且在添加年度、季度和月度季节性模式方面做了一些调整——它已经能够给出一个非常不错的结果。
Hyndman 在 R 中的包也是一个选择。但是我决定不这么做,因为在这个例子中我尽量不使用 R。
其他方法
在探索解决这个问题的可能选项时,我遇到了一些值得一提的方法:
- 向量自回归模型(VAR)。它基本上是一个多元线性时间序列模型,旨在捕捉多个时间序列之间的动态变化。更多细节,请查看[5]和[6]
- AWS Deep AR 我只是在工作的后期才发现这一点。它基本上是一个监督学习模型,旨在用于单变量数据。但是,它也允许多变量时间序列输入。更多细节见[7]。
由于严格的截止日期要求,我无法探究上述算法——因此我不得不放弃它们。
构建预测模型
在这一节中,我将介绍一些我认为在使用基于树的方法构建预测模型时非常重要(尤其独特)的活动。
随机森林不能预测 t+1 以上的时间对吗?
这是真的——我们不能像使用线性模型那样,使用随机森林预测超过 1 个值或无限期预测未来。这意味着,当我试图预测未来 6 个月时,我需要实际使用过去 6 个月的数据作为输入。
举个例子,如果我的模型能够预测未来 6 个月;为了预测 2019 年 7 月 1 日的流量,我需要使用 2019 年 1 月 1 日的数据点(为了简化,我假设所有月份都有 30 天)。为了预测 2019 年 7 月 2 日,我将使用 2019 年 1 月 2 日。以此类推,直到 2019 年 6 月 30 日,这给了我 2019 年 12 月 30 日的预测。
使用这种方法的缺点是无法使用更接近现在的数据(即使用 2019 年 6 月 30 日的数据进行 2019 年 7 月 1 日的预测,如上例所示)。在我们的场景中,我们真正感兴趣的是未来 6 个月的流量,这仍然是可以接受的。
为什么是 6 个月?因为知道流量会如何(好或坏)会让我们有时间做出必要的改变来尝试改变它。较短的时间框架有助于仓促决策和执行。
但是,如果您的用例需要对明天或下周发生的事情进行真正准确的预测(例如股票交易),那么使用最近的数据会更好。
添加基于时间的变量
我们使用 fastai 库[9]的add_datepart
方法引入了额外的基于日期的变量。这样做使我们能够从数据集中捕捉趋势、季节性或周期性模式。这是一个非常有用的方法,尤其是当我们需要处理大量的时间序列数据时。
def add_datepart(df, fldname, **drop=True**):
fld = df[fldname]
if not np.issubdtype(fld.dtype, np.datetime64):
df[fldname] = fld = pd.to_datetime(fld,
infer_datetime_format=True)
targ_pre = re.sub('[Dd]ate$', '', fldname)
for n in ('Year', 'Month', 'Week', 'Day', 'Dayofweek',
'Dayofyear', 'Is_month_end', 'Is_month_start',
'Is_quarter_end', 'Is_quarter_start', 'Is_year_end',
'Is_year_start'):
df[targ_pre+n] = **getattr**(fld.dt,n.lower())df[targ_pre+'Elapsed'] = fld.astype(np.int64) // 10**9
if drop: df.drop(fldname, axis=1, inplace=True)
运行该方法会给我们提供以下变量。
- 月
- 年
- 周
- 一天
- 星期几
- 一年一天
- 是 _ 月 _ 末
- 是 _ 月 _ 开始
- 是季度末
- 是 _ 季度 _ 开始
- 是 _ 年 _ 末
- 是 _ 年 _ 开始
- 消逝
然而,我们不一定需要使用它们。例如,在我的用例中,我的数据点是基于每周的——因此我真的不需要Day
变量。
缩放/标准化您的数据
由于趋势可以在时间序列图中上下波动,为了确保我们的算法可以在测试集上更好地概括,最好首先将我们的数据归一化到一些较小的尺度。Box Cox、Log 或 StandardScaler(当然还有其他方法…我的列表决不是详尽的)可以用来修正我们的数据到一个更合适的。
记住,一旦你完成了你的预测,就把它们按比例缩小。
移除输入变量的趋势
确保数据的稳定性非常重要,因为这将使我们能够对未来做出准确的预测。为了强调为什么这是一个问题,考虑下图。
The y values in the validation set doesn’t appear in the training set. [10]
上面演示了通常如何将数据分成时间序列问题的训练集和验证集。请注意,由于拆分,定型集将无法捕获验证集的 y 值。
随机森林不太适合处理时间序列分析时经常遇到的上升或下降趋势,例如季节性[10]
为了补救这一点,我们需要从根本上“拉平”趋势,使其变得“稳定”。最简单的方法是使用数据的斜率或简单地扣除变量在时间 t 的滞后值在时间 t-1 。
添加滞后变量
由于随机森林评估数据点时不会将过去的信息带到现在(与线性模型或递归神经网络不同),因此定义滞后变量有助于从过去获得要在现在评估的模式。我们应该选择回到多远,很大程度上取决于数据本身的周期性。理想情况下,我们希望能够捕获至少一个周期的数据。
使用 delta 作为目标
类似于前面提出的观点,我们甚至对我们的目标变量也这样做(添加滞后变量),因为它是基于时间的。然而,由于我们不能直接获得 t-1 的数据,我们使用当前的交通。因此,预测交通量的公式如下。
where traffic(f) is traffic 6 month into the future and traffic(n) is current traffic.
有时在某处记下公式会有所帮助,因为我们需要在模型预测前后应用它。
建立基准
不言而喻,有一个比较基准是很重要的,这样我们就可以有一个参照点来比较我们的模型。在我的例子中,我使用了两种类型的基准;(I)使用当前流量,以及(ii)使用 6 个月的平均流量。
就模型的度量标准而言,我选择了 RMSPE(均方根百分比误差),这样我就可以评估从 0 到 100 的误差值(也便于与利益相关者沟通)。
维度的诅咒
这一点实际上并不是时间序列独有的。但是,在从滞后数据中创建了几百个额外的变量之后,由于我们引入了大量的变量,同时仍然只依赖于有限数量的数据点,我们的模型很容易过度拟合。
为了解决这个问题,我有意识地决定将使用的变量数量限制在前 N 位,这里 N 小于数据点的总数。
回溯测试策略
最初,我只是使用通常的训练有效性测试数据分割来检查我的模型的有效性。然而,当我深入这个主题并接近完成时,我终于明白,如果我不对它进行严格的基于时间的测试,我永远无法真正确定这个模型的性能。
事实证明,优步[11]在时间序列这个话题上有很多很好的参考。
Two major approaches to test forecasting models. Sliding window (left) and expanding window (right). Image taken from [11]
在我的场景中,我采用了扩展窗口的方法——在每次迭代中,我的训练数据都会变大,而保持测试/验证窗口间隔不变。测试窗口保持不变,这样我们就可以随着时间的推移比较它的性能和稳定性。
理想情况下,正如[11]中提到的,一旦我们的数据足够大,我们应该将测试方法从扩展窗口切换到滑动窗口。
在[12]中还可以找到关于该主题的更深入的文章。
再训练模型和预测
除了在训练模型之前使数据稳定之外,这是我从做这个练习中得到的最大的教训之一。
你不能只是部署一个静态模型并对其评分,模型服务的概念对时间序列预测没有意义。相反,您需要确保训练和模型选择可以在生产中即时完成,并且您必须确保您的整个训练集可以在生产中存储和处理。[13]
我对如何部署 ML 模型的通常理解一直是,模型在需要重新培训(如果有的话)之前服务大约 3-6 个月,并且可能监控在此期间性能下降的任何迹象。
可以说,[13]中提出的即时再训练和预测确实让我大吃一惊。然而,由于时间序列模型的可靠性在很大程度上取决于数据的更新程度(例如,假设我们试图预测时间 t+1 的交通流量;那么使用的最佳预测器将是时间 *t、*的流量,在每个预测时间重新训练模型毕竟不是一个荒谬的想法。
当然,如果历史数据的结构足够稳定;也许可以以较低的频率间隔安排再训练,或者也许只有当检测到变化点[15]事件时才进行再训练。
结论
上面的文章主要基于我在这个用例中的学习笔记。当我第一次开始研究它的时候,我从来没有想到我会学到这么多——有点期待它来自时间序列分析,而不是模型构建。
然而,让我颇感惊讶的是,寻找关于这个主题的信息是如此的不直接。虽然可以说,也许没有多少数据科学家喜欢使用基于树的方法来建立他们的预测模型。
最后,我的最终模型不是随机森林。我用使用 LightGBM 构建的模型替换了它,以获得更好的准确性和能够生成预测间隔的额外好处(通过分位数回归)。尽管使用梯度增强方法时需要仔细考虑,因为很容易建立一个过度拟合数据的模型。就我而言,LightGBM [14]的文档给了我一些如何克服这个问题的想法。
最后,特别感谢我的同事们,他们一直是我的跳板,帮助我在这么短的时间内弄清楚了这个问题。
更新(2019 年 3 月 4 日):增加额外章节随机森林不能预测超过 t+1 对吗?和根据读者的反馈缩放/标准化您的数据。(感谢侯赛因。)
参考
- 理解实体嵌入及其应用
- 随机森林回归变量,作者特伦斯·帕尔和杰瑞米·霍华德
- 《泰坦尼克号:从 R 开始》,作者特雷弗·斯蒂芬斯。(老实说,我只是为这篇教程添加了一个插件,因为这是我在 2015 年开始学习数据科学时学习的第一篇文章。目前,你可以找到更多关于决策树/媒体 RF 等的文章,但早在那时,这篇文章是仅有的几篇之一。是的,我最初是从 r 开始的,是的,我对此很伤感。Lol。)
- 先知,脸书
- 向量自回归(VAR)简介,IMF
- 使用递归神经网络和向量自回归模型进行时间序列预测:何时和如何,刘镇伟
- DeepAR 预测算法,AWS
- 小心默认随机森林重要性,作者特伦斯·帕尔和杰瑞米·霍华德
- 该方法不再作为最新库的一部分提供。尽管如此,你仍然可以在罗斯曼的笔记本上找到。
- 为什么随机森林不能预测趋势,如何克服这个问题?,作者阿曼·阿罗拉
- 优步的《优步的天气预报:简介》
- 时间序列嵌套交叉验证,作者 Courtney Cochrane
- 3 个让经验丰富的机器学习实践者惊讶的时间序列预测事实,作者斯坎达·汉纳奇博士
- 参数调谐,LightGBM
- 变化检测,由维基百科提供
基于随机梯度下降的音乐艺术家推荐系统(七)
了解如何通过从零开始实现随机梯度下降来为音乐艺术家构建推荐系统
TL;DR 从头开始用 Python 构建一个推荐系统。从 last.fm 数据集创建评级矩阵并预处理数据。使用随机梯度下降(SGD)训练模型,并使用它来推荐音乐艺术家。
随着“互联网”上的信息量呈指数级增长,推荐系统变得越来越重要:
从书籍、电影、游戏中找到你可能喜欢的东西,以及在 Instagram 上关注谁,变得越来越困难。此外,我们(用户)需要与我们日常使用的产品进行更快的交互,所以我们不会觉得我们在浪费时间(即使我们比人类历史上任何时候都更浪费时间)。随着数据量的增加,您的计算资源可能很难产生足够快的结果。
在这里,我们将看看一个推荐系统的简洁实现,它既是许多现实世界实现的基础,又易于理解。我强烈推荐你通读一下:)
用户评级
传统上,推荐系统是围绕给定的一组项目的用户评级建立的,例如 IMDB 上的电影评级。这里,我们将看看如何使用另一个指标来提出建议。
我们的数据来自 GroupLens 主持的 last.fm (从这里下载)。它包含以下内容:
- user_artists.dat — userID,artistID,weight —用户播放的艺人。
- artists.dat — id,名称,网址,图片网址
- tags.dat — tagID,tagValue
- user _ tagged artists . dat—userID,artistID,tagID,日,月,年
- user _ tagged artists-timestamps . dat—userID,artistID,tagID,时间戳
- user _ friends . dat—userID,friendID。用户/朋友关系。
我们将关注 user_artists.dat 和 artists.dat ,因为它们包含向用户推荐新音乐艺术家所需的所有数据。我们将使用每个艺术家的用户播放计数,而不是评级。
加载数据
让我们将数据加载到熊猫数据框中:
数据争论
在处理数据之前,您需要进行一些争论:
我们合并艺术家和用户播放,并将权重列重命名为播放计数。让我们根据用户播放的次数对艺术家进行排名:
并将结果与先前的数据帧合并:
以下是部分数据:
探测
我们来看看每个艺人被用户玩了多少:
以及被播放次数最多的艺术家的名字:
有多少用户扮演艺术家:
这是对艺术家受欢迎程度的另一种看法:
这并不奇怪,受欢迎的艺术家正在承担大部分的戏剧。不过,好在“披头士”仍然很强:)
推荐系统
推荐系统(RS)几乎被用在你有一系列商品可供选择的任何地方。他们通过提出建议来帮助你做出更好/更快的选择。
你可能认为你是一片特殊的雪花,但是 RS 利用用户(你和其他人)之间共享的行为模式。例如,你和你的朋友可能对某些东西有相似的口味。RS 试图在其他用户中寻找“朋友”,并推荐你没有尝试过的东西。
两种最常用的过滤方式是基于内容的过滤和协同过滤。协同过滤基于用户对项目偏好的知识来产生推荐,即它使用“群体的智慧”来推荐项目。相比之下,基于内容的推荐系统专注于项目的属性,并根据项目之间的相似性向您提供推荐。
协同过滤(CF)
协同过滤(CF)是推荐引擎的主力。该算法的好处是它能够进行特征学习的特性,这允许它开始学习使用哪些特征。CF 可以分为基于记忆的协同过滤和基于模型的协同过滤。
基于记忆的协同过滤
基于内存的 CF 方法可以分为两部分:用户-项目过滤和项目-项目过滤。区别在于:
- 项目-项目协同过滤:“喜欢这个项目的用户也喜欢……”
- 用户项目协同过滤:“与你相似的用户(有点像你从来不知道你有双胞胎)也喜欢……”
这两种方法都需要包含用户 u u 对项目 i i 的评分的用户项目矩阵。由此,您可以计算相似性矩阵。
项目-项目协同过滤中的相似性值是通过考虑对一对项目进行了评价的所有用户来计算的。
对于用户-项目协同过滤,通过观察由一对用户评价的所有项目来计算相似性值。
基于模型的协同过滤
基于模型的 CF 方法基于矩阵分解(MF) 。MF 方法是一种无监督的学习方法,用于潜在变量分解和降维。与基于内存的 CF 相比,它们可以更好地处理可伸缩性和稀疏性问题。
MF 的目标是从已知的评分中学习潜在的用户偏好和项目属性。然后使用这些变量通过用户和项目的潜在特征的点积来预测未知的评级。
矩阵分解将用户项矩阵重构为低秩矩阵。可以用两个低秩矩阵相乘来表示,其中的行包含潜在变量的向量。通过将低秩矩阵相乘,您希望这个矩阵尽可能接近原始矩阵。这样,您可以预测原始矩阵中缺少的条目。
奇异值分解
协同过滤可以通过使用奇异值分解(SVD)来近似矩阵 X 来公式化。在 Netflix 有奖竞赛中获胜的团队使用 SVD 矩阵分解模型赢得了奖品。SVD 可以表示为:
给定 m × n 矩阵 X :
- U 是( m × r )正交矩阵
- S 是对角线上有非负实数的( r × r )对角矩阵
- VT 是( r × n )正交矩阵
其中 U 代表用户的特征向量, V 代表项目的特征向量, S 对角线上的元素称为奇异值。
可以通过取 U 、 S 和 VT 的点积进行预测。下面是如何用 Python 实现 SVD 的一个简单例子:
推荐音乐艺术家
虽然大多数关于“互联网”的教程都专注于基于内存的方法,但它们似乎并没有在实践中使用。尽管它们产生了良好的结果,但是它们不能很好地扩展,并且受到“冷启动”问题的困扰。
另一方面,应用 SVD 需要对用户项目矩阵进行因式分解,当矩阵非常稀疏时(许多用户项目评级丢失),这可能是昂贵的。此外,经常使用输入缺失值,因为当数据缺失时 SVD 不起作用。这可以显著增加算法的数据量和运行时性能。
最近的方法集中于通过最小化关于潜在用户特征矩阵 P 和潜在项目特征矩阵 Q 的正则化平方误差来预测评级:
其中 K 为一组( u , i )对, r ( u , i )为用户 u 对 i 的评分, λ 为正则项(用于避免过拟合)。我们模型的训练包括最小化正则化的平方误差。在获得对 P 和 Q 的估计后,您可以通过对用户和项目的潜在特征进行点积来预测未知的评级。
我们可以应用随机梯度下降(SGD) 或交替最小二乘法(ALS) 来最小化损失函数。这两种方法都可以用于随着新评级的到来逐步更新我们的模型(在线学习)。
在这里,我们将实现 SGD,因为它似乎一般比 ALS 更快和更准确(除了在高度稀疏和隐式数据的情况下)。作为一个额外的奖励,SGDis 广泛用于训练深度神经网络(我们将在后面讨论)。因此,这种算法有许多高质量的实现。
预处理
为了应用 CF 算法,我们需要将数据集转换成用户-艺术家播放计数矩阵。让我们先完成数据缩放后再做:
这将压缩[0–1]范围内的播放计数,并在我们的数据框中添加一个新列。让我们构建我们的“评级”数据框架:
我们使用 Pandas pivot 方法创建索引/列数据帧,并用 0 填充缺失的播放计数。
让我们看看我们的数据框有多稀疏:
0.28%
我们的数据集看起来很稀疏。接下来,让我们将数据分成训练和验证数据集:
这里,我们对train_test_split
函数的定义略有不同:
好吧,这和你想象的大相径庭。我们通过用零替换用户的一些现有播放计数来删除它们。
测量误差
用于评估推荐系统的准确性的最流行的度量之一是均方根误差(RMSE),定义为:
其中 yi 是项目t5 I 的真实值, yi ^是预测值, N 是训练集的大小。
下面是 Python 中的 RMSE :
培养
让我们用 SGD 来训练我们的推荐器:
我们首先为用户和评级的潜在特征创建 2 个矩阵。对于每个用户、项目对,我们计算误差(注意,我们使用现有和预测评级的简单差异)。然后,我们使用梯度下降更新 P 和 Q 。
在每个训练时期之后,我们计算训练和验证误差,并存储它们的值以供以后分析。下面是predictions
方法的实现:
正如我们之前讨论的,我们通过取转置的 P 矩阵与 Q 的点积来获得预测。
估价
让我们通过查看培训和验证 RMSE 来快速了解一下培训流程:
我们的模型似乎是逐渐训练的,两个误差都随着时期数的增加而减小。请注意,您可能想要花更多的时间来训练您的模型,因为它可能会变得更好。
提出建议
最后,我们准备为用户提供一些建议。下面是predict
方法的实现:
首先,我们获得具有所有预测播放计数的矩阵。第二,我们获取所有未知播放计数的索引,并仅返回这些索引作为预测。让我们为特定用户提供一些建议:
在查看推荐列表之前,我们先来看看这个用户目前的偏好是什么:
以下是我们的模型给出的建议:
现在可能是去 YouTube 或 Spotify 上试试这些艺术家的好时机!
结论
恭喜你从零开始构建了一个高性能的推荐系统!您已经学会了如何:
- 为提出建议准备原始数据
- 从头开始实现简单的随机梯度下降
- 用这个模型来预测你可能真正喜欢的新艺人!
谷歌协作笔记本中的完整源代码
您能在数据集上应用同样的模型吗?在下面的评论里告诉我进展如何!
最初发表于https://www.curiousily.com。
喜欢你读的吗?你想了解更多关于机器学习的知识吗?提升你对 ML 的理解:
“我不能创造的,我不理解”——理查德·费曼这本书将引导你走向更深的…
leanpub.com](https://leanpub.com/hmls)
说出那种类型
用算法确定流派需要什么?
任何行业的流派都是主观的。定义会随着时间的推移而改变,你越想得到具体的定义,越多的人会愤怒地告诉你你错了。但是基本的类型将会有几个主要的方面,使它们更容易被识别。
在很大程度上,流派是由它们唤起的体验和共同的 T2 元素定义的。恐怖电影用可怕的怪物和令人不安的情节吓你,动作片用快速的汽车和没有情节把你放在座位的边缘。
It works really well though. (Source: giphy.com)
那么我们能通过算法预测流派吗?理想的过程应该是确定一个娱乐媒体的所有代表性特征,找出如何从原始资料中解读这些特征的价值,抓取一堆数据,将其投入一个分类算法,然后嘣,流派!
在尝试为音乐做这件事时,我中途遇到了 Spotify 的音频功能。他们在收集代表不同音乐流派目标体验的特征方面做得很好,比如可跳性或效价(一首歌有多“快乐”),以及节奏或调等结构元素。
**数据:**11 个流派各 100 首歌曲,全部来自 Spotify:蓝调、古典、乡村、迪斯科、hiphop、爵士、金属、流行、雷鬼、摇滚、电子。我为第一次运行保持了广泛的东西;我们不需要在流派数量上有太多的颗粒度,就能找到我们需要知道的东西。
everynoise.com has a ton of different, unique genres, and Spotify playlists for all of them.
工具: Spotipy 对于使用 Python 中的 Spotify API 来说是一个非常有用的库。我用它来收集这个项目的数据。 Sk-learn 非常适合构建和测试不同的模型,而 Pandas 非常适合存储数据。我还用 Flask 帮忙做了 app。
作为使用 Spotipy 的一个例子,我用来获取这 1100 首曲目数据的代码如下。我后来得到的数据帧也显示出来了。
**方法:**分类。名义上的目标类和对可解释模型的访问使它非常适合。我尝试了几个不同的模型,最后我用了一个随机森林,因为它给了我最好的精确度。我使用的特征是:可舞性、声音、语速、能量、响度、乐器性、效价、节奏、活力、基调和调式。
这一步是关于模型的。我将我的数据分为训练集和测试集,使用这些集训练所有这些模型,并基于以下方面做出我的决定…
**公制:**准确度。对于这个问题,最重要的是要知道预测的流派是否正确,所以唯一重要的统计数据是训练好的模型正确预测流派的频率。
Random Forest had the best accuracy of all the models I tried.
我收集了 1100 首歌曲的上述特征,将其分为训练集和测试集,在这些集上拟合各种模型,并制作了一个应用程序,让你可以在 Spotify 上搜索任何歌曲的预测流派。(警告:它有 63.64%的准确率,所以如果你认为它预测错了,你可能是对的:)
Spotify 的音频功能相当不错,但仅凭这些似乎不足以每次正确预测一个流派。我尝试了一些优化方法来获得更好的准确性分数,比如使用网格因子分解来尝试和优化模型超参数。我还标准化了速度的值,努力使它们与大多数其他值相比具有相似的尺度。然而,这些方法并没有产生非常重要的结果。接下来的步骤将包括 Spotify 的片段和节拍数据,他们按照歌曲结构的片段来划分歌曲,如合唱、桥段等。,并以均匀的时间间隔。我还会收集更多歌曲的数据。
按照我在开始时描述的理想过程,我们应该能够达到接近 100%的准确率。虽然很难确定具体的子类型,但是任何媒体的主要类型都是相当明确的。大多数体裁都有经常出现的比喻,这些比喻几乎总是一种或多种成分的特定风格。流派本身通常根据它们试图传达的体验来分类。真正的困难在于量化一种媒体的组成元素,使之有可能识别这些比喻。然而,一旦它们都被量化,预测流派就变得容易多了。这是另一个有趣的问题,但不幸的是,我将不得不把它留给另一篇文章。现在,享受预测一些流派吧!
附录
音乐听众统计:last.fm 的 last.year 作为 R 包
当开始用 last.week 和 last.year 函数分析last . FMscrobbbles 时,我总是缺少一些图表或纯数据表。这就是为什么我开发了包" analyzelastfm "作为一个简单的 R6 实现。我想有不同的专辑统计数据,例如,每张专辑的播放次数,除以专辑中的曲目数。这一点现已落实。要获得音乐收听统计数据,您可以从以下内容开始:
# If you don't have it, install devtools
# install.packages("devtools")
devtools::install_github("zappingseb/analyze_last_fm")
library(analyzelastfm)
首先,它允许您通过使用 last.fm REST API 导入您的 last.year 数据。因此,您需要有一个 last.fm API 密钥。这个只要去 last.fm API 网站就可以推导出来。从那里你将得到 32 个字符长的密钥。收到密钥后,我通过以下方式获得了 last.fm 数据:
api_key <- "PLEASE ENTER YOUR KEY HERE"
data <- UserData$new("zappingseb",api_key,2018)
数据对象现在包含函数albumstats
,它允许我获得我想要的特定信息。我会把艺术家“死德雷”排除在外???"因为这是一个来自德国的儿童侦探故事,我听了很多,它的专辑被分成 1 分钟的曲目,这真的打乱了我的统计。
View(data$albumstats(
sort_by="by_album_count", # album track plays / nr tracks on album
exclude_artist="Die drei ???", # exclude my audio book favorite
exclude_album=c(""), # exclude tracks without album name
min_tracks=5) # have minimum 5 tracks on the album (NO EPs)
)
结果看起来是这样的:
Album statistics of 2018 of zappingseb
统计数据显示了n
播放次数、count
专辑曲目数和count_by_track=n/count
。
你可以在这里找到前 5 张专辑:
除了这些计算,我还对我听音乐的时间感兴趣。因此我在包里添加了一些情节。第一个是监听时钟:
data$clock.plot()
Clock plot for my music history
我通常在早上 7 点到 8 点和下午 5 点到 6 点骑车上班的路上听音乐。我最重要的统计数据是我一年中听音乐的时间。我最感兴趣的是一些特定的日子和一个平均的游戏/月,这可以告诉我当时的心情。因此我创建了函数daily_month_plot
。它将每月平均播放次数和每日播放次数绘制在一个图中。每月的平均播放量可以在每日峰值后看到。这里你可以看到二月对我来说是一个非常平静的月份。
data$daily_month_plot()
对于一些简单的统计数据,我还包含了一个名为barplots
的聚合绘图函数。它可以按工作日、周、月或日绘制聚合图。该函数的数据由函数bar_data
提供。
data$barplots("weekdays")
每周(从 2017 年第 52 周开始):
data$barplots(“week”)
我可以清楚地看到,在今年年初,我并没有真正听很多音乐,到第 18 周,我的听力活动急剧增加。
这篇文章有点超出了我的范围,主要是关于 R 包对制药有用的包。但我真的很喜欢音乐,认为音乐和数据科学是很好的结合。声音在一起很棒!
请在https://github.com/zappingseb/analyze_last_fm找到 R 包——开始行动永远不晚;)
musicnn:一个开源的、基于深度学习的音乐标记器
musicnn 库(读作“音乐家”)采用深度卷积神经网络对歌曲进行自动标记,被收录的模型在公开评测基准中达到最好成绩。这些最先进的模型已经作为开源库发布,可以很容易地安装和使用。例如,你可以使用 musicnn 来标记这首来自 Muddy Waters 的标志性歌曲——它将主要将其标记为布鲁斯!
有意思的是,虽然 musicnn 对自己的蓝调预测相当有信心,但它也考虑到了(决心较小!)歌曲的某些部分可以被标记为爵士乐、灵魂乐、摇滚甚至乡村音乐——这些都是密切相关的音乐流派。请看上面这首歌的标签图(标签概率随时间的演变):
Taggram representation: Muddy Waters — see the evolution of the tags across time.
Vertical axis: tags. Horizontal axis: time. Model employed: MTT_musicnn
这个项目是由巴塞罗那的一个音乐和音频研究实验室开发的,是多年研究的成果。这个研究机构,Pompeu Fabra大学音乐技术小组以其对音乐和音频技术的研究而闻名。例如:他们贡献了开创性的歌唱语音合成引擎,如 Vocaloid ,或者他们维护开源项目,如 Freesound 。
这些研究人员开源了 musicnn,你只需安装它就可以使用:
pip 安装音乐
安装后,你只需要在终端运行这个一行程序,给你的歌曲加上 musicnn 标签——但是在他们的文档中你会找到更多选项,比如如何在 jupyter 笔记本上使用它:
python-m musicnn . tagger your _ song . MP3–print
既然你知道如何使用它,你可以试着自动标记《皇后乐队》的《波西米亚狂想曲》——看看你是否同意 musicnn 的预测(附后):
Taggram representation: Queen (Bohemian Rhapsody)— see the evolution of the tags across time.
Vertical axis: tags. Horizontal axis: time. Model employed: MTT_musicnn
请注意,合唱前奏被很好地检测到,以及钢琴和摇滚部分。一个特别有趣的困惑是佛莱迪·摩克瑞的声音被标记为女声!此外,该模型与其预测非常一致(无论是否是“合理的”混淆)。直到人们可以在标记图中清楚地识别歌曲的不同部分。例如,可以为具有相同结构的部分找到“重复模式”,或者该模型在检测歌声是否存在时相当成功。
要了解更多关于 musicnn 的信息,可以咨询作者们将在 ISMIR 2019 上发表的最新突破/演示文章或他们的 ISMIR 2018 文章(获得了这个国际科学场馆的最佳学生论文奖)。
关于 GANs 的必读论文
生成对抗网络是深度学习最有趣和最流行的应用之一。本文将列出 10 篇关于 GAN 的论文,它们将为您提供关于 GAN 的精彩介绍以及理解最新技术水平的基础。让我们来看看这份列表吧!
如果你对阅读每篇论文的描述不感兴趣,这里有一个快速列表:
1—dcgan
2 —训练 GANs 的改进技术
3—有条件的 GANs
4 —逐渐增长的天然气水合物
5 —比根
6 — StyleGAN
7 — CycleGAN
8 像素 2 像素
9 —堆栈根
10 —生成性敌对网络
拉德福德等人(2015 年)
我建议您从 DCGAN 白皮书开始您的 GAN 之旅。本文展示了如何将卷积层用于 GANs,并为此提供了一系列额外的架构指南。论文还讨论了诸如 GAN 特征可视化、潜在空间插值、使用鉴别器特征训练分类器以及结果评估等主题。所有这些额外的主题一定会出现在你的 GAN 研究中。总之,DCGAN 论文是一篇必须阅读的 GAN 论文,因为它以如此清晰的方式定义了架构,以至于很容易从一些代码开始,并开始开发 GAN 的直觉。
DCGAN model — generator architecture with upsampling convolutional layers
[## 深度卷积生成对抗网络的无监督表示学习
近年来,卷积网络的监督学习(CNN)在计算机视觉领域得到了广泛应用…
arxiv.org](https://arxiv.org/abs/1511.06434)
训练 GANs 的改进技术——Salimans 等人(2016 年)
这篇文章(作者包括 Ian Goodfellow)提供了一系列建议,用于在上面的 DCGAN 文章中列出的体系结构指南的基础上进行构建。本文将帮助你理解 GAN 不稳定性的最佳假设。此外,本文还提供了许多旨在稳定 DCGANs 训练的附加技术。这些包括特征匹配、小批量鉴别、历史平均、单侧标签平滑和虚拟批量标准化。使用这些建议构建一个简单的 DCGANs 实现是学习更多关于 gan 的一个很好的练习。
[## 训练 GANs 的改进技术
我们提出了各种新的建筑特点和培训程序,我们适用于生成性对抗…
arxiv.org](https://arxiv.org/abs/1606.03498)
有条件的 GANs — Mirza 和 Osindero (2014 年)
这是一篇很棒的论文,可以快速阅读。有条件的 GANs 是最先进的 GANs 的核心主题。本文展示了集成数据的类别标签如何产生更稳定的 GAN 训练。这种用先验信息调节 GAN 的概念在 GAN 研究的未来工作中是一个反复出现的主题,对于专注于图像到图像或文本到图像的论文尤其重要。
Architecture of the Conditional GANs, in addition to the random noise vector z, the class label y is concatenated together as input to the network
[## 条件生成对抗网
生成对抗网[8]是最近引入的一种训练生成模型的新方法。在这项工作中,我们…
arxiv.org](https://arxiv.org/abs/1411.1784)
逐步种植 gan 以提高质量、稳定性和变化性——Karras 等人(2017 年)
由于其令人印象深刻的结果和解决 GAN 问题的创造性方法,日益增长的 GAN 架构是必读的。本文使用多尺度架构,其中 GAN 的分辨率从 4 到 8,最高可达 1024。GAN 不稳定性相对于目标图像分辨率大小大大增加,本文给出了解决该问题的方法。
This image depicts the multi-scale architecture of the Progressively Growing GAN architecture. The model goes from 4² progressively up to 1024²
[## 为了提高质量、稳定性和多样性而逐步种植甘蔗
我们描述了一种新的生成式对抗网络的训练方法。关键的想法是增长发电机…
arxiv.org](https://arxiv.org/abs/1710.10196)
比根-布洛克等人(2019 年)
BigGAN 模型是 ImageNet 生成的最新技术。这个模型很难在本地机器上实现,该架构有许多组件,如自关注、光谱归一化和带投影鉴别器的 cGAN,这些组件在各自的论文中有更好的解释。然而,这篇文章提供了一个很好的概述,包括当前最先进的基础论文的思想。
Unbelievable samples from the BigGAN state-of-the-art model
[## 用于高保真自然图像合成的大规模 GAN 训练
尽管最近在生成图像建模方面取得了进展,但成功地从图像生成高分辨率、多样化的样本…
arxiv.org](https://arxiv.org/abs/1809.11096)
StyleGAN-Karras 等人(2019 年)
StyleGAN 模型可以说是最先进的,尤其是在潜在空间控制方面。这个模型借用了一种被称为自适应实例规范化(AdaIN)的神经风格转移机制,来控制潜在空间向量 z,这与之前的任何东西都不同。映射网络和 AdaIN 调节在整个生成器模型中的分布相结合,使得自己实现起来相当困难,但它仍然是一个很好的读物,包含许多有趣的想法。
StyleGAN architecture that allows for state-of-the-art latent space control
[## 一种基于风格的生成对抗网络生成器体系结构
我们借鉴风格转移理论,提出了一种新的生成对抗网络生成器结构
arxiv.org](https://arxiv.org/abs/1812.04948)
CycleGAN —朱等(2017)
CycleGAN 的论文不同于前面提到的 6 篇论文,因为它讨论的是图像到图像的转换问题,而不是从随机向量合成图像。CycleGAN 更具体地处理图像到图像转换的情况,其中没有成对的训练样本。然而,这是一篇值得一读的好文章,仅仅是因为周期一致性损失公式的优雅和这如何稳定 GAN 训练的直觉。CycleGAN 还可以用于许多很酷的应用,如超分辨率、风格转换和马到斑马。
Central Idea behind the Cycle Consistency Loss, a sentence translated from French to English and back to French should be the same sentence
[## 使用循环一致对抗网络的不成对图像到图像翻译
图像到图像的翻译是一类视觉和图形问题,其目标是学习图像和图形之间的映射
arxiv.org](https://arxiv.org/abs/1703.10593)
Pix2Pix — Isola 等人(2016 年)
Pix2Pix 是另一种图像到图像转换 GAN 模型。该框架使用成对的训练样本,并在 GAN 模型中用许多不同的配置进行研究。在阅读这篇论文时,我最感兴趣的事情之一是关于 PatchGAN 的讨论。PatchGAN 查看图像的 70 x 70 个区域来确定它们是真的还是假的,而不是查看整个图像。这个模型还展示了一个有趣的 U-Net 风格的生成器架构,以及在生成器模型中使用 ResNet 风格的跳过连接。这有许多很酷的应用,如边缘映射到照片般逼真的图像。
Image-to-Image translation with paired training samples
[## 基于条件对抗网络的图像到图像翻译
我们研究条件对抗网络作为图像到图像翻译问题的通用解决方案…
arxiv.org](https://arxiv.org/abs/1611.07004)
StackGAN —张等(2017)
StackGAN 的论文与列表中的前几篇论文非常不同。它非常类似于有条件的 gan 和渐进增长的 gan。StackGAN 模型的工作原理类似于渐进式增长的 GAN,因为它适用于多种规模。StackGAN 首先输出分辨率为 64 的图像,然后将其作为先验信息来生成分辨率为 256 的图像。StackGAN 与其他论文非常不同,因为它是从自然语言文本到图像的。这是通过改变文本嵌入来实现的,以便它捕获视觉特征。这是一篇非常有趣的论文,如果能看到 StyleGAN 中展示的潜在空间控制与 StackGAN 中定义的自然语言接口相结合,那将是令人惊讶的。
Idea behind the StackGAN multi-scale architecture conditioned on a text embedding
[## StackGAN:利用堆叠生成式对抗网络进行文本到照片的真实感图像合成
从文本描述中合成高质量的图像是计算机视觉中一个具有挑战性的问题,有许多应用前景
arxiv.org](https://arxiv.org/abs/1612.03242)
生成性对抗网络——good fellow 等人(2014 年)
Ian Goodfellow 的原始论文是任何研究 GANs 的人的必读之作。本文定义了 GAN 框架并讨论了“非饱和”损失函数。本文还给出了最佳鉴别器的推导,这一证明在最近的 GAN 论文中经常出现。本文还在 MNIST、TFD 和 CIFAR-10 图像数据集上验证了 GAN 的有效性。
[## 生成对抗网络
我们提出了一个新的框架,通过一个对抗的过程来估计生成模型,在这个过程中,我们同时…
arxiv.org](https://arxiv.org/abs/1406.2661)
感谢阅读!我提供了许多发表在 TowardsDataScience 上的这些论文的博文摘要,如下所列:
生成对抗网络最有趣的部分之一是生成网络的设计。的…
towardsdatascience.com](/dcgans-deep-convolutional-generative-adversarial-networks-c7f392c2c8f8) [## 深入到 DCGANs
进一步探索 GAN 过拟合、GAN 特征可视化和潜在空间插值等主题。
towardsdatascience.com](/deeper-into-dcgans-2556dbd0baac) [## 用 DCGANs 生成篮球鞋
在 Keras 中实现 DCGANs 以生成 45x45 篮球鞋图像的代码、结果和分析。
medium.com](https://medium.com/@connorshorten300/generating-basketball-shoes-with-dcgans-6cd72d521c01) [## 条件甘斯
条件 GAN[1]是 GAN 框架的一个非常有趣的扩展。这种架构扩展了原有的…
medium.com](https://medium.com/@connorshorten300/conditional-gans-639aa3785122) [## Pix2Pix
本文将解释一篇关于图像到图像翻译的流行论文的基本机制
towardsdatascience.com](/pix2pix-869c17900998) [## 渐进增长的甘斯
NVIDIA 发布并在 ICLR 2018 上发布的逐步增长的 GAN 架构已经成为主要的…
towardsdatascience.com](/progressively-growing-gans-9cb795caebee)