厄瓜多尔移动网络运营商的覆盖范围
原文:https://towardsdatascience.com/mobile-network-operators-coverage-in-ecuador-9fdd78d3b4fb
2G、3G 和 4G 蜂窝天线发展的地理可视化
图片由作者提供。厄瓜多尔从 2008 年开始开放细胞识别数据。2G 蓝色,3G 粉色 4G 黄色
自 2017 年以来, OpenCell ID 组织一直在向世界各地的社区收集蜂窝天线的位置。这个开放数据项目包含大约 3.3GB 的全球压缩数据,包括位置属性、移动网络运营商代码、覆盖范围和国家代码。该数据集有助于公共/私人机构了解天线覆盖的模式。如今,美国是覆盖范围最广的国家(就小区数量而言),约有 700 万个,其次是德国,约有 200 万个。
为电信开发的最新技术是 5G,它覆盖了数据速率高达 20Gbps 的移动宽带(比传统移动技术快得多)。第一个将 5G 技术商业化的国家是 2019 年的韩国,如今是这一发展的领导者。[ 1 到 2021 年,5G 发展排名前 10 位的国家是韩国、挪威、阿联酋、沙特、卡塔尔、科威特、瑞典、中国、中国台湾和新西兰。
厄瓜多尔仍然未能达到这一技术,仍然严重依赖 2G 和 3G 连接,样本超过 20%。[ 2
蜂窝天线是干什么用的?
在移动电话上进行的每一次连接都记录在近距离天线中。与移动数据连接相关的通话、信息和操作都存储在使用手机的蜂窝天线中。在国家和全球层面,存储了来自作为移动网络运营商客户的数百万用户的大量数据。数据是匿名的,主要反映用户不同位置的 pings。
一些公司在分析开发如此庞大的数据量方面很聪明。分析的洞察力可以揭示内部人口、国际旅游和网络统计的流动情况。令人惊讶的是,这一分析已被联合国证实是可靠的,并可被世界各国统计局用于官方统计。
爱沙尼亚公司*Positium是移动定位数据分析领域的领导者。出席 2021 年世界数据论坛的这家私营公司讲述了他们为支持新冠肺炎紧急情况而采取的行动,为人口流动提供了一个创新的仪表盘。*
如果你愿意了解移动定位数据的分析结果及其应用,我建议你阅读这个故事:
*
目标
这个故事旨在展示如何操作来自 OpenCell ID 的数据以及如何将其可视化。就类别而言:
- 移动网络运营商
- 通过 2G、3G(厄瓜多尔使用最多)和 4G 技术
- 靠你自己的创造力
数据许可证
- OpenCell ID 的数据库是在知识共享署名-共享 4.0 国际许可下许可的。
地理可视化实践
找到您感兴趣的国家,并从 Open Cell ID 下载数据。然后你解压数据,就像这样:
**from** datetime **import** datetime
**import** pandas **as** pd**# read with Pandas**
data = pd.read_csv(r’740.csv.gz’, header=None, compression=’gzip’)
国家数据的第一个问题是它不包含列名。为了帮助你,你可以像这样添加它们:
**# change columns of OpenCell** col_names = [‘radio’, ‘mcc’, ‘mnc’, ‘lac’, ‘cid’, ‘changeable_0’,
‘long’, ‘lat’, ‘range’, ‘sample’, ‘changeable_1’,
‘created’, ‘updated’, ‘avgsignal’]data.columns = col_names
再加上 2G,3G,4G 这一代,还有运营商。在本练习中,我将只使用 Movistar、Tuenti 和克拉罗。
**# add generation**
data[‘radio’] = data[‘radio’].replace(‘UMTS’, ‘3G’).replace(‘GSM’, ‘2G’).replace(‘LTE’, ‘4G’).replace(‘CDMA’, ‘3G’)**# add operator**
data = data.loc[data['mnc'].isin([0, 1, 3])]
data['mnc'] = data['mnc'].replace(0, 'Movistar').replace(1, 'Claro').replace(3, 'Tuenti')
因此,它可能看起来像:
图片由作者提供。桌子准备好了。
操作员的覆盖范围:
图片由作者提供。按操作员代码排列的天线。
图片由作者提供。加拉帕戈斯群岛的运营商覆盖范围
一般来说,所有运营商都连接到天线。尽管 Tuenti 展示了少量天线(根据覆盖范围确定大小),但它实际上连接了整个蜂窝天线网络。克拉罗似乎拥有更多基础设施。
世代覆盖率:
图片由作者提供。各代天线的覆盖范围。
似乎 2G 和 3G 是之前所说的主导者。4G 还在发展中。可以看出,这主要发生在城市地区,如基多、瓜亚基尔、昆卡、曼塔或马查拉。
图片由作者提供。加拉帕戈斯群岛的世代覆盖率
在加拉帕戈斯群岛,2G 和 3G 是大陆地区的主导。
时间性覆盖:
我喜欢绘制混乱的地图。
图片由作者提供。蜂窝天线的发展
建议
开放细胞 ID 是开放数据的来源,可以帮助分析细胞天线在世界范围内的分布。但是不要想当然。一些天线似乎位于海洋中或街道中间。是这样吗?嗯,我相信由于它是一个开源数据集,对真实位置的保护是可以改变的。但是,有一个参考还是很好的,特别是如果我们在国家层面上使用地理可视化。
这种做法可以支持不同国家的移动网络运营商的空间分布及其蜂窝天线的技术发展。因此,只需使用这些材料就可以更好地了解电信发展的现状。
参考文献
[1] 美洲开发银行。(2020) 。“5G 是拉丁美洲和加勒比地区下一代数字社会的驱动力”本作品采用知识共享 IGO 3.0 归属-非商业-非衍生(CC-IGO BY-NC-ND 3.0 IGO)许可协议(https://Creative com—mons.org/licenses/by-nc-nd/3.0/igo/legalcode),可在归属 IDB 的情况下出于任何非商业目的进行复制。不允许衍生作品
[2] Ookla (2021) 。“增长和放缓:2021 年全球 5G 的状况”。https://www . ookla . com/articles/state-of-world wide-5G-2021 #:~:text = 5G % 20 slowed % 20 down % 20 at % 20 global % 20 level&text = Over % 20 the % 20 past % 20 year % 20 from,Mbps)% 20 during % 20 same % 20 period%20during%20the%20same%20period)。*
手机:一个图像分类问题
原文:https://towardsdatascience.com/mobile-phones-an-image-classification-problem-8dd207205c0d
使用监督学习算法的背景和介绍
分类
分类是识别数据集中趋势的最广泛使用的方法之一。这些类型的算法致力于在不使用其他数据操作技术的情况下对数据集进行可靠分类的目标。分类算法要么是有监督的,要么是无监督的。监督学习使用有标签的数据来做决策,而后者使用无标签的数据。例如,有监督的学习可以处理线性关系,而无监督的学习必须处理未知关系(通常是聚类)。因此,根据数据集的类型,分析师将不得不决定对问题采用适当的算法。对于这项研究,监督学习算法已被选为数据集被标记。
图像分类
图像分类是机器学习过程,通过该过程,开发者能够将一组图像分类成不同的类别或主题。使用模型(训练的或未训练的),可以提供图像,使得该模型使用具有深度学习技术的神经网络来准确地分类所有图像。该模型是一组预编码的指令,供计算机应用于一组图像,以便它能够将数据集分类/归类。
神经网络
神经网络是模拟大脑的一种尝试。大脑包含数万亿个神经元连接,而开发人员只能对人工神经网络中节点之间的有限数量的连接进行编程。人工神经网络由输入层、输出层、激活层和几个其他计算/隐藏层组成,是一个大型决策树,它使用数学方法来计算数百万个结果,以便算法在训练、验证甚至测试阶段取得进展。
卷积神经网络(CNN)
不一样的,相信我!
“卷积”是指使用 2 个函数创建新的第三个函数的过程。“卷积神经网络”是一种神经网络,它使用两个给定的输入,并在移动到连续隐藏层、激活层或输出层中的节点时产生输出。此外,CNN 还用于剩余学习的环境中。残差学习是神经网络能够重新使用它在连续层中丢失的任何输入的过程,这使得算法产生最小的损失和更高的精度。
好吧…我想这需要消化很多背景知识。
收集数据
形象
我从无版权来源获得了我所有的图片,所以在项目后期不会有任何问题。
- 正面案例:手机
- 反面案例:洗衣机/洗碗机/平板电脑/笔记本电脑
主要(软件端)工具
- 语言:Python
- ML 框架:PyTorch
- 预训练模型:Resnet18
PyTorch 和 Resnet18:一个词
Pytorch 是开源的,包含预先训练和未训练的学习模型,这使得它适合大多数 ML 开发者。R esnet18 是深度学习算法的机器学习模型。“18”指的是 CNN 的 18 层。该项目利用了预训练版本 Resnet18,因此该过程可以简化为给定图像的实时训练和验证。
我是怎么做到的?
- 确保足够的电源和内存
2.使用命令行工具安装 Python 和 PyTorch
3.运行几个命令来测试 Python 和 PyTorch 是否在机器上运行
4.如果机器没有足够的处理能力(功率、内存或其他):遵循步骤 5 至 8
5.联系业内专业人士或者用 GPU 设置桌面
6.将桌面配置为服务器(可以通过 ssh 连接到它)
7.使用“ssh”或电缆连接来连接到桌面
8.在命令行上运行几个命令,确保桌面服务器正在响应
9.记录培训、验证准确性和时间(两者)的值
10.迭代算法并收集必要的数据,在每次迭代结束时改变“lr”和“epochs”的值(这是为了最大化精度)
实验后数据
结构
- 8 次试验
- 每个试验都有不同的#时期和#lr 值
- 中位数:培训+ Val 准确性和完成时间(注明)
数据汇总(图片由作者提供)
所有关于模型性能的数据都以“xlsx”格式上传到 Github 存储库中。任何电子表格编辑器都应该能够打开它。
分析:数据告诉我什么?
试验 8 在训练和交叉验证数据集上都产生了最少的损失和最高的总体准确性。试验 8 的组合可以在其他数据集上产生相同的测量。试验 8 已经被进一步详细说明,因为该组合使得该算法与其他算法相比执行得最好。
试验 8 总结(图片由作者提供)
(ACC 是准确度,Val 是验证)
试验 8:可视化
图 4: Trial_8 训练损失(图片由作者提供)
图 5: Trial_8 训练精度(图片由作者提供)
图 6: Trial_8 验证失败(作者图片)
图 7: Trial_8 验证准确性(图片由作者提供)
洞察力:这些图表背后的意义
图 4,5
与数据集上模型的定型阶段相关。如图 4 所示,训练损失在图表的第一部分急剧下降。这可能指示模型的“预热”阶段,以便理解特征向量和比较基础。对于训练精度来说,这可能是类似的情况,但是,在训练精度的情况下,精度值很快达到峰值,这表明模型没有使用大量迭代来实现更高的精度值。虽然,该图的一个方面是使用现有选择的限制,即在 0.99 处的可察觉的渐近线,用于 90 次迭代的精度值的波动次数。这是选择学习率和 epoch#时要考虑的一个方面,因为这些值的微小差异可能会在准确性和模型完全分类数据集所需的时间方面产生显著差异。这可以通过比较上表中试验 7 和试验 8 的测量值的绝对值看出,该表包含所有测量值的中值。
图 6,7
交叉验证的可视化描绘了与训练阶段相似的趋势。然而,在交叉验证中,模型的性能稍好。这表明训练阶段是有效的,因为训练集的性能通常为开发人员提供了关于交叉验证数据集的性能的关键信息。在这种情况下,交叉验证被视为测试集,这意味着在大多数迭代中获得 100%的准确性表明模型成功,因为它表明它能够以高精度解决问题。
结束语
概括来说,问题陈述是“给定一张产品图片,以 x%的置信度确定该产品是否属于特定类别(本练习中为手机)”。该算法对图像进行正确分类,总体准确率高达 99.82168%。这表明试验 8 的组合是成功的。然而,当应用于更大的数据集时,仍然存在几乎 0.28%的误差率,这意味着显著的绝对误差。因此,这些结果不能用于工业环境。
改进/扩展:我在某个地方出错了!
- 操纵 CNN 的步长和动量。
- 使用不同的框架。例如张量流。
- 应用不同方向的图像来测试不可预测的数据。例如旋转
- 将更大的数据集应用于模型以改进数据收集
感谢您阅读我的项目总结!。
我对这个领域很陌生,所以,在我的写作中可能会有不一致/混乱,我可能已经错过了。如果您有任何批评或需要进一步澄清,您可以通过下面列出的电子邮件直接联系我。
电子邮件:rahulr280623@gmail.com
Github 储存库:https://github . com/ra hulr 2003/Mobile-Vs-Non-Mobile-Classification
参考
巴蒂亚,理查。“神经网络不像人脑那样工作——让我们揭穿这个神话.” Analytics India Magazine ,2018 年 10 月 31 日,analyticsindiamag . com/neural-networks-not-work-like-human-brains-let-拆穿-myth/#:~:text = b)% 20 artificial % 20 neural % 20 networks % 20 vs,有% 20millions % 20of %个连接。
邦纳,安妮。"深度学习完全初学者指南:卷积神经网络."中,走向数据科学,2019 年 6 月 1 日,走向数据科学. com/wtf-is-image-class ification-8e 78 a 8235 ACB。
脸书人工智能研究实验室。火炬视觉模型。Torch vision . models—py Torch 1 . 7 . 0 文档,Torch 贡献者,2019,pytorch.org/docs/stable/torchvision/models.html.
冯,文森特。" ResNet 及其变体概述."介质,走向数据科学,2017 年 7 月 17 日,走向数据科学. com/an-overview-of-resnet-and-its-variants-5281 e2f 56035。
贾恩,普拉奇。"电子商务中的图像分类[上]. "中,走向数据科学,2019 年 2 月 13 日,走向数据科学. com/product-image-class ification-with-deep-learning-part-I-5b C4 E8 dccf 41。
麦克唐纳康纳。"神经网络(NN)图."走向数据科学,中,2017 年 12 月 22 日,走向数据科学. com/machine-learning-fundamentals-ii-neural-networks-f1 e 7 B2 CB 3 eef。
Python.org。“欢迎来到 python . org”。Python.org、Python.org、www.python.org/doc/.
鲁伊斯帕布罗。“理解和可视化结果”中,走向数据科学,2019 . 04 . 23,走向数据科学. com/understanding-and-visualizing-RES nets-442284831 be 8。
周,维克多。"初学者的机器学习:神经网络导论."中型,走向数据科学,2019 年 12 月 20 日,走向数据科学. com/machine-learning-for-neural-networks-d 49 f 22d 238 f 9。
基于癌症数据的模型学习
原文:https://towardsdatascience.com/model-based-decision-making-for-health-data-581bd58a1a3
基于模型的学习;实践教程
基于癌症数据的模型学习
关于在不平衡和缺失的健康数据上部署基于模型的人工智能的教程
在本文中,我将从头到尾概述如何将基于模型的学习应用于真实世界的健康数据——在我的例子中是癌症数据。在这篇文章的最后,我希望你能了解为什么基于模型的学习是一个有用的通用框架,可以应用于许多不同的数据集,以及它如何帮助识别基于医疗保健等数据领域做出的具体分类决策。
例如,在医疗保健领域,预测某人是健康的,而实际上他们可能需要手术或治疗——戴夫致命的会付出代价吗,因为他们的潜在状况可能不会被人类医生发现,直到为时已晚,因为他们已经被自动系统认为是健康的。然而,在病人实际健康的情况下预测癌症的模型并不是一件坏事,因为病人可以通过他们的保险进行定期检查。如果病情恶化,他们的医生会第一个知道。
我将使用的数据集是来自葡萄牙科英布拉医院和大学中心的真实数据,由 165 名“肝细胞癌”患者组成,这是一种常见但致命的肝癌,通常与甲型肝炎有关
初始数据分析
修复缺失的健康记录数据
首先,我们需要从 UC Irvine 机器学习库的这个链接下载数据。您会注意到,在链接中,它说大约 10%的数据是缺失,只有8 个患者记录有完整的数据。所以我们的第一步是解决这个问题。
图片鸣谢:作者。缺少的值标有问号“?”。
在我们进行任何特征选择或机器学习之前,我们首先必须修复缺失的数据。通常, pandas 库会提供某种类型的选项,比如pandas.fillna
,它基本上是用均值、中值或最近邻(如果列是数字)或模式(如果列是分类的)来填充每个特征列中的缺失值。
然而,在这种情况下,对于我们的癌症数据,该论文的作者(他们在 UCI 上免费发布了该数据集)概述了一种基于患者相似性度量的缺失数据方案,称为“异构欧几里德重叠度量”(HEOM),根据作者的说法,该方案对于填充具有连续和离散类型的数据集中的缺失值非常有效。该代码包含 Python 中关于如何实现这一点的细节;你可以在这里查看。
寻找最佳功能
现在我们已经填充了缺失的数据,让我们来看看如何选择我们的特征。我决定不在特性选择上花太多时间。有很多方法可以做到这一点:使用递归特征消除(RFE),互信息,卡方检验独立性,等等。我通常不会推荐 RFE,因为有了足够多的特性,你需要测试的组合数量会增长得非常快。
在这种情况下,对于健康记录,我将完全做其他事情:我将使用随机森林来确定特征。你可能会问,“我为什么要用一个随机的森林来计算呢??"但事实证明,随机森林有一个名为 feature_importances 的内置属性,这是由所使用的决策树集合决定的。(顺便说一句,如果你想要一篇关于 Random Forests 的快速评论文章,看看我以前关于它们的帖子,以及对现实世界糖尿病数据的应用!)
使用随机森林,我们发现预测患者存活的前 3 个特征依次是:甲胎蛋白(ng/dL)、血红蛋白(g/dL)和碱性磷酸酶(U/L)。(这些健康记录属性也在数据集所在的 UCI 数据库中列出。)
图片鸣谢:作者。前 3 个特征对应于最高的 3 个条。
基于模型的学习
现在到了我想投入精力和注意力的有趣部分:基于模型的学习。
我们已经填充了缺失的数据,并找到了最能提供信息的特征,现在让我们来看看数据集的形状。我们总共有 165 个数据记录,其中 102 例患者存活,63 例患者死亡。我们已经遇到了两个主要的“问题”——我们的数据集样本量对于机器学习来说不是那么大,我们有类别不平衡。
现在你可能会说,“Raveena,你为什么不对较小的类进行过采样,或者对较大的类进行过采样?”的确,我可以!我可以用称为 SMOTE 的合成采样对“病人死亡”类进行过采样。(这里有一个来自 sci-kit learn 的关于它的很棒的教程)然而,我正试图结合基于模型的学习,这意味着我将走更贝叶斯的路线——我将在下面简要解释。
基本的想法就像它的名字一样:我要做的是为幸存的患者创建一个具有前三个特征的模型,为那些不幸从癌症中死去的患者创建一个模型。希望是,一旦我有了这两个模型,对于一个新的测试患者,我可以比较每个模型的判断,并决定测试患者是否会生存,死亡,或由于巨大的不确定性而犹豫不决。
在最终决定之前,贝叶斯步骤还包括一件事:我将结合我们对病人的先验知识,并将其乘以模型判断。你会问,先验知识是什么?嗯,在训练集中有 73 名患者存活,42 名患者死亡——因为我之前提到的“阶级不平衡”。这听起来可能是件坏事。但是在基于模型的学习中,我们实际上可以利用它!我要做的是——结合存活和死亡患者之间的先前差异,以及模型判断——并使用这两者来做出最终决定。
创建模型
为了创建实际的模型,我将使用一种称为高斯混合的模型。用最简单的方式来描述它,高斯混合模型查看一堆数据,并试图将数据的分布分解为各个钟形曲线的基本总和,或高斯正态分布。每个更简单的正态分布都有一个与之相关联的特定权重,该权重告诉模型对该特定高斯分布的重视程度。这是高斯混合模型拟合数据的 GIF 图,链接到这里,下面是一个截图:
图片来源:维基百科。高斯混合模型及其组件的屏幕截图。您可以看到单独的红色、黄色、紫色、绿色和蓝绿色正态分布,每一个都添加了特定的权重,以给出整体较细的深蓝色曲线
高斯混合模型比核密度估计器更不容易过度拟合训练数据,核密度估计器通常试图最大化分布对训练数据的拟合,从而产生过度拟合的风险。
# Gaussian Mixture model for patients who survived carcinoma
life_model_2feature **=** GaussianMixture(n_components**=**6, random_state**=**0)**.**fit(X_train_2life)# Gaussian Mixture model for patients who died from carcinoma
death_model_2feature **=** GaussianMixture(n_components**=**4, random_state**=**0)**.**fit(X_train_2death)
我们将基于前 2 个特征来看存活和死亡患者的模型;我的代码中详细介绍了前 3 个特性。
图片鸣谢:作者。这是计算机为幸存病人准备的内部模型。这是通过根据它的模型生成 100 个幸存病人的合成样本来实现的
图片鸣谢:作者。这是电脑为死去的病人准备的内部模型。这是通过根据它的模型生成 100 个死亡病人的合成样本来实现的
模型预测
最后,是时候看看该模型将如何根据测试患者数据预测患者存活率了。不过,在开始之前,我想讨论一件重要的事情。
我们不能冒误报的风险
如果我们根据患者的甲胎蛋白和血红蛋白含量来预测患者是否会在这种特定的癌症中存活,那么意外预测患者会在癌症中存活是极其危险和不道德的,因为他们可能有很高的死亡几率。这在统计学中被称为“假阳性”,在这种情况下,阳性=存活,阴性=死亡。如果我们要对测试患者做出最终决定,如果我们做出了假阳性选择,我们需要更加重视——我们需要“惩罚”这个决定,这样它就不会发生,我们不会无意中对患者撒谎,告诉他们他们会在癌症中幸存下来,而他们在没有适当治疗的情况下死亡的几率要高得多。
假设我们想要做出假阳性决策的权重是假阴性决策的 5 倍。如果我们想惩罚 5 倍的假阳性决定,那么我们只能接受这样的决定,即如果最终的优势比高于某个数量,则预测患者“存活”。更具体地说:
图片鸣谢:作者。这基本上是贝叶斯定理,为了更重地惩罚 5 倍的假阳性决策,我们使决策赌注更高。
(只是作为一个重要的提醒,在这个项目中,Y=1 表示患者会存活,Y=0 表示患者不会存活于癌。)
(这方面的细节在代码中,所以你可以在这里自由地自己查看)。但是如果您感兴趣,这里有一个代码示例:
threshold = 5**for** odds **in** log_posterior_odds: **if** odds **>** np**.**log(threshold):
decisions**.**append(1)
**else**:
decisions**.**append(0)
那么……这个模型预测了什么?
实现这个决策规则,我们得到下面的混淆矩阵结果。(混淆矩阵只是一个 2x2 表格的花哨术语,它显示了模型在测试数据上的表现,有假阳性,也有假阴性— 不仅仅是准确性。准确性有时会误导人!)
模型做得不算太差!––50 道题中有 36 道正确,准确率为 72%。右上角的深紫色方框是假阳性——该模型预测了 5 名测试患者,他们将是健康的,但实际上不会在癌症中存活。
但是我想让你注意到,对于这个基于模型的学习框架来说,比准确性更重要的东西——因为记住,准确性不是一切。还记得我说过,我们将通过将比率阈值设置为 5 来惩罚犯有更多假阳性错误的模型(该模型对患者撒谎说他们将在癌症中存活)吗?
当我将阈值增加到 10 时,请注意右上角紫色框中的数字会发生什么变化,因此我们增加了 10 倍的权重:
通过将阈值增加到 10,模型少犯了一个假阳性错误,代价是犯了一个假阴性错误。
但是如果门槛很高,比如 20 岁,看看会发生什么。所以我们对假阳性分类错误的重视程度是假阴性的 20 倍。
现在这个模型真的开始最小化假阳性,这很好——但是这是以增加假阴性的巨大成本为代价的。这意味着太多可能不需要检查的患者被模型送到他们的医疗提供者那里进行检查。除非他们的保险可以涵盖定期检查,否则这对病人来说是不划算的。所以你可以看到,设置阈值是模型的一个平衡游戏。
最后的话
我希望这篇文章能让您了解基于模型的学习的灵活性,以及如何将它应用到健康领域的真实数据中,
在我看来,基于模型的学习的主要优势之一是这个框架可以应用于许多类型的表格数据,而不仅仅是健康记录。这种类型的机器学习甚至可以应用于视觉和语音识别领域,只要从数据中提取正确的特征类型,并使用有效的概率生成模型。
我认为的另一个优势是,我们对假阳性、假阴性的最终分析,以及根据我们数据的域来补偿任一错误,使用基于模型的学习是非常简单的。我们所要做的就是决定我们对惩罚假阳性或假阴性的重视程度,并像我们所做的那样设定一个阈值。在 Python 中只需要几行代码,但是这种分析在例如医疗保健领域是非常重要的,在那里,不管准确性如何,出现假阳性错误可能比假阴性更昂贵或更致命。**
非常感谢您的阅读,我们将在下一篇文章中再见!
如果你想了解更多关于我的信息,我对机器学习和数据科学感兴趣,我想从事什么,你可以在这里查看我的 LinkedIn。
Scikit-learn 中的模型评估
原文:https://towardsdatascience.com/model-evaluation-in-scikit-learn-abce32ee4a99
机器学习
关于如何使用 scikit-learn 计算最常见的回归和分类指标的教程。
Scikit-learn 是最流行的用于机器学习的 Python 库之一。它提供了模型、数据集和其他有用的功能。在本文中,我将描述 scikit-learn 为模型评估提供的最流行的技术。
**模型评估允许我们评估模型的性能,并比较不同的模型,以选择最佳模型投入生产。**模型评估有不同的技术,这取决于我们想要解决的具体任务。在本文中,我们重点关注以下任务:
- 回归
- 分类
对于每个任务,我将通过一个实际的例子来描述如何计算最流行的指标。
1 加载数据集
作为一个示例数据集,我使用由 UCI 机器学习库提供的葡萄酒质量数据集。要使用此数据集,您应该正确引用来源,如下所示:
- Dua d .和 Graff c .(2019 年)。UCI 机器学习知识库[http://archive . ics . UCI . edu/ml]。加州欧文:加州大学信息与计算机科学学院。
- 页(page 的缩写)科尔特斯、塞德伊拉、阿尔梅达、马托斯和雷伊斯。
通过物理化学特性的数据挖掘建立葡萄酒偏好模型。在决策支持系统中,爱思唯尔,47(4):547–553,2009。
我下载了数据文件夹,其中包含两个数据集:一个是红酒数据集,另一个是白酒数据集。我构建了一个数据集,它是两个数据集的串联,如下所示。
我将两个数据集都作为熊猫数据帧加载,然后合并它们:
import pandas as pdtargets = ['red', 'white']
df_list = []
df = pd.DataFrame()
for target in targets:
df_temp = pd.read_csv(f"../Datasets/winequality-{target}.csv", sep=';')
df_temp['target'] = target
df_list.append(df_temp)
print(df_temp.shape)df = pd.concat([df_list[0], df_list[1]])
我添加了一个新列,它包含原始数据集名称(红色或白色)。数据集如下表所示:
作者图片
数据集包含 6497 行和 13 列。
现在,我定义一个函数,它对所有分类列进行编码:
from sklearn.preprocessing import LabelEncoderdef **transform_categorical**(data):
categories = (data.dtypes =="object")
cat_cols = list(categories[categories].index)
label_encoder = LabelEncoder()
for col in cat_cols:
data[col] = label_encoder.fit_transform(data[col])
我还定义了另一个函数,它缩放数字列:
from sklearn.preprocessing import MinMaxScalerdef **scale_numerical**(data):
scaler = MinMaxScaler()
data[data.columns] = scaler.fit_transform(data[data.columns])
2 回归
为了评估回归模型,最常用的指标是:
- 平均绝对误差 —实际值与预测值之差的平均值。它衡量预测与实际产出的差距。MAE 越低,模型越好。
- 均方根误差 —均方误差的平方根(MSE)。MSE 计算实际值和预测值之差的平方的平均值。
- R2 分数—Y 中可以用 x 解释的方差比例
作为一项回归任务,我希望在给定其他特征的情况下,预测每个记录的 pH 值。我将 X 和 y 变量定义如下:
X = df.drop("pH", axis = 1)
y = df["pH"]
然后,我将类别转换成数字,并对数字进行缩放:
transform_categorical(X)
scale_numerical(X)
因此,我有以下输入数据集:
作者图片
现在,我将数据集分为训练集和测试集:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = **train_test_split**(X, y, test_size=0.20, random_state=42)
我定义了一个辅助函数,它接收模型作为输入,然后对其进行训练和测试:
from sklearn.metrics import mean_absolute_error,r2_score,mean_squared_error
import numpy as npdef **run_experiment**(model):
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print("R^2 : ", r2_score(y_test, y_pred))
print("MAE :", mean_absolute_error(y_test,y_pred))
print("RMSE:",np.sqrt(mean_squared_error(y_test, y_pred)))
现在我建立一个线性回归模型,并测试它的性能:
from sklearn.linear_model import LinearRegression
model = **LinearRegression**()
run_experiment(model)
作为输出,run_experiment()
函数返回以下结果:
R^2 : 0.6508427991759342
MAE : 0.07476031320105749
RMSE: 0.09761343652989583
我还建立了另一个回归模型,基于随机梯度下降:
from sklearn.linear_model import SGDRegressor
model = SGDRegressor()
run_experiment(model)
作为输出,我得到了以下结果:
R^2 : 0.6243269738606405
MAE : 0.07703814197219305
RMSE: 0.10125211591520658
两个实验的比较表明,线性回归器具有较低的 RMSE,因此它优于另一个模型。
3 分类
最常见的分类评估指标有:
- 精确——在所有积极的预测中,数一数有多少是真正积极的。
- 回忆 —在所有真正的阳性病例中,统计有多少被预测为阳性。
- 准确性 —在所有案例中,计算有多少案例被正确预测。
作为分类任务,我考虑目标类(红/白)的预测。因此,我构建 X 和 y 变量如下:
X = df.drop("target", axis = 1)
y = df["target"]
现在,我将分类列转换为数字列,然后缩放所有数字列:
transform_categorical(X)
scale_numerical(X)
我还对目标类进行了编码:
label_encoder = LabelEncoder()
y = label_encoder.fit_transform(y)
现在,我将数据集分为训练集和测试集:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42)
现在,我定义一个辅助函数,它接收模型作为输入,通过计算之前定义的指标来训练和测试它:
def **run_experiment**(model):
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
plot_confusion_matrix(model, X_test, y_test, cmap='GnBu')
plt.show() print('Precision: %.3f' % precision_score(y_test, y_pred))
print('Recall: %.3f' % recall_score(y_test, y_pred))
print('F1: %.3f' % f1_score(y_test, y_pred))
print('Accuracy: %.3f' % accuracy_score(y_test, y_pred))
我构建了一个随机森林分类器,然后计算它的性能:
from sklearn.ensemble import RandomForestClassifiermodel = RandomForestClassifier()
run_experiment(model)
该函数返回以下输出:
Precision: 0.994
Recall: 0.999
F1: 0.996
Accuracy: 0.995
我还训练了一个决策树分类器:
from sklearn.tree import DecisionTreeClassifiermodel = DecisionTreeClassifier()
run_experiment(model)
该函数返回以下输出:
Precision: 0.992
Recall: 0.985
F1: 0.988
Accuracy: 0.983
就准确性而言,随机森林分类器的性能优于决策树分类器。
摘要
恭喜你!您刚刚学习了如何在 scikit-learn 中为分类和回归执行模型评估。所描述的技术没有考虑参数优化,因为本文的目的是展示最常见的评估指标。
如果你读到这里,对我来说,今天已经很多了。谢谢!你可以在这篇文章中读到更多关于我的内容。
相关文章
从社区收集的文章
评估指标
View list2 stories
数据分析
View list4 stories
模型解释不是弱监督分割
原文:https://towardsdatascience.com/model-explanation-is-not-weakly-supervised-segmentation-68610987420
特色图片(天空拼图)来自维基百科(知识共享许可)。
在这篇文章中,我们将比较三个相关但不同的计算机视觉任务,它们可以用卷积神经网络来处理:图像分类模型解释、弱监督分割和完全监督分割。我们将考虑目标、训练数据和方法的异同。请注意,我将把重点放在这些任务的神经网络方法上,尽管所有这三项任务都可以通过非神经网络方法来解决。
如果你想引用这篇文章,它是基于我的论文“使用 HiResCAM 而不是 Grad-CAM 来忠实地解释卷积神经网络”的摘录。
本帖将使用一个基于该船图像草图的运行示例:
作者图片
目标
首先,让我们考虑一下目标:
- 模型解释:突出显示区域用于预测对象的模型
- 弱监督或全监督分割:识别作为对象一部分的所有像素
目标的哲学差异对判断任务的成功有重要的影响,接下来会详细讨论。
模型解释的目标
模型解释的目的是演示模型在图像中的哪些位置用于进行特定预测— ,即使这意味着突出显示相关对象之外的区域。例如,如果一个模型使用轨道来识别一列火车,解释应该突出轨道。如果模型使用水来识别一艘船,解释应该突出水。
作者图片
因此,评估解释正确性(“解释质量”)的任何性能度量都必须根据“模型用于每个预测的位置”这一基本事实来计算,这反过来只能通过模型和解释方法的数学属性来揭示。例如,在 HiResCAM 的论文中,我们证明了 HiResCAM 准确地解释了 CNN 使用的位置,这些位置以一个完全连接的层结束。
“模型使用的位置”可能与对象分割图没有任何关系,这些位置也不能由人类手动创建,因为如果人类能够足够好地理解模型以限定用于每个预测的区域,那么首先就不需要解释方法。
分割的目标
分割的目标是识别作为对象一部分的所有像素。
在弱监督分割中,这个目标必须仅使用整个图像标签来实现。在完全监督分割中,地面真实分割图可用于训练。
作者图片
因为从图像分类器导出的弱监督分割图是“模糊的”,并且通常倾向于集中在对象的小的区别部分,所以弱监督分割方法包括阈值处理和后处理步骤,旨在将原始“模糊”分割图变换/扩展成更清晰和更准确的图(例如,通过使用条件随机场)。
作者图片
借据不得用于评估解释正确性
分割任务的一个常见性能指标是交集/并集(IoU ),当一个类的预测分割与该类的基本事实分割完全重叠而没有扩散到其他区域时,该指标最高。
IoU 是通过将模型的预测分割中的像素与真实分割中的像素进行比较来计算的。真阳性“tp”(预测和实际情况中的像素)、假阳性“fp”(预测中不在实际情况中的像素)和假阴性“fn”(不在预测中但存在于实际情况中的像素)用于计算 IoU,如下图所示,这是假设医学图像分类任务的肺和心脏的卡通图:
作者图片
虽然 IoU 是判断分段性能的合理指标,但 IoU 永远不应该用于评估解释的正确性。不幸的是,一些论文试图通过实验来评估解释的正确性,使用根据基本事实对象分段计算的 IoU,或使用密切相关的设置,要求人类主观判断解释与对象的对应程度(这实际上对应于人类估计类似 IoU 的数量)。这些实验中不言而喻的假设是,分类模型总是使用相关对象来预测类别,因此“好的”解释方法将实现高 IoU。然而,如前所述,模型并不保证总是使用相关的对象来预测类,事实上,不期望的模型行为的可能性是解释方法开发背后的主要动力。
任何时候,一个模型的行为出乎意料或利用虚假的相关性,真实模型解释的 IoU 将会很低,但如果得出低 IoU 意味着解释质量差的结论,那就错了。要知道一个解释方法是否忠实于一个特定类型的模型,唯一的方法是根据模型的定义和解释方法的定义来证明它。
忠实解释方法的 IoU 提供了对模型的洞察
虽然 IoU 不能用于评估解释方法的质量,但是基于具有保证属性的解释方法(例如 CAM 或 HiResCAM )计算的 IoU 可以用于评估特定的型号。在这些情况下,高 IoU 表示该模型倾向于根据需要使用感兴趣对象内的区域进行预测,而低 IoU 表示该模型倾向于使用感兴趣对象外的区域进行预测,从而利用背景或相关对象。
方法
既然我们已经概述了解释和分段的不同目标和评估,让我们考虑一下用于每项任务的方法。
模型解释可以通过显著图、 CAM 、 HiResCAM 等技术完成;显著图通过了完整性检查,CAM 和 HiResCAM 都具有保证的忠实性。 Grad-CAM 通常被用作解释技术,但事实上并不适合用于模型解释,因为它有时会突出显示模型并未实际用于预测的区域。其他模型解释方法已被证明更像边缘检测器而不是解释,因此在选择模型解释方法时,选择一个具有保证属性的方法非常重要,以避免产生混淆模型实际工作的误导性解释。
有些令人困惑的是,弱监督分割方法通常建立在 CAM 家族解释方法的基础上,因此许多弱监督分割方法的名称中都有“CAM”,尽管它们的目标是分割而不是模型解释:例如, Mixup-CAM 、子类别 CAM 和 Puzzle-CAM 。重要的是要记住,即使这些弱监督的分割方法利用了模型解释方法,它们也有一个根本不同的目标。
像 U-Nets 或 Mask R-CNNs 这样的完全监督分割模型利用了基础真实分割掩码。全监督分割模型通常优于弱监督分割模型,因为全监督模型具有更多可用信息。如上所述,弱监督分割图是从仅在存在/不存在标签上训练的分类模型中导出的——例如,对于整个图像,“boat=1”或“boat=0”。全监督分割模型在像素级标签上训练;典型的 RGB 自然图像可能具有大约 256×256 = 65,536 个像素。因此,与弱监督分割模型相比,全监督分割模型在数量级的更多信息上被训练。完全监督分割的缺点是获得像素级标签的费用,这限制了训练样本的数量和可以考虑的不同类别的数量。
总结
下表总结了这些任务之间的相似之处和不同之处:
作者图片
快乐解释和分段!
原载于 2022 年 7 月 2 日 http://glassboxmedicine.comhttps://glassboxmedicine.com/2022/07/02/model-explanation-is-not-weakly-supervised-segmentation/。
机器学习模型的可解释性和可解释性
原文:https://towardsdatascience.com/model-interpretability-and-explainability-27fe31cc0688
SHAP,石灰,可解释的助推机器,显著图,TCAV,蒸馏,反事实,和解释
艾蒂安·吉拉尔代在 Unsplash 上拍摄的照片
ML/AI 模型变得越来越复杂,越来越难以解释和说明。简单、易于解释的回归或决策树模型不再能够完全满足技术和业务需求。越来越多的人使用集成方法和深度神经网络来获得更好的预测和准确性。然而,那些更复杂的模型很难解释、调试和理解。因此,许多人将这些模型称为黑盒模型。
当我们训练一个 ML/AI 模型时,我们通常专注于技术细节,如步长、层、早期停止、丢失、膨胀等等。我们真的不知道为什么我们的模型会以某种方式运行。例如,考虑一个信用风险模型。为什么我们的模型会给个人分配一定的分数?我们的模型依赖于什么特性?我们的模型是否严重依赖一个不正确的特征?即使我们的模型没有将种族和性别作为输入特征,我们的模型是否会从其他特征中推断出这些属性,并引入对某些群体的偏见?利益相关者能理解并信任模型行为吗?该模型能为人们提供如何提高信用评分的指导吗?模型解释和说明可以提供对这些问题的洞察,帮助我们调试模型,减少偏差,并建立透明度和信任。
人们对机器学习模型的可解释性和可解释性越来越感兴趣。研究人员和 ML 实践者已经设计了许多解释技术。在这篇文章中,我们将提供八种流行的模型解释技术和工具的高级概述,包括 SHAP、Lime、可解释的助推机器、显著图、TCAV、蒸馏、反事实和解释。
SHAP
图一。SHAP 解释机器学习模型输出(来源:https://shap.readthedocs.io/,麻省理工许可)
“SHAP(SHapley Additive exPlanations)是一种博弈论方法,用来解释任何机器学习模型的输出。它使用博弈论及其相关扩展中的经典 Shapley 值,将最优信用分配与本地解释联系起来。
图 1 显示了 SHAP 工作的要点。假设基本速率,即预测值 E[f(x)]的先验背景期望值是 0.1。现在我们有了一个新的观察结果,特征年龄=65,性别=F,血压=180,身体质量指数=40。这个新观察的预测值是 0.4。我们如何解释 0.4 的产值和 0.1 的基础率之间的这种差异?这就是 Shapley 值发挥作用的地方:
- 先说基础率 0.1。
- 加上身体质量指数 Shapely 值 0.1,我们得到 0.2。
- 加上 BP Shapely 值 0.1,我们得到 0.3。
- 加上性感匀称值-0.3,我们得到 0。
- 加上年龄匀称值 0.4,我们得到 0.4
基于 Shapely 值的加性,这个新观察的模型预测是 0.4。SHAP 值提供了对每个要素重要性的深入了解,并解释了模型预测的工作原理。
我们如何计算 Shapley 值?SHAP 绘制了线性模型的部分相关图,其中 x 轴代表特性,y 轴代表给定特性时输出的期望值(见图 2)。特征的 Shapley 值是在该特征的给定值,即图中红线的长度,预期模型输出和部分相关性图之间的差。
图二。部分依赖情节(来源:【https://shap.readthedocs.io/】T2,麻省理工学院许可)
Shapley 值的计算可能很复杂,因为它是所有可能的联盟排列的平均值。shap
库使用采样和优化技术来处理所有复杂的计算,并为表格数据、文本数据甚至图像数据返回直观的结果(参见图 3)。通过conda install -c conda-forge shap
安装 SHAP 并试一试。
图 3。https://shap.readthedocs.io/,麻省理工学院许可,SHAP 解释图像分类(来源:
石灰
模型可以是全局复杂的。Lime(局部可解释模型不可知解释)不是关注整体复杂模型行为,而是关注局部区域,并使用线性近似来反映预测实例周围的行为。
图 4 展示了 Lime 的工作原理。蓝色/粉色背景表示原始复杂模型的决策函数。红十字(我们称之为 X)是我们想要预测和解释的实例/新观察。
- X 周围的采样点
- 使用原始模型预测每个采样点
- 根据样本与 X 的接近程度对样本进行加权(图中权重较大的点对应于较大的尺寸)
- 在加权样本上拟合线性模型(虚线)
- 用这个线性模型来解释 X 附近的局部
图 4。石灰直觉(来源:https://github.com/marcotcr/lime,BSD 执照)
使用 Lime,我们可以在本地解释表格数据、文本数据和图像数据的模型行为。下面是一个使用 Lime 来解释文本分类器的例子。我们可以看到这个分类器正确地预测了实例,但是出于错误的原因。
图 5。石灰解释文本分类器示例(来源:https://github.com/marcotcr/lime,BSD 许可)
要了解更多关于 Lime 的信息,请查看 Github 页面并通过pip install lime
安装。
可解释的助推器
“可解释的助推机 (EBM)是一个基于树的、循环梯度助推广义加法模型,具有自动交互检测功能。EBM 通常与最先进的黑盒模型一样精确,同时保持完全可解释性。”
EBM 的工作原理如下:
- 在每次迭代中,我们以循环方式一次一个特征地训练一个装袋和梯度提升树。我们首先在第一个特征上训练,然后更新残差并在第二个特征上训练,并继续直到我们完成所有特征的训练。
- 然后我们重复这个过程很多很多次。
- 因为 EBM 逐个特征循环,所以它可以显示每个特征在最终预测中的重要性。
EBM 是在 interpret.ml 中实现的,我们将在本文后面介绍。
显著图
显著图方法广泛用于解释神经网络图像分类任务。它测量每个像素的重要性,并突出显示哪些像素对预测很重要。在高层次上,显著性图采用每个类别相对于每个图像输入像素的梯度或导数,并将梯度可视化(参见图 6)。
图 6。显著地图(来源:https://pair-code.github.io/saliency/#guided-ig,阿帕奇许可)
PAIR 显著性项目提供了“最新显著性方法的框架不可知实现”,包括引导集成梯度、XRAI、SmoothGrad、香草梯度、引导、反向传播、集成梯度、遮挡、Grad-CAM、模糊 IG。
要了解更多关于显著性方法的信息,请查看 Github 页面并通过 pip 安装显著性。
TCAV
TCAV 主张用概念激活向量(CAV)进行定量测试。TCAV“量化了用户定义的概念对分类结果的重要程度——例如,斑马的预测对条纹的存在有多敏感”(金,2018)。
图 7。用概念激活向量进行测试。(资料来源:Kim,2018 年)
TCAV 执行以下步骤来确定一个概念是否重要:
- 定义概念激活向量(图 7 步骤 a-d)
TCAV 使用概念图像(带有条纹物体的图像)和随机图像的例子作为输入,并检索层激活。然后,它训练一个线性分类器来分离激活,并采用与超平面决策边界正交的向量(CAV)。CAV 代表图像中的条纹。
- 计算 TCAV 分数(图 7 步骤 e)
TCAV 分数是通过对 CAV 取方向导数来计算的。它代表了模特对条纹等特定概念的敏感度。
- CAV 验证
测试一个概念是否有静态意义。同样的过程可以在随机图像和随机图像中进行。我们可以将概念对随机图像 TCAV 分数分布与随机对随机图像 TCAV 分数分布进行比较。可以进行双侧 t 检验来检验 TCAV 分数分布差异。
要了解更多关于 TCAV 的信息,请查看 Github 页面并通过pip install tcav
安装。
蒸馏
“在机器学习中,知识提炼是将知识从大模型转移到小模型的过程。”
在模型解释上下文中,大模型是黑盒模型,也是教师模型。较小的模型是解释者,学生模型。学生模型试图模仿教师模型的行为,并且是可解释的。
例如,可以构建一个决策树来近似原始的复杂模型(Bastani,2019)。Bastani 的论文“提出了一种用于学习决策树的模型提取算法——为了避免过度拟合,该算法通过主动采样新输入并使用复杂模型标记它们来生成新的训练数据。”
图 8。用决策树解释黑盒模型。(来源:通过模型提取解释黑盒模型。奥斯伯特.巴斯塔尼,卡罗琳.金,哈姆萨.巴斯塔尼。2019
反事实的
反事实描述了改变模型预测所需的最小输入特征变化量。反事实提出了很多假设问题。如果我们增加这个功能或减少那个功能会怎么样?例如,根据黑盒模型,约翰有很高的心脏病风险。如果约翰一周锻炼 5 天会怎么样?如果约翰是素食者呢?如果约翰不抽烟会怎么样?这些变化会导致模型预测的变化吗?那些反事实提供了易于理解的解释。
有很多关于生成反事实的研究和方法。例如,骰子(不同的反事实解释)为同一个人生成一组不同的特征扰动选项,该人的贷款被拒绝,但如果收入增加 10,000 美元或收入增加 5,000 美元并有 1 年以上的信用历史,则该人会获得批准。DiCE 在支持用户特定要求的情况下,对原始输入的多样性和接近度进行了优化。
要了解更多关于 interpretML 的信息,请查看文档并通过conda install -c conda-forge dice-ml
安装。
图 9。骰子(来源:https://github.com/interpretml/DiCE,麻省理工学院许可)
解释性语言
" InterpretML 是一个开源包,在一个屋檐下集成了最先进的机器学习可解释性技术。"
interpretML 提供了对 glassbox 模型的解释,包括
- 可解释的助推器,
- 线性模型,
- 决策树,
- 和决策规则。
它还解释了使用
- Shapley 加法解释,
- 本地可解释的模型不可知的解释,
- 部分相关图,
- 和莫里斯敏感度分析。
interpretML 的结果可以显示在一个带有良好交互界面的 Plotly 仪表盘中:
图 10。interpretML 仪表板(来源:https://interpret.ml/docs/getting-started.html,麻省理工学院许可)
要了解更多关于 interpretML 的信息,请查阅文档并通过conda install -c interpretml interpret
进行安装。
结论
总的来说,我们已经对一些流行的模型可解释性技术和工具进行了高层次的概述,包括 SHAP、Lime、可解释推进机、显著图、TCAV、蒸馏、反事实和解释。每种技术都有自己的变化。我们将在以后详细讨论每种技术。
参考资料:
- https://shap.readthedocs.io/
- “我怎么忽悠你?”:通过误导性的黑箱解释操纵用户信任。奥斯伯特.巴斯塔尼。AAAI/ACM 人工智能、伦理和社会会议(AIES),2020 年。
- 对黑盒模型的忠实和可定制的解释。Himabindu Lakkaraju,Ece Kamar,Rich Carauna,Jure Leskovec。AAAI/ACM 人工智能、伦理和社会会议(AIES),2019 年。
- https://explainml-tutorial.github.io/neurips20
- 【https://christophm.github.io/interpretable-ml-book
- https://homes.cs.washington.edu/~marcotcr/blog/lime/
- “我为什么要相信你?”:解释任何分类器的预测。马尔科·图利奥·里贝罗,萨姆尔·辛格,卡洛斯·盖斯特林。2016 年第 22 届 ACM SIGKDD 知识发现和数据挖掘国际会议论文集。
- 对黑盒模型的忠实和可定制的解释。拉卡拉朱、卡马尔、卡鲁阿纳和莱斯科维奇。AIES,2019。
- 通过模型提取解释黑盒模型。奥斯伯特.巴斯塔尼,卡罗琳.金,哈姆萨.巴斯塔尼。2019
- 特征归因之外的可解释性:概念激活向量的定量测试(TCAV)。被金,马丁瓦滕伯格,贾斯汀吉尔默,卡莉蔡,詹姆斯韦克斯勒,费尔南达维加斯,罗里塞尔。2018.
- https://www.youtube.com/watch?v=Ff-Dx79QEEY
- pair-code.github.io/saliency/
- https://interpret.ml/
- 通过不同的反事实解释来解释机器学习分类器。陈豪·谭·阿米特·夏尔马·拉马鲁文·k·莫西拉尔 2019.
. . .
最初发表于anaconda.org
作者索菲亚杨 2022 年 8 月 23 日。
Sophia Yang 是 Anaconda 的高级数据科学家。在 LinkedIn 、 Twitter 和 YouTube 上与我联系,并加入 ds/ml❤️读书俱乐部
用火花进行模型预测和分配
原文:https://towardsdatascience.com/model-prediction-and-distribution-with-spark-9710c3065e62
如何用 Spark 实现和分发机器学习模型——py Spark 实现
由于 Apache Spark,任务处理可能是分散的。通过将内存中的属性与 Spark SQL 功能结合使用,它增强了这一过程。Spark 的分布式数据记录和处理方法是通过包括分布式脚本、数据处理、数据工作流的创建和具有 MLlib 函数的机器学习技术在内的功能实现的。
Spark 可以根据平台以不同的方式安装。在本节中,我们将重点关注本地安装。
Apache Spark 可以在任何安装了 Python、Scala 或 Java 的环境中运行。本文将关注 Python 语言。紧凑快速地安装所需的 Python 包和 Jupyter Notebook 的最简单方法是使用 Anaconda 。
探索性数据分析
*“ny T2”*数据集将在整篇文章中使用。你可以通过 Kaggle 网站从这个链接下载。
数据集的格式具有使用“JSON”函数的基本要求。
tr_df = spark.read**.**json('dataset/nyt2.json')ts_df = spark.read**.**json('dataset/nyt2.json')
新特征生成:特征工程
通过使用特征工程,可以从数据集的当前变量中收集更多的信息数据。
个人的头衔也包含在 Titanic 数据集的“姓名”列中。该模型可以从该信息中受益。然后创建一个新的变量。可以使用’ withColumn '方法添加新的标题列。
tr_data = tr_df.withColumn("writer", regexp_extract(col("author"),"([A-Za-z]+)\.", 1))
可能有一些重复的作者姓名。“替换”功能可用于替换它们。
feature_dataframe = tr_data.\
replace(["Jane Greenn",
"Stepheniei Meyer",
"Jimmy Buffett"],
["Jane Green",
"Stephenie Meyer",
"Jimmy Buffett"])
标题的分布看起来比先前遵循替换过程更精确。
用 Spark MLlib 建模
最终的建模数据集必须将所有字符串格式的列转换为正确的数字类型,因为预测算法需要数字变量。
from pyspark.ml.feature import StringIndexerwriterIndexer = StringIndexer(inputCol="writer", outputCol="writer_Ind").fit(feature_dataframe)descriptionIndexer = StringIndexer(inputCol="published_date", outputCol="published_ind").fit(feature_dataframe)
数据帧中包含所有数字变量,因为以前的字符串格式操作已被删除并编入索引。我们可以使用数据帧中的列来创建特征向量,因为每一列都具有非字符串格式。
from pyspark.ml.feature import VectorAssemblerassembler = VectorAssembler(
inputCols = ["writer","price","published_ind"],
outputCol = "features")
当创建流水线时,分类器的参数可以在` ParamGridBuilder 的帮助下进行优化。网格搜索后将创建相应的参数。
from pyspark.ml.tuning import ParamGridBuilder
pg = ParamGridBuilder().build()
评估指标
精确度可用作模型评估的统计数据。“精确度”数学公式。
带 MLFlow 的 MLOps】
对于 PySpark 模型,MLFlow 可用作模型服务库。根据官方文档中的说明,可以为 PySpark 编程安装该库。
pip install mlflow
“mlflow.pyfunc”函数可用于填充相关的模型推断。为此,独立分配模型和数据集路径至关重要。然后,模型路线可用于创建火花 UDF。接下来是读取它们并将其注册到数据帧中。先前建立的火花 UDF 在最后阶段用于构造新特征。
在我的 GitHub repo 中可以找到这个模型预测和分发脚本的完整实现示例版本!
非常感谢您的提问和评论!
参考
使用 TensorFlow API 在深度神经网络中剪枝模型
艾蒂安·德洛里欧在 Unsplash 上拍摄的照片
机器学习中最常见的问题之一就是过拟合。这可能是由多种原因造成的[1]。为了解决这个问题,一个常见的解决方案是在模型中添加正则化项。另一种方法是通过减少参数的数量来降低模型的复杂性。要获得最佳解决方案,应结合使用这两种方法。在本文中,我们将探讨后者,更具体地说,如何使用 Tensorflow 模型优化 API 在 Keras Tensorflow 模型中合并模型修剪(包括删除模型中多余的权重)。
什么是修剪,为什么选择修剪?
修剪机器学习模型包括移除(永久设置为 0)某些权重。通常被修剪的权重是那些已经接近 0(绝对值)的权重。这阻止了模型过度拟合,因为在训练开始时被认为无用的权重不能再次被重新激活。
有不同的方法来修剪模型。人们可以在开始时修剪一些随机数量的权重。人们可以在训练结束时进行修剪,以简化模型并使其更轻。在这里,我们将看到如何建立一个修剪调度程序,它将在每批学习结束时慢慢修剪一些权重,直到达到所需的稀疏度(权重百分比设置为 0)。
有人可能想知道为什么模型应该被修剪,而不是从一开始就用较少的可训练参数初始化。这样做的原因是,为了增加模型容量,您可能希望保持一个相当复杂的模型架构,在特性之间有许多可能的交互,但是限制它们的数量。此外,微调哪些层的大小应该减少,哪些层的大小应该增加,以及哪些功能应该保留,往往是一项乏味而徒劳的工作。在训练过程中,为了一点一点地去除多余的权重,对模型进行修剪要简单得多。这种方法的一个优点是,它允许人们训练多个不同的模型,这些模型可能已经被不同地修剪,然后人们可以使用各种集成学习技术来组合这些模型[2]。这些集合模型通常比单一模型更加稳健。我们现在将看到如何实现这一技术。
张量流模型优化工具包
目标是在每个训练步骤(批次)结束时消除最弱的重量。虽然人们可以实现自己的回调来做到这一点,但幸运的是,已经存在一个名为 tensor flow Model Optimization(TF mot)的 Tensorflow API 来做这件事[3]。这个工具允许用户定义一个修剪调度程序,它将自动处理权重消除。调度程序遵循多项式衰减调度。一个提供初始稀疏度、最终稀疏度、开始修剪的步骤、结束修剪的步骤,最后是多项式衰减的指数。在每一步,该工具包将消除足够的权重,以使实现的稀疏度为:
多项式衰减调度程序的公式
其中 S 为稀疏度, S ₑ为最终稀疏度, S ₀为初始稀疏度, t 为当前时间步,tₑ为结束步, t ₀为开始步,α为指数。α的默认值是 3。为了找到最佳值,需要考虑其他超参数。理想情况下,应该在相当长的时间内一点一点地削减权重,以便网络有时间适应权重的损失。事实上,如果权重修剪得太快,就有删除权重的风险,这些权重可能仅仅是因为它们被初始化为接近 0,而网络没有时间学习。
为了更好地理解这些概念,我们将通过一个例子来说明如何在您的模型中应用修剪。
修剪:一个例子
修剪最适用于具有许多参数的模型(如 MLPs ),并且我们怀疑许多参数是无用的。当我们的数据集有许多特征(几百个),但并不是所有的特征都是相关的时,就会出现这种情况。自然地,如果知道哪些特征是需要的,哪些是不需要的,那么在过程的特征工程步骤中,应该使用降维技术(例如 PCA、NMF [4]等)来消除不相关的特征。).然而,情况并非总是如此。
对于我们的示例数据集,我们将使用 sklearn.datasets 库的 make_regression 函数。此函数生成一个回归数据集,用户可以在其中指定所需的观测值数量、要素数量、相关要素数量以及数据的噪声程度。
**import** pandas **as** pd
**import** numpy **as** np
**from** sklearn.model_selection **import** train_test_split
**from** sklearn.datasets **import** make_regression*# Parameters of the data-set*
**n_samples** = 10000
**n_features** = 1000
**n_informative** = 500
**noise** = 3*# Create dataset and preprocess it*
x, y = **make_regression**(**n_samples**=n_samples, **n_features**=n_features, **n_informative**=n_informative, **noise**=noise)
x = x / **abs**(x).**max**(axis=0)
y = y / **abs**(y).**max**()
x_train, x_val, y_train, y_val = **train_test_split**(x, y, **test_size**=0.2, **random_state**=42)
现在我们有了我们的例子,让我们建立我们的模型。因为有大量的特征,并且为了我们的示例的目的,我们将设计一个具有许多参数的非常大的 MLP:
**import** tensorflow **as** tf
**from** tensorflow.keras.models **import** Sequential
**from** tensorflow.keras.layers **import** Dense, ReLU**model** = tf.keras.Sequential()
**model**.add(Dense(1024, kernel_initializer="he_normal", input_dim=n_features))
**model**.add(ReLU())
**model**.add(Dense(1024))
**model**.add(ReLU())
**model**.add(Dense(1))
这种架构产生了一个超过 2,000,000 个参数的模型,这是一个很大的数目,尤其是因为我们知道有一半的特性实际上是没有用的。我们如何整合修剪?这很简单。我们必须首先在字典中设置各种修剪参数。然后,我们使用 tfmot 使用修剪参数基于原始模型定义一个新模型。最后,我们添加一个修剪回调函数。
**import** tensorflow_model_optimization **as** tfmot**initial_sparsity** = 0.0
**final_sparsity** = 0.75
**begin_step** = 1000
**end_step** = 5000**pruning_params** = {
'pruning_schedule': tfmot.sparsity.keras.PolynomialDecay(
**initial_sparsity**=initial_sparsity,
**final_sparsity**=final_sparsity,
**begin_step**=begin_step,
**end_step**=end_step)
}**model** = tfmot.sparsity.keras.prune_low_magnitude(model, **pruning_params)
**pruning_callback** = tfmot.sparsity.keras.UpdatePruningStep()
然后,我们像往常一样编译和拟合模型,不要忘记在拟合步骤中添加回调:
**model**.compile(
loss="mse",
optimizer=tf.keras.optimizers.Adam(learning_rate=0.001)
)**model**.fit(
x_train,
y_train,
epochs=200,
batch_size=1024,
callbacks= pruning_callback,
verbose=1
)
选择超参数
我们现在有了修剪所需的所有元素。但是效果如何呢?你如何设置参数?我通常总是将初始稀疏度保持在 0,除非你有目的地想要用非常不同的随机初始化来创建多个稀疏模型,以便聚集它们。我设置了 begin 步骤,以便在几个时期后开始修剪。我通常设置的最后一步是在几个时期内进行修剪(大约 10 个时期)。
根据我的经验,这些参数没有最终的稀疏度参数重要,最终的稀疏度参数实际上取决于手头的问题。在过拟合的情况下,模型在训练集上的性能将比在验证集上好得多。在模型中引入一些稀疏性很可能会降低训练集的性能,但会提高验证集的性能。进一步增加稀疏度将继续提高验证集的性能。显然,当最终稀疏度太大时,模型变得太简单,训练集和验证集的性能都将开始下降,这意味着我们的模型现在对数据拟合不足。因此,作为最终稀疏度的函数,验证集上的性能存在最小值。
结果
在下图中,我采用了前面提到的例子,并用不同的最终稀疏度训练了不同的模型。模型的性能是用不同的随机初始化在 10 个不同的训练上平均的:
[0,1]中最终稀疏度的训练集和验证集的平均损失
对于非常低的最终稀疏度,模型明显过拟合,如上图所示。验证集的损失比训练集的损失大几个数量级。随着最终稀疏度的增加,训练集的损失单调增加,而验证集的损失在大约 95%稀疏度时具有最小值,这导致模型具有大约 100,000 个参数。这在下图中可以看得更清楚:
[0.8,1]中最终稀疏度的训练和验证集的平均损失
结束语
在这篇短文中,我们看到了使用 Tensorflow 模型优化工具包在 Tensorflow 模型中实现修剪非常简单,只需添加几行代码。修剪是减少过度拟合的另一种方法,与其他常用方法(如正则化、剔除和批量归一化)一起使用。修剪在模型有大量参数和数据集有很多特征的情况下表现出色。根据奥卡姆剃刀原理,它允许一个人在保持节俭的同时训练大容量的模型。然后,可以通过集成学习技术将这些模型结合起来,以构建更健壮的模型。
感谢
我要感谢尼古拉斯·莫里泽和克里斯托夫·盖斯勒对本文写作的帮助和支持。
参考文献
[1]https://hastie.su.domains/ElemStatLearn/(第七章)
https://link.springer.com/article/10.1007/s10462-009-9124-7
https://www.tensorflow.org/model_optimization/
https://hal.archives-ouvertes.fr/hal-03141876/document
https://www.jmlr.org/papers/volume22/21-0366/21-0366.pdf
关于我们
Advestis 是一家欧洲合同研究组织(CRO),对统计和可解释的机器学习技术有着深刻的理解和实践。Advestis 的专长包括复杂系统的建模和时间现象的预测分析。
领英:https://www.linkedin.com/company/advestis/
用 Python 实现亚马逊 Kindle 书评的模型选择和超参数调整
基于模型选择和超参数优化的书评情感分析
Emil Widlund 在 Unsplash 上拍摄的照片
介绍
这篇文章旨在选择和部署最佳的机器学习模型,对亚马逊 Kindle 商店的书评数据集进行情感分析。
在之前的一篇文章中,我们在一个 IMDB 电影评论数据库上优化了一个支持向量机算法。虽然 SVM 是分类问题的一个很棒的算法,但它也是最好的选择吗?对于这个新项目,现在的目标是包含模型选择机制。
通过管道化多个模型,我们可以从不同的方面比较它们,包括准确性和效率。
数据
你可以在下面的链接中找到这个数据集,它由大约 1,000,000 篇书评组成[1][6]。目标是通过对数据集的一部分进行训练,产生一个高性能的情感分析器。如果你想复习什么是情绪分析,我可以建议快速阅读这篇文章,它涵盖了所有的基础知识。
csv 文件的结构包括 10 列:
asin
-产品的 ID,如 B000FA64PKhelpful
-评价的有用性等级-例如:2/3。overall
-对产品的评级。reviewText
-审查文本(标题)。reviewTime
-审查时间(未加工)。reviewerID
-审核人的 ID,如 A3SPTOKDG7WBLNreviewerName
-审核人的姓名。summary
-评审总结(描述)。unixReviewTime
- UNIX 时间戳。
对于该算法,我们只需要两个:评论语料库及其评级。
以下是一个示例评论:
I enjoy vintage books and movies so I enjoyed reading this book. The plot was unusual. Don't think killing someone in self-defense but leaving the scene and the body without notifying the police or hitting someone in the jaw to knock them out would wash today. Still it was a good read for me.
正如您所注意到的,该文本呈现出很少的“特殊”字符,这使得它更容易清理。最重要的是,我们应该删除所有不增加价值的介词和代词,因为它们太复杂了。
文本处理
尽管文本预处理不是本文的重点,我还是要简单解释一下,如果你想了解更多细节,请点击下面的链接,链接到我以前的文章之一。
在自然语言处理领域,文本包含各种各样对 ML 算法没有用的符号和单词。因此有一个阶段,称为文本处理,指的是文本的分析、处理和生成[2]。
这使得 ML 模型更容易训练,因为它减少了“噪声”,即对于预测无用的信息量。
模型
对于这个特殊的分类问题,我考虑了 7 种流行的高性能机器学习算法。每种方法都有其独特之处,很可能会返回与其他方法不同的结果:
- 线性判别分析(LDA) 关注组间方差的最小化以及组间方差的最大化。换句话说,该算法跟踪保证最大类别可分性的超平面(帮助分类数据点的决策边界)。
- k 个最近邻居(kNN) 创建多个 k 个最近邻居的数据记录 t 的“邻域”。然后,多数表决机制决定该记录 t 是否属于该类。该方法不考虑基于距离的加权。
- 高斯朴素贝叶斯 是一种概率分类器。简单和高效是它最显著的特点。贝叶斯定理是分类器的基础。它计算一个记录属于某个类别的概率[3]。
- 利用给定的独立变量数据集,逻辑回归计算事件发生的概率。为此,首先使用一个函数计算赔率,该函数返回一个介于 0 和 1 之间的数字,其中 0 表示不太可能发生。最后,应用 logit 变换将结果精确分类为 0 或 1。
- 决策树分类器(CART) 是一种通过“询问”一系列问题来分离数据的模型,因此决定将一个新记录放在哪个桶中。这会创建一个树形图,其中每个节点代表一个问题,每个叶子代表一个用于预测的输出变量。
- 【SVM】支持向量机是非概率分类器。与 LDA 类似,SVM 采用了超平面的概念。假设两个类是线性可分的,它们可以被超平面所除。在此基础上,该算法旨在通过在称为“向量”的超平面上的两条线来最大化类别 1 和类别 2 之间的空间。
超参数
在定义超参数之前,定义一个“标准”参数很重要。当一个模型收敛时,我们可以说它找到了描述它所训练的数据的一般行为的最佳参数组合。
每个机器学习模型都有一个隐喻性的架构。超参数让用户有机会使用实验方法找到模型“结构”的最佳配置。假设有 5 个超参数,每个超参数有 10 种可能的设置,当专业人员尝试各种设置组合直到性能达到峰值时,就会发生“调整”。例如,超参数 1 可能等于 5,超参数 2 可能等于 0.2,依此类推。
我想强调参数和超参数之间的根本区别。前者也意味着系数或权重,这是学习过程的结果。后者由用户在训练前手动设置。
代码部署
数据可视化
代码部署的第一部分侧重于数据探索和可视化。与文本评论相关的分数分布可以告诉我们有价值的信息。
**#Importing libraries**
import matplotlib.pyplot as plt
import pandas as pd**#Reading Dataset**
df = pd.read_csv('kindle_reviews.csv')**#Counting values within each review bucket**
category_dist = df['overall'].value_counts()**#Defining chart**
plt.figure(figsize=(8,6))
category_dist.plot(kind='bar')
plt.grid()
plt.xlabel("Scores", fontsize = 12)
plt.ylabel("Number of Reviews by Rating", fontsize = 12)
plt.title("Distribution of Reviews by Rating", fontsize = 15)**#Generating chart**
plt.show()
按评级列出的评论分布—按作者列出的图表
绝大多数评论都集中在 4 星和 5 星之间,这通常是不好的。数据集是不平衡的,因此当我们训练它时,算法可能会有偏差。
最重要的是,研究表明,与多类分类相比,二元分类总体上更准确[4]。由于我们要有更高的精度,我们需要将这个项目转化为一个二元分类问题。
进行改变的一种可能方式是将所有高于 3 分的评论视为“正面的”,而将所有低于 3 分(包括 3 分)的评论视为“负面的”。接下来的步骤是仅对数据集的一部分执行模型选择。
在将近 1,000,000 行上确定最佳模型可能会大幅增加处理时间,而不会增加任何越来越有价值的性能信息。
在从原始数据集中选择 50,000 行并将检查分数分成两类后,最终结果应该如下所示:
仅分析 50,000 条记录的评论分布(按情感分类)——按作者分类的图表
文本清理
代码部署的第二部分侧重于文本清理。如前所述,句子中的单词越多,复杂度越高,但对准确性的贡献却微乎其微。
解决方案在于消除停用词。在英语中,、【the】、、、等都可以作为停用词。在文本挖掘中,停用词被定义为携带很少有用信息的不重要的词。
最重要的是,单词需要统一,全部小写,特殊字符需要消除。如果我们在前面看到的例句上部署代码,结果类似如下:
enjoy vintage books movies enjoyed reading book plot unusual think killing someone self defense leaving scene body without notifying police hitting someone jaw knock would wash today still good read
你会同意我的观点,现在消极和积极的词更容易识别,例如,“享受”,“享受”和“好”标志着潜在的积极评价。检查后,评论家给这本书打了 5 颗星。在项目结束时,我们的模型应该将此归类为“积极”。
最后一步是增加负面评论的数量,直到它们达到相同数量的正面评论。“上采样”人工生成少数类的数据点,并将它们添加到数据集中。该过程旨在使两个标签具有相同的计数,并防止模型偏向多数类。
型号选择
代码部署的第三部分侧重于为我们的数据选择性能最佳的模型。
- Scikit-learn 和 matplotlib 是唯一需要的两个库。Sklearn 包括对数据执行机器学习所需的所有功能。每个模型需要分配一个“子库”:逻辑回归、KNeighborsClassifier、决策树分类器、SVC、GaussianNB 和线性判别分析。
- 在上一节中,我们使用了一种称为“上采样”的技术来匹配负面书评和正面书评的数量。在这个阶段,我们可以从数据中定义输入和目标变量。输入变量 x 为“ reviewText ”,包含评论的语料库;输出变量 y 为“”,包含标签“ 正 ”和“ 负 ”。
- 我们知道,一些用于分析的模型,包括决策树分类器,需要一个密集的矩阵。密集矩阵大多包含非零值。密集转换器类确保所有矩阵都是密集的,以避免任何错误。
- 然后创建一个名为“模型”的列表,然后将分配给每个模型的对象添加到列表中。另一方面,列表“结果”将包含与其名称相关联的所有不同的模型分数。
- kfold 参数表示我们需要多少 k 倍。这引入了交叉验证的概念。交叉验证旨在更好地估计模型的准确性。它被定义为 k 重交叉验证,k 是数据被划分的子组数。该模型在一个子组上训练,并在剩余的 k-1 上测试。准确度是根据平均分计算的。
- 管道在 k-fold of choice 上应用计数矢量器、密集转换器和选择模型,并执行交叉验证。然后它在控制台上打印结果。
- matplotlib 最后生成一个箱线图,这样我们就可以更好地解释结果。
为我们的数据寻找性能最佳的模型
模型选择过程后算法的准确性比较—作者提供的图表
箱线图为您提供了关于我们的模型在精确度方面的五个临界值的信息:最小值、第一个四分位数(25%)、中值(第二个四分位数)、第三个四分位数(75%)和最大值。
在 x 轴上,有所有用于交叉验证分析的模型。相反,在 y 轴上,我们有准确度分数。例如,逻辑回归模型是表现最好的模型,其最小精度为 0.82,最大精度为 0.86,但是支持向量机保证了最一致的性能,其最小值和最大值彼此接近。KNN 是表现最差的,表现出很少的一致性。LDA、CART 和朴素贝叶斯也表现不佳。
由于上述原因,超参数优化现在将集中在两个性能最高的模型上:逻辑回归和支持向量机。
支持向量机超参数调整
代码部署的第四部分关注支持向量机模型的超参数调整:
- 在前一个代码单元中已经导入了库,但是我决定重新导入它们以使这个代码片段独立
- 这次的流水线只包括计数矢量器和支持向量机模型,不需要密集转换器
- 转到参数列表,这些参数包含 grid_search 将为管道的每个组件尝试的所有可能的超参数组合。例如,计数矢量器的参数 max_df 负责模型的泛化。Max_df 删除出现太频繁的单词,max_df 为 0.7 会忽略出现在 70%以上文档中的术语。在一个场景中,“ vect__max_df ”将使用内核 poly 和 C 参数 10,将 0.7 的 max_df 与(1,1)的 ngram_range 组合起来。因为每个交叉验证进行了 5 次,所以总“适合”(组合)是 405。
- 在启动 grid_search.fit 之后,最后一部分代码开始在控制台上打印计算结果
为计数矢量器和 SVM 模型寻找最佳参数
结果如下:
*Best: 0.840734 using {'SVM__C': 10, 'SVM__kernel': 'rbf', 'vect__max_df': 0.7, 'vect__ngram_range': (1, 2)} 0.730129 (0.038366) with: {'SVM__C': 10, 'SVM__kernel': 'poly', 'vect__max_df': 0.7, 'vect__ngram_range': (1, 1)} 0.692791 (0.049500) with: {'SVM__C': 10, 'SVM__kernel': 'poly', 'vect__max_df': 0.7, 'vect__ngram_range': (1, 2)}*
性能最佳的超参数设置是:
- C = 10
- 核类型= rbf
- max_df = 0.7
- ngram_range = (1,1)
如果我们对 90,000 个向上采样的行应用上面找到的具有优化的超参数的管道,并且我们计算精确度方面的性能,结果是相当惊人的。针对 kindle 评论优化的支持向量机模型在分类新数据方面的效率为 99%。大约 1 小时的处理时间后显示结果。
*precision recall f1-score support Negative 0.98 1.00 0.99 8924
Positive 1.00 0.98 0.99 9109 accuracy 0.99 18033
macro avg 0.99 0.99 0.99 18033
weighted avg 0.99 0.99 0.99 18033*
逻辑回归超参数调整
代码部署的第五部分关注逻辑回归算法的超参数优化。所有代码都与上一节极其相似,只有很少的重要区别。
逻辑回归模型需要一个参数来表示它可以达到的最大迭代次数,没有这个参数,模型就不会收敛。最重要的是,与 SVM 模型相比,求解器的类型发生了变化。考虑用于分析的解算器是“牛顿-cg”、“lbfgs”和“liblinear”。
为计数向量机和逻辑回归模型寻找最佳参数
结果如下:
*Best: 0.857362 using {'LR__C': 1.0, 'LR__solver': 'newton-cg', 'vect__max_df': 0.7, 'vect__ngram_range': (1, 3)}
0.825643 (0.003937) with: {'LR__C': 100, 'LR__solver': 'newton-cg', 'vect__max_df': 0.7, 'vect__ngram_range': (1, 1)} 0.852704 (0.004520) with: {'LR__C': 100, 'LR__solver': 'newton-cg', 'vect__max_df': 0.7, 'vect__ngram_range': (1, 2)}*
性能最佳的超参数有:
- C = 1
- 求解器=牛顿-重心
- max_df = 0.7
- ngram_range = (1,3)
同样,如果我们对 90,000 个向上采样的行应用具有优化超参数的逻辑回归模型,结果非常接近 SVM 模型。在任何与机器学习相关的场景中,都很难达到 98%的准确率。这次的处理时间大致是 3 分钟。
*precision recall f1-score support
Negative 0.97 1.00 0.98 8924
Positive 1.00 0.96 0.98 9109 accuracy 0.98 18033
macro avg 0.98 0.98 0.98 18033
weighted avg 0.98 0.98 0.98 18033*
测试算法
SVM 和逻辑回归在准确性方面都表现出色。如果我们只根据这个参数来选择算法,那么支持向量机模型将是最佳选择。然而,需要考虑的另一个重要方面是:处理时间。SVM 模型在 70,000 行上训练需要一个小时,而逻辑回归只需要 3 分钟。当涉及到模型部署时,准确性之上的计算效率是基础。
**在这个阶段,需要进行最后的检查。“测试包含一个肯定句,而“测试 _ 1”包含一个否定句。
*##Testing Algorithm on single sentences
test = ['The book was really good, I could have not imagined a better ending']test_1 = ['The book was generally bad, the plot was boring and the characters were not original']test = count_vect.transform(test).toarray()
test_1 = count_vect.transform(test_1).toarray()#Printing prediction
print(LR.predict(test))
print(LR.predict(test_1))*
下面的输出显示,经过训练的分类器正确地预测了一篇书评是正面的还是负面的。
*Output:['Positive']
['Negative']*
结论
本文展示了模型选择和超参数调整如何显著提高精度,并提供了其他方面的全貌。我们从 6 个模型开始,4 个被过滤掉了,剩下的两个有很好表现的模型中,只有一个有可能进入生产。多亏了来自亚马逊 Kindle 商店的非常结构化的数据,除了单独确定情绪之外,还会有如此多的未来项目。从人工智能开始,它可以在一本书出版前对其进行评论和评级,或者在书籍被添加到商店后立即了解哪些书会做得很好。尤其是机器学习,可能性是无穷无尽的。
最后一点,如果您喜欢该内容,请考虑添加一个关注,以便在新文章发布时得到通知。如果你对这篇文章有什么要考虑的,写在评论里吧!我很想读读它们:)谢谢你的阅读!
PS:如果你喜欢我写的东西,如果你能通过 这个链接 订阅一个中等会员,那对我来说就是全世界。这是一种间接的支持我的方式,你会得到媒体文章提供的惊人价值!
参考
[1]麦考利,J. (2018)。亚马逊评论数据。检索于 2022 年 7 月 31 日,来自 Ucsd.edu 网站:http://jmcauley.ucsd.edu/data/amazon/
[2]阿佩尔,o .,奇克拉纳,f .,卡特,j .,&藤田,H. (2016 年 5 月 19 日)。句子级情感分析问题的混合方法。检索于 2022 年 7 月 30 日,来自 ResearchGate 网站:https://www . ResearchGate . net/publication/303402645 _ A _ Hybrid _ Approach _ to _ the _ opinion _ Analysis _ Problem _ at _ the _ Sentence _ Level
[3] Raschka,s .,& Mirjalili,V. (2014 年)。朴素贝叶斯和文本分类 I 导论和理论。从 https://arxiv.org/pdf/1410.5329.pdf取回
[4]杰哈,a .,戴夫,m .,,马丹,S. (2019)。使用不同数据挖掘分类技术的二分类器和多分类器的比较。 SSRN 电子杂志。https://doi.org/10.2139/ssrn.3464211
[5]何,r .,&麦考利,j .(未注明)。沉浮:用一类协同过滤对流行趋势的视觉演变建模。https://doi.org/10.1145/2872427.2883037
正确选择模型:嵌套交叉验证的温和介绍
实用机器学习
了解如何使用这一重要的机器学习技术
由 Unsplash 上的 Edge2Edge 媒体拍摄
本文将回顾机器学习中最重要的技术之一:嵌套交叉验证。当部署一个模型时,我们从几个选择(例如,随机森林与支持向量机)中选择具有超参数的最佳组合(例如,具有 50 棵树的随机森林与具有 5 棵树的随机森林)的最佳选择。但是,我们还需要估计泛化误差(模型在生产中的表现)。嵌套交叉验证允许我们找到最佳模型并正确估计其泛化误差。
在文章的最后,我们提供了一个用 Ploomber 开发的示例项目,您可以重用您的数据,立即开始运行嵌套的交叉验证!
为什么我们需要交叉验证?
让我们想象一下,我们正在进行一个机器学习项目,我们已经完成了清理数据和获得一些训练集的繁重工作,并且我们训练了它。我们准备好部署它了吗?
不完全是。在部署之前,我们想知道该模型在生产中的表现如何。为此,我们可以计算一个评估指标,比如说准确性。
我们使用哪些数据来计算指标?一种方法是为我们的训练集中的所有观察值生成预测,并计算评估度量:
图片作者。
这是它在代码中的样子:
控制台输出:(1/1):
Accuracy: 0.97
这种方法在方法上是不正确的:我们不应该用相同的数据进行训练和评估,因为我们的模型已经看到了训练示例。因此,它可以简单地记住标签,并具有完美的准确性。
我们将数据分为两部分:模拟生产条件的训练和测试(根据看不见的数据进行预测)。用第一部分拟合我们的模型,用第二部分评估。
图片作者。
下面是如何用代码实现的:
控制台输出:(1/1):
Accuracy: 0.91
我们可以看到这次的估计值更低了(0.91 vs . 0.97);较高的估计是对我们的模型将如何表现的过于乐观的估计。
因此,这种基本的训练/测试方法比第一种方法更好。尽管如此,它还有一个问题:对测试集的选择是明智的。
我们可以幸运地选择一个简单的测试集导致一个过于乐观的泛化错误(或者不幸地有一个过于悲观的估计)。因此,为了覆盖我们的地面,我们可以这样做:重复相同的过程多次,平均结果;这个过程被称为交叉验证:
图片作者。
总之:交叉验证为我们提供了一种可靠的方法来评估我们的模型在生产中的性能。
让我们来实现它:
控制台输出:(1/1):
Cross-validated accuracy: (0.98 + 0.92 + 0.96) / 3 = 0.95
所以现在我们得到了一个结果(0.95),介于第一种(方法错误)方法(0.97)和第二种训练/测试方法(0.91)之间。
型号选择
我们有一种通过交叉验证来估计泛化误差的方法,但是我们还没有完成。有很多模型可用:随机森林、XGBoost、支持向量机、逻辑回归等。因为我们不知道哪一种效果最好,所以我们尝试了几种。
所以假设我们尝试随机森林和支持向量机。我们已经有了随机森林的结果,现在让我们在支持向量机上运行交叉验证。
控制台输出:(1/1):
Cross-validated accuracy: (0.96 + 0.98 + 0.94) / 3 = 0.96
让我们总结一下结果:
图片作者。
根据结果,我们应该使用支持向量机。
然而,我们并没有改变模型的参数(例如,一个拥有大量树木的随机森林)。那么,有没有可能我们做出了一个次优的决定?
让我们尝试几个实验,这一次,用几个超参数训练两个模型(使用我们的交叉验证程序):
控制台输出:(1/1):
SVC(kernel='linear', random_state=0):
Cross-validated accuracy: (1.00 + 1.00 + 0.98) / 3 = 0.99SVC(kernel='poly', random_state=0):
Cross-validated accuracy: (0.98 + 0.94 + 0.98) / 3 = 0.97 RandomForestClassifier(n_estimators=2, random_state=0):
Cross-validated accuracy: (0.98 + 0.92 + 0.96) / 3 = 0.95RandomForestClassifier(n_estimators=5, random_state=0):
Cross-validated accuracy: (0.98 + 0.94 + 0.94) / 3 = 0.95
基于这些结果,我们得到了一个更好的模型!0.99 精度的线性核的支持向量机!
不完全是。这里有一个方法上的错误。
我们强行找到了最好的模型。本文证明了当我们使用(普通的)交叉验证方法优化超参数和模型选择时,可能会出现过于乐观的泛化误差(由于过度拟合)。
输入嵌套交叉验证
我们使用嵌套交叉验证来修复上述错误,这提供了一种更准确的方法来估计泛化错误,同时还优化了超参数。
它之所以得名,是因为我们有效地嵌套了两个交叉验证过程。让我们看看它在实践中是怎样的:
图片作者。
我们嵌套了两个交叉验证循环。看第三个作为参考。在进行初始剥离后,我们再次剥离(2/3 的数据)。内部循环优化超参数:我们为每个超参数配置(在这种情况下,n_estimators = 2
和n_estimators = 5
)进行训练,计算交叉验证的度量(平均值)并挑选最佳超参数配置(在这种情况下,n_estimators = 5
),然后,我们进入外部循环,使用最佳配置(n_estimators = 5
)重新训练并报告准确度。我们重复同样的过程,直到完成。
在这个过程结束时,我们将有一个表格,报告每个模型的估计泛化误差;让我们运行它:
控制台输出:(1/1):
GridSearchCV(estimator=RandomForestClassifier(random_state=0), param_grid={'n_estimators': [2, 5]}):
Cross-validated accuracy: (0.98 + 0.92 + 0.96) / 3 = 0.95 GridSearchCV(estimator=SVC(random_state=0), param_grid={'kernel': ['linear', 'poly']}):
Cross-validated accuracy: (1.00 + 0.94 + 0.98) / 3 = 0.97
模型性能总结。图片作者。
有了这些信息,我们可以自信地选择支持向量机作为我们的赢家模型。我们还可以说,它的估计泛化误差为 0.97(看,这低于我们之前没有使用嵌套交叉验证时的估计值 0.99)。
作为最后一步,我们运行最后的交叉验证程序,以找到最佳参数。注意这是一个普通的交叉验证过程:
图片作者。
代码如下:
控制台输出:(1/1):
SVC(kernel='linear', random_state=0):
Cross-validated accuracy: (1.00 + 1.00 + 0.98) / 3 = 0.99SVC(kernel='poly', random_state=0):
Cross-validated accuracy: (0.98 + 0.94 + 0.98) / 3 = 0.97
所以现在我们已经准备好部署:我们将使用kernel = 'linear'
部署支持向量机!
但是考虑一个关键点:我们将报告 0.97(通过嵌套的交叉验证过程)作为我们的泛化估计,而不是这里得到的 0.99。
就是这样!现在,您已经具备了嵌套交叉验证技术,可以选择最佳模型并优化超参数!
示例代码
图片作者。
为了您的方便,我们为您准备了一个示例 Ploomber 管道,让您快速上手;以下是获得它的方法:
一旦执行了管道,检查一下output/report.html
文件,它将包含嵌套交叉验证过程的结果。编辑tasks/load.py
来加载你的数据集,再次运行ploomber build
,你就可以开始了!您可以编辑pipeline.yaml
来添加更多模型并并行训练它们。
警告
在我们的示例中,我们只评估了两种配置的两个模型。然而,由于我们嵌套了两个交叉验证过程,培训程序的数量像雪球一样越滚越大。如果我们添加更多的模型和超参数,我们很快就会被要求运行数百个训练程序来找到最佳模型。所以,为了加快结果,你可能想要并行运行所有这些实验;用 Ploomber 在一台机器上就可以轻松做到。不过,如果你想在多台机器上分配工作,你必须建立一些云基础设施。或者,您可以尝试 Ploomber Cloud ,它将快速启动必要的资源,在云中执行您的代码(并将作业并行化),获得结果,并关闭基础架构,这样您就不会让那些昂贵的服务器继续运行。不用离开你的笔记本。
最后的想法
在我作为数据科学家的日子里,我花了一些时间来完全掌握嵌套交叉验证的概念。所以希望这篇帖子对你有帮助。你有什么问题吗?请联系我们的社区,我们很乐意为您提供帮助。
最初发表于 ploomber.io
模型测试对于构建领域知识至关重要
原文:https://towardsdatascience.com/model-tests-are-critical-for-building-domain-knowledge-8d5fde2660d8
测试可以防止退化。但是测试最重要的产品是领域知识和强大的能力。
嵌入空间中两个分布之间边界的选择。图片作者。
在机器学习中,测试是一项关键但经常被忽视的实践。在没有测试的情况下建立一个机器学习系统很可能在最糟糕的时候产生糟糕的结果——当所有的盒子都被检查时,当模型被投入生产时,当真实的人受到影响时。
这是一个典型的(真实的)机器学习测试故事。但是这个故事只有大棒没有胡萝卜。它完全忽略了测试数据团队取得进步的最重要的产品:领域知识。
随着机器学习项目从开始阶段走向成熟,它们的复杂性也在增加。开发过程中的每一次迭代都会产生新的见解,触发诸如数据清理、模型调整或更多标记之类的活动。这些行为可能是净增值,但系统中的小口袋会出现倒退,有时是看不见的。测试可以防止这些退化。
测试经常给人一种乏味的感觉,这是很好的实践,但并不总是必要的。围绕测试的经典问题出现了,比如测试什么是必要的,这些测试应该有多复杂。但是将测试视为领域知识的构建和系统化,显示了测试超越棘轮以防止倒退的力量。
将测试与其他知识构建活动(如错误分析和数据注释)结合起来,可以鼓励科学进步和良好的工程设计。注释、错误分析和测试可以被交叉利用,从而产生复合收益以获得更好的系统性能和对建模内容的更深入的理解。自动驾驶汽车为理解这一点提供了一个有趣的视角,特斯拉自动驾驶部门的方法论展示了这一视角的力量。
通过测试积累知识需要平台支持。平台团队必须在测试和其他活动中实现无缝体验。MLOps 领域的工具构建者应该在这方面支持他们,将集成工作放在第 n 个特性之上。如果我们关心平台用户的长期价值,仅仅解决工作流的一小部分是不够的。
测试是知识的积累
模型测试是一种断言,即模型应该在某些场景中以某种方式运行。从技术上讲,场景是由模型输入指定的,可以是一个样本,也可以是多个样本。
在你进行测试之前,你可能甚至不知道一个场景的存在。以一个自动驾驶汽车模型为例,它可以检测视野中的行人。你可能不会想到行人会有翅膀、不正常的长腿或闪闪发光的衣服,直到在有许多盛装行人的游行中进行路试。
一个非常令人困惑的行人的例子。来源:维基共享资源。执照: CC BY-SA 4.0
(自动驾驶汽车是测试对人工智能安全有多重要的一个很好的例子。)
了解这些奇怪的案例是通过经验,或隐性知识。为了利用隐性知识,需要将其编码到系统中。
知识的隐式编码是最普遍的,因为它很方便。方程中一个奇怪的无法解释的项,或者一个碰巧稳定模型训练的“神奇”配置,都是隐性知识的例子。他们的作者可能知道他们在做什么,但没有人知道。这就产生了所谓的部落知识。
隐式编码不仅对协作有害,而且还阻碍了技术固有的累积杠杆作用。显式编码使其他人能够学习和建立该知识。在神奇的训练配置示例中,我们可以将训练配置存储在一个数据库中,其中包含链接到训练结果的作者注释。队友们以后可以在许多实验中查询配置,以找到那些效果最好的。通过组织和链接元数据,学习和获得新的见解成为可能。
在一些 python 文件中编写test_for_winged_pedestrian()
测试函数错过了一个复合知识收获的重要机会。有翅膀的步行者,如果在步行者之下的概念分类中被适当地组织,产生跨越测试之外的多个工作流程步骤的杠杆作用。这种利用通过构建更高级别的数据查询来体现。盛装行人是一个首先必须与其他概念联系在一起的概念:
Road obstruction
├── Stationary
│ ├── Traffic cone
│ └── ...
└── Non-stationary
├── Pedestrian
│ ├── Average pedestrian
│ ├── Pedestrian with walking aid
│ └── Costumed pedestrians
├── Bicyclist
└── ...
现在想象一种情况,其中“行人”作为模型的目标标签可能在性能上遭受损失。穿着服装的行人以及手持拐杖或步行者、骑摩托车者和其他移动障碍物的行人可能是在查询中使用的有价值的概念,也许是为了理解行人检测模型可能失败的原因,或者是为了进一步标注而显示未标注的示例。实现这一点的第一步是认识到测试用例、标记和错误分析是同一件事情的不同方面:构建领域知识。
工作流程中的测试
在我们的例子中,一名技术人员在进行道路测试时,可能会注意到笔记本电脑屏幕上的错误。或者科学家在模型上做错误分析时可能会注意到。标注者可能会在标记来自路测的新数据时发现它。它甚至可能在数据准备管道中的不同测试失败时出现。
机器学习开发工作流程。图片作者。
有许多工具可以处理每个工作流程步骤,但是这些工具通常不能很好地集成。预期体验没有考虑之前和之后的步骤,这会导致摩擦并抑制整体效率。一个好的平台将融合不同步骤之间的接缝,在开发人员工作时为他们提供统一的体验。
如果在注释中发现一个数据点的问题,想象一下直接在注释工具中放置一个“添加到测试套件”的按钮的能力。
一个分类标签界面的简单模型。“添加到测试套件”按钮使得向测试套件添加例子变得容易。图片作者。
如果问题出现在数据收集或数据准备管道中,开发人员应该准备好任何东西,从 pytest 到像Great expects这样的成熟工具,以便快速添加测试用例。
测试函数示例。像这样的代码将与管道代码一起存储在 git repo 中。注意将测试与概念联系起来的装饰器。图片作者。
这些接口使得开发人员可以很容易地添加测试,降低了模型回归的可能性,并为知识共享奠定了基础。
案例研究:特斯拉自动驾驶仪
Andrej Karpathy 描述了内部平台上的工作流和功能,实现了自动驾驶汽车的开发,这在很大程度上依赖于在同一视图中查看标签、测试和错误分析。
“Operation Vacation”的描述,特斯拉自动驾驶团队通过标记和测试来收集和改进他们的数据的过程。摘自 Andrej Karpathy 的 2020 年演讲,“特斯拉全自动驾驶的人工智能”。图片作者。
对于一个新的对象检测任务,他们建立了一个图像种子集,并选择一些作为单元测试。随着产品和标签团队的迭代,他们改进他们的测试并创建新的测试。该过程的其余部分循环进行,直到测试通过。
正如 Karpathy 提到的,他的团队的北极星目标是“度假行动”——即使整个计算机视觉团队都去度假,自动驾驶任务也应该得到改善。实现该过程意味着该平台由数据模型支持,该数据模型将围绕测试、标记和模型预测的元数据联系在一起。
知识积累的复合收益
当测试用例被公式化时,它们也被标记。如果测试场景显著影响性能,可以挖掘类似的样本进行额外的标记。如果标记工具使得添加新的测试用例变得简单,那么我们就有了一个有效的扩展测试场景知识的过程。
当在大量测试场景中考虑这个过程时,这些收益是复合的。如果我们的模型曾经对光照条件敏感,我们可能会有“日光”或“一天中的时间”的概念。基于直觉,我们也可以想象,检测骑自行车的人是检测穿着特殊服装的行人的一个有用的步骤。然后,我们可以为有用的行人检测样本构建查询:
使用 Python 中的高级概念的示例查询。图片作者。
或者想象一个可视化查询组件,使上述查询的一部分更容易构建:
组合查询界面的可视点选择和代码的并排视图。图片作者。
两件事带来了复合收益:消除可用性的缝隙,花时间明确地组织知识。特斯拉自动驾驶团队通过“触发器”的概念来查询客户数据以进行标记,从而展示了这些收益。
特斯拉自动驾驶团队用来获取标签数据的触发器示例。摘自安德烈·卡帕西在 2021 年 CVPR 奥运会上的演讲。图片作者。
开发这些查询需要明确编码的领域知识。一些触发因素需要理解自动驾驶汽车开发中的概念,如雷达和视觉之间的差异或边界框的定义。其他触发器利用现实世界的概念,如刹车灯、道路和构成车顶的东西。许多人同时依赖这两种类型的概念来实现触发器。如果没有这些低级概念的定义,为这些高级概念(触发器)构建查询将是相当具有挑战性的。
知识发展平台
跨不同开发活动构建知识需要一个具有统一数据模型的平台。统一是实现领域知识复合收益的关键。
但是由于更基本的原因,建立一个平台是具有挑战性的。所需功能的广度是巨大的,并且不同用例、团队和公司的特性优先级是不同的。MLOps 的开源工具和供应商在一定程度上有所帮助,但最近的情绪指向了一种分裂的感觉。平台团队需要争论大量的工具,管理多个供应商,并长时间(有时几年)进行构建,直到他们的努力完全实现。
平台团队有时会在生产培训和部署中优先考虑大型基础设施项目,以尽量缩短上市时间。虽然这可能是一个合理的短期策略,但它有可能朝着次优的方向发展。
平台团队也可以从思考知识构建中受益。机器学习系统的最大收获往往可以追溯到对问题的更好理解。新知识是通过迭代发现的,所以一个平台的中心目标应该是端到端的效率。只有当开发引擎运行时,工作流中容易摘到的果实才是可见的。平台团队应该通过任何必要的手段来启动这个引擎,以免陷入过早优化的陷阱。这可能会排除强大的基础设施。
首先考虑框架和数据模型意味着可以适当地添加基础设施以获得最大的利用。如果性能问题的根源在于数据或模型误解,那么拥有可扩展的 GPU 计算或亚毫秒级服务延迟是行不通的。
MLOps 工具也可以发挥作用。MLOps 行业的工具构建者倾向于关注开发或部署用例的垂直部分。虽然这降低了产品起步的风险,但长期来看,用户会因为给平台团队施加集成压力而遭受损失。开销是巨大的——每个工具都有自己的语言,通过 UI、API 和数据格式来表达。
从长远来看,易于互操作并努力获得一致体验的工具为他们的客户(平台团队和他们所服务的开发人员)提供了更多的价值。整合正是平台团队必须反复做的工作,排除了有助于公司竞争优势的定制功能。如果工具构建者关心向他们的客户交付长期价值,他们必须优先考虑集成工作,而不是增量特性开发。
在可预见的未来,平台仍将难以构建。但像特斯拉这样的公司建立了世界级的人工智能,因为他们的平台使人工智能开发者能够了解他们的领域,理解他们的模型,并将他们新发现的知识编码到他们的系统中。不管我们在构建人工智能系统中的角色如何,有一点是明确的:知识构建是人工智能发展的核心。乍看起来,测试似乎不重要,但将它理解为构建知识的一流使能器表明,它对人工智能的成功开发至关重要。
觉得这些想法有趣吗?来和我们在 Twitter 上聊天吧!@ hoddieot@ skylar _ b _ Payne,或者订阅* 数据鸿沟 。*
消费者决策建模:联合分析
原文:https://towardsdatascience.com/modeling-consumer-decisions-conjoint-analysis-f4eda531ecf6
产品开发的基于选择的联合分析指南
人们花费大量时间对他们购买的一些产品和服务进行决策。事实上,最近的一项研究表明,平均每个人每年要花大约 130 个小时来决定去哪里吃饭。一般来说,消费者通过基于产品提供给他们的效用在产品的各种属性之间做出权衡来做出购买决定。作为营销人员或产品经理,了解消费者如何做出这些权衡以及每个属性提供的效用至关重要。
为了理解属性和效用的概念,让我们考虑购买新智能手机的例子。人们在决定购买时可能会考虑的因素有 RAM、存储容量、相机规格、屏幕尺寸和分辨率、品牌、价格等。这些被考虑的因素被称为属性,消费者从这些属性中的每一个得到一些效用。从每个属性中获得的效用也称为部分价值。每个消费者都是不同的,他们可以从产品的属性中获得不同的效用。例如,摄影爱好者可能会从相机规格属性中获得比 RAM 和存储容量等其他属性更多的效用。相比之下,游戏发烧友将从 RAM、存储容量和屏幕尺寸/分辨率中获得更多的效用。为了开发成功的产品,营销人员/产品经理必须了解其客户群的属性偏好,并量化客户从属性中获得的效用。联合分析是一种统计方法,用于了解属性的相对重要性/偏好,并量化消费者从产品的每个属性中获得的效用。因此,它可以用来模拟消费者在做出购买决定时可能做出的权衡。
在进行联合分析时,我们有两个基本假设:
- 消费者购买给他们最高总效用(单个属性效用的总和)的产品
- 消费者遵循补偿性决策过程。简单来说,这意味着产品的一个正面属性可以弥补一个负面属性,即客户愿意做出取舍。
市场研究设计
联合分析的第一步是设计一个市场调查研究。本研究的参与者通过分层随机抽样选出,代表产品的人口或目标受众。
让我们再次考虑购买智能手机的例子。(产品团队花费大量时间集思广益产品的属性,并经常组织焦点小组从消费者那里获得更多见解)为了简单起见,让我们假设仅有的属性是 Ram、存储、摄像头、屏幕、品牌和价格。
本研究的问卷设计如下:
问卷样本(图片由作者提供)
研究的参与者被给予多个选择集,并被提示从每个选择集中选择一个选项。(为了简单起见,我只提供了两个随机选择集。在实际的调查中,根据产品属性的数量,参与者会得到 10 到 20 个选择集。这些选择集的设计本身是一项复杂的任务,因此我在本文中不会深入探讨。这些问题以所示的方式设计,以模拟消费者将经历的实际决策过程。每个参与者对每个选项集的回答都被记录下来并进行建模处理。
统计模式
记录并处理每个参与者的响应。结果数据集的示例如下所示:
样本响应数据(图片由作者提供)
在创建模型之前,我们需要确保我们正确地编码了连续变量和分类变量。在本例中,我将把除“品牌”之外的所有属性都视为连续属性。然后我们运行一个逻辑回归,选择作为因变量,属性作为自变量。对于这个模型,将截距强制为 0 也是有用的,因为当所有的因变量都为 0 时,技术上产品的效用应该为 0。这可以在 R 中使用以下代码来完成:
model <- glm(Choice ~ 0 + Ram + Storage + Camera + Screen + Brand + Price, Data = Data, Family = Binomial)
模型结果和解释
在我们运行回归之后,我们获得每个属性的系数。这方面的一个例子如下所示:
样本系数表(图片由作者提供)
这些系数可以解释为常规逻辑回归。在这种情况下,我们使用逻辑回归建模的对数优势表示消费者从属性中获得的效用。因此,对于我们的客户来说,“RAM”每增加 1GB,平均会增加 2.1 个单位的效用。同样,“价格”每增加 1 美元,我们客户的平均效用就会减少 0.08 个单位。我们也明白,与品牌‘A’和‘B’相比,客户更看重品牌‘C’。(品牌“D”不包括在系数表中,因为它被作为系数为 0 的参考)
最后,我们可以根据产品的属性来计算产品的总效用和购买概率,如下所示:(这些结果和计算基于我创建的随机数据,而不是实际数据。这可能会使一些结果看起来不合逻辑)
具有给定属性的产品的示例计算(图片由作者提供)
有了模型的结果,我们可以测试产品属性的多个规格,并得出目标客户的总效用和购买概率。这在设计新产品投放市场时特别有用。
市场模拟
我们也可以使用这种方法来模拟市场,并估计新产品的市场份额。我们不是对市场调查研究的所有参与者的全部数据进行逻辑回归,而是对每个参与者的回答进行逻辑回归。这给出了产品的总效用和样本中每个参与者的购买概率。由于样本被选择来代表总体,因此样本的结果可以外推至整个总体,以得出估计的市场份额。更复杂的方法,如分层贝叶斯模型,也可以用来达到更有统计学意义的结果。
结论
联合分析是了解特定环境下消费者偏好的产品属性的有力方法。它可以用于设计各种产品甚至服务。从专业角度来说,我在一家快餐店用这种方法来了解顾客的食物偏好。它也常用于基于属性的定价。虽然营销决策是艺术和科学的结合,但这种方法是在设计产品或服务时消除主观性和个人偏见的有力工具。不用说,这是一个让每个营销分析师受益的方法。
用生命周期模拟客户生命周期价值
原文:https://towardsdatascience.com/modeling-customer-lifetime-value-with-lifetimes-71171a35f654
用几行代码评估客户的价值并制定积极的行动
来源: Unsplash
T**β-几何负二项分布(BG-NBD)模型是一种有影响力的描述客户行为和预测客户终身价值的概率模型(CLV)。**在本系列的上一篇文章中,我们探讨了这个模型的直觉、假设和数学推导。如果你没有看过,我建议你看一看!
正如你可能从那篇文章中推断的那样,手动编写所有这些 BG-NBD 方程并不容易。幸运的是,有一个名为 的 Python 库可以为我们完成所有繁重的工作。 寿命抽象出 BG-NBD 的内部复杂性,使我们能够专注于从模型中获得洞察力和商业价值。
这个令人敬畏的库是由 Cam-Davidson Pillon 创建的,他也是《概率编程&黑客的贝叶斯方法 》一书的作者,这是所有贝叶斯爱好者的必读之作。
这篇文章探究了寿命的来龙去脉。这是我们的议程:
- 首先,我们将看看在建模之前数据集需要的必要的表格式。
- 其次,我们将看到如何使用寿命来训练和评估 BG-NBD 模型。
- 第三,我们将理解寿命促成的各种见解和分析。
- 最后,我们将讨论几个由寿命带来的实际商业应用。
我们开始吧!
数据准备
数据转换
通常,企业在“交易”表中记录他们的交易。这样的表具有代表单个交易的行和代表交易的不同方面的列,例如涉及的客户、交易的时间戳及其值。
由生存期提供了一个示例事务表。这张表记录了 CDNow 的交易,这是一家网络时代的公司,销售 CD 和音乐产品。它包含从 1997 年 1 月 1 日至 1998 年 6 月 30 日(共 78 周)期间 2,357 名客户的 6,919 笔交易。我们将在整篇文章中使用它。下面是如何加载它:
交易
**在拟合 BG-NBD 模型之前,我们需要首先将该表重组为规范的“RFM”格式。**RFM 格式的表包含代表各个客户的行和以下列:
- 频率 **,**表示客户重复购买的次数。
- 最近度,代表客户最近一次购物的“年龄”。
- T ,代表观察期结束时客户的“年龄”。
- *monetary_value,*可选列,其中表示给定客户购买的平均值,不包括第一次购买。
作者图片
寿命提供了一个实用函数,方便了从“交易”格式到 RFM 格式的转换。
‘RFM’
我们解释 RFM 数据帧第一行的方式如下:
- 在观察期内,顾客 4 总共购买了 4 次(因此重复购买了 3 次)。
- 他第一次和最后一次购买的时间跨度是 49 周。
- 他第一次购买和观察期结束之间的时间跨度是 78 周。
- 除了第一笔交易,他的平均交易金额是 23.73 美元。
请注意,当频率、新近度和货币值列的值为零时(例如对于客户 18 ),表示客户在观察期内仅购买了一次。
校准-维持分离
将表格重新格式化为 RFM 格式时,我们还可以选择执行校准-保持分离,这与我们熟悉的训练-测试分离程序在精神上是相似的。校准-保持分离将我们的事务分成两部分,具体取决于它们是属于校准期还是*观察期。*校准期间发生的交易用于训练模型,而观察期发生的交易(交易)用于验证模型。
作者图片
在本例中,我们将校准和观察期分别设置为 52 周和 26 周。下面是我们如何使用生存期进行分割:
‘rfm_cal_holdout’
我们看到,现在每个客户都与用于模型训练的校准功能和用于模型验证的维持(观察期)功能相关联。
训练、预测和评估
适合的
在生存期中,模型拟合遵循熟悉的 scikit-learn 步骤,即实例化模型对象(可选地包括超参数设置)并将其拟合到校准(训练)数据:
就这样——两条线,我们就有了一个可用的 BG-NBD 模型!
你可能还记得从 第一篇 **开始,一个 BG-NBD 模型是由一个伽玛和一个贝塔分布组成的。**γ分布的参数 r 和 α 以及β分布的参数 a 和 b 可通过访问。拟合模型对象的概要属性:
拟合模型的参数
在下一节中,我们将从这些参数中获得一些业务见解。
通过比较模型生成的人工数据和真实数据来评估模型拟合度
“垃圾进,垃圾出”的格言适用于 BG-NBD 模型:依赖一个不合适的模型会导致灾难性的商业决策。因此,在使用我们的模型进行预测和解释之前,我们应该首先评估模型的性能。
寿命提供了几种评估我们模型的方法。第一个是比较我们的真实校准数据和从 BG-NBD 模型生成的分布中采样的人工数据之间的频率。函数plot _ period _ transactions在一行中完成:
该图显示,训练数据中的频率分布与我们拟合的模型人工生成的频率分布基本一致。这表明我们的模型很好地捕捉到了我们假设生成数据的物理过程。
做预测
拟合 BG-NBD 模型的主要目的之一是进行预测。在本节中,我们将了解如何生成预测,并随后用于进一步评估模型的性能。
当给定具有特定频率、新近度和*、*的客户时,拟合的模型对象可以生成两种类型的预测:
- 他将在未来几个时期购买的数量
- 他在观察期结束时活跃的概率。
让我们来看一个如何做到这一点的例子。首先,我们将选择一个样本客户,检查他在校准和观察期的频率、新近度和 T :
我们看到,在观察期内,客户进行了 2 + 1 = 3 笔交易(“ + 1”来自于将不包括第一笔交易的重复交易的数量转换为总交易)。
现在,让我们将这个“真实”数字与英国地质调查局-NBD 所做的预测进行比较。以下代码得出了客户在未来 26 周(观察期的长度)内将进行的交易的预期数量:
我们看到预测的事务数(0.76 个事务)低于实际的事务数(3 个事务)。
我们可以类似地预测某个客户在校准期结束/观察期开始时仍然活跃/活着的概率)。
由于顾客在观察期内确实进行了一些购买,我们完全确定他在校准期结束时是活跃的。因此,0.57 的预测概率是一个低估。
实际交易数和预测交易数的比较
在了解了如何预测一个人的交易数量后,我们可以将这个过程扩展到我们的整个客户群。然后,可以将得到的预测与真实的交易数据进行比较,以评估我们模型的准确性。
如果需要更严格的评估,这两列可以采用典型的回归指标,如 RMSE:
见解和解释
可视化最大似然伽玛和贝塔分布
一旦我们对模型的性能感到满意,我们就可以继续从中获得洞见。
一个好的起点是提取和可视化估计的伽马和贝塔参数。如前一篇文章所述,Gamma 和 Beta 分布具有重要的商业意义。伽玛分布告诉我们客户群交易率的分布,而贝塔分布反映了停用概率的分布。
以下代码显示了如何从模型中提取 Gamma 和 Beta 参数,并绘制分布图:
从该图中,我们可以看到伽马分布相对健康,大多数𝜆位于 2 附近。这意味着我们的顾客预计每周购物 2 次。
贝塔分布看起来也很健康,大部分的 p 接近 0。这意味着我们的客户不太可能很快停用。
频率/最近/未来购买矩阵
除了所描述的模型拟合评估之外,拟合的模型对象也可以用于一些解释性分析。
例如,我们可以查看它的频率/最近/未来购买矩阵。该矩阵显示了不同的频率-新近组合如何产生不同的未来购买预期数量。
频率/最近/未来购买矩阵
正如我们所看到的,我们最好的客户在右下角——这些人最近经常购物,所以我们对他们的回访抱有很高的期望。
相反,我们最不看好的客户在右上角——他们经常购买,然后就不再来了,我们已经几个月没见到他们了。他们很可能找到了另一家商店(即他们已经停用)。
频率/最近/概率存活矩阵
类似地,我们也可以产生频率/最近/概率活矩阵。这个矩阵与前一个矩阵共享相同的轴,但是现在每个单元的阴影告诉我们具有各种频率-新近组合的客户的存活概率。
频率/最近/概率存活矩阵
毫不奇怪,我们可以看到类似的模式,其中最好和最差的客户分别位于矩阵的右上角和右下角。
商业应用
使用 BG-NBD 的 CLV 估计
我们已经看到了如何使用 BG-NBD 模型来预测生存概率 p 以及下一个 k 周期的购买数量。这两个预测可以反过来用于计算下一个 k 周期的客户价值的粗略估计。该估计值可以计算如下:
这一估计依赖于以下两个简单的假设:
- 存活概率 p 在接下来的 k 周期中保持不变
- 下一个 k 周期的平均采购价值等于观察期的平均采购价值。
请注意,这些天真的假设理论基础薄弱——在现实中, p 通常会在每次购买后发生变化,未来的购买价值可能会与过去的价值相差很大。因此,得出的估计是粗略的。如果您感兴趣,还有更复杂的概率模型,如 Gamma-Gamma 模型,可以在更严格的 manner⁴中计算未来的购买价值。
这是我们如何在熊猫身上进行上述计算的:
得到的 value_10_pred 列概括了我们的客户在未来 10 周的估计价值。然后,我们可以使用这一估计来衡量我们业务的健康状况。例如,我们可以获得 value_10_pred 的汇总统计数据:
我们看到,平均而言,我们预计客户在未来 10 周内的支出约为 5.18 美元。
我们还可以绘制一个直方图:
我们看到我们的大部分客户的 value_10_pred 接近于 0。最终的平均值 5.18 美元是由一些异常值(少数具有非常高的价值 _10_pred 的客户)驱动的。在下一节中,我们将看到如何进一步利用这个结果。
主动干预
这三个新的栏目, alive_prob 、 n_transactions_10_pred 和 value_10_pred ,将我们客户以前看不到的方面具体化和量化。除了提供信息之外,这些新特性还可以用来推动具体的行动。例如,我们可以利用这些新功能有选择地主动接触不同的客户群体,以提高他们的预期 CLV 。
我们之前已经得出结论,我们的总体客户价值很大程度上归因于少数高价值客户。由于这些客户是我们的收入来源,我们希望特别关注他们。一个想法是偶尔给他们发贺电/代金券,鼓励他们继续保持忠诚。
另一个想法是联系高翻盘概率的客户(即存活概率低的客户),劝阻他们放弃我们的业务。
需求预测
正如我们之前所看到的, value_10_pred 估算了我们的客户在接下来的十个时间段内的购买量。**利用这一点的另一种方法是将该值视为客户的预测需求。**这种预测可以反过来支持我们的供应链决策(如补货或生产计划)。
警告:BG-NBD 并不是作为一个时间序列模型来设想的;它不具备时间序列功能,如季节性和趋势的会计。因此,当谈到预测时,明智的做法是不要仅仅依赖 BG-NBD 公司的预测,而是将它与 ARIMA 等时间序列模型结合起来。
结论
我们已经看到了生命周期如何让我们方便地了解我们客户群的购买行为,并从中获得强大而可行的见解。
虽然这很棒,但请记住,对寿命的估计是最大似然估计,完全是根据我们提供的数据推断出来的。
在本系列的第三篇文章中,我将向您展示实现 BG-NBD 的另一种方法,这次使用由 PyMC3 支持的贝叶斯分层建模。我们将看到这个实现提供了更多的灵活性,因为它允许我们将领域知识引入到建模步骤中。
我希望在那里见到你!
参考
[1]“计算你的顾客”的简单方法:帕累托/NBD 模型的替代方案(布鲁斯·哈迪 et。阿尔,2005 年)
【2】这个函数来自 BG-NBD 论文(资料来源【1】)的方程(10)
【3】使用 BG/NBD 模型计算 P(alive )( Bruce Hardieet。阿尔,2008)
[4]货币价值的伽玛-伽玛模型(Bruce Hardie et。阿尔,2013)
注 :所有图像、图表、表格、方程式均由本人创作,除非另有说明。
如果你对这篇文章有任何意见或者想联系我,请随时通过 LinkedIn 给我发一个联系方式。此外,如果你能通过我的推荐链接支持我成为一名中级会员,我将非常感激。作为一名会员,你可以阅读我所有关于数据科学和个人发展的文章,并可以完全访问所有媒体上的故事。
用 PyTorch 建模 DNA 序列
原文:https://towardsdatascience.com/modeling-dna-sequences-with-pytorch-de28b0a05036
适合初学者的教程
作者图片
DNA 是一个复杂的数据流。虽然它可以用一串 ACTGs 来表示,但它充满了复杂的模式和结构上的细微差别,人类很难通过查看原始的核苷酸序列来理解。近年来,利用深度学习对 DNA 数据建模取得了很大进展。
研究人员应用了卷积神经网络(CNN)、长短期记忆网络(LSTMs)、甚至变压器等方法,直接从 DNA 序列预测各种基因组测量值。这些模型特别有用,因为有了足够多的高质量训练数据,它们可以自动拾取与预测任务相关的序列模式(或基序),而不需要专家事先指定要寻找哪些模式。总的来说,人们越来越热衷于在基因组学中使用深度学习来帮助将 DNA 序列映射到它们的生物功能!
作为一名对使用计算方法解决可持续性和合成生物学挑战感兴趣的研究生,我一直在学习如何使用 PyTorch 研究 DNA 序列模式。不缺少关于如何开始使用 PyTorch 的教程,但是许多教程倾向于关注图像或语言输入数据。对于使用 DNA 作为输入,有许多伟大的项目已经开发了 PyTorch 框架来模拟各种生物现象[ 1 、 2 、 3 ],但是它们可能非常复杂,对于初学者来说很难钻研。
我在为 PyTorch 新手寻找那些也关注 DNA 数据的初学者例子时遇到了一些困难,所以我编写了一个快速教程,以防将来的 DNA 建模者发现它对入门有帮助!
教程本身可以作为一个 Jupyter 笔记本 交互式运行,或者您可以跟随本文剩余部分中的关键概念和 Github 要点摘要。
建立 PyTorch 模型来预测 DNA 序列的得分
本教程展示了 PyTorch 框架的一个示例,它可以使用原始 DNA 序列作为输入,将这些输入到神经网络模型中,并直接从序列中预测定量标记。
教程概述:
- 生成合成 DNA 数据
- 为 PyTorch 培训准备数据
- 定义 PyTorch 模型
- 定义训练循环函数
- 运行模型
- 在测试集上检查模型预测
- 可视化卷积滤波器
- 结论
它假设读者已经熟悉 ML 概念,如:
- 什么是神经网络,包括卷积神经网络(CNN)的基础知识
- 跨时代的模型训练
- 将数据分成训练/值/测试集
- 损失函数和比较列车与 val 损失曲线
它还假设对生物学概念有所了解,如:
- DNA 核苷酸
- 什么是调控基序?
- 可视化 DNA 基序
注意: 下面的方法不一定是 最优 的方法!我相信还有更好的解决方法,这只是我在学习中的尝试。但是,如果您刚刚开始使用 PyTorch,并且也在使用 DNA 序列作为输入,那么本教程可能是一个有用的例子,说明如何在 DNA 序列分析的背景下“将一些 PyTorch 管连接在一起”。
1.生成合成 DNA 数据
通常,科学家可能对预测结合分数、表达强度或转录因子结合事件的分类感兴趣。但在这里,我们将保持简单:本教程的目标是观察深度学习模型是否可以学习检测 DNA 序列中非常小、简单的模式,并对其进行适当的评分(同样,这只是一个练习任务,以说服我们自己我们实际上已经正确设置了 PyTorch 片段,以便它可以从看起来像 DNA 序列的输入中学习)。
因此,假设给定一个八聚体 DNA 序列,给它每个字母的分数如下:
- A = +20 分
- C = +17 点
- G = +14 点
- T = +11 点
对于每一个 8-mer,合计其总点数,然后取平均值。举个例子,
AAAAAAAA
会得分20.0
mean(20 + 20 + 20 + 20 + 20 + 20 + 20 + 20) = 20.0
ACAAAAAA
会得分19.625
mean(20 + 17 + 20 + 20 + 20 + 20 + 20 + 20) = 19.625
这些核苷酸的值是任意的——这里没有真正的生物学!这只是为了我们 PyTorch 练习的目的而给序列分配分数的一种方式。
然而,由于最近的许多论文使用类似 CNN 的方法来自动检测“基序”,或 DNA 中可以激活或抑制生物反应的短模式,让我们在我们的评分系统中再增加一项。为了模拟诸如影响基因表达的基序之类的东西,假设一个给定的序列,如果TAT
出现在八聚体中的任何地方,就会得到一个+10
凸起,如果其中有一个GCG
,就会得到一个-10
凸起。同样,这些图案在现实生活中没有任何意义,它们只是一种模拟简单激活或抑制效果的机制。
一个简单的八聚体 DNA 序列评分系统。图片作者。
下面是这个简单评分系统的实现:
绘制 8 聚体序列的分数分布图,我们看到它们分成 3 组:
- 带有
GCG
的序列(分数= ~5) - 没有基序的序列(得分= ~15)
- 带
TAT
的序列(分数= ~25)
八聚体分数的分布。图片作者。
我们现在的目标是训练一个模型,通过观察 DNA 序列来预测这个分数。
2.为 PyTorch 培训准备数据
为了让神经网络做出预测,你必须把你的输入作为一个数字矩阵给它。例如,为了根据图像是否包含猫来对图像进行分类,网络将图像“视为”像素值的矩阵,并学习像素的相对排列中的相关模式(例如,对应于猫耳朵或长有胡须的鼻子的模式)。
我们同样需要将我们的 DNA 序列(ACGTs 的字符串)转换成一个数字矩阵。那么我们如何假装自己的 DNA 是猫呢?
一种常见的策略是一次性编码 DNA:将每个核苷酸视为长度为 4 的向量,其中 3 个位置为 0,一个位置为 1,具体取决于核苷酸。
这种一次性编码方案有一个很好的特性,它使你的 DNA 看起来就像计算机看到的猫的照片一样!图片作者。
有了这个一次性编码方案,我们就可以准备好我们的训练集、val 集和测试集。这个quick_split
只是在 pandas 数据帧中随机选择一些指数来分割(sklearn 也有一个函数来做这个)。
注意:在真实的/非合成的任务中,根据你的预测任务,你可能需要更聪明地使用分裂策略:通常论文会根据染色体或其他基因组位置特征创建训练/测试分裂。
为 PyTorch 准备数据的一个重要步骤是使用 DataLoader 和 Dataset 对象。我花了很多时间在谷歌上搜索来找出一些东西,但这是我能够通过大量梳理文档和堆栈溢出帖子来炮制的解决方案!
简而言之,数据集将数据包装在一个对象中,该对象可以顺利地将正确格式化的 X 示例和 Y 标签提供给正在训练的模型。DataLoader 接受数据集和其他一些有关如何根据数据形成批次的详细信息,并使迭代训练步骤变得更加容易。
这些数据加载器现在可以在训练循环中使用了!
3.定义 PyTorch 模型
我感兴趣尝试的主要模型是卷积神经网络,因为这些已经被证明对从基因组数据中学习基序是有用的。但是作为比较,我包含了一个简单的线性模型。以下是一些模型定义:
注意:这些不是优化的模型,只是一些开始的东西(同样,我们只是在 DNA 环境中练习连接 PyTorch 管)。
- 线性模型试图通过简单地加权出现在每个位置的核苷酸来预测分数。
- CNN 模型使用 32 个长度为(
kernel_size
) 3 的过滤器来扫描 8-mer 序列以获得信息性的 3-mer 模式。
4.定义训练循环功能
接下来,我们需要定义训练/体能循环。我承认我在这里并不超级自信,并且花了很多时间费力地解决矩阵维度不匹配错误——可能有更好的方法来解决这个问题!但也许这样就可以了?- 耸肩 -(有反馈就给我发消息🤓)
在任何情况下,我都是这样定义函数堆栈的:
*# adds default optimizer and loss function*
run_model()
*# loops through epochs*
fit()
*# loop through batches*
train_step()
*# calc train loss for batch*
loss_batch()
val_step()
*# calc val loss for batch*
loss_batch()
5.运行模型
首先,让我们试着在我们的八聚体序列上运行一个线性模型。
在收集了 train 和 val 损失之后,让我们在一个快速的图中查看它们:
线性模型训练和验证损失曲线。图片作者。
乍一看,似乎没有学到多少东西。
接下来让我们试试 CNN,画出损耗曲线。
CNN 和线性模型的损耗曲线。图片作者。
从损失曲线可以清楚地看出,CNN 能够捕捉到数据中的一种模式,而线性模型却不能!我们来抽查几个序列,看看是怎么回事。
从上面的例子可以看出,线性模型实际上是低估了含有大量 G 的序列,而高估了含有大量 T 的序列。这可能是因为它注意到GCG
制造的序列具有异常低的分数,而TAT
制造的序列具有异常高的分数。然而,由于线性模型没有办法考虑到GCG
与GAG
的不同上下文,它只是预测具有 G 的序列应该更低。从我们的评分方案中我们知道事实并非如此:不是 G 一般都是有害的,而是特别是 GCG
是有害的。
CNN 更能适应 3-mer 基序之间的差异!它对有和没有基序的序列都有很好的预测。
6.在测试集上检查模型预测
在任何机器学习任务中,一个重要的评估步骤是检查你的模型是否能在测试集上做出好的预测,这是在训练中从未见过的。这里,我们可以使用奇偶图来可视化实际测试序列分数与模型预测分数之间的差异。
测试集序列的实际分数与预测分数的比较。图片作者。
奇偶图对于可视化模型预测单个序列的效果非常有用:在完美的模型中,它们都落在y=x
线上,这意味着模型预测正是序列的实际值。但如果它偏离了y=x
线,这意味着模型预测过高或过低。
在线性模型中,我们可以看到它可以在一定程度上预测测试集序列的趋势,但确实会被分布的高和低区域中的这些序列桶(具有基序的序列)所混淆。
然而对于 CNN 来说,它更擅长预测接近实际值的分数!这是意料之中的,因为我们的 CNN 架构使用 3-mer 核来扫描序列中有影响的基序。
但是 CNN 并不完美。我们也许可以训练它更长时间或者调整超参数,但是这里的目标不是完美——相对于实际的监管语法,这是一个非常简单的任务。相反,我认为使用 Altair 可视化库来交互式地检查模型出错的序列会很有趣:
请注意,不在对角线上的序列往往有多个基序实例!在评分函数中,如果序列至少有一个基序,我们只给它一个+/-凸起,但如果基序出现多次,决定增加多个奖励肯定是合理的。在这个例子中,我任意地只增加了至少 1 个模体出现的奖励,但是我们可以使用不同的评分函数。
无论如何,我认为这个模型注意到了多次出现并预测它们是重要的,这很酷。我想我们确实愚弄了它一点,虽然 0.95 的 R2 是相当可观的:)
7.可视化卷积滤波器
当训练 CNN 模型时,可视化第一层卷积滤波器以尝试了解更多关于模型正在学习的内容可能是有用的。对于图像数据,第一层卷积滤波器通常会学习边界、颜色或纹理等模式,这些基本的图像元素可以重新组合,以形成更复杂的特征。
在 DNA 中,卷积过滤器可以被认为类似于模体扫描仪。与用于可视化序列标志的位置权重矩阵类似,卷积过滤器就像一个显示特定 DNA 模式的矩阵,但它不是一个精确的序列,它可以保留一些关于哪些核苷酸出现在模式的哪个部分的不确定性。一些位置可能是非常确定的(例如,在位置 2 中总是有一个 A;高信息含量),而其他位置可以以大约相等的概率容纳多种核苷酸(高熵;信息量低)。
发生在神经网络隐藏层中的计算可能会变得非常复杂,并且不是每个卷积滤波器都是明显相关的模式,但是有时滤波器中的模式确实会出现,并且可以提供信息来帮助解释模型的预测。
下面是一些功能,以可视化的第一层卷积滤波器,既作为一个原始的热图,也作为一个主题标志。
好吧,也许这有点帮助,但通常人们喜欢将带有一些不确定性的序列可视化为模体标志:x 轴是模体中的位置,y 轴是每个核苷酸出现在每个位置的概率。通常,这些概率被转换成比特(也称为信息内容),以便于可视化。
为了将原始卷积滤波器转换成位置权重矩阵视觉效果,通常收集滤波器激活:沿着一个独热编码序列应用滤波器的权重,并测量滤波器激活(也称为权重与序列的匹配程度)。
对应于与给定序列紧密匹配的过滤权重矩阵将被强烈激活(产生更高的匹配分数)。通过收集产生最高激活分数的 DNA 子序列,我们可以为每个过滤器创建“高度激活序列”的位置权重矩阵,因此将卷积过滤器可视化为基序标志。
对于给定的卷积滤波器,如何收集强激活子序列并将其转换为 motif 徽标的示意图。图片作者。
从这个特定的 CNN 训练中,我们可以看到一些过滤器选择了强烈的 TAT 和 GCG 主题,但其他过滤器也专注于其他模式。
关于卷积滤波器可视化与模型可解释性的相关性存在一些争论。在具有多个卷积层的深度模型中,卷积滤波器可以在隐藏层内部以更复杂的方式重新组合,因此第一层滤波器本身可能不会提供足够的信息( Koo 和 Eddy,2019 )。这个领域的大部分已经转向注意力机制和其他可解释的方法,但是如果你好奇的把你的过滤器想象成潜在的主题,这些函数可以帮助你开始!
8.结论
本教程展示了一些基本的 PyTorch 结构,用于构建处理 DNA 序列的 CNN 模型。本演示中使用的练习任务不能反映真实的生物信号;相反,我们设计了评分方法来模拟非常短的序列中调控基序的存在,这对于我们人类来说很容易检查和验证 PyTorch 的行为符合预期。从这个小例子中,我们观察到具有滑动过滤器的基本 CNN 如何能够比仅考虑绝对核苷酸位置(没有局部上下文)的基本线性模型更好地预测我们的评分方案。
要阅读更多关于 CNN 应用于野外 DNA 的信息,请查阅以下基础论文:
- 深度绑定:阿里帕纳西等人 2015
- 深海:周与特洛扬斯卡娅 2015
- 巴塞特:凯利等人 2016
我希望其他对解决生物学问题感兴趣的新手可以发现这有助于开始使用 PyTorch 对 DNA 序列建模:)
9.脚注
脚注 1
在本教程中,CNN 模型定义使用了 1D 卷积层,因为 DNA 不是二维图像,Conv1D 足以沿着长度维度滑动,而不是上下扫描。(事实上,上下滑动过滤器并不适用于一键编码的 DNA 矩阵:将A
和C
行与G
和T
行分开是没有意义的——你需要所有 4 行来精确地表示一个 DNA 序列。)
然而,我曾经发现自己需要使用一个用 keras 构建的分析工具,并找到了一个 pytorch2keras 转换脚本。转换脚本只知道如何处理 Conv2d 层,并给出了带有 Conv1d 层的模型的错误:(
如果您遇到这种情况,以下是如何使用 Conv2D 重新格式化 CNN 定义的示例,同时确保它仍然像 Conv1D 一样扫描 DNA:
脚注 2
如果你正在做一个分类任务而不是回归任务,你可能想要使用CrossEntropyLoss
。然而,CrossEntropyLoss
期望的格式与MSELoss
略有不同——试试这个:
loss = loss_func(xb_out, yb.long().squeeze(1))
使用 PyMC3 建模营销组合
原文:https://towardsdatascience.com/modeling-marketing-mix-using-pymc3-ba18dd9e6e68
实验先验、数据标准化,并将贝叶斯建模与 Robyn(脸书的开源 MMM 包)进行比较
杰里米·贝赞格在 Unsplash 上的照片
在这篇文章中,我将贝叶斯方法应用于评估不同媒体渠道的广告支出对收入的影响的营销问题。我涵盖了贝叶斯建模的几个方面,这些方面对 MMM 从业者应该很重要:
- 因变量和自变量的标准化以及先验的选择
- 响应变量的标准化对估计效果的影响
此外,我将结果与 Robyn 框架进行了比较,遵循其方法论,使用岭回归的 MMM 建模开源包,以及用于超参数优化的无梯度优化框架。
之前关于营销组合建模和贝叶斯推理的出版物
有不少关于使用贝叶斯编程对营销组合建模的文章,涵盖了建模的不同方面,例如:
- 贝叶斯框架及其揭示数据真实参数的稳健性:具有遗留和形状效应的媒体混合建模的贝叶斯方法,媒体混合建模中的遗留和形状效应:论文综述
- 倍增 MMM: 倍增营销组合模型的 Python/STAN 实现
- 股票和饱和效应建模:通过 PyMC3 在 Python 中进行贝叶斯营销组合建模
- 贝叶斯模型的实际用法: HelloFresh
文章的结构如下
- 营销组合建模 —我简单介绍一下 MMM 背后的理论。
- Adstock/carry Effect—我介绍了几何 ad stock 函数的差异,提供了 Robyn 框架中使用的几何函数的 ano 实现
- 收益递减/饱和效应 —我涵盖了可用于收益递减建模的各种函数
- 建模 —这是本文的主要部分,我在其中探索了数据规范化对结果的影响。我使用 Robyn 团队提供的演示数据,并遵循 Robyn 的数据处理方法。最后,我将结果与 Robyn 的建模进行比较。
营销组合建模
我花在广告上的钱有一半都浪费了;问题是我不知道是哪一半(约翰·沃纳梅克)
MMM 的目标是了解销售的驱动因素,衡量所有可能影响销售的因素的影响。这些因素可分为两大类:一类是对销售只有间接影响的因素(也称为基准),如经济形势、节假日、天气、竞争;另一类是对销售有直接影响的因素(也称为营销贡献),如在不同媒体渠道(如电视、广播、在线平台或价格)上的广告支出(ad spend)以及促销。
建模器的目标是定义可能影响销售的相关组件,准备营销活动和其他(控制)变量的历史时间序列数据,并建立一个统计模型来估计每个组件对销售的影响。这通常是使用多元线性回归来完成的。
整个过程因两种营销效应而变得复杂:结转效应和收益递减效应。广告对销售的影响可能会有延续效应,也就是说,在广告之后的几天或几周内,销售会受到广告的影响。此外,由于消费者反应迟缓,广告效果可能不会立竿见影,在这种情况下,我们谈论的是滞后效应。
收益递减表明,从特定的媒体支出开始,支出和销售之间的关系不是线性的,而是达到了一个饱和点**,在这个点上,额外的广告投入不会导致销售的增加。**
MMM 面临的挑战是对每个媒体渠道的遗留和饱和效应以及基线和媒体成分进行建模,将一些约束应用于从营销角度来看有意义的建模。其中一个限制是,媒体支出对销售有积极影响,这要求线性模型估计媒体渠道的正系数。
解决这一挑战需要一个建模框架,能够根据不同的约束和先验知识优化各种参数。这可以通过使用一些通用的超参数优化框架或使用贝叶斯编程来实现。在本文中,我使用 PyMC3,一个贝叶斯框架,来建模营销组合。
库存/结转影响
我们可以使用几个 adstock 变换函数来模拟遗留效应。常用的变换是所谓的几何衰减的 adstock。然而,它有两种口味。第一个在这篇论文中描述,有三个参数需要估计:
- 广告效应的衰减率**:0<α<1,简单来说就是如果我们今天投资 100 欧元,α为 0.5,那么明天的预期效应将是 50 欧元**
- 假设媒体频道的最大效果持续时间**(以天、周为单位)**
- 峰值效应θ (0 ≤ θ ≤ L-1)的延迟,对不会立即开始的广告支出可能产生的滞后效应进行建模。
这个版本转换的实现可以在这里找到。基于该版本的其他实现,但是具有稍微不同的延迟权重计算,可以在这里的和这里的和中找到。
第二个版本更容易实现。它只有一个参数——衰变率α。Robyn 团队也在他们的框架中使用这个版本。
其中,α是衰减率,x(t)是当前广告花费,y(t-1)是时间 t-1 的累积广告效果,y(t)是时间 t 的最终广告。
python 中的实现有几行代码:
def **adstock_geometric**(x: float, alpha: float):
x_decayed = np.zeros_like(x)
x_decayed[0] = x[0] for xi in range(1, len(x_decayed)):
x_decayed[xi] = x[xi] + alpha* x_decayed[xi - 1] return x_decayed
示例:
x = np.array([1.0, 2.0, 3.0, 4.0, 5.0 , 6.0])
**adstock_geometric**(x, 0.5)#output: 1.0, 2.5, 4.25, 6.125, 8.062, 10.031
- 第 2 天的库存量为 2.5: 2.0 + 1.0 * 0.5
- 第三天的库存量为 4.25: 3.0 + 2.5 * 0.5****
- 第 4 天的库存为 6.125: 4 + 4.25 * 0.5
- ….
当应用于时间序列时,adstock 效应的结果可以在下图中看到:
作者图片
因为我们要使用 PyMC3,所以我们必须重写 no 中的几何衰减函数。
def **adstock_geometric_theano_pymc3**(x, theta):
x = tt.as_tensor_variable(x)
def adstock_geometric_recurrence_theano(index,
input_x,
decay_x,
theta):
return tt.set_subtensor(decay_x[index],
tt.sum(input_x + theta * decay_x[index - 1])) len_observed = x.shape[0] x_decayed = tt.zeros_like(x)
x_decayed = tt.set_subtensor(x_decayed[0], x[0]) output, _ = theano.scan(
fn = adstock_geometric_recurrence_theano,
sequences = [tt.arange(1, len_observed), x[1:len_observed]],
outputs_info = x_decayed,
non_sequences = theta,
n_steps = len_observed - 1
)
return output[-1]
收益递减/饱和效应
有各种函数可以用来模拟广告支出和销售之间的非线性关系,例如幂函数、负指数或逻辑。Robyn 团队使用本文中描述的 Hill 函数。
其中 α 控制曲线形状, γ 控制拐点。 α 越大,收益递减越有 S 形。 α 越小,C 形越多。下面的图展示了不同的饱和度曲线作为α和γ的函数。
作者图片
作者图片
由于饱和希尔函数是在 adstock 变换后应用的,因此在 ano 中不需要特殊处理。输入 x 已经是一个张量。
def **saturation_hill_pymc3**(x, alpha, gamma):
x_s_hill = x ** alpha / (x ** alpha + gamma ** alpha)
return x_s_hill
建模
数据
我使用由 Robyn 提供的演示数据集,并遵循相同的数据准备方法步骤,以获得相同的比较基准。为了与 Robyn 解决方案进行比较,我运行了演示。Robyn 包自带的 R 文件,用 R 写的,设置没有任何改动。
该数据集包含 208 周的收入,包括:
- 5 个媒体消费渠道:电视、网络、印刷品、facebook、搜索
- 2 个也有曝光信息(印象,点击)的媒体渠道:facebook_I,search_clicks_P
- 无支出有机媒体:时事通讯
- 控制变量:事件、节假日、竞争对手销售额(competitor_sales_B )
建模窗口为 2016 年 11 月 21 日至 2018 年 8 月 20 日的 92 周。为了使其通用,我定义了两个索引变量来引用这个时间窗口:
START_ANALYSIS_INDEX = 52
END_ANALYSIS_INDEX = 144
数据准备
我们必须应用 Robyn 中描述的两个准备步骤:
Robyn 利用 Prophet ,脸书的开源 ML 库进行时间序列预测。我们使用 Prophet 直接从响应中自动分解趋势、季节性和节假日影响,作为进一步建模的输入变量。这种能力通常会提高模型拟合度,减少残差中的自回归模式。
此外,我们可以使用 Prophet 分解将分类变量如事件转换成数值。
第二步准备:
当使用曝光变量(印象、点击、GRPs 等)而不是花费时,Robyn 在曝光和花费之间拟合了一个带有米氏门登函数的非线性模型,以建立花费-曝光关系
第二步将允许我们将曝光度转换为最终支出份额与效果份额比较的支出。
让我们先加载数据:
data = pd.read_csv("./data/data_raw_2015-11-23__2019-11-11.csv", parse_dates = ["DATE"])
data.columns = [c.lower() if c in ["DATE"] else c for c in data.columns]
data
作者图片
假日数据是 Prophet 最初附带的一个单独的文件。原始假日数据具有每日粒度,因此应该首先在每周级别上进行聚合。Robyn 在他们的演示中使用了德国假日。
holidays = pd.read_csv("./data/prophet_holidays_daily.csv", parse_dates = ["ds"])
holidays["begin_week"] = holidays["ds"].dt.to_period('W-SUN').dt.start_time
#combine same week holidays into one holiday
holidays_weekly = holidays.groupby(["begin_week", "country", "year"], as_index = False).agg({'holiday':'#'.join, 'country': 'first', 'year': 'first'}).rename(columns = {'begin_week': 'ds'})
holidays_weekly_de = holidays_weekly.query("(country == 'DE')").copy()
holidays_weekly_de
作者图片
先知分解
现在,我们准备将 Prophet 拟合到我们的数据中,包括假期,一个分类变量,并使用每年的季节性。重要的是要注意,我们将分解应用于所有可用的数据,而不是建模窗口。
prophet_data = data.rename(columns = {'revenue': 'y', 'date': 'ds'})
#add categorical into prophet
prophet_data = pd.concat([prophet_data, pd.get_dummies(prophet_data["events"], drop_first = True, prefix = "events")], axis = 1)prophet = **Prophet**(**yearly_seasonality**=True, holidays=holidays_weekly_de)
prophet.**add_regressor**(name = "events_event2")
prophet.**add_regressor**(name = "events_na")prophet.fit(prophet_data[["ds", "y", "events_event2", "events_na"]])
prophet_predict = prophet.**predict**(prophet_data[["ds", "y", "events_event2", "events_na"]])
作者图片
让我们提取季节性、趋势、假日和事件组件:
prophet_columns = [col for col in prophet_predict.columns if (col.endswith("upper") == False) & (col.endswith("lower") == False)]
**events_numeric** = prophet_predict[prophet_columns].filter(like = "events_").sum(axis = 1)final_data = data.copy()
final_data["**trend**"] = prophet_predict["trend"]
final_data["**season**"] = prophet_predict["yearly"]
final_data["**holiday**"] = prophet_predict["holidays"]
final_data["**events**"] = (events_numeric - np.min(events_numeric)).values
支出风险评估
在这一步中,我们使用米氏门登函数来估计支出-敞口的非线性关系
支出-风险函数定义如下:
作者图片
其中 Vmax 和 Km 是我们需要估计的两个参数。这两个参数稍后将被用于找到暴露-花费的反向关系。为建模窗口估计参数。
#define the function
**spend_to_exposure_menten_func =** lambda spend, V_max, K_m**: V_max * spend / (K_m + spend)**media_exposures = ["facebook_I", "search_clicks_P"]
media_spends = ["facebook_S", "search_S"]media_spend_exposure_df = pd.DataFrame()
for (media_exposure, media_spend) in zip(media_exposures, media_spends):
V_max = final_data[media_exposure].values[START_ANALYSIS_INDEX : END_ANALYSIS_INDEX].max()
K_m = V_max / 2
spend = final_data[media_spend].values[START_ANALYSIS_INDEX : END_ANALYSIS_INDEX]
exposure = final_data[media_exposure].values[START_ANALYSIS_INDEX : END_ANALYSIS_INDEX]
best_values, _ = **optimize.curve_fit**(f = spend_to_exposure_menten_func, xdata = spend, ydata = exposure, p0 = [V_max, K_m])
media_spend_exposure_df = pd.concat([media_spend_exposure_df, pd.DataFrame({'spend': [media_spend], 'exposure': [media_exposure], 'V_max': [best_values[0]], 'K_m': [best_values[1]]})]).reset_index(drop = True)
media_spend_exposure_df
作者图片
贝叶斯建模
现在我们已经准备好建模了。我们将我们的响应变量(收入)建模为加性线性回归,可以用以下等式描述:
作者图片
其中 b_0 对应于基线收入, b_m 系数对应于通过 adstock 和 saturation 函数转换的媒体变量, b_c 系数对应于控制变量,ϵ是一些噪声。所有提到的系数、噪声以及吸附和饱和函数的参数都应该由模型来估计。
在建模之前,我们必须做出的第一个决定是,我们将如何标准化我们的因变量和自变量。通过标准化独立变量,我们可以将我们的模型推广到其他数据源,因为我们可以对大多数独立变量使用相同的先验。此外,很难对非标准化数据设定先验。因此,我对独立变量应用 0–1 归一化,并对响应变量进行两种不同的归一化实验:
- 扩展 100K
- 0–1 标准化
缩放 100K
最初的收入范围是 672250–3827520,因此通过将收入扩大 100K,我得到了以下范围:6.72–38.27,这使得试验先验更容易。
首先,我定义我的输入变量:
data = final_data
**transform_variables** = ["trend", "season", "holiday", "competitor_sales_B", "events", "tv_S", "ooh_S", "print_S", "facebook_I", "search_clicks_P", "newsletter"]**delay_channels** = ["tv_S", "ooh_S", "print_S", "facebook_I", "search_clicks_P", "newsletter"]**media_channels** = ["tv_S", "ooh_S", "print_S", "facebook_I", "search_clicks_P"]**control_variables** = ["trend", "season", "holiday", "competitor_sales_B", "events"]**target** = "revenue"
然后,我使用最小最大缩放器将自变量标准化,并将因变量缩放 100K
data_transformed = data.copy()numerical_encoder_dict = {}for feature in transform_variables:
scaler = **MinMaxScaler**()
original = data[feature].values.reshape(-1, 1)
transformed = scaler.fit_transform(original)
data_transformed[feature] = transformed
numerical_encoder_dict[feature] = scalerdependent_transformation = None
original = data[target].values
data_transformed[target] = **original / 100_000**
建模部分包括几个步骤:
- 我首先通过媒体通道(延迟通道)进行迭代,并定义 adstock 和饱和度变换的先验。我试验了不同的先验,但最终我使用了那些在贝叶斯方法论文中描述的先验
- 我对所有可用数据应用 adstock 变换,以允许使用历史数据建立结转效应
- 我在由 START_ANALYSIS_INDEX 和 END_ANALYSIS_INDEX 定义的建模窗口上应用饱和度变换
- 我使用半正态分布强制延迟通道的回归系数为正
- 接下来,我遍历其余的变量,对系数的符号没有任何限制
- 我将截距的先验定义为从收入平均值开始的正态分布。我遵循罗宾的方法,将截距限制为正值。
response_mean = []
with pm.Model() as model_2:
for channel_name in **delay_channels**:
print(f"Delay Channels: Adding {channel_name}")
x = data_transformed[channel_name].values
**adstock_param** = pm.Beta(f"{channel_name}_adstock", 3, 3)
**saturation_gamma** = pm.Beta(f"{channel_name}_gamma", 2, 2)
**saturation_alpha** = pm.Gamma(f"{channel_name}_alpha", 3, 1)
x_new = **adstock_geometric_theano_pymc3**(x, adstock_param)
x_new_sliced = x_new[START_ANALYSIS_INDEX:END_ANALYSIS_INDEX]
saturation_tensor = **saturation_hill_pymc3**(x_new_sliced, saturation_alpha, saturation_gamma)
**channel_b** = pm.HalfNormal(f"{channel_name}_media_coef", sd = 3)
response_mean.append(**saturation_tensor * channel_b**)
for control_var in **control_variables**:
print(f"Control Variables: Adding {control_var}")
x = data_transformed[control_var].values[START_ANALYSIS_INDEX:END_ANALYSIS_INDEX]
**control_beta** = pm.Normal(f"{control_var}_control_coef", sd = 3)
control_x = **control_beta * x**
response_mean.append(control_x)
**intercept** = pm.Normal("intercept", np.mean(data_transformed[target].values), sd = 3)
#intercept = pm.HalfNormal("intercept", 0, sd = 3)
**sigma** = pm.HalfNormal("sigma", 4)
**likelihood** = pm.Normal("outcome", mu = **intercept + sum(response_mean)**, sd = sigma, observed = data_transformed[target].values[START_ANALYSIS_INDEX:END_ANALYSIS_INDEX])
我从以前的分布中生成样本,以检查我对以前的选择是否合理:
作者图片
并绘制先验分布:
作者图片
现在我们可以拟合模型了:
with model_2:
trace = pm.sample(1000, tune=1000, step=None, **target_accept = 0.95**, return_inferencedata=True)
trace_summary = az.summary(trace)
我将 target_accept 参数增加到 0.95,因为我得到了一些带有默认值的收敛警告。
当拟合完成时,我从后面采样数据
with model_2:
ppc_all = **pm.sample_posterior_predictive**(
trace, var_names=["outcome"] + list(trace_summary.index), random_seed=42
)
az.plot_ppc(az.from_pymc3(posterior_predictive=ppc_all, model=model_2), var_names = ["outcome"])
作者图片
观察到的数据的分布不是正态的,而是严格为正的,而我定义的可能性是正态分布的,这就是为什么我们在最低收入水平上看到不匹配。这也可能是一些收敛问题的原因,但使用标准缩放器或 PowerTransformer 并没有带来任何改善,所以我决定坚持使用更直观的标准化。
有了后验样本,我们现在可以测量拟合优度,绘制各种辅助图,如残差图,并执行收入分解和测量渠道贡献。
拟合优度
Robyn 用来测量预测误差的指标之一是归一化均方根误差( NRMSE )。
def **nrmse**(y_true, y_pred):
return np.sqrt(np.mean((y_true - y_pred) ** 2)) / (np.max(y_true) - np.min(y_true))
预测收入是后验样本的平均值乘以 100K:
y_true = data[target].values[START_ANALYSIS_INDEX:END_ANALYSIS_INDEX]#restore the original revenue by multiplying back 100K
y_pred = ppc_all["outcome"].mean(axis = 0) * 100_000print(f"RMSE: {np.sqrt(np.mean((y_true - y_pred)**2))}")
print(f"MAPE: {np.mean(np.abs((y_true - y_pred) / y_true))}")
print(f"NRMSE: {nrmse(y_true, y_pred)}")
分解
为了按渠道分解收入,我们必须使用模型估计的参数对媒体渠道应用库存和饱和度,然后乘以相应的估计系数。
模型估计的参数和系数汇总:
作者图片
我绘制了实际收入、预测的后验收入以及通过合计每个组成部分的收入贡献计算的收入,以比较分解的收入是否与预测的后验收入匹配。
作者的形象
分解收入的 NRMSE:0.058,MAPE: 0.067
最后一步是计算媒体渠道支出份额,并将其与收入份额(效果份额)进行比较
我使用原始数据计算支出份额。我找到了使用其曝光信息(facebook_I,search_clicks_P)建模的变量的花费,使用曝光与花费的关系:
**exposure_to_spend_menten_func** = lambda exposure, V_max, K_m: **exposure * K_m / (V_max - exposure)**spend_df = pd.DataFrame()
for media_channel in **media_channels**:
temp_series = data[media_channel].iloc[START_ANALYSIS_INDEX:END_ANALYSIS_INDEX].values
#exposure to spend should
if len(media_spend_exposure_df[media_spend_exposure_df.exposure == media_channel]) > 0:
**vmax** = media_spend_exposure_df[media_spend_exposure_df.exposure == media_channel]["V_max"].iloc[0]
**km** = media_spend_exposure_df[media_spend_exposure_df.exposure == media_channel]["K_m"].iloc[0]
**spends** = **exposure_to_spend_menten_func**(temp_series, V_max = vmax, K_m = km)
spends_total = spends.sum()
else:
spends_total = temp_series.sum()
spend_df = pd.concat([spend_df, pd.DataFrame({'media': [media_channel], 'total_spend': [spends_total]})]).reset_index(drop=True)spend_df["**spend_share**"] = spend_df["total_spend"] / spend_df["total_spend"].sum()
spend_df
然后,我用分解的信息找出这些变量的影响份额。
response_df = pd.DataFrame()
for media_channel in **media_channels**:
response = data_transformed_decomposed[media_channel].iloc[START_ANALYSIS_INDEX:END_ANALYSIS_INDEX].values
response_total = response.sum()
response_df = pd.concat([response_df, pd.DataFrame({'media': [media_channel], 'total_effect': [response_total]})]).reset_index(drop=True)
response_df["**effect_share**"] = response_df["total_effect"] / response_df["total_effect"].sum()response_df
最后,绘制支出份额与效果份额的对比图:
作者图片
0–1 归一化
让我们进行同样的实验,但是这次将响应变量归一化到 0 和 1 之间
dependent_transformation = **MinMaxScaler**()
original = data[target].values.reshape(-1, 1)
transformed = dependent_transformation.fit_transform(original)
data_transformed[target] = transformed
截距和系数的先验现在应根据响应范围进行调整:
response_mean = []
with pm.Model() as model_3:
for channel_name in **delay_channels**:
print(f"Delay Channels: Adding {channel_name}")
x = data_transformed[channel_name].values
adstock_param = pm.Beta(f"{channel_name}_adstock", 3, 3)
saturation_gamma = pm.Beta(f"{channel_name}_gamma", 2, 2)
saturation_alpha = pm.Gamma(f"{channel_name}_alpha", 3, 1)
x_new = adstock_geometric_theano_pymc3(x, adstock_param)
x_new_sliced = x_new[START_ANALYSIS_INDEX:END_ANALYSIS_INDEX]
saturation_tensor = saturation_hill_pymc3(x_new_sliced, saturation_alpha, saturation_gamma)
**channel_b** = pm.HalfNormal(f"{channel_name}_media_coef", sd = 0.1)
response_mean.append(saturation_tensor * channel_b)
for control_var in **control_variables**:
print(f"Control Variables: Adding {control_var}")
x = data_transformed[control_var].values[START_ANALYSIS_INDEX:END_ANALYSIS_INDEX]
**control_beta** = pm.Normal(f"{control_var}_control_coef", 0.1, sd = 0.1)
control_x = control_beta * x
response_mean.append(control_x)
**intercept** = pm.HalfNormal("intercept", 0.1)
**sigma** = pm.HalfNormal("sigma", 0.15)
**likelihood** = pm.Normal("outcome", mu = **intercept + sum(response_mean)**, sd = **sigma**, observed = data_transformed[target].values[START_ANALYSIS_INDEX:END_ANALYSIS_INDEX])
事先分配似乎是合理的:
作者图片
建模和后验预测检查与之前相同,因此让我们检查拟合优度,并绘制花费与效果份额的对比图:
NRMSE: 0.058,MAPE: 0.065
现在比较这两种模型:
作者图片
在估计的效果份额上有微小的差异,但是我可以得出结论,在估计效果份额与花费份额的相对大小上,两个模型是一致的
与罗宾的比较
Robyn 生成一组模型,并允许建模者选择与业务最相关的模型。对于几个最佳解决方案,它会生成支出份额与效果份额的对比图,并将它们保存在文件中。
在最好的模型中,我主观地挑选了一个或多或少与 PyMC3 生成的模型相当的模型:
Robyn 生成的图像
我将 Robyn 与两款 PyMC3 车型进行了比较:
作者图片
比较表明,在 PyMC3 中生成的两个模型的结果彼此更相似,而不是与 Robyn 更相似。一个可能的原因是,与 PyMC3 生成的解决方案类似的解决方案是首选,但不是首选。另一个原因可能与 Robyn 选择顶级候选人的方式有关:Robyn 使用两种方法进行多目标优化:旨在减少模型预测误差的 NRMSE 和 RSSD(分解均方根距离):
该距离说明了花费份额和渠道的系数分解份额之间的关系。如果距离太远,其结果可能太不现实——例如,花费最小的媒体活动获得最大的效果
结论
在本文中,我试验了自变量和因变量、先验和后验分布的标准化。我使用了 Robyn 提出的数据准备方法,该方法允许在真实场景中重用本文中的代码。同样,我将贝叶斯建模的结果与 Robyn 进行了比较。由于模型的最终选择与业务相关,如果没有额外的业务背景和校准,在这些实验中很难确定 Robyn 或 PyMC3 生成的模型是否更好。如果只比较 NRMSE,罗宾选择的顶级模特 NRMSE 更低,因此更适合。由于 Robyn 额外优化了与业务相关的指标,因此它很少有机会生成一个在统计上准确但从营销角度看不切实际的模型。我相信贝叶斯 MMM 解决方案还可以有进一步的改进。一些对我来说仍然开放的问题是如何改善先验参数化以解决收敛警告,以及什么样的非正态概率分布可以用于非正态分布的正响应变量。
完整的代码可以从我的 Github repo 下载
感谢阅读!