TowardsDataScience 博客中文翻译 2020(二百零六)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

使用 PySpark 进行流失预测

原文:https://towardsdatascience.com/churn-prediction-using-spark-1d8f6bd4092d?source=collection_archive---------58-----------------------

预测音乐流媒体应用的用户流失

项目概述

该项目旨在探索用户交互数据,以识别客户流失。这个问题特别关注使用 Spark 处理大型数据集。PySpark 用于清理、辩论和处理数据,并执行建模和调优以构建流失预测模型。

问题陈述

Sparkify 是一家音乐流媒体公司,和 Spotify 一样。数据集包含用户交互的日志。完整的数据集为 12 GB。我们正在处理一个 128MB 的较小数据集。使用用户日志,我们需要识别有流失倾向的客户,以便为他们提供促销。我们可以确定哪些因素是客户流失的重要指标。

探索性数据分析

该数据集包含 286,500 个用户交互的日志。它有关于用户、交互、时间戳、用户使用的设备等信息。数据的模式如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据模式

数据集快照如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据清理

我们清理数据集以删除缺少 userIdsessionId 的记录,其中 userId 为空,我们有 278,154 条记录,因为这些记录中的大部分是尚未登录或希望注册的用户。我们还将注册日期和当前时间从时间戳转换为更容易理解的日期时间格式。页面功能列出了数据集中所有可能的用户操作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用户操作

我们将客户流失定义为用户执行取消确认操作。这项服务有两种订阅级别——免费和付费。用户可以升级或降级他们的订阅级别。我们创建了一个标志来标识用户何时降级他们的帐户,以及用户是否发生了搅动。

电子设计自动化(Electronic Design Automation)

我们通过观察一些特征的分布来识别数据中的模式。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

流失用户的分布

被搅动的用户在数据集中的分布表明数据集严重不平衡。虽然这是流失分析问题的标准,但我们需要在建模过程中考虑这一点。我们需要通过欠采样来平衡我们的数据集,或者选择适当的指标来更好地考虑少数类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按订阅级别分发

我们音乐流媒体服务的免费用户比付费用户多得多。我们还应该检查给定订阅级别的用户是否有流失倾向。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按订阅级别划分的流失

我们注意到付费用户比免费用户更有可能流失。这可能是预测用户流失的一个重要因素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用户的性别

我们的男性用户比女性用户多,但数字相差不大,所以我们可以认为我们的数据集性别基本平衡。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按性别划分的用户流失

我们注意到,与女性用户相比,男性用户更容易流失。我们还可以分析组合中订阅级别的趋势。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每次收听的歌曲数量

我们发现,与付费用户相比,免费用户每次收听的歌曲要少得多。此外,没有流失的用户平均每次听的歌曲略多,尤其是付费用户。

最后,让我们看看流媒体服务上最受欢迎的艺术家。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

特征工程

由于数据集包含用户交互,我们需要在用户层面上对它们进行聚合,以构建用户档案,这将有助于识别客户流失倾向。

基于数据集中可用的特征和我们对用户行为的理解,我们创建代表用户参与度、用户简档等的特征。

我们识别用户寿命、用户性别等特征。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用户生命周期功能

我们还创建了用户参与功能,如添加的朋友数量,添加到播放列表的歌曲数量,对歌曲的褒贬。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

添加的好友数量

我们还创建了与他们的音乐收听行为相关的功能,如用户收听的歌曲数量、用户收听的艺术家数量、每次会话的歌曲数量等

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用户收听的歌曲数量

一旦我们创建了这些特征,我们就为每个用户合并它们,以创建我们将用于建模的最终数据库。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最终数据帧

接下来,我们移动到建模部分。

建模

注意:230 MB 的中型数据集用于建模部分,训练是在 IBM Watson 集群上完成的,而 EDA 是在 128 MB 的小型数据集上完成的。

在开始对数据集进行建模之前,我们需要将要素转换为数字要素,然后对要素进行缩放。是否缩放数据集取决于我们计划使用的模型。我们还将把我们的数据集分成训练验证测试集,以确保对模型性能的准确评估。我对数据集使用了 70:15:15 的分割。

现在我们已经准备好了数据集,我们将根据基线模型对其进行测试。在我们建立模型之前,我们将问题定义为一个二元分类问题,其中 0 表示用户没有流失,1 表示用户流失。此外,由于我们的数据集是不平衡的,准确性可能不是最好的衡量标准,因为我们可以预测所有值为 0,并具有高准确性,但召回率很低。因此,为了平衡这一点,我们使用 F1 作为我们的指标。

我认为虚拟分类器总是预测用户不会流失。我们也可以有一个随机预测用户流失的基线模型。我们的虚拟分类器的结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

虚拟分类器

我们尝试其他模型,如逻辑回归、随机森林分类器、线性支持向量和梯度提升树分类器。我们在训练集上拟合模型,并对验证数据集进行预测。然后我们选择最好的 F1 分数。在我们的例子中,它是随机森林分类器。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

逻辑回归度量

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

梯度增强的树分类器度量

接下来,我们调整我们的随机森林分类器模型。一旦我们有了一个最终的模型,我们就用它来对测试集进行预测,从而对模型性能进行基准测试。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最终模型的测试集结果

我们可以看看我们模型的特征重要性。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

特征重要性

我们看到 user_lifetime 对预测客户流失的影响最大。

结论

我们利用 CRISP-DM 过程研究了客户流失预测问题。这与增加商业价值的真实问题非常相似。我们可以通过战略性地实施从探索和建模中收集的见解来留住用户并增加公司收入。

对于像这样高度不平衡的数据集,准确性不是一个可靠的指标,所以我们使用 F1 分数。我们还可以尝试对数据集进行 SMOTE 过采样或随机欠采样,以平衡类。

我们可以提取其他特征,如用户使用的设备,并查看它们对客户流失预测的影响。

我们尝试在中小型数据集上进行建模练习。我们可以探索完整的 12GB 数据集。拥有更多少数民族的记录将会提高预测能力。

该项目的完整代码可以在我的 Github 上找到。

使用 Spark 进行流失预测

原文:https://towardsdatascience.com/churn-prediction-using-spark-d9c2da720bc8?source=collection_archive---------52-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

扎拉克·汗在 Unsplash 上的照片

项目描述

下面这个项目试图预测一个名为 Sparkify 的虚拟音乐流媒体服务的用户流失率。

我在 Amazon Web Services ( AWS )中使用 Spark 和一个由 3 台 m5.xlarge 机器组成的弹性 Map Reduce ( EMR )集群。一名司机和两名工人。数据集大小为 12gb,以 JSON 格式从 AWS 简单存储服务(S3)桶中读取。该文件包含用户每天使用服务时注册的活动。

至于软件库,我用过 PySpark,Python 的 Spark API。AWS EMR 版本 5.29.0。逻辑回归、随机森林、梯度提升树(GBT)分类器和朴素贝叶斯形成了 Spark 的机器学习库。来自标准数据科学 Python 堆栈的 Pandas 和 Matplotlib。

商业理解

客户流失预测是银行、保险公司、电信公司、有线电视运营商以及网飞、Hulu、Spotify 和 Apple Music 等流媒体服务的一个重要分类用例。能够预测更有可能取消其服务订阅的客户的公司可以实施更有效的客户保留策略。

根据一家领先的客户参与度分析公司的研究,客户流失每年给公司带来大约 1360 亿美元的损失。

贝恩公司所做的研究显示,增加客户保留率,仅增加**5%25%至 95% 2

在减少客户流失方面投入资源的理由是基于 Lee Resource Inc .的一项研究,该研究表明,吸引新客户的成本是保持现有客户的五倍以上! 3

数据理解

数据集总共有543705 行18 列。该模式如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据集架构

页面类别中,我们总共有 22 个唯一的条目。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

页面栏目内容

我定义了一个名为 流失 的新列,它由任何 取消确认提交降级 事件组成,作为用户已经离开服务或停止付费(免费订阅)的确认。每页的点击量分布如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每页点击量的分布

我们可以看到 NextSong 页面被大量访问,这是有意义的,因为它表明用户正在听歌。接下来,是 首页 后跟三个表示与服务交互的: 竖起大拇指添加到播放列表添加好友 。这三项表明对服务的积极体验。另一方面,我们有 滚动广告拇指向下* 和 错误 作为用户对服务的不良体验的可能指标。*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从总结中可以看出,我们面对的是一个非常不平衡的数据集。未流失(0)和流失(1)的比率为2516

总共有 225,393 名女性302,612 名男性用户,其中有 15,700 名用户没有透露他们的性别,我将其归类为(不可用)😗*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

性别栏分布

我们在计划/服务中共有 428,597 付费 用户和 115,108 用户。正如我们之前所说的,我们必须确保尽可能多地保留这些付费用户,以最大化收入(或最小化损失)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

付费用户与免费用户

数据准备

我首先着手解决的是不平衡的问题。我用了一种叫做 过采样 的技术。这是一个非常基本的方法,我利用 PySpark 的 explode dataframe 特性从代表不足的类中选择尽可能多的事件(在本例中,流失等于 1)来填充差异,直到我得到一个平衡的数据集来处理。

我读到过一些更高级的方法,但它们大多是为Pandas/Numpydata frames/sets 构建的,在我的 Spark 环境中不能很好地并行化。这肯定需要更多的时间和调查,以找到一个更强大的解决方案。我了解到的最有希望的方法是击打*,感兴趣的读者可以在这里找到更多细节。***

应用这种技术后,我扩展并平衡了数据帧,使其增加了 ~50% :

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

从总共 543,705 个条目到总共 1,086,945 个条目。这被证明是非常有用的,因为我的模型的准确性提高了,我大大减少了没有它时我所面临的过度拟合问题。尽管它并不完美,还可以进一步改进。

userAgent 提供了我构建的两个特性的一些信息,我使用了: os浏览器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

浏览器可以看到642801使用 Safari249372使用 Firefox**

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Windows 是使用较多的操作系统,其次是 MacintoshX11 (Linux)。 iPhone 是第四个更常用的,兼容可能是指安卓?

我使用了 ts (时间戳)列来构建更多的特性。从 ts 我构造了 星期几小时 列。

使用这些新的栏目,我们可以看到用户倾向于在一天结束时听更多的歌曲。用户在午饭后开始收听,下午 4-5 点达到高峰(在通勤开车期间?).

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一天中每小时播放的歌曲数量

用户在工作日也更多地听歌。周四似乎是引人注目的一天,但并不能得出什么结论。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按星期几播放的歌曲数量

我构建了以下特征:

  • saved _ Settings所有按“ userId 分组的“保存设置”页面事件的计数
  • num_songs 用户播放的’歌曲’的数量统计(按’ userId '分组)
  • 拇指向上 按“用户标识”分组的所有“拇指向上”页面事件的计数
  • num _ advertisement按“ userId ”分组的所有“滚动广告”页面事件的计数
  • thumbs_down 按“ userId ”分组的所有“ Thumbs Down 页面事件的计数
  • Playlist _ added所有按“ userId ”分组的“ Add to Playlist ”页面事件的计数
  • 好友 _ 添加 所有按“ userId ”分组的“添加好友”页面事件计数
  • errors_pages 按“ userId ”分组的所有“ Error ”页面事件的计数
  • songs _ persession用户(按’ userId’ )在给定会话( sessionId’ )上播放的平均歌曲数(按’下一首歌’页面事件分组)

我使用了 PySpark ML 特性库中的 StringIndexer、VectorAssembler 和 Normalizer。 StringIndexer 将一列标签编码成一列标签索引。 VectorAssembler 是一个转换器,它根据 ML 算法的要求,将给定的列/特征列表组合成一个向量列。最后,规格化器是一个转换器*,它转换一个数据集的向量行,规格化每个向量以具有单位规格化。它采用参数 p,该参数指定用于归一化的 p 范数。(默认情况下 p=2。)这种规范化可以帮助标准化您的输入数据,并改进学习算法的行为。***

建模

我已经在训练集和测试集中分别分割了 80–20%的数据集,以进入建模阶段。

对于建模,我使用了来自 Spark ML 库中的逻辑回归、随机森林分类器、GBT 分类器和朴素贝叶斯算法。我衡量了表现最好的人,使用 F-1 评分标准作为所有人的参数来选择最好的并进行微调。

F-1 分数对我们的流失率预测模型更有意义,因为我们对假阴性假阳性更感兴趣。第一个是因为它表明我们预测用户不会离开,不会流失。第二个表示我们预测要离开但没有离开的用户。综上所述,我并不是说真阴性*(预测离开服务的用户不会离开)也不重要!***

型号选择

我用“训练”数据集上的默认参数训练了逻辑回归*、随机森林分类器GBT 分类器朴素贝叶斯算法,并用“测试”数据集对其进行了评估。***

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

表 1 —模型结果总结

其中:

F1- F-1 得分

WP - 加权精度

WR -加权召回

最佳型号选择

表 1* 中我们可以看到性能最好的型号是 GBTClassifier 。我对这个模型进行了微调,运行了一个交叉验证,带有 5 个折叠和一个参数网格,如下所示:***

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用于模型微调的参数网格

在获得以下值之前,我使用相同的指标对模型进行了评估:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

表 2 —最佳模型参数汇总

结论

正如我们所看到的,与之前的运行相比,这个经过微调的模型的所有指标都提高了 4% ,与其他模型相比几乎提高了 10%

我们的模型预测了 46,435 名离开的用户(真正)和 58,499 名没有离开的用户(真负)。该模型还预测了 13,790 个用户离开,而没有离开(假阳性),以及 4,047 个用户没有离开(假阴性)。**

尽管我们的模型远非完美。用一个的精度只有的 77%和一个 的召回的 92%意味着我们准确地正确预测了 2/3 的流失案例。**

GBTClassifier 是我在这个项目中尝试的所有算法中最好的,也是需要更长时间训练的一个,因为它一个接一个地训练树。我在 EMR 集群的性能方面遇到了问题,必须进行一些配置才能成功地在 Spark 中训练所有这些模型。对于所有这些细节,请前往我的 GitHub 仓库。

正如我之前提到的,这个不平衡数据集的过采样/欠采样还有很大的改进空间。如果时间和预算允许,可以使用比我在这里使用的更多的超参数进行更广泛的网格搜索,以提高模型性能,但这将需要时间和预算,因为 EMR 不是免费服务。

基于机器学习的客户流失预测

原文:https://towardsdatascience.com/churn-prediction-with-machine-learning-c9124d932174?source=collection_archive---------14-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

斯科特·格雷厄姆Unsplash 上的照片

用 SVC、Logistic 回归和 XGBoost 构建流失预测模型

对任何公司来说,建立和保持忠诚的客户群都是一项挑战,尤其是当客户可以自由地从一个产品类别的众多供应商中进行选择的时候。此外,留住现有客户通常比获得新客户更划算。

因此,评估客户保持率对企业来说至关重要。重要的是,不仅要衡量客户满意度,还要衡量停止与某个公司或服务做生意的客户数量。

客户流失,也称为客户流失,是在特定时期内停止使用公司服务的客户的百分比。保持尽可能低的流失率是每个企业的追求,了解这些指标可以帮助公司及时识别潜在的客户,以防止他们离开客户群。

在本文中,我们将基于电信公司数据集构建客户流失预测模型。

关于数据

数据集由 IBM 开发者平台提供,可在这里获得。一些信息,如公司名称和私人客户数据,为了保密而保持匿名,不会影响模型的性能。

我们将处理来自 7043 个客户的数据,我们有 20 个特征,如下所示:

人口统计客户信息

  • genderSeniorCitizenPartnerDependents

每位客户已签约的服务

  • PhoneServiceMultipleLinesInternetServiceOnlineSecurityOnlineBackupDeviceProtectionTechSupportStreamingTVStreamingMovies

客户账户信息

  • tenureContractPaperlessBillingPaymentMethodMonthlyChargesTotalCharges

上个月离开的客户(这是我们的模型将要预测的特征)

  • Churn

让我们检查一下目标变量Churn的值分布。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图一。流失分布

流失率为 26.54%,我们正在处理一个不平衡的数据集。搅棒的数量明显小于非搅棒的数量。

数据准备

初步观察表明,我们正在处理 10 个分类变量、7 个二元变量和 3 个数值变量。然而,这项研究将这些分类特征中的一些视为二元的。为了说明,列StreamingTVTechSupport具有值“否”、“是”和“没有互联网服务”。在这些情况下,“没有互联网服务”将被视为“没有”。最终模型将使用 4 个分类变量、13 个二元变量和 3 个数值变量进行计数。

在继续之前,让我们检查一下数值变量中的异常值,更具体地说,是在MonthlyChargesTotalCharges中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图二。检查异常值

乍一看,数字特性一切正常。检查箱线图,没有离群值的证据。

如前所述,对初始数据集进行了调整。为了改进我们的模型,一些具有 3 个唯一值的特征被转换为二进制。解决了所有特性之后,让我们来看一个这些特性的客户流失分布的例子。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图三。流失分布

看上面的例子,我们可以解释性别可能不是模型的一个有意义的变量,因为男女客户的流失率非常相似。另一方面,有受抚养人的客户不太可能停止与公司的业务往来。

至于互联网服务,有光纤计划的客户更有可能退出。他们的流失率是 DSL 和无互联网用户的两倍多。

谈到保护服务,拥有设备保护和在线安全计划的客户更有可能维持他们的合同。

最后,合同的类型可能是模型的一个有价值的特性。请注意,逐月合约的流失率远高于一年期和两年期合约的流失率。

在建立 ML 算法之前,我们需要执行一些预处理。考虑到大多数机器学习算法在处理数字输入时效果更好,我们将使用 Scikit Learn 的LabelEncoder和 pandas 的get_dummies对数据进行预处理。以下是数据集外观的示例:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4。预处理后的数据集示例

机器学习模型

需要做的第一件事是将数据分成训练集和测试集。之后,为了管理不平衡的情况,我们将使用StardardScaler标准化训练集的特性,然后应用RandomUnderSampler,根据官方文档,这是一种“通过为目标类随机选择数据子集来平衡数据的方法”。

数据经过标准化和平衡后,将使用以下模型,我们将确定哪种模型显示的结果更好:

  • 支持向量分类器
  • 逻辑回归
  • XGBoost

为了评估这些模型的有效性,我们可以使用PrecisionRecall。精确将会给我们正确识别的比例,而回忆将会决定正确识别的比例。

考虑到我们正在努力解决的问题,Recall将更适合于这项研究,因为这里的目标是确定实际上倾向于停止与该公司做生意的客户的最大数量,即使一些“非搅动者”被错误地确定为“搅动者”。也就是说,在我们的情况下,最好是追求尽可能小的一些假阴性。

我们还使用了交叉验证来获得更好的结果。cross_validate方法不是简单地将数据分成训练集和测试集,而是将我们的训练数据分成 k折叠,从而更好地利用数据。在这种情况下,我们进行了 5 重交叉验证。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图五。回忆价值观

请注意,所有 3 个模型都提供了相似的结果,召回率约为 80%。我们现在将调整模型上的一些超参数,看看我们是否可以实现更高的召回值。这里使用的方法是GridSearchCV,它将搜索每个估计器的指定参数值。每个模型都有各种可以调整的参数,但我们只调整那些更有可能影响预测的参数(在param_grid参数中指定),而其余的可以保留默认值。

请在下面找到每个型号的调校:

支持向量分类器

param_grid = {'kernel': ['linear', 'poly', 'rbf', 'sigmoid'], 'C': [0.0001, 0.001, 0.01, 0.1, 1, 10, 100]}

最佳召回率:0.96 对于{‘C’: 0.01,’ kernel’: ‘poly’}

请注意超参数调整是多么有效。我们搜索了Ckernel的不同值,对于 C = 0.01 和内核类型“poly”,我们得到了 96%的增加的召回率。

逻辑回归

param_grid = {'solver': ['newton-cg', 'lbfgs', 'liblinear'], 'C': [0.0001, 0.001, 0.01, 0.1, 1, 10, 100]}

最佳召回率:对于{‘C’: 0.0001,’ solver’: ‘liblinear’},召回率为 0.88

转向逻辑回归,我们也实现了更好的召回,对于 C = 0.0001 和 solver =“liblinear”,召回率为 88%。

最后,让我们对 XGBoost 估计量进行一些调整。XGBoost 被认为是最有效的机器学习算法之一,因为它在分类和回归预测建模问题的结构化和表格化数据集上表现出色。它具有高度的可定制性,可以调节更大范围的参数。

XGBoost

第一步,我们将确定 XGBoost 模型中最优的树的数量,搜索n_estimators参数的值。

param_grid = {'n_estimators': range(0,1000,25)}

最佳召回率:0.82 对于{‘n_estimators’: 25}

我们已经可以检测到召回率的提高。现在我们已经确定了更好的n_estimators值,我们可以继续搜索两个相关参数max_depthmin_child_weight

param_grid = {'max_depth': range(1,8,1), 'min_child_weight': np.arange(0.0001, 0.5, 0.001)}

最佳召回率:{‘max_depth’: 1,’ min_child_weight’: 0.0001}的 0.86

在接下来的步骤中,我们将确定gamma的最佳值,这是一个用于控制模型过度拟合趋势的重要参数。

param_grid = {'gama': np.arange(0.0,20.0,0.05)}

最佳召回率:0.86 对于{‘gama’: 0.0}

最后,我们将搜索最佳的learning_rate值。

param_grid = {'learning_rate': [0.0001, 0.01, 0.1, 1]}

最佳召回率:{‘learning_rate’: 0.0001}的 0.88

在测试集上评估模型

在调整了 SVC、逻辑回归和 XGBoost 的参数之后,我们注意到所有三个模型都有所改进。在测试集上运行每个模型的调整版本,以检查它们的性能是至关重要的。

现在,让我们为这些算法中的每一个绘制一个混淆矩阵,以可视化它们在测试集上的性能。

支持向量分类器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图六。SVC 混淆矩阵

逻辑回归

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 7。逻辑回归混淆矩阵

XGBoost

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 8。XGBoost 混淆矩阵

在测试集上运行算法后,我们有一个显示,显示当我们调整一些参数时,模型的性能如何得到改善。这三个模型在调优后召回率都有所提高,其中 XGBoost 的召回率最高。

结论

该项目的目的是开发一个模型,能够尽可能有效地确定电信公司的大量客户。

能够提前识别潜在的客户,使公司能够制定策略,防止客户离开客户群。有了这些数据,公司可以提供激励措施,如折扣或忠诚度计划,或提供额外的服务,以降低流失率。

值得一提的另一点是调整超参数的重要性,调整 ML 算法以获得更好的结果。参数调整后,三个模型的召回率都有所提高。

XGBoost 已经在数据科学项目中证明了它的有效性,在这个项目中,它提供了模型中最好的结果。出于这个原因,XGBoost 算法将是我们解决这里提出的问题的选择。

完整代码请参考笔记本

基于机器学习的客户流失预测

原文:https://towardsdatascience.com/churn-prediction-with-machine-learning-ca955d52bd8c?source=collection_archive---------3-----------------------

机器学习项目的分步说明。

流失预测是机器学习领域的一个常见用例。如果你不熟悉这个术语,churn 的意思是“离开公司”。对于一个企业来说,了解客户可能流失的原因和时间是非常重要的。拥有一个强大而准确的客户流失预测模型有助于企业采取措施防止客户离开公司。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

克里斯·利维拉尼在 Unsplash 上的照片

在这个项目中,我将使用 Kaggle 上的“电信客户流失”数据集。

对于 7043 个客户,有 20 个特征(自变量)和 1 个目标(因变量)。目标变量表明客户是否在上个月离开了公司(即客户流失=是)。由于目标变量有两种状态(是/否或 1/0),这是一个二元分类问题。

这些变量是:’ customerID ‘,’ gender ‘,’ SeniorCitizen ‘,’ Partner ‘,’ Dependents ‘,’ tension ‘,’ PhoneService ‘,’ MultipleLines ‘,’ InternetService ‘,’ OnlineSecurity ‘,’ OnlineBackup ‘,’ DeviceProtection ‘,’ TechSupport ‘,’ StreamingTV ‘,’ StreamingMovies ‘,’ Contract ‘,’ PaperlessBilling ‘,’ PaymentMethod ‘,’ MonthlyCharges ‘,’ TotalCharges ‘,’ Churn '。

乍一看,只有 customerID 似乎与客户流失无关。其他变量可能会也可能不会对客户流失产生影响。我们会弄清楚的。

该项目的结构如下:

  1. 探索性数据分析
  2. 数据预处理
  3. 模型创建和评估
  4. 改进模型

1。探索性数据分析

让我们从导入所需的库开始,然后导入数据集:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline#Dataset
df = pd.read_csv("Telco-Customer-Churn.csv")
df.shape
(7043, 21)

我总是寻找缺失的值,并尝试处理它们。我们使用的数据集是预先清理过的,所以我认为没有丢失值。让我们检查一下以确保:

df.isna().sum().sum()
0

数据集中没有丢失的值,因此我们可以跳转来研究它。我们可以从目标变量开始:

df.Churn.value_counts()
No     5174
Yes    1869

目标变量具有不平衡的类分布。正类(流失=是)比负类(流失=否)少很多。不平衡的类别分布会对机器学习模型的性能产生负面影响。我们将使用上采样或下采样来克服这个问题。

在试图建立模型之前探索特征(独立变量)总是有益的。我们先来发现只有两个值的特性。

columns = df.columns
binary_cols = []for col in columns:
    if df[col].value_counts().shape[0] == 2:
        binary_cols.append(col)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

剩余的分类变量有两个以上的值(或类)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

二元分类特征

让我们检查二进制特征的类分布。

fig, axes = plt.subplots(2, 3, figsize=(12, 7), sharey=True)sns.countplot("gender", data=df, ax=axes[0,0])
sns.countplot("SeniorCitizen", data=df, ax=axes[0,1])
sns.countplot("Partner", data=df, ax=axes[0,2])
sns.countplot("Dependents", data=df, ax=axes[1,0])
sns.countplot("PhoneService", data=df, ax=axes[1,1])
sns.countplot("PaperlessBilling", data=df, ax=axes[1,2])

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

老年人和电话服务变量之间存在严重的不平衡。大多数顾客都不是老年人,同样,大多数顾客都有电话服务。

最好根据二进制特征检查目标变量(churn)如何变化。为了能够进行计算,我们需要改变目标变量的值。“是”将为 1,“否”将为 0。

churn_numeric = {'Yes':1, 'No':0}
df.Churn.replace(churn_numeric, inplace=True)

让我们看看男性和女性的流失率是否不同:

df[['gender','Churn']].groupby(['gender']).mean()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

男性和女性的平均流失率大致相同,这表明性别变量不会给模型带来有价值的预测能力。因此,我不会在机器学习模型中使用性别变量。

同样,我们可以根据流失率检查其他二元分类特征:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其他二元特征对目标变量有影响。如果你认为 2%的差异可以忽略不计,电话服务也可能被跳过。我已经决定在模型中使用这个特性。

我们还可以使用 pandas pivot_table 函数来检查特征和目标变量之间的关系。

table = pd.pivot_table(df, values='Churn', index=['gender'],
                    columns=['SeniorCitizen'], aggfunc=np.mean)
table

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其他分类特征

是时候探索其他分类特征了。我们也有连续的功能,如任期,每月收费和总费用,我将在下一部分讨论。

互联网服务

互联网服务有 6 个变量,分别是流媒体电视、流媒体电影、在线安全、在线备份、设备保护和技术支持。如果客户有互联网服务,这些变量就会发挥作用。

sns.countplot("InternetService", data=df)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

互联网服务变量在预测流失率方面无疑是重要的。如您所见,使用光纤互联网服务的客户比其他客户更容易流失,尽管使用 DSL 和光纤的客户数量没有太大差异。这家公司可能在光纤连接方面存在一些问题。然而,只根据一个变量进行假设并不是一个好方法。让我们也检查一下每月的费用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

光纤服务比 DSL 贵得多,这可能是客户流失的原因之一。

我们现在可以检查互联网服务相关变量的分布:

fig, axes = plt.subplots(2, 3, figsize=(12, 7), sharey=True)sns.countplot("StreamingTV", data=df, ax=axes[0,0])
sns.countplot("StreamingMovies", data=df, ax=axes[0,1])
sns.countplot("OnlineSecurity", data=df, ax=axes[0,2])
sns.countplot("OnlineBackup", data=df, ax=axes[1,0])
sns.countplot("DeviceProtection", data=df, ax=axes[1,1])
sns.countplot("TechSupport", data=df, ax=axes[1,2])

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

所有与互联网服务相关的功能对于它们的类别似乎具有不同的流失率,因为流失率根据拥有这些服务的客户而变化。流媒体电视和流媒体电影的区别并不大,但它们仍然可以为模式带来价值。您可以决定不包括这两个特性。

电话服务

df.PhoneService.value_counts()
Yes    6361
No      682df.MultipleLines.value_counts()
No                  3390
Yes                 2971
No phone service     682

如果客户没有电话服务,他/她就不能拥有多条线路。与 PhoneService 列相比,MultipleLines 列包含更具体的数据。所以我将不包括电话服务栏,因为我可以从多线栏了解有电话服务的人数。MultipleLines 列将 PhoneService 列向前推进了一步。

让我们看看拥有多条生产线是否会改变流失率:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

它类似于 StreamingTV 和 StreamingMovies 变量,因此在模型中利用这些变量取决于您。我会将它们包含在模型中。

合同及付款方式

plt.figure(figsize=(10,6))
sns.countplot("Contract", data=df)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如预期的那样,签订短期合同的客户更有可能流失。这清楚地解释了公司与客户建立长期关系的动机。

plt.figure(figsize=(10,6))
sns.countplot("PaymentMethod", data=df)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用电子支票支付的客户更有可能流失,这种支付方式比其他支付方式更常见。因此,如果使用电子支票支付的客户有任何其他共同之处,可以进一步调查该细分市场。

连续特征

连续功能是任期,每月收费和总费用。总费用栏中的金额与任期(月数)乘以每月费用成正比。因此没有必要在模型中包含总费用。添加不必要的特征会增加模型的复杂性。如果可能的话,最好有一个更简单的模型。复杂的模型往往会过度拟合,不能很好地推广到新的、以前看不到的观察结果。由于机器学习模型的目标是预测或解释新的观察结果,过拟合是一个至关重要的问题。

我们再来看看连续特征的分布。

fig, axes = plt.subplots(1,2, figsize=(12, 7))sns.distplot(df["tenure"], ax=axes[0])
sns.distplot(df["MonthlyCharges"], ax=axes[1])

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

任期:客户在公司呆的月数。

根据任期变量的分布,大多数客户要么是新客户,要么已经在公司呆了很长时间。我们的目标应该是找到一种方法来留住这些客户长达几个月的任期。

月度费用也有类似的趋势。低利率和高利率之间似乎有差距。

让我们来看看流失率是如何随着任期和每月费用而变化的:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

很明显,已经成为客户很长时间的人倾向于留在公司。离开公司的人的平均任期比留下来的人少 20 个月。

似乎月费对流失率也有影响。

合同和任期特征可能相互关联,因为长期合同的客户可能会在公司呆更长时间。让我们弄清楚。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如所料,合同和任期是高度相关的。拥有长期合同的客户比拥有短期合同的客户成为客户的时间更长。我认为合同对保有权特性没有什么价值,所以我不会在模型中使用合同特性。

在研究了这些变量之后,我决定不使用下面的变量,因为它们很少或根本不增加模型的信息量:

  • 客户 ID
  • 性别
  • 电话服务
  • 合同
  • 总费用
df.drop([‘customerID’,’gender’,’PhoneService’,’Contract’,’TotalCharges’], axis=1, inplace=True)

2。数据预处理

分类特征需要转换为数字,以便它们可以包含在由机器学习模型完成的计算中。我们数据集中的分类变量不是有序的(也就是说,它们没有顺序)。例如,“DSL”互联网服务并不优于“光纤”互联网服务。有序分类变量的一个例子是从 1 到 5 的评级,或者是具有类别“差”、“一般”和“好”的变量。

当我们对分类变量进行编码时,会给每个类别分配一个数字。具有较高数字的类别将被认为更重要或对模型的影响更大。因此,我们需要对变量进行编码,使每个类别由一列表示,该列中的值为 0 或 1。

我们还需要缩放连续变量。否则,具有较高值的变量将被赋予更大的重要性,这会影响模型的准确性。

from sklearn.preprocessing import LabelEncoder, OneHotEncoder
from sklearn.preprocessing import MinMaxScaler

分类变量编码:

cat_features = ['SeniorCitizen', 'Partner', 'Dependents',
'MultipleLines', 'InternetService','OnlineSecurity'      'OnlineBackup', 'DeviceProtection', 'TechSupport', 'StreamingTV',
'StreamingMovies', 'PaperlessBilling', 'PaymentMethod']X = pd.get_dummies(df, columns=cat_features, drop_first=True)

缩放连续变量:

sc = MinMaxScaler()
a = sc.fit_transform(df[['tenure']])
b = sc.fit_transform(df[['MonthlyCharges']])X['tenure'] = a
X['MonthlyCharges'] = b

让我们检查数据集的新维度:

X.shape
(7043, 26)

重采样

正如我们在开始时简要讨论的,具有不平衡类别分布的目标变量对于机器学习模型来说是不期望的。我将使用上采样,这意味着通过从类中随机选择行,用较少的样本增加类的样本数。

sns.countplot('Churn', data=df).set_title('Class Distribution Before Resampling')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

分离积极类别(流失=是)和消极类别(流失=否):

X_no = X[X.Churn == 0]
X_yes = X[X.Churn == 1]

向上采样正类:

X_yes_upsampled = X_yes.sample(n=len(X_no), replace=True, random_state=42)print(len(X_yes_upsampled))
5174

结合正反类,检查类分布:

X_upsampled = X_no.append(X_yes_upsampled).reset_index(drop=True)sns.countplot('Churn', data=X_upsampled).set_title('Class Distribution After Resampling')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3。模型创建和评估

我们需要将数据集划分为训练和测试子集,以便我们能够在新的、以前未见过的示例上测量我们的模型的性能。

from sklearn.model_selection import train_test_splitX = X_upsampled.drop(['Churn'], axis=1) #features (independent variables)y = X_upsampled['Churn'] #target (dependent variable)

将数据集划分为训练和测试子集:

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state=42)

山脊分级机

我已经决定使用脊分类器作为基础模型。然后我会尝试一款我认为性能会更好的车型。

from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import accuracy_score

创建脊线分类器对象并对其进行训练:

clf_ridge = RidgeClassifier() #create a ridge classifier object
clf_ridge.fit(X_train, y_train) #train the model

对训练集进行预测并评估:

pred = clf_ridge.predict(X_train)accuracy_score(y_train, pred)
0.7574293307562213

对测试集进行预测并评估:

pred_test = clf_ridge.predict(X_test)accuracy_score(y_test, pred_test)
0.7608695652173914

该模型在训练集和测试集上的准确率分别达到了 75%和 76%。该模型没有过度拟合,因为训练集和测试集的精度非常接近。然而,75%的准确度不是很好,所以我们将尝试使用不同的模型来获得更好的准确度。

随机森林

from sklearn.ensemble import RandomForestClassifier

创建随机林对象并训练它:

clf_forest = RandomForestClassifier(n_estimators=100, max_depth=10)clf_forest.fit(X_train, y_train)

这里需要提到两个参数。

  • n_estimators:森林中树木的数量。
  • max_depth:树的最大深度。

这些参数在模型的准确性以及防止模型过度拟合方面具有关键作用。一般来说,如果我们使用深树(max_depth 非常高),模型可能会过拟合。

对训练集进行预测并评估:

pred = clf_forest.predict(X_train)accuracy_score(y_train, pred)
0.8860835950712732

对测试集进行预测并评估:

pred_test = clf_forest.predict(X_test)accuracy_score(y_test, pred_test)
0.842512077294686

训练集的精度比测试集的精度高 4%,这表明有轻微的过度拟合。我们可以减少树在森林中的深度,因为随着树越来越深,它们会变得越来越具体,这导致不能很好地概括。但是,减少树深度也可能会降低准确性。所以我们在优化参数时需要小心。我们还可以增加森林中的树木数量,这将有助于模型更加通用,从而减少过度拟合。几乎在每个项目中,参数调整都是非常关键的部分。

另一种方法是进行交叉验证,允许使用训练集和测试集中的每个样本。

4。改进模型

GridSearchCV 提供了一种简单的参数调整方法。我们可以使用 GridSearchCV 进行交叉验证并尝试不同的参数。

from sklearn.model_selection import GridSearchCV

创建 GridSearchCV 对象:

parameters = {'n_estimators':[150,200,250,300], 'max_depth':[15,20,25]}forest = RandomForestClassifier()clf = GridSearchCV(estimator=forest, param_grid=parameters, n_jobs=-1, cv=5)

cv = 5 意味着具有 5 重交叉验证。因此数据集被分成 5 个子集。在每次迭代中,4 个子集用于训练,另一个子集用作测试集。当 5 次迭代完成时,模型使用所有样本作为训练样本和测试样本。

n_jobs 参数用于选择使用多少处理器。-1 表示使用所有处理器。

clf.fit(X, y)

让我们检查一下最佳参数和总体精度:

clf.best_params_
{'max_depth': 20, 'n_estimators': 150}clf.best_score_
0.8999806725937379

best _ score _:best _ estimator 的平均交叉验证分数。

我们已经实现了将近 90%的总体准确率。这是 best_estimator 的平均交叉验证分数。在前一个随机森林中,平均分数约为 86%(训练 88%,测试 84%)。使用 GridSearchCV,我们将模型精度提高了 4%。

我们总是可以尝试改进模型。机器学习模型的燃料是数据,因此如果我们能够收集更多的数据,对改进模型总是有帮助的。我们还可以在 GridSearchCV 中尝试更大范围的参数,因为稍微调整一个参数可能会略微增加模型。

最后,我们可以尝试更健壮或更高级的模型。请记住,在做出此类决定时,会有一个权衡。高级模型可能会提高准确性,但它们需要更多的数据和更多的计算能力。所以这归结为商业决策。

你可以从这个回购下载该项目的完整笔记本。

感谢您的阅读。如果您有任何反馈,请告诉我。

使用 PySpark 进行流失预测

原文:https://towardsdatascience.com/churn-prediction-with-pyspark-cdb7293c0850?source=collection_archive---------38-----------------------

搅动婴儿搅动器!

你不讨厌你的顾客离开吗?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

马科斯·保罗·普拉多在 Unsplash 上的照片

很难过,他们可能再也不会回来了!

正如 Flo 在的文章:中提到的,根据 《哈佛商业评论》 的说法,获得新客户比留住现有客户要贵五到二十五倍。”

你可以做点什么!

如果我告诉你,你可以预测客户流失。

在本文中,我将为您提供实用的机器学习实现,使用一个虚构的数字音乐流媒体服务来预测客户流失。

我们将讨论以下几点:

  1. 客户参与度指标的特征工程
  2. 秘方是过采样
  3. 最佳性能模型

介绍

在讨论细节之前,让我们先解释一下数据源。

该数据集来自一个名为 Sparkify 的虚拟数字音乐流媒体服务。它包含几个从网站交互日志中派生出来的潜在有趣的字段。

我们使用 Spark ,因为数据集是 12GB,我们需要分布式机器学习技术的力量来帮助我们完成繁重的工作。

在我们的例子中,客户流失被定义为 page == “取消确认”

数据的模式如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

客户参与度指标的特征工程

我们的数据集允许多种特征工程方法。我把重点放在结合使用“页面”字段和我们的时间“ts”组件来理解用户对我们网站的参与度。

页面字段是分类字段,有几个不同的值,如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 PySpark 中,从分类列创建虚拟变量一点也不简单。值得展示这些步骤:

使用 StringIndexer 将分类列转换为索引列

使用 OneHotEncoder 将索引转换为稀疏向量

这可能就足够了,因为机器学习函数的输入接受特征作为稀疏向量。然而,让我们想想我们现在所拥有的。对于每个“页面”分类值,我们在稀疏向量矩阵中有 1 和 0。

功能选择

我们希望获得一种客户参与度指标。当从用户的角度考虑这个问题时,我希望我的所有页面交互都有每日使用量以及每周和每月的平均值。此时,我不确定哪个分类值在预测客户流失方面最重要,所以我将保留所有分类值。

为了检查特定参与度指标的增长或下降是否会影响流失率,我们将在每日、7 天和 30 天平均值之间进行比较。

以下是我想要的功能列表:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后,我们将在平台上添加终身职位作为附加功能。这是一个常用的用户参与度指标。

为了获得每日、每周和每月的指标,我需要将“ts”转换为日期,并对每个功能使用某种窗口功能。

使用行提取器获取每个稀疏事件项的各个列:

日期操作:从“ts”到天数

创建每日数据框

这将为我们提供日常指标:

创建衍生指标

现在来点好玩的。我发现了一种很好的方法来遍历这个每日数据集,以获得 7d 和 30d 的平均值,并导出几个度量对的方差度量。听起来很复杂。但我预计,如果你每天听的歌曲明显低于你的 7d 平均水平,你就会变得无所事事,因此更有可能取消。

达到平均值:

获取差异指标:

在平台上添加任期

最后,我创建了一个任期指标,如下所示:

检查您的空值

我们现在已经做了许多计算。存在一种风险,即它们并不都产生值(例如除以 0)。使用这个堆栈溢出答案检查每列的空值。

这告诉我,我肯定需要填充我的数据框架:

矢量装配器

在继续之前,对于 PySpark ML 中的建模,我们需要将所有单独的度量组合回一个 SparseVector 中。我们可以使用向量组装器:

秘方是过采样

你曾经因为你的逻辑回归只预测你标签的大多数类别而沮丧过吗?

不是模特的错。它正确地预测了最可能的分类。

这是由数据集中的不平衡造成的。有许多方法可以处理不平衡的数据。特别是,如果您感兴趣的类非常小,过采样可以工作。

这是你的模型表现更好的秘方,通过训练更多的少数民族的例子。

我为万军的 Pyspark 找到了这个简洁的过采样方法:

最佳性能模型

我们测试了 3 种不同的模型:

  • 物流回收
  • 随机森林分类器
  • 梯度推进树分类器

首先,在 PySpark 中进行训练测试分割:

继续建模:

物流回归

结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

随机森林分类器

结果越来越好:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

梯度增强树分类器

结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GradientBoostingTree 分类器(CrossValidator)

这最后一个模型表现非常好。通过快速交叉验证,maxDepth=20 的结果甚至更好。由于性能问题,我无法运行完整的数据集。

以下是一小部分的结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

基准模型分析

您可以在下面找到按型号划分的所有指标的摘要。maxDepth=20 的 GBT 明显胜出。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

了解特征重要性

为了找出哪些特性是最重要的,我用下面的代码查看了我的 GBT 模型:

发现以下是预测客户流失的一些最重要的指标:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结论

在这篇文章中,我给了你一些预测客户流失的实用工具:

  1. 在我们的功能工程部门,我们创建了一个大的计算参与度指标集
  2. 我们给了你处理不平衡数据的秘密:过采样
  3. GradientBoostingTree 分类器在该数据集上表现出色

可能的改进

  1. 我处理向量的方式可能更优雅。我在努力从这些结构中获取信息。
  2. 此外,我可以使用主成分分析来降低特征维数,这将提高模型的整体执行速度。

编码时面临的困难

我在几个不同的领域遇到了困难:

  • AWS 集群的计算容量(自由层)。我想在 GBT 上运行的交叉验证无法在我的完整数据集上完成。我必须为我的特征工程的大部分定义函数,以便在较小的数据集上快速完成所有步骤
  • 超参数:由于性能问题,我一次只能测试有限数量的参数。即使在较小的数据集上
  • Datetime 计算:我花了很长时间才弄清楚如何处理 Pyspark 中的日期格式,以及随后如何添加 datatime 以得出任期指标。
  • BestModel:我花了很长时间才找到如何从 pipelin(或者 CV)选择 stages 来直接在模型上调用 BestModel 函数。
  • 载体:处理载体可能会令人困惑

我希望你喜欢这篇文章!

完整的 Github 库在这里:https://github.com/thijsessens/sparkify_churn_prediction

使用 Spark 进行客户流失预测

原文:https://towardsdatascience.com/churn-prediction-with-spark-e16d96bbf147?source=collection_archive---------45-----------------------

客户流失预测对于留住客户至关重要,也是成功的关键因素之一,因为它有助于企业在关键时刻主动向客户提供正确的优惠和折扣。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

兰迪·法特在 Unsplash 上的照片

为了 Udacity 的数据科学家 Nanodegree 的顶点项目,我试图为虚构的音乐流媒体服务 Sparkify 建立一个机器学习管道来进行流失预测。我为这个项目写的代码可以在这个资源库中找到。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由 Udacity 提供的 Sparkify 虚构徽标

Sparkify 已经收集了一个关于其平台上成千上万独立用户活动的大型数据库。作为一项不断发展的服务,Sparkify 将在未来继续产生更多的数据(当然,前提是它已经存在)。在这种情况下,Spark 被证明是一个合适的工具,因为它提供了急需的可伸缩性。

问题陈述

Sparkify 提供的大型数据集(~12GB),包含用户活动的详细信息。具体来说,每一行代表一个用户活动,包括关于用户的基本信息(用户 ID、名字、姓氏、性别、他们的订阅级别、他们是否登录过……)和关于活动性质的进一步信息(例如,活动的时间戳、他们访问的页面的名称,或者他们请求的艺术家、歌曲和歌曲长度的名称)。每个唯一用户可以在数据集中记录多个活动。

给定数据集,主要任务是清理数据(如果必要的话),执行数据探索和分析,特征提取,最后,实现机器学习模型来对搅动的用户进行分类。理想情况下,当给定用户活动列表时,解决方案模型应该能够预测他们是否是搅动者(当然,不需要查看数据集中的取消事件)。

这些模型是根据它们的 F1 分数而不是准确性进行评估的,因为在这种情况下,与平台上的用户总数相比,被搅动的用户数量很少,并且数据是不平衡的。

设置

对于这个项目,我在 IBM Watson Studio 上使用了 Python 3.7Spark 3.0.1 ,它提供了 2 个执行器:1 个 vCPU 和 4 GB RAM,以及一个驱动程序:1 个 vCPU 和 4 GB RAM,采用 Lite 计划。由于硬件容量的原因,我只处理了原始数据集(大约 12GB)的一个子集(大约 200MB)。

数据探索

子数据集包含 543705 个观察值,每个观察值代表属于 448 个唯一用户之一的活动,以及 18 个特征。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

数据模式—按作者分类的图像

页面列特别有趣,因为它包含记录的用户活动类型。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

的独特价值—作者图片

请注意,该列中没有丢失数据,NextSong 是最受欢迎的活动,这是可以理解的,因为 Sparkify 是一种音乐流媒体服务。

然而升级降级的数量相对于提交升级提交降级取消取消确认的数量,甚至是唯一用户的数量,都是巨大的。因此,我们可能会猜测升级降级是用户可以选择升级或降级其订阅的页面,而不是这样做的实际事件。

清理数据集

下一步是清理数据集。查看每列中缺失数据的数量,有两组:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每列中缺失值的数量-按作者排序的图像

  1. 当且仅当页面类型为下一首歌曲时,艺术家长度歌曲不为空(包含一些值)。
  2. 名字姓氏性别地点注册用户代理在用户未登录或未注册时缺失。事实上, userId 在这种情况下也会丢失,但是丢失的值被伪装成空字符串。然而,这些用户无法访问 Sparkify 的主要功能,因此,我们可以安全地删除所有这些观察。

定义流失

接下来,我使用取消取消确认来定义客户流失。特别地,任何具有这些事件中的至少一个的用户被认为是被搅动的用户。我还检查了这些事件实际上是同时发生的,并且有 99 个用户,大约是数据集中用户总数的 22%

可视化数据

在清理数据集和定义客户流失后,我用一些图表来回答我认为对客户流失预测和用户行为至关重要的 4 个问题。

用户参与度和用户留存之间有什么关系?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

每位用户的事件/互动总数-按作者分类的图片

我们可以看到,流失用户对服务的参与度略有下降。

在此分析中,时间戳有用吗?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

绝对是的,用户群之间的上次交互和用户生存期明显不同。我们还可以注意到,长期用户对服务更忠诚。

免费用户会取消他们的服务吗?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

不幸的是,也是的。事实上,免费用户和付费用户的取消率大致相同。

关于流失,用户活动能告诉我们什么?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

一般来说,被取消的用户竖起大拇指的少,下一首少,加入播放列表少,竖起大拇指多,滚动广告多,降级多。我们可以看到,总的来说,这些用户并没有像以前那样喜欢这项服务。

注意:记住 降级 不是实际的账户降级事件,而可能是用户可以选择降级其账户的页面。

建模

功能选择

我按照用户 Id 对数据集进行分组,并选择了我认为最相关的 13 个特性:

  • 交互总数
  • 注册时间戳
  • 上次交互时间戳
  • 用户寿命
  • 一生中的平均相互作用
  • 等级(1 表示付费,0 表示免费)
  • 竖起大拇指的百分比
  • 拇指向下的百分比
  • 回家的百分比
  • next song 的百分比
  • 添加到播放列表的百分比
  • 滚动广告的百分比
  • 降级百分比

然后,产生的数据集被分成训练和测试数据集(分别为 90%和 10%)。

建造管道

在获得训练和测试数据集后,我为两种不同的分类方法建立了三个机器学习管道:逻辑回归和随机森林。每个管道执行三个主要任务:

  • 根据 PySpark 输入模式的要求,将所选要素组装成矢量。
  • 对矢量进行标准化(缩放平均值为 0,标准偏差为 1),将所有要素放在相似的尺度上。还有其他的缩放方法;然而,标准化对异常值是最稳健的。
  • 执行网格搜索并使用 F1 分数选择最佳超参数。

网格搜索中使用的超参数如下:

对于物流回收:

  • regParam: [0.01,0.1]

对于 RandomForestClassifier :

  • maxDepth(一棵树的最大深度) : [12,30]
  • numTrees(树的总数):【20,100】

结果

最佳逻辑回归模型能够在训练数据集上达到 F1 得分 0.868 ,并且在测试数据集(F1 得分 0.912,准确度 0.917)中正确预测 36 个用户中的 33 个,其中 regParam=0.01

有了一个 maxDepth 12 和 numTrees 100 的随机森林,我能够在 train 数据集上取得更好的结果(F1 得分= 0.887 )。该模型在测试数据集上产生了相同的预测(36 个中有 33 个正确,F1 值为 0.912,准确度为 0.917)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

两种方法在测试数据集上的预测结果—作者提供的图片

但是,测试数据集上的这种性能并不意味着随机森林模型不好。仅包含 36 个用户的测试数据集根本不够大,无法用于有效地比较不同的模型。

我认为,在这种情况下,随机森林比逻辑回归更好,因为它可以对一系列数据进行分组(例如,流失用户的寿命通常在 10 亿到 30 亿’时间单位’)而逻辑回归只能根据与某个值(大于或小于该值)的比较对数据进行分类。为了用逻辑回归区分一系列数据,我们需要添加隐藏层,因此,使用深度学习。因此,我认为随机森林模型是一个更好的选择。

此外,随机森林的一个优点是,我们可以通过查看特性的重要性来了解每个特性对结果的影响:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

正如在上面的数据可视化部分中所猜测的,用户订阅级别贡献不大,而最后一次交互用户生命周期对模型的性能至关重要。因此,为了提高客户保持率,最简单和最有效的方法之一是针对最近不活跃的用户(上次互动的较低值)提供特殊优惠和折扣。这些折扣也可以在用户点击取消页面时提供。

可能的进一步改进

  • 使用 last interaction 可能不是最好的主意,因为我们可能想知道谁不喜欢 Sparkify,甚至在他们想取消之前。相反,我们可以把目标人群锁定在约会少、否决、滚动广告**、多、访问降级**页面更频繁的人群。
  • 在这个项目中,我没有使用用户听过的艺人歌曲,或者用户的地点性别。这些特性可能对更好的模型有用。

结论

总之,我通过可视化和分析探索了数据集。我还清理、转换了数据,提取了 Sparkify 上关于用户的相关特征。根据这些特征,我使用逻辑回归和随机森林建立了不同的机器学习管道,并比较了结果。最佳随机森林模型在训练数据集上达到了 0.887 的 F1 分数,并且在测试数据集中对 36 个用户中的 33 个进行了正确分类。

通过这个项目,我学会了 Spark,并能够将我的知识应用到实际问题中。我还以一个漂亮的顶点项目结束了我与 Udacity 上的数据科学家 Nanodegree 的旅程。

带有 Azure DevOps 和的 Lambda 函数的 CI/CD。网络核心

原文:https://towardsdatascience.com/ci-cd-for-lambda-functions-with-azure-devops-and-net-core-9131b36582c0?source=collection_archive---------19-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

卡尔·海尔达尔在 Unsplash 上拍摄的照片

自 AWS Lambda 功能首次发布(2014 年 11 月)以来,我们一直在挑战自己,以不同的方式思考开发。

随着时间的推移,无服务器模式越来越多地出现在具有新资源、工具和方法的软件开发中。

然而,如果没有控制,我们很容易制造一场噩梦。就像本叔叔说的:“权力越大,责任越大”。

帮助我们完成这一“责任”的方法之一是为 Lambda 函数建立 CI/CD 管道,并提取完整 ALM 的全部好处。

在这篇文章中所有这些观点的激励下,我们将创建一个管道来部署我们的 Lambda 函数。

所以,我们开始吧!😄

要求

  • Azure DevOps 帐户
  • AWS 帐户
  • C#的基础知识

AWS 帐户

我们需要创建一个编程访问用户,负责连接 AWS 和 Azure DevOps 账户。

对于测试且仅对于测试,您可以为您的用户设置此权限:

绝不、绝不、绝不授予生产中的所有访问权限。在安全性方面,越少越好:)

通过我们的 AWS 编程用户、访问密钥和秘密密钥,我们可以创建 Azure DevOps 项目。

Azure DevOps 管道

我最喜欢的 Azure DevOps 特性之一是管道。我是这种资源的忠实粉丝,因为它非常容易使用,必要时可以用来处理巨大而复杂的场景。

首先,我们将连接两个帐户:

Azure DevOps 的 AWS 工具包

这个工具包对于创建服务连接和启用我们将在管道作业中使用的 LambdaDeployFunction 任务是必要的。

您可以通过此链接安装工具

在我们的帐户上安装了工具包后,我们可以进入下一步。

将 AWS 帐户连接到 Azure DevOps

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure Devops —项目主页

并创建服务帐户:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure DevOps —服务连接

AWS 服务连接:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure DevOps —服务连接

用您的 AWS 凭据填充它,并添加一个名称:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure DevOps —服务连接

Azure DevOps 变量组

对于这个例子,一个变量组是必要的,因为我们将使用它来存储 Lambda 函数 ARN,这个链接包含创建和配置该组所需的所有信息。

厉害!现在,我们已经在 AWS 帐户中连接了 Azure DevOps 项目。让我们最终看到一点代码:D

。网络核心

您可以从这里克隆完整的源代码:

git clone [https://github.com/lbazetto/dotnet-core-aws-lambda-ci-cd-pipeline-azuredevops.git](https://github.com/lbazetto/dotnet-core-aws-lambda-ci-cd-pipeline-azuredevops.git)

由于该项目基于。Net Lambda Tools ,我们保留了推荐的文件夹结构:

.
├── awsLambdaCICDPipeline.sln
├── azure-pipelines.yml
├── src
│   └── awsLambdaCICDPipeline
│       ├── Function.cs
│       └── awsLambdaCICDPipeline.csproj
└── test
    └── awsLambdaCICDPipeline.Tests
        ├── FunctionTest.cs
        └── awsLambdaCICDPipeline.Tests.csproj

src 文件夹包含 Lambda 函数,而 test 文件夹包含单元测试。

因为这个想法关注的是进程而不是 Lambda 函数本身,所以代码非常简单,它只是接收一个字符串并执行一个 ToUpper。在单元测试中,它只是模拟上下文并调用函数:

多级管道 YAML

一切都整理好了,是时候检查本教程最重要的部分,管道。我们的渠道分为两个阶段:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure DevOps —多级管道

构建阶段

这个阶段负责构建、运行单元测试,并将工件发布到 Azure DevOps。

部署阶段

该阶段部署在第一阶段创建的 Lambda 函数。

为什么我们有两个阶段?

将我们的构建定义分成几个阶段使它更加灵活,并帮助我们为每种情况创建一些特定的规则。在这个场景中,我们可以在创建拉请求或完成拉请求时运行相同的定义。

YAML 的定义:

创建 Azure DevOps 管道

现在是创建管道的时候了:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure DevOps —管道视图

选择代码位置:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure DevOps —源代码位置

根据您的代码位置,您可能需要输入一些凭据。

我们现在可以看到 YAML 的定义了:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

azure devo PS-YAML 管道

只要保存它,您就可以在您的回购中看到管道。
重要提示:如果你的代码在 Github 上,会自动创建一个 pull 请求验证。如果没有,您可以通过分支策略进行设置。

一起测试

我们现在有:

  • 链接到 AzureDevOps 的 AWS 帐户
  • 带有λ函数和 YAML 定义的源代码

拉请求管道

当一个拉动被创建时,我们可以在 Github 上看到检查。

如果您单击 pipeline details,可能会注意到部署阶段已被跳过。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

GitHub 管道检查和 Azure DevOps 多阶段

主管道

一旦管道完成,代码被合并到 master,我们就可以看到两个阶段都已运行:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure DevOps —管道阶段

λ函数

最后,我们可以看到从 Azure DevOps 部署的 Lambda 函数:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

亚马逊 AWS Lambda 执行

就是这样!

你怎么想?你有没有用另一种方式做一些事情,或者你认为我可以改进?请告诉我:)

非常感谢您的宝贵时间!

最初发布于https://devandops . cloud/ci-CD-for-lambda-functions-with-azure-devo PS-and-net-core/

在 AWS 上构建 CICD 管道

原文:https://towardsdatascience.com/ci-cd-logical-and-practical-approach-to-build-four-step-pipeline-on-aws-3f54183068ec?source=collection_archive---------18-----------------------

DevOps — AWS CI/CD

在 20 分钟内建立一个无服务器的全自动 CICD 管道。

在本文中,我们将使用 AWS 原生工具构建一个 4 步 CI/CD 管道。为了从概念上理解 CI/CD 渠道,强烈建议重温以前的文章&持续集成【持续交付——神话、陷阱和,实用方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AWS 上的四步 CI/CD 管道

在这篇文章中,我们将集体讨论选择构建 CI/CD 渠道的工具背后的思维过程和推理。在 AWS 平台上,我们将构建一个托管在 EC2 服务器上的简单 web 应用程序,并使用所有 AWS 本地服务。简要介绍为 CI/CD 实施选择正确工具的重要性:

安全性 —任何实施的第一步都应该是安全性。总的来说,应用程序架构、硬件、网络和数据应该有助于构建安全的环境。

还记得臭名昭著的优步事件吗?黑客获得了嵌入 GitHub 软件库中的 AWS 证书,窃取了 5700 万用户和 60 万名司机的个人信息。

需要注意的一点是,每一层的安全性都很重要。

架构 —架构应该允许多个并发的实现。同时,它应该允许对应用程序进行严格的测试,以确保一次成功(FTR)。微服务架构最适合实现这些目标;然而,不同的应用程序可能有不同的适用架构,如面向服务的架构(SOA)和 Lambda 架构。最终,重点应该是实现目标。

我们将使用以下服务建立 CI/CD 管道-

源代码管理存储库: AWS 代码提交

构建: AWS 代码构建

部署: AWS 代码部署

通知: AWS SNS

托管网络服务器: EC2 AMI

CI/CD 管道: AWS 代码管道

阶段 1:源代码控制库——AWS 代码提交

AWS 代码提交是无服务器的。默认情况下,静态数据是加密的,并且为传输中的数据启用了 SSH 或 HTTPS 端点。它提供数据持久性、数据可用性、自动扩展,并且更重要的数据存储在远离计算资源的地方。同时也相当便宜。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AWS 代码提交流程

我们将在 AWS 上设置代码库,将代码从本地机器推送到代码提交库。在整篇文章中,我们将使用 AWS 地区作为所有服务的 us-east-1 (N. Virginia)。

  1. 创建存储库- 登录 AWS 管理控制台,搜索代码提交。在主页上,单击“创建存储库”。填写以下详细信息,然后单击“创建”

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们可以使用 CodeCommit 控制台、AWS CLI 或 GIT 客户端将代码推送到 CodeCommit。在本文中,我们将使用 GIT bash。如果还没有安装 GIT 客户端,请按照官方网站给出的说明进行安装。

2。克隆存储库——在 AWS 控制台中,选择页面右上角的克隆 URL,然后选择克隆 HTTPS。克隆 GIT 存储库的地址被复制到剪贴板。打开 GIT bash,键入命令 GIT clone,后面跟着前面复制的 URL。这是第一次,它将提示输入通过 GIT 连接到 AWS 的凭证。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3。将代码推送到库— 点击此处或按照截图从我的 Github 库中下载示例代码。将代码放在文件夹 DemoCICD 中。作为最佳实践,我们应该创建一个分支并将代码合并到分支,但是为了使本文简单,我们现在将代码合并到主节点。切换到当前目录,使用下面的命令添加新文件。切换到当前目录,使用下面的命令添加新文件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

添加新文件后,使用下面的命令提交更改

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在使用下面的命令将文件推送到 AWS CodeCommit 存储库

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

检查 AWS 中的存储库,应复制所有文件。Appspec.yml 包含 CodeDeploy 的设置。Buildspec.yml 包含代码构建的设置

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AWS 代码提交存储库

构建的先决条件:

EC2 实例托管应用程序并部署代码部署代理- 我们将启动 EC2 Linux 实例来托管 web 应用程序。然后我们将部署 codedeploy 代理,以便将构建工件部署到机器上。在启动实例之前,让我们创建一个 IAM 角色来分配正确的访问权限。

实例角色

1.点击此处的打开 IAM 控制台

2.从控制台仪表板中,选择角色,然后选择创建角色。

3.在“选择受信任实体的类型”下,选择 AWS 服务。在选择用例下,选择 EC2,然后选择下一步-权限。

4.搜索并选择名为 AmazonEC2RoleforAWSCodeDeploy 的策略,然后选择 Next- Tags。

5.选择下一步:复习。输入角色的名称(例如,DemoCICDEC2InstanceRole),然后选择“创建角色”。

启动 EC2 实例:

1.点击这里打开亚马逊 EC2 控制台

2.从控制台仪表板中,选择启动实例

3.在步骤 1:选择一个 Amazon 机器映像(AMI),找到 Amazon Linux 2 AMI (HVM),SSD 卷类型,然后选择 Select。

4.在“步骤 2:选择实例类型”页面上,选择 t2.micro 类型(符合自由层条件),然后选择下一步-配置实例详细信息。

5.在“步骤 3:配置实例详细信息”页面上,执行以下操作:

在自动分配公共 IP 中,选择启用。

在 IAM 角色中,选择您在前面的过程中创建的 IAM 角色(例如,DemoCICDEC2InstanceRole)。

6.展开高级详细信息,并在用户数据字段中输入将在启动安装时执行的以下脚本。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

7.点击添加存储->点击添加标签->创建一个标签,其关键字为“目的”,值为 DemoCICD”。我们将使用这些标记来标识 EC2 实例以进行部署。->配置安全组

8.在“配置安全组”下,选择分配安全组:“创建新的安全组”。安全组名称为“SG-EC2-CICD”。添加 SSH(通过 putty 访问实例)和 HTTP(访问 web 应用程序)类型的端口,并在 source 中选择“My IP”。点击“查看并启动”。下载密钥文件,然后按“启动”。

构建包— AWS 代码构建

AWS service CodeBuild 是一个完全托管的服务,它编译代码、运行测试并创建一个可以随时部署的软件包。选择这项服务的原因是

无服务器 —您不需要管理构建服务器。

可伸缩性 —它自动伸缩,可以同时处理多个构建。

经济高效的 — CodeBuild 基于“按需付费”模式,这意味着构建一个包需要按分钟付费。

安全— 构建工件使用由 AWS KMS 管理的客户专用密钥进行加密。此外,可以使用 AWS IAM 提供细粒度的访问。记住提供最低特权访问。

下一步是从 CodeCommit 中的代码构建一个包。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AWS 代码构建流程

构建项目:

在这一步中,我们将创建一个构建项目,AWS CodeBuild 将使用它来运行构建。登录 AWS 管理控制台并搜索 CodeBuild 或点击此处。选择同一个 AWS 地区(N. Virginia)。单击“创建构建”并填写以下详细信息:

项目名称: BuildCICD。根据最佳实践填写描述并创建标签。

**源下:**源提供者— AWS 代码提交,存储库— DemoCICD,引用类型—分支,分支主

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在环境下—选择托管映像,操作系统为 Amazon Linux 2,运行时—标准,映像—Amazon Linux 2–86 _ 64—标准:1.0(或适合您的使用情形),服务角色—新服务角色

在 Buildspec 下——选择一个 buildspec 文件(我们将很快对此进行讨论)

保持其他一切不变,然后单击 create build project

build spec—build spec 是 codeBuild 服务用来运行构建的命令和相关设置的集合。您可以将 buildspec.yml 文件作为源代码的一部分,或者在构建项目时输入构建命令。我们已经在代码库中上传了 buildspec.yml 文件。

它可以有不同的阶段,如安装、预构建、构建和后构建。

使用 AWS 代码部署的部署

CodeDeploy 是一个完全托管的服务,用于完全自动化软件部署。它可用于将代码部署到 AWS EC2 或本地服务器、AWS Fargate 和 AWS Lambda。优点是

完全托管服务: CodeDeploy 可随您的基础设施自动扩展,这意味着除了您正在部署的基础设施(如 EC2)之外,无需管理任何其他基础设施。CodeDeploy 可以与自动扩展组集成,以自动扩展 EC2 容量。

**蓝/绿展开:**该选项对应蓝/绿展开。应用程序的新版本与旧版本一起启动。一旦新版本经过测试并宣布就绪,CodeDeploy 就可以根据您的规范将流量从您以前的版本转移到您的新版本。

集中控制— CodeDeploy 允许您轻松启动和跟踪部署状态。它提供了详细的部署报告,您可以为更新配置推送通知。

定价— 通过 CodeDeploy 部署到 EC2 或 AWS Lambda 是免费的。对于其余的部署,它非常便宜。

在代码部署中,我们将创建一个包含要部署的软件应用程序的应用程序。我们将创建 CodeDeploy 包并将其安装到 EC2 实例中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AWS 代码部署流程

CodeDeploy 角色:在 IAM 控制台中,通过单击“选择受信任实体的类型”下的创建角色- > 来创建角色,在“选择用例”下选择 AWS 服务- >,选择“CodeDeploy - >选择“下一步:权限”AWSCodeDeployRole 托管策略已附加到角色- >选择“下一步:标记- >下一步:审阅- >输入角色的名称(CodeDeploy) - >创建角色。

在代码部署中创建应用程序

1.单击此处的打开 CodeDeploy 控制台

2.如果“应用程序”页面没有出现,请在“AWS 代码部署”菜单上选择“应用程序”。

3.选择创建应用程序。在应用程序名称中,输入 CICDDemoApplication。

4.在计算平台中,选择 EC2/内部部署。

5.选择创建应用程序。

部署组— 在部署组中,我们将定义与部署相关的设置。在显示应用程序的页面上,选择“创建部署组”。

  1. 在部署组名称中,输入 DemoCICDDeploy。
  2. 在“服务角色”中,选择您之前创建的服务角色(例如,CodeDeploy)。
  3. 在“部署类型”下,选择“就地”。
  4. 在环境配置下,选择 Amazon EC2 实例。在“关键字”字段中,输入用于标记实例的名称(例如,MyCodePipelineDemo)。
  5. 在部署配置下,选择 CodeDeployDefault.OneAtaTime。
  6. 在“负载平衡器”下,清除“启用负载平衡”。对于本文,您不需要设置负载平衡器或选择目标组。
  7. 选择创建部署组。

至此,我们已经完成了构建管道所需的所有服务的配置。现在,我们将使用上面创建的服务构建一个即插即用的 CI/CD 管道。

CI/CD 管道

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

四步 AWS CI/CD 管道

AWS 代码管道是一个完全托管的无服务器服务,有助于自动化整个软件交付版本。这是一个管道,我们可以在其中以任何顺序和任何次数调用所有其他服务,如代码构建、代码提交、手动批准、测试和部署等。它之所以适合,是因为它完全不需要服务器,采用随用随付的方式,成本模型完全安全且可配置的工作流,并且支持一个位置监控和快速软件交付。

1.登录 AWS 管理控制台,点击这里打开代码管道控制台

2.选择创建管道。将管道名称命名为“DemoCICD”。按如下所述填写详细信息:

源阶段

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

构建阶段-

提供作为 AWS 代码构建的构建提供程序,并按如下所述填写详细信息,然后单击下一步。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

部署阶段

选择 deploy provider as CodeDeploy,并像下面这样填写其余的详细信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

单击下一步并查看更改。如果一切正常,那么点击创建管道。这将首次启动管道。如果一切都设置正确,它应该会成功。现在,这是持续部署。如果您提交任何更改,管道将自动触发。因为我们已经创建了一个 web 服务器,所以您可以尝试使用 EC2 实例公共 IP 访问网站。

产品升级和技术支持服务-手动批准:

让我们创建一个新步骤来添加手动批准。为此,请单击管道页面上的编辑。我们将在构建阶段后添加批准。为此,在构建阶段后单击+添加阶段。命名为“生产-签署”。在“生产-签署”下,单击“添加行动组”。我已经创建了一个 SNS 主题来发送电子邮件给我审批。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

单击完成。这样,我们成功地添加了一个手动批准阶段。为了自动触发完整的管道,我们只需在本地修改 index.html,然后进行代码提交。我已经添加了一个重定向到我在 index.html 的媒体简介。这将自动启动管道。你的收件箱里一定有一封批准它的邮件。一旦完成应用程序将被部署,你可以使用 EC2 实例公共地址访问网站。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

部署前的电子邮件批准

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结论:

我们已经成功建立了一个 4 步 CI/CD 管道。记住舞台布置应该仔细考虑。如果你喜欢这篇文章,请告诉我,并关注我的下一篇文章。

免责声明——本文中的观点仅代表作者个人,并不代表作者所属任何组织的观点。

通过 Azure DevOps 为数据科学项目提供 CI/CD 管道。

原文:https://towardsdatascience.com/ci-cd-pipeline-with-azure-devops-for-data-science-project-f263586c266e?source=collection_archive---------18-----------------------

CI/CD 管道实施,或数据科学的持续集成/持续部署。

在本文中,我将展示如何使用 Azure DevOps 为机器学习项目构建持续集成和持续交付管道。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

CI/CD 管道

首先,我们来定义一下 CI/CD。正如 Wiki 所说,“CI/CD 通过在应用程序的构建、测试和部署中实施自动化,在开发和运营活动以及团队之间架起了一座桥梁。现代的 DevOps 实践涉及软件应用程序在其整个开发生命周期中的持续开发、持续测试、持续集成、持续部署和持续监控。 CI/CD 实践或 CI/CD 管道构成了现代开发运营的支柱。”

好,让我们分别找出 CI 和 CD。

持续集成 是一种编码哲学和一套实践,驱动开发团队实现小的变更,并频繁地将代码签入版本控制库。因为大多数现代应用程序需要在不同的平台和工具上开发代码,所以团队需要一种机制来集成和验证它的更改。

连续交货 在连续积分结束的地方拾取。CD 自动向选定的基础架构环境交付应用程序。大多数团队使用除生产环境之外的多种环境,例如开发和测试环境,CD 确保有一种自动的方式将代码变更推给他们。

那么,它为什么重要呢?机器学习应用程序在我们的行业中变得越来越流行,但是,与更传统的软件(如 web 服务或移动应用程序)相比,开发、部署和持续改进它们的过程更加复杂。

好,让我们试着为我的项目建立一个简单的管道。该项目是关于以下 Azure 服务的预测分析:Azure SQL,Azure 数据工厂,Azure 存储帐户 V2,Azure 数据砖。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

解决方案架构

这个解决方案包括三个步骤。第一步—运行 data ADF 数据流以从 SQL DB 获取数据,转换并从表中选择几个列格式,然后将这些结果保存到 Azure Data Lake 中的 Stage 文件夹。第二步—使用关于存储帐户的指定参数从 ADF 运行 Azure Databriks notebook,以准备历史数据集并运行训练模型。在这一步,我们可以使用 MLflow rack 实验来记录和比较参数和结果。最后一步——从 ADF 运行 Azure Databriks notebook,并使用关于存储帐户的指定参数对我们的模型进行评分,并将结果保存到 Azure Data Lake。

为了启动这个项目,我需要在 Azure 门户网站中创建 3 个资源组。这些资源组将负责不同的环境—开发、试运行和生产。在这些环境中,我创建了以下服务——Azure SQL、Azure Data Factory、Azure 存储帐户 V2、Azure Data Bricks 和 Azure Key Vault。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure 资源组和服务

在所有 Azure SQL 中,我上传了两个表——历史数据和分数数据。这个数据的描述你可以通过这个 链接 找到。在 Azure 存储帐户中,我创建了一个包含三个文件夹的容器——RawData、PreprocData 和 Results。下一步是在 Azure 密钥库中创建秘密。我需要一个 Azure 存储帐户的秘密,在那里我为我的 Azure SQL DB 使用了访问密钥和连接字符串。重要的是,要从 Azure Data Factory 访问您的秘密,您需要在 Azure 存储帐户的访问策略中进行一些配置

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

访问策略配置

正如你所看到的,我添加了一个带有适当的 Azure 数据工厂服务和 Azure 数据块的访问策略,这是我早期创建的,允许获取一个秘密。

下一步是配置 Azure 数据块。为了引用 Azure Key Vault 中存储的秘密,我创建了一个由 Azure Key Vault 支持的秘密范围。要创建它,请转到https://<databricks-instance>#secrets/createScope。此 URL 区分大小写;createScope中的作用域必须大写,并填写下表:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建 Azure 密钥库支持的秘密范围

Azure Databricks 配置的下一步是—将我的笔记本连接到 Azure DevOps 存储库。要做到这一点,只需打开你的笔记本,按下同步,并填写关于你的 Azure DevOps 存储库的信息表单。这样,您可以将笔记本中的更新提交到存储库中。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure Databricks 笔记本连接到 Azure DevOps 存储库。

Azure 服务的基本配置已经完成,让我们开始在 Azure 数据工厂中创建管道。第一步是将 ADF 连接到 Azure DevOps 存储库。我可以通过两种方式连接它——在服务创建期间和在 ADF 配置中。我只需要为开发环境配置这个连接。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure 数据工厂连接到 Azure DevOps 存储库。

好了,现在我们可以选择我们想要发展管道的分支。下一步——创建所有 Azure 服务的链接服务。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

列表链接的服务

为了创建 Azure Databricks 链接服务,我填写了下一个表单:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure Databricks 链接服务配置

为了创建 Azure SQL DB 链接服务,我填写了下一个表单:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure SQL 链接服务配置

为了创建 Azure 存储帐户关联服务,我填写了下一个表单:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure 存储帐户链接服务配置

为了创建 Azure Key Vault 链接服务,我填写了下一个表单:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

为了创建 Azure Key Vault 链接服务,我填写了下一个表单:

为了控制不同环境之间的链接服务名称,我在 ADF 中使用了全局参数,创建了三个参数— dev、stg、prd。

让我们创建一个管道:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ADF 管道

我的管道的第一步是数据流:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ADF 数据流

在这个数据流中,我从 Azure SQL DB 获取数据,转换数据格式,从表中选择一些列,并将结果上传到 Azure Data Lake 的适当文件夹中。此流程是为历史记录和分数(新数据)表创建的。

管道的下一步是运行 data_preparation_model_train 和 score_new_data 脚本。为此,我们需要:

  1. 选择合适的链接服务
  2. 选择笔记本的目的地
  3. 添加带有存储名称的参数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

配置 Azure Databricks 笔记本从 ADF 运行

与 score_new_data 脚本相同。

这是我的 ADF 管道的所有阶段,接下来的步骤是验证,创建 pull 请求以将我的分支与 master 连接,然后将所有更新从 ADF 发布到 master 分支。结果是:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Azure DevOps 存储库结构

让我们开始在 Azure DevOps 中配置 CI/CD。

第一步——创建新的发布管道(在 Azure DevOps 门户中,导航至“管道”->“发布”并点击新管道)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建新的发布渠道(步骤 1)

选择显示各种预配置模板的模板窗口。在数据工厂的情况下,选择是创建一个空作业,并将其命名为**—**ADF-devo PS 2020-CICD:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建新的发布渠道(步骤 2)

创建一个新的阶段“登台”(测试环境):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

空白释放管道

现在我们已经创建了一个空白的发布管道。下一步是创建任务将使用的变量组和变量。为此,我们需要导航到 Pipelines -> Library 并创建一个新的变量组。在新表单中填写下一个信息,然后克隆它,为生产阶段创建相同的信息。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

变量组创建

结果,我得到了两个变量组。稍后我将被映射到相应的阶段。

下一步—创建发布管道变量。由于变量组值的继承,变量将包含与环境无关的值。因此,变量值将被调整到使用它的阶段。为了创建它,返回到管道- >释放,然后打开标签变量。我创建了下一个变量:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

管道变量

是时候创建和配置开发阶段了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

配置开发阶段。

这些行动将创造一个发展阶段。每次我们更新我们的master分支时,它都会触发持续交付管道,将更新后的 ARM 模板交付给其他环境,如试运行和生产。我们还可以自动完成创建触发器的过程:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

连续部署触发器

现在是时候配置试运行或测试阶段了。是时候为这个阶段创建几个任务了。对于我的第一个管道,我创建了两个工作——在 Azure Data Factory 中部署管道和将 Python 笔记本复制到 Azure Databricks。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

测试阶段的工作

让我们更详细地了解任务臂模板部署。我想描述的主要内容是-

  • 在资源组字段中填入一个变量:$(resourceGroup)
  • 选择模板位置:“链接工件”
  • 选择 ARM 模板和模板参数文件

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

ARM 模板和模板参数文件位置

  • 用先前创建的变量覆盖默认模板参数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

模板参数

在结果中,我们得到了下一种形式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

部署 ADF 任务

我的下一个任务是部署笔记本电脑。让我们更详细地了解一下。我们需要填充:

  1. 我要将 Azure Databricks 中的笔记本复制到的文件夹。app id,我之前创建的。(如何创建— 链接 )。)
  2. 相同的应用程序 id
  3. 订阅 id
  4. 租户 id

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

复制数据块笔记本任务

因此,我在这个阶段有两个任务:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我还需要制作阶段。点击克隆暂存环境到生产:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

克隆测试阶段

生产阶段是通过克隆一个阶段创建的,没有额外的调整或添加。这是因为底层作业是由变量配置的,这些变量包含指向所有外部引用的指针,如资源组、密钥库、存储帐户。此外,对于此阶段,建议创建“预部署”批准。因此,当分段部署结束时,执行流将等待分配的批准者的操作。我可以通过电子邮件通知或使用 DevOps 门户 UI 直接做出反应。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

配置“预部署”批准

所有配置的最后一步是将变量组映射到阶段。这一步对于将特定于阶段的变量值映射到特定阶段是必要的。例如,如果流水线在生产阶段处理作业,则变量$(环境)具有值“prd ”,并且如果作业在暂存阶段被触发,则将该值设置为“stg”。要使它打开标签变量->变量组并点击“链接变量组”。将变量组“生产”映射到阶段“生产”,并选择范围“阶段生产”而不是“发布”,然后对“阶段”重复相同的操作。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将变量组映射到阶段

是时候运行并检查这个简单的管道了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建并运行发布

结果,我在 Stage and Production Resource 组的适当服务上找到了 ADF pipeline 和 Azure Databricks 笔记本。我还可以分析每个阶段所有任务的细节,例如:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在测试阶段分析部署 ADG 任务

为了使这个管道更加完整,我还可以在测试阶段添加一些测试任务。例如,这些测试可以运行 ADF 管道并分析其结果 Azure Data Lake 中的一个又一个副本表、MLflow 日志以及得分后表中的结果。通过所有这些测试后,我们可以批准生产阶段。

在这个故事中,我将一步一步地详细说明如何创建和配置发布管道,以在 Azure 数据工厂环境中实现 CI/CD 实践。它显示了 Azure DevOps、Azure Data Factory、Azure SQL DB、Azure Data Lake 和 Azure Databricks 在一起使用时可能带来的限制和可能性。

感谢阅读。

有用的链接:

圆形线段:2D 的多维数据

原文:https://towardsdatascience.com/circle-segments-high-dimensional-data-on-2d-de67380db55f?source=collection_archive---------52-----------------------

数据可视化

用 python 中的“matplotlib”实现高维数据的圆段数据可视化

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

雷内·伯默的照片

可视化数据有助于更好地理解探索性数据分析。数据的频率、相关性和比例很容易解释。这些统计数据在决定机器学习方法时也起着重要的作用。尤其是理解变量之间的关系。因此,散点图是了解特定位置上一个或多个变量的分布或关系的最常用技术之一。散点图的挑战是可视化高维数据。人类可理解的维度最多只能是 x、y 和 z 三个。这意味着我们只能在同一个图中将三个变量可视化为点。此外,解释 3D 图比 2D 图更难。因此,我们可以尝试将颜色、形状和大小作为其他维度添加到 2D 图中。然而,这个问题的另一个解决方案是散点图矩阵。散点图矩阵是一种用每对变量创建 2D 散点图并在矩阵结构上显示它们的方法。由于这一点,我们可以在同一视图中看到所有散点图。

还有另一种在 2D 上可视化高维数据的选择,称为“圆段,由 Ankerst,m .等人在 2001 年提出[1]。在这篇文章中,我将解释;什么是圆段可视化,如何在 matplotlib 上应用。我们将看到以下部分:

  • 什么是圆段可视化
  • 圆分段算法如何工作
  • “matplotlib”在圆线段中的应用

什么是圆段可视化

众所周知,颜色是可视化的主要组成部分之一。它可用于可视化另一个维度的数据,而无需向绘图添加任何轴。圆段可视化技术主要依赖于颜色。它基本上将圆分割成变量(维度)的数量。从第一次观察到最后一次观察,每个切片都将变量值表示为像素。算法根据观察值给每个像素分配颜色。比如说;我们将变量的最高值设置为蓝色,最低值设置为红色。假设 X 变量的值从第一次观察到最后一次观察增加,Y 变量的值从第一次观察到最后一次观察减少。因此,片 X 中像素的颜色将从蓝色开始,并在片的末端变成红色,而片 Y 中的颜色将从红色开始,并在末端变成蓝色。另外,我们可以添加更多的切片(变量)并在 2D 图上进行比较。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们将在本文中创建一个圆形部分可视化输出的例子(作者可视化)

圆分段算法如何工作

圆形片段可视化技术处理停留在切片下的像素。因此,如果有更多的观察,视觉将有更多的像素。变量切片下的像素根据该变量的值进行处理。但是,定义显示像素着色的方向也很重要。在比较不同的切片时,方向起着重要的作用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

圆段着色方案(由 Ankerst,m .等人于 2001 年创建[1])

上图显示了如何用圆形线段技术给像素着色。第一次观察从圆心开始,最后一次观察在圆的边界结束。这种方法已在研究中提出[1]。但是,当有太多的数据点时,可能很难跟踪每个像素来了解变量之间的相关性。因此,在另一项研究[2]中,切片边界之间的线条被着色,而不是像素。这种方法在切片边界之间画线,并根据值给它们着色。在本文中,我们将按照第二种方法创建圆段可视化。

“matplotlib”在圆线段中的应用

matplotlib ”中没有任何自动创建圆段可视化的方法。因此,我们将在本节中从头开始创建一个关于“ matplotlib 的算法。开始之前,请确保您的系统中安装了“ matplotlib ”。我们将使用 葡萄酒质量 数据集,您也可以从 Kaggle 下载。

如前所述,我们将在切片边界之间绘制线条,而不是像素。这种方法更容易理解。因此,我们需要定义在可视化中将使用多少个变量,以便决定在圆中有多少个切片。为此,我们需要完成以下步骤:

  • 导入所需的包
  • 读取数据文件并删除丢失的值
  • 选择将在可视化上显示的变量
  • 获取观察值和变量的数量
  • 获取变量名(为了显示附近的切片)

完成这一步后,我们知道将使用多少个切片(#26 处的“var”)以及将在切片中绘制多少条平行线(#23 处的“r”)。现在,我们可以创建一个方法,在每个切片和坐标之间绘制直线,这些坐标在切片内彼此平行,以表示变量中的每个值。我们还可以找到变量名的坐标,以便显示哪个切片属于哪个变量。

“切片”方法采用两个参数作为“ num 和“半径”。“ num 代表一个圆将有多少个切片,“半径代表将画多少条线。因此,“半径”将等于观测值的数量,“ num 将等于变量的数量。该方法返回 3 个数组,分别为“”、“”和“标签点”。“点”是将在切片之间绘制的线的坐标,“线”是每个切片中代表每个值的线的坐标,“ labelPoints ”是用于定位变量名的坐标。

我们还需要再创建两个方法。其中一个用于计算变量的单个值应该使用哪种颜色,另一个用于通过使用第一种方法从变量创建 RGB 数据。这个过程也称为线性颜色插值。" matplotlib "有自己的颜色插值方法,但它不符合我们可视化算法的要求。这就是为什么,我们将从头开始创建它。

方法“ colorFader ”采用三种颜色作为十六进制格式。第一种颜色代表最低值,第二种代表中间值,第三种代表变量中的最高值。它的作用是取 0 到 1 之间的单个值,并将其转换为 RGB 代码。例如,如果一个变量的值为 1,那么 RGB 将等于最高值的颜色。如果它是 0.75,RGB 颜色将是混合中间色和最高色的颜色

方法“发生器”取四个自变量为“ df ”、“”、“”、“”。" df "是 Pandas 数据框,包括所有变量和其他自变量颜色代码(十六进制字符串类型),用于最低、中间和最高值。最重要的部分是,我们需要通过使用最小-最大归一化方法来归一化 0 和 1 之间的每个变量。因为“ colorFader ”将颜色分配给 0 到 1 之间的值。标准化后,它会转换数据框中的每个值,以获得它们的 RGB 代码。

好吧!现在,我们所有的方法都准备好创建圆段可视化。我们需要做的就是将这些方法应用于我们的数据,并通过使用“ matplotlib ”在极坐标系统上绘制/着色线条。您可以执行以下代码来创建绘图。

运行上面的代码后,您应该会看到下面的画面。根据数据大小,渲染视觉效果可能需要一些时间。蓝色代表最高值,绿色代表中间值,红色代表最低值。例如,挥发性酸度的值从最高值开始到中间值,而总二氧化硫的值从中间值开始到最高值。这意味着当挥发性酸度增加时,总二氧化硫减少。因此,我们可以说挥发性酸和总二氧化硫之间存在负相关关系。我们还可以通过详细考虑颜色模式来检查其他变量。你也可以添加更多的变量和改变颜色。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结论

在这篇文章中,我们学习了如何使用圆段可视化技术来可视化 2D 空间上的高维数据。我们讨论了什么是圆段可视化技术,它的算法是如何工作的,以及如何用" matplotlib "应用该算法。正如你从技术输出中看到的,通过使用颜色插值,我们可以很容易地比较不同的变量。虽然,技术允许我们增加数量变量。由于这一点,我们可以在同一个绘图中检查更多的变量。

如果你有任何问题,请随时提问。希望有帮助…

参考

[1]安克斯特,米哈伊尔&凯米,丹尼尔&克里格尔,汉斯-彼得。(1996).圆形线段:一种可视化探索大型多维数据集的技术。第一次出版。见:可视化’ 96,热门话题会议,旧金山,加州,1996 年 11 月。

[2] 林春平,王绍林,谭国生,Navarro,Jain,2010,使用圆段可视化技术进行神经网络特征选择和分析,神经计算,73,第 613–621 页。

循环队列或环形缓冲区

原文:https://towardsdatascience.com/circular-queue-or-ring-buffer-92c7b0193326?source=collection_archive---------3-----------------------

Python 和 C 实现。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

介绍

循环队列有许多不同的实现方式,它们都可能更适合特定的应用。这篇博文旨在帮助理解循环队列的工作原理及其用途和优点。

环形队列

队列是一种简单的数据结构,它实现了 FIFO(先进先出)排序。这仅仅意味着添加到队列中的第一个项目是第一个出来的。就像在熟食店排队一样,第一个排队的顾客是最先被服务的。一个循环队列本质上是一个具有最大大小或容量的队列,它将继续以循环运动的方式返回自身。

应用程序

当数据流的输入和输出以不同的速率发生时,环形缓冲区是常用的数据结构。

  • 缓冲数据流
  • 计算机控制的交通信号系统
  • 内存管理
  • CPU 调度

优势

循环队列提供了一种快速、干净的方式来存储最大大小的 FIFO 数据。

  • 不使用动态内存→没有内存泄漏
  • 节省内存,因为我们只存储我们的容量(相反,如果输入超过输出,队列可能会继续增长。)
  • 简单实施→易于信任和测试
  • 从不需要重新组织/复制数据
  • 所有操作都发生在常数时间 O(1)中

不足之处

循环队列只能存储预先确定的最大数量的元素。

  • 必须事先知道最大尺寸

它是如何工作的?(数组实现)

循环队列中有两个主要操作:

1: **入队(项目)😗*将项目添加到队列中。

if Queue.isfull()
    print "Queue is Full"
else 
    increase tail by 1
    Queue[tail] = item
    size++

2: Dequeue() :返回行前(头)的项,并将其移除。

if Queue.isEmpty()
    print "Queue is Empty"
else 
    tmp = Queue[head]
    increase head by 1
    size--
    return tmp

注意 :我们实际上并没有从数组中移除任何东西,我们只是增加了 来指向下一个“in line”项目。

让我们看看这些操作在大小为 6 的数组上是如何进行的:

  • 请注意当我们将第七个项目(35)排队时,如何绕回零。
  • 注意是如何随着我们出列而增加的,但是没有值从数组中移除,它们只是在 Enqueue()到达数组中的那个位置时被覆盖。

模运算符

如果我们应该将数组中的增加 1 个点,那么当我们到达末尾时,如何将它设置回零,以确保我们继续遍历数组?

我们可以这样做:

if (head + 1) = capacity 
    head = 0
else 
    head = head + 1

这真的没有错,但是,有一个更好的方法使用模操作符。模运算符 (%) 给出除法后的余数。在看两个整数 ab 的关系时;a 将是 b 乘以某个整数 q 加上某个整数 r : 的乘积

a = b x q + r
    q : quotient = a div b
    r : remainder = a mod b

让我们看一些简单的例子:

a = b x q + r                    a % b = r
5 = 3 x 1 + 2                    5 % 3 = 2
2 = 5 x 0 + 2                    2 % 5 = 2
9 = 3 x 3 + 0                    9 % 3 = 0
9 = 2 X 4 + 1                    9 % 2 = 1

注:这是欧几里德算法确定 GCD 的基础。

让我们将它应用于我们的循环队列实现:

self.head = (self.head + 1) % self.capacity
  • 现在,每当我们到达数组的末尾时,我们将自动从零开始。漂亮!让我们看看大小为 6 的循环队列会是什么样子:
0 % 6 = 0
1 % 6 = 1
2 % 6 = 2
3 % 6 = 3
4 % 6 = 4
5 % 6 = 5
6 % 6 = 0
...

Python 实现

这是一个简单的实现,其中我们只有两个主要方法,Enqueue(item)、Dequeue()和 display()方法,我认为这有助于理解。许多其他实现也可能包括:

  • isFull():如果队列已满,则为 true,否则为 false。
  • isEmpty():如果队列为空,则为 true,否则为 false。
  • peek():查看队列最前面的内容,而不“删除”它。
  • 等等…

许多其他实现不会存储当前大小,而是通过简单地比较头部和尾部来确定 isFull()和 isEmpty()。我认为存储大小可以更容易地跟踪正在发生的事情。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

实施情况

您可以看到 C 实现与 Python 实现非常相似,只是增加了有趣的 C 元素,如结构和内存分配。这里我们还需要一个 create_queue()函数,因为我们使用了 structs。我们还使用了一些我们之前讨论过的辅助函数,比如 isFull()、isEmpty()等…

思考者

  • 有哪些边界情况?
  • 我们在做什么假设?
  • 我们如何实现循环队列来动态改变容量呢?这将如何影响循环队列的优点和缺点?
  • 如果队列已满,这两种实现都不允许您将新项目加入队列。你能想到循环队列的一些应用程序中这可能是不好的吗?我们如何改变实现以允许重写?

结论

我鼓励阅读这篇文章的人看看 web 上的其他实现,比较它们,并思考循环队列的不同应用。我自己还是个学生,还有很多东西要学。然而,我希望这可能对第一次学习循环队列的人有所帮助。感谢阅读!

Python 中的分类和阈值处理

原文:https://towardsdatascience.com/clahe-and-thresholding-in-python-3bf690303e40?source=collection_archive---------5-----------------------

Python 中使用 OpenCV 的对比度受限的自适应直方图均衡化和阈值化

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由菲利普·莱昂Unsplash 上拍摄

介绍

在本文中,我们来谈谈直方图均衡化和图像阈值。直方图均衡化是我们用于图像预处理的工具之一,它使图像阈值化或分割任务变得更容易。

我们需要直方图均衡化的原因是,当我们收集褪色的图像或低对比度的图像时,我们可以拉伸直方图以跨越整个范围。

让我们看一个例子,图像是用电子显微镜采集的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

测试图像

在上面的图像中,我们可以看到分离,但它并不清楚。因此,让我们看看直方图,并使用均衡来拉伸直方图,以设定阈值。

import cv2
import numpy as np
from matplotlib import pyplot as plt img = cv2.imread("test.jpg", 0)
equ = cv2.equalizeHist(img)

首先,我将我的图像读取为灰度,并将其赋给变量img。为了执行直方图均衡化,我们可以运行cv2.equalizeHist(img)

让我们看看测试图像的直方图。你可以看到它向右侧倾斜。

plt.hist(img.flat, bins=100, range=(0, 255))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

均衡前

让我们看看均衡图像的直方图。你可以看到直方图一直延伸到 255。

plt.hist(equ.flat, bins=100, range=(0, 255))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

均衡后

下面是直方图均衡化图像的结果,

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

均衡图像

正如你所看到的,上面的图像中有很多噪声,因为它考虑了图像的全局对比度,而不仅仅是局部对比度。因此,执行全局均衡可能无法很好地处理您的图像,在这种情况下,我们可以使用自适应直方图均衡或称为 CLAHE(对比度限制自适应直方图均衡)

对比度限制自适应直方图均衡化(CLAHE)

对比度受限的 AHE ( CLAHE )是自适应直方图均衡化的变体,其中对比度放大是受限的,以便减少噪声放大的问题。简而言之,CLAHE 以高精度和对比度限制在小块或小块中进行直方图均衡化。

现在我们知道了 CLAHE 是什么,让我们看看如何设置它。

clahe = cv2.createCLAHE(clipLimit =2.0, tileGridSize=(8,8))
cl_img = clahe.apply(img)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

CLAHE 图像

正如你从上面的图片中看到的,CLAHE 给出了比普通均衡图像更好的结果。但它仍然有很多噪声,让我们看看如何阈值工作,以获得更好的结果。

为了获得更好的图像效果,使用 **.tiff** 文件格式,而不是 **.jpeg** 文件格式

在开始阈值处理之前,我们需要看看 CLAHE 图像的直方图。

plt.hist(cl_img.flat, bins=100, range=(100, 255))

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

CLAHE 图像直方图

从上面的直方图可以看出,在 160–200 之间有一个倾角,我们可以确定一个接近的数字来分隔这两个峰值。在我们决定一个接近的数字后,我们可以用它来做阈值(我选择了 190)

ret, thresh1 = cv2.threshold(cl_img, 190, 150, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(cl_img, 190, 255, cv2.THRESH_BINARY_INV)

忽略第一个参数ret,我们可以得到阈值图像的变量thresh1thresh2。在上面的代码部分中,第一个参数是图像,其次是我们选择的阈值,第三,我们需要给所有被阈值化的像素赋予一个值,最后,我们需要给出一个方法。我给了THRESH_BINARYTHRESH_BINARY_INV来分开变量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

左阈值 2 和右阈值 1

在第一阈值图像(thresh1)中,灰度值为 150,第二阈值图像(thresh2)的灰度值为 255。这只是基于直方图的阈值处理。

在上面的例子中,我们通过参考直方图发现值 190 是最佳值。但是使用 OTSU 有一种更简单的方法来找到最佳值。

ret, thresh3 = cv2.threshold(cl_img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

使用 OTSU,我们可以自动分割它。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

阈值 3 — OTSU

如果使用二进制阈值,OTSU 是找到最佳值的最佳方法。如果有必要,你甚至可以使用 K-means。

文章到此为止。如果你的图像有噪声,不要忘记先去噪。然后你可以做所有这些练习。

结论

总结一下,CLAHE 在大多数情况下都很有效。然后,您可以使用直方图将图像分为这两个阶段,但如果您不想绘制直方图来识别分离,则可以使用 OTSU。

资源

[## Sreeni 为显微镜专家开发的 Python

本频道将带您了解学习 Python 编码的整个过程;从基础到高级…

www.youtube.com](https://www.youtube.com/channel/UC34rW-HtPJulxr5wp2Xa04w)

类激活映射

原文:https://towardsdatascience.com/class-activation-mapping-using-transfer-learning-of-resnet50-e8ca7cfd657e?source=collection_archive---------11-----------------------

一种强有力的弱监督目标定位和调试方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Ales NesetrilUnsplash 上拍摄的照片

介绍

在这篇文章中,我想与你分享一个非常强大和有趣的技术。这种技术被称为类别激活图(CAMs),是由麻省理工学院的研究人员在论文“学习深度特征进行区分定位”中首次引入的。CAMs 的使用使你不仅可以看到网络预测的类别,还可以看到网络特别感兴趣的图像部分。这有助于更深入地了解网络的学习,并且也简化了调试,因为用户不必显式地标记该对象的边界框就可以获得预测类的对象定位。在章节方法论中,我想浏览一下使用的数据,以及在哪里可以找到本文使用的代码。章节模型描述了所使用的模型及其训练。章节类激活映射描述了 CAMs 的概念以及如何计算它。第章结论应该是总结调查结果。

方法学

网络的训练过程和凸轮的计算是用 jupyter 笔记本和 tensorflow 完成的。使用来自 Kaggle 的 360°水果挑战赛的数据集。它包含 90483 幅水果和蔬菜的图像,共有 131 个不同的类别。图 1 显示了一个以地面实况标签为标题的示例图像。相应的笔记本可以在我的 Github 资源库中找到。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1:来自 Kaggle 数据集的示例图像

模型

作为模型,我决定使用已经训练好的 ResNet50 [4]进行迁移学习(TL)。该模型在包含 1000 个不同类的 ImageNet 挑战上被训练。TL 对于快速训练一个大而深的网络非常有用,因为网络不用从头开始训练。通常,你越深入,过滤器在你的网络中学习的特征就越复杂。第一层的过滤器仅学习非常低级的特征,如边缘。这是因为第一层的滤光器只能看到输入图像的一小部分。在第二层,这部分(也称为感受野)已经更大,因此过滤器可以学习更复杂的特征。并且在最后的卷积层上,过滤器已经可以检测完整的对象。当使用 TL 时,预训练的模型被加载,分类层被删除。之后,除了新添加的分类层之外,整个 CNN 被冻结和训练,直到损失收敛。这避免了由于初始潜在的大梯度而破坏已经学习的特征。或者,您可以随后解冻 CNN 的剩余部分或只解冻最后的层,并微调它们的权重以适应您当前的任务。对于这项任务,我决定只重新训练分类层,以便专注于计算凸轮。因此,我在最后删除了 ResNet50 中的所有密集层,并添加了一个全局平均池层(请参见下一章为什么添加此层)以及 softmax 层,该层具有与要分类的类一样多的神经元。该架构将在下一章中详细描述。然后,该模型被训练五个时期,最终得到 99%的验证准确度。

类激活映射

CAM 是为每个图像生成的加权激活图[1]。它有助于识别 CNN 在对图像进行分类时正在查看的区域。摄像机不是在监督下训练的,而是以一种弱监督的方式。这意味着对象不必手动标记,本地化是“免费”学习的。在架构上唯一需要改变的是去掉末端完全连接的密集层,以保持最后一个卷积层输出中包含的空间信息。此外,之后还会添加一个全局平均池层。这一层通常用于正则化,以防止网络过拟合[2]。最后,添加输出 softmax 层,其神经元数量与要分类的类数量一样多(在我们的示例中为 131)。图 2 总结了所需的架构,并展示了如何计算 CAM。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2: CAM 架构和程序[1]

在我们的例子中,架构变化和训练已经完成(参见章节模型),所以我们可以直接从计算 CAM 开始。作为第一步,我们向网络输入一幅图像,并计算网络的分类输出。下一步,我们获取连接到“获胜”神经元的权重。此外,我们存储最终卷积层的输出。然后,我们通过将来自最终卷积层的输出的每个深度乘以连接到“获胜”神经元的相应权重来计算 CAM(即,w1 将乘以最终卷积层输出的深度 1,w2 乘以深度 2,…),并将它们全部相加。最后,我们使用双线性上采样来扩展 CAM 的大小以匹配输入图像的大小。图 3 显示了我的 github 页面上 jupyter 笔记本的功能。

图 3:计算 CAM 的函数(代码来自[3])

图 4 显示了六个示例 cam。每个 CAM 的标题显示了网络的预测标签。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 CAM 的示例输出和网络预测

结论

可以看出,只需对网络架构稍作调整,就可以轻松计算 CAM,而且是免费的,因此没有人需要为数据贴上昂贵的标签。此外,CAM 还可以用于调试,因为可以看到网络聚焦在图像的哪个区域。例如,如果网络应该对图像中港口的存在进行分类,并且通过绘制 CAM 可以清楚地看出网络关注的是天空而不是港口本身,那么这可能是有帮助的。然后,用户可以调整数据集,使其也包含没有可见天空的港口的图像,从而避免这种错误的关联。

资源

[1]:周,Aditya Khosla,Agata Lapedriza,Aude Oliva,Antonio Torralba,学习深度特征进行区分性本地化 (2015),MIT
[2]:,,和水城颜, Network In Network (2013),新加坡国立大学
[3]: Alexis Cook,全球平均池 (2017),Github Blogpost
[4]:何,,,任

分类中的阶级不平衡问题

原文:https://towardsdatascience.com/class-imbalance-problem-in-classification-a2ddaba98f4a?source=collection_archive---------19-----------------------

如果 SMOTE 和 TOMEK 没有改善你的模型怎么办?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当我们在处理分类的时候,我们会面临很多问题。其中之一是阶层失衡:一个阶层代表过多,另一个阶层代表严重不足。这个问题出现在许多研究领域,例如,当我们试图诊断一种罕见的疾病或检测欺诈交易时。在这篇文章中,我想谈谈在我的一个分类项目中,我是如何处理班级失衡问题的。

通常,当我们的阶级比例低于 10/90 时,我们可以说我们面临着阶级失衡。在某些情况下,甚至会更严重。我曾经做过一个分类项目,试图预测丝芙兰出售的哪种美容产品会赢得声望倾城之美奖。在检查了我的数据后,我意识到我有 1920 件产品没有获奖,只有 81 件获奖。注意:有更多的获奖产品,但只有 81 个在丝芙兰售出,我只是在处理他们的数据。

传统方法

为了创建一个二元分类模型,我决定先采用一种简单的方法:不加任何处理地运行逻辑回归。结果是预期的:模型执行的准确率为 96%,但不存在召回。这意味着,这种方法将所有未被充分代表的类别视为背景噪音,或者简单地说,只是假设所有产品都不是赢家,并且在 96%的情况下都是正确的。

如果我们谈论的是赢得奖项的美容产品,这不是世界末日,但如果我们试图诊断一种致命的疾病呢?我们需要消除第二类错误。

有两种著名的处理类不平衡问题的传统方法:使用 TOMEK 链接的欠采样和使用 SMOTE 的过采样。

在第一种情况下,我们检测两个不同类的实例之间的链接,这两个类彼此靠近并且混淆了模型。在我的项目中,可能有两个非常相似的产品(相同的价格,相似的评级,等等。)但是其中一个得了奖,另一个没有。我们在这些实例之间创建一个链接并删除它们,尽可能地将两个类分开。

对于 SMOTE(合成少数过采样技术),我们采用不同的方法。我们不是减少数据点的数量,而是创建代表性不足的类的合成实例。同样,在我的例子中,我们只是分析价格、评级和其他代表诱惑赢家的预测因素,并创建更多具有这些特征的实例。

在从事我的项目时,我尝试了这两种方法,但我建立的模型(逻辑回归、朴素贝叶斯、XGBoost)都没有超过 78%的准确率,也没有提高召回率。

我反而做了什么

经过慎重考虑,我决定采取循序渐进的方法。

首先,我需要创建两个独立的数据框架,赢家和非赢家(为了简单起见,让我们称他们为输家,尽管这听起来可能不太合适)

df_lose = df[df[‘Allure’] == 0]
df_win = df[df[‘Allure’] == 1]

接下来,为了确保我的欠采样是无偏的,我们需要打乱非获胜数据帧 df_lose 的行:

df_lose = shuffle(df_lose)

接下来,我们需要截断这个数据帧,以匹配 df_win 的维度(记住,我们只有 81 个获胜者):

df_lose_81 = df_lose[:81]

最后,我们将它们连接在一起,再次洗牌,以防万一:

twodf = [df_win, df_lose_81]
edf = pd.concat(twodf, ignore_index=True)edf = shuffle(edf)

现在,我们可以查看新数据框的数字,并直观地检查这些类在其预测列中是否不同。事实证明,确实如此,尤其是在“心”这个类别(有多少人“喜欢”这个产品)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

最后,我们可以运行我们的分类模型。我最好的模型是 XGBoost,验证准确率为 96.97%,召回率为 0.93。在得到这些有希望的结果后,我有点怀疑,如果我只是碰巧选择了两个类中最不同的实例呢?我重复了这个过程,将行重新排列了四次,每次模型的性能都保持不变。

请随意叉克隆我的 GitHub repo ,希望我的小小研究有所帮助!

资源下载链接为: https://pan.quark.cn/s/9a27693985af 《基于SSM的JSP招聘网》是一款功能丰富的在线招聘平台,主要面向普通游客、求职者、企业和管理员四种用户角色,提供了多样化的服务与管理功能。该系统采用SSM(Spring、SpringMVC、MyBatis)技术栈开发,确保了系统的稳定性与高效性。以下是对系统功能模块及其技术实现的介绍。 对于普通游客,系统提供职位浏览功能。游客可以查看平台上的各种招聘信息,如职位描述、工作职责、薪资待遇等。这需要后台数据库对招聘信息进行有效存储和检索。在SSM框架中,SpringMVC负责处理HTTP请求,将数据传递给Spring服务层进行业务逻辑处理,MyBatis作为持久层工具,执行SQL查询并将结果映射为Java对象。 求职者注册成为平台用户后,可进行职位收藏和投递。收藏的职位信息会保存在个人中心,方便随时查看。职位投递功能涉及用户个人信息与简历的提交,需要系统具备用户认证和授权机制,可通过Spring Security或Apache Shiro实现。此外,系统可能采用AJAX技术进行异步操作,如即时刷新收藏夹状态,以提升用户体验。 企业用户可在系统中发布职位、查看求职者简历。发布职位时,需进行表单验证和数据合法性检查,SpringMVC的控制器可协同前端校验库(如Hibernate Validator)完成。查看简历时,企业可对求职者进行筛选和评价,这要求数据库设计合理,以便快速查询和分析求职者信息。 管理员负责管理平台运行,包括用户管理、职位审核、系统设置等。管理员模块通常包含后台管理界面,通过SpringMVC的模型视图解析器和模板引擎(如Thymeleaf或FreeMarker)生成动态页面。同时,日志记录和异常处理必不可少,Spring框架提供了强大的日志和AOP支持,可方便实现这些功
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值