TowardsDataScience 博客中文翻译 2020(二百五十八)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

客户体验、人工智能和机器学习——来自 Oovvuu、Canva 和 Minerva Collective 的思考

原文:https://towardsdatascience.com/customer-experience-artificial-intelligence-and-machine-learning-748d8c1e1127?source=collection_archive---------26-----------------------

人工智能(AI)和机器学习(ML)现在是热门话题,它对重新定义商业的许多方面做出了重大贡献,这是理所当然的。然而,许多人仍然对 AI 和 ML 在增强客户体验方面的应用持怀疑态度。

一些人可能会认为,机器不可能接管客户服务,这种服务非常注重人与人之间的互动。机器缺乏同理心和情商核心来提供出色的客户体验。另一方面,许多人也看到了应用人工智能和人工智能来自动化重复性任务的好处,允许人类将更多的时间用于,嗯,做人。

我们联系了来自 Oovvuu、Canva 和 Minerva Collective 的一些专家,向他们请教这个问题。

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

摩根·豪斯尔在 Unsplash 上的照片

客户体验的现状如何,你如何看待 AI & ML 技术的发展?

目前的客户体验“到处都是,结果大相径庭。Minerva Collective 的数据科学家和联合创始人安东尼·托卡尔(Anthony Tockar)表示:“使用同一服务的两个客户对他们的体验可能会有完全不同的印象,在许多情况下,该服务既笨重又结构不良。不幸的现实是,由于糟糕的服务体验,78%的消费者放弃了交易或没有购买意向。事实上,公司只听取了 4%的不满意客户的意见。消费者有如此多的选择,找到另一家提供类似产品的公司比花时间抱怨或打电话解决问题要容易得多。这就是为什么非常有必要关注客户体验,这一因素对于留住现代客户变得越来越重要。

Canva 的机器学习工程师 Paul Tune 认为“改善客户体验有两种趋势:

  • 随着越来越多的关于每个客户的数据被大规模收集,出现了为个人量身定制的趋势;
  • 通过预测客户的需求,在多个接触点为客户提供流畅体验的趋势。"

为了展示客户体验是如何发展的,Paul 继续举了一个例子。“早期的推荐系统,如 21 世纪初亚马逊和网飞开发的推荐引擎,主要为特定的客户群提供更粗糙的推荐。在不久的将来,推荐的粒度将会更细。例如,我最近和一位来自网飞的工程师交谈过,他提到当电视连续剧被选中时,用户最喜欢的角色会出现在菜单中。这意味着必须更多地了解每个客户,并预测他们的习惯。我们也看到智能个人助理的形式,如 Alexa 和 Siri,”他说。

Oovvuu 的创始人兼首席执行官里奇·萨顿补充说,尽管人工智能和人工智能“在(客户体验中)肯定有一个要素可以发挥作用,但它也缺乏一个关键要素……同理心。所以我认为它会进化。人工智能用得越多,它就学得越多,变得越好,但人类层面的同理心目前仍是一个白日梦。”

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

图片来自 https://unsplash.com/的。

你从将智能技术应用于客户体验中学到的最大教训是什么?

对于安东尼来说,这个教训是人们需要使用智能技术来正确理解它——“我的经验是,人们通常不信任他们不理解的东西。最新的技术很容易成为头条新闻,但只有最具前瞻性的企业才会认真应用这些技术来获取价值。这不一定是件坏事——领域知识对于好的数据科学至关重要,盲目依赖新方法有许多内在风险。随着时间的推移,我们对客户体验有了很多了解,有必要使用正确的语言向商业人士解释智能技术,让他们充分认识到它的价值。”

对 Paul 来说,最重要的是客户的端到端体验。这意味着与客户的所有接触点都应该是无缝的。对他来说,“整合智能技术以改善用户体验的挑战与管理任何其他复杂系统类似:随着更多移动部件的出现,系统出现故障的几率更高。天真地应用机器学习来改善客户体验是被误导的。如果机器学习是对客户体验的补充,那么它就能发挥最大的作用,有助于提升伟大产品的体验。”

“在 Canva,我们的目标很简单:我们希望给客户最好的体验,让他们能够创造和设计。为此,我们关注两个方面。首先,我们如何让他们的设计所需的内容易于访问。其次,我们如何预测哪些资源在未来可能对他们有帮助。我们通过改善搜索和推荐服务来提升客户体验,从而实现这些目标。”

对里基来说,最大的教训是“AI 把人类变成了超人,但只是为了某些任务。”—“当我们开始 Oovvuu 时,我们聘请编辑阅读文章并找到相关视频,他们每人每天能够阅读一份出版物并找到 40 个相关视频。使用我们创建的人工智能工具的同一个人,现在每天可以阅读 10 万个出版商和 30 万个故事,涵盖 2600 万个主题,并找到来自 40 多个全球广播公司的相关视频。人工智能在自动化人工任务方面非常强大,但人类在所有让我们成为人类的事情上仍然更好。”

对于试图整合 AI & ML 技术和客户体验的企业来说,有哪些挑战?

Anthony、Paul 和 Ricky 都认为,企业面临的一个巨大挑战是没有一个可靠的数据基础架构,或者没有对实现业务目标和客户满意度的确切衡量标准的深刻理解。

“许多公司与我们接洽,寻求将人工智能作为解决商业问题的现成灵丹妙药。还有人来要求玩 AI,这样就能找到商机。两者都不太管用。”里基说。“对我们来说,解决方案是了解我们试图解决的业务问题:也就是说,在全球范围内发布的每篇文章中放入相关视频。然后我们使用人工智能来解决它,但我们开始做的是非常基础的工作,无法胜任。我们有一个团队培养了近 1000 天的教学,以达到它的目的。”

Anthony 继续补充道,“没有灵丹妙药,需要优秀的数据科学家将这些算法转化为商业价值。拥有可靠的数据科学战略至关重要,通过良好的领导力、不断提高的数据素养以及对如何建立高性能数据科学团队的理解,企业可以利用这些技术打造竞争优势。”

Paul 总结了许多企业在流程中采用 AI & ML 时面临的另一个常见挑战——数据量。“目前的机器学习技术依赖于相对大量的数据来提供良好的预测,”他说。“虽然目前正在进行基础研究,以(有望)减少训练这些机器学习模型所需的数据量,但在可预见的未来,目前需要大量数据的主要技术限制仍将存在。”但“幸运的是,如果收集的数据质量足够高,这种影响可以减轻。”

你是如何实施人工智能和人工智能来改善客户体验的?在下面的评论中与我们分享你的故事吧!

关于贡献者

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

安东尼·托卡尔

Anthony 是数据科学领域的领导者,研究过保险、忠诚度、技术、电信、社会部门甚至神经科学领域的问题。作为一名受过正规培训的精算师,Anthony 在著名的西北大学获得了分析学硕士学位。他在 Neustar 发表的关于数据隐私的帖子成为头条新闻后,他回到悉尼作为一名数据科学家进行实践,同时联合创立了 Minerva Collective 和数据科学早餐会。他还帮助组织了其他几次数据科学家会议和项目,这符合他的使命,即扩大数据的范围和影响,以帮助人们。

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

保罗·图恩

保罗是 Canva 的机器学习工程师,负责为 Canva 的客户开发定制和个性化内容的解决方案。他在著名的计算机科学会议和期刊上发表了几篇文章,包括 2015 年的 ACM SIGCOMM 会议。他的兴趣包括深度学习、统计学和信息论。你也可以在媒体上找到他。

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

里奇·萨顿

里奇是 Oovvuu 的创始人兼首席执行官,Oovvuu 是一家由 IBM 和亚马逊支持的初创公司,利用人工智能将全球广播公司的视频与全球出版商进行匹配。它的任务是使用人工智能在每篇文章中插入相关的短格式和长格式视频。通过这样做,它旨在以一种新的、更有说服力的方式讲述新闻,结束假新闻,并通过这样做,将脸书和谷歌的数十亿美元返还给制作内容的记者和广播公司。

原贴于 织于

离散时间契约环境下的顾客终身价值

原文:https://towardsdatascience.com/customer-lifetime-value-in-a-discrete-time-contractual-setting-math-and-python-implementation-af3ef606cefe?source=collection_archive---------24-----------------------

数学和 Python 实现

激励性问题

在按月/按年(即离散时间)订阅业务环境(即合同)中,根据我们当前客户的特征,新客户的预期价值是什么?

  • 请注意,我们的设置是离散时间合同设置。如果你的商业模式不是基于订阅的(即非合同的),请查看 Python 中的生命周期包。

假设

  • 这里我们只关注收入,而忽略了客户获取成本,以及其他成本。

等式

(法德尔、彼得和布鲁斯(2007 年 a))

客户生命周期价值期望值的等式非常简单:

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

  • m:订阅率
  • s(t):t 时刻的生存函数
  • d:反映货币时间价值的贴现率

例子

这里有一个来自论文推子,彼得和布鲁斯(2007 年 b)的例子。假设我们有 1000 个客户,在第 1 年(t0),我们有所有 1000 个客户。在第 2 年(t1),只有 631 个客户是活跃的。到了第 5 年,只有 326 个客户仍然活跃。假设我们的订阅费率为 100 美元/年,折扣率为 10%。

  • m = 100 美元/年
  • d = 10%

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

  • 基于 CLV 方程,我们可以填入数据并改写方程,如上所示。
  • 问题:唯一的问题是我们不知道未来的存活率。因此,我们可以使用几何贝塔模型来模拟我们的数据和预测生存函数。

几何贝塔模型

(法德尔、彼得和布鲁斯(2007 年 a))

客户持续时间~ geometric(𝜃)

我们假设客户持续时间/生命周期遵循几何分布,因为客户只能流失一次。

  • 流失概率:𝜃
  • 留任概率:1−𝜃
  • 时间 t 时客户流失的概率:

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

  • 时间 t 时的存活率:

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

  • 时间 t 时的保留率:

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

𝜃∼𝑏𝑒𝑡𝑎(𝛼,𝛽)

我们将𝜃的异质性建模为贝塔分布。我们使用贝塔分布,因为它以区间[0,1]为界,并且它有各种可能的形状。

  • 定义在区间[0,1]上

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

几何贝塔分布

然后我们可以结合几何分布和贝塔分布,计算联合分布。并且通过一些贝塔函数和伽玛函数的计算,我们可以计算出客户在任意时刻 t 的流失概率,以及任意时刻 t 的留存率。

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

  • 可能性函数:在 t1 失去𝑛1n1 客户的概率,在 t2 失去𝑛2 客户的概率,以及在观察期结束时保留𝑛−∑𝑛_t 客户的概率。

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

对数似然函数:𝐿𝐿(𝛼,𝛽|𝑑𝑎𝑡𝑎)=𝑙𝑛(𝐿(𝛼,𝛽|𝑑𝑎𝑡𝑎))

找出𝛼和𝛽的最大似然估计量

  • 为了找到参数的最大似然估计量,我们将对数似然函数最大化或负对数似然函数最小化。通过最优化过程,我们得到了𝛼和𝛽.的最大似然估计值

计算 CLV

给定𝛼和𝛽,计算每个时间点的存活率

  • 𝑟(𝑡)=(𝛽+𝑡−1)/(α+β+t−1)
  • t = 0 时的𝑠(𝑡)=1
  • 𝑠(𝑡)=𝑟(𝑡)𝑠(𝑡−1)当 t>0 时

计算 CLV

为 k 选择一个合理的大数

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

Python 实现

最大似然估计

这是我的 Python 实现,用于计算对数似然函数,并优化负对数似然函数。注意,我们需要给参数一个初始值,作为优化的起点。在我们的例子中,𝛼和𝛽的初始值都是 1。

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

通过优化,优化后的负对数似然为 1409.5,𝛼和𝛽的最大似然分别为 0.78 和 1.35。

模型拟合

这是我访问模型拟合的函数。这里我只是比较观察到的和计算出的存活率。你可以改变这个函数来比较似然函数和保持率。

这里的第一个图使用了初始参数(1,1)作为模型参数,我们可以看到模型计算出的存活率不是很理想。第二个图使用参数的最大似然值,模型计算的存活率非常接近观察到的存活率。

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

计算 CLV

现在,我们可以使用 MLE 参数来计算客户终身价值的期望值。我们可以看到,一个新客户的期望值是 362 美元。

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

参考资料:
Fader,Peter S .和 Bruce G.S. Hardie (2014),“一个懂电子表格的非统计学家的贝塔几何模型指南。”http://brucehardie.com/notes/032/
Fader,Peter S .和 Bruce G.S. Hardie (2017),“探索客户终身价值的分布(在合同环境中)。”http://brucehardie.com/notes/035/

通过保留实现客户终身价值——在 Python 中,使用 Pandas 和 Numpy

原文:https://towardsdatascience.com/customer-lifetime-value-via-retention-in-python-with-pandas-and-numpy-143171cc98bc?source=collection_archive---------9-----------------------

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

埃菲社在 Unsplash 上拍摄的照片

在基于订阅的例子中

将这些视为客户终身价值的入门书:这三个部分非常容易理解,会给你一个很好的介绍 LTV 的机会。在第一部中,我浏览了逻辑部分,所以如果你感兴趣,去看看吧!在第二部分中,我展示了一个例子,展示了群组保留如何增加客户的平均加权寿命。在第 3 部分中,我添加了一个 Python 蓝图代码,您可以使用并改进它来推断您的客户 LTV。

零件和内容

第一部分:通过群组保持率估算客户终身价值, CLV 或 LTV 称之为

第二部分:加权队列寿命,作为队列保持的总和,不是证明而是实验

第 3 部分:通过保留实现客户终身价值——在 Python 中,使用 Pandas 和 Numpy

在我开始之前,我想重申一下,LTV 不是一个财务指标,仅仅是一个估计,然而,它允许比直接猜测更好的近似。LTV 最重要的用途之一是客户获取成本的基准,因为它允许设定合理的支出上限。

目的

本系列的目的是阐述一种简单的技术,通过历史趋势的推断,为您提供客户终身价值的估计。在 Python 中,你可以用 Pandas 和 NumPy 做到这一点——这再简单不过了。因此,在这篇文章中,我们不会深究更高级的涉及个体 LTV 预测的技术。我正在考虑写一篇关于此事的独立博文。最后,您可能需要考虑底部列出的一些附加改进。

数据集和假设

在这篇文章中,我们将生成虚拟的月度订阅数据。我们需要 客户 id认购日期到期日 直到认购被取消,否则直到当前日期,以及平均 认购金额

对于这篇文章,我将生成 34 个月的数据。如果你没有这么多的数据,你将不得不对群体行为和寿命做出更多的假设。绘制保留曲线和研究衰变率可能有助于实现这一目的。

Python 实现

虚拟数据

总的来说,我们将遵循本系列第一部分中的逻辑:1)获得群组矩阵;2)获得边际留存;3)外推边缘保持力;4)使用(3)外推(1)。按群组估计的寿命将是第(4)点按行的总和。

首先,我们需要一个订阅数据集。我从 Python 博客文章的 队列分析中获得了一些技术,这些技术对队列的虚拟数据生成和可视化有很好的想法。

下面是我们将用来生成的几个帮助函数:a)客户列表 b)订阅日期、到期日和订阅价值 c)将 a 和 b 放在一个数据框架中。

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

Helper 函数为客户命名,礼貌地向Fabian Bosler和他的博客帖子

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

用于随机订阅日期和结果数据框架的辅助函数

当所有这些加在一起时,我们有 4000 行的随机数据帧看起来有点像这样。最后一列是订阅日期的月初,相当于分组。

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

队列保持率

群组保持率是已获得的客户中达到到期时间 t 的比例。在这种情况下,到期时间是取消订阅之前的时间,或者,如果订阅在当前日期之前有效,则是订阅开始日期和今天之间的时间。

一个有用的功能是绘制保留热图。

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

从我们的数据中获取数据的方法之一是两步:1)旋转上面的数据框架,以获得到期的群组客户的计数 2)将从 T+1 到 T 的所有客户相加,因为在 T+1 活跃的所有客户都在 T 活跃。

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

枢纽队列数据

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

回滚订阅者的数量

将月活跃用户数除以群组规模,最终得到三角形保留矩阵,其中每个值都在[0,1]之间。根据下面的留存矩阵,您已经可以对平均寿命和寿命价值做出假设,这对于在营销活动中选择客户群非常有用。

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

应用我们上面创建的热图绘图功能,我们可以看看队列如何保持超过 34 个月。

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

群组保持原样,您可以看到下面的外推版本并进行比较

边际保留率

边际保留略有不同:它取每一列 T+1,其中 T ≠ 1,然后除以 T。结果,我们得到了上个月的订阅者中在下个月重新订阅的一部分。

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

取前 N 行的平均值来外推矩阵:

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

你可以看到边际保留率是如何在矩阵中平均和外推的。如果你期望边际保留率发生变化,这是调整的好时机。

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

外推的边缘队列保持率

把所有的东西放在一起

在外推的边缘保留和队列保留矩阵准备好之后,我们可以外推队列的保留矩阵。

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

你可以在热图上看到群体保持率是如何推断出来的:

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

外推队列保持率

寿命与价值

群组中平均客户的生命周期,或平均群组生命周期,是整个到期期间保留百分比的总和。

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

进一步改进

显然,这种方法给出了一个队列的平均寿命和价值,因此您可以将其与这个采集时间所花费的 CAC 进行比较。如果你想把 LTV 定为“高于平均水平”的目标,并根据收购时间进行调整,这也会有所帮助。但是,在某些情况下,您可能希望预测某个特定的个人客户的 LTV。为此,您可以使用预测建模*,我将在后面介绍。*

另一个容易实现的改进是将运营利润添加到订阅价值中。这将为您提供一个更好的客户获取成本对比基础。差价会告诉你,一旦客户被吸引过来,第一笔订单送达,这笔生意还剩多少。

对于我们这些熟悉金融中贴现概念的人来说。来自 Investopedia :确定未来将收到的一笔或一系列付款的现值的过程。)—可以纳入你的估算。

你可以考虑的另一个改进是你的业务的季节性,并在你正在做的推断中考虑它。当你查看热图时,可以发现季节性:模式将非常明显,并可能形成一条对角线。

与季节性相似,可能会有一个针对群组的调整或边际保留,您可能希望基于基本知识引入。例如,如果您开展一项活动来影响保留率或提高参与度,则有可能在计算中包含一个变化率。你可以从 计算订阅终身价值的电子表格 中获得一些灵感,这是一篇非常整洁的博客文章——带有电子表格。

说到留存率的计算,您可能已经注意到了,如果有 N 个值可用,那么代码采用窗口为 N 的简单滚动平均。群组规模权重可用于加权平均值

最后,因为在我的代码中,一半的群组和边缘矩阵是按元素填充的,计算可能在较大的矩阵上运行缓慢,所以那里肯定有改进的空间。

最后,我把我的 Colab 笔记本分享给有兴趣复印的朋友:https://Colab . research . Google . com/drive/1 viht 58-NSW-idjbp 1 ks brx 7 _ q 4 DSN 5h 3?usp =共享

如果你想和我联系,你可以在 LinkedIn 和 Twitter 上找到我

https://www.linkedin.com/in/areusova/T14https://twitter.com/khunreus

好好呆着!

人工智能助力平台商业时代的顾客偏好

原文:https://towardsdatascience.com/customer-preferences-in-the-age-of-the-platform-business-with-the-help-of-ai-98b0eabf42d9?source=collection_archive---------25-----------------------

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

照片由晨酿Unsplash 拍摄

在经营平台业务时,如何利用深度学习发现客户的喜好,了解产品库存

M 营销和产品团队的任务是了解客户。为此,他们关注客户偏好——动机、期望和倾向——这些与客户需求相结合,驱动他们的购买决策

作为一名数据科学家,我了解到客户——他们的偏好和需求——很少(或者从来没有?)落入我们用来理解它们的简单的客观桶或分段中。相反,客户的偏好和需求是复杂的,相互交织的,并且不断变化。

虽然理解客户已经够有挑战性了,但许多现代数字企业也不太了解他们的产品。他们运营数字平台来促进生产者和消费者之间的交流。数字平台商业模式创造了具有网络效应的市场和社区,允许其用户进行互动和交易。平台企业不像线性企业那样通过供应链控制库存。

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

图片由来自 Pixabay 的穆罕默德·哈桑拍摄

描述平台业务的一个很好的方式是,他们不拥有生产手段,而是创造连接手段。平台业务的例子有亚马逊脸书YouTubeTwitterEbayAirBnB ,像 Zillo 这样的房地产门户网站,以及像旅游预订网站这样的聚合业务。在过去的几十年里,平台业务开始主导经济。

在平台业务时代,我们如何利用人工智能来理解我们的客户和产品?

这篇博文是我之前关于营销中行为数据新黄金标准的讨论的延续:

[## 人工智能符合营销细分模型

新的黄金标准:使用机器学习从行为数据中获得用户和产品分类,为一个…

towardsdatascience.com](/data-science-powered-segmentation-models-ae89f9bd405f)

在这篇博文中,我们使用了一种更先进的深度神经网络来为客户和产品建模。

神经网络体系结构

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

与 CCBY、 ProSymbolslastsparkJuan Pablo Bravo

我们使用具有以下元素的深度神经网络:

  1. 编码器:获取描述产品或客户的输入数据,并将其映射到特征嵌入中。(嵌入被定义为将一些输入投影到另一个更方便的表示空间)
  2. 比较器:将客户和产品特征嵌入组合成一个偏好张量
  3. 预测器:将偏好转化为预测购买倾向

我们使用神经网络来预测产品购买,因为我们知道购买决策是由客户的偏好和需求驱动的。因此,我们教导编码器从客户行为数据、客户和产品属性中提取此类偏好和需求。

我们可以分析和聚类学习到的客户和产品特征,以得出数据驱动的细分。稍后将详细介绍。

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

晨酿Unsplash 拍摄的照片

TensorFlow 实现

以下代码使用 TensorFlow 2 和 Keras 来实现我们的神经网络架构:

代码创建 TensorFlow 特征列,可以使用数字以及分类特征。我们正在使用 Keras 功能 API 来定义我们的客户偏好神经网络,该网络可以使用二进制交叉熵作为损失函数,通过 Adam 优化器进行编译。

使用 Spark 训练数据

我们需要客户偏好模型的训练数据。作为一个平台企业,你的原始数据将属于大数据类别。为了从点击流、产品搜索和交易中准备 TB 的原始数据,我们使用 Spark。面临的挑战是将这两种技术结合起来,并将来自 Spark 的训练数据输入 TensorFlow。

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

[OC]

大量 TensorFlow 训练数据的最佳格式是将其存储为 TFRecord 文件格式,这是 TensorFlow 自己基于协议缓冲区的二进制存储格式。二进制格式极大地提高了加载数据并将其输入模型训练的性能。例如,如果您使用 csv 文件,您将花费大量计算资源来加载和解析数据,而不是训练您的神经网络。TFRecord 文件格式确保您的数据管道不会成为神经网络训练的瓶颈。

Spark-TensorFlow 连接器允许我们用 Spark 保存 TFRecords。只需将它作为 JAR 添加到新的 Spark 会话中,如下所示:

spark = (
  SparkSession.builder
  .master("yarn")
  .appName(app_name)
  .config("spark.submit.deployMode", "cluster")
  **.config("spark.jars.packages","org.tensorflow:spark-tensorflow-connector_2.11:1.15.0")**
  .getOrCreate()
)

并将火花数据帧写入 TFRecords,如下所示:

(
  training_feature_df
  .write.mode("overwrite")
  **.format("tfrecords")**
  **.option("recordType", "Example")
  .option("codec", "org.apache.hadoop.io.compress.GzipCodec")**
  .save(path)
)

要使用 TensorFlow 加载 TFRecords,需要定义记录的模式,并使用 TensorFlow 数据集 API 将数据集解析到 python 字典的迭代器中:

SCHEMA = {
  "col_name1": tf.io.FixedLenFeature([], tf.string, default_value="Null"),
  "col_name2: tf.io.FixedLenFeature([], tf.float32, default_value=0.0),
}data = (
  **tf.data.TFRecordDataset**(list_of_file_paths, compression_type="GZIP")
  .map(
    lambda record: **tf.io.parse_single_example**(record, SCHEMA),
    num_parallel_calls=num_of_workers
  )
  .batch(num_of_records)
  .prefetch(num_of_batches)
)

使用 Spark 和 PandasUDFs 进行批量评分

在训练我们的神经网络之后,有明显的实时评分应用,例如,在产品搜索中对搜索结果进行评分,以解决拥有成千上万产品的平台上的选择瘫痪问题。

但是有一个高级分析用例来查看产品/用户特性和偏好洞察,并创建数据驱动细分来帮助产品开发等。为此,我们对我们的整个客户群和产品目录进行评分,以获取我们模型的编码器和比较器的输出,用于聚类

为了捕获中间神经网络层的输出,我们可以如下重塑我们训练的张量流:

trained_customer_preference_model = tf.keras.models.load_model(path)
customer_feature_model = tf.keras.Model(
  inputs=trained_customer_preference_model.input,
  outputs=trained_customer_preference_model.get_layer(
    "customer_features").output
)

出于性能原因,我们使用 PandasUDF 对 Spark 的用户进行评分,一次对一批用户进行评分:

from pyspark.sql import functions as F
import numpy as np
import pandas as pdspark = SparkSession.builder.getOrCreate()
customerFeatureModelWrapper = CustomerFeatureModelWrapper(path)
CUSTOMER_FEATURE_MODEL = spark.sparkContext.broadcast(customerFeatureModelWrapper)[**@F**](http://twitter.com/F)**.pandas_udf("array<float>", F.PandasUDFType.SCALAR)
def customer_features_udf(*cols):**
  model_input = dict(zip(FEATURE_COL_NAMES, cols))
  model_output = CUSTOMER_FEATURE_MODEL.value([model_input])
  return pd.Series([np.array(v) for v in model_output.tolist()])(
  customer_df
  .withColumn(
    "customer_features",
    **customer_features_udf(*model_input_cols)**
  )
)

我们必须将 TensorFlow 模型包装到一个包装器类中,以允许序列化、在 Spark 集群中广播以及在所有工作器上对模型进行反序列化。我使用 MLflow 来跟踪模型工件,但是您可以简单地将它们存储在任何没有 MLflow 的云存储上。实现一个下载功能,从 S3 或者任何存储模型的地方获取模型工件。

class CustomerFeatureModelWrapper(object):
  def __init__(self, model_path):
    self.model_path = model_path
    self.model = self._build(model_path)
  **def __getstate__(self):**
    return self.model_path
  **def __setstate__(self, model_path):**
    self.model_path = model_path
    self.model = self._build(model_path)
  **def _build(self, model_path):**
    local_path = download(model_path)
    return tf.keras.models.load_model(local_path)

你可以在我之前的文章中了解更多关于 MLflow 如何帮助你完成数据科学项目的信息:

[## 用 Mlflow 为非傻瓜完成数据科学项目模板。

数据科学项目最佳实践,适用于在本地或云中工作的每个人,从刚起步的忍者到大…

towardsdatascience.com](/complete-data-science-project-template-with-mlflow-for-non-dummies-d082165559eb)

聚类和分割

使用 Spark 对我们的客户群和产品库存进行评分后,我们有了一个包含以下特征和偏好向量的数据框架:

+-----------+---------------------------------------------------+
|product_id |product_features                                   |
+-----------+---------------------------------------------------+
|product_1  |[-0.28878614, 2.026503, 2.352102, -2.010809, ...   |
|product_2  |[0.39889023, -0.06328985, 1.634547, 3.3479023, ... |
+-----------+---------------------------------------------------+

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

( Pixabay )

作为第一步,我们必须创建一个有代表性的但小得多的客户和产品样本,用于聚类。重要的是,你要对你的样本进行分层,每层的客户和产品数量相等。通常,我们有许多匿名客户,他们没有什么客户属性,比如人口统计等。为了分层。在这种情况下,我们可以根据客户与之交互的产品的产品属性对客户进行分层。这符合我们的一般假设,即他们的偏好和需求决定了他们的购买决策。在 Spark 中,您使用地层键创建一个新列。按层次获取客户和产品的总数,并计算每个层次对样本的份额,大约等于按层次的计数。你可以用 Spark 的

DataFrameStatFunctions.sampleBy(col_with_strata_keys, dict_of_sample_fractions, seed)

创建分层样本

为了创建我们的分割,我们使用 T-SNE 来可视化我们的分层数据样本的高维特征向量。T-SNE 是一种随机 ML 算法,以可视化的方式降低维度,将相似的客户和产品聚集在一起。这也被称为邻居嵌入。我们可以使用额外的产品属性为 t-sne 结果着色,以解释我们的聚类,作为我们分析的一部分,从而产生洞察力。在我们从 T-SNE 获得结果之后,我们在 T-SNE 邻居嵌入上运行 DBSCAN 来找到我们的聚类

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

[OC]

利用来自 DBSCAN 输出的集群标签,我们可以计算集群质心:

centroids = products[["product_features", "cluster"]].groupby(
    ["cluster"])["product_features"].apply(
    lambda x: np.mean(np.vstack(x), axis=0)
)cluster
0     [0.5143338, 0.56946456, -0.26320028, 0.4439753...
1     [0.42414477, 0.012167327, -0.662183, 1.2258132...
2     [-0.0057945233, 1.2221531, -0.22178105, 1.2349...
...
Name: product_embeddings, dtype: object

在我们获得聚类质心后,我们将所有的客户群和产品目录分配给它们的代表聚类。因为到目前为止,我们只对大约 50,000 个客户和产品进行了分层抽样。

我们再次使用 Spark 将我们所有的客户和产品分配到他们最近的集群质心。我们使用 L1 规范(或出租车距离)来计算客户/产品到群集质心的距离,以强调每个特征对齐

**distance_udf = F.udf(lambda x, y, i: float(np.linalg.norm(np.array(x) - np.array(y), axis=0, ord=i)), FloatType())**customer_centroids = spark.read.parquet(path)
customer_clusters = (
    customer_dataframe
    .**crossJoin**(
        F.broadcast(customer_centroids)
    )
    .withColumn("distance", **distance_udf**("customer_centroid", "customer_features", F.lit(1)))
    .withColumn("distance_order", F.row_number().over(Window.partitionBy("customer_id").orderBy("distance")))
    .filter("distance_order = 1")
    .select("customer_id", "cluster", "distance")
)+-----------+-------+---------+
|customer_id|cluster| distance|
+-----------+-------+---------+
| customer_1|      4|13.234212|
| customer_2|      4| 8.194665|
| customer_3|      1|  8.00042|
| customer_4|      3|14.705576|

然后,我们可以总结我们的客户群,得出集群突出度:

total_customers = customer_clusters.count()
(
    customer_clusters
    .groupBy("cluster")
    .agg(
        F.count("customer_id").alias("customers"),
        F.avg("distance").alias("avg_distance")
    )
    .withColumn("pct", F.col("customers") / F.lit(total_customers))
)+-------+---------+------------------+-----+
|cluster|customers|      avg_distance|  pct|
+-------+---------+------------------+-----+
|      0|     xxxx|12.882028355869513| xxxx|
|      5|     xxxx|10.084179072882444| xxxx|
|      1|     xxxx|13.966814632296622| xxxx|

这完成了从我们的神经网络嵌入中导出数据驱动分段所需的所有步骤:

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

[OC]

在我的上一篇文章中阅读更多关于细分和从我们的模型中提取洞察力的方法:

[## 人工智能符合营销细分模型

新的黄金标准:使用机器学习从行为数据中获得用户和产品分类,为一个…

towardsdatascience.com](/data-science-powered-segmentation-models-ae89f9bd405f)

实时评分

要了解关于如何部署实时评分模型的更多信息,我推荐我以前的一篇文章:

[## 如何将 Spark ML 模型作为 Kafka 实时流应用程序嵌入到生产部署中

用于生产评分的 2 种模型部署

towardsdatascience.com](/how-to-embed-a-spark-ml-model-as-a-kafka-real-time-streaming-application-for-production-deployment-933aecb79f3f)

一般注意事项和建议

  • 与链接文章中的协同过滤方法相比,神经网络学会了一般化,经过训练的模型可以用于新客户和新产品。神经网络有没有冷启动的问题。
  • 如果除了历史购买和其他客户档案数据之外,您至少使用一些行为数据作为您客户的输入,那么您训练的模型甚至可以对没有任何交易或客户档案数据的新客户做出购买倾向预测。
  • 学习到的产品特征嵌入将会比你的客户特征嵌入聚类成更大数量的不同聚类。大多数顾客都归入一个大群体并不罕见。这并不意味着 90%的顾客都是一样的。如简介中所述,您的大多数客户都有复杂、交织且不断变化的偏好和需求。这意味着它们不能被分成不同的组。不代表他们是同一个。集群的简化无法捕捉到这一点,这只是重申了机器学习对客户意义的需求。
  • 虽然许多利益相关者会喜欢该模型产生的洞察力和细分,但该模型的真正价值在于其预测购买倾向的能力。

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

Jan 是公司数据转型方面的成功思想领袖和顾问,拥有将数据科学大规模应用于商业生产的记录。他最近被 dataIQ 评为英国 100 位最具影响力的数据和分析从业者之一。

在 LinkedIn 上连接:https://www.linkedin.com/in/janteichmann/

阅读其他文章:https://medium.com/@jan.teichmann

使用机器学习进行客户细分和获取

原文:https://towardsdatascience.com/customer-segmentation-and-acquisition-using-machine-learning-a219ce0ec139?source=collection_archive---------8-----------------------

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

斯特凡诺·阿莱马尼在 Unsplash 上拍摄的照片

使用无监督学习根据人口统计数据将客户聚类成细分市场,并使用监督学习来预测潜在客户

介绍

这篇博文是关于我在 Udacity 的机器学习工程师纳米学位项目中做的最后一个项目。该项目基于 Arvato Financial Solutions 提供的真实数据。任务是了解销售有机产品的邮购公司的客户群,并将这些客户群与总体数据进行比较,以预测未来可能的客户。

这个项目尽可能接近真实世界的数据科学项目。这很有挑战性,也很有趣,我在这方面学到了很多。我决定写这篇关于我的学习的文章。

本文的结构:

  • 什么是客户细分
  • 项目介绍
  • 数据描述和分析
  • 使用无监督学习的客户细分
  • 使用监督学习预测未来客户

客户细分

将客户分成具有共同特征的个体的过程称为客户细分。这种细分使营销人员能够为特定的客户群创建有针对性的营销信息,从而增加人们购买产品的机会。它允许他们创建和使用特定的沟通渠道来与不同的细分市场进行沟通,以吸引他们。一个简单的例子是,公司试图通过社交媒体帖子吸引年轻一代,通过广播广告吸引老一代。这有助于公司建立更好的客户关系,并提高公司的整体绩效。

三种最常见的客户细分类型

尽管有三种以上的客户细分类型,我们还是要看看三种最常见的客户细分策略。

1.人口细分

年龄、性别、教育程度、收入、财务状况等参数。从人口统计学的角度来看。这种细分是最常见的客户细分方法,因为这种数据易于获取和分析。此外,人口统计与一个人最重要的特征相对应,这将有助于营销人员做出明智的决策。例如,一家航空公司可以发送电子邮件,向低收入群体提供经济舱机票,向高收入群体提供头等舱机票。

2.地理分割

顾名思义,这种客户细分是基于一个人的物理位置来完成的。在这种情况下,一个制造空调系统的公司就是一个例子。它不能向印度和冰岛的人们提供同样的产品。

3.行为细分

这种客户细分是基于客户的行为数据。基于购买习惯、消费习惯、品牌互动、浏览历史或对应于行为或人的任何其他数据来进行分组。我们今天在网上看到的所有定向广告都使用某种行为细分来决定哪个广告针对哪个客户。

项目介绍

Arvato 在该项目中提供的数据是其客户的人口统计数据和德国一般人口的人口统计数据。因此,任务是根据人口统计数据进行客户细分。该数据包括对应于每个人的 366 个特征,这些特征指示年龄、性别、生活阶段、经济状况、家庭状况、家庭状况、房屋位置、邻居信息。这些特征只是数据中 366 个特征中的几个。

问题陈述

问题陈述表述为“给定一个人的人口统计数据,邮购公司如何高效地获取新客户”。

根据这一陈述,我们可以得出结论,我们必须以某种方式比较现有的客户数据和总体数据,以推断它们之间的关系。手动方式是比较客户和普通人群之间的统计数据。例如,可以比较年龄的平均值和标准偏差,以确定哪个年龄组更有可能成为客户,或者可以比较工资,以查看哪一组人成为客户,等等。

但是这种分析会给出许多结果,必须再次对这些结果进行分析,以得出最终的策略。这个过程将需要大量的时间,到这个分析完成时,市场上的竞争对手将占领大部分人口,公司将倒闭。今天,随着机器学习(ML)技术在每个领域的出现,这个问题也可以在 ML 算法的帮助下得到解决。

数据描述和分析

如前所述,Arvato 提供的数据包含现有客户的人口统计数据和一般人口数据。此外,还为监督学习部分提供了两个额外的文件,一个用于培训,一个用于测试。最后,测试集上的预测将提交给 Kaggle competition。此外,还提供了两个附加文件,其中包含有关特征值及其描述的信息。这两个文件是有益的,因为所有的功能名称都是德语和简短的形式。让我们看看关于数据集的信息。

普通人群-包含德国普通人群的人口统计数据,相当于 891,211 人,每个人有 366 个特征。(891211x366)

客户数据-包含邮购公司现有客户的人口统计数据,对应于 191,652 人,每个人有 369 个特征。这三个额外的特性是特定于公司的,涉及如何下订单以及订单的数量。(191652x366)

训练数据-由 42,982 人的人口统计数据组成,并带有一个除 366 之外的附加列,指示一个人是否是客户,用于训练监督学习模型。

测试数据-由 42,833 人的人口统计数据组成,具有相同的 366 个特征,但没有目标。

包含功能信息的两个附加文件

数据清理

数据分析从将错误记录的值替换为 NaN 值开始。这些错误记录的值是使用给定的信息文件确定的。例如,根据属性信息文件中给出的描述,列“LP_STATS_FEIN”只需包含“1–5”中的值,但给出的数据包含“0”。这意味着记录的这些值有错误,这些值必须被视为缺失值。属性信息文件还包含关于哪些值对应于某些列中的未知值的信息。这些信息在某种程度上是有帮助的,所有错误的信息都可以转换为缺失值。

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

图 1:缺失值超过 30%的列

在清理了错误记录的值之后,下一步是处理丢失的值本身。对每列缺失值的百分比进行分析,以确定有多少列有缺失值,以及它们是否包含多少百分比。图 1 显示了缺失值超过 30%的列。在此分析之后,选择阈值 30 来删除列。随后,必须按行对缺失值进行分析,以移除具有缺失特征的观测值。这里,选择每个观测值缺失 50 个特征的阈值来删除行。在此分析之后,得到的形状是:

普通人群— (737288x356)

客户数据— (13426x356)(忽略额外的客户特定功能)

特征工程

有一些用数值编码的分类特征(事实上有很多,但为了简单起见,只给出了几个)。这些特征用二进制编码。此外,一些功能包含太多信息,例如,在一个单独的列中包含关于财务状况和年龄的信息。这种类型的特征被识别,或者被重新编码以包含更广泛的信息,或者被分成两列以分别包含两种特征。在属性信息文件的帮助下,任何包含超过 20 个类别的特征要么被丢弃,要么被重新构建成有用的东西。

由于许多要素包含转储到单个列中的分类值,这一步有助于简化后面步骤的数据。这一步产生了 353 个特征。

输入缺失值

即使在根据某个阈值删除了列和行之后,我们仍然会得到一些缺少值的数据。这个问题在简单估算器的帮助下得到解决,它用一些我们可以控制的值来填充缺失的数据。数值特征的一般方法是用中值或平均值估算缺失值。但是更常见的分类特征方法是用最常见的值进行估算。由于数据对应于总体,因此用最常见的值来估算缺失值更为敏感。

现在,数据是干净的,可以进行建模了,最后一步是缩放数据,即将所有要素纳入同一范围。这是使用标准的定标器来完成的。

使用无监督学习的客户细分

对于聚类分割,需要执行两个步骤。

  • 降维
  • 使聚集

降维

虽然我们有 353 个特征,但并不是所有的特征都有变化,也就是说,有些特征对所有人来说可能是相同的。我们可以浏览这里的所有特性,看看每个特性有多少唯一值,以选择具有所需变化的特性。但是更系统的方法是在删除任何列之前执行某种分析。因此,已经进行了主成分分析来分析主成分分析成分的解释方差。PCA 对数据应用线性变换以形成新的坐标系,使得新坐标系中的分量代表数据的变化。

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

图 2: PCA 解释的方差图

这种分析将帮助我们确定有多少特征具有足够的方差来解释数据中的变化。解释的方差图用于选择分量的数量,即缩减坐标空间中的维数。从上面的图中可以看出,在大约 150 个组件的帮助下,几乎 90%的差异都可以得到解释。现在,在 PCA 变换之后,我们剩下 150 个 PCA 分量,每个分量由主要特征之间的线性组合组成。

使聚集

降维之后,下一步就是把普通人群和客户人群划分成不同的细分。K-Means 聚类算法已被选为这项任务。因为它测量两个观察值之间的距离来分配一个聚类,所以它是简单的并且适合于这个任务。该算法将帮助我们在简化特征的帮助下将一般人群分成指定数量的聚类,并使用该聚类信息来了解一般人群和客户数据中的相似性。借助于肘形图,群集的数量被选择为“8”。

聚类分析

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

图 3:集群比例

普通人群和客户人群已经被分成了几个部分。图 3 显示了进入每个集群的人口比例。一般群体的聚类分布是均匀的,这意味着一般群体已被均匀地聚类成 8 个段。但客户群似乎来自“0”、“3”、“4”和“7”这几个类别。如图 4 所示,我们可以通过计算客户群和普通人群群的比例来进一步证实这一点。

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

图 4:集群比例比率

如图 4 所示,如果比例比大于 1,这意味着该集群在现有人口中拥有更多的客户,并有可能拥有更多的未来客户。如果比率小于 1,这意味着这些集群拥有未来客户的可能性最小。

还执行更详细的聚类分析,解释每个聚类和相应的组件。它记录在用于本项目的 jupyter 笔记本中。我不在这里解释,因为这篇博文已经太长了。

使用监督学习获取客户

在分析了一般人群和客户数据之后,了解应该关注哪些细分市场。我们可以进一步扩展这种分析,利用最大似然算法来进行决策。由于我们已经有了客户数据和一般人群数据,我们可以将它们组合起来形成训练数据,并训练 ML 模型来预测是否接近客户。

在这种情况下,使用给定的训练和测试数据进行监督学习。由于该问题是一个高度不平衡的分类,AUROC 分数已被选为评估标准。基线性能是用逻辑回归模型设置的,该模型在基于树的集成模型的帮助下得到进一步改进。AdaboostClassifier 和 XGBoostClassifier 是最终选定的模型,它们的预测被提交给 Kaggle,以便在只有两次提交的情况下(在提交之日)获得前 30%的位置。

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

图 5: Kaggle 排行榜

结论

使用无监督学习算法对普通人群和顾客人群进行了比较和分割。我们能够确定哪些集群有更多的客户,哪些是潜在的集群有可能的客户。我们还使用监督学习算法,根据人口统计数据预测未来可能的客户。

由此产生的分析产生了很好的结果,使我在竞赛领导委员会中名列前 30%。排行榜的最高分是 0.81063,和我达到的分数(0.80027)相差不远。数据准备步骤还有改进的余地。

项目报告中给出了对每个步骤以及算法和指标选择背后的原因的更全面的解释,并且所有步骤都记录在这个笔记本中。

最后,我要感谢 Arvato Financial Solutions 和 Udacity 提供了这个处理真实数据的绝佳机会。这帮助我获得了宝贵的经验,并帮助我使用和提高我的技能。

参考

  1. https://www . business 2 community . com/customer-experience/4-type-of-customer-segmentation-all-markets-should-know-02120397
  2. https://blog.alexa.com/types-of-market-segmentation/
  3. https://clever tap . com/blog/customer-segmentation-examples-for-better-mobile-marketing/
  4. https://www.shopify.com/encyclopedia/customer-segmentation
  5. https://www.liveagent.com/academy/customer-segmentation/
  6. https://www . data novia . com/en/lessons/determining-the-optimal-number-of-clusters-3-must-know-methods/
  7. https://towards data science . com/what-metrics-we-should-use-on-unbalanced-data-set-precision-recall-roc-e2e 79252 aeba

原载于 2020 年 4 月 16 日https://pranaymudukuru . github . io

Python 中的客户细分

原文:https://towardsdatascience.com/customer-segmentation-in-python-9c15acf6f945?source=collection_archive---------4-----------------------

无监督学习

基于 K-均值聚类算法的图像分割。

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

里卡多·戈麦斯·安吉尔在 Unsplash 上的照片

T4:假设我们有一家公司销售该产品,你想知道该产品的销售情况如何。

你有我们可以分析的数据,但是我们能做什么样的分析呢?

嗯,我们可以根据客户在市场上的购买行为对他们进行细分。

请记住,数据非常庞大,我们无法用肉眼来分析。我们将使用机器学习算法和计算能力。

本文将向您展示如何使用 Python 中的 K-Means 算法根据客户的行为对客户进行聚类。

我希望这篇文章能帮助你从准备数据到聚类,一步一步地进行客户细分。

行动(或活动、袭击)计划

在我们进入这个过程之前,我会简要地告诉你我们将采取什么样的步骤。

  • 收集数据
  • 创建最近频率货币(RFM)表
  • 管理偏斜度并衡量每个变量
  • 探索数据
  • 对数据进行聚类
  • 解读结果

分析

数据收集

在这一步中,我们将首先收集数据。对于这种情况,我们将从 UCI 机器学习中获取名为在线零售数据集的数据。

数据集本身是一个交易数据,包含一家英国在线零售商从 2010 年 12 月 1 日到 2011 年 12 月 9 日的交易。

每一行代表发生的交易。它包括产品名称、数量、价格和其他表示 ID 的列。

您可以从这里访问数据集。

这是数据集的大小。

(541909, 8)

在这种情况下,我们不使用所有的行。相反,我们将从数据集中抽取 10000 行作为样本,并假设这是客户进行的全部交易。

代码看起来会像这样,

**# Import The Libraries**
# ! pip install xlrd
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np**# Import The Dataset**
df = pd.read_excel('dataset.xlsx')
df = df[df['CustomerID'].notna()]**# Sample the dataset**
df_fix = df.sample(10000, random_state = 42)

这是数据集的一瞥,

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

创建 RFM 表

在我们对数据进行采样之后,我们将使数据更容易进行分析。

为了细分客户,我们可以使用一些指标,如客户上次购买产品的时间、客户购买产品的频率以及客户为产品支付的金额。我们将这种分割称为 RFM 分割。

为了制作 RFM 表,我们可以创建这些列,比如 Recency、Frequency 和 MonetaryValue 列。

要获得最近的天数列,我们可以用事务发生的日期减去快照日期。

要创建 frequency 列,我们可以计算每个客户的交易量。

最后,为了创建货币值列,我们可以对每个客户的所有交易进行求和。

代码看起来像这样,

**# Convert to show date only** from datetime import datetime
df_fix["InvoiceDate"] = df_fix["InvoiceDate"].dt.date**# Create TotalSum colummn**
df_fix["TotalSum"] = df_fix["Quantity"] * df_fix["UnitPrice"]**# Create date variable that records recency**
import datetime
snapshot_date = max(df_fix.InvoiceDate) + datetime.timedelta(days=1)**# Aggregate data by each customer**
customers = df_fix.groupby(['CustomerID']).agg({
    'InvoiceDate': lambda x: (snapshot_date - x.max()).days,
    'InvoiceNo': 'count',
    'TotalSum': 'sum'})**# Rename columns**
customers.rename(columns = {'InvoiceDate': 'Recency',
                            'InvoiceNo': 'Frequency',
                            'TotalSum': 'MonetaryValue'}, inplace=True)

这是数据集的一瞥,

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

目前,数据集由最近、频率和货币值列组成。但是我们还不能使用数据集,因为我们必须对数据进行更多的预处理。

管理偏斜度和缩放比例

我们必须确保数据符合这些假设,

数据应该满足假设,即变量没有偏斜,并且具有相同的均值和方差。

正因为如此,我们必须管理变量的偏斜度。

这是每个变量的可视化,

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

从左到右:最近、频率和货币值列

正如我们从上面看到的,我们必须转换数据,所以它有一个更对称的形式。

我们可以使用一些方法来管理偏度,它们是,

  • 日志转换
  • 平方根变换
  • box-cox 变换

注意:当且仅当变量只有正值时,我们才能使用转换。

下面是每个变量的可视化,有和没有转换。每个变量从左上顺时针方向显示了没有变换、对数变换、平方根变换和 box-cox 变换的图。

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

左:最近列,右:频率列

基于这种可视化,它显示了具有 box-cox 变换的变量显示出比其他变换更对称的形式。

为了确保这一点,我们使用 skew 函数计算每个变量。结果看起来像这样,

**variable, without, log, sqrt, box-cox transformations
Recency, 14.77, 0.85, 3.67, 0.16
Frequency, 0.93, -0.72, 0.32, -0.1**

下面是如何解读偏斜度值。如果该值接近 0,变量往往具有对称形式。然而,如果不是这样,变量就有偏斜。基于这种计算,我们使用使用 box-cox 变换的变量。

基于该计算,我们将利用使用 box-cox 变换的变量。MonetaryValue 变量除外,因为该变量包含负值。为了处理这个变量,我们可以对数据使用立方根变换,所以比较看起来像这样,

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

不含和含立方根变换

通过使用这种转换,我们将得到不那么扭曲的数据。偏斜度值从 16.63 下降到 1.16。因此,我们可以用这段代码转换 RFM 表,

from scipy import stats
customers_fix = pd.DataFrame()
customers_fix["Recency"] = stats.boxcox(customers['Recency'])[0]
customers_fix["Frequency"] = stats.boxcox(customers['Frequency'])[0]
customers_fix["MonetaryValue"] = pd.Series(np.cbrt(customers['MonetaryValue'])).values
customers_fix.tail()

它看起来会像这样,

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

我们现在能使用数据吗?还没有。如果我们再看一下这个图,每个变量都没有相同的均值和方差。我们必须把它正常化。为了规范化,我们可以使用 scikit-learn 库中的 StandardScaler 对象来实现。代码看起来会像这样,

**# Import library**
from sklearn.preprocessing import StandardScaler**# Initialize the Object**
scaler = StandardScaler()**# Fit and Transform The Data**
scaler.fit(customers_fix)
customers_normalized = scaler.transform(customers_fix)**# Assert that it has mean 0 and variance 1**
print(customers_normalized.mean(axis = 0).round(2)) **# [0\. -0\. 0.]** print(customers_normalized.std(axis = 0).round(2)) **# [1\. 1\. 1.]**

数据会像这样,

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

最后,我们可以使用这些数据进行聚类。

系统模型化

在我们对数据进行预处理之后,现在我们可以专注于建模了。为了从数据中进行分割,我们可以使用 K-Means 算法来实现。

K-Means 算法是一种无监督学习算法,它使用几何原理来确定哪个聚类属于数据。通过确定每个质心,我们计算到每个质心的距离。如果每个数据与另一个数据的距离最小,则该数据属于一个质心。如此重复,直到下一次总距离没有比之前有显著变化。

用 Python 实现 K-Means 很容易。我们可以使用 scikit 中的 KMeans 函数——学会做这件事。

为了使我们的聚类达到最佳性能,我们必须确定哪个超参数适合数据。为了确定哪个超参数最适合我们的模型和数据,我们可以使用肘方法来决定。代码看起来会像这样,

from sklearn.cluster import KMeanssse = {}
for k in range(1, 11):
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(customers_normalized)
    sse[k] = kmeans.inertia_ # SSE to closest cluster centroidplt.title('The Elbow Method')
plt.xlabel('k')
plt.ylabel('SSE')
sns.pointplot(x=list(sse.keys()), y=list(sse.values()))
plt.show()

这是结果,

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

如何解读剧情?x 轴是 k 的值,y 轴是数据的 SSE 值。我们将通过查看 k 值在下一个连续 k 值的线性趋势来选择最佳参数。

根据我们的观察,k 值为 3 是我们模型的最佳超参数,因为下一个 k 值往往具有线性趋势。因此,我们对数据的最佳模型是 K-Means,聚类数是 3

现在,我们可以用这段代码来拟合这个模型,

model = KMeans(n_clusters=3, random_state=42)
model.fit(customers_normalized)
model.labels_.shape

通过拟合模型,我们可以得到每个数据所属的聚类。借此,我们可以分析数据。

解释该部分

我们可以根据聚类来总结 RFM 表,并计算每个变量的平均值。代码看起来会像这样,

customers["Cluster"] = model.labels_
customers.groupby('Cluster').agg({
    'Recency':'mean',
    'Frequency':'mean',
    'MonetaryValue':['mean', 'count']}).round(2)

代码的输出如下所示,

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

汇总表

除此之外,我们可以使用蛇情节来分析片段。它需要标准化数据集和聚类标签。通过使用该图,我们可以很好地从数据中直观地了解集群之间的差异。我们可以通过使用这些代码来绘制图表,

**# Create the dataframe**
df_normalized = pd.DataFrame(customers_normalized, columns=['Recency', 'Frequency', 'MonetaryValue'])
df_normalized['ID'] = customers.index
df_normalized['Cluster'] = model.labels_**# Melt The Data**
df_nor_melt = pd.melt(df_normalized.reset_index(),
                      id_vars=['ID', 'Cluster'],
                      value_vars=['Recency','Frequency','MonetaryValue'],
                      var_name='Attribute',
                      value_name='Value')
df_nor_melt.head()**# Visualize it**
sns.lineplot('Attribute', 'Value', hue='Cluster', data=df_nor_melt)

这是结果,

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

蛇的阴谋

通过使用这个图,我们知道每个部分是如何不同的。它描述的比我们使用的汇总表更多。

我们推断,集群 0 是经常性的,花费更多,他们最近购买产品。因此,这可能是一群的忠实客户

然后,集群 1 的频率较低,花费较少,但他们最近购买了该产品。因此,它可能是新客户的集群。

最后,集群 2 的频率更低,花费更少,他们在旧时间购买产品。因此,这可能是一群被搅动的顾客

结论

总之,客户细分对于了解每个客户的特征是非常必要的。本文向您展示了如何使用 Python 实现它。希望这篇文章对你有用,可以落实到你的案例上。

如果你想知道代码是如何编写的,你可以查看这个谷歌实验室这里

参考

[1] Daqing C .,Sai L.S,和 kung g .在线零售业的数据挖掘:使用数据挖掘进行基于 RFM 模型的客户细分的案例研究 (2012),数据库营销和客户战略管理杂志*。*
【2】mill man k . J,Aivazis M. 面向科学家和工程师的 Python(2011),科学中的计算&工程*。*
【3】rade CIID处理偏斜数据的 3 大方法 (2020),走向数据科学。
【4】肘法求 k 中最优值 KMeans ,极客为极客。

感谢您阅读我的文章,您也可以在下面查看我以前的文章:

[## R 时间序列分析导论

从探索,到预测。使用印度尼西亚 2002 年 12 月至 2020 年 4 月的消费者价格指数(CPI)数据

towardsdatascience.com](/introduction-to-time-series-analysis-with-r-a2f97650baa3) [## R 中 ARIMA 模型的时间序列预测

从勘探到预测 1970 年至 2015 年的二氧化碳排放数据。

towardsdatascience.com](/time-series-forecasting-with-arima-model-in-r-77f4e2ae7abb) [## 企业家的数据工程

这是一家更加数据驱动的公司。

towardsdatascience.com](/data-engineering-for-entrepreneurs-fa10f9190831)

客户细分:K 均值聚类和 A/B 检验

原文:https://towardsdatascience.com/customer-segmentation-k-means-clustering-a-b-testing-bd26a94462dd?source=collection_archive---------17-----------------------

该项目旨在研究数字平台上的客户行为,在没有任何先验知识的情况下对客户进行分组,并进行 A/B 测试,以帮助提高业务绩效。

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

照片由 nrdUnsplash 上拍摄

语境

我在广告业工作了近 3 年,特别是数字媒体和表演,客户行为分析是我日常工作的核心内容之一。在不同分析平台(例如 Google Analytics、Adobe Analytics)的帮助下,我的生活变得比以前更加轻松,因为这些平台自带了内置的细分功能,可以跨维度和指标分析用户行为。

然而,尽管提供了便利,我还是希望 利用机器学习来进行客户细分 ,这可以 扩展并适用于 数据科学中的其他优化(例如 A/B 测试)。然后,我偶然发现了 Google Analytics 为 Kaggle 比赛提供的数据集,并决定将它用于这个项目。

如果您感兴趣,请随意查看数据集这里!注意数据集有几个子数据集, 每个子数据集都有超过 90 万行

A.解释性数据分析(EDA)

这始终是每个数据科学项目中必不可少的一步,以确保数据集干净并经过适当的预处理以用于建模。

首先,让我们导入所有必需的库并读取 csv 文件:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as snsdf_raw = pd.read_csv("google-analytics.csv")
df_raw.head()

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

1.展平 JSON 字段

正如您所看到的,上面的原始数据集有点“混乱”,根本不容易理解,因为一些变量被格式化为 JSON 字段,将不同子变量的不同值压缩到一个字段中。例如,对于地理网络变量,我们可以知道有几个子变量,如大陆、次大陆等。组合在一起。

多亏了 Kaggler 的帮助,我能够通过展平那些 JSON 字段,将这些变量转换成更容易理解的变量:

import os
import json
from pandas import json_normalizedef load_df(csv_path="google-analytics.csv", nrows=None):
    json_columns = ['device', 'geoNetwork', 'totals', 'trafficSource']
    df = pd.read_csv(csv_path, converters={column: json.loads for column in json_columns},dtype={'fullVisitorID':'str'}, nrows=nrows)
    for column in json_columns:
        column_converted = json_normalize(df[column])
        column_converted.columns = [f"{column}_{subcolumn}" for subcolumn in column_converted.columns]
        df = df.drop(column, axis=1).merge(column_converted, right_index=True, left_index=True)
    return df

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

在展平这些 JSON 字段后,我们能够看到一个更加清晰的数据集,尤其是那些被拆分为子变量的 JSON 变量(例如,设备被拆分为 device_browser、device_browserVersion 等。).

2.数据重新格式化和分组

对于这个项目,我选择了我认为对用户行为有更好影响或相关性的变量:

df = df.loc[:,['channelGrouping', 'date', 'fullVisitorId', 'sessionId', 'visitId', 'visitNumber', 'device_browser', 'device_operatingSystem', 'device_isMobile', 'geoNetwork_country', 'trafficSource_source', 'totals_visits', 'totals_hits', 'totals_pageviews', 'totals_bounces', 'totals_transactionRevenue']]df = df.fillna(value=0)
df.head()

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

接下来,由于新数据集的变量更少,但数据类型不同,我花了一些时间来分析每个变量,以确保数据在建模前“足够干净”。下面是一些要清理的未清理数据的快速示例:

**#Format the values**
df.channelGrouping.unique()
df.channelGrouping = df.channelGrouping.replace("(Other)", "Others")**#Convert boolean type to string** 
df.device_isMobile.unique()
df.device_isMobile = df.device_isMobile.astype(str)
df.loc[df.device_isMobile == "False", "device"] = "Desktop"
df.loc[df.device_isMobile == "True", "device"] = "Mobile"**#Categorize similar values**df['traffic_source'] = df.trafficSource_sourcemain_traffic_source = ["google","baidu","bing","yahoo",...., "pinterest","yandex"]df.traffic_source[df.traffic_source.str.contains("google")] = "google"
df.traffic_source[df.traffic_source.str.contains("baidu")] = "baidu"
df.traffic_source[df.traffic_source.str.contains("bing")] = "bing"
df.traffic_source[df.traffic_source.str.contains("yahoo")] = "yahoo"
.....
df.traffic_source[~df.traffic_source.isin(main_traffic_source)] = "Others"

重新格式化后,我发现 fullVisitorID 的唯一值少于数据集的总行数,这意味着记录了多个 full visitorid。因此,我继续按 fullVisitorID 对变量进行分组,并按收入进行排序:

df_groupby = df.groupby(['fullVisitorId', 'channelGrouping', 'geoNetwork_country', 'traffic_source', 'device', 'deviceBrowser', 'device_operatingSystem'])
               .agg({'totals_hits':'sum', 'totals_pageviews':'sum', 'totals_bounces':'sum','totals_transactionRevenue':'sum'})
               .reset_index()df_groupby = df_groupby.sort_values(by='totals_transactionRevenue', ascending=False).reset_index(drop=True)

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

df.groupby()和 df.sort_values()

3.异常值处理

任何 EDA 过程中不可忽视的最后一步是检测和处理数据集的异常值。原因是异常值,尤其是那些边缘极端的异常值,会影响机器学习模型的性能,大多数是负面的。也就是说,我们需要从数据集中移除这些异常值,或者转换它们(通过均值或模式)以使它们适合大多数数据点所在的范围:

**#Seaborn Boxplot to see how far outliers lie compared to the rest** sns.boxplot(df_groupby.totals_transactionRevenue)

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

sns.boxplot()

如您所见,大多数收入数据点都低于 200,000 美元,只有一个极端异常值接近 600,000 美元。如果我们不移除这个异常值,模型也会考虑它,从而产生不太客观的反映。

因此,让我们继续下去,并删除它,并请这样做,为其他变量。简单说明一下,有几种处理异常值(比如分位数间)的方法。然而,在我的例子中,只有一个,所以我只是继续定义我认为非常适合的范围:

df_groupby = df_groupby.loc[df_groupby.totals_transactionRevenue < 200000]

B.k 均值聚类

什么是 K 均值聚类,它如何帮助客户细分?

聚类是最著名的无监督学习技术,它通过识别相似的组/聚类,特别是借助 K-Means,在未标记的数据中发现结构。

K-Means 试图解决两个问题:(1) K: 我们期望在数据集中找到的聚类(组)的数量,以及(2) Means: 我们试图最小化的数据到每个聚类中心(质心)的平均距离。

此外,值得注意的一点是,K-Means 有几种变体,典型的有:

  1. init = ‘random’: 随机选择每个簇的质心
  2. init = ‘k-means++’: 随机选择第一个质心,其他质心尽可能远离第一个质心

在这个项目中,我将使用第二个选项来确保每个集群之间有很好的区分:

from sklearn.cluster import KMeansdata = df_groupby.iloc[:, 7:]kmeans = KMeans(n_clusters=3, init="k-means++")
kmeans.fit(data)labels = kmeans.predict(data)
labels = pd.DataFrame(data=labels, index = df_groupby.index, columns=["labels"])

在应用该算法之前,我们需要定义“ n_clusters ”,这是我们期望从建模中得到的组的数量。这种情况下,我随机放 n_clusters = 3。然后,我继续使用两个变量可视化数据集是如何分组的:收入和浏览量:

plt.scatter(df_kmeans.totals_transactionRevenue[df_kmeans.labels == 0],df_kmeans.totals_pageviews[df_kmeans.labels == 0], c='blue')plt.scatter(df_kmeans.totals_transactionRevenue[df_kmeans.labels == 1], df_kmeans.totals_pageviews[df_kmeans.labels == 1], c='green')plt.scatter(df_kmeans.totals_transactionRevenue[df_kmeans.labels == 2], df_kmeans.totals_pageviews[df_kmeans.labels == 2], c='orange')plt.show()

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

如你所见,x 轴代表收入数,而 y 轴代表浏览量。建模后,我们可以看出 3 个集群有一定程度的差异。然而,我不确定 3 是否是集群的“正确”数量。也就是说,我们可以依赖 K-Means 算法的估计量, inertia_ ,它是每个样本到质心的距离。特别是,在我的例子中,我们将比较范围从 1 到 10 的每个集群的惯性,并查看哪个是最低的以及我们应该走多远:

#Find the best number of clustersnum_clusters = [x for x in range(1,10)]
inertia = []for i in num_clusters:
    model = KMeans(n_clusters = i, init="k-means++")
    model.fit(data)
    inertia.append(model.inertia_)

plt.plot(num_clusters, inertia)
plt.show()

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

型号.惯性 _

从上面的图表中,惯性从第 4 个或第 5 个集群开始缓慢下降,这意味着这是我们可以获得的最低惯性,所以我决定使用“ n_clusters=4 ”:

plt.scatter(df_kmeans_n4.totals_pageviews[df_kmeans_n4.labels == 0], df_kmeans_n4.totals_transactionRevenue[df_kmeans_n4.labels == 0], c='blue')plt.scatter(df_kmeans_n4.totals_pageviews[df_kmeans_n4.labels == 1],
df_kmeans_n4.totals_transactionRevenue[df_kmeans_n4.labels == 1], c='green')plt.scatter(df_kmeans_n4.totals_pageviews[df_kmeans_n4.labels == 2],
df_kmeans_n4.totals_transactionRevenue[df_kmeans_n4.labels == 2], c='orange')plt.scatter(df_kmeans_n4.totals_pageviews[df_kmeans_n4.labels == 3],
df_kmeans_n4.totals_transactionRevenue[df_kmeans_n4.labels == 3], c='red')plt.xlabel("Page Views")
plt.ylabel("Revenue")plt.show()

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

将浏览量切换到 x 轴,将收入切换到 y 轴

这些集群现在看起来更容易区分了:

  1. 集群 0(蓝色):高浏览量,但几乎没有收入
  2. 集群 1(红色):中等浏览量,低收入
  3. 集群 2(橙色):中等浏览量,中等收入
  4. 集群 4(绿色):浏览量趋势不明朗,收入高

除了第 0 类和第 4 类(不清楚模式),它们超出了我们的控制,第 1 类和第 2 类可以在这里讲述一个故事,因为它们似乎有一些相似之处。

为了了解可能影响每个集群的因素,我按照通道、设备和操作系统对每个集群进行了划分:

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

群组 1

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

群组 2

如上所述,在群组 1 中,推荐渠道贡献的收入最高,其次是直接搜索和有机搜索。相比之下,在第 2 类中做出最大贡献的是 Direct。类似地,虽然 Macintosh 是集群 1 中最主要的设备,但集群 2 中的 Windows 实现了更高的收入。两个集群之间唯一的相似之处是设备浏览器,Chrome 浏览器被广泛使用。

瞧啊。这种进一步的细分有助于我们判断哪个因素(在本例中是渠道、设备浏览器、操作系统)更适合每个集群,因此我们可以更好地评估未来的投资!

C.通过假设检验进行 A/B 检验

什么是 A/B 检验,假设检验如何补充这一过程?

A/B 测试对于从事广告和媒体工作的人来说并不陌生,因为它是帮助以更高的成本效率提高性能的强大技术之一。特别是,A/B 测试将观众分为两组:测试与控制。然后,我们向测试组展示广告/展示不同的设计,只是为了看看两组之间是否有任何显著的差异:暴露组与未暴露组。

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

图片鸣谢:https://product Coalition . com/are-you-segmenting-your-a-b-test-results-c 5512 c 6 def 65?gi=7b445e5ef457

在广告中,市场上有许多不同的自动化工具,可以轻松地帮助一键完成 A/B 测试。然而,我仍然想在数据科学中尝试一种不同的方法来做同样的事情:假设检验。方法基本相同,假设检验比较零假设(H0)和替代假设(H1 ),看看两者之间是否有显著差异!

假设我开展了一项推广活动,向测试组展示了一则广告。下面是用假设检验来检验结果时需要遵循的步骤的快速总结:

  1. 样本量确定
  2. 先决条件:正态性和相关性检验
  3. 假设检验

对于第一步,我们可以依靠功效分析来确定从人群中抽取的样本量。功效分析需要 3 个参数:(1)效果大小,(2)功效和(3)α。如果你正在寻找关于如何进行功耗分析的细节,请 参考我前段时间写的一篇深入的文章

下面是每个参数的快速注释,便于您快速理解:

#Effect Size: (expected mean - actual mean) / actual_std
effect_size = (280000 - df_group1_ab.revenue.mean())/df_group1_ab.revenue.std() #set expected mean to $350,000
print(effect_size)#Power
power = 0.9 #the probability of rejecting the null hypothesis#Alpha
alpha = 0.05 #the error rate

准备好 3 个参数后,我们使用 TTestPower() 来确定样本大小:

import statsmodels.stats.power as smsn = sms.TTestPower().solve_power(effect_size=effect_size, power=power, alpha=alpha)print(n)

结果是 279,这意味着我们需要从每组中抽取 279 个数据点:测试组和对照组。由于我没有真实的数据,我使用 np.random.normal 来生成收入数据列表,在本例中,每组的样本量= 279:

#Take the samples out of each group: control vs testcontrol_sample = np.random.normal(control_rev.mean(), control_rev.std(), size=279)
test_sample = np.random.normal(test_rev.mean(), test_rev.std(), size=279)

转到第二步,我们需要确保样本(1)正态分布和(2)独立(不相关)。同样,如果您想更新一下本步骤中使用的测试,请参考我上面的文章。简而言之,我们将使用(1)夏皮罗作为正态性检验和(2)皮尔逊作为相关性检验。

#Step 2\. Pre-requisite: Normality, Correlationfrom scipy.stats import shapiro, pearsonrstat1, p1 = shapiro(control_sample)
stat2, p2 = shapiro(test_sample)print(p1, p2)stat3, p3 = pearsonr(control_sample, test_sample)
print(p3)

对照组和试验组的 Shapiro p 值分别为 0.129 和 0.539,p 值> 0.05。因此,我们不拒绝零假设,并且能够说 2 组是正态分布的。

皮尔逊的 p 值为 0.98,大于 0.05,意味着 2 组相互独立。

最后一步到了!由于有两个变量需要相互测试(测试组与对照组),我们使用 T-Test 来查看运行 A/B 测试后收入是否有任何显著差异:

#Step 3\. Hypothesis Testingfrom scipy.stats import ttest_indtstat, p4 = ttest_ind(control_sample, test_sample)
print(p4)

结果是 0.35,大于 0.05。因此,进行的 A/B 测试表明,接触广告的测试组并没有比没有接触广告的对照组表现出任何优势。

瞧啊。这个项目到此结束——客户细分和 A/B 测试!我希望这篇文章对你有用并且容易理解。

在不久的将来,请留意我的即将到来的数据科学和机器学习项目!与此同时,您可以在这里查看我的 Github 以获得完整的资源库:

github:【https://github.com/andrewnguyen07T2
LinkedIn:www.linkedin.com/in/andrewnguyen07

谢谢!

使用 Instacart 数据集进行客户细分

原文:https://towardsdatascience.com/customer-segmentation-using-the-instacart-dataset-17e24be9c0fe?source=collection_archive---------17-----------------------

当您想要的数据不存在时发挥创造力

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

照片由法比奥·布拉克特Unsplash 上拍摄

我最近有机会使用来自 Instacart (via Kaggle) 的数据集完成了一个开放式数据分析项目。经过一番探索,我决定尝试客户细分。幸运的是,我找到了 Tern Poh Lim 的一篇文章,这篇文章为我如何做到这一点提供了灵感生成了一些方便的可视化工具来帮助我交流我的发现。在这篇文章中,我将介绍我是如何在 Instacart 数据集上采用 RFM(近期、频率、货币)分析进行客户细分的。由于数据集实际上不包含时间戳或任何关于收入的信息,我必须有点创意!

看看那些购物车

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

照片由 Alexandru TuguiUnsplash 上拍摄

如果你不熟悉的话, Instacart 是一个杂货店购物服务。用户通过应用程序订购食品,就像其他零工经济公司一样,自由职业者“购物者”负责完成用户订单。 Instacart 市场购物篮分析数据集是为特定应用而设计的:试图预测客户未来会再次订购哪些商品。如果您查看 Kaggle 上的文档,您会看到数据集包含以下类型的信息:

  • 每个订单的记录,包括星期几和小时(但没有实际的时间戳);
  • 每个订单中每个产品的记录,以及每个项目添加到给定订单中的顺序,以及该项目先前是否由同一客户订购的指示;和
  • 每个产品的名称、通道和部门。

这些数据已经完全匿名化,因此除了用户 ID 和订单历史记录之外,没有关于用户的任何信息—没有位置数据、实际订单日期或订单的货币价值。

这一点很重要,因为这些缺失的信息类型对业务分析非常重要。公司非常想知道用户最近是否活跃,他们在过去一天/一周/一个月/一个季度的活跃程度,以及他们对公司的货币价值。如果我想用这个数据集进行客户细分,我必须找到一个创造性的解决方案。

客户细分:基础知识

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

照片由德鲁·比默Unsplash 上拍摄

简单来说,客户细分意味着根据客户的真实或可能行为将他们分类,以便公司能够更有效地与他们合作。例如,一家公司可以向其最忠实的客户提供一种促销或折扣,而向新客户或不经常光顾的客户提供不同的激励。

进行客户细分的典型方法是进行 RFM 分析。(这是对 RFM 分析的一个很好的介绍。)RFM 代表“最近性、频率、金钱”,从公司的角度来看,代表了客户的一些最重要的属性。为了进行这种分析,您需要收集每个客户的相关数据,并根据每个 RFM 变量的相似值将客户分组。这背后的数学可能更复杂或更简单,这取决于您是否希望对 RFM 变量进行不同的加权。

Tern Poh Lim 的文章概述了如何使用 k-means 对客户进行聚类分析。更好的是,他指出,你可以迭代地使用 k-means 来计算要使用的最佳聚类数,从而消除聚类过程中的大量猜测。正如您将在下面看到的,我改编了他的一些代码,使用不同数量的聚类的剪影分数来生成肘图,并生成蛇图来总结每个聚类的属性。但我已经超越自我了!首先,让我们看看我对 Instacart 客户进行细分的总体方法。

走向细分的步骤

我采取了四个基本步骤来细分 Instacart 客户:

  • 设计一些功能来取代 RFM,因为我没有这些变量的正确数据;
  • 使用肘形图确定要计算的最佳聚类数;
  • 创建 TSNE 图并检查聚类的可分性;
  • 描述每个集群的关键属性。

步骤 1:特征工程

在缺乏适当的数据进行 RFM 分析的情况下,我不得不创建一些功能来捕捉用户行为的类似方面。经过一些实验,我发现了三个与 RFM 非常相似的特性:

  • 每个客户的订单总数;
  • 每个客户的订单之间的平均延迟(天数);和
  • 每位客户的订单(产品)平均规模。

总订单和每个客户的平均延迟类似于近期和频率;他们捕获了客户使用 Instacart 的次数(尽管在这种情况下,使用分布在一个不确定的时间段内)。每位客户的平均订单规模是货币价值的一种代表。虽然我不确定 Instacart 究竟是如何评估送货和服务费的,但我做了一个大致的假设,即订单的大小可能与其货币价值有关(至少它的大小是我可以实际测量的!).即使我的功能没有完美地映射到 RFM,它们仍然捕捉到了许多关于客户如何使用 Instacart 的重要信息。

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

所有功能都已标准化,订单数量也已对数转换。

因为我要将这些特征传递给 k-means 算法,所以我需要注意非正态分布和异常值,因为聚类很容易受到这两种情况的影响。当我检查我的三个特性的分布时,每个客户的订单数显示了一个很强的正偏态。我使用了对数转换来解决这个问题。然后我标准化了所有三个特性(使用 sk learn . preprocessing . standard scaler ),以减轻任何剩余异常值的影响。就这样,我为下一步做好了准备!

步骤 2:确定最佳 k

K-means 可以把你的客户进行聚类排序,但是你要告诉它你想要多少个聚类。这可能很棘手。两个集群有意义吗?10 点怎么样?通过测试 k 的一组值,我们可以更清楚地了解有多少聚类真正适合我们的数据。

我们可以使用几个指标来评估 k 聚类与给定数据集的吻合程度。对于我的项目,我使用了两个指标:失真分数轮廓分数

失真分数有点像残差平方和;它测量一个簇内的误差,或者每个数据点与其指定簇的质心之间的距离。较低的失真分数意味着更紧密的聚类,这意味着该聚类中的客户有很多共同点。

剪影得分将任何给定数据点与其指定聚类中心之间的距离与该数据点与其他聚类中心之间的距离进行比较。基本上,剪影分数是问,“这个点实际上更接近其他一些集群的中心吗?”同样,我们希望该值较低,这意味着我们的集群在向量空间中更紧密,彼此之间也更远。

我将这两个指标放在肘图中,肘图显示了具有不同数量的聚类的模型的分数。我任意选择了 2 到 10 个集群进行尝试。两个图都显示了在 4 个集群的得分(或肘部)的巨大变化。

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

Tern Poh Lim 的文章中,我了解到这是一种常见的做法,不仅要用你最好的 k ,还要用 k — 1 和 k + 1。这三个选项中的一个可能会给你最可分离的集群,这就是你想要的。

步骤 3:检查聚类的可分性

我在这一步寻找的是尽可能少重叠的集群。任何时候两个集群彼此非常接近,都有可能靠近一个集群边缘的任何一个客户更适合相邻的集群。你知道,我们不想向 30 岁以下的顾客发送关于老年人折扣的电子邮件!越容易画一条直线来分隔我们的聚类,我们的聚类分配就越可能准确。TSNE 图获取了我们所知道的关于每个客户的一切信息,并将其缩减为二维,这样我们就可以很容易地看到各个集群之间的关系。看看这个:

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

当只有 3 个集群时,它们看起来很容易分开(而且相当均衡——没有一个集群比其他集群大很多)。4 个集群中的两个比我希望的要重叠一些,5 个集群到处都是。看起来 3 个集群是该客户群和这些功能的最佳选择。

步骤 4:描述每个集群

使用 k = 3,我使用 k-means 将每个客户分配到一个集群。现在怎么办?嗯,你可以总结每个集群的每个特性的价值,从而了解该集群的购买习惯。再次遵循 Tern Poh Lim 的文章,我使用了一个“蛇图”(一个 Seaborn 点图)来可视化每个集群的三个特征的平均值。情节是这样:

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

我们可以用这些信息做什么?以下是我根据这个情节给营销团队的建议:

  • 集群 0:这些是我们最喜欢的客户!他们大量使用 Instacart,做中型订单。针对这些客户的营销可以侧重于保持他们的忠诚度,同时鼓励他们下订单,为公司带来更多收入(无论这意味着更多的商品、更贵的商品等。).
  • 集群 1:这些客户不经常使用 Instacart,但当他们使用时,他们会下大订单。当然,我们可以专注于将他们转化为更频繁的用户,根据 Instacart 从订单中产生收入的确切方式,我们可能会促使他们做出更频繁、更小的订单,或者继续做出那些大订单。
  • 第 2 组:这是我们最有改进空间的部分。他们尝试过 Instacart,但不经常使用,购买的物品也不多。针对这些人的营销策略可以侧重于增加订单频率和/或数量。

我希望我已经说服你,即使没有通常用于客户细分的数据,你也可以获得一些关于客户的非常有用的见解。你可以在我的 GitHub 上查看这个项目的所有代码。对 Tern Poh Lim 为这个项目的灵感(和许多有用的代码)最后一次大喊!

基于 K 均值聚类的客户细分

原文:https://towardsdatascience.com/customer-segmentation-with-kmeans-e499f4ebbd3d?source=collection_archive---------16-----------------------

营销活动不再采用一刀切的方式

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

照片由汉娜·林Unsplash 上拍摄

并非所有的顾客都是平等的。—我(还有许多其他人)

你永远不会像对你的伴侣那样对你的父母说话,也不会像对你的经理那样对你的孩子说话。那么,为什么你的营销团队在你的营销材料中使用一刀切的语言呢?

利用机器学习和人工智能处理大量的消费者历史、网络流量和产品评论,可以对营销活动产生重大影响。通过利用统计和分析工具的力量,可以根据三个简单的行为特征将客户划分为不同的群体,从而影响多渠道营销活动中使用的语言,并提高点击率和转化率。

你越了解你的顾客,你就越富裕。

作为客户,你不希望被视为达到目的的手段。你想成为社区的一员。作为一名零售商,你的工作是了解你的顾客,并告诉他们你对他们的了解。不要被动,了解他们的痛点,了解他们的购买习惯,建立信任。收入也会随之而来。

市场细分和 RFM 模型

一般来说,有四种方法来划分你的消费群:

  • 人口统计—年龄、性别、社会经济地位
  • 地理——他们在世界的什么地方?
  • 心理分析——寻找结婚戒指,计划买房子
  • 行为——一旦你的客户到达你的网站,他们会做什么?

谷歌的 BigQuery API 允许你对谷歌分析数据进行类似 SQL 的查询。如果你通过谷歌分析账户进行电子商务跟踪,你就可以获得客户的行为数据。该研究是在 2016 年 8 月至 2017 年 8 月期间对谷歌商品商店的数据进行的。在此期间,超过 740,000 名不同的人访问了 merch 商店,购买了 11,500 件商品,总价值超过 200,000 美元。

为了补充我们从谷歌商品商店获得的网络数据,我们将设计一些功能,以便根据 RFM 模型为每个客户“打分”。该技术采用最近一次购买的最近度(R ),所有购买的频率(F)或计数减 1,以及由平均订单金额定义的货币值(M)。

RFM 特色工程

为了对数据进行分段,您需要从三列开始:唯一的客户 id、交易日期和交易金额。我用这个函数将谷歌商店的数据处理成一种我们可以用来建模的格式

一旦我们通过这个函数运行我们的数据框架,我们就剩下以下信息:

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

值得注意的是,你的网站可能也有不购物的访问者,但是这种细分方法是针对已经转化的客户的。另一项研究可以——也应该——对那些不购买的人的行为进行研究,这样你就可以提高网站的转化能力。

基于 Kmeans 的无监督机器学习

既然我们的数据已准备好进行聚类,我们将测试几个聚类级别并比较肘形图中的误差平方和,以确定对每个要素单独进行聚类的最佳级别。

看起来,频率开始在五个集群水平,最近在四或五,收入在四或五。根据您的业务模型,您可能有理由选择较低或较高数量的集群。经过几次反复,我决定了五个频率、四个最近和五个收入。

从这里开始,我们将需要一些辅助函数来从最差到最好对集群进行排序,并为每个数据点分配相应的集群。

结果如下:

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

  • 频率——绝大多数客户属于较低的类别,在 3 到 4 之间有一个巨大的跳跃,只有一个客户购买超过 15 次
  • 最近——大多数客户都很不活跃(你真正需要多少件谷歌 t 恤?)最近的窗口变得越大,聚类分配越好。
  • 收入——绝大多数消费者平均在谷歌商品商店购买了价值 17 到 19 美元的商品。这五个收入群分布相当均匀,平均订单支出不超过 23 美元。

我们将通过合计每个聚类的得分来确定总体得分,并由此确定细分分层。

rfm_df[‘OverallScore’] = rfm_df[‘RecencyCluster’] + rfm_df[‘FrequencyCluster’] + rfm_df[‘RevenueCluster’]rfm_df.groupby(‘OverallScore’)[‘Recency’,’Frequency’,’logRevenue’].mean()

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

根据你的商业模式,你可能已经有了一定的细分市场。在这里,我把他们分成三组。不活跃、
不频繁、低消费的客户是低价值客户,中值客户高于平均收入,平均收入高于平均收入,最近消费频率高于平均收入,高价值客户属于至少两个特征的上层客户。

# Naming and defining segments
rfm_df[‘Segment’] = 0
rfm_df.loc[rfm_df[‘OverallScore’]>4,’Segment’] = 1 
rfm_df.loc[rfm_df[‘OverallScore’]>6,’Segment’] = 2

现在来看看每个集群,看看我们做得有多好:

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

看看那些轮廓优美的集群!

从该图中,我们可以看到,有些客户并没有花很多钱,但是经常访问该网站,并且最近进行了购买,这也属于高价值类别。分数似乎被非常不频繁的购买或很久以前的最后一次购买拉低了。

从这里,你可以将这些信息传递给你的营销团队,或者如果你是营销团队,使用这些信息为针对每个客户特定购买行为的电子邮件营销活动或广告设计语言。您已经播下了种子,现在看看您的收入如何增长吧!

基于机器学习的客户细分

原文:https://towardsdatascience.com/customer-segmentation-with-machine-learning-a0ac8c3d4d84?source=collection_archive---------1-----------------------

机器学习

K-means 算法应用于现实世界的电子商务销售数据

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

图怀亚特Unsplash 上拍摄

想象一下,你对待你每天购物的杂货店老板,就像你对待你的另一半一样。开始的时候可能会很有趣,但是也可能会导致灾难性的情况。同样,对一家公司来说,以同样的方式管理与每个客户的关系也是不利的。

客户细分使公司能够定制与客户的关系,就像我们在日常生活中所做的那样。

当你进行客户细分时,你会发现每个客户的行为和需求都有相似的特征。然后,将它们归纳成组,以满足不同策略的需求。此外,这些策略可以作为

  • 针对特定群体的营销活动
  • 推出符合客户需求的功能
  • 产品路线图的开发

市场上有不同的产品/解决方案,从套装软件到 CRM 产品。今天我就用 Python 来应用一个无监督的机器学习算法

这个从 2018 年 11 月到 2019 年 4 月的数据集是由一家电子商务公司提供的实际销售数据。这是提供给我的一个采访案例研究。

是的,他们有一个令人惊讶的面试过程,但更多的在那之后,在这篇文章的结尾。我也没有得到这个角色,主要是因为远程就业后勤,但这是另一个故事了。

我将通过以下步骤对数据集应用 K 均值聚类。

  1. 商业案例
  2. 数据准备
  3. 基于 K-均值聚类的分割
  4. 超参数调谐
  5. 结果的可视化和解释

在这个过程中,我将解释 K-means 聚类是如何工作的。最后,我将为形成的细分市场提供具体的策略。

出于保密原因,我对数据进行了匿名处理。

你可以按照笔记本上的步骤进行:

[## nbviewer 笔记本

客户细分将使用 scikit-learn 的 K-means 聚类应用于电子商务客户数据库。它…

nbviewer.jupyter.org](https://nbviewer.jupyter.org/github/cereniyim/Customer-Segmentation-Unsupervised-ML-Model/blob/0418ed702b0b8f87b472d68971c84a4913fa956e/Customer_Segmentation_Kmeans_Clustering.ipynb)

…并在这里 找到 GitHub 库

1.商业案例

在案例研究中,我从不同方面形象化了客户行为和特征。更进一步,我将围绕这个问题形成商业案例:能否将客户群分组以发展定制关系?

我将从行为角度(替代方法可以是地理或人口统计学角度)探讨这个问题,以更好地了解顾客的消费和订购习惯,其特征如下:订购的产品数量、平均退货率和总消费。

2.数据准备

原始数据集中大约有 25000 个不同的客户及其订单信息:

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

数据集格式良好,没有 NA 值。所以,我们可以从形成特征开始。将根据customer_id计算 3 个特征,它们将在后面的步骤中帮助我们进行可视化(使用 Plotly 库)和算法解释。数据准备将由熊猫熊猫完成。

  • **订购产品数量:**通过以下函数计算客户订购的product_type:

  • **平均退货率:**客户所有订单的平均returned_item_quantityordered_item_quantity之比。

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

  • **总支出:**是总销售额的总和,是税后和退货后的最终金额。

计算后,3 个特征合并到customers数据框中:

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

我们来看看特性的个体分布:

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

所有 3 个分布都是正的偏斜分布。订购产品呈幂律分布,99%的顾客平均退货率为 0。

3 特性具有不同的范围,在[1,13]、[0,1]和[0,1000]之间变化,这是一个重要的观察结果,表明特性需要缩放!

缩放:

K-means 算法将customers数据帧中的每一行解释为三维空间中的一个点。当对它们进行分组时,它使用数据点和组中心之间的欧几里德距离。由于范围变化很大,算法的性能可能很差,无法按预期形成分组。

为了使 K-means 有效执行,我们将使用对数变换来缩放数据,对数变换是一种适用于倾斜数据的变换。这将按比例缩小我们的数据分布的 3D 空间,同时保持点之间的邻近性。

应用上述函数后, customers 数据帧准备好送入 K-means 聚类:

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

3.基于 K-均值聚类的分割

我们将使用 scikit-learn 中的 K-means 算法。我们先来了解一下算法会如何形成客户群体:

  1. 随机或智能初始化 k = n 个质心 = 簇数
  2. 基于欧几里德距离将每个数据点分配到最近的质心,从而形成组
  3. 将中心移动到聚类中所有点的平均值

重复步骤 2 和 3,直到收敛

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

k-表示 n 个质心=3 的作用中。来源:维基媒体

运行步骤至时,该算法会检查每个聚类的聚类点和中心之间的距离平方和。从数学上来说,它试图最小化—优化每个簇 簇内距离平方和惯性

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

聚类内距离平方和或惯性的数学表达式,其中 X 是聚类中的点,并且是当前质心

惯性 值不再最小化时,算法收敛。因此,迭代停止。

from sklearn.cluster import Kmeans
kmeans_model = KMeans(init='k-means++', 
                      max_iter=500, 
                      random_state=42)
  • 带有k-means++init参数允许算法灵活地放置初始中心,而不是随机的。
  • max_iter是算法在单次运行中的最大迭代次数,默认值为 300。
  • random_state保证模型结果的再现性。

该算法易于理解,在计算时间方面非常适合大数据集,并且保证了收敛性。然而,当随机初始化质心时,算法可能不会以最佳方式将点分配给组。

一个重要的考虑是选择 k 。换句话说,应该组成多少个小组?例如,上面应用的 K-means 使用 k=8 作为默认值。

下一步,我们将选择 K 均值中最重要的超参数 k

4.超参数调谐

在选择 k、时,我们将使用肘方法来决定 K 均值、惯性的优化标准。我们要用 k 值 1 到 15 建立不同的 K 均值模型,并保存相应的惯性值。

results = make_list_of_K(15, customers.iloc[:,3:])
k_values_distances = pd.DataFrame({"clusters": clusters,
                                   "within cluster sum of squared distances": results})

当我们绘制惯性k 值时:**

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

对于肘法,我们将选择惯性下降稳定的 k 值。

**当 k=1 惯性最大时,意味着数据尚未分组。惯性急剧下降,直到 *k=2。*在 k=24、之间,曲线继续快速下降。

k=4 处,下降稳定并继续直线下降,在 k=4 处形成一个弯头。这就指出了客户群的最佳数量是 4

5.结果的可视化和解释

让我们将 k=4 插入 K-means,想象一下客户群是如何创建的:

# create clustering model with optimal k=4
updated_kmeans_model = KMeans(n_clusters = 4, 
                              init='k-means++', 
                              max_iter=500, 
                              random_state=42)updated_kmeans_model.fit_predict(customers.iloc[:,3:])

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

每个数据点的值可以在这里交互观察

数据点显示在球体中,每组的质心用立方体显示。4 客户群如下:

****蓝色:至少订购了一种产品,最高总消费为 100 英镑,平均退货率最高的客户。他们可能是电子商务网站的新来者。

****红色:订购 1 至 4 件商品,平均总消费 150,最高退货率 0.5 的客户。

****紫色:订购 1 至 4 件商品,平均总消费 300,最高退货率 0.5 的客户。

****绿色:订购 1 至 13 件商品,平均总消费 600,平均退货率为 0 的客户。它为公司创造了最有利的客户群。

让我们来看看每个组中有多少客户——称为集群数量:

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

总体策略是保留最有利的客户群——绿色客户群,同时将蓝色客户群转移到红色和紫色区域。

Blue group 占所有客户的 42%,在该客户群中实现的任何改进都将显著增加收入。消除高回报率和提供礼品卡可以将这个客户群体转移到低平均回报率和高总消费领域。如果我们假设他们是新来的,礼品卡可以加速他们的回头客。

红紫集团合计占所有客户的 50%。从平均退货率和订购产品的角度来看,它们表现出相同的特征,但与总支出不同。这些群体可以定义为已经知道该品牌并订购多种产品的人。这些客户可以通过一些专门的沟通和折扣来了解最新的品牌信息。

绿色客户群占所有客户的 8%,形成对品牌最有利的客户群。他们订购多种产品,并且极有可能保留这些产品。为了保持并可能扩大这个群体,特价和产品发布会可能会有所帮助。此外,它们可以吸引新客户,影响客户群的扩大。

结论

我们从行为角度研究了客户细分问题,包括每位客户订购的产品数量、平均退货率和总支出。使用 3 个特性有助于我们理解和可视化模型。

总而言之,数据集易于执行无监督的机器学习问题。起初,我们只有带有订单信息的客户数据,不知道他们是否属于任何组。使用 K-means 聚类,可以发现数据中的模式,并进一步扩展到组中。我们为形成的群体制定了策略,从最初是尘云的数据集中获取意义。

关于面试;我喜欢参与案例研究,面试过程是我迄今为止最棒的面试经历。这是对我在一个典型的、实际的任务中的技能的一个非常现实的评估,我会经常执行这个任务。这使得整个过程非常简单有趣。我希望这种实用的数据科学面试成为主流,让应聘者和雇主都受益。

感谢您的阅读,对于评论或建设性的反馈,您可以通过回复、 TwitterLinkedin 联系我!

看过此物品的顾客也看过…

原文:https://towardsdatascience.com/customers-who-viewed-this-item-also-viewed-40026c4eb700?source=collection_archive---------28-----------------------

每次你完成一部关于网飞的电影,你都会看到一个新电影的推荐。每次打开 YouTube 都会看到一些推荐视频,因为你看了类似的东西。我最喜欢的一个是亚马逊的推荐算法,因为你甚至不需要购买或查看某样东西就可以看到它是*推荐。*如果你谈到了手机附近的一本书,你会在亚马逊的建议中看到它。就这么简单!

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

感谢查尔斯·德鲁维奥的照片

这些推荐功能,也称为推荐系统,在过去十年中成为一种有用和流行的机器学习算法。其背后的算法实际上并不令人困惑。例如,该系统可以基于过去的购买或评论推荐一个人可能感兴趣的产品。为了理解细节,我们应该熟悉余弦相似度的概念。

余弦相似度

余弦相似度表示一个人的品味或偏好在多大程度上可以用另一个人的选择来描述。在数学中,它计算两个向量的余弦值。在这种情况下,向量由人们的选择来表示。我们发现余弦相似性,我们计算 2 个向量的单位向量的点积。

假设人 A 的偏好用向量 A 表示,人 B 的偏好用向量 B 表示。

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

余弦相似度是介于-1 和 1 之间的数字。如果 A 人和 B 人的选择完全相同,他们的余弦相似度为 1。如果它们完全不相似,它们的余弦相似度是-1。这是一个重要的细节,因为-1 余弦同样能告诉我们这两个人的偏好。这意味着他们喜欢彼此相反的产品。人 A 喜欢某部电影,而人 B 不喜欢同一部电影。在-1 余弦相似度中仍然有信息。然而,如果余弦相似度为 0,人 A 的选择没有给出关于人 B 的偏好的信息。

一旦我们理解了余弦相似性的概念,推荐系统就更有意义了。通常有两种常见类型的推荐系统。这些是基于内容的推荐系统和协作推荐系统。

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

照片由 Unsplash 上的 Nordwood Themes 拍摄

基于内容推荐系统

在基于内容的推荐系统中,目标是对相似的实例(电影、书籍等)进行分组。)根据它们的产品特性分成不同的组。聚类是基于产品的实际特征建立的。

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

在上面的例子中,不管用户怎么看,每部电影都有不同的特点。在基于内容的推荐系统中,用户(顾客)并不扮演积极的角色。这里我们的向量是表格的行。我们找到每个向量与其他向量的余弦相似性。

在实践中,我们从特征工程开始,使每个记录成为一个数值,然后我们类似地计算余弦。余弦相似度告诉我们最相似的向量。使用这种方法,当您插入一个新的电影名称时,它将返回与产品功能最相似的电影。

协同推荐系统

协同推荐系统将用户考虑在内。用户的行为是产生推荐的一个非常重要的输入。该算法利用用户-产品交互。协同推荐系统也分为两个主要的模型。

  1. 基于用户的协同推荐系统
  2. 基于项目的协同推荐系统

基于用户的协同推荐系统基于用户的购买或评级,使用余弦相似性数学对用户进行聚类。

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

在上面的例子中,我们看到了 4 部电影的用户评分。用户 1 和用户 2 之间有相似之处,因为他们都喜欢和不喜欢相同的电影。基于这个事实,我们可以向用户 1 推荐《十二怒汉》,因为用户 2 喜欢。此外,我们不应该向用户 5 推荐“教父”,因为用户 4 不喜欢它,并且他们有相似的偏好。

这种推荐系统的一个缺点是它完全依赖于客户的评分。不是每个顾客都喜欢给产品评级。此外,众所周知,有负面经历的人比有正面经历的人更有可能提交评级分数。这就是为什么许多公司从基于评级的推荐系统转向基于购买的推荐系统。基于购买的系统更可靠,因为它们考虑了用户的实际行为。此外,收集数据也容易得多。让我们看看下面的例子:

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

基于购买决策,我们可以向用户 A 推荐“Forest Gump ”,因为他的购买行为与用户 B 相似,并且用户 B 观看了它。这种特殊型号与“顾客购买这种产品同时也购买了……”的概念相同。

基于项目的协同推荐系统非常类似于基于用户的协同推荐系统。不同的是矩阵是转置的。在基于项目的协同推荐系统中,我们查看产品屏幕,发现电影的余弦相似性。

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

在上面的例子中,用户用 1-5 的尺度给电影评分。电影“12 个愤怒的人”可以呈现给用户 1,因为这部电影已经从相同的人那里收到了与“搏击俱乐部”相同的反应。如果用户 1 喜欢“搏击俱乐部”,他也可能喜欢“12 个愤怒的人”。

排除用户 1;《搏击俱乐部》的 s 向量= [ 4,3,4,4]和《十二怒汉》的 s 向量= [ 5,3,4,4]非常相似。

推荐系统在 Python 中的实现

实际上,当我们创建一个推荐系统时,我们首先创建一个数据透视表。在 Python 中,我们使用*。pivot_table( )* 函数就是这么做的。例如基于项目的推荐系统,产品的名称(可以是电影、书籍或音乐名称等。)将是我们的数据帧的索引,用户信息(名称或 Id,取决于您的数据集)将在列中。这个*。pivot_table( )* 函数将返回一个巨大的表格,向我们展示每个用户对每部电影的行为。当然,不是每个人对所有产品都有一种行为(这种行为意味着评级,或购买信息),这就是为什么我们会在数据透视表中看到许多 NaN 或“0”值。这就是稀疏矩阵派上用场的地方。快速提醒;稀疏矩阵获取数据帧,并通过移除所有“0”值将其压缩成更轻的格式。我们的数据帧的信息没有改变,但它在计算机中占用的空间要少得多,因为稀疏矩阵没有零的负担。这里我们可以认为“0”和 NaN 值携带的信息相等;因为当数据是二进制的时候,“0”意味着没有行为发生或者没有购买发生。因此,在使用稀疏矩阵之前,可以将“NaN”值转换为“0”。

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

一旦你创建了稀疏矩阵,你需要做的就是计算余弦相似度。Scikit-Learn 库有一个 pairwise_distances 函数,可以为我们计算余弦。该函数返回一个正方形矩阵,将每个产品与其他产品进行比较。

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

这里我们必须注意到,我们的推荐者矩阵不再有用户信息。当我们的稀疏矩阵携带用户输入时,成对距离函数将其转换成推荐者矩阵。推荐矩阵是一个方阵,它只有每个产品之间的余弦相似性信息。

该推荐者矩阵也没有项目标题。我们可以从 pivot_table 中获取这些标题,并将其与推荐者矩阵组合在一个大的快乐数据框架中。

这里需要注意的另一个重要事项是,与实际的余弦相似性值不同,scipy 库的*。pairwise _ distance()函数以不同的比例返回相似性数字。通常,余弦相似标度在-1 和 1 之间。如前所述,余弦相似度=1 意味着项目具有非常相似的接受度,余弦相似度= -1 意味着项目具有完全相反的接受度。在的结果中。pairwise _ distance()*函数,但这是完全不同的。当我们在推荐矩阵中看到“0”时,我们知道这些项目是相似的,当我们看到“1”时,我们知道这些项目非常不相似。因此,*scipy . pairwise _ distances()*函数的余弦值介于 0 和 1 之间。

希望这篇文章有助于你理解推荐系统背后的算法。如果您有任何问题或意见,请在下面留下您的评论。

定制 Vim 以充分利用它

原文:https://towardsdatascience.com/customising-vim-to-get-the-best-out-of-it-a5a4dae02562?source=collection_archive---------14-----------------------

.vimrc中设置默认值以提高效率

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

照片由 Marius NiveriUnsplash 上拍摄

Vim 的命令是这样的,它的全部功能仅使用键盘就能实现。但是这并不容易。需要一段时间来适应。毕竟是各种程序员都信誓旦旦的编辑器。

作为刚接触 Vim 的程序员,我们经常在终端中偶然发现它,完全被新的编辑界面所迷惑,感觉完全不知所措,敲打键盘键以弄清楚如何管理 Vim。难怪“如何退出 Vim”一直是堆栈溢出过去最受欢迎的问题之一。

当开始使用 Vim 时,真正重要的是首先创造一个让人们使用 Vim 感到舒适的环境。如果没有配置任何默认设置,Vim 看起来一点也不吸引人,您也不太可能使用 Vim。这意味着您最终会错过这个极其强大的模态编辑器,这对程序员来说是一个巨大的损失。

Vim 是高度可定制的,它应该可以帮助你编辑;而不是相反。因此,让我们进入一些设置,让 Vim 有宾至如归的感觉。

  • syntax on:开启语法高亮显示。毫无疑问,需要打开这个设置。
  • colorscheme desert:该设置使用“沙漠”配色方案突出显示语法。我个人很喜欢。
    获取所有可用配色方案的列表:
    ls -l /usr/share/vim/vim*/colors/
    有很多选项可供选择!我在另一篇博客文章这里中更详细地讨论了语法突出显示(在标题 语法突出显示 下)。
  • set showmatch:当文本指示器在匹配的大括号上时,显示匹配的大括号
  • set number:显示行号
  • set relativenumber:在numberrelativenumber都设置的情况下,当前行显示该行的实际编号,其上下的行相对于当前行进行编号。这有助于了解在行与行之间上下跳动的确切数字。
  • set ignorecase:该设置使搜索不区分大小写
  • set smartcase:该设置使搜索不区分大小写,但如果搜索包含任何大写字母,则区分大小写。
  • set incsearch:此设置允许在您键入时搜索,而不是只在您按回车键时搜索
  • 这是一个非常烦人的设置,但是对于 Vim 新手来说非常有用(是的,我打开了这个设置)。它不鼓励使用箭头键在 Vim 中浏览文本,并提示您使用hjkl键。一开始你会行动缓慢,但慢慢地这将成为你的第二天性。
**" comments in vimrc start with "
" in normal mode**
nnoremap <Left>  : echoe "Use h" <CR>
nnoremap <Right> : echoe "Use l" <CR>
nnoremap <Up>    : echoe "Use k" <CR>
nnoremap <Down>  : echoe "Use j" <CR>**" in insert mode**
inoremap <Left>  : echoe "Use h" <CR>
inoremap <Right> : echoe "Use l" <CR>
inoremap <Up>    : echoe "Use k" <CR>
inoremap <Down>  : echoe "Use j" <CR>
  • 编辑:另一个必须在.vimrc中设置的是缩进行。我花了很长时间试图找到一个允许缩进的选项,类似于 Visual Studio 或 Sublime,但还没有找到一个有效的。同时,set autoindent肯定会使在 Vim 中编辑比以前容易得多。

将这些设置添加到您的.vimrc文件中,并注意不同之处!您肯定会发现现在在 Vim 中编辑文本更有吸引力了!

点击 查看第 2 部分 中一些非常需要的补充内容!

参考

使用 purrr 和 ggplot2 可定制 R 中的关联热图

原文:https://towardsdatascience.com/customizable-correlation-plots-in-r-b1d2856a4b05?source=collection_archive---------6-----------------------

不用任何相关绘图包制作高质量的相关图

如果你曾经觉得被R中的关联热图包所限制,这篇文章将向你展示如何编写你自己的函数来将众多的关联整理成一个ggplot2友好的绘图形式。

最后,您将能够运行一个函数来获得一个整理好的相关性数据框架。然后,您可以在这个数据框上运行ggplot2代码来制作您自己的关联热图。

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

如果你只是想要代码,你可以跳到最后。你也可以在我的网站上阅读我的其他博客文章, KHstats

我真的很感激一些允许我使用R超快速地制作相关图的包和函数。这里有几个例子:

corrplot::corrplot(cor(mtcars))

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

corrgram::corrgram(mtcars)

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

ggcorrplot::ggcorrplot(cor(mtcars))

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

所有这些都很好,但没有一个最终能像我需要的那样可定制。接下来我将展示如何绕过使用其他人的函数约束,以一种ggplot2友好的格式在数据中准备相关性。

我们可以使用基本的R函数cor()来得到我们的相关性,但是我不喜欢缺省的数据。相反,我使用 Frank Harrell 的Hmisc::rcorr()函数有两个原因:

  1. 默认情况下,它会丢弃丢失的对
  2. 它返回 p 值,因此只需要一个函数就可以获得相关系数和匹配的 p 值

让我们加载我们为此需要的库,它们是使用kable显示表格的knitrtidyverse(我们将具体使用tidyrdplyrggplot2tibblepurrr)。

library(knitr) library(tidyverse, warn.conflict=F)

首先,让我们看看我们将使用的相关函数的输出,Hmisc::rcorr()。它要求输入是一个矩阵,并输出三个矩阵的列表。

mtcars_cor <- Hmisc::rcorr(as.matrix(mtcars))

这三个矩阵包括相关系数(默认为皮尔逊系数)、r、p 值、P以及用于每个相关的观察值数量n。让我们把每个矩阵变成一个data frame,用headkable来看前六行。

相关系数,r:

data.frame(mtcars_cor$r) %>% head() %>% kable()

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

Pp 值:

data.frame(mtcars_cor$P) %>% head() %>% kable()

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

观察次数,n。在mtcars数据集中没有缺失数据,因此有 32 对用于所有相关。

data.frame(mtcars_cor$n) %>% head(n=3) %>% kable()

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

接下来,我们可以编写一个函数,为Hmisc::rcorr()正确格式化一个data frame,然后依次处理列表中的三个元素(rnP)

cors <- function(df) { 
   # turn all three matrices (r, n, and P into a data frame)
   M <- Hmisc::rcorr(as.matrix(df))
   # return the three data frames in a list return(Mdf)
   Mdf <- map(M, ~data.frame(.x))
  }

在这个函数中没有发生太疯狂的事情。现在我们只有三个数据帧的列表。我们可以使用first()查看列表的第一个元素,它显示了所有变量之间的相关性:

cors(mtcars) %>% first() %>% head() %>% kable()

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

下一步是准备好用ggplot2绘图的数据。我们现在可以将数据保存在一个列表中,并使用来自purrrmap()函数。

首先,我们需要使用tibble::rownames_to_column()将行名移动到它们自己的列中。的输出如下所示:

cors(mtcars) %>% 
   map(~rownames_to_column(.x, var="measure1")) %>%
   # look at the first element of the list (r)
   first() %>%
   head() %>%
   kable()

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

接下来,我们可以使用tidyr::pivot_longer()将列移动到名为measure2的单个列

cors(mtcars) %>%
 map(~rownames_to_column(.x, var="measure1")) %>%
 # format each data set (r,P,n) long
 map(~pivot_longer(.x, -measure1, "measure2")) %>%
 # look at the first element of the list (r)
 first() %>%
 head() %>%
 kable()

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

现在,我们准备使用bind_rows()取消数据列表。这将把我们的相关性变成一个很长的数据帧,所有的行从r开始,然后是n,然后是P

cors(mtcars) %>%
 map(~rownames_to_column(.x, var="measure1")) %>%
 # format each data set (r,P,n) long 
 map(~pivot_longer(.x, -measure1, "measure2")) %>%
 # merge our three list elements by binding the rows
 bind_rows(.id = "id") %>%
 head() %>%
 kable()

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

对于ggplot2,我们需要将rnP作为它们自己的列。我们可以用pivot_longer()来做到这一点。

cors(mtcars) %>%
 map(~rownames_to_column(.x, var="measure1")) %>%
 # format each data set (r,P,n) long 
 map(~pivot_longer(.x, -measure1, "measure2")) %>%
 # merge our three list elements by binding the rows
 bind_rows(.id = "id") %>%
 pivot_wider(names_from = id, values_from = value) %>%
 head() %>%
 kable()

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

最后,我们可以添加一些列,这些列在以后可能会对我们的相关图提供更多信息非常有用。让我们添加告诉我们 p 值是否小于 0.05 的列,如果是,返回 1)p 值和 2)相关系数,以防我们想要用这些值标记我们的图。

cors(mtcars) %>%
 map(~rownames_to_column(.x, var="measure1")) %>%
 # format each data set (r,P,n) long 
 map(~pivot_longer(.x, -measure1, "measure2")) %>%
 # merge our three list elements by binding the rows
 bind_rows(.id = "id") %>%
 pivot_wider(names_from = id, values_from = value) %>%
 mutate(sig_p = ifelse(P < .05, T, F), p_if_sig = ifelse(P <.05, P, NA), r_if_sig = ifelse(r <.05, r, NA)) %>% 
 head() %>%
 kable()

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

这似乎是我想画的所有东西。当然,你可以添加更多。在这一点上,我将我的格式化相关性转换成一个函数:

formatted_cors <- function(df){
 cors(df) %>%
 map(~rownames_to_column(.x, var="measure1")) %>%
 map(~pivot_longer(.x, -measure1, "measure2")) %>% 
 bind_rows(.id = "id") %>%
 pivot_wider(names_from = id, values_from = value) %>%
 mutate(sig_p = ifelse(P < .05, T, F), p_if_sig = ifelse(P <.05, P, NA), r_if_sig = ifelse(P <.05, r, NA)) 
}

我们可以测试该功能是否如预期的那样工作:

formatted_cors(mtcars) %>% head() %>% kable()

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

我们终于准备好在ggplot2中绘制我们的关联热图了。

该图最简单的形式只需要我们分别在xy轴上指定measure1measure2。然后,我们可以将相关性r映射到fill aes合成,并添加一个图块作为geom合成。

formatted_cors(mtcars) %>%
 ggplot(aes(x = measure1, y = measure2, fill = r)) +
 geom_tile()

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

我们可以做一些小的美学上的改变,比如填充颜色比例、标题和字体系列。

formatted_cors(mtcars) %>%
 ggplot(aes(x = measure1, y = measure2, fill = r)) +
 geom_tile() +
 labs(x = NULL, y = NULL, fill = "Pearson's\nCorrelation", title="Correlations in Mtcars") +
 # map a red, white and blue color scale to correspond to -1:1 sequential gradient scale_fill_gradient2(mid="#FBFEF9",low="#0C6291",high="#A63446", limits=c(-1,1)) +
 theme_classic() +
 # remove excess space on x and y axes
 scale_x_discrete(expand=c(0,0)) +
 scale_y_discrete(expand=c(0,0)) +
 # change global font to roboto
 theme(text=element_text(family="Roboto"))

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

我们可以添加额外信息的相关性。对于这个特殊的图,我只添加了显著的(p 值小于 0.05)相关性,使用从formatted_cors()输出的列r_if_sig

formatted_cors(mtcars) %>% 
 ggplot(aes(measure1, measure2, fill=r, label=round(r_if_sig,2))) +
 geom_tile() +
 labs(x = NULL, y = NULL, fill = "Pearson's\nCorrelation", title="Correlations in Mtcars", subtitle="Only significant Pearson's correlation coefficients shown") + scale_fill_gradient2(mid="#FBFEF9",low="#0C6291",high="#A63446", limits=c(-1,1)) +
 geom_text() +
 theme_classic() +
 scale_x_discrete(expand=c(0,0)) +
 scale_y_discrete(expand=c(0,0)) +
 theme(text=element_text(family="Roboto"))

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

另一个版本可以包括不同大小的正方形,以使用geom_point来表示相关性的强度,其中shape被设置为来自这些可用的 [geom_shape](http://www.sthda.com/english/wiki/ggplot2-point-shapes) s值。一定要取相关的绝对值,这样强的负相关也可以表示得更大。

formatted_cors(mtcars) %>%
 ggplot(aes(measure1, measure2, col=r)) +
 ## to get the rect filled geom_tile(col="black", fill="white") + geom_point(aes(size = abs(r)), shape=15) + labs(x = NULL, y = NULL, col = "Pearson's\nCorrelation", title="Correlations in Mtcars") + theme_classic() +
 scale_color_gradient2(mid="#FBFEF9",low="#0C6291",high="#A63446", limits=c(-1,1)) +
 scale_x_discrete(expand=c(0,0)) +
 scale_y_discrete(expand=c(0,0)) +
 theme(text=element_text(family="Roboto")) +
 scale_size(range=c(1,11), guide=NULL)

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

cors <- function(df) {
 M <- Hmisc::rcorr(as.matrix(df)) 
 Mdf <- map(M, ~data.frame(.x)) return(Mdf) }formatted_cors <- function(df){
 cors(df) %>%
 map(~rownames_to_column(.x, var="measure1")) %>%
 map(~pivot_longer(.x, -measure1, "measure2")) %>% 
 bind_rows(.id = "id") %>%
 pivot_wider(names_from = id, values_from = value) %>%
 mutate(sig_p = ifelse(P < .05, T, F), p_if_sig = ifelse(P <.05, P, NA), r_if_sig = ifelse(P <.05, r, NA)) }formatted_cors(mtcars) %>% 
 ggplot(aes(measure1, measure2, fill=r, label=round(r_if_sig,2))) +
 geom_tile() + 
 labs(x = NULL, y = NULL, fill = "Pearson's\nCorrelation", title="Correlations in Mtcars", subtitle="Only significant Pearson's correlation coefficients shown") + 
 scale_fill_gradient2(mid="#FBFEF9",low="#0C6291",high="#A63446", limits=c(-1,1)) +
 geom_text() +
 theme_classic() +
 scale_x_discrete(expand=c(0,0)) + 
 scale_y_discrete(expand=c(0,0)) +
 theme(text=element_text(family="Roboto"))

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

原载于 2020 年 3 月 15 日https://www.khstats.com

自定义分类模型输出层

原文:https://towardsdatascience.com/customize-classification-model-output-layer-46355a905b86?source=collection_archive---------24-----------------------

使用 Keras 在自定义层中保存分类标签和最高机密

图像分类是深度学习应用的手册示例。制作分类模型的标准方法包括预处理步骤,在该步骤中,人类可读的类标签(例如:“汽车”、“人”、“猫”)被改变成机器可用的数字(例如:0,1,2)。最常见的方法是将可能的类列表与它们的索引进行映射。当然,这也需要一个后处理步骤,将结果转换成预期的形式。一种常见的方法是存储具有最高分数的类的标签和分数(对此广泛使用的术语是置信度)。

在这个故事中,我将展示一个在模型末尾使用自定义图层在模型中存储标签的示例。我的模型的首选输出是前 k 标签及其置信度得分的列表。格式化的输出在产品是模型的生产中是有用的,并且标签必须存储在模型中。或者,当标签列表随着模型的每次迭代而改变时。

Input: image(W,H,C) Outputs: labels(k) string, confidences(k) float

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

照片由大卫·兰格尔Unsplash 上拍摄

训练分类模型

对于这个故事,我将使用一个简单的分类模型。这个 Colab 笔记本展示了一个在时尚 MNIST 数据集上训练的分类器的例子(在 60000 张图片上训练,在 10000 张图片上测试)。该模型预期 28x28x1 灰度图像,并返回 10 类的 softmax 概率。类别标签列表包括:

class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat', 'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

处理模型输出的一种简单方法是简单的映射:找到得分最高的索引并使用该索引的标签。

class_names[np.argmax(predictions[0])]获取图像的标签 0。

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

时尚 MNIST 范例(作者 Zalando,麻省理工学院许可)。

构建自定义图层

要了解如何在 Keras 中制作自定义图层,建议阅读 Keras 和 TensorFlow 中的原始文档

我想实现一个自定义层来存储labels 和一个topn值,这样该层的输出可以是前 n 个置信度标签及其分数。为此,我们必须覆盖图层的__init__callcompute_output_shapeget_config 功能。

带有标签和 Top_k 选择的自定义图层

初始化

在 init 函数中,我们将构造函数参数存储为类的字段。不要忘记调用父类的构造函数!super(LabelLimitLayer, self).__init__(**kwargs)

打电话

call 函数期望前一层的输出作为输入,并计算top_k 类及其标签。为此,我使用了张量流函数。

为了从标签列表中创建一个(?,len(labels)) 形状的张量,我们首先使用列表(我们自定义类的参数)创建一个张量,然后使用前一层输出的形状扩展它(我们从中提取batch_size )。这些步骤是:

tf_labels = tf.constant([self.labels], dtype=”string”)弦型张量
tf_labels = tf.tile(tf_labels,[batch_size,1])展开得到(?1)处理批次的动态形状。

为了选择最高的 k 个分数,我使用了相应的 TensorFlow 函数。我们存储这些指数,这样我们就可以映射这些指数的标签以及置信度值。
top_k = tf.nn.top_k(x, k=self.topn, sorted=True, name=”top_k”).indices

为了使用一个张量的索引来获取另一个张量的值,我使用了 tf.gather 函数。
top_conf = tf.gather(x, top_k, batch_dims=1) top_labels = tf.gather(tf_labels, top_k, batch_dims=1)

最后,该层返回最后两个张量。
return [top_conf, top_labels]

计算输出形状

由于有两个输出张量,Keras 层不能自动计算输出形状。好在可以这样计算:
top_shape = (batch_size, self.topn) return [top_shape, top_shape]

获取配置

为了序列化定制层(当保存模型时),必须用类参数的值更新配置。不要忘记将超类的配置添加到字典中!

将输出图层添加到模型

在这个例子中,我在基本分类模型的末尾添加了一个自定义层,带有标签(class_names)和 top_k 值(2)。

label_layer = LabelLimitLayer(class_names, 2)(base_model.output) label_model = Model(base_model.input, label_layer)

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

时尚 MNIST 数据集中的预测标签

保存和加载模型

最后,为了保存一个模型,我们可以使用 Keras 模型的 save 函数。要加载带有自定义层的模型,必须在custom_objects 参数中定义该自定义层。

label_model.save(‘test.h5’) restored_model = keras.models.load_model(“test.h5”, custom_objects={“LabelLimitLayer”:LabelLimitLayer})

摘要

这个片段展示了如何使用 Keras 自定义层来创建字符串标签作为模型的输出。这个故事还使用 top_k 只保留相关的类。相应的代码可在这款 Colab 笔记本上找到。

定制损失函数,使 LSTM 模型更适用于股票价格预测

原文:https://towardsdatascience.com/customize-loss-function-to-make-lstm-model-more-applicable-in-stock-price-prediction-b1c50e50b16c?source=collection_archive---------10-----------------------

损失函数不要只考虑价格差异,方向损失也很重要!!!

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

尼克·崇在 Unsplash 上的照片

背景

这里有很多在线教程或文章教你如何建立一个 LSTM 模型来预测股票价格。无论是简单的还是复杂的,我们都可以以某种方式获得一个“想要的”结果,类似于下图(图表 1)。是的,如果我们简单地通过查看均方差(MSE)来判断模型,这是可取的。

但是,在现实世界的交易中,做得好就能帮我们赚大钱吗?很遗憾,答案总是否定的。在本文中,我们将尝试定制损失函数,使我们的 LSTM 模型更适用于现实世界。

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

附件 1——基于简单 LSTM 模型的汇丰(0005.HK)股票价格预测

面临的问题

我这不是因为教程出了问题或者模型训练得不够好。但是从根本上说,有几个主要的限制很难解决。

1.所有免费库只提供每日股价数据没有实时数据,我们不可能在当天执行任何订单

2.常用的损失函数(MSE)是一个纯粹的统计损失函数*——纯粹的价格差异不代表全貌*

  1. LSTM 模型或任何其他递归神经网络模型始终是一个黑箱*——交易策略只能基于没有任何理由支持的价格运动,并且这些策略很难扩展到投资组合分配*

如果没有更多的资源,限制(1)和(3)很难解决。对于(1),解决方案可能是连接到实时交易数据提供商,如彭博,然后训练出一个实时 LSTM 模型。下一秒的交易指令可以自动下达。但是很遗憾地说,如果你不在交易大厅工作,很难做到这一点。

对于(3),如果旨在通过一些解释扩展到投资组合分配,可能其他概念如均值-方差优化、一些稳健的估计量,然后考虑风险价值(VaR)更合适。但那完全是另一回事了。

在本文中,我们将指出第二个限制,并重点关注一种可能的方法— 通过考虑方向损失来定制损失函数,以使 LSTM 模型在有限的资源下更适用。

存在的困难

L et 回到上图(附表 1)。它看起来很完美,表明该模型的预测能力非常高。诚然,在训练 300 个历元后,其训练损失的 MSE 仅为 0.000529,但其预测第二天价格运动方向的准确性仅为 0.449889 ,甚至低于抛硬币!!!

MSE 主要关注真实价格和预测价格的差异,而不考虑预测的方向是否正确。如果我们应用基于 LSTM 模型预测的卖出/买入期权这样的交易策略,这一特征会造成巨大的麻烦。从这个角度来看,应该强调方向的正确性。

此外,该模型是基于给定数据可用性的每日价格,并试图预测第二天的收盘价,这并没有捕捉到当天的价格波动。在这种情况下,方向的准确性甚至比价格差异更重要。甚至有些日子你可能会赚得少,但至少不会导致金钱损失。

方法论

N 现在,我们开始自定义损失函数。关于数据预处理的细节以及如何建立简单的 LSTM 模型股票预测,请参考 Github 链接这里。完整的代码也可以在那里找到。

步骤 1:从损失函数的输入张量中提取必要的信息

def **custom_loss**(y_true, y_pred):

	*#extract the "next day's price" of tensor*
	y_true_next = y_true[1:]
	y_pred_next = y_pred[1:] *#extract the "today's price" of tensor* 	y_true_tdy = y_true[:-1]
	y_pred_tdy = y_pred[:-1]

永远记住损失函数的输入是两个张量, y_true (真实价格)和 y_pred (预测价格)。首先,我们必须创建四个新的张量来存储来自两个输入传感器的“第二天的价格”和“今天的价格”,以备将来使用。

第二步:创建新的张量来记录价格运动(涨/跌)

*#substract to get up/down movement of the two tensors*
y_true_diff = tf.subtract(y_true_next, y_true_tdy)
y_pred_diff = tf.subtract(y_pred_next, y_pred_tdy)*#create a standard tensor with zero value for comparison*
standard = tf.zeros_like(y_pred_diff)*#compare with the standard; if true, UP; else DOWN*
y_true_move = tf.greater_equal(y_true_diff, standard)
y_pred_move = tf.greater_equal(y_pred_diff, standard)

TF . subtract是从 y_true_next 张量中减去 y_true_tdy 张量中的元素值。然后,我们将两个差分张量( y_true_diffy_pred_diff )与标准零张量进行比较。如果该值大于或等于零,则属于向上运动,否则属于向下运动。 tf.greater_equal 将返回一个布尔张量。

第三步:找出两个张量运动方向不同时的指标

*#find indices where the directions are not the same*
condition = tf.not_equal(y_true_move, y_pred_move)
indices = tf.where(condition)ones = tf.ones_like(indices)
indices = tf.add(indices, ones)

(a)TF . not _ equal比较两个布尔张量 y_true_movey_pred_move ,生成另一个新的布尔张量——条件。如果第二天的方向在真实运动和预测运动之间相同,则返回,否则返回

(b)在条件张量中 tf.where 返回“真”的位置。

©TF . add索引张量中的每个元素加 1。如果您足够仔细,您可能会注意到任何处理过的张量的形状都是(49,1),比原始输入的形状(50,1)短一个单位。加 1 意味着我们在一天后移动索引,这代表了第二天在原始输入张量中的真实位置。

第四步:创建一个张量来存储方向损耗,并将其放入自定义损耗输出

direction_loss = tf.Variable(tf.ones_like(y_pred), dtype='float32')
updates = K.cast(tf.ones_like(indices), dtype='float32')
alpha = 1000
direction_loss = tf.scatter_nd_update(direction_loss, indices, alpha*updates)custom_loss = K.mean(tf.multiply(K.square(y_true - y_pred), direction_loss), axis=-1)

现在,我们正在创建最重要的张量—direction _ loss*。由于它应该是一个可训练的张量并被放入最终输出custom _ loss,*它必须被设置为一个变量张量,使用 tf.Variable.

张量 索引 存储了真实价格和预测价格之间方向不匹配的位置。通过TF . scatter _ nd _ update,我们可以通过指定位置来更新张量direction _ loss中的值,并用新值替换。但是请记住,索引和更新的形状必须相同。direction _ loss的最终乘积是一个值为 1 或 1000 的张量。

最后,我们用 方向损失 张量乘以真实价格和预测价格的平方差。这里的概念是,如果当天的真实价格和预测价格之间的方向匹配,我们将损失保持为平方差。如果不匹配,那么我们用α(1000)乘以差值的平方。

**最后,定制的损失函数完成。**我们现在已经考虑了预测价格是否与真实价格同向。如果我们应用具有相同设置(批量:50,时期:300,时间步长:60)的 LSTM 模型来预测汇丰银行(0005。HK),预测价格方向的精度从 0.444343 提高到 0.561158。这是一个很大的进步,但仍远非完美。如果我们想建立一个更好的损失函数,我们将在本文的最后部分讨论一些需要克服的障碍。

一些可以帮你节省时间的技巧

M 大多数时候,我们可能要用和上面完全不同的概念来定制损失函数。以下是一些技巧,可以帮助您节省时间或跟踪过程中的错误。

(a)get _ shape—当你不确定张量的形状时,毫不犹豫地用这个函数把它打印出来。几乎所有的处理函数都要求所有输入张量的形状相同。

(b)keras . back end . cast—当错误消息称张量中的元素格式与其他元素不匹配时,尝试使用此功能将张量的元素格式更改为特定类型。

©tensor flow . reshape—当错误消息称形状与原始输入不匹配时,应保持(x,1)的一致形状,尝试使用此函数 tf.reshape(tensor,[-1]) 展平张量。

(d)custom _ loss—记住,最终产品必须由两个输入的张量 y_truey_pred 组成,并将返回到 LSTM 模型的主体进行编译。

需要克服更多障碍…

他的成绩现在已经有了很大的进步,但还远远不够完美。然而,要更进一步,许多障碍在等着我们,下面是其中的一些。

(a)难以平衡价格差异和方向性损失 —如果 alpha 设置过高,您可能会发现预测价格波动很小。如果我们画出来,它几乎是一条直线。这意味着方向损耗主导了损耗函数。在这种情况下,预测的价格变得毫无意义,但只有它的方向是有意义的。我们只是在打赌第二天的价格是上涨还是下跌。

(b)难以将分类分类器应用于股票价格预测—你们中的许多人可能会发现,如果我们只是简单地押注价格运动(上涨/下跌),那么我们为什么不应用分类分类器来做预测,或者将损失函数变成TF . binary _ cross entropy*。很抱歉,结果没有任何改善。我试过先把所有的价格数据转换成用 0(跌)或 1(涨)表示的“运动数据”,输入进行训练。但是由于数据的本质是时间序列,与手写识别不同,每个训练批次中的 0 或 1 数组不足以进行第二天价格运动的预测。一些方法,如支持向量机(SVM)和卷积神经网络(CNN),在分类中表现很好,但很难应用于这种情况。*

© Alpha 对每只股票来说都非常具体——我曾试图将相同的模型应用于其他 10 只股票的股价预测,但并不是所有股票都有很大的改善。对于每一只股票来说,价差和方向性亏损之间的关系似乎非常独特。所以我们可能要花很多时间来找出每只股票的最佳组合。

结论

从最小化均方误差的角度出发,建立一个理想的 LSTM 模型来预测股票价格总是不难的。但是它在现实世界中并不适用。本文介绍了一种可能的方法——通过考虑方向损耗来定制损耗函数,并讨论了在此过程中的一些困难并提供了一些建议。我希望它将开启关于如何改进我们的 LSTM 模式的讨论。如前所述,如果我们想更进一步,就必须克服许多障碍,特别是在资源有限的情况下。

这篇文章也是我第一次在媒体上发表。在未来,我将尝试探索更多关于数据科学和机器学习技术在经济和金融领域的应用。感谢支持!!!

参考

  1. 阿苏托什·纳亚克。(2019).用 LSTM 预测股票价格
  2. Dhiraj K. (2019)。如何在 Keras 中创建自定义损失函数
  3. 埃亚尔·扎凯。(2019).高级 Keras——构建复杂的客户损失和指标

[## 用我的推荐链接加入媒体-哈德森高

如果你对我写的东西感兴趣,不要错过成为 Medium 会员的机会。您将可以完全访问所有…

medium.com](https://medium.com/@hudsonko/membership)

在 Matplotlib 中自定义多个子情节

原文:https://towardsdatascience.com/customizing-multiple-subplots-in-matplotlib-a3e1c2e099bc?source=collection_archive---------5-----------------------

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

Unsplash 上由 Aron 视觉拍摄的照片

入门

使用 subplot、add_subplot 和 GridSpec 在 Matplotlib 中创建复杂 subplot 的指南

在某些时候,我们需要将我们的数据可视化成复杂的图形,因为我们应该这样做或者制作一个伟大的图形。例如,您想在绘图中制作一个缩放效果,如图 1 所示。为了呈现它,你需要建立一个复杂的次要情节。图 1 由三个不同的轴构成:轴 1、轴 2 和轴 3。Axes1 在左上角的面板上,用绿色的绘图线显示数据,axes2 在右上角的面板上,用橙色的线显示数据,最大的 axes3 位于底部的面板上。

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

**图一。**Matplotlib 中的缩放效果(图片作者)。

在创建复杂的图之前,你需要知道 Matplotlib 中的术语之间的区别。为此,您可以了解 Matplotlib 中定义的图形的结构,如图 2 所示。

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

**图二。**Matplotlib 中图形和轴的区别(图片由作者提供)。

被定义为所有元素的主容器,如轴、图例、标题等。一个图形可以包含一些轴(我们将更深入地了解它)。在图 1 中,我们只有一个图形,它包含三个轴。如果您想在 Maptlotlib 中创建缩放效果,请访问此链接。

[## 使用 Matplotlib 可视化数据的 5 个强大技巧

如何使用 LaTeX 字体,创建缩放效果,发件箱图例,连续错误,以及调整框填充边距

towardsdatascience.com](/5-powerful-tricks-to-visualize-your-data-with-matplotlib-16bc33747e05)

使用子情节在图形中创建简单的轴

在这一节中,我们将学习 Matplotlib 中子情节的基本原理。我将展示给你的一些例子不是现实的情节,但它将成为理解支线剧情的好例子。

要创建轴,至少可以使用两种不同的方法。第一种可以使用语法 支线剧情 ,第二种是使用 gridspec。 在开始学习 支线剧情 的时候,我会给你看一个简单的支线剧情,如图 3。

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

**图 3。**Matplotlib 中的一个简单支线剧情(图片由作者提供)。

您可以使用以下代码生成图 3

import matplotlib.pyplot as pltfig = plt.figure()
coord = 111
plt.subplot(coord)
plt.annotate('subplot ' + str(coord), xy = (0.5, 0.5), va = 'center', ha = 'center')

理解 Matplotlib 中子绘图的一件重要事情是定义轴的坐标。上面代码中的变量 coord 是 111。它由代表行数、列数和轴序列的三个数字组成。 coord 111 的意思是,你生成一个由一行一列组成的图形,你在第一个序列轴中插入子情节。因为你只有一行一列(这意味着你只有一个单元格),你的轴是主要的图形。您也可以在没有子图语法的情况下生成图 3,因为您在一个图形中只生成一个轴。

下一步是在图形中创建两个水平轴,如图 4 所示。您可以使用这段代码来生成它

fig = plt.figure(figsize=(12, 4))
coord1 = 121
coord2 = 122plt.subplot(coord1)
plt.annotate('subplot ' + str(coord1), xy = (0.5, 0.5), va = 'center', ha = 'center')plt.subplot(coord2)
plt.annotate('subplot ' + str(coord2), xy = (0.5, 0.5), va = 'center', ha = 'center')

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

**图 4。**图中两个横轴(图片由作者提供)。

您需要定义图形大小来创建一个漂亮的两个水平轴。如果你不这样做,你会得到一个类似数字 5 的数字。

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

**图 5。**一个图形中的两个横轴,没有定义图形大小(图片由作者提供)。

如果要创建两个垂直轴,只需更改坐标 1 和坐标 2,如以下代码所示

fig = plt.figure(figsize=(6, 7))
coord1 = 211
coord2 = 212plt.subplot(coord1)
plt.annotate('subplot ' + str(coord1), xy = (0.5, 0.5), va = 'center', ha = 'center')plt.subplot(coord2)
plt.annotate('subplot ' + str(coord2), xy = (0.5, 0.5), va = 'center', ha = 'center')

现在,我将尝试使用循环在一个图形中创建更多的支线剧情。我将创建 2x4 轴,如图 6 所示。

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

**图 6。**在 Matplotlib 中使用循环创建一个简单的子情节(图片由作者提供)。

您可以使用这段代码重现图 6

fig = plt.figure(figsize=(16, 6))coord = []# create coord array from 241, 242, 243, ..., 248 
for i in range(1, 9): # in python, 9 is not included
    row = 2
    column = 4
    coord.append(str(row)+str(column)+str(i))

# create subplot 241, 242, 243, ..., 248
for i in range(len(coord)):
    plt.subplot(coord[i])
    plt.annotate('subplot ' + str(coord[i]), xy = (0.5, 0.5), va = 'center', ha = 'center')

因为你要创建 8 个轴(2 行 4 列),所以你需要做一个从 241 到 248 的数组。之后,使用与前面代码相同的过程创建子情节,但是将它放在循环语法中。

用 gridspec 在图形中创建简单轴

正如我之前提到的,除了使用 subplot 在图形中创建一些轴,还可以使用 gridspec。例如,如果您想用 gridspec 创建图 6(两行 4 列),您可以使用下面的代码

import matplotlib.pyplot as pltfig = plt.figure(figsize=(16, 6))rows = 2
columns = 4grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)for i in range(rows*columns):
    exec (f"plt.subplot(grid{[i]})")
    plt.annotate('subplot 24_grid[' + str(i) + ']', xy = (0.5, 0.5), va = 'center', ha = 'center')

要使用 gridspec 创建简单的子情节,首先要定义行数和列数。要将支线剧情嵌入到图中,你只需调用支线剧情的编号。在 gridspec 中,子情节的数量从 0 开始,而不是从 1 开始。所以,如果要使用 gridspec 在一个图中嵌入 8 列,需要从 0 到 7 调用它们,使用PLT . subplot(grid[0])直到PLT . subplot(grid[7])。在循环中,你会遇到一个问题,因为你想用[]调用网格号。要处理它,可以使用语法exec(f "…{[I]} "

图 7 是使用 gridspec 创建 8 个轴的结果

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

**图 7。**在 Matplotlib 中使用 gridspec + looping 创建一个简单的子情节(图片由作者提供)。

使用 gridspec 的一个好处是你可以用比只使用支线剧情更简单的方式创造更多支线剧情。例如,如果您想在一个图形中创建 10 个以上的支线剧情,您将定义最后一个坐标。子情节仅由三个数字组成,例如 111、428、439 等。一个支线剧情无法促成第四个。例如,您想在一个图形中创建 18 个轴(3 行 6 列)。如果只使用支线剧情,需要定义 361,362,263,…,3616。当你嵌入一个 3610 的支线剧情时,你将面临错误。要解决它,可以使用 gridspec。图 8 展示了使用 gridspec 创建 18 个轴。

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

**图 8。**在 Matplotlib 中使用 gridspec + looping 创建简单的 18 个支线剧情(图片由作者提供)。

您可以用这段代码创建图 8

fig = plt.figure(figsize=(22, 8))rows = 3
columns = 6grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)for i in range(rows*columns):
    exec (f"plt.subplot(grid{[i]})")
    plt.annotate('subplot 36_grid[' + str(i) + ']', xy = (0.5, 0.5), va = 'center', ha = 'center')

为了做一个更真实的例子,我将在图 8 中为每个轴插入一个图。所以,我需要为每个轴做 18 个不同的函数。它是由***【sin(x^(i/9】)***的函数编译而成,其中 i 是从 0 到 17 的网格数。您可以在图 9 中看到该图。

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

**图九。**Matplotlib 中更现实的支线剧情(图片由作者提供)。

要创建图 9,您可以使用下面的代码

fig = plt.figure(figsize=(25, 10))color = ['#00429d', '#2754a6', '#3a67ae', '#487bb7', '#548fc0', 
         '#5ea3c9', '#66b8d3', '#6acedd', '#68e5e9', '#ffe2ca', 
         '#ffc4b4', '#ffa59e', '#f98689', '#ed6976', '#dd4c65', 
         '#ca2f55', '#b11346', '#93003a']rows = 3
columns = 6grid = plt.GridSpec(rows, columns, wspace = .25, hspace = .25)for i in range(rows*columns):
    np.random.seed(100)
    x = np.linspace(0., 5., 100)
    y = np.sin(x**(i / 9)) + np.random.random() * i

    exec (f"plt.subplot(grid{[i]})")

    plt.plot(x, y, color = color[i])

要用不同的颜色呈现,还需要定义 18 种不同的颜色。您可以使用这个链接来生成它。我已经在下面的链接中解释了如何使用它。

[## 用于科学绘图的 Matplotlib 样式

为您的科学数据可视化定制 Matplotlib

towardsdatascience.com](/matplotlib-styles-for-scientific-plotting-d023f74515b4)

用 add_subplot 在图形中创建复杂轴

在本节中,我们将学习如何使用 add_subplotGridSpec 定制复杂的轴。我提到的复杂轴如图 10 所示。

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

**图 10。**Matplotlib 中复杂的轴(图片由作者提供)。

示例 1 使用 add_subplot

我们将使用 add_subplot 语法创建 3 个轴(顶部 2 个,底部 1 个),如图 1 所示。您可以使用这段代码来创建它。

如果你分析代码,你会得到一个与子情节语法概念类似的概念。您需要定义三个坐标,例如(2,2,1)或(2,2,(3,4))。 sub1 轴位于 2 行 2 列图形的第一个轴(1)上。 sub2sub1 有类似的方案。其中重要的是轴 3 和轴 4 的组合 sub3、 。所以 sub3 的坐标是(2,2,(3,4))。如果您运行上面的代码,您将得到一个结果,如图 11 所示。

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

**图 11。**Matplotlib 中第一个使用 add_subplot 的复杂轴的例子(图片由作者提供)。

如果要为每个轴添加绘图,可以在定义 sub1、sub2 和 sub3 之后添加此代码。

sub1.plot(x, y)
sub2.plot(x, y)
sub3.plot(x, y)

完整的代码在这里。

全部

您将得到一个结果,如图 12 所示。

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

**图 12。**Matplotlib 中第一个使用 gridspec 的复杂轴的例子(图片由作者提供)。

示例 1 使用 gridspec

作为替代,您也可以使用 gridspec 语法创建图 12。下面是您可以用来创建它的代码。

该代码创建了 2 行 2 列。 sub1sub2 放在第一行第 0 列第 1 列(记住 gridspec 是从 0 索引开始的)。 sub3 放在第二行,取所有列,用 : 表示。如果您运行上面的代码,您将得到相同的图,如图 12 所示。

示例 2 使用 add_subplot

复杂轴的第二个例子如图 13 所示。

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

**图十三。**Matplotlib 中使用 gridspec 的复杂轴的第二个例子(图片由作者提供)。

您将在图形中生成 4 个轴:sub1、sub2、sub3 和 sub4,共 2 行 4 列。 sub1 取第一行的所有列。 sub2、sub3 和 sub4 放置在第二行的每一列上。要生成图 12,您可以使用以下代码。

示例 2 使用 gridspec

要使用 gridspec 创建图 12,可以使用下面的代码。

我觉得上面的代码已经足够清晰易懂了:d .代码会生成一个情节,如图 14 所示。

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

**图 14。**Matplotlib 中使用 gridspec 的复杂轴的第二个例子(图片由作者提供)。

示例 3 使用 add_subplot

第三个例子如图 15 所示。

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

**图 15。**Matplotlib 中复杂轴使用 add_subplot 的第三个例子(图片由作者提供)。

要创建图 15,您可以使用以下代码。

示例 3 使用 gridspec

要使用 gridspec 创建图 15,可以使用下面的代码。

结果如图 16 所示。

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

**图 16。**Matplotlib 中使用 gridspec 的复杂轴的第三个例子(图片由作者提供)。

示例 4 使用 add_subplot

在最后一个示例中,将指导您在图形中创建 6 个轴,行数为 4,列数为 2。如图 17 所示。

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

**图 17。**Matplotlib 中复杂轴使用 add_subplot 的第四个例子(图片由作者提供)。

要用 add_subplot 创建它,可以使用下面的代码。

示例 4 使用 gridspec

要用 gridspec 创建图 17,可以使用下面的代码。

你需要注意 sub4 ,放在 1:3 行 1 列。行 1:3 意味着 sub4 将采用行号 1 和 2。请记住,不包括第 3 行。代码将生成一个图,如图 17 所示。

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

**图 18。**Matplotlib 中使用 gridspec 的复杂轴的第四个例子(图片由作者提供)。

结论

处理复杂数据时,需要创建一个复杂的绘图来可视化数据。我希望这个故事可以帮助你从不同的角度来可视化你的数据。如果你需要用 Matplotlib 创建科学发表图,可以访问这个链接

如果你喜欢这篇文章,这里有一些你可能喜欢的其他文章:

[## 使用 Matplotlib 可视化数据的 5 个强大技巧

如何使用 LaTeX 字体,创建缩放效果,发件箱图例,连续错误,以及调整框填充边距

towardsdatascience.com](/5-powerful-tricks-to-visualize-your-data-with-matplotlib-16bc33747e05) [## 用于科学绘图的 Matplotlib 样式

为您的科学数据可视化定制 Matplotlib

towardsdatascience.com](/matplotlib-styles-for-scientific-plotting-d023f74515b4) [## 在 Matplotlib 中创建色彩映射表

从颜色列表中创建和定制自己的色彩映射表的指南

towardsdatascience.com](/creating-colormaps-in-matplotlib-4d4de78a04b8) [## 使用 Matplotlib 实现 Python 数据可视化—第 1 部分

完成了从基础到高级的 Python 绘图的 Matplotlib 教程,包含 90 多个示例

towardsdatascience.com](/visualizations-with-matplotlib-part-1-c9651008b6b8) [## Vaex 大数据简介—读取 12.5 亿行的简单代码

用 Python 高效读取和可视化 12.5 亿行星系模拟数据

towardsdatascience.com](/introduction-to-big-data-a-simple-code-to-read-1-25-billion-rows-c02f3f166ec9)

仅此而已。感谢您阅读这个故事。喜欢就评论分享。我还建议您关注我的帐户,以便在我发布新故事时收到通知。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值