生活帮网络报废
网络报废让我的生活变得简单多了。然而,从大多数网站中提取内容的过程从来没有真正被提及过。这使得处理信息几乎不可能
为什么?
网络报废让我的生活变得简单多了。然而,从使用专有系统锁定内容的网站中实际提取内容的过程从未被真正提及。这使得将信息重新格式化成期望的格式即使不是不可能,也是极其困难的。几年来,我发现了几种(几乎)防失败的技术来帮助我,现在我想把它们传递下去。
我将带您了解将纯网络书籍转换为 PDF 的过程。这里的想法是强调如何根据自己的情况复制/修改它!
如果你有任何其他的技巧(或者有用的脚本)来完成这样的任务,一定要让我知道,因为创建这些生活黑客脚本是一个有趣的爱好!
封面图片来源于此处
再现性/适用性?
我列举的例子来自一个只提供学习指南的网站(为了保护他们的安全,我排除了特定的网址)。我概述了几个经常出现在网络废弃时的缺陷/问题!
要犯的错误?
我在试图搜索受限访问信息时犯了几个错误。每一个错误都消耗大量的时间和能量,所以它们是:
- 使用 AutoHotKey 或类似的来直接影响鼠标/键盘(这种会产生躲闪 不一致的行为)
- 加载所有页面,然后导出一个 HAR 文件(HAR 文件没有实际数据,需要很长时间才能加载)
- 尝试使用 GET/HEAD 请求(大多数页面使用授权方法,这实际上是不可逆的)
进展缓慢
为这些网站写一个 300 行的简短脚本似乎很容易/很快,但它们总是比这更困难。以下是解决方案的潜在障碍:
- Selenium changing 使用的浏览器配置文件
- 以编程方式查找配置文件
- 不知道要等多久才能加载链接
- 当链接不等于当前链接时进行检测
- 或者使用浏览器 JavaScript(可能的话,将在下面详细描述)
- 需要找到关于当前网页内容的信息
- 看看潜在的 JavaScript 函数和 URL
- 失败时重新启动长脚本
- 减少文件的查找次数
- 将文件复制到可预测的位置
- 在开始做任何复杂的事情之前,检查这些文件
- 不知道一个长的脚本是什么
- 打印任何必要的输出(仅用于那些花费大量时间且没有其他度量的输出)
密码
准备工作
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from PIL import Image
from natsort import natsorted
import time
import re
import os
import shutil
import img2pdf
import hashlibdriver = webdriver.Firefox()
cacheLocation = driver.capabilities['moz:profile'] + '/cache2/entries/'
originalPath = os.getcwd()
baseURL = 'https://edunlimited.com'
装载书
driver.get(loginURL)
driver.get(bookURL)
wait.until(lambda driver: driver.current_url != loginURL)
获取元数据
经常可以找到用于提供有用信息的 JavaScript 函数。有几种方法可以做到这一点:
- 查看页面的 HTML 源代码(右键单击“查看页面源代码”)
- 使用 web 控制台
bookTitle = driver.execute_script('return app.book')
bookPages = driver.execute_script('return app.pageTotal')
bookID = driver.execute_script('return app.book_id')
组织文件
脚本通常不会按预期执行,有时需要很长时间才能完成。因此,在脚本的迭代过程中保持进度是相当自由的。实现这一点的一个好方法是保持有条理!
if not os.path.exists(bookTitle):
os.mkdir(bookTitle)
if len(os.listdir(bookTitle)) == 0:
start = 0
else:
start = int(natsorted(os.listdir(bookTitle), reverse=True)[0].replace('.jpg', ''))
driver.execute_script('app.gotoPage(' + str(start) + ')')
os.chdir(bookTitle)
浏览这本书
图像总是存储在缓存中,所以当其他方法都失败时,就利用这一点吧!
不过这并不容易,首先我们需要加载页面,然后我们需要以某种方式恢复它!
为了确保我们总是加载整个页面,有两种安全措施:
- 在移动到下一页之前,等待当前页面加载
- 如果无法加载,则重新加载页面
让这两者工作需要保证完成(JavaScript 或浏览器响应)的函数,以及故障安全等待时间跨度。安全时间跨度是反复试验的,但是通常在 0.5 到 5 秒之间效果最好。
直接从硬盘缓存中恢复特定数据是一个相对模糊的话题。关键是首先找到一个下载链接(通常很容易,因为不需要工作)。然后在 URL 上运行 SHA1 、十六进制摘要和一个大写函数,产生最终的文件名(它不仅仅是上述安全算法中的一个,因为旧的来源让你相信,而是两个都有)。
最后一点,确保现在而不是以后清理数据(从 PNG 图像中删除 alpha 通道),因为它减少了代码中使用的循环次数!
for currentPage in range(start, bookPages - 1):
while driver.execute_script('return app.loading') == True:
time.sleep(0.5)
while (driver.execute_script('return app.pageImg') == '/pagetemp.jpg'):
driver.execute_script('app.loadPage()')
time.sleep(4)
location = driver.execute_script('return app.pageImg')
pageURL = baseURL + location
fileName = hashlib.sha1((":" + pageURL).encode('utf-8')).hexdigest().upper()
Image.open(cacheLocation + fileName).convert('RGB').save(str(currentPage) + '.jpg')
driver.execute_script('app.nextPage()')
转换为 PDF
我们终于可以得到一个方便的 PDF 文件
finalPath = originalPath + '/' + bookTitle + '.pdf'
with open(finalPath, 'wb') as f:
f.write(img2pdf.convert([i for i in natsorted(os.listdir('.')) if i.endswith(".jpg")]))
移除多余的图像
os.chdir(originalPath)
shutil.rmtree(bookTitle)
封面图片来源于此处
感谢阅读!
这基本上是我在博客上发表的第一篇以代码为中心的文章,所以我希望它有用!
———下次见,我要退出了
我们为一家大型科技客户部署的终身价值模型
查尔斯·德鲁维奥在 Unsplash 上拍摄的照片
让我深入研究一下。我曾与一家科技公司合作,该公司为零售商提供数字化传单和优惠券。公司是怎么赚钱的?本质上,优惠券的点击量。
有一天,公司的高层路过我们的办公室,问我们——“我们能知道用户在年底积累了什么价值吗?”就这样,我们开始了机器学习的冒险。
我们着手建立一个预测客户终身价值的模型。而且,我们将它生产化,并让它在服务器上端到端地自动运行,以预测所有用户的生命周期价值。
我想利用这次经历来强调实际模型的部署与学校教授机器学习的方式有多么不同。
模型目标和用例
我们想看看年底客户的价值是多少。用例是使用预测的客户终身价值来为用户定制营销策略,并限制每个给定已获得用户群的购买支出。
技术堆栈
该模型是在 Spark 上创建的,我们使用 Scala MLlib 来创建模型和转换器类。如果你不熟悉 MLlib,不要太担心它——它与 scikit learn 非常相似,只是它是针对分布式数据集而不是本地 pandas 数据帧的。
我们如何设置数据
我们拥有的数据是用户和这些用户随时间积累的一些参与度指标。我们可以使用这些参与度指标来计算任何给定用户在任何给定日期累积的收入。我不会深入研究数据的结构,因为这个模型是为一个真实的客户设计的,我想确保不会透露太具体的内容。但是在他们的许可下,这里有一个数据外观的摘要。
用户年龄定义为用户在我们平台上的天数
如您所知,这是一个为期 1 年的终身价值计算。因此,要构建一个模型来预测给定日期一年后的收入,我们需要确保我们有至少 365 天的用户数据。
从原始的非结构化数据创建基表需要相当多的聚合。此外,可伸缩性变得非常重要,因为聚合大量非结构化数据的成本非常高。
另外,关于建筑特征的说明。我们创造了很多很多功能。然后,我们将使用特征选择、维数减少和特征重要性标准来减少特征的数量。
下一步是将数据分成训练和测试数据。
设置列车并测试
然后,数据集被分成训练和测试子集。训练数据集用于训练模型,测试数据集用于跟踪模型的表现。
在生产中,我们如何使用测试数据集?我们首先用它来选择最佳模型。此外,我们用它来跟踪误差的训练模型随着时间的推移。所以,我们会在第一天训练一个模型。然后我们想在第 1、2、3 天等测试模型。然后,我们希望看到误差从哪一天开始增加,这决定了我们希望重新训练模型的时间间隔。
车型
我们做了一些探索性的数据分析,并深入到模型中。我们有一堆预测变量,比如用户第一天的收入,等等。我们想要预测的变量是用户在第 365 天的收入。
这显然是一个回归问题,所以我们用了几个回归算法来解决它,在数据维数相当高的情况下,最有效的算法是回归树和回归树的集合。
我们想尝试不同的算法。我们想尝试使用和不使用 PCA 的算法来降低维数。我们想尝试使用不同的列功能集。这个名单还在继续。我们想尝试许多不同的排列。我们是怎么做到的?我们设置了一个接口函数,允许我们在不重写整个脚本的情况下为每个模型迭代尝试许多不同的参数。
误差度量和监控误差
我们选择的误差函数是 RMSE。因此,每次模型迭代的目标都是最小化 RMSE 成本函数。
管道结构:
那么,我们来想一想,模型在生产中是如何工作的?
首先,我们创建测试和训练数据集。这些测试每天运行,我们收集测试数据集的错误指标。这让我们知道模型性能显著下降大约需要多长时间。然后,如果模型性能在 x 天后下降,我们根据最新数据单独重新训练模型。
然后,重新训练的模型被保存到 S3。在 S3,这些模型每天都被用来给用户打分。因此,在任何一天,我们都会调用我们所有的用户。每个用户都有不同的年龄。每个用户,以及他们在某个年龄积累的指标,都将被输入到机器学习模型中。一旦模型完成了对所有用户的预测,我们就为每个用户生成一个预测。所以,下面提供了最终的表格。
结论
我几乎没有触及我们如何部署机器学习模型的复杂逻辑。因此,我在这篇文章中想要做的是摆脱大多数课程中如何教授机器学习以及它实际上如何部署的范式。首先,没有干净的数据集可供你进行机器学习。实际上,你要做的大部分工作将是为机器学习构建特征和基表。此外,当您在数据上拟合实际的机器学习算法时,您会希望拟合许多参数排列。因此,构建函数时要允许你尝试不同的组合。
最后,最好考虑一下所有的东西是如何联系在一起的。新的基表什么时候生成,机器学习模型什么时候运行?您将如何使用来自已训练模型的错误度量来告知模型重新训练的频率?你将如何给你的用户打分?所有这些细微差别都是机器学习如此复杂和迷人的原因。
LightGBM
梯度助推器
那个说国王裸体的人
在准确性和性能方面,XGBoost 统治了一段时间,直到一个竞争者接受了挑战。LightGBM 来自微软研究院,是一种更高效的 GBM,随着数据集的规模不断增长,它成为了当务之急。LightGBM 比 XGBoost 更快,并且在某些情况下精度也更高。尽管 XGBoost 做了一些改变并实现了 LightGBM 提出并赶上的创新,但 LightGBM 已经引起了轰动。它成为许多卡格尔比赛中获胜组合的主要组成部分。
来源: Unsplash
LightGBM 的起点是 XGBoost 。所以本质上,他们采用了 XGBoost 并对其进行了优化,因此,它拥有了 XGBoost 的所有创新(或多或少),以及一些额外的创新。让我们来看看 LightGBM 所做的增量改进:
树木逐叶生长
与所有其他 GBM(如 XGBoost)的主要变化之一是树的构造方式。在 LightGBM 中,采用了逐叶的树生长策略。
所有其他流行的 GBM 实现都遵循一种叫做逐层树生长的方法,在这种方法中,你可以找到最好的节点进行分割,然后将它向下分割一层。这种策略将产生对称树,其中一级中的每个节点都有子节点,从而产生额外的深度层。
在 LightGBM 中,逐叶树生长会找到最大程度上减少损失的叶子,并且只分裂那片叶子,而不关心同一层中的其余叶子。这导致不对称的树,其中随后的分裂很可能仅发生在树的一侧。
与逐层生长策略相比,逐叶树生长策略倾向于实现较低的损失,但是它也倾向于过度拟合,尤其是小数据集。如此小的数据集,水平方向的增长就像一个正则化来限制树的复杂性,而叶子方向的增长往往是贪婪的。
基于梯度的单侧采样(GOSS)
子采样或下采样是我们在集合中引入多样性并加速训练过程的方式之一。这也是一种正则化形式,因为它限制了对完整训练数据的拟合。通常,这种二次采样是通过从训练数据集中抽取随机样本并在该子集上构建一棵树来完成的。但是 LightGBM 引入了一种智能的方式来进行下采样。
这个想法的核心是,不同样本的梯度是一个指标,表明它在树构建过程中发挥了多大的作用。具有较大梯度(训练不足)的实例比具有小梯度的实例对树构建过程贡献更多。因此,当我们向下采样时,我们应该努力保持具有大梯度的实例,以便树的构建是最有效的。
最直接的想法是丢弃低梯度的实例,只在大梯度的实例上构建树。但这将改变数据的分布,进而损害模型的准确性。因此,高斯方法。
算法非常简单:
- 保留所有具有大梯度的实例
- 对具有小梯度的实例执行随机采样
- 当在树构建过程中计算信息增益时,为具有小梯度的数据实例引入常数乘数。
如果我们选择梯度大的 a 实例,随机采样梯度小的 b 实例,我们通过 (1-a)/b 放大采样数据
独家功能捆绑(EFB)
EFB 背后的动机是 LightGBM 和 XGBoost 的共同主题。在许多现实世界的问题中,虽然有很多特征,但大多数都很稀疏,就像热门的编码分类变量。LightGBM 处理这个问题的方式略有不同。
这个想法的关键在于这样一个事实,即这些稀疏特征中的许多是排他的,即它们不同时取非零值。我们可以有效地将这些功能捆绑在一起,并将其视为一体。但是找到最佳的特性包是一个 NP 难的问题。
为此,本文提出了一种贪婪的近似方法,即排他性特征捆绑算法。该算法本质上也有点模糊,因为它将允许并非 100%互斥的捆绑特征,但是当选择捆绑时,它试图保持准确性和效率之间的平衡。
该算法在较高层次上是:
- 构建一个包含所有特征的图,用代表特征间冲突总数的边进行加权
- 按照图中要素的度数以降序对其进行排序
- 检查每个特性,或者将其分配给存在小冲突的现有包,或者创建一个新包。
基于直方图的树分裂
构建一棵树所花费的时间与需要评估的分裂数量成正比。当具有高基数的连续或分类要素时,这一时间会急剧增加。但是,可以为一个特性进行的大多数拆分在性能上只会带来微小的变化。这个概念就是为什么基于直方图的方法被应用于树构建。
核心思想是将特征分组到一组箱中,并基于这些箱执行分割。这降低了从 O(#data) 到*O(# bin)*的时间复杂度。
稀疏输入
在另一项创新中,与 XGBoost 类似,LightGBM 在创建直方图时会忽略零特征值。并且这将构建直方图的成本从O(#数据)降低到O(#非零数据)。
分类特征
在许多真实世界的数据集中,分类特征大量存在,因此适当地处理它们变得至关重要。最常见的方法是将分类特征表示为一键表示,但这对于树学习者来说是次优的。如果您有高基数分类特征,您的树需要非常深才能达到准确性。
LightGBM 接受一个分类特征列表作为输入,以便更好地处理它。它从 Fisher,Walter D .的“关于最大同质性的分组”中获得灵感,并使用以下方法来寻找分类特征的最佳分割。
- 对累积梯度统计的直方图进行排序
- 在排序的直方图上找到最佳分割
有几个超参数可以帮助您调整处理分类特征的方式[4]:
cat_l2
,默认=10.0
,类型=双精度,约束:cat_l2 >= 0.0
cat_smooth
,默认=10.0
,类型=双精度,约束:cat_smooth >= 0.0
- 用于分类特征
- 这可以减少分类特征中噪声的影响,特别是对于数据很少的类别
max_cat_to_onehot
,默认=4
,类型= int,约束:max_cat_to_onehot > 0
性能改进
大多数增量性能改进是通过戈斯和 EFB 完成的。
xgb_exa 是最初的 XGBoost,xgb_his 是基于直方图的版本(后来出的),lgb_baseline 是没有 EFB 和戈斯的 LightGBM,LightGBM 有 EFB 和戈斯。很明显,与 lgb_baseline 相比,戈斯和 EFB 的改进是显著的。
其余的性能改进来自并行化学习的能力。并行学习过程有两种主要方式:
特征平行
特征并行试图以分布式方式并行化“寻找最佳分割”部分。评估不同的拆分是在多个工人之间并行完成的,然后他们互相交流,决定谁的拆分最好。
数据并行
数据并行试图将整个决策学习并行化。在这种情况下,我们通常会分割数据,并将数据的不同部分发送给不同的工作人员,他们根据收到的数据部分计算直方图。然后,它们进行通信以在全局级别合并直方图,并且该全局级别直方图是在树学习过程中使用的。
平行投票
投票并行是数据并行的一个特例,其中数据并行的通信开销被限制为一个常数。
超参数
LightGBM 是一种有很多超参数的算法。它是如此的灵活,以至于对初学者来说是令人生畏的。但是有一种方法可以使用该算法,并且仍然不需要调整 80%的参数。让我们看看几个参数,你可以开始调整,然后建立信心,并开始调整其余的。
objective
🔗︎ ,默认=regression
,类型=枚举,选项:regression
,regression_l1
,huber
,fair
,poisson
,quantile
,mape
,gamma
,tweedie
,binary
,multiclass
,multiclassova
,cross_entropy
,cross_entropy_lambda
,lambdarank
,rank_xendcg
,别名:objective_type
,app
,application
boosting
🔗︎ ,默认=gbdt
,类型=枚举,选项:gbdt
,rf
,dart
,goss
,别名:boosting_type
,boost
learning_rate
🔗︎ ,默认=0.1
,类型=双精度,别名:shrinkage_rate
,eta
,约束:learning_rate > 0.0
- 收缩率
- 在
dart
中,它也影响被丢弃树木的归一化权重 num_leaves
🔗︎ ,默认=31
,类型= int,别名:num_leaf
,max_leaves
,max_leaf
,约束:1 < num_leaves <= 131072
max_depth
🔗︎ ,默认=-1
,类型= intmin_data_in_leaf
🔗︎ ,默认=20
,类型= int,别名:min_data_per_leaf
,min_data
,min_child_samples
,约束:min_data_in_leaf >= 0
min_sum_hessian_in_leaf
🔗︎ ,默认=1e-3
,类型=双精度,别名:min_sum_hessian_per_leaf
,min_sum_hessian
,min_hessian
,min_child_weight
,约束:min_sum_hessian_in_leaf >= 0.0
lambda_l1
🔗︎ ,默认=0.0
,类型=双精度,别名:reg_alpha
,约束:lambda_l1 >= 0.0
lambda_l2
🔗︎ ,默认=0.0
,类型=双精度,别名:reg_lambda
,lambda
,约束:lambda_l2 >= 0.0
- 贪婪函数近似:一种梯度推进机器。安。统计学家。29 (2001 年),第 5 号,1189-1232。
- 柯,等(2017)。LightGBM:一种高效的梯度推进决策树。神经信息处理系统进展,3149-3157 页
- 沃尔特·d·费希尔。关于最大同质性的分组。美国统计协会杂志。第 53 卷,第 284 期(1958 年 12 月),第 789-798 页。
- LightGBM 参数。https://github . com/Microsoft/light GBM/blob/master/docs/parameters . rst # core-parameters
原载于 2020 年 2 月 20 日http://deep-and-shallow.com。
LightGBM 算法:树到数据帧方法的端到端评述
LightGBM 最近获得了一种称为“trees_to_dataframe”的新方法,它允许您将构成 lightGBM 模型的多个树估计器转换为可读的 pandas 数据框架。该方法增加了模型的可解释性,并允许您在粒度级别上理解影响任何数据点预测的划分。在本文中,我将构建一个简单的模型,并向您展示“trees_to_dataframe”的输出,以帮助您理解如何解释日常使用的数据帧。
什么是 LightGBM:
对于本文,我将使用以下学术论文作为参考:https://papers . nips . cc/paper/6907-light GBM-a-highly-efficient-gradient-boosting-decision-tree。
Light GBM 是一种梯度增强集成方法,其特征在于:
- 单侧采样(GOSS) :仅使用具有较大梯度的数据点来估计信息增益(使用较少的观测值获得信息增益的精确估计。这使得它更轻——因此它的名字是:LightGBM。术语预警!我们将梯度定义为我们试图最小化的损失函数的负导数。
- 排他性特征捆绑(EFB): 将很少出现非零值的特征捆绑在一起,用于相同的观察(例如:独热编码)。
- **基于直方图的分割:**使用更有效的基于直方图的宁滨策略来寻找数据中的分割点。这也使得它比常规的梯度推进算法更快。
练习:
为了深入研究 LightGBM 使用树来数据化框架的可解释性,我将使用移动价格分类 Kaggle 数据集。我们的模型将被训练来预测手机的价格范围。
原始数据集的目标变量用数字编码成从零(0)到三(3)的 4 个类别。因为这个练习的目的不是预测,而是理解如何解释 LightGBM 的“trees_to_dataframe”方法,所以我将简化我们的练习,把目标变量分成二进制类别,而不是多类。从价格范围零(0)到价格范围一(1),我将编码为 0,从价格范围二(2)到三(3),我将编码为 1。我也不会把数据分成训练和测试。
该数据集包含以下功能:“电池电量”、“蓝色”、“时钟速度”、“双 sim”、“fc”、“四 g”、“int_memory”、“m_dep”、“mobile_wt”、“n_cores”、“pc”、“px_height”、“px_width”、“ram”、“sc_h”、“sc_w”、“talk_time”、“three_g”、“touch_screen”和“wifi”。
为了充分理解树到数据帧的方法,我将放弃使用测试数据。我将训练一个特意简单的模型,只包含三个估计器,最大深度为 3。在 Kaggle 笔记本内核中,我开始安装最新的 LightGBM 版本,因为“trees_to_dataframe”方法最近被集成到算法的源代码中。
使用下面的代码,我创建了一个训练数据集,我将使用它来生成我将要分析的 lightGBM 模型。
这里有木星的代码
从 basic_model.trees_to_dataframe()中,我们获得了一个包含以下各列的 pandas 数据帧:’ tree_index ‘,’ node_depth ‘,’ node_index ‘,’ left_child ‘,’ right_child ‘,’ parent_index ‘,’ split_feature ‘,’ split_gain ‘,’ threshold ',
’ decision _ type ‘,’ missing_direction ‘,’ missing_type ‘,’ value ‘,’ weight ',
’ count '。我们将探究这些分别代表什么。
图 1:获得的数据帧的第一行。
图 2:算法的第一棵树(估计器)。
树索引:
树索引是指我们正在查看的树。在这种情况下,我们看到的是索引为 0 的树。第一个估计量。
节点深度:
指示分区发生的级别。例如,第一行引用节点深度 1,这是第一个分区(节点索引 0-S0)。
节点索引,左子节点和右子节点,父节点:
指示节点的索引及其“子节点”的索引。换句话说,当前节点分区到的要创建的节点。父节点是指当前节点所在的节点。因为 0-S0 是第一个分区,所以它没有父节点。
分割特征:
该功能对节点进行分区以创建子节点或叶。
分割增益:
通过以下方式测量分割质量。
阈值:
用于决定观察是前进到节点的左侧子节点还是右侧子节点的特征值。
缺少方向:
指示缺少的值转到哪个子节点(基于决策类型)。
价值:
这些是粗略的预测。详情请参见附录示例 A.1。
重量
用于分割增益计算。
计数:
计数是落在节点内的观察值的数量。
附录 A.1:
让我们遵循下面的观察:
我们的 LightGBM 算法有三个估计器:
在估计值 0 中,我们的观察结果落在叶子 1: ram 为 2549,battery_power 为 842。第一个叶的叶值是 0.496250。
在估计器 1 中,观察值落在叶子 7 中:ram 为 2549,battery_power 为 842。估计量 1 中叶 7 的值是 0.044437。
在估计器 2 中,观察值落在叶 1 中:ram 为 2549,battery_poer 为 842。叶 1 的值是-0.001562。
我们将数据点所在的不同叶的值相加:
0.49625 + 0.044437 — 0.001562 = .539125
总之,新推出的 lightGBM“trees _ to _ data frame”方法通过将 light GBM 模型转换为 pandas 数据框架,成为一个可解释的工具。通过允许您在较低的级别读取多个分区标准,以及每个数据点所属的叶值,该方法增加了透明度,并有助于更好地理解影响任何数据点预测的决策。
[## ana prec 07/notebook 133 a3 e 568-1-Jovian
在 anaprec07/notebook 133 a3 e 568-1 笔记本上与 ana prec 07 协作。
jovian.ai](https://jovian.ai/anaprec07/notebooke133a3e568-1)
关于我:
[## Ana Preciado -数据科学家-COVIDPTY.com | LinkedIn
联系人:anamargaritapreciado@gmail.com |+(507)61305543。自从我做了电子商务的本科研究后,我…
www.linkedin.com](https://www.linkedin.com/in/anapreciado/)
分位数回归的 LightGBM
了解分位数回归
对于回归预测任务,并非所有时候我们都只追求绝对准确的预测,事实上,我们的预测总是不准确的,因此,我们不寻求绝对精度,有时需要预测区间,在这种情况下,我们需要分位数回归,即我们预测目标的区间估计。
损失函数
幸运的是,强大的lightGBM
使分位数预测成为可能,分位数回归与一般回归的主要区别在于损失函数,这被称为弹球损失或分位数损失。弹球损失在这里有一个很好的解释,它有公式:
其中y
是实际值,z
是预测值,𝛕是目标分位数。所以第一眼看到损失函数,我们可以看到,除了当分位数等于 0.5,损失函数是不对称的。让我们来看看:
实现可以在我的 Git Repo 上找到。在图中,绘制了三个不同的分位数,以分位数 0.8 为例,当误差为正时(z > y
—预测值高于实际值),损失小于误差为负时的损失。在另一个世界中,更高的误差受到更少的惩罚,这是有意义的,因为对于高分位数预测,损失函数鼓励更高的预测值,反之对于低分位数预测。
生成样本数据集
现在让我们为 lightGBM 预测生成一些数据。
这里我们使用一个 sin(x)函数和一些额外的噪声作为训练集。
LightGBM 预测
发起LGMRegressor
:
注意和一般回归不同的是,objective
和metric
都是quantile
,alpha
是我们需要预测的分位数(详情可以查看我的 Repo )。
预测可视化
现在让我们看看分位数预测结果:
我们可以看到,大多数噪声点位于预测范围内,其中绿线是 0.9 分位数的上限,蓝色是 0.1 分位数。
这篇文章最初是受 this 的启发,这是一个很好的起点分位数回归启动器。
Spark 中的 LightGBM 超参数调谐
网格搜索,顺序搜索,远视…
克里斯多夫·伯恩斯在 Unsplash 上拍摄的照片
LightGBM 在各行各业的数据科学家中非常受欢迎。lightgbm 包用 Python 和 r 开发的很好,当数据越来越大的时候,人们希望在分布式数据框架的集群上运行模型。
我最近在 Azure Databricks 上开发一个推荐系统。项目中使用了 LightGBM 模型。超参数调整部分不像在 Python 中那样平滑。在这篇博客中,我将分享我在调优时尝试过的 3 种方法。正在调整的参数有:
- numLeaves
- 最大深度
- 袋装馏分
- 特征分数
- 明苏姆·谢宁利夫
- lambdaL1
- lambdaL2
这里用的 LightGBM 包是 mmlspark ,微软机器学习 for Apache Spark。
网格搜索
网格搜索是一种蛮力方法。如果你有无限的计算能力,这种方法可以保证你的最佳超参数设置。以下代码显示了如何对 LightGBM 回归器进行网格搜索:
我们应该知道网格搜索有维度的诅咒。随着参数数量的增加,网格呈指数增长。在我的实践中,上面的网格设置永远不会在我的 exploring 集群上以下面的设置结束:
事实是,即使大幅缩小网格,计算也很可能失败(由于内存问题)。
顺序搜索
降低计算压力的实质是降维。因此出现了按顺序进行调优的想法。在做了一些研究后,我发现这个由拜伦·吴写的中文博客非常有帮助。这个概念是一步一步地进行调整:
第一步:设定一个相对较高的学习率,降低你的迭代次数。
这允许您在下面的步骤中更快地进行调优。完成调优后,您可以增加迭代次数,降低学习速度,以获得不错的性能。
步骤 2:调整 numLeaves 和 maxDepth
这两个参数控制树模型的复杂性。值越高,模型越复杂。理论上,numLeaves ≤ 2^maxDepth.你可以检查你调好的值是否满足这个条件。你的模型可能会有高方差和低偏差。因此,在接下来的几个步骤中,我将尝试通过调整其他变量来减少过拟合
对了,CrossValidatorModel API 真的不友好。你可以输出 bestModel,但是你不能轻易地检查你的最终超参数。我写了一个函数来轻松地提取超参数信息进行检查。
步骤 3:调整 minSumHessianInLeaf
这个参数有很多别名,比如 min_sum_hessian_per_leaf,min_sum_hessian,min_hessian,min_child_weight。简而言之,它告诉你“一旦你在一个节点中达到一定程度的纯度,并且你的模型能够适应它,就不要试图分裂”。minSumHessianInLeaf 的正确值可以减少过度拟合。
步骤 4:调整 bagging fraction & feature fraction
这两个参数必须同时调整。baggingFraction 控制实例子采样,featureFraction 控制要素子采样。它们都服务于减少过拟合的目的。(更小的分数也允许更快的计算)
# similar code here
步骤 5:调整λ1 和λ2
L1 和 L2 法规参数也有助于减少过度拟合
# similar code here
步骤 6:调整学习速度和迭代次数以适应模型
通过这个连续的过程,尽管很繁琐,但您最终可以得到一个合理的调优结果。这种方法的主要问题是,首先需要初始化一个合理大小的网格。如果最优值位于您的网格之外,您需要重新分配一个合适的范围。一些尝试是不可避免的。你最好是一个有经验的数据科学家来做调整。因为每次尝试都要耗费大量的计算资源。
远视
Hyperopt 是一个 Python 库,用于在笨拙的搜索空间上进行串行和并行优化,搜索空间可能包括实值、离散和条件维度
“目前,hyperopt 中实施了三种算法:
Hyperopt 已经被设计为适应基于高斯过程和回归树的贝叶斯优化算法,但是这些算法目前还没有实现。"
Hyperopt 到目前为止还没有广泛使用,我发现一些帖子给出了指导性的 Python 实现: 1。超参数调谐部分 0 , 2。超参数调谐部分 2 。然而,尽管 Azure Databricks 已经准备好使用 hyperopt,但在任何网站上都找不到 spark 实现。
幸运的是,hyperopt 的实现非常简单。经过几次测试后,我能够在 spark 上运行调优。而且和我之前试过的所有方法相比真的很快。调音结果也很令人满意。下面是我如何在 PySpark 中实现的:
结论
总之,据我所知,Hyperopt 可能是目前在 spark 数据框架上调整 LightGBM 的超参数的最佳选择。它比强力网格搜索快得多,比顺序搜索更可靠。但是它确实还没有被很好的记录。如果没有我在 Python 中找到的关于 hyperopt 的帖子,我可能无法在 spark 上实现它。
我一直在 spark 上学习机器学习。然而,到目前为止,该材料仅限于在线使用;大部分的模型文件都不足以供外人使用。spark ml 实现的一些示例代码是共享的。希望越来越多的数据科学家可以分享他们的工作和故事,互相帮助。
喜欢讨论就上 LinkedIn 找我。
多个 GPU 上的闪电般快速 XGBoost
无需大量的代码更改
XGBoost 是数据科学中最常用的库之一。
在 XGBoost 出现的时候,它比它最接近的竞争对手 Python 的 Scikit-learn GBM 快得多。但随着时间的推移,它已经被一些令人敬畏的库如 LightGBM 和 Catboost 所竞争,无论是在速度还是准确性上。
就我而言,我使用 LightGBM 来处理大多数我刚刚得到 CPU 进行培训的用例。但是当我拥有一个或多个 GPU 时,我仍然喜欢用 XGBoost 进行训练。
为什么?
因此,我可以将 XGBoost 提供的优秀 GPU 功能与 Dask 结合使用,在单 GPU 和多 GPU 模式下使用 XGBoost。
怎么会?
这个帖子是关于在多 GPU 机器上运行 XGBoost 的。
数据集:
UCI·希格斯
我们将使用 UCI 希格斯数据集。这是一个具有 11M 行和 29 列的二进制分类问题,可能需要相当长的时间来解决。
从 UCI 网站:
这些数据是使用蒙特卡罗模拟产生的。前 21 个特征(第 2-22 列)是由加速器中的粒子探测器测量的运动特性。后 7 个特征是前 21 个特征的函数;这些是由物理学家得出的高级特征,有助于区分这两个类别。人们有兴趣使用深度学习方法来消除物理学家手动开发这些特征的需要。基准测试结果使用贝叶斯决策树从一个标准的物理包和 5 层神经网络提出了在原来的文件。最后 500,000 个示例用作测试集。
我们可以通过使用我从 NVidia post 的借用的漂亮函数将这个数据集加载到内存中。
这个函数下载 Higgs 数据集,并创建 Dmatrix 对象供以后 XGBoost 使用。
XGBoost:CPU 方法
因为我们已经加载了数据,所以我们可以用 CPU 来训练 XGBoost 模型,以便进行基准测试。
print("Training with CPU ...")
param = {}
param['objective'] = 'binary:logitraw'
param['eval_metric'] = 'error'
param['silent'] = 1
param['tree_method'] = 'hist'tmp = time.time()
cpu_res = {}
xgb.train(param, dtrain, num_round, evals=[(dtest, "test")],
evals_result=cpu_res)
cpu_time = time.time() - tmp
print("CPU Training Time: %s seconds" % (str(cpu_time)))---------------------------------------------------------------CPU Training Time: **717.6483490467072 seconds**
这段代码耗时 717 秒,大约需要 12 分钟才能完成。这很好,值得称赞,但我们能做得更好吗?
XGBoost:单一 GPU 方法
最棒的是,我们不需要对上面的代码做太多修改,就可以使用单个 GPU 来构建模型。
我们可以用 GPU 为什么要用 CPU?
我们将tree_method
改为gpu_hist
print("Training with Single GPU ...")param = {}
param['objective'] = 'binary:logitraw'
param['eval_metric'] = 'error'
param['silent'] = 1
**param['tree_method'] = 'gpu_hist'**
tmp = time.time()
gpu_res = {}xgb.train(param, dtrain, num_round, evals=[(dtest, "test")],
evals_result=gpu_res)
gpu_time = time.time() - tmp
print("GPU Training Time: %s seconds" % (str(gpu_time)))----------------------------------------------------------------
GPU Training Time: 78.2187008857727 seconds
我们实现了 10 倍的加速 ,我们的模型现在只需 1.3 分钟就能完成。这很好,但是如果我们有多个 GPU,我们能做得更好吗?
XGBoost:多 GPU 方法
例如,我的机器中有 2 个 GPU,而上面的代码只使用了 1 个 GPU。随着 GPU 现在变得越来越便宜,集群拥有 4 个以上的 GPU 并不罕见。那么我们可以同时使用多个 GPU 吗?
两个 GPU 总比一个好
要使用 MultiGPUs,过程并不是像上面那样加一点参数那么简单,涉及到几个步骤。
首先是数据加载的差异:
数据加载有多个步骤,因为我们需要 dask DMatrix 对象来训练 XGBoost 使用多个 GPU。
- 使用熊猫阅读 CSV 文件。
- 从 Pandas 数据帧创建 Dask 数据帧,以及
- 使用 dask 数据帧创建 Dask 数据矩阵对象。
为了使用多 GPU 来训练 XGBoost,我们需要使用 Dask 来创建一个 GPU 集群。这个命令创建了一个 GPU 集群,dask 稍后可以通过使用client
对象来使用它。
cluster = LocalCUDACluster()
client = Client(cluster)
我们现在可以加载 Dask Dmatrix 对象并定义训练参数。注意nthread
被设置为one
,而tree_method
被设置为gpu_hist
ddtrain, ddtest = load_higgs_for_dask(client)param = {}
param['objective'] = 'binary:logitraw'
param['eval_metric'] = 'error'
param['silence'] = 1
**param['tree_method'] = 'gpu_hist'
param['nthread'] = 1**
我们现在可以在多个 GPU 上训练,使用:
print("Training with Multiple GPUs ...")
tmp = time.time()
output = **xgb.dask.train**(client, param, ddtrain, num_boost_round=1000, evals=[(ddtest, 'test')])
multigpu_time = time.time() - tmp
bst = output['booster']
multigpu_res = output['history']
print("Multi GPU Training Time: %s seconds" % (str(multigpu_time)))
---------------------------------------------------------------
Multi GPU Training Time: 50.08211898803711 seconds
请注意对xgb.train
的调用如何变为xgb.dask.train
,以及它如何也需要 dask 客户端来工作。
这大约需要 0.8 分钟,比单个 GPU 的速度提高了 1.5 倍。我只有 2 个 GPU 可供我使用,所以我不能测试它,但我相信它是线性增长的,即更多的 GPU 和更多的时间减少。
结果
以下是所有三种设置的结果:
虽然多 CPU 和单 CPU 之间的区别现在看起来有些多余,但在运行手头的多个超参数调优任务时,可能需要运行多个具有不同超参数的 GBM 模型,这种区别将是相当可观的。
此外,当我们将其扩展到许多 GPU 时,这个结果可能会发生变化。
所以继续缩放。
你可以在 Github 上找到这篇文章的完整代码。
继续学习
如果你对深度学习感兴趣,并想为此使用你的 GPU,我想推荐这门关于计算机视觉中的深度学习的优秀课程。
谢谢你的阅读。将来我也会写更多初学者友好的帖子。在 中 关注我或者订阅我的 博客 了解他们。一如既往,我欢迎反馈和建设性的批评,可以通过 Twitter@ mlwhiz联系
此外,一个小小的免责声明——这篇文章中可能会有一些相关资源的附属链接,因为分享知识从来都不是一个坏主意。
Google Cloud 上轻量级但可扩展的 TensorFlow 工作流
我的超能力工具包:TFRecorder、TensorFlow Cloud、人工智能平台预测和权重与偏差
图片由作者使用figma.com
我正要说出来。今天,机器学习(ML)的广度和深度越来越大,这让我完全不知所措。
- 需要建立一个高性能的数据管道?学习 Apache Beam 或 Spark 和协议缓冲区
- 需要缩放你的模型训练?了解全还原和多节点分布式架构
- 需要部署您的模型吗?学习 Kubernetes、TFServing、量化和 API 管理
- 需要跟踪管道?建立一个元数据库,学习 docker,成为一名 DevOps 工程师
这甚至还不包括算法和建模空间,这也让我觉得自己像一个没有研究背景的冒名顶替者。一定有更简单的方法!
过去几周,我一直在思考这个两难的问题,以及我会向一位与我有相似思维模式的数据科学家推荐什么。上面的许多主题都很重要,尤其是如果你想专注于 MLOps 这一新领域,但有没有工具和技术可以让你站在巨人的肩膀上?
下面是 4 个这样的工具,它们抽象出许多复杂性,可以让你更有效地开发、跟踪和扩展你的 ML 工作流程。
- TFRecorder 【通过数据流】:通过导入 CSV 文件,轻松将数据转化为 TFRecords。对于图像,只需在 CSV 中提供 JPEG URIs 和标签。通过数据流扩展到分布式服务器,无需编写任何 Apache Beam 代码。
- TensorFlow Cloud**(通过 AI 平台训练)😗*通过一个简单的 API 调用,将您的 tensor flow 模型训练扩展到 AI 平台训练的单节点和多节点 GPU 集群。
- **AI 平台预测:**将您的模型作为 API 端点部署到 Kubernetes 支持的带有 GPU 的自动缩放服务,与 Waze 使用的相同!
- **权重&偏差:**记录工件(数据集和模型)来跟踪整个开发过程中的版本和沿袭。自动生成你的实验和工件之间的关系树。
工作流程概述
我将使用一个典型的猫和狗的计算机视觉问题来浏览这些工具。此工作流程包含以下步骤:
- 将原始 JPEG 图像保存到对象存储中,每个图像位于指定其标签的子文件夹下
- 以所需格式生成带有图像 URIs 和标签的 CSV 文件
- 将图像和标签转换为 TFRecords
- 从 TFRecords 创建数据集,并使用 Keras 训练 CNN 模型
- 将模型存储为 SavedModel,并部署为 API 端点
- JPEG 图像、TFRecords 和 SavedModels 都将存储在对象存储中
- 实验和人工制品的传承将通过权重和偏差进行跟踪
我使用的笔记本和脚本都在这个 GitHub 库里。
现在让我们深入了解每种工具。
TF 记录器
TFRecords 还是让我很困惑。我理解它们提供的性能优势,但是一旦我开始处理一个新的数据集,我总是很难使用它们。显然我不是唯一的一个,谢天谢地,TFRecorder 项目最近才发布。使用 TFRecords 从未如此简单,它只需要(1)以逻辑目录格式组织您的图像,以及(2)使用 PANDAS 数据帧和 CSV。以下是我采取的步骤:
- 创建一个包含 3 列的 CSV 文件,包括指向每个图像目录位置的图像 URI
作者图片
- 将 CSV 读入 PANDAS 数据帧,并调用 TFRecorder 函数转换数据流上的文件,指定输出目录
dfgcs = pd.read_csv(FILENAME)dfgcs.tensorflow.to_tfr(
output_dir=TFRECORD_OUTPUT,
runner='DataFlowRunner',
project=PROJECT,
region=REGION,
tfrecorder_wheel=TFRECORDER_WHEEL)
就是这样!不到 10 行代码就可以将数百万张图像转换成 TFRecord 格式。作为一名数据科学家,您刚刚为高性能培训渠道奠定了基础。如果你对后台发生的奇迹感兴趣,你也可以看看数据流控制台中的数据流作业图和指标。
作者图片
通读了一点 GitHub repo 之后,tfrecord 的模式如下:
tfr_format = {
"image": tf.io.FixedLenFeature([], tf.string),
"image_channels": tf.io.FixedLenFeature([], tf.int64),
"image_height": tf.io.FixedLenFeature([], tf.int64),
"image_name": tf.io.FixedLenFeature([], tf.string),
"image_width": tf.io.FixedLenFeature([], tf.int64),
"label": tf.io.FixedLenFeature([], tf.int64),
"split": tf.io.FixedLenFeature([], tf.string),
}
然后,您可以使用下面的代码将 TFRecords 读入 Keras 模型定型管道的 TFRecordDataset 中:
IMAGE_SIZE=[150,150]
BATCH_SIZE = 5def read_tfrecord(example):
image_features= tf.io.parse_single_example(example, tfr_format)
image_channels=image_features['image_channels']
image_width=image_features['image_width']
image_height=image_features['image_height']
label=image_features['label']
image_b64_bytes=image_features['image']
image_decoded=tf.io.decode_base64(image_b64_bytes)
image_raw = tf.io.decode_raw(image_decoded, out_type=tf.uint8)
image = tf.reshape(image_raw, tf.stack([image_height, image_width, image_channels]))
image_resized = tf.cast(tf.image.resize(image, size=[*IMAGE_SIZE]),tf.uint8)
return image_resized, labeldef get_dataset(filenames):
dataset = tf.data.TFRecordDataset(filenames=filenames, compression_type='GZIP')
dataset = dataset.map(read_tfrecord)
dataset = dataset.shuffle(2048)
dataset = dataset.batch(BATCH_SIZE)
return datasettrain_dataset = get_dataset(TRAINING_FILENAMES)
valid_dataset = get_dataset(VALID_FILENAMES)
TensorFlow 云(AI 平台训练)
现在我们有了一个 tf.data.Dataset,我们可以将它输入到我们的模型训练调用中。下面是一个使用 Keras 顺序 API 的 CNN 模型的简单例子。
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(150, 150, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(256, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid')
])model.summary()
model.compile(loss='binary_crossentropy',
optimizer=RMSprop(lr=1e-4),
metrics=['accuracy'])
model.fit(
train_dataset,
epochs=10,
validation_data=valid_dataset,
verbose=2
)
我首先在我的开发环境中对一部分图像(在我的例子中是一个 Jupyter 笔记本)运行这个,但是我想让它扩展到所有的图像并使它更快。TensorFlow Cloud 允许我使用单个 API 命令来封装我的代码,并提交作为分布式 GPU 作业运行。
import tensorflow_cloud as tfctfc.run(entry_point='model_training.ipynb',
chief_config=tfc.COMMON_MACHINE_CONFIGS['T4_4X'],
requirements_txt='requirements.txt')
这不是愚人节的玩笑。上面的代码(< 5 行代码)是完整的 python 脚本,您需要将它放在与 Jupyter 笔记本相同的目录中。最棘手的部分是遵循所有的设置说明,以确保您正确地通过了 Google 云平台项目的身份验证。这是一种巨大的超级力量!
让我们更深入地了解一下这是怎么回事。
首先,将构建一个 docker 容器,其中包含您需要的所有库和笔记本,并保存在 Google Cloud 的容器注册服务中。
作者图片
该容器然后被提交给完全管理的无服务器培训服务,AI 平台培训。无需设置任何基础设施和安装任何 GPU 库,我就可以在一台 16 vCPU 60GB RAM、配有 4 个英伟达 T4 GPU 的机器上训练这个模型。我只在需要的时候使用这些资源(大约 15 分钟),并且可以使用 IDE 或 Jupyter 笔记本在我的本地环境中继续开发。
作者图片
SavedModel 最终存储在对象存储中,这是在我的训练脚本的最后指定的。
MODEL_PATH=time.strftime("gs://mchrestkha-demo-env-ml-examples/catsdogs/models/model_%Y%m%d_%H%M%S")
model.save(MODEL_PATH)
人工智能平台预测
通过对象存储中的 SavedModel,我可以将它加载到我的开发环境中,并运行一些示例预测。但是,如果我想允许其他人使用它,而不需要他们设置 Python 环境和学习 TensorFlow,该怎么办?这就是人工智能平台预测发挥作用的地方。它允许您将模型二进制文件部署为 API 端点,可以使用 REST、简单的 Google Cloud SDK (gcloud)或各种其他客户端库来调用这些端点。最终用户只需要知道所需的输入(在我们的例子中,JPEG 图像文件被转换为[150,150,3] JSON 数组)并可以将您的模型嵌入到他们的工作流中。当你做了一个改变(在一个新的数据集上重新训练,一个新的模型架构,甚至一个新的框架),你可以发布一个新的版本。
下面简单的 gcloud SDK 是将您的模型部署到这个 Kubernetes 支持的自动缩放服务的超级力量。
MODEL_VERSION="v1"
MODEL_NAME="cats_dogs_classifier"
REGION="us-central1"gcloud ai-platform models create $MODEL_NAME \
--regions $REGIONgcloud ai-platform versions create $MODEL_VERSION \
--model $MODEL_NAME \
--runtime-version 2.2 \
--python-version 3.7 \
--framework tensorflow \
--origin $MODEL_PATH
人工智能平台预测是一项让我特别兴奋的服务,因为它消除了让你的模型进入世界(内部和外部)并开始从中创造价值的许多复杂性。虽然这个博客的范围是一个实验性的工作流程像 Waze 这样的公司正在使用人工智能平台预测来部署和服务他们的大规模生产模型。
权重和偏差
现在我已经完成了一个实验,但是我未来的实验呢?我可能需要:
- 本周晚些时候运行更多的实验,并跟踪我的工作
- 一个月后再来,试着记住我每个实验的所有输入和输出
- 与有希望将我的工作流程拼凑起来的队友分享工作
在 ML 管道领域有很多工作要做。这是一个令人兴奋但仍处于萌芽状态的领域,最佳实践和行业标准仍有待开发。一些很棒的项目包括 MLFlow、Kubeflow Pipelines、TFX 和 Comet.ML。对于我的工作流的需求,MLOps 和连续交付超出了范围,我想要简单的东西。我选择了 Weights & bias(WandB ),因为它易于使用,并且可以轻量级集成来跟踪实验和工件。
先说实验。WandB 提供了许多定制选项,但是如果你使用任何一个流行的框架,你不需要做太多。对于 TensorFlow Keras API,我简单地(1)导入了 wandb python 库(2)初始化了我的实验运行,以及(3)在模型拟合步骤中添加了一个回调函数。
model.fit(
train_dataset,
epochs=10,
validation_data=valid_dataset,
verbose=2,
** callbacks=[WandbCallback()**]
)
这将自动将现成的指标流入集中的实验跟踪服务。看看人们使用 WandB 的所有方式。
作者图片
WandB 还提供了一个工件 API,它比当今一些笨重的工具更适合我的需求。我在整个管道中添加了简短的代码片段,以定义 4 个关键项目:
- 初始化管道中的一个步骤
- 使用现有的工件(如果有的话)作为这个步骤的一部分
- 记录由该步骤生成的工件
- 说明一个步骤已经完成
run = wandb.init(project='cats-dogs-keras', job_type='data', name='01_set_up_data')***<Code to set up initial JPEGs in the appropriate directory structure>***artifact = wandb.Artifact(name='training_images',job_type='data', type='dataset')
artifact.add_reference('gs://mchrestkha-demo-env-ml-examples/catsdogs/train/')
run.**log_artifact**(artifact)
run.finish()run = wandb.init(project='cats-dogs-keras',job_type='data', name='02_generate_tfrecords')artifact = run.**use_artifact**('training_images:latest')***<TFRecorder Code>***artifact = wandb.Artifact(name='tfrecords', type='dataset')
artifact.add_reference('gs://mchrestkha-demo-env-ml-examples/catsdogs/tfrecords/')
run.**log_artifact**(artifact)
run.finish()run = wandb.init(project='cats-dogs-keras',job_type='train', name='03_train')
artifact = run.**use_artifact**('tfrecords:latest')***<TensorFlow Cloud Code>***artifact = wandb.Artifact(name='model', type='model')
artifact.add_reference(MODEL_PATH)
run.**log_artifact**(artifact)
这个简单的工件 API 存储了每次运行和工件的元数据和沿袭,因此您可以完全清楚您的工作流。UI 也有一个漂亮的树形图来图形化地查看它。
作者图片
摘要
如果你被无休止的机器学习主题、工具和技术吓倒,你并不孤单。我每天与同事、合作伙伴和客户谈论数据科学、MLOps、硬件加速器、数据管道、AutoML 等的各个方面时,都会感到一种冒名顶替综合症。请记住,重要的是:
- 实际一点:让我们所有人都成为开发操作系统、数据和机器学习领域的全栈工程师是不现实的。选择一两个你感兴趣的领域,和其他人一起解决整个系统的问题。
- 关注你的问题:我们都被新的框架、新的研究论文、新的工具冲昏了头脑。从您的业务问题、数据集和最终用户需求开始。不是每个人都需要每天对生产中的数百个 ML 模型进行重新训练,并提供给数百万用户(至少现在还不是)。
- **识别超级工具:**找到一套核心工具,作为效率倍增器,提供可伸缩性并消除复杂性。我浏览了我的 Tensorflow 工具包(TF recorder+tensor flow Cloud+AI 平台预测+权重&偏差),但是找到了映射到您的问题和工作流的正确工具包。
有问题或者想聊天?在 Twitter 上找到我
这个博客的笔记本例子可以在我的 GitHub 上找到。
非常感谢 Mike Bernico 、Rajesh thal am和 Vaibhav Singh 帮助我完成这个示例解决方案。
可能性比率会让你(和你的算法)更聪明
非统计人员的统计数据
有人,不是披头士,使用艾比路人行横道。几率有多大?Sparragus / CC BY
很多人(我希望不是你)都有一种印象,认为统计数字可以证明事情。他们不能。他们所做的只是估计一种现象发生的可能性。
但是概率很难适应这个世界。我们(和我们的算法)必须基于不完美的信息做出二元决策——是/否,停止/继续。我们必须把可能性当作确定无疑的事情来对待。一种方法是尝试完善这些信息——创建一个完美的测试,从不失败,并且总是给出正确的结果。
我们都知道这种方法在现实世界中是不现实的。根据定义,这个世界比测试或算法中的任何描述都要复杂。更糟糕的是,从产品开发的角度来看,完善测试的努力很快就会产生递减的回报。这会耗费时间和资源,让你在老板或客户面前显得很笨。
摆脱这个陷阱的方法是在你的决策中加入其他信息。我们都知道这一点,我们都这样做。但是我们并不总是做得很好。似然比允许您将测试结果与其他信息结合起来,并且做到严谨和精确。
医疗保健中的 LRs
似然比被开发用于医疗保健决策。这就是我的背景,所以我将从这里开始,但是如果血肉之躯让你厌烦,并且你想要一个机器学习的例子,请随意跳到下一部分。原理完全一样。
我在这里抱怨被过度宣传的癌症测试的缺点。有问题的测试表面上表现良好,但由于流行率低,会产生令人发指的假阳性。然而,似然比可能拯救这样的测试,并使其对人类有用。
让我们从任何诊断测试的基础开始:它的敏感性和特异性。敏感性是测试呈阳性的真阳性(患病患者)的比例。特异性是测试阴性的真阴性(无疾病的患者)的分数。
在我用于肺癌的例子中,液体活检测试的灵敏度为 80%,特异性为 93%。因为肺癌很罕见,每年有 0.05%的人口出现新病例,阳性结果并不意味着你得了癌症。事实上,你患癌症的几率仍然低于百分之一。阳性检测结果本身比没用更糟糕。
在这张照片中,一名医生看起来很担心。他可能正在决定是否根据不确定的测试结果采取行动。要是他知道可能性比率就好了。乔纳森·博尔巴在 Unsplash 上的照片
似然比利用了这个结果。正似然比定义为
插入上述灵敏度和特异性的数字,测试结果意味着你患肺癌的可能性是没有阳性结果时的 11 倍。这是一个非常小的数字的 11 倍,所以它仍然是一个很小的数字,并不是真正可行的。
但是现在你可以把它和其他信息结合起来。吸烟会使你患肺癌的几率增加 24 倍(T4)。这是一个很大的数字,但不足以证明干预的合理性——24x 0.0005(基线几率)仅为 0.012。但现在乘以测试后的增长,你的几率已经上升到 11 x 24 x 0.0005 = 0.13,或 12%*的概率。这足以证明干预是正当的。似然比允许你结合一些不充分的信息,得出一个有用的结论。
模式识别中的 LRs
假设你正在研究人工智能中最难的问题之一——物体识别。也许你的工作是提出一种算法来识别自动驾驶车辆的停车标志。您的产品需求文档声明您的代码必须具有小于 1/1000 的假阴性率(即,丢失停止标志),以及小于 1/1000 的假阳性率(当没有标志时停止)。
安瓦尔·阿里在 Unsplash 上的照片
你的编码(和往常一样)很棒,很有创新性。但你还是碰壁了。虽然你能单独击中每个目标,但你不能同时满足两个目标。降低概率阈值以减少失误,代码开始抛出误报,在没有停止标志的地方看到停止标志。降低假阳性,你的车开始运行停止标志。不太好。
您已经进行了广泛的测试,并且知道(在最大的准确度下)您的代码具有 99.5%的灵敏度(即它每 1000 个符号会遗漏 5 个)。
您因无法编写更好地识别停车标志的代码而感到沮丧。为了缓解压力(并摆脱老板对状态更新的要求),你带着你的老瘸腿狗去散步。当它嗅树时环顾四周,你意识到你不需要更好的识别代码。你只需要独立的信息,并把它与认知结合起来。
一项城市调查显示,80%的人行横道也有停车标志。可能性比率让你使用这些信息来满足你的规格。
要使用 LRs,请遵循以下步骤:
- 将某个对象是停止标志的概率转换为 odds (P/(1-P))。如果你的算法检测到 99.5%的停车标志,检测到停车标志的几率是 0.995/(1–0.995)= 199。对你的贝叶斯先验做同样的处理,人行横道也有停止标志的概率(0.8/(1–0.8)= 4)。
- 乘以赔率:4 * 199 = 796。
- 换算回概率:796/(1+796) = 99.9%
瞧啊。问题解决了。你现在能发现 99.9%的停车标志。似然比让你结合贝叶斯先验,人行横道通常有停止标志。这些信息,再加上您出色的对象识别代码,就能完成任务。
运用所有的知识
没有一个测试是完美的,无论它多么复杂和优雅。所有这些都有可能出现假阳性和假阴性。似然比调动了其他信息以服务于更好的测试性能。它们让你使用完全独立的,甚至形式上完全不同的信息。如果你的测试包含了可能性比率,它更有可能让世界变得更美好。
*要将赔率转换为概率,将赔率除以(1+赔率)。这种转换对于小概率值并不重要。
ARIMA 的局限性:处理异常值
为什么要谨慎解读 ARIMA 预测
当涉及到对一个序列的总体趋势和季节模式进行建模时,ARIMA 模型可以是相当熟练的。
在之前一篇名为 SARIMA:用 Python 和 R 预测季节性数据的文章中,使用了 ARIMA 模型来预测爱尔兰都柏林的最高气温值。
结果显示了显著的准确性,70%的预测与实际温度值相差在 10%以内。
预测更极端的天气状况
也就是说,前一个示例中使用的数据采用的温度值没有特别显示极值。例如,最低温度值为 4.8°C,而最高温度值为 28.7°C。这两个值都没有超出爱尔兰典型的全年天气标准。
然而,让我们考虑一个更极端的例子。
Braemar 是一个位于阿伯丁郡苏格兰高地的村庄,被称为英国冬季最冷的地方之一。1982 年 1 月,根据英国气象局的记录,该地区的最低温度为-27.2 摄氏度,这与 1981 年至 2010 年间记录的-1.5 摄氏度的平均最低温度明显不同。
ARIMA 模式在预测布雷默异常寒冷的冬天时表现如何?
利用 1959 年 1 月至 2020 年 7 月的英国气象局月度数据(包含公共部门信息)构建了一个 ARIMA 模型。
时间序列是这样定义的:
weatherarima <- ts(mydata$tmin[1:591], start = c(1959,1), frequency = 12)
plot(weatherarima,type="l",ylab="Temperature")
title("Minimum Recorded Monthly Temperature: Braemar, Scotland")
这是月度数据的图表:
来源:英国气象局天气数据
以下是单个时间序列组件的概述:
资料来源:RStudio
ARIMA 模型配置
80%的数据集(前 591 个月的数据)用于构建 ARIMA 模型。然后,后 20%的时间序列数据被用作验证数据,以比较预测值与实际值的准确性。
使用 auto.arima,选择最佳拟合的 p 、 d 和 q 坐标:
# ARIMA
fitweatherarima<-auto.arima(weatherarima, trace=TRUE, test="kpss", ic="bic")
fitweatherarima
confint(fitweatherarima)
plot(weatherarima,type='l')
title('Minimum Recorded Monthly Temperature: Braemar, Scotland')
最佳配置选择如下:
> # ARIMA
> fitweatherarima<-auto.arima(weatherarima, trace=TRUE, test="kpss", ic="bic")Fitting models using approximations to speed things up...ARIMA(2,0,2)(1,1,1)[12] with drift : 2257.369
ARIMA(0,0,0)(0,1,0)[12] with drift : 2565.334
ARIMA(1,0,0)(1,1,0)[12] with drift : 2425.901
ARIMA(0,0,1)(0,1,1)[12] with drift : 2246.551
ARIMA(0,0,0)(0,1,0)[12] : 2558.978
ARIMA(0,0,1)(0,1,0)[12] with drift : 2558.621
ARIMA(0,0,1)(1,1,1)[12] with drift : 2242.724
ARIMA(0,0,1)(1,1,0)[12] with drift : 2427.871
ARIMA(0,0,1)(2,1,1)[12] with drift : 2259.357
ARIMA(0,0,1)(1,1,2)[12] with drift : Inf
ARIMA(0,0,1)(0,1,2)[12] with drift : 2252.908
ARIMA(0,0,1)(2,1,0)[12] with drift : 2341.9
ARIMA(0,0,1)(2,1,2)[12] with drift : 2249.612
ARIMA(0,0,0)(1,1,1)[12] with drift : 2264.59
ARIMA(1,0,1)(1,1,1)[12] with drift : 2248.085
ARIMA(0,0,2)(1,1,1)[12] with drift : 2246.688
ARIMA(1,0,0)(1,1,1)[12] with drift : 2241.727
ARIMA(1,0,0)(0,1,1)[12] with drift : Inf
ARIMA(1,0,0)(2,1,1)[12] with drift : 2261.885
ARIMA(1,0,0)(1,1,2)[12] with drift : Inf
ARIMA(1,0,0)(0,1,0)[12] with drift : 2556.722
ARIMA(1,0,0)(0,1,2)[12] with drift : Inf
ARIMA(1,0,0)(2,1,0)[12] with drift : 2338.482
ARIMA(1,0,0)(2,1,2)[12] with drift : 2248.515
ARIMA(2,0,0)(1,1,1)[12] with drift : 2250.884
ARIMA(2,0,1)(1,1,1)[12] with drift : 2254.411
ARIMA(1,0,0)(1,1,1)[12] : 2237.953
ARIMA(1,0,0)(0,1,1)[12] : Inf
ARIMA(1,0,0)(1,1,0)[12] : 2419.587
ARIMA(1,0,0)(2,1,1)[12] : 2256.396
ARIMA(1,0,0)(1,1,2)[12] : Inf
ARIMA(1,0,0)(0,1,0)[12] : 2550.361
ARIMA(1,0,0)(0,1,2)[12] : Inf
ARIMA(1,0,0)(2,1,0)[12] : 2332.136
ARIMA(1,0,0)(2,1,2)[12] : 2243.701
ARIMA(0,0,0)(1,1,1)[12] : 2262.382
ARIMA(2,0,0)(1,1,1)[12] : 2245.429
ARIMA(1,0,1)(1,1,1)[12] : 2244.31
ARIMA(0,0,1)(1,1,1)[12] : 2239.268
ARIMA(2,0,1)(1,1,1)[12] : 2249.168Now re-fitting the best model(s) without approximations...ARIMA(1,0,0)(1,1,1)[12] : Inf
ARIMA(0,0,1)(1,1,1)[12] : Inf
ARIMA(1,0,0)(1,1,1)[12] with drift : Inf
ARIMA(0,0,1)(1,1,1)[12] with drift : Inf
ARIMA(1,0,0)(2,1,2)[12] : Inf
ARIMA(1,0,1)(1,1,1)[12] : Inf
ARIMA(2,0,0)(1,1,1)[12] : Inf
ARIMA(0,0,1)(0,1,1)[12] with drift : Inf
ARIMA(0,0,2)(1,1,1)[12] with drift : Inf
ARIMA(1,0,1)(1,1,1)[12] with drift : Inf
ARIMA(1,0,0)(2,1,2)[12] with drift : Inf
ARIMA(2,0,1)(1,1,1)[12] : Inf
ARIMA(0,0,1)(2,1,2)[12] with drift : Inf
ARIMA(2,0,0)(1,1,1)[12] with drift : Inf
ARIMA(0,0,1)(0,1,2)[12] with drift : Inf
ARIMA(2,0,1)(1,1,1)[12] with drift : Inf
ARIMA(1,0,0)(2,1,1)[12] : Inf
ARIMA(2,0,2)(1,1,1)[12] with drift : Inf
ARIMA(0,0,1)(2,1,1)[12] with drift : Inf
ARIMA(1,0,0)(2,1,1)[12] with drift : Inf
ARIMA(0,0,0)(1,1,1)[12] : Inf
ARIMA(0,0,0)(1,1,1)[12] with drift : Inf
ARIMA(1,0,0)(2,1,0)[12] : 2355.279Best model: ARIMA(1,0,0)(2,1,0)[12]
该模型的参数如下:
> fitweatherarima
Series: weatherarima
ARIMA(1,0,0)(2,1,0)[12]Coefficients:
ar1 sar1 sar2
0.2372 -0.6523 -0.3915
s.e. 0.0411 0.0392 0.0393
使用配置的模型 ARIMA(1,0,0)(2,1,0)【12】,生成预测值:
forecastedvalues=forecast(fitweatherarima,h=148)
forecastedvalues
plot(forecastedvalues)
这是一张预测图:
资料来源:RStudio
现在,可以生成一个数据框来比较预测值和实际值:
df<-data.frame(mydata$tmin[592:739],forecastedvalues$mean)
col_headings<-c("Actual Weather","Forecasted Weather")
names(df)<-col_headings
attach(df)
资料来源:RStudio
此外,使用 R 中的度量库,可以计算 RMSE(均方根误差)值。
> library(Metrics)
> rmse(df$`Actual Weather`,df$`Forecasted Weather`)
[1] 1.780472
> mean(df$`Actual Weather`)
[1] 2.876351
> var(df$`Actual Weather`)
[1] 17.15774
据观察,在平均温度为 2.87°C 的情况下,记录的 RMSE 为 1.78,与平均值相比明显较大。
让我们进一步研究数据中更极端的值。
资料来源:RStudio
我们可以看到,当涉及到预测特别极端的最低温度(为了便于讨论,低于-4°C)时,我们看到 ARIMA 模型明显高估了最低温度的值。
在这方面,相对于测试集中 2.87°C 的平均温度,RMSE 的大小刚刚超过 60%,这是因为 RMSE 对较大错误的惩罚更重。
在这方面,似乎 ARIMA 模型在捕捉更在正常值范围内的温度方面是有效的。
资料来源:RStudio
然而,该模型在预测更极端的数值方面存在不足,特别是在冬季月份。
也就是说,如果使用 ARIMA 预测的下限会怎样?
df<-data.frame(mydata$tmin[592:739],forecastedvalues$lower)
col_headings<-c("Actual Weather","Forecasted Weather")
names(df)<-col_headings
attach(df)
资料来源:RStudio
我们看到,虽然模型在预测最小值方面表现更好,但实际最小值仍然超过预测值。
此外,这并没有解决问题,因为这意味着模型现在将大大低估高于平均值的温度值。
因此,RMSE 显著增加:
> library(Metrics)
> rmse(df$`Actual Weather`,df$`Forecasted Weather`)
[1] 3.907014
> mean(df$`Actual Weather`)
[1] 2.876351
在这方面,应该谨慎解释 ARIMA 模型。虽然它们可以有效地捕捉季节性和总体趋势,但它们可能无法预测明显超出正常范围的值。
在预测这些数值时,蒙特卡罗模拟等统计工具可以更有效地模拟更极端数值的潜在范围。这里有一篇后续文章讨论了如何使用这种方法模拟极端天气事件。
结论
在这个例子中,我们看到了 ARIMA 在预测极值方面的局限性。虽然该模型擅长模拟季节性和趋势,但异常值很难预测 ARIMA 的情况,因为它们不在该模型捕捉的总体趋势之内。
非常感谢您的阅读,您可以在michael-grogan.com找到更多我的数据科学内容。
免责声明:本文是在“原样”的基础上编写的,没有担保。本文旨在提供数据科学概念的概述,不应以任何方式解释为专业建议。本文中的发现和解释是作者的,不以任何方式得到英国气象局的认可或隶属于该局。
图形神经网络的局限性
走向更强大的 GNN。来源。
图形表示有两种范式:图形内核和图形神经网络。图核通常基于分解以无监督的方式创建图的嵌入。例如,我们可以计算一个图中每种类型的三角形或者更一般的三元组的数量,然后使用这些计数来得到嵌入。这是 graphlet 内核的一个实例。
所有尺寸为 4 的小图。计算一个图中所有四元组中每个 graphlet 的数量将得到一个 graphlet 内核。来源:用于大型图形比较的高效 graphlet 内核
这种范式的主要研究动机是创建一种保持图之间同构的嵌入,即两个图同构当且仅当它们对应的嵌入相同。不用说,如果我们有这样的嵌入,我们就解决了图同构问题,这是目前已知的比 p 类问题更难的问题。然而,有像匿名行走嵌入这样的嵌入保持同构,当然是以运行时间计算为代价的。尽管如此,这里的主要信息是图形内核被设计来解决图形同构问题。您的嵌入能够区分的图形越多,您的嵌入就越好。这是原则。
对于图形神经网络,原理已经改变。我们可以尝试解决任何给定的问题,而不是解决一个问题,即图同构,比如寻找最短路径或检测循环。这是很有希望的,因为它允许我们通过它所能解决的问题来指导我们的网络设计。这听起来很神奇:不用使用一些成熟的组合算法,你只需训练你的网络,它就会为你找到解决方案。但这也是可疑的:神经网络正在通过 SGD 搜索解决方案,并涉及许多其他技术问题,如果你陷入了糟糕的局部最优怎么办——那么它如何解决任何问题?事实上,图形神经网络有一些限制,我将在下面描述。
GNN 强大的条件。
我将从作品开始,图神经网络有多强大,它引发了很多关于 GNN 理论解释的研究。特别地,将 GNNs 与一个被充分研究的图同构算法,Weisfeiler-Lehman (WL)算法相比较。
关于 WL 算法。
这个算法很容易描述。你从一个图开始,其中每个节点都有一些颜色(如果没有,放一个度数)。在每次迭代中,每个节点都获得其邻居的一组颜色,并以特定的方式更新其颜色。具体来说,有一个内射函数,它从节点的先前颜色 c 和邻域颜色 x 的有序列表中创建节点的新颜色 c’。该算法在n
次迭代后停止,更新图的颜色。
注意:重要的是 WL 算法使用内射函数,因为它保证不同的输入将得到不同的输出。WL 使用的一个特殊的内射函数是,它为每个输入参数创建了一个以前没有遇到过的新颜色。因为它在分类(可数)域(颜色)中操作,所以它总是可以创建这样的映射。
内射、双射和满射映射(从左到右)。来源。
该算法的主要用途是测试两个图之间的同构。如果最终着色不同,那么两个图不是同构的。如果两个图具有相同的最终着色,那么 WL 算法输出它们可能是同构的,这意味着它们仍然有微小的机会不是同构的。
这种算法是 70 年代在苏联的秘密实验室里设计的,当时计算机仍然使用穿孔卡。但是从那时起,世界各地的研究人员研究了它的性质,特别是,当 WL 算法失败时,我们知道不同的图族。例如,对于任意两个具有n
顶点的d
-正则图,最终的着色将是相同的。尽管如此,这是一个非常强大的同构测试,有定理表明,当n
趋于无穷大时,WL 失败的可能性为 0。所以这是一个相当强的算法。
回到 GNN。
如果你研究过 GNN,你会发现 GNN 更新节点特征的方式和 WL 算法更新节点颜色的方式有很多相似之处。特别是,GNN 使用消息传递机制更新特性。
不同 GNN 之间的区别在于它们使用的聚合和读出函数。但是很容易理解,如果聚合函数是内射的,那么如果 WL 把图映射到不同的着色,那么 GNN 也会把这些图映射到不同的嵌入。定理 3 是这种说法的正式方式。
换句话说,GNN 的参数化函数phi
和f
如果是内射的,那么它们保证 GNN 的强幂。这并不奇怪,因为 WL 算法也要求它的函数是内射的,而在其他方面,这两个过程是等价的。
请注意我们更新节点嵌入的特殊方式。我们得到先前嵌入h_v^(k-1)
和邻居先前嵌入的多重集作为两个不同的自变量,而不是当你把这两个合并在一起时作为一个自变量。这一点很重要。
所以,你可以用 GNN 来判断图是否同构,这相当于用 WL 算法。
这是神奇的部分。GNN 突然变成了著名的算法。但是它的局限性在哪里呢?
关于 GNN 的局限性。
来自上面的主要限制是你需要有内射函数phi
和f
。这些功能是什么?这些是将多重嵌入集映射到新嵌入集的函数。例如,您可以使用均值函数。该函数将取嵌入的平均值,并将其指定为新的嵌入。然而,很容易看出,对于一些不同的图,这些将给出相同的嵌入,因此均值函数不是内射的。
节点 v 和 v’的嵌入的平均聚合(这里嵌入对应于不同的颜色)将给出相同的嵌入,即使图是不同的。来源:图神经网络有多强大?
但是如果你以特定的方式求和并变换嵌入,就有可能得到内射函数。这里是引理 5:
这里真正重要的是,你可以首先使用一些函数f(x)
将和下的每个嵌入映射到一个新的嵌入,然后取和,得到一个内射函数。在证明中,他们实际上明确地陈述了这个函数 f,它需要两个附加条件,即X
是可数的,并且任何多重集是有界的。我认为这两个假设都不可靠,因为无论如何,我们将 GNN 应用于有限图,其中特征和邻域的基数是有限的。但是至少我们现在知道,如果我们使用变换 f,然后加法,我们可以得到一个内射映射。
然而,从上述定理 3(条件 a)应该有一个特定的聚合方案,除了邻居的聚合之外,该聚合方案使用当前节点h_v^(k-1)
的先前嵌入。为了包含它,我们需要另一个语句:
注意,这里函数h
像以前一样取变换后的邻居特征的总和,但是此外,加上(1+eps)f(c)
并且这个eps
是任何无理数。这样函数h
就是内射的。
好吧,我们知道些什么?我们知道我们的聚集函数phi
和f
应该是内射的,并且我们有内射的函数h
。如果我们的目标是构建强大的嵌入,那么我们就完成了。但是我们尝试的不仅仅是构建嵌入,而是以监督的方式解决下游任务,比如节点分类。并且函数h
不具有可以拟合数据的可学习参数(可能eps
除外)。
GIN architecture 提出的是用 MLP 代替函数phi
和f
,由于通用逼近定理,我们知道 MLP 可以逼近任何函数,包括内射函数。因此,特别地,GIN 的嵌入更新具有以下形式:
注意,MLP 内部的东西不再保证是内射的,而且 MLP 本身也不保证是内射的。事实上,对于第一层,如果输入特征是一位热编码的,那么 MLP 内部的和将是内射的,原则上,MLP 可以学习一个内射函数。但是在第二层和更高层,节点嵌入变得不合理,并且很容易得出嵌入的和不再是内射的例子(例如,有一个嵌入等于 2 的邻居或者有两个嵌入等于 1 的邻居)。
所以,如果 MLP 和嵌入的和是内射函数,那么 GIN 和 WL 算法一样强大。
但事实上,在训练中没有任何东西可以保证这种内射性,可能有一些图形是金不能区分的,而 WL 可以。所以这是关于杜松子酒的一个很强的假设,如果违反了这个假设,那么杜松子酒的力量是有限的。
这一限制稍后在论文判别结构图分类中进行了讨论,其中显示了为了使 MLP 内射,输出嵌入的大小应该与输入要素的大小成指数关系,尽管分析是针对无界邻域(无限图)进行的。找到一个具有内射聚合并对下游任务有足够表达能力的架构是一个公开的问题,即使有几个架构将 GIN 推广到更高维的 WL 算法以及其他问题;然而,还不能保证学习的 GNN 架构将解决所有输入图的特定任务。关于图形神经网络表达能力的调查很好地解释了 GNN 能力理论解释的最新进展。
结论。
对 GNN 房地产的研究现在是一个活跃的研究领域(你可以查看的最新趋势),有许多开放性的问题需要解决。这篇文章的主要信息是要表明,GNN 目前不能保证收敛到像 WL 算法那样强大的状态,尽管一般来说,当 GNN 算法变得强大时,它会有一组参数。GNN 可以解决图上的不同问题,但是到目前为止,研究都集中在它们能解决什么不能解决什么,而不是它如何对得到的解有一些保证,我认为这将是下一篇研究论文的重点。
P.S .我会继续写关于图机器学习的文章,所以如果你有兴趣,可以在 medium 上关注我或者订阅我的 电报频道 (我每天更新的)或者 我的 twitter (我每周更新一次)。
回归的局限性
在科学公式中
回归分析的作者说明
回归分析是一种统计技术,常用于建立因变量或解释变量与自变量或预测变量之间的关系。例如,一个销售人员可能想知道为什么一种产品的销售,比如说报纸在一个月的某些时候销量很高。然后,他将首先尝试确定确切的日期或星期,即销售波动的时间,并寻找影响转换的独特事件。在这些发现之后,通常会做出旨在改进流程或降低成本的决策。因此,回归是基于可验证的观察或经验,而不是理论或纯逻辑,因此有时被称为经验模型。
呈现回归模型的最普通的方式是将被解释或响应变量 Yᵢ 写成自变量 Xᵢ 的函数,由系数 *β限定。*一个额外的误差项, ϵ 通常被添加来表示可能或可能不直接与响应变量相关的未捕获信息。无论回归模型是线性的还是非线性的,方程通常遵循以下形式:
情商。(1)
回归分析的最早形式是广为人知的最小二乘法,由勒让德于 1805 年提出,后来高斯于 1809 年提出了一个改进版本。虽然回归已经辉煌了三个多世纪,但它受到了难以置信的限制,尤其是在面向自然科学的科学出版方面。
我们最近探索了科学家如何遵循一种叫做“激进”的方法来制定新的方程式。我认为其中一个回答很有分量,值得一个体面的回答,来自重力井(见下面截图中的帖子)
图 1:对文章“科学家如何建立新方程”的回应
这是一个有效的关注,因此我们将解决它以及为什么经验模型可能不是第一选择的其他原因,只要制定新的方程是一个关注。
回归分析的问题
回归可能不起作用的第一个也是最明显的原因是,你在寻找全新的方程,因此很可能文献中没有数据支持你的假设。因此,我们正在探索方法,甚至在开始进行实验之前,甚至在获得获得实验装置的资金之前,就开始你的研究。接下来将适用以下场景:
- 因此,建议甚至在建立实验之前就采用激进的方法。这样,你的目标就是大幅削减成本。例如,你的最终方程是 p=mv ,如果你在进行实验之前得到这个,你的工作会更容易,因为你事先知道,例如,你不期望任何常数。还要记住,你不知道这些变量是什么,这就是为什么所有的回归方程看起来像: y=ax + b 。该常数几乎是不可避免的,因为在大多数情况下(如果不是全部的话),它是由实验设置误差造成的。我同行评议过许多文章,在这些文章中,作者完全没有意识到他们所拥有的潜力,如果他们多做一点努力,将方程转换成动态形式的话。
- 其次,虽然回归分析有利于数据探索,但你很少能得到所有的信息,尤其是关于单位或维度的信息。你会意识到这些报告中的讨论部分只关注统计测量,如相关性、现场数据和实验之间的最佳拟合等。,就差不多了。
- 经验模型很难概括。这意味着,如果你进行实验,并提出方程,只讨论相关性,以及(2)中提到的一些其他统计参数,该模型将只属于进行实验的特定系统。但是,如果您将其一般化,那么您就有很好的机会为其他类似的系统共享(并应用)这种方法。这在经济学和认识论上都很重要,因为有人可以从你的研究中学到新的东西。
- 最后,你可能意识到有些方程没有实验方法。一些实验无法完成,因为无法进入系统,例如,相对论宇宙学和当代量子力学中的许多实验,薛定谔就是一个很好的例子。据我们所知,例如薛定谔的方程,没有标准的推导方法,它就是有效的——甚至薛定谔自己也不能解释他自己的魔法。因此,在这种情况下,最可靠的方法是执行本文中解释的方法。它也是可行的,假设你有所有的实验工具,但你不知道到底要测量什么或从哪里开始研究——这种情况比你想象的要经常发生。即使在进行回归分析之前,你通常也知道要测量什么,但大多数情况下,如果你没有做好计划,你可能最终会放弃所有这些结果——这是许多博士生的常见问题,尤其是在他们的第一年。他们只是后来才意识到这一点,已经花费了数百小时和数吨的项目研究资金。因此,回归分析可能不是严肃研究的第一步。尽管它对销售分析和其他一些事情很有效,但在大多数其他情况下却不尽如人意。特别是,如果你要执行一个更健壮的项目,就像运筹学中绝大多数需要深入分析的项目一样,你很少能触及本质。
结论
虽然回归分析是分析观察结果和得出结论的重要工具,但它也可能令人望而生畏,尤其是当目标是提出新的方程来全面描述新的科学现象时。在大多数情况下,数据可用性是不准确的,因此衍生模型的通用化和跨平台应用将受到限制。最后,我们仍然无法接触到一些系统特别是相对论宇宙学和当代量子力学中的大多数情况。因此,如果要对一种新现象进行数学研究,一种基于理论分析的更稳健的方法是不可避免的。
ML 中的有限内存 Broyden-Fletcher-goldf ARB-Shanno 算法。网
对 L-BFGS 算法及其使用 ML.NET 实现的简短理论介绍。
前一段时间,我发表了一篇关于使用 ML.NET 实现朴素贝叶斯的文章。今天继续这个系列,我将向你介绍有限记忆的 Broyden-Fletcher-goldf ARB-Shanno 方法。我将从一个理论开始,并解释这个方法是关于什么的,它是用来做什么的。
一些事实
该算法的创造者是豪尔赫·诺塞达尔。它是由阿贡国家实验室和西北大学的合资企业优化中心创建的。最初的源代码是用 FORTRAN 写的。它被称为大规模无约束优化软件。正如您从名字中所料,这种方法类似于 BFGS,但是它使用的内存更少。因此,它非常适合大型数据集。
左旋 BFGS
这是一个来自拟牛顿法族的算法。这些是求函数局部极值的算法,是基于牛顿求函数驻点的方法。
该做些数学了
在这些方法中,使用二次近似来寻找最小值函数 *f(x)。*函数 f(x) 的泰勒级数如下:
其中δf是函数的一个梯度, H 是其黑森。
泰勒级数的梯度看起来是这样的:
我们想找到最小值,也就是解方程:
从这里开始:
现在,应该任命海森。属于这个家族的每个方法都有不同的指定方式。我想我们可以结束这部分了。我不想用这些公式来烦你,但是我想让你对这是怎么回事有一个简单的概念。
BFGS 和 L-BFGS 的区别
正如我前面提到的,L-BFGS 算法适用于大型数据集,因为它比标准 BFGS 需要更少的内存。两种算法都使用 Hessian 逆矩阵估计来控制变量空间搜索。虽然 BFGS 存储了对逆黑森的密集***【n】xn*逼近,但 L-BFGS 只存储了几个隐式表示逼近的向量。这就是节省内存的区别。
数据集
我在实验中使用了 UCI 机器学习库中的皮肤分割数据集。所分析的数据集具有 3 个特征和 2 个类别。这些类确定样本是否被认为是皮肤。该数据集有 245057 个实例,因此 L-BFGS 算法在这里将完美地工作。
实施
在创建了一个控制台应用程序项目并从 NuGet 包中下载了 ML.NET 之后,您可以继续进行实现和模型创建。开始时,您应该创建对应于数据集属性的类。清单中显示了创建的类:
然后,您可以继续加载数据集,并将其分为训练集和测试集。我建议采用流行的划分,即 70%是训练集,30%是测试集。
*var dataPath = "../../skin-segmentation.csv";var ml = new MLContext();var DataView = ml.Data.LoadFromTextFile<Features>(dataPath, hasHeader: true, separatorChar: ',');var partitions = ml.Data.TrainTestSplit(DataView, testFraction: 0.3);*
现在您需要使模型结构适应 model 图书馆提出的标准。这意味着指定类的属性必须称为 Label。其余的属性必须压缩在名称 Features 下。
*var pipeline = ml.Transforms.Conversion.MapValueToKey(inputColumnName: "Class", outputColumnName:"Label")
.Append(ml.Transforms.Concatenate("Features", "V1","V2","V3")).AppendCacheCheckpoint(ml);*
现在是建立培训渠道的时候了。在这里,选择 L-BFGS 形式的分类器,在参数中指定标签和要素的列名。您还指示了表示预测标签的属性。
*var trainingPipeline = pipeline.Append(ml.MulticlassClassification.Trainers.LbfgsMaximumEntropy("Label","Features")).Append(ml.Transforms.Conversion.
MapKeyToValue("PredictedLabel"));*
完成前面的步骤后,您现在可以开始训练和测试模型了:
*var trainedModel = trainingPipeline.Fit(partitions.TrainSet);var testMetrics = ml.MulticlassClassification.
Evaluate(trainedModel.Transform(partitions.TestSet));*
结果和总结
L-BFGS 算法的准确率为 91.8%。结果似乎很好,但是当然,需要更深入的分析和使用其他度量来确认其价值。在本文中,我向您介绍了 L-BFGS 算法,并展示了如何通过 ML.NET 来使用它。它在 lines 的使用仅限于几行代码,但是我认为了解一下这个算法是关于什么的是值得的。
Jupyter 上 Plotly 的折线图动画
Plotly 统一悬停模式,按钮,等等
**Table of Contents**[**Introduction**](#0c1e)1\. [Data preparation](#0dc9)
2\. [All countries line chart](#90a6)
3\. [Adding LOG and LINEAR buttons](#a093)
4\. [Changing hovermode](#2b8b)
5\. [Line chart animation](#7b32)
6\. [Scatter and bar chart animations](#e0ab)[**Conclusion**](#2bbc)
介绍
在本文中,我将尝试使用 Jupyter 上的 Plotly 动画在数据图表中重现我们的世界之一。
ourworldindata.org 是一个优秀的网站,我非常喜欢他们的视觉效果。
上图可以动画显示图形,高亮显示线条,在右侧选择不同的案例,选择线性和对数按钮,选择想要显示的国家。
该项目是一个开源项目,你可以探索他们的 GitHub repo。
它是一个基于 JavaScript 的 app,使用 MySQL 作为数据库和 React、Mobx、TypeScript、Node、Express、D3 和其他 JavaScript。
Plotly 支持创建动画、按钮和可选线条。
然而,目前的 Plotly 动画有一些限制,平滑的帧间过渡只可能用于散点图和条形图。它不支持复选框,尽管用于构建 web 应用程序的 Python 框架 PlotlyDash 支持[Checklist](https://dash.plotly.com/dash-core-components/checklist)
。
本文假设你已经熟悉 JupyterLab/Jupyter 笔记本的基本操作。
Plotly 安装
plotly.py 可以使用 pip 安装。
$ pip install plotly==4.8.1
或者康达。
$ conda install -c plotly plotly=4.8.1
JupyterLab 支持(Python 3.5 以上)
使用画中画:
$ pip install jupyterlab "ipywidgets>=7.5"
或康达:
$ conda install jupyterlab "ipywidgets=7.5"
然后运行以下命令(您需要安装节点):
# JupyterLab renderer support
$ jupyter labextension install jupyterlab-plotly@4.8.1
# OPTIONAL: Jupyter widgets extension
$ jupyter labextension install @jupyter-widgets/jupyterlab-manager plotlywidget@4.8.1
[## 如何在 Docker 上运行 Jupyter 笔记本
不再有 Python 环境和包更新
towardsdatascience.com](/how-to-run-jupyter-notebook-on-docker-7c9748ed209f) [## 如何在 Jupyter 中创建动画条形图
使用 Plotly Python 显示最新美国失业率的数据可视化
towardsdatascience.com](/how-to-create-an-animated-bar-chart-in-jupyter-9ee1de8d0e80) [## 如何用不到 15 行代码创建一个动画的 Choropleth 地图
在 Jupyter 上使用 Python 中的 Plotly Express
towardsdatascience.com](/how-to-create-an-animated-choropleth-map-with-less-than-15-lines-of-code-2ff04921c60b)
数据准备
import pandas as pd
import plotly.express as px
df = pd.read_csv('[https://raw.githubusercontent.com/shinokada/covid-19-stats/master/data/daily-new-confirmed-cases-of-covid-19-tests-per-case.csv](https://raw.githubusercontent.com/shinokada/covid-19-stats/master/data/daily-new-confirmed-cases-of-covid-19-tests-per-case.csv)')display(df.head())
display(df.shape)
原始数据集。它有 26123 行 x 5 列。作者图片
import pandas as pd
import plotly.express as pxdf = pd.read_csv('https://raw.githubusercontent.com/shinokada/covid-19-stats/master/data/daily-new-confirmed-cases-of-covid-19-tests-per-case.csv') excludes = ["World", "Africa", "North America", "South America", "Asia", "Europe", "European Union", "High income", "Low income", "Lower middle income", "Oceania", "Upper middle income", "World excl. China", "World excl. China and South Korea", "International", "World excl. China, South Korea, Japan and Singapore","Asia excl. China"] df=df[~df['Entity'].isin(excludes)]
df.columns = ['Country','Code','Date','Confirmed','Days since confirmed']
df['Date']= pd.to_datetime(df['Date']).dt.strftime('%Y-%m-%d')
df_all=df[(df['Date']>'2020-03-01') & (df['Date'] <'2020-06-14')]
- 导入必要的库、Pandas 和 Plotly.express,将一个逗号分隔值(csv) 文件读入 DataFrame。
excludes
是我们想要排除的Entity
列中的名称列表。isin
方法在Entity
列中找到excludes
值,我们使用~
来排除这些行。- 我们将列名重命名为 Country、Code、Date、Confirmed、Days since confirmed。
- 我们将
Date
列的数据类型从object
更改为datetime
。我们也将它格式化为年-月-日。 - 我们在
Date
列中选择从2020-03-01
到2020-06-14
的行。
display(df.head())
display(df.shape)
准备好的数据集。它有 23414 行 x 5 列。作者图片
所有国家折线图
让我们使用df_all
创建一个折线图。我们设置Date
为 x 轴,Confirmed
为 y 轴,使用Country
为线条颜色。
fig = px.line(df_all, x="Date", y="Confirmed", color="Country")
fig.show()
折线图。作者图片
通过将鼠标光标移动到数据点上,图表能够揭示关于该数据点的更多信息。我们可以通过点击右侧的国家名称来隐藏或显示线条。
添加对数和线性按钮
我们将添加两个改变 y 轴刻度的按钮。
fig = px.line(df_all, x="Date", y="Confirmed", color="Country")
fig.update_layout(
updatemenus=[
dict(
type = "buttons",
direction = "left",
buttons=list([
dict(
args=[{"yaxis.type": "linear"}],
label="LINEAR",
method="relayout"
),
dict(
args=[{"yaxis.type": "log"}],
label="LOG",
method="relayout"
)
]),
),
]
)
fig.show()
使用[update_layout](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Figure.html#plotly.graph_objects.Figure.update_layout)
方法更新图形布局的属性。增加LINEAR
和LOG
两个按钮,并将yaxis.type
相应改为linear
和log
。
线性和对数按钮。作者图片
更换hovermode
Plotly 有三种不同的[hovermode](https://plotly.com/python/hover-text-and-formatting/)
。默认设置是hovermode='closest'
,正如我们在上图中看到的,光标正下方的点会出现一个悬停标签。
对于这个图表,我们将使用统一的hovermode='x unified'
。它显示一个包含所有数据信息的悬停标签。为了清楚起见,我们选择了四个国家。
import numpy as np
import pandas as pd
import plotly.graph_objects as go #plotly 4.0.0rc1 df = pd.read_csv('https://raw.githubusercontent.com/shinokada/covid-19-stats/master/data/daily-new-confirmed-cases-of-covid-19-tests-per-case.csv')
df.columns = ['Country','Code','Date','Confirmed','Days since confirmed']
df['Date']= pd.to_datetime(df['Date']).dt.strftime('%Y-%m-%d')
df=df[(df['Date']>'2020-03-15') & (df['Date'] <'2020-06-14')] includes=['United States','Russia', 'India','Brazil']df_selected=df[df['Country'].isin(includes)] fig = px.line(df_selected, x="Date", y="Confirmed", color="Country") fig.update_layout(
hovermode='x unified',
updatemenus=[
dict(
type = "buttons",
direction = "left",
buttons=list([
dict(
args=[{"yaxis.type": "linear"}],
label="LINEAR",
method="relayout"
),
dict(
args=[{"yaxis.type": "log"}],
label="LOG",
method="relayout"
)
]),
),
]
)
fig.show()
hovermode='x unified' in a line chart. Image by the author
折线图动画
Plotly 动画有一些限制,并且不支持折线图。
可以制作折线图动画,但它不如其他动画(如条形图和散点图)简洁。
import numpy as np
import pandas as pd
import plotly.graph_objects as godf = pd.read_csv('[https://raw.githubusercontent.com/shinokada/covid-19-stats/master/data/daily-new-confirmed-cases-of-covid-19-tests-per-case.csv'](https://raw.githubusercontent.com/shinokada/covid-19-stats/master/data/daily-new-confirmed-cases-of-covid-19-tests-per-case.csv'))
df.columns = ['Country','Code','Date','Confirmed','Days since confirmed']
df['Date']= pd.to_datetime(df['Date']).dt.strftime('%Y-%m-%d')
df=df[(df['Date']>'2020-03-15') & (df['Date'] <'2020-06-14')]usa=df[df['Country'].isin(['United States'])]
brazil=df[df['Country'].isin(['Brazil'])]
india=df[df['Country'].isin(['India'])]
russia=df[df['Country'].isin(['Russia'])]trace1 = go.Scatter(x=usa['Date'][:2],
y=usa['Confirmed'][:2],
mode='lines',
line=dict(width=1.5))trace2 = go.Scatter(x = brazil['Date'][:2],
y = brazil['Confirmed'][:2],
mode='lines',
line=dict(width=1.5))trace3 = go.Scatter(x = india['Date'][:2],
y = india['Confirmed'][:2],
mode='lines',
line=dict(width=1.5))trace4 = go.Scatter(x = russia['Date'][:2],
y = russia['Confirmed'][:2],
mode='lines',
line=dict(width=1.5))frames = [dict(data= [dict(type='scatter',
x=usa['Date'][:k+1],
y=usa['Confirmed'][:k+1]),
dict(type='scatter',
x=brazil['Date'][:k+1],
y=brazil['Confirmed'][:k+1]),
dict(type='scatter',
x=india['Date'][:k+1],
y=india['Confirmed'][:k+1]),
dict(type='scatter',
x=russia['Date'][:k+1],
y=russia['Confirmed'][:k+1]),
],
traces= [0, 1, 2, 3],
)for k in range(1, len(usa)-1)]layout = go.Layout(width=700,
height=600,
showlegend=False,
hovermode='x unified',
updatemenus=[
dict(
type='buttons', showactive=False,
y=1.05,
x=1.15,
xanchor='right',
yanchor='top',
pad=dict(t=0, r=10),
buttons=[dict(label='Play',
method='animate',
args=[None,
dict(frame=dict(duration=3,
redraw=False),
transition=dict(duration=0),
fromcurrent=True,
mode='immediate')]
)]
),
dict(
type = "buttons",
direction = "left",
buttons=list([
dict(
args=[{"yaxis.type": "linear"}],
label="LINEAR",
method="relayout"
),
dict(
args=[{"yaxis.type": "log"}],
label="LOG",
method="relayout"
)
]),
),
]
)layout.update(xaxis =dict(range=['2020-03-16', '2020-06-13'], autorange=False),
yaxis =dict(range=[0, 35000], autorange=False));fig = go.Figure(data=[trace1, trace2, trace3, trace4], frames=frames, layout=layout)
fig.show()
如果我们愿意,我们可以增加更多的国家。
- 我们创建四个独立的数据帧。您可以增加或减少国家的数量。
- 我们用自己的
x
、y
、mode
和line
值创建四个轨迹。如果你改变了国家的数量,你也需要在这里进行调整。 - 我们用
data
列表值创建框架。traces=[0,1,2,3]
用于迭代frame[k]['data'][0]
、frame[k]['data'][1]
等。如果您更改国家的数量,同样,您需要调整这里的代码。如traces=[0,1,2,3,4,5]
。 - 我们设置了
width
、height
、hovermode
和updatemenus
。我们设置了两种按钮,一种用于播放,另一种用于LINEAR
和LOG
。 [update](https://plotly.com/python-api-reference/generated/plotly.graph_objects.Figure.html?highlight=update#plotly.graph_objects.Figure.update)
用带有关键字参数的dict
更新图形的属性。
我们创建一个新的Figure
实例,并添加我们在第 15–33 行创建的所有跟踪。如果您更改了国家的数量,您需要更新这一行。
Plotly 折线图动画。图片由作者提供。
散点图和条形图动画
Plotly 支持散点图和条形图动画。
你可以在这里找到代码。
散点图动画。图片由作者提供。
您可以通过添加fig["layout"].pop("updatemenus")
来删除动画按钮,并将其用作滑块。
pop("updatemenus ")放下动画按钮。图片由作者提供。
在条形图动画中,我们可以悬停以查看更多详细信息,并且可以通过单击右侧菜单来隐藏/显示项目。
条形图动画。图片由作者提供。
结论
它与我们在数据网站中的世界并不完全相同,但我们学会了如何创建折线图、折线图动画、添加统一的悬停模式以及添加按钮。
目前,Plotly 需要更多代码来制作折线图动画。此外,如果散点图可以为动画绘制轨迹线和速度控制参数,那就太好了。
通过 成为 会员,获得媒体上所有故事的访问权限。
https://blog.codewithshin.com/subscribe
[## 如何用 Python 中的 Plotly Express 创建分组条形图
Python melt 函数将数据帧从宽到长格式化
towardsdatascience.com](/how-to-create-a-grouped-bar-chart-with-plotly-express-in-python-e2b64ed4abd7) [## 如何在 Jupyter 中创建一个有吸引力的气泡图
从 Github repo 抓取数据的分步指南
towardsdatascience.com](/how-to-create-an-attractive-bubble-map-5cf452c244e9) [## 如何在 Jupyter 中创建交互式下拉列表
用下拉菜单更新图表
towardsdatascience.com](/how-to-create-an-interactive-dropdown-in-jupyter-322277f58a68)
线性代数
机器学习的隐藏引擎
迈克尔·泽兹奇在 Unsplash 上的照片
一个代数最早是取自 Khwarizmi(780-850 CE)写的一本关于计算和方程的书。它是数学的一个分支,用字母代替数字。每个字母在一个地方可以代表一个特定的数字,在另一个地方可以代表一个完全不同的数字。在代数中,记号和符号也被用来表示数字之间的关系。记得大概 17 年前我还是一个应用数学的普通学生(今天普通毕业生!),我对哈佛大学玛丽亚姆·米尔扎哈尼(1977-2017)在代数方面的一些研究非常好奇,这些研究是关于类比计数问题的。这门科学在历史上发展了很多,现在包括了许多分支。
初等代数包括四种主要运算的基本运算。在定义了分隔定数和变量的符号之后,就可以用一些方法来求解这些方程。多项式是有限个非零项之和的表达式,每个项都由一个常数和有限个整数次幂的变量的乘积组成。
抽象代数或近世代数是代数家族中研究群、环、域等高级代数结构的一个群。代数结构及其相关的同态构成了数学范畴。范畴理论是一种形式主义,它允许用一种统一的方式来表达各种结构的相似性质和结构。抽象代数是如此受欢迎,并在数学和工程科学的许多领域使用。例如,代数拓扑使用代数对象来研究拓扑。2003 年证明的庞加莱猜想断言,流形的基本群编码了关于连通性的信息,可以用来确定流形是否是球面。代数数论研究推广整数集合的各种数环。
我相信其他科学中最有影响力的代数分支是线性代数。让我们假设你出去慢跑,在新冠肺炎一级防范禁闭的情况下,这可不容易,突然一朵美丽的花吸引了你所有的注意力。请不要急着去摘,只是拍张照片,其他人也可以欣赏。过一会儿当你看这张照片时,你可以认出图像中的花,因为人类的大脑已经进化了数百万年,能够探测到这样的东西。我们不知道在我们大脑的背景中发生的操作,这些操作使我们能够识别图像中的颜色,它们被训练为自动为我们做这些。但是,用机器做这样的事情并不容易,这就是为什么这是机器学习和深度学习中最活跃的研究领域之一。实际上,最根本的问题是:“机器是如何存储这个图像的?”你可能知道今天的计算机只能处理两个数字,0 和 1。现在,像这样有不同特征的图像如何存储?这是通过将像素强度存储在一个称为“矩阵”的结构中来实现的。
线性代数的主要课题是向量和矩阵。向量是有长度和方向的几何对象。例如,我们可以提到速度和力,它们都是矢量。每个向量由一个箭头表示,箭头的长度和方向表示向量的大小和方向。两个或多个矢量的相加可以基于使用平行四边形方法或图像方法的易用性来完成,在图像方法中,每个矢量被分解成沿坐标轴的分量。向量空间是向量的集合,这些向量可以通过标量相加和相乘。标量通常可以从任何字段中选取,但通常是实数。
矩阵是二维的有序数字阵列,通常有 m 行和 n 列。如果两个矩阵大小相同,这意味着每个矩阵都有相同的行数和列数,就像另一个一样,它们可以逐个元素地相加或相减。只有当第一个矩阵的列数与第二个矩阵的行数相同时,我们才能将这些矩阵相乘。例如,假设内部维度是相同的,一个(m×n)矩阵的 n 乘以一个(n×p),则得到一个(m×p)矩阵。
机器学习中广泛使用的另一个重要概念是张量。张量是描述与向量空间相关的代数对象集之间的多线性关系的代数对象。张量可以有几种不同的形式,一般来说,二维和更高的二维张量也称为矩阵。矩阵用于创建问题数据与其信息分类之间的顺序。
三维张量
例如,张量用于图像处理,可能一个维度用于宽度,一个维度用于高度,一个维度用于颜色,还有一个维度用于焦点信息。为了联系所有的概念,我们从上面了解到,我们可以说,零维的张量是标量,一维的是向量,最后二维的是矩阵。近年来,开发了用于编程语言的库,以方便张量的使用及其快速处理。其中之一是谷歌开发的 TensorFlow。谷歌还开发了一种专用集成电路,称为张量处理器单元(TPU),用于高效、快速地计算神经网络的张量。
特征向量和特征值是机器学习中广泛使用的另一个重要概念。线性变换的特征向量是一个非零向量,当对其应用线性变换时,该向量按一个标量因子变化。特征值是一组特殊的非零尺度,特征向量将被它拉伸。如果标度是负的,方向将是相反的。
前缀“eigen”来源于德语,意思是特征。特征向量在工程科学中有各种应用,其中之一是它在机器学习算法中的应用,以执行特征约简和维度操作。
蓝色箭头是这个剪切映射的特征向量,因为它不改变方向,并且由于它的长度不变,所以它的特征值是 1。
在机器学习中,我们需要处理向量和矩阵形式的数据的基础知识,获得解线性代数方程组的技能,找到基本的矩阵分解,并对它们的适用性有一个大致的了解。实际上,你必须知道什么是向量和矩阵,以及如何使用它们,包括特征值和特征向量的棘手问题,以及如何使用这些来解决问题。
如果你想学习更多的线性代数知识,不要从零开始,以一种学术的风格。依靠定义,尝试用机器学习算法及其隐藏引擎方法解决一些问题。
参考
班纳吉、苏迪普托;Roy,Anindya (2014),用于统计的线性代数和矩阵分析,统计科学文本(第 1 版。),查普曼和霍尔/CRC,ISBN 978–1420095388
斯特朗,吉尔伯特(2005 年 7 月 19 日),《线性代数及其应用》(第 4 版。),布鲁克斯·科尔,ISBN 978–0–03–010567–8
夏普(2000 年 11 月 21 日)。微分几何:卡坦对克莱因的埃尔兰根程序的推广。施普林格科学&商业媒体。第 194 页。ISBN 978–0–387–94732–7。
威廉·布朗(1991),矩阵与向量空间,纽约:m .德克尔,ISBN 978–0–8247–8419–5
*西亚达提,萨曼。(2014).代数的第一课。10.13140/*T3
数据科学的线性代数:一种新的开始方式—第 1 部分
数据科学的思考
吉尔伯特·斯特朗教授关于线性代数的观点和建议
安迪·霍姆斯在 Unsplash 上的照片
线性代数可能是数据科学、模式识别和机器学习的最基本的构建模块之一。我认为,理解基础是任何人在追求高级主题之前应该做的第一件事。为什么?因为我们不想陷入在高级话题和基础知识之间来回循环的怪圈!
在这一系列中,我将讨论 Gilbert Strang 教授在其最新系列讲座“2020 年线性代数展望”中涉及的主题。这是一个优秀的系列讲座,他在应用线性代数教学中采用自上而下的方法。我在这里的目的是与你们分享我对相关细节的理解,我相信这将有助于以更好和细致入微的方式理解讲座。
所以让我们开始吧!
第 1 部分涵盖的主题:
- 矩阵的行列空间
- 秩、零空间和无效性
- 秩 1 矩阵
- CR 分解
列间距和行间距
为了理解列空间和行空间,我们首先需要理解“跨度”,它只不过是一组向量的所有可能的线性组合的集合。因此,矩阵 A 的列间距和行间距被定义为矩阵 A 的列和行的跨度。
的列的线性组合
A 的列间距= C(A) =所有向量 *Ax。*换句话说,就是矩阵 A. 中线性无关列所跨越的空间,这里我们可以看到,第 3 列( c3 )可以表示为第 1 列( c1 )和第 2 列( c2 ) *,*我们只有两个线性无关列 *(c1 和 c2)。*这里的 c1 和 c2 称为列空间的基础。形式上,一个空间的基被定义为一组线性独立并跨越该空间的向量。
矩阵 A 跨越 R(平面)而不是 R (3D 空间),尽管是一个 3x3 矩阵。
同样的概念也适用于行空间。在这种情况下,只需用行替换列。此外,列空间的维度总是与行空间的维度相同。这只是到达同一点的另一种方式。当研究线性代数的四个基本空间时,我们将详细地重新讨论行空间和列空间。
军阶
秩被定义为向量空间的列所跨越的维度,其等于线性无关列的数量(列秩)以及线性无关行的数量(行秩)。请注意,行秩总是等于列秩,数学家证明超出了本文的范围,但是直观上,因为列和行空间跨越相同的向量空间,所以它们的维数必须相同。计算矩阵秩的一种常用方法是通过高斯消去法和计算枢轴数(行梯队形式中每行的第一个非零元素)来减少行梯队形式的矩阵。
矩阵及其行梯队形式
这里,矩阵的秩等于 2,因为在其行梯队形式中有两个枢纽元素。
零空间和无效
既然我们一直在谈论不同种类的空间,我们不要忘记它的起源。毕竟,不定义原点就不能定义空间。我们将零空间定义为所有向量乘上矩阵 *A,*即 Ax = 0 后变成零(原点落地)的空间。
零度被定义为零空间的维数。它给我们带来了一个非常特殊的结果**秩(A) +无效性(A) =维数(A)。**这就是秩零定理。
秩 1 矩阵
秩 1 矩阵本质上是矩阵代数的构造块。您现在一定已经猜到了,如果矩阵只有一个独立的列和一个独立的行,那么它的秩是 1。奇怪吗?你一定想知道这个矩阵会包含什么信息?它包含的信息比看起来要少得多。我们稍后将回到他们身上。
矩阵 A 是两个向量的外积
秩 1 矩阵可以被视为两个向量的外积。这是一个非常特殊的结果,因为它可以被看作矩阵 A 有很大的维数,但它只跨越了一个 1D 空间!还有,任何矩阵变换都可以看成是 n 秩为 1 的矩阵之和(给你一个小作业!).
铬分解
现在,在了解了基本概念之后,让我们深入了解一种独特的分解技术,这种技术在许多数据科学、统计学和数据分析问题中被高度使用,即 CR 分解。
在 CR 分解中,像任何其他矩阵分解一样,我们将矩阵 A 表示为两个矩阵 C 和 R *的乘积。*矩阵 C 和 R 被描述为:
- 矩阵 C 包含矩阵 A 的独立列
- 矩阵 R 包含了行空间 A 的基础
让我们看一个例子:
矩阵 A 的 CR 分解
观察结果:
- 可以看到,矩阵有两个独立的列 c1 和 c2 构成了矩阵 C ,矩阵包含了行空间的基础,也就是说,告诉我们如何使用矩阵 C 的列来重构矩阵**
- 的 r (= 2)列是独立的(根据它们的构造)
- A 的每一列都是那些 r 列的组合。
- 的 r (= 2)行是独立的。
- 每一排 A 都是那些 r 排的组合。
关键要点:
- C 有列直接来自 A 。它可以提供关于矩阵的向量空间的有意义的信息。
- R 原来是排的缩减梯队形式的矩阵 一个 。**
- 矩阵的行秩=列秩
- C :列基, R :矩阵的行基 A 。
- 如果 A 是可逆矩阵那么C = AR = I。
在本系列接下来的部分中,我将涉及的主题包括但不限于:
- 线性代数的大局。
- 正交矩阵及其应用。
- 不同的矩阵分解技术及其应用。
- 奇异值分解、主成分分析,以及它们之间的相互关系。
- 矩阵分解在一些现实应用中的应用。
希望这对你有帮助。下次见。谢谢大家!
参考
[1]吉尔伯特斯特朗。线性代数的 2020 年愿景。【2020 年春季。麻省理工学院:麻省理工学院开放课件,【https://ocw.mit.edu】T2。许可:知识共享协议 BY-NC-SA 。
[2]吉尔伯特·斯特朗。 18.06 线性代数。2010 年春天。麻省理工学院:麻省理工学院开放课件,https://ocw.mit.edu。许可:知识共享协议 BY-NC-SA 。
数据科学的线性代数 Ep 3-恒等矩阵和逆矩阵
用 NumPy 的线性代数类求解线性方程组
点积 (Ep2)帮助我们表示方程组,我们可以继续讨论恒等式和逆矩阵。正如我们将看到的,这两种类型的矩阵帮助我们求解线性方程组。基于上述概念,我们将使用 NumPy 进一步求解一个由 2 个方程组成的系统。
如果你想看我向你解释这些概念,而不是读这个博客:
恒等式矩阵
一种特殊的矩阵,其主对角线单元格用 1 填充,其余单元格用 0 填充。以下是 3×3 身份矩阵的样子:
3×3 恒等式矩阵
属性:
恒等式矩阵类似于 1(标量),表示将恒等式矩阵应用(相乘)到向量或矩阵对受试者没有影响。
例如:
Ix = x
在那里,
I为身份矩阵
x是一个向量
代码:
我们可以使用 NumPy 的eye()
方法创建一个身份矩阵。
import numpy as np
I = np.eye(3)
上面的代码返回一个 3×3 的身份矩阵,如下所示:
在代码中确认属性后,我们可以用向量或矩阵计算点积,如下所示:
注:确保满足乘法规则。
逆矩阵
A 矩阵的逆是矩阵乘以 A 本身,返回恒等式矩阵。它是由 一 ⁻所表示的。
数学上:
直觉告诉我们,如果我们用矩阵 A、 对空间进行线性变换,我们可以通过将 A⁻再次应用于空间来恢复变化。
注:如果矩阵的行列式为零,则没有和的逆;矩阵被认为是奇异的。只有非奇异矩阵才有逆。
代码:
我们可以用 NumPy 的 array()
方法创建一个 2D 阵列,然后用linalg.inv()
方法找出它的逆阵。
A = np.array([[3,0,2], [2,0,-2], [0,1,1]])
A_inv = np.linalg.inv(A)
现在,既然我们已经生成了逆,我们就可以通过计算 A 与 A ⁻的点积来检查属性:
返回单位矩阵
因此,该性质对逆矩阵成立。
求解线性方程组
正如在ep2中所解释的,我们可以用矩阵来表示线性方程组。现在,我们可以用逆矩阵来求解。
对于任何方程 Ax = b, 我们可以简单地将方程两边的 A ⁻相乘,我们将得到一个对 x 没有任何影响的单位矩阵,因此我们的 x 将是a⁻b为
示例:
假设我们有一个如下所示的方程组,现在这个方程组首先需要用一种格式来表示,在这种格式中,它可以用右边的方法以 Ax = b 的形式来表示。
将所有未知项移至左侧,常数移至右侧后,我们现在可以写出上述系统的矩阵形式:
现在,我们需要做的就是使用 NumPy 在代码中创建这些矩阵和向量,然后找出x=a⁻b .
代号:
A = np.array([[2,-1], [1,1]])A_inv = np.linalg.inv(A)b = np.array([[0], [3]])x = A_inv.dot(b)
输出:x = [[1],[2]]
我们计算过的 x(1,2) 就是系统中 2 个方程的交点。
我们可以通过使用 matplotlib 绘制这两条线来确认我们的答案:
x = np.arange(-10, 10)
y1 = 2*x
y2 = -x + 3import matplotlib.pyplot as plt
plt.figure()
plt.plot(x, y1)
plt.plot(x, y2)
plt.xlim(0,3)
plt.ylim(0,3)
plt.grid(True)plt.show()
下面是您将得到的输出图,它证实了我们的答案:
摘要
这是关于单位矩阵和逆矩阵,它们是其他重要概念的基础。下一集将介绍线性相关和跨度。敬请关注 Harshit,继续学习数据科学。
Harshit 的数据科学
通过这个渠道,我计划推出几个覆盖整个数据科学领域的系列。以下是你应该订阅频道的原因:
- 该系列将涵盖每个主题和子主题的所有必需/要求的高质量教程,如 Python 数据科学基础。
- 解释了为什么我们在 ML 和深度学习中做这些事情的数学和推导。
- 与谷歌、微软、亚马逊等公司的数据科学家和工程师以及大数据驱动型公司的首席执行官的播客。
- 项目和说明实施到目前为止所学的主题。
数据科学中的线性代数:线性代数的大图景—第 2 部分
数据科学的思考
线性代数基本定理的序言
格雷格·拉科齐在 Unsplash 上的照片
快速介绍一下,在这个系列中,我将重温吉尔伯特·斯特朗教授在其最新系列讲座“2020 年线性代数展望”中讨论的主题。这篇文章是“数据科学的线性代数”系列的第二部分,我建议你浏览第一部分,这样你就不会错过流程。
我在这里的目的是与你们分享我对相关细节的理解,我相信这将有助于以更好和细致入微的方式理解讲座。
所以让我们开始吧!
第 2 部分涵盖的主题:
在这一部分,我将主要讨论线性代数的四个基本子空间以及它们之间的关系。
- 向量空间的子空间
- 四个基本子空间
- 基本子空间的基
- 大局!
子空间
如果 V 是实数域上的向量空间,定义为并且 W 是 V 的子集,那么 W 是V的子空间例如,让向量空间 V 是实数坐标空间 R 并且 W 是最后一个分量为 0 的 V 中所有向量的集合那么 W 就是 V 的子空间。矩阵方面,设 A 是一个 3 乘 2 的矩阵,那么列空间是子空间如果 R,行空间是子空间如果 R。
在 R 中,两个不同的二维子空间的交集。牡蛎弗雷德,CC BY-SA 4.0
四个基本子空间
吉尔伯特·斯特朗的《线性代数基本定理》描述了一个 m 乘 n 矩阵 A 的作用。矩阵 A 产生从 R^n 到 R^m 的线性变换,但是这个图片本身太大了。关于 Ax = b 的“真值”用四个子空间来表示(两个是 R^n 的,两个是 R^m).的第一步是把 Ax 看成 a 的列的组合,这一步把视点上升到子空间。我们在列空间中看到 Ax 。求解 Ax = b 就是找到列空间中产生 b 的列的所有组合。
四个基本子空间是:
- 列空间 C(A),R^m 的一个子空间
- 行空间c*(a’),*r^n 的一个子空间(a’= a 的转置)
- 零空间 N(A),R^n 的子空间
- 左零空间n(a’),R^m 的子空间
列间距的基础
从第 1 部分我们知道列空间的维数等于行空间的维数,等于矩阵 A,的秩 r 即dim(C(A))= dim(C(A’)= r**。
我们还看到,为了计算列空间的基础,我们需要减少矩阵 A 的行梯队形式,并挑选对应于枢纽元素的列。现在我们来看看如何计算其他三个子空间的基。
行空间的基础
在继续之前,让我们与我们将使用的符号保持一致:
- A 是一个m×n矩阵
- *A’*是转置如果 A
- R 是 A 的缩减行梯队形式这是一个特例,当每个前导 1 是其列中唯一的非零条目。
矩阵 A 及其简化的行梯型 R
为了找到行空间的基础,我们首先将矩阵简化为简化的行梯队形式,并在 R 中选取行,这构成了大小等于秩 r. 的单位矩阵如上图所示,行空间的基础是前两行。所以,这里行空间的基础是 R 的前两行。
请注意,在从 A 到 R 的转换中,行间距保持不变,但列间距发生了变化。
零空间的基础
为了得到 A 的零空间的基,我们需要解齐次方程组, Ax = 0 。我们首先获得对应于矩阵 A 的缩减行梯队形式矩阵,然后找到对应于自由变量的系数(对应于缩减行梯队形式中非枢纽列的变量)。让我们试着借助一个例子来理解:
矩阵 A 及其简化的行梯型 R
求解 Ax = 0,我们得到上面的解
左零空间的基
左边的零空间也可以看作是零空间。所以,在这种情况下,我们求解 A’ y = 0。 你可能会奇怪为什么会“留下”零空间?嗯,这背后没有数学上的原因,但只是为了证明我们的选择,让我们建立一个解释(所有信贷斯特朗教授!).让我们在方程的两边进行转置 A’y = 0。 现在相当于 y’ A = 0。 请注意,这里的零点向量现在是一个行向量。由于***y’***现在出现在矩阵 A 的左边,我们称这个空间为左零空间。
找到左零空间的一个显而易见的方法是像我们求解零空间一样求解方程,但是等等,干!(不重复!).我们换一种方式做吧!耶!
从我们的第二个公式中,我们知道***y’***现在是 A 左边的一个行向量,它在右边产生一个零的行向量。让我们利用这一点。
记住我们在确定行空间时所做的,我们将我们的矩阵 A 转换为R .【Let】,将一个 m x m 单位矩阵扩充为 m x n 矩阵 A,并执行相同的步骤,现在将把**【A | I】转换为【R | E】,** 其中 R 是m x nE 是 m x m. 让我们花一分钟来观察发生了什么……我们应用了与应用于矩阵 A 相同的行变换来获得 R 到矩阵 I 来获得 E. 它的意思是,【T42
请注意:当 A 可逆时,R = I,E =逆(A)
**
将*【A | I】还原为【R | E】***
如上式, EA = R 同解 y’ A = 0, 从矩阵 R 我们可以看到,秩(A) = 2。所以,左零空间的维数= 3-2 = 1,即列空间-秩的维数。因此, A 的左零空间的基对应于 E 中产生 R 中零行的行,即 [ -1 0 1】。
大局!
现在看到大图,你就能猜到为什么叫“大图”了。它是所有四个基本子空间的本质都在一个地方!因此,让我们注意它包含哪些信息:
- 有四个基本的子空间,行空间、列空间、零空间和左零空间
- 维度(行空间)=维度(列空间)=等级
- Dim(零空间)= n-r,其中 n =行的维度
- Dim(左零空间)= m-r,其中 m =列的维度
- 任何转换 Ax = b 将 x 从行空间转换到列空间。
- 任何转换 Ax = 0 将 x 从行空间转换到左零空间。
- 行空间和零空间是正交的,列空间和左零空间彼此正交(我们将在接下来的部分中讨论正交性)
我希望这有所帮助。下次见。谢谢大家!
参考
[1]吉尔伯特斯特朗。线性代数的 2020 年愿景。【2020 年春季。麻省理工学院:麻省理工学院开放课件,【https://ocw.mit.edu】T2。许可:知识共享协议 BY-NC-SA 。
[2]吉尔伯特·斯特朗。 18.06 线性代数。2010 年春天。麻省理工学院:麻省理工学院开放课件,https://ocw.mit.edu。许可:知识共享协议 BY-NC-SA 。
面向数据科学家的线性代数—用 NumPy 解释
线性代数的核心概念和实践。
作者图片
机器学习和深度学习模型需要大量数据。它们的性能高度依赖于数据量。因此,我们倾向于收集尽可能多的数据,以便建立一个稳健而准确的模型。数据以多种不同的格式收集,从数字到图像,从文本到声波。然而,我们需要将数据转换成数字,以便对其进行分析和建模。
仅仅将数据转换成标量(单个数字)是不够的。随着数据量的增加,用标量完成的操作开始变得低效。我们需要矢量化或矩阵运算来有效地进行计算。这就是线性代数发挥作用的地方。
线性代数是数据科学领域中最重要的课题之一。在这篇文章中,我们将通过使用 NumPy 的例子来介绍线性代数中的基本概念。
NumPy 是 Python 的科学计算库,是许多库(如 Pandas)的基础。
线性代数中的对象类型
线性代数中的对象(或数据结构)类型:
- 标量:单一数字
- Vector:数字数组
- 矩阵:数字的二维数组
- 张量:N 维数组,其中 n > 2
一个标量只是一个数字。正如我们将在下面的例子中看到的,它可以用于矢量化运算。
向量是一个数字数组。例如,下面是一个包含 5 个元素的向量:
我们可以在矢量化运算中使用标量。对向量和标量的每个元素执行指定的操作。
矩阵是一个二维向量。
它看起来像一个有行和列的熊猫数据框架。实际上,熊猫数据帧被转换成矩阵,然后输入机器学习模型。
张量是一个 N 维数组,其中 N 大于 2。张量主要用于深度学习模型,其中输入数据是三维的。
很难用数字来表示,但是可以把 T 想象成 3 个 3x2 的矩阵。
shape 方法可用于检查 numpy 数组的形状。
数组的大小通过乘以每个维度的大小来计算。
常见矩阵术语
如果行数等于列数,则称一个矩阵为方阵。因此,上面的矩阵 A 是一个方阵。
**单位矩阵,**表示为 **I,**是对角线上有 1 而其他位置都有 0 的方阵。NumPy 的单位函数可以用来创建任意大小的单位矩阵。
单位矩阵的特殊之处在于它在相乘时不会改变矩阵。在这个意义上,它类似于实数中的数字 1。我们将在这篇文章的矩阵乘法部分用单位矩阵做例子。
矩阵的逆是与原矩阵相乘时给出单位矩阵的矩阵。
不是每个矩阵都有逆矩阵。如果矩阵 A 有逆,则称其为可逆或非奇异。
点积和矩阵乘法
点积和矩阵乘法是复杂机器学习和深度学习模型的构建模块,因此全面了解它们是非常有价值的。
两个向量的点积是关于它们位置的元素乘积的和。第一个向量的第一个元素乘以第二个向量的第一个元素,依此类推。这些乘积之和就是点积。NumPy 中计算点积的函数是 dot() 。
让我们首先以 numpy 数组的形式创建两个简单的向量,并计算点积。
点积的计算方法是(12)+(24)+(3*6),即 28。
因为我们在相同的位置乘元素,为了得到点积,两个向量必须有相同的长度。
在数据科学领域,我们主要处理矩阵。矩阵是一组以结构化方式组合的行和列向量。因此,两个矩阵的乘法涉及许多向量的点积运算。当我们复习一些例子时会更清楚。我们先用 NumPy 创建两个 2x2 矩阵。
2×2 矩阵有 2 行 2 列。行和列的索引从 0 开始。例如,的第一行(索引为 0 的行)是[4,2]的数组。的第一列是[4,0]的数组。第一行第一列的元素是 4。
我们可以访问单独的行、列或元素,如下所示:
这些是理解矩阵乘法的重要概念。
两个矩阵的乘法涉及第一矩阵的行和第二矩阵的列之间的点积。第一步是 A 的第一行和 b 的第一列之间的点积。该点积的结果是结果矩阵在位置0,0的元素。
所以得到的矩阵 C 在第一行和第一列有一个(44) + (21)。 C[0,0] = 18。
下一步是 A 的第一行和 b 的第二列的点积。
c 将在第一行和第二列有一个(40) + (24)。 C[0,1] = 8。
第一行 A 已完成,因此我们从 A 的第二行开始,并遵循相同的步骤。
c 在第二行第一列有一个(04) + (31)。 C[1,0] = 3。
最后一步是 A 的第二行和 b 的第二列之间的点积。
c 将在第二行第二列有一个(00) + (34)。 C[1,1] = 12。
我们已经看到它是如何一步一步完成的。所有这些操作都是用一个 np.dot 操作完成的:
您可能还记得,我们提到过单位矩阵在相乘时不会改变矩阵。我们来做一个例子。
我们也提到过,当一个矩阵乘以它的逆矩阵时,结果就是单位矩阵。让我们首先创建一个矩阵,并找到它的逆。我们可以用 NumPy 的 linalg.inv() 函数求一个矩阵的逆。
让我们把 B 和它的逆矩阵 C 相乘:
答对了。我们有单位矩阵。
正如我们从矢量点积中回忆的那样,两个矢量必须有相同的长度,才能得到点积。矩阵乘法中的每个点积运算都必须遵循这个规则。点积在第一个矩阵的行和第二个矩阵的列之间完成。因此,第一矩阵的行和第二矩阵的列必须具有相同的长度。
矩阵乘法的要求是第一个矩阵的列数必须等于第二个矩阵的行数。
例如,我们可以将一个 3×2 的矩阵乘以一个 2×3 的矩阵。
结果矩阵的形状将是 3x3,因为我们对 A 的每一行进行 3 次点积运算,而 A 有 3 行。确定最终矩阵形状的一个简单方法是从第一个矩阵中获取行数,从第二个矩阵中获取列数:
- 3x2 和 2x3 相乘得出 3x3
- 3x2 和 2x2 相乘得出 3x2
- 2x4 和 4x3 乘法返回 2x3
我们已经讨论了线性代数的基本但非常基础的运算。这些基本操作是复杂机器学习和深度学习模型的构建模块。在模型的优化过程中,需要进行大量的矩阵乘法运算。因此,理解基础知识也是非常重要的。
感谢您的阅读。如果您有任何反馈,请告诉我。