营销的数据科学实用指南(一)

原文:annas-archive.org/md5/40bb0ccf1a2c14d899522b1d83c83f6c

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

数据科学和机器学习在营销中的应用正在不断增长,从小型企业到大型组织都在采用这些技术。通过数据科学,你可以更好地理解过去营销策略成功与失败的驱动因素,深入了解客户的行为和他们与产品的互动方式。借助数据科学,你还可以预测客户行为,制定更具针对性和个性化的营销策略,从而实现更低的获客成本、更高的转化率以及更高的净销售额。通过本书,你将能够应用各种数据科学技术,制定数据驱动的营销策略。

本书作为一本实践指南,旨在帮助你完成从简单到复杂的营销任务。你将使用数据科学来了解推动销售和客户参与的因素。你将使用机器学习预测哪些客户更可能与产品互动,并具有最高的预期生命周期价值。你还将使用机器学习了解不同客户群体的数据,并为每个客户推荐最可能购买的产品。读完本书后,你将对各种数据科学和机器学习技术以及它们如何应用于不同营销目标有深刻的了解。

就个人而言,我本会从像这样的书籍中受益匪浅。当我开始从事数据科学和营销工作时,关于不同数据科学和机器学习技术的理论和细节有着丰富的资源,但关于如何将这些技术和方法特别应用于营销的资源却少之又少。学习这些理论与实际将其应用于现实世界中的营销业务案例是完全不同的。在本书中,我希望能分享我在将数据科学和机器学习应用于不同营销目标过程中,通过大量试错所获得的经验和知识。读完本书后,你将能很好地理解不同营销场景下所使用的技术和方法,了解哪里可以找到更多的资源,并且知道读完本书后该学习什么。

本书将使用 Python 和 R 进行数据科学和机器学习练习。如你所知,Python 和 R 是数据科学家、数据分析师和机器学习工程师最常用的两种编程语言,原因在于它们易于使用、拥有丰富的数据科学和机器学习资源,并且拥有庞大的用户社区。在每一章中,我们将指导你如何使用不同的软件包和库,并讲解如何安装它们,所以在开始本书之前,你不必担心该在计算机上安装什么。

本书适合人群

本书面向营销专业人士、数据科学家与分析师、机器学习工程师和软件工程师,他们具备一定的 Python 和 R 工作经验,并且对机器学习和数据科学有一些基础了解。即使你没有深入了解数据科学和机器学习算法背后的理论,也不用担心!本书的重点是机器学习的实际应用,旨在帮助你快速掌握相关知识,并能将其用于下一步的营销策略。如果你曾经学习过数据科学和机器学习,那么这本书将非常适合你。它将引导你如何将数据科学和机器学习的知识与经验应用于营销中的实际案例。如果你是一个对数据科学充满热情并感兴趣的营销专业人士,那么太好了!这本书将是你理想的选择。你将学到数据科学如何帮助你改进营销策略,以及如何使用预测性机器学习模型来精细调整目标营销。本书将引导你一步步地利用数据科学和机器学习来实现你的营销目标。

本书实际上是为所有热衷于将数据科学和机器学习应用于营销的人设计的。如果你有兴趣构建数据驱动的营销策略,解读数据中的客户行为,预测客户如何反应,以及预测客户会如何回应,那么你来对地方了!

本书涵盖的内容

第一章,数据科学与营销,介绍了数据科学如何应用于营销的基础知识。它将简要介绍常用的数据科学和机器学习技术,以及这些技术在制定更好营销策略时的应用方法。还会介绍如何为即将开展的项目配置 Python 和 R 环境。

第二章,关键绩效指标与可视化,讲解了营销中需要跟踪的一些关键绩效指标KPIs)。本章讨论了如何使用 Python 和 R 来计算这些 KPIs,以及如何构建这些 KPIs 的可视化。

第三章,营销参与度背后的驱动因素,展示了如何使用回归分析来理解客户参与的驱动因素。本章介绍了如何在 Python 和 R 中拟合线性回归模型,并如何从模型中提取截距和系数。通过回归分析获得的洞察,我们将探讨如何利用这些信息潜在地改善营销策略,以提高参与度。

第四章,从参与到转化,讨论了如何使用不同的机器学习模型来理解什么驱动了转化。本章介绍了如何在 Python 和 R 中构建决策树模型,以及如何解释结果并提取转化背后的驱动因素。

第五章,产品分析,带你完成探索性的产品分析。本章引导你通过在 Python 和 R 中使用各种数据聚合和分析方法,深入了解产品的趋势和模式。

第六章,推荐合适的产品,介绍了如何提高产品的可见性,并推荐个别客户最有可能购买的产品。它讨论了如何在 Python 和 R 中使用协同过滤算法来构建推荐模型。然后,介绍了如何将这些推荐应用于营销活动。

第七章,客户行为的探索性分析,进一步深入数据分析。本章讨论了分析客户行为和与产品互动的各种指标。通过使用 Python 和 R,本章扩展了你的知识,涉及到数据可视化和不同的图表技术。

第八章,预测营销参与的可能性,讨论了如何构建机器学习模型来预测客户参与的可能性。本章介绍了如何使用 Python 和 R 训练机器学习算法。然后,讨论了如何评估模型的性能,以及如何将这些模型应用于实现更精准的目标营销。

第九章,客户生命周期价值,介绍了如何获取个别客户的生命周期价值。本章讨论了如何在 Python 和 R 中构建回归模型并评估它们。还会介绍如何利用计算出的客户生命周期价值来制定更好的营销策略。

第十章,数据驱动的客户细分,深入探讨了如何使用数据驱动的方法进行客户细分。本章介绍了聚类算法,使用 Python 和 R 从数据中构建不同的客户群体。

第十一章,保持客户,讨论了如何预测客户流失的可能性,并重点介绍了如何在 Python 和 R 中构建分类模型以及如何评估其性能。本章将讲解如何在 Python 和 R 中使用keras库构建人工神经网络ANN)模型,这是深度学习的核心。

第十二章,更好的营销策略中的 A/B 测试,介绍了一种基于数据驱动的方法,帮助做出更好的营销策略决策。本章讨论了 A/B 测试的概念以及如何使用 Python 和 R 进行实施和评估。接着讨论了 A/B 测试在实际营销策略中的应用和益处。

第十三章,下一步是什么?,总结了本书中讨论的内容,并讲解了在营销中使用数据科学的实际挑战。本章还介绍了其他数据科学和机器学习的包与库,以及可以应用于未来数据科学项目的其他机器学习算法。

为了最大化地利用本书

为了从本书中获得最大的收获,我强烈建议您彻底完成每一章中的编程练习。每个练习旨在为更高级的练习打下坚实的基础,因此跟随每一个步骤是至关重要的。我还建议您勇于尝试。每一章中讨论的不同技术和方法可以与其他章节的技术结合使用。某一章中的技术并非仅限于该章使用,您可以将一章中学到的技术和方法应用到其他章节中。因此,建议您在完成本书后,从头再阅读一遍例子,并尝试将不同章节中学到的技术混合使用,这将对您有益。

下载示例代码文件

您可以通过在www.packt.com注册您的账户,下载本书的示例代码文件。如果您是在其他地方购买的此书,您可以访问www.packt.com/support并注册,代码文件会直接发送到您的邮箱。

您可以按照以下步骤下载代码文件:

  1. 登录或注册 www.packt.com

  2. 选择“支持”标签。

  3. 点击“代码下载与勘误”。

  4. 在搜索框中输入书名,并按照屏幕上的说明操作。

文件下载完成后,请确保使用以下最新版本的解压缩工具进行解压:

  • Windows 版的 WinRAR/7-Zip

  • Mac 版的 Zipeg/iZip/UnRarX

  • Linux 版的 7-Zip/PeaZip

本书的代码包也托管在 GitHub 上,地址为github.com/PacktPublishing/Hands-On-Data-Science-for-Marketing。如果代码有更新,将会在现有的 GitHub 仓库中进行更新。

我们还提供了其他代码包,来自我们丰富的书籍和视频目录,您可以在**github.com/PacktPublishing/**查看。快来看看吧!

下载彩色图像

我们还提供了一个 PDF 文件,包含本书中使用的截图/图表的彩色图像。你可以在这里下载:www.packtpub.com/sites/default/files/downloads/9781789346343_ColorImages.pdf

使用的约定

本书中使用了许多文本约定。

CodeInText:表示文本中的代码字、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 用户名。以下是一个示例:“将下载的WebStorm-10*.dmg磁盘映像文件挂载为系统中的另一个磁盘。”

代码块设置如下:

# total number of conversions
df.conversion.sum()
# total number of clients in the data (= number of rows in the data)
df.shape[0]

当我们希望特别指出代码块中的某部分时,相关行或项目会用粗体显示:

# total number of conversions
df.conversion.sum()
# total number of clients in the data (= number of rows in the data)
df.shape[0]

所有命令行输入或输出如下所示:

$ mkdir css
$ cd css

粗体:表示新术语、重要词汇或你在屏幕上看到的词汇。例如,菜单或对话框中的词汇在文本中会以这样的形式出现。示例如下:“从管理面板中选择‘系统信息’”。

警告或重要提示如下所示。

提示和技巧如下所示。

联系我们

我们始终欢迎读者的反馈。

一般反馈:如果你对本书的任何部分有疑问,请在邮件主题中注明书名,并通过customercare@packtpub.com与我们联系。

勘误:尽管我们已经尽力确保内容的准确性,但难免会有错误。如果你在本书中发现错误,我们将非常感激你能向我们报告。请访问www.packt.com/submit-errata,选择你的书籍,点击“勘误提交表单”链接,并填写详细信息。

盗版:如果你在互联网上发现任何我们作品的非法副本,无论以何种形式出现,我们将非常感激你能提供相关位置地址或网站名称。请通过copyright@packt.com联系我们,并提供相关材料的链接。

如果你有兴趣成为作者:如果你在某个领域具有专业知识,并且有兴趣撰写或参与编写一本书,请访问authors.packtpub.com

评论

请留下评论。在你阅读并使用本书后,为什么不在你购买本书的网站上留下评论呢?潜在读者可以参考并使用你的公正意见来做出购买决定,我们 Packt 也能了解你对我们产品的看法,而我们的作者也可以看到你对其书籍的反馈。谢谢!

想了解更多关于 Packt 的信息,请访问packt.com

第一部分:介绍与环境设置

本节将向你介绍市场营销中的数据科学,并为即将开展的项目设置 Python 和 R 环境。

本节包含以下章节:

  • 第一章,数据科学与市场营销

第一章:数据科学与市场营销

欢迎来到《营销数据科学实战》的第一章!如你所知,数据科学在营销行业中的重要性和应用在过去几年中显著上升。然而,市场营销数据科学仍然是一个相对较新的领域,现有的教育和参考资料远远落后于其发展势头。然而,每年收集到的数据量呈指数级增长,这为从数据中学习并获得洞察力提供了更多机会。

随着数据量的不断增长以及数据科学在市场营销中的应用,我们可以轻松找到数据科学在营销工作中应用的实例。公司开始利用数据科学更好地理解客户行为,并根据客户的活动模式识别不同的客户群体。许多组织还使用机器学习来预测未来的客户行为,例如客户可能购买哪些商品、可能访问哪些网站,以及哪些客户可能流失。数据科学在市场营销中的应用案例几乎无穷无尽,任何规模的公司都可以通过运用数据科学和机器学习来促进其市场营销工作。在本章节的简短介绍之后,我们将学习如何将数据科学和机器学习应用于具体的市场营销任务。

在本章节中,我们将涵盖以下内容:

  • 市场营销趋势

  • 数据科学在市场营销中的应用

  • 设置 Python 环境

  • 设置 R 环境

技术要求

你需要安装 Python 和 R 才能运行本书中的大多数代码,安装代码可以在以下链接找到:github.com/PacktPublishing/Hands-On-Data-Science-for-Marketing/tree/master/Chapter01

市场营销趋势

随着每年数据量的指数级增长以及获取这些宝贵数据集的便利性增加,数据科学和机器学习已成为市场营销中不可或缺的一部分。数据科学在市场营销中的应用从构建有价值的报告和仪表板,到利用复杂的机器学习算法预测客户行为或通过产品和内容与客户互动。近年来,市场营销趋势趋向于更加数据驱动的目标营销。我们将在以下内容中讨论一些我们在营销行业中看到的趋势:

  • 数字营销的重要性日益提升:随着人们在线时间的增加,数字营销的重视程度和效果也随着时间不断上升。许多营销活动现在都发生在数字渠道上,如搜索引擎、社交网络、电子邮件和网站。例如,Google Ads 帮助你的品牌通过其搜索引擎、Gmail 或 YouTube 接触到更多潜在客户。你可以轻松自定义目标受众,选择你希望广告展示的对象。Facebook 和 Instagram 是两个知名的社交网络,你可以在这些平台上发布广告,以触及目标客户。在互联网时代,这些营销渠道比传统的营销渠道(如电视广告)更具成本效益。以下是 Google 提供的不同数字营销渠道的示例 (ads.google.com/start/how-it-works/?subid=us-en-ha-g-aw-c-dr_df_1-b_ex_pl!o2~-1072012490-284305340539-kwd-94527731):

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/cec322da-75fc-44a4-b1d6-84df1155f5bc.png

  • 市场分析:市场分析是一种监控和分析营销效果的方法。它不仅帮助你了解通过营销获得了多少销售或曝光,还可以帮助你深入了解更多个体层面的模式和趋势。在电子商务企业中,你可以通过市场分析分析和可视化不同类型和细分的客户,以及哪种类型的客户为你的业务带来最多的收入。在媒体行业,通过市场分析,你可以分析哪些内容最能吸引用户,以及关键词搜索的趋势是什么。市场分析还帮助你了解营销活动的成本效益。通过查看投资回报率ROI),你可以进一步优化未来的营销活动。随着市场分析的应用和使用日益增加,现如今很容易找到各种市场分析软件产品。

  • 个性化和目标营销:随着数据科学和机器学习在营销中应用的增加,另一个营销趋势是个体层面的目标营销。各种不同规模的组织利用机器学习算法从用户历史数据中学习,并对其用户基础的更小和更特定的子群体应用不同和专业的营销策略,从而降低每次获取成本,提高投资回报率。在零售业务中,许多公司实施人工智能和机器学习来预测哪些客户更有可能购买以及他们将从他们的店铺购买哪些商品。利用这些预测,他们定制每位客户的营销信息。许多媒体企业也利用人工智能和机器学习来提升个体用户的参与度,以增长其用户基础。由于这些定制和目标营销带来了更高的投资回报率,许多 SaaS 公司,如 Sailthru 和 Oracle,提供了个性化营销的平台。Sailthru 最近发布了一份《零售个性化指数》报告,分析了各种零售公司如何在不同营销渠道中使用个性化营销。在这份报告中,我们可以发现零售公司,如 Sephora、JustFab 和 Walmart,在其网站、电子邮件和其他营销渠道中大量使用个性化营销。您可以在以下链接找到这份报告:www.sailthru.com/personalization-index/sailthru100/

在营销方面的总体趋势已经向更加数据驱动和量化方法发展。各大小公司都在越来越多地投资于营销分析和技术。根据 2018 年 2 月的 CMO 调查,过去 5 年中对营销分析的依赖从 30%增加到了 42%。B2C 公司对营销分析的依赖增加了 55%。此外,过去 5 年中使用量化工具来展示营销影响的公司数量增加了 28%。最后,CMO 调查表明,预计在接下来的 3 年内利用人工智能和机器学习的公司比例将增加到 39%。您可以在以下链接找到更多有关这份 2018 年 2 月 CMO 调查报告的详细信息:www.forbes.com/sites/christinemoorman/2018/02/27/marketing-analytics-and-marketing-technology-trends-to-watch/#4ec8a8431b8a

数据科学在营销中的应用

我们已经讨论了营销趋势,以及趋势如何朝着更多数据驱动和量化营销的方向发展,通常使用数据科学和机器学习。在营销行业应用数据科学和机器学习有多种方法,讨论数据科学和机器学习的典型任务和用法将对我们有益。

在本节中,我们将涵盖机器学习的基础知识、不同类型的学习算法以及典型的数据科学工作流程和流程。

描述性分析与解释性分析与预测性分析的比较

当我们在接下来的章节中进行练习和项目时,我们将主要进行本书中的三种不同类型的分析:描述性、解释性和预测性分析。

  • 描述性分析:这种分析旨在更好地理解和描述给定的数据集。分析的目的是通过数量化和统计总结数据所包含的信息。例如,如果你对用户购买历史数据进行描述性分析,你将回答诸如“什么是畅销商品?”、“过去一年的月销量如何?”、“售出商品的平均价格是多少?”在本书中,每当我们介绍新数据集时,我们都将进行描述性分析。特别是在第二章,“关键绩效指标和可视化”,我们将更详细地讨论如何使用描述性分析来分析和计算关键摘要统计数据,并可视化分析结果。

  • 解释性分析:当描述性分析的目的是从数据中回答什么如何时,解释性分析则是利用数据来回答为什么。这种类型的分析通常在你有一个特定问题需要回答时进行。例如,对于电子商务企业,如果你想分析是什么促使用户进行购买,你会进行解释性分析,而不是描述性分析。我们将在第三章中详细讨论这种类型的分析及其示例,“驱动市场参与背后”;和第四章,“从参与到转化”,在这些章节中,我们将使用解释性分析来回答诸如“是什么促使用户更多参与我们的营销活动?”和“是什么让用户从我们的零售店购买商品?”等问题。

  • 预测分析: 当你希望预测某个特定的未来事件时,进行此分析。此分析的目的是构建机器学习模型,从历史数据中学习并对未来将要发生的事件进行预测。类似于之前的电子商务和购买历史数据,你可以通过这种分析回答的问题之一可能是,哪位用户最有可能在接下来的七天内进行购买? 通常,为了进行预测分析,你需要首先进行描述性和解释性分析,以更好地理解数据,并生成关于该项目使用哪种类型的学习算法和方法的想法。我们将在第六章 推荐合适的产品、第八章 预测营销参与的可能性、以及第十一章 保持客户中更详细地讨论预测分析及其在营销中的应用。

学习算法的类型

现在,让我们讨论更多关于机器学习和机器学习算法的内容。广义上说,机器学习算法分为三种类型:监督学习、无监督学习和强化学习。我们首先来了解这三种不同类型的机器学习算法是如何相互区分的:

  • 监督学习算法: 当预测目标或结果已知时,使用这些算法。例如,如果我们想使用机器学习预测未来几天谁会进行购买,那么我们将使用监督学习算法。在这里,预测目标或结果是此人在给定时间窗口内是否进行了购买。基于历史购买数据,我们需要构建特征来描述每个数据点,如用户的年龄、地址、最后一次购买日期等,然后监督学习算法将从这些数据中学习如何将这些特征映射到预测目标或结果。我们将在第三章 营销参与驱动因素、第四章 从参与到转化、第八章 预测营销参与的可能性,以及最后的第十一章 保持客户中探讨如何在营销中使用这些算法。

  • **无监督学习算法:**与监督学习算法不同,无监督学习算法在我们没有特定预测目标或结果时使用。这类机器学习算法常用于聚类和推荐系统。例如,你可以使用无监督学习算法将客户群体根据行为划分为不同的子组或细分市场。在这种情况下,我们没有具体的目标或结果想要预测,我们只是将相似的客户分到不同的细分群体中。在第六章《推荐合适的产品》和第十章《数据驱动的客户细分》中,我们将探讨如何在市场营销中使用无监督学习算法。

  • **强化学习算法:**这些算法在我们希望模型在没有先验知识或经验的情况下不断学习和自我训练时使用。在强化学习的情况下,模型通过大量的试错来学习如何进行预测。一个应用强化学习的市场营销例子是,当你有多种营销策略想要测试并选择效果最好的策略时。此时,你可以运行一个强化学习算法,让它每次随机选择一个策略,当出现积极结果时给予奖励。经过多次的试错迭代后,强化学习模型将学会根据每种营销策略所获得的总奖励来选择最佳策略。

数据科学工作流程

现在我们已经涵盖了机器学习算法的基础知识和不同类型,接下来我们讨论数据科学的工作流程。一个典型的工作流程如下所示:

  1. **问题定义:**通常,任何数据科学和机器学习项目都从问题定义开始。在第一步中,你需要定义你希望通过数据科学解决的问题、项目的范围以及解决该问题的方法。当你思考解决问题的方法时,你需要头脑风暴,思考之前讨论过的分析类型(描述性分析、解释性分析、预测性分析)和学习算法类型(监督学习、无监督学习、强化学习)中哪些适合解决给定的问题。

  2. 数据收集:一旦你清楚地定义了项目的目标,就可以进入数据收集阶段。这是你收集所有需要的数据以继续进行数据科学项目的阶段。你可能需要从第三方供应商购买数据、从网上抓取和提取数据,或者使用公开的数据。在某些情况下,你还需要从内部系统中收集数据。根据不同的情况,数据收集阶段可能很简单,也可能很繁琐。

  3. 数据准备:当你从数据收集阶段收集到所有需要的数据后,接下来的步骤就是数据准备。这个步骤的目标是将数据转化并为未来的步骤做准备。如果数据源的格式不同,那么你需要转换并统一数据。如果数据没有特定的结构,那么你需要将数据结构化,通常是以表格格式,以便于你能够轻松进行不同的分析并构建机器学习模型。

  4. 数据分析:完成数据准备步骤后,你就需要开始查看数据。在数据分析阶段,通常会进行描述性分析,计算一些描述性统计数据,并构建可视化图表以更好地理解数据。在这一阶段,你很可能能够发现一些可识别的模式,并从数据中获得一些洞察。你也可能会发现数据中的异常情况,例如缺失值、损坏的数据或重复记录。

  5. 特征工程:特征工程是数据科学和机器学习中最重要的部分,因为它直接影响预测模型的表现。特征工程需要专业知识和良好的领域知识,因为它要求你将原始数据转化为更加信息丰富的数据,以便算法从中学习。特征工程的一个好例子是将文本数据转换为数值数据。由于机器学习算法只能从数值数据中学习,因此你需要提出一个想法和策略,将文本数据转化为数值数据。随着本书的进展以及我们构建机器学习模型的过程中,我们将讨论并实验各种特征工程技术。

  6. 模型构建:一旦完成特征工程步骤,你就可以开始训练和测试机器学习模型了。在这一步,你可以尝试不同的学习算法,找出最适合你使用案例的算法。在这一步,值得注意的一点是验证指标。拥有一个好的模型性能衡量标准很重要,因为机器学习算法会尝试在给定的性能度量上进行优化。随着我们在接下来的章节中开始构建机器学习模型,我们将详细讨论根据我们所处理问题的类型使用哪些指标。

以下图表展示了典型数据科学项目的整体工作流程:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/dfaf7e80-93c7-41cf-8f13-3432f6b09620.png

从这个图表中可以看出,数据科学工作通常不是一次性完成的。当你发现模型表现不佳,或者注意到可以改进输入数据的质量时,你可能需要重复数据收集步骤。当你有了更好的思路和策略来从原始数据集构建特征时,可能还需要重新审视特征工程步骤。如果你认为通过调整学习算法的超参数可以改进模型结果,模型构建步骤可能需要多次重复。在接下来的章节中,当我们进行实际项目和练习时,我们将更详细地讨论某些步骤以及我们可以使用的不同技术。

设置 Python 环境

现在我们已经讨论了数据科学的一些基础知识及其在营销中的应用,让我们开始为接下来的章节和项目准备开发环境。如果你打算使用 R 语言进行练习,可以跳过这一部分,直接进入设置 R 环境部分。对于打算使用 Python 语言进行练习的同学,即使你已经熟悉 Python,按照这些步骤安装所有所需的 Python 包并准备好 Python 环境仍然会对你有所帮助。

安装 Anaconda 发行版

在本书的数据科学和机器学习任务中,我们将使用许多不同的 Python 包。举例来说,我们将使用 pandas 包进行数据清理和数据分析。您可以在以下链接找到有关此包的更多信息:pandas.pydata.org/。我们还将使用 scikit-learn 包来构建机器学习模型。有关此包的更多信息,请访问以下页面:scikit-learn.org/stable/。我们还会经常使用 numpy 这个 Python 包。当我们需要对多维数据进行数学和科学操作时,此包将非常有用。您可以在此页面找到有关此包的更多信息:www.numpy.org/。除了我们刚刚提到的这三个包之外,我们还将使用一些其他 Python 库,并在使用它们时逐个进行详细讨论。

由于我们在数据科学和机器学习任务中需要各种 Python 库,有时单独安装它们可能会有些麻烦。幸运的是,Anaconda 发行版可以一次性安装所有所需的包。为了下载 Anaconda 发行版,请访问 www.anaconda.com/download/ 进行安装。当您访问此链接时,网页应如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/f26c6554-80e1-4fc5-a888-d20a39fb9b01.png

在本书中,我们将在 Python 3 中使用 Anaconda 5.2。一旦您下载了 Anaconda 发行版,可以使用安装程序安装所有包。在 macOS 上,安装程序如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/b7fdf858-628d-46bc-8d30-0de516b96c36.png

一旦您按照安装程序的步骤完成 Anaconda 发行版的安装,我们现在已经准备好开始运行数据科学和机器学习任务。在接下来的部分,我们将构建一个简单的逻辑回归模型,以了解如何使用我们刚刚安装的关键 Python 库进行未来的练习。

Python 中的简单逻辑回归模型

现在我们已经安装了所有的包,让我们测试一下是否可以使用它们。我们将来会使用 Jupyter Notebook 来进行所有的数据分析、数据可视化和机器学习任务。Jupyter Notebook 是一个开源的 web 应用程序,您可以轻松编写代码、显示图表,并与他人分享笔记本。您可以在此链接找到更多关于 Jupyter Notebook 的信息:jupyter.org/

由于 Jupyter Notebook 是前一节中刚刚安装的 Anaconda 发行版的一部分,您的计算机上应该已经安装了它。

要启动 Jupyter Notebook,您可以打开终端窗口并输入以下命令:

jupyter notebook

当您输入此命令时,应该会看到类似以下截图的输出:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/15287607-aba6-40b9-a07e-137e5869c551.png

最后,它应该会在你的浏览器中打开一个网页应用程序。网页界面应该如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/8c27f056-8e1b-4680-a23b-bdf5d111be94.png

从这张截图可以看到,你可以通过点击右上角的 New 按钮,然后选择 Python 3 来创建一个新的 Jupyter Notebook。这将创建一个新的空白笔记本,选择 Python 3 作为编程语言。新创建的笔记本应该如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/6a3af3da-81e2-4aa8-86b8-47e31a989584.png

为了更改这个笔记本的名称,你只需点击顶部栏,那里写着Untitled,然后输入一个新的名称。

现在我们已经创建了一个笔记本,接下来让我们使用一些 Python 库来构建一个简单的逻辑回归模型。在第一个单元格中,我们将导入numpyscikit-learn库。代码如下所示:

import numpy as np
from sklearn.linear_model import LogisticRegression

从这段代码示例中可以看到,我们已经导入了numpy库并将其别名为np。这是numpy库的标准别名。同时,我们只导入了scikit-learn库中linear_model模块下的LogisticRegression模块(sklearn.linear_model)。

为了构建一个模型,我们需要数据。在本章的演示和测试中,我们将创建二维输入数据和二元输出。以下代码展示了我们是如何创建输入和输出数据的:

input_data = np.array([
    [0, 0],
    [0.25, 0.25],
    [0.5, 0.5],
   [1, 1],
])

output_data = [
    0,
    0,
    1,
    1
]

从这段代码示例中可以看出,我们使用numpy数组数据类型创建了 4 行 2 列的输入数据。输出是二元的,只能取01

使用这些数据,我们可以训练一个逻辑回归模型,代码如下所示:

logit_model = LogisticRegression()
logit_model.fit(input_data, output_data)

从这段代码中可以看到,我们使用LogisticRegression实例化了一个模型对象。然后,我们使用了fit函数,输入和输出数据作为参数,用于训练逻辑回归模型。你可以通过以下代码来获取这个逻辑回归模型的系数和截距:

logit_model.coef_    # output: array([[0.43001235, 0.43001235]])
logit_model.intercept_    # output: array([-0.18498028])

到目前为止,我们的 Jupyter Notebook 如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/19cab5a6-5274-480c-bd0a-0a40dcc33d59.png

为了对新数据进行预测,你可以使用逻辑回归模型对象logit_modelpredict函数。此函数将返回每个输入的预测输出类别。代码如下所示:

predicted_output = logit_model.predict(input_data)

到目前为止,我们已经尝试了如何使用numpyscikit-learn库来构建机器学习模型。接下来,我们将熟悉另一个用于数据可视化的库。在本书的各章节中,我们将大量使用matplotlib库来可视化任何数据分析结果。欲了解更多信息,你可以访问这个页面:matplotlib.org/

让我们首先看一下以下代码:

import matplotlib.pyplot as plt

plt.scatter(
    x=input_data[:,0], 
    y=input_data[:,1], 
    color=[('red' if x == 1 else 'blue') for x in output_data]
)
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Actual')
plt.grid()
plt.show()

正如你从这个代码片段中看到的,你可以像在代码的第一行那样轻松导入matplotlib库。为了构建一个散点图,我们使用了scatter函数,它接受xy的值,以及每个点的color。你可以使用xlabel函数来修改* x 轴的标签,使用ylabel函数来修改 y *轴的标签。通过title函数,你可以修改图表的标题。grid函数会在图表中显示网格,而你需要调用show函数来实际显示图表。

Jupyter Notebook 应该如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/eef5e2b7-80c5-4bd8-b0cc-01b01b54e05e.png

需要注意的一点是以下代码:

%matplotlib inline

这是为了在 Web 应用程序中显示图表。如果没有这一行代码,图表将不会显示在 Web 界面中。为了将实际输出与模型的预测进行比较,我们使用预测值构建了另一个散点图。

代码和图表如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/4ce91ee3-c659-4da0-9e9c-6f8feb5ba05b.png

如果将这张图与前一张图进行比较,你会发现模型正确预测了四分之三的输出,并且错误预测了一个点。

你可以从以下链接下载我们在本节中使用的完整 Jupyter Notebook:github.com/yoonhwang/hands-on-data-science-for-marketing/blob/master/ch.1/python/Setting%20Up%20Python%20Environment.ipynb

在本书中,我们将频繁使用这三个 Python 库,这些库是我们刚刚实验过的。随着章节的推进,我们将介绍这些 Python 库的更多高级特性和功能,以及如何充分利用它们进行数据科学和机器学习任务。

设置 R 环境

对于那些打算在接下来的练习和项目中使用 R 语言的朋友,我们将在本书中讨论如何为数据科学和机器学习任务准备 R 环境。我们将从安装 R 和 RStudio 开始,然后使用 R 构建一个简单的逻辑回归模型,帮助自己熟悉 R 语言在数据科学中的应用。

安装 R 和 RStudio

除了 Python,R 也是数据科学和机器学习中最常用的语言之一。它非常容易使用,而且有大量用于机器学习的 R 库,吸引了许多数据科学家。为了使用这门语言,你需要从以下链接下载: www.r-project.org/。如果你访问该网页,它的界面会类似于以下截图:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/de2e1020-8601-4aad-ad8e-1b219960bf91.png

你可以在此网页找到有关 R 的更多信息。为了让你下载,请点击页面中的下载 R 链接。它会要求你选择一个 CRAN 镜像。你可以选择距离你最近的镜像位置来下载 R。下载完成后,按照安装程序中的步骤进行安装。在 macOS 上的安装程序如下图所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/fda32aae-ce25-4b89-b391-08ab51fe0c7a.png

安装完 R 后,我们还需要为我们的 R 开发环境安装一个工具。在本书中,我们将使用 RStudio,这是一个流行的 R 编程语言 IDE。你可以通过以下链接下载 RStudio:www.rstudio.com/products/rstudio/download/。当你访问这个 RStudio 下载页面时,页面应显示如下截图:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/f300bc29-063b-43d4-a084-4f52339d760c.png

本书中将使用 RStudio Desktop Open Source License 版本,但如果你已经拥有其他版本的许可证,也可以随意使用。下载并安装 RStudio 后,打开 RStudio 时你将看到类似下面的截图:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/6132f932-c55e-4124-b4eb-d9efd7d92c38.png

现在我们已经准备好了 R 环境,接下来让我们构建一个简单的逻辑回归模型,以便更好地熟悉 R。

R 中的一个简单逻辑回归模型

让我们通过在 R 中构建一个简单的逻辑回归模型来测试我们的环境设置。打开 RStudio 并创建一个新的 R 脚本文件。你可以使用以下代码在 R 中创建一个数据框:

# Input Data
data <- data.frame(
  "X"=c(0, 0.25, 0.5, 1), 
  "Y"=c(0, 0.5, 0.5, 1), 
  "output"=c(0, 0, 1, 1)
)

如代码片段所示,我们构建了一个包含XYoutput列的数据框。X列的取值为00.250.51Y列的取值为00.50.51output是一个二元分类,取值为01data如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/6320e186-c7c7-478c-a7bd-cad771ff78f0.png

现在我们有了训练逻辑回归模型的数据,接下来让我们看一下以下代码:

# Train logistic regression
logit.fit <- glm(
  output ~ X + Y, 
  data = data, 
  family = binomial
)

如代码片段所示,我们在 R 中使用glm函数来拟合逻辑回归模型。由于glm函数用于拟合任何线性模型,我们需要定义模型的family变量,以便指定我们要训练的模型类型。为了训练逻辑回归模型,我们在glm函数中使用binomial作为family参数。第一个参数output ~ X + Y定义了该模型的公式,而data参数则用于定义训练模型所使用的数据框。

在 R 中,你可以使用summary函数来获取拟合的逻辑回归模型的详细信息,如下代码所示:

# Show Fitted Results
summary(logit.fit)

这将输出如下截图所示的内容:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/08db8d9a-38c7-407e-a559-5d43463f91bd.png

如你所见,从这个输出中,我们可以轻松找到模型的系数和截距。我们将在本书中频繁使用这个summary函数,以更好地理解训练好的模型。

有了训练好的模型,我们可以使用以下代码对新数据进行预测:

# Predict Class Probabilities
logit.probs <- predict(
  logit.fit, 
  newdata=data, 
  type="response"
)

# Predict Classes
logit.pred <- ifelse(logit.probs > 0.5, 1, 0)    
logit.pred    # output: 0 0 1 1

如你从这个代码片段中看到的,我们使用predict函数通过训练好的模型logit.fit和在参数newdata中定义的新数据进行预测。这个predict函数将输出新数据中每个示例的概率或可能性;为了将这个输出转换成二进制类别,我们可以使用ifelse函数将高于某一阈值(在此例中为0.5)的输出编码为1,其余部分编码为0

最后,让我们快速看一下如何在 R 中构建图表。我们将在本书中使用 R 包ggplot2进行绘图。因此,了解如何导入这个绘图库并使用它进行数据可视化将对你有帮助。如果这是你第一次使用这个包,你很可能在尝试导入ggplot2包时会看到以下错误信息:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/9d6a11b3-b01a-4b18-b3d5-3490306685a5.png

如消息所示,ggplot2包尚未安装在你的计算机上。要安装任何 R 包,你只需运行以下命令:

install.packages('ggplot2')

如果你运行这个命令,你会看到类似以下的输出:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/b0ce690c-8af7-4c4b-ae9c-f53fc0944a1e.png

一旦这个库的安装完成,你就可以导入并使用这个库了。我们将使用ggplot2库构建一个简单的散点图,如下所示的代码片段:

# Plotting Library
library(ggplot2)

# Simple Scatterplot
ggplot(data, aes(x=X, y=Y, color=output)) +
  geom_point(size=3, shape=19) +
  ggtitle('Actual') +
  theme(plot.title = element_text(hjust = 0.5))

如你从这个代码片段中看到的,你可以使用ggplot2包中的ggplot函数构建一个基于data的散点图。为了改变散点图中点的形状和大小,你可以使用geom_point函数。你还可以使用ggtitle函数来更改图表的标题。当你运行这段代码时,你将看到以下图表:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/ac63a363-159f-4887-a7e3-2a4cc71abbbf.png

我们将对预测结果执行相同的操作。代码如下:

ggplot(data, aes(x=X, y=Y, color=logit.pred)) + 
  geom_point(size=3, shape=19) +
  ggtitle('Predicted') +
  theme(plot.title = element_text(hjust = 0.5))

输出如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/a1d9b743-6dbb-4a3d-a1e4-b3932868564b.png

在本书中,我们将大量使用这些函数和绘图库ggplot2,因此随着章节和练习的进行,你将越来越习惯于用 R 编程,并且能够熟练使用这些其他库。

你可以从以下链接查看并下载用于本节的完整 R 代码:github.com/yoonhwang/hands-on-data-science-for-marketing/blob/master/ch.1/R/SettingUpREnvironment.R.

总结

在这一章中,我们讨论了市场营销中的整体趋势,并了解了数据科学和机器学习在营销行业中日益重要的作用。随着数据量的增加,以及我们观察到利用数据科学和机器学习进行营销的好处,各种规模的公司都在投资构建更多以数据为驱动的定量营销策略。

我们还学习了不同类型的分析方法,特别是本书中我们将频繁使用的三种分析方法——描述性分析、解释性分析和预测性分析——以及这些分析的不同使用案例。在这一章中,我们介绍了不同类型的机器学习算法,以及数据科学中的典型工作流程。最后,我们花了一些时间在 Python 和 R 中设置我们的开发环境,并通过构建一个简单的逻辑回归模型来测试我们的环境设置。

在下一章中,我们将介绍一些关键绩效指标KPIs)以及如何可视化这些关键指标。我们将学习如何在 Python 中计算并构建这些 KPIs 的可视化图表,使用不同的包,如pandasnumpymatplotlib。对于那些使用 R 语言跟随本书练习的读者,我们还将讨论如何使用 R 来计算并绘制这些 KPIs,利用 R 中的各种统计和数学函数,以及用于可视化的ggplot2包。

第二部分:描述性分析与解释性分析

在本节中,你将学习在营销行业中常用的关键绩效指标(KPI),如何使用 Python 和 R 中的图表库来可视化指标,以及如何使用机器学习算法理解什么因素推动了营销活动的成功与失败。

本节包括以下章节:

  • 第二章,关键绩效指标与可视化

  • 第三章,营销互动背后的驱动因素

  • 第四章,从互动到转化

第二章:关键绩效指标和可视化

当你进行营销活动或其他任何营销工作时,你很可能想要了解每个活动的表现如何,并理解每个营销努力的优缺点。在本章中,我们将讨论一些常用的关键绩效指标KPI),这些指标帮助你跟踪营销工作表现。更具体地说,我们将涵盖诸如销售收入、客户获取成本CPA)、数字营销 KPI 和网站流量等指标。我们将学习这些 KPI 如何帮助你朝着营销目标稳步前进。

在讨论了一些常用的 KPI 后,我们将学习如何使用 Python 和/或 R 来计算这些 KPI 并构建它们的可视化。在本章中,我们将使用一个银行营销数据集,展示一个金融组织营销活动的真实案例。对于 Python 项目,我们将学习如何使用pandasmatplotlib库来分析数据并构建可视化图表。对于 R 项目,我们将介绍dplyrggplot2库来分析和处理数据,并创建可视化图表。

特别地,本章将涵盖以下主题:

  • 用于衡量不同营销活动表现的 KPI

  • 使用 Python 计算和可视化关键绩效指标(KPI)

  • 使用 R 计算和可视化关键绩效指标(KPI)

用于衡量不同营销活动表现的 KPI

每一项营销努力都需要公司投入资金。当你通过电子邮件进行营销活动时,发送每封邮件都会产生一定的费用。当你在社交网络服务或广播媒体上开展营销活动时,也需要一些资本。由于每项营销活动都涉及一定的成本,因此,检查营销活动的表现并跟踪营销活动的投资回报率ROI)是至关重要的。本节我们将主要讨论如何跟踪销售收入、CPA 和数字营销 KPI。

销售收入

很明显,每个营销努力的目标都是为公司创造和增长更多的收入。没有公司希望在营销上的花费超过其带来的收入。为了准确报告销售收入,你需要清楚地定义如何将销售归因于每一项营销活动。部分销售可能来源于电子邮件营销活动,而另一些可能来自电视或公共交通上的广告。也有可能一些销售是自然发生的,并没有归因于任何营销活动。

为了正确报告每个营销活动所带来的销售收入,你需要明确定义规则,将销售额归因于每个营销活动。例如,如果你是一家电子商务公司,通过电子邮件和电视广告活动进行促销,你可能希望在电子邮件中使用与电视广告中不同的 URL。这样,你就可以将通过电子邮件营销活动获得的销售与通过电视营销活动获得的销售区分开来。

根据你的需求,你可能还希望报告时间序列的销售收入数据。你可以以电子表格的格式报告,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/b625535c-0106-4f31-929a-f002fefc79eb.png

你还可以通过折线图报告时间序列的销售收入数据,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/747bf180-1b19-4247-8601-dbcf45c6d315.png

我们将在本章末的 Python 和 R 练习中讨论更多关于报告 KPI 时可以使用的不同类型的图表和数据可视化方式。

每客户获取成本(CPA)

另一个衡量营销效果的方法是 CPA(每客户获取成本)。这个 KPI 指标告诉你,通过营销活动获取一个客户的成本是多少。高 CPA 意味着获取新客户的成本较高,而低 CPA 显然意味着获取新客户的成本较低。根据不同的业务类型,即使 CPA 较高,你仍然可以拥有一个非常有利可图的营销活动。例如,如果你销售的是非常奢华且高端的产品,目标客户群体较小,获取这些客户的成本较高,那么你的 CPA 可能较高,但你所获得的每个客户的价值可能更高,从而导致一个有利可图的营销活动。

我们将看一下以下这个假设案例:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/a5badd7a-3ac4-4829-9ea4-eddf96d26b2a.png

如果你查看这个电子表格,欢乐时光活动是最昂贵的营销活动,无论是从总成本还是 CPA 来看。然而,它产生了最多的销售额每客户销售额;因此,它是最有价值的活动。另一方面,广播广告的 CPA 最低,尽管总成本是第二高的,因为它帮助企业获得了最多的客户。然而,这些客户的总销售额并没有超过该活动的总成本,并给公司带来了净亏损。

即使这是一个假设情境,类似的情况也可能发生在现实生活中。营销活动,比如欢乐时光活动网络研讨会,比广播广告更能精准地瞄准客户。通过高度精准的营销活动获取的客户质量比通过非精准营销活动获取的客户好得多。

现在我们已经看到如何分解营销活动结果,以更深入地分析成本效益,我们将看看一些常用的数字营销 KPI。

数字营销 KPI

随着营销渠道选择的增加,如社交网络服务、博客和搜索引擎,报告数字营销效果变得越来越重要。之前讨论过的 KPI、销售收入和获取成本,同样适用于数字营销领域。

作为一个例子,基于单一归因逻辑,你可以分析通过不同社交网络服务(如 Facebook、LinkedIn 和 Instagram)生成了多少销售。你还可以分析通过这些营销渠道获得了多少客户,并查看各个数字营销活动的 CPA 和所生成的价值。让我们来讨论更多的数字营销 KPI:

  • 点击率CTR)是另一个数字营销中常常关注的 KPI。CTR 是观看了广告并点击广告的人的百分比。公式如下:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/3475a6d1-f101-400a-b723-31b7ac1aed70.png

点击率(CTR)是数字营销渠道中的一个重要指标,因为它衡量了你的在线营销在将流量引导到你的网站方面的效果。

  • 然后,你可以使用潜在客户比率来衡量有多少网站流量可以转化为潜在客户。通常,只有一部分网站流量适合成为你的客户。这些营销合格潜在客户MQL)是那些已经准备好接受营销的潜在客户,符合特定商业标准,有可能成为会购买的客户,基于他们的特征。当你开始对这些合格的潜在客户进行营销时,你也应该关注转化率。

  • 转化率是将潜在客户转化为活跃客户的百分比。你可以根据你的营销目标来定义什么应当视为转化。如果你的目标是查看有多少潜在客户变成了付费客户,那么你可以按照类似下面的公式计算转化率:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/8f945f3a-851b-460b-9b69-ab2086f7b8b6.png

如果你的目标是查看有多少潜在客户在你的网站上注册,那么你可以按照以下公式计算转化率:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/257bbf18-22d1-4498-9855-90865d946ee9.png

到目前为止,我们已经查看了各种 KPI,并讨论了这些 KPI 如何帮助你跟踪营销工作的进展和效果。接下来,我们将看看如何使用 Python 和/或 R 来计算这些 KPI 并进行可视化。如果你计划使用本书中介绍的两种编程语言之一,Python 或 R,你可以跳过并直接进入你想要学习的部分。

使用 Python 计算和可视化 KPI

在本节中,我们将讨论如何使用 Python 计算和可视化我们在前几节中讨论的关键绩效指标(KPI)。我们将主要集中于使用银行营销数据分析转化率。对于那些希望使用 R 进行本次练习的读者,您可以跳到下一节。我们将使用pandasmatplotlib库来操作和分析数据,并构建各种图表,以准确报告营销工作的进展和表现。

在本节的练习中,我们将使用UCI 的银行营销数据集,可以通过以下链接找到:archive.ics.uci.edu/ml/datasets/bank+marketing。您可以访问该链接,并通过点击左上角的Data Folder链接下载数据。对于本次练习,我们下载了bank-additional.zip数据,并将使用其中的bank-additional-full.csv文件。

当您打开这个bank-additional-full.csv文件时,您会注意到使用分号(;)作为分隔符,而不是逗号(,)。为了加载这些数据,您可以使用以下代码将数据读取到pandasDataFrame中:

import pandas as pd

df = pd.read_csv('../data/bank-additional-full.csv', sep=';')

正如您在这段代码中看到的,我们导入了pandas库,并使用别名pd,我们还使用read_csv函数来加载数据。对于除逗号外的其他分隔符,您可以在read_csv函数中使用sep参数来定义自定义分隔符。

如果您查看数据下载页面中的字段描述(archive.ics.uci.edu/ml/datasets/bank+marketing),您会发现输出变量y(它包含客户是否订阅定期存款的信息)被编码为'yes''no'。为了简化我们的转化率计算,我们将把该变量编码为'yes'对应1'no'对应0。您可以使用以下代码进行编码:

df['conversion'] = df['y'].apply(lambda x: 1 if x == 'yes' else 0)

正如您在这段代码中看到的,我们使用apply函数将变量y中的'yes'编码为1,将'no'编码为0,然后将这些编码后的数据作为新列conversion添加进去。代码和我们在 Jupyter Notebook 中加载的数据如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/b122168c-72eb-431e-91af-644d51aad7e6.png

现在我们已经成功将数据读取到pandasDataFrame中,我们将开始查看如何使用各种方法和图表来分析和可视化转化率。

聚合转化率

首先,我们将查看聚合转化率。我们可以通过将订阅定期存款的客户总数除以数据中客户的总数来计算这个指标。由于我们已经将输出变量编码为1(表示已转化)和0(表示未转化),并将其存储在名为conversion的列中,我们可以简单地对这一列求和来获得转化的总数。

以下代码片段展示了我们如何对conversion列进行求和,并获得数据中客户的总数:

# total number of conversions
df.conversion.sum()
# total number of clients in the data (= number of rows in the data)
df.shape[0]

以下是我们在 Jupyter Notebook 中进行转化率计算的代码:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/5b8cd4a4-f2ef-42d8-b18c-a3596a1d6930.png

如你所见,在 Jupyter Notebook 中的代码输出结果中,我们从总计41188名银行客户中转换了4640名客户,这表明总体转化率为11.27%。在接下来的部分,我们将分析这些转化率如何根据不同年龄组的变化。

按年龄的转化率

总体转化率告诉我们营销活动的整体表现。然而,它并没有给我们太多的洞察。当我们报告并跟踪营销进展时,通常需要深入分析数据,将客户群体细分为多个部分,并计算每个部分的关键绩效指标(KPI)。我们将首先按age将数据划分为更小的细分,并查看不同年龄组的转化率差异。

我们首先来看以下代码:

conversions_by_age = df.groupby(
    by='age'
)['conversion'].sum() / df.groupby(
    by='age'
)['conversion'].count() * 100.0

如你所见,在这段代码中,我们使用了groupby函数按年龄计算转化率。

我们首先根据变量名age进行分组,并使用sum函数对conversion列进行求和,以获得每个年龄段的总转化数。然后,我们再次按age进行分组,使用count函数统计每个年龄段记录的数量。

使用这两项计算,我们可以按age计算每个年龄段的转化率,如代码所示。以下是每个age的部分转化率计算结果:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/3101f3f1-1c3d-4036-bb46-3c3719a4122a.png

另一种查看不同客户年龄段转化率的方法是通过绘制折线图,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/fd275a9a-750e-40d7-a624-3e0b95d3a0dd.png

用于可视化不同年龄段转化率的代码如下所示:

ax = conversions_by_age.plot(
    grid=True,
    figsize=(10, 7),
    title='Conversion Rates by Age'
)

ax.set_xlabel('age')
ax.set_ylabel('conversion rate (%)')

plt.show()

如代码所示,我们使用了之前构建的conversions_by_age变量和plot函数来绘制折线图。如你从代码中看到的那样,可以通过名为figsize的参数改变图形的大小,通过名为title的参数改变图表的标题。为了更改X轴和Y轴的标签,可以使用set_xlabelset_ylabel函数。

在之前的折线图中,有一点值得注意的是,老年组的数据显示似乎有很多噪音。对于70岁或以上的人群,转化率波动较大,如果你查看数据,会发现这主要是因为这个年龄组的客户数量相对较少,和其他年龄组相比差距较大。

为了减少这种不必要的噪音,我们可以将多个年龄组合并。在本练习中,我们将银行客户根据年龄分为六个不同的组——1830岁,3040岁,4050岁,5060岁,6070岁,以及70岁及以上。可以使用以下代码将客户分组:

df['age_group'] = df['age'].apply(
    lambda x: '[18, 30)' if x < 30 else '[30, 40)' if x < 40 \
        else '[40, 50)' if x < 50 else '[50, 60)' if x < 60 \
        else '[60, 70)' if x < 70 else '70+'
)

如果你查看这段代码,我们正在对age列应用apply函数,将客户分为六个不同的年龄组,并将这些数据添加到一个名为age_group的新列中。为了计算这些新创建的年龄组的转化率,我们可以使用以下代码:

conversions_by_age_group = df.groupby(
    by='age_group'
)['conversion'].sum() / df.groupby(
    by='age_group'
)['conversion'].count() * 100.0

与之前的情况类似,我们使用groupbysumcount函数来计算这六个不同年龄组的转化率。结果数据如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/c87019e0-eeb8-4d7b-ae77-3e2cf41f8573.png

从这个结果可以看出,各年龄组之间的差异比之前要小得多,尤其是在老年组。我们可以使用条形图来可视化这些数据,如下所示的屏幕截图所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/6400ebaa-c9a5-430f-9512-3e4c1f509fe0.png

构建此条形图的代码如下所示:

ax = conversions_by_age_group.loc[
    ['[18, 30)', '[30, 40)', '[40, 50)', '[50, 60)', '[60, 70)', '70+']
].plot(
    kind='bar',
    color='skyblue',
    grid=True,
    figsize=(10, 7),
    title='Conversion Rates by Age Groups'
)

ax.set_xlabel('age')
ax.set_ylabel('conversion rate (%)')

plt.show()

正如你从这段代码中看到的,我们使用了之前用来绘制线形图的相同plot函数。唯一的区别是kind参数,通过它我们可以定义想要绘制的不同类型的图形。在这里,我们将kind参数的值设置为bar,以绘制条形图。

你可以在以下仓库中找到完整的代码:github.com/yoonhwang/hands-on-data-science-for-marketing/blob/master/ch.2/python/ConversionRate.ipynb

转化与未转化

另一个我们可以观察的方面是已转化客户与未转化客户之间的人口统计差异。这种分析可以帮助我们识别在营销活动中,已转化组与未转化组之间的区别,帮助我们更好地了解目标客户以及哪些类型的客户更容易响应我们的营销活动。在本练习中,我们将比较已转化组与未转化组之间婚姻状况的分布。

我们将首先计算每个婚姻状况的转化和未转化的数量。以下代码展示了如何使用pandas函数来计算这一点:

pd.pivot_table(df, values='y', index='marital', columns='conversion', aggfunc=len)

从这段代码中可以看出,我们正在使用pandas库中的pivot_table函数。我们根据maritalconversion列进行分组,其中marital将成为新DataFrame的索引,conversion将成为列。通过aggfunc参数,我们可以指定要执行的聚合类型。在这里,我们使用len函数简单地计算每个组的客户数量。生成的数据如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/5a85b170-769b-4e0b-af04-85822cbe4e16.png

另一种表示这些数据的方式是使用饼图,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/0b8ac645-7b7f-403a-8b37-8d4132cfe650.png

以下代码展示了我们如何构建这些饼图:

conversions_by_marital_status_df.plot(
    kind='pie',
    figsize=(15, 7),
    startangle=90,
    subplots=True,
    autopct=lambda x: '%0.1f%%' % x
)

plt.show()

从这段代码中可以看出,我们使用了与之前相同的plot函数,但使用pie作为我们希望构建的图表类型。你可以使用autopct参数来格式化饼图中每个群体的标签。

与数据输出的表格格式相比,饼图使得理解数据的整体分布变得更加容易。通过饼图,我们可以轻松看到married群体在转化组和非转化组中占据最大的比例,而single群体则排在第二。使用饼图,我们可以轻松地可视化两个群体之间的相似性和差异。

按年龄和婚姻状况的转化

到目前为止,我们已经根据一个标准对数据进行了汇总。然而,有时你可能希望根据多个列来对数据进行分组。在本节中,我们将讨论如何根据多个标准分析和报告转化率。作为一个练习,我们将使用前一节中构建的年龄组和婚姻状况作为两个列进行分组。

让我们首先看看代码:

age_marital_df = df.groupby(['age_group', 'marital'])['conversion'].sum().unstack('marital').fillna(0)

age_marital_df = age_marital_df.divide(
    df.groupby(
        by='age_group'
    )['conversion'].count(), 
    axis=0
)

从这段代码中可以看出,我们正在根据两个列age_groupmarital对数据进行分组,并求出转化的数量。然后,我们将这个数量除以每个群体中的客户总数。生成的数据如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/a834d935-1164-4371-abb1-533264c4e68b.png

如您从这些数据中看到的,我们现在可以根据两个标准(年龄组和婚姻状况)看到转化率的分布。例如,单身且年龄在1830岁之间的客户转化率为 13.25%,而已婚且年龄在6070岁之间的客户转化率为 30.11%。另一种可视化这些数据的方式是使用如下所示的条形图:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/a7a55ab6-0b06-46af-a335-3b8770e229a3.png

在这张条形图中,我们可以清楚地看到每个年龄和婚姻状态群体的转化率分布。我们用来构建这张条形图的代码如下所示:

ax = age_marital_df.loc[
    ['[18, 30)', '[30, 40)', '[40, 50)', '[50, 60)', '[60, 70)', '70+']
].plot(
    kind='bar', 
    grid=True,
    figsize=(10,7)
)

ax.set_title('Conversion rates by Age & Marital Status')
ax.set_xlabel('age group')
ax.set_ylabel('conversion rate (%)')

plt.show()

与之前的情况类似,我们使用了pandas库的plot函数,并将bar传递给该函数的kind参数。由于DataFrame对象age_marital_df对于每种婚姻状态有四列,并且按年龄组进行索引,因此plot函数为每个年龄组的每种婚姻状态构建了一个包含四个条形的条形图。

如果您想要将每个年龄组的四个条形图叠加起来,您可以使用以下代码绘制堆叠条形图:

ax = age_marital_df.loc[
    ['[18, 30)', '[30, 40)', '[40, 50)', '[50, 60)', '[60, 70)', '70+']
].plot(
    kind='bar', 
    stacked=True,
    grid=True,
    figsize=(10,7)
)

ax.set_title('Conversion rates by Age & Marital Status')
ax.set_xlabel('age group')
ax.set_ylabel('conversion rate (%)')

plt.show()

如您在这段代码中看到的,唯一的区别是我们在代码中使用的参数stacked。当此参数设置为True时,它将构建一个堆叠条形图,效果如下:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/2634f436-965d-41af-bfd5-d27600fcc768.png

从这个堆叠条形图中可以看到,不同的婚姻状态在每个年龄组中被叠加在一起。通过这种方式,我们不仅可以轻松看到不同年龄组的转化率的整体趋势,还可以看到每个年龄组中不同婚姻状态的转化客户的比例。

我们在此 Python 练习中使用的完整代码和 Jupyter Notebook 可以在以下仓库中找到:github.com/yoonhwang/hands-on-data-science-for-marketing/blob/master/ch.2/python/ConversionRate.ipynb

使用 R 计算和可视化 KPI

在本节中,我们将讨论如何使用 R 计算和可视化我们在前几节中讨论的 KPI。我们将主要专注于使用银行营销数据分析转化率。对于那些希望使用 Python 进行此练习的读者,您可以在前一节中找到 Python 的练习代码。我们将使用 R 中的dplyrggplot2库来处理和分析数据,并构建各种图表,以准确报告营销工作中的进展和效果。dplyr库提供了多种用于数据科学和机器学习任务的数据处理功能。

本节练习中,我们将使用UCI银行营销数据集,可以通过以下链接找到:archive.ics.uci.edu/ml/datasets/bank+marketing。您可以点击此链接,在左上角点击Data Folder链接下载数据。为了进行此练习,我们下载了bank-additional.zip数据,并将在该压缩文件中的bank-additional-full.csv文件中使用数据。

当您打开这个bank-additional-full.csv文件时,您会注意到文件中使用分号(;)作为分隔符,而不是逗号(,)。为了加载此数据,您可以使用以下代码将数据读取到一个DataFrame中:

conversionsDF <- read.csv(
  file="~/Documents/data-science-for-marketing/ch.2/data/bank-additional-full.csv", 
  header=TRUE, 
  sep=";"
)

从这段代码中可以看出,我们使用read.csv函数来加载数据。对于逗号以外的分隔符,你可以在read.csv函数中通过sep参数定义自定义分隔符。如果你的数据文件包含标题行,你可以将header参数设置为TRUE。另一方面,如果数据文件没有标题行,并且数据从第一行开始,你可以将其设置为FALSE

如果你查看数据下载页面中的字段描述(archive.ics.uci.edu/ml/datasets/bank+marketing),输出变量y表示客户是否订阅了定期存款,其信息编码为'yes''no'。为了简化我们的转化率计算,我们将该变量编码为'yes'对应1'no'对应0。你可以使用以下代码来进行编码:

# Encode conversions as 0s and 1s
conversionsDF$conversion <- as.integer(conversionsDF$y) - 1

从这段代码片段可以看出,我们使用了as.integer函数将'yes'编码为1,将'no'编码为0,并将这个编码后的数据作为新列conversion添加到数据中。由于as.integer函数默认会将'no''yes'分别编码为12,所以我们将其值减去1。现在,数据在 RStudio 中的显示情况如下:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/d9e71c7f-eaba-4b63-8567-0aecc6b1a58b.png

现在我们已经成功将数据读取到RDataFrame中,接下来我们将开始探索如何分析和可视化转化率,使用不同的方法和图表。

总体转化率

首先,我们要查看的是总体转化率。我们可以通过将订阅了定期存款的客户数量除以数据中总客户数量来计算这个指标。由于我们已经将输出变量编码为 1(表示已转化)和 0(表示未转化),并将其存储在名为conversion的列中,我们可以简单地对该列求和,得到转化的总客户数量。以下代码片段展示了我们如何对conversion列求和并得到数据中的总客户数:

# total number of conversions
sum(conversionsDF$conversion)

# total number of clients in the data (= number of records in the data)
nrow(conversionsDF)

从这段代码中可以看出,我们使用了 R 中的sum函数来计算总的转化数量,并使用nrow函数来统计数据集中行的数量。顺便提一句,和nrow类似,你可以使用ncol函数来统计DataFrame的列数。

以下截图展示了我们在 RStudio 中的代码显示情况:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/5b064e7d-c589-41fa-9129-bac465e2a0d6.png

从 RStudio 中的代码输出可以看出,我们在41188个银行客户中,共有4640个客户进行了转化,这表明总体转化率为11.27%。在接下来的部分,我们将分析不同年龄组的转化率差异。我们使用了sprintf函数来格式化包含整数和浮点数的字符串。

按年龄分组的转化率

聚合转化率告诉我们营销活动的整体表现。然而,它并没有给我们太多的洞察。在报告和跟踪营销进展时,我们通常希望更深入地分析数据,将客户基础拆分为多个细分市场,并计算各个细分市场的 KPI。我们将首先按年龄将数据拆分成更小的段,并查看不同年龄组的转化率差异。

我们首先来看以下这段代码:

conversionsByAge <- conversionsDF %>% 
  group_by(Age=age) %>% 
  summarise(TotalCount=n(), NumConversions=sum(conversion)) %>%
  mutate(ConversionRate=NumConversions/TotalCount*100.0)

这段代码中的管道操作符%>%是你可以按顺序应用不同函数的方式。在这段代码中,我们将conversionDF传递给group_by函数,然后将group_by函数的结果传递给summarise函数,最后传递给mutate函数。

group_by函数中,我们通过age列对DataFrame进行分组。然后,针对每个年龄组,我们使用函数n()计算每组的记录数,并将其命名为TotalCount。同时,我们使用sum函数对每个年龄组的conversion列求和,并将其命名为NumConversions

最后,我们使用mutate函数,该函数添加新的变量,同时保留原始的DataFrame,来计算每个年龄组的转化率。如你所见,我们只是将NumConversion除以TotalCount,然后乘以100.0来获得转化率。

结果数据如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/ebdf5a19-e660-43bb-8d27-d35b2e8e86da.png

查看不同年龄段客户的转化率的另一种方法是绘制折线图,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/b44831d7-3be8-48fe-b526-910b16b7ee62.png

用于可视化不同年龄段转化率的代码如下所示:

# line chart
ggplot(data=conversionsByAge, aes(x=Age, y=ConversionRate)) +
  geom_line() +
  ggtitle('Conversion Rates by Age') +
  xlab("Age") +
  ylab("Conversion Rate (%)") +
  theme(plot.title = element_text(hjust = 0.5))

从这段代码中可以看出,我们使用ggplot函数初始化一个ggplot对象,数据为conversionsByAge,其中Age列作为x轴,ConversionRate列作为y轴。

然后,我们使用geom_line函数连接观测值,绘制折线图。你可以使用ggtitle函数更改图表标题。此外,你还可以使用xlabylab函数分别重命名 x 轴和 y 轴标签。

在前一张折线图中,显而易见的一点是,较高年龄组的噪声似乎很多。70 岁或以上的转化率变化较大,如果你查看数据,会发现这主要是因为该年龄组的客户数量相对较少,与其他年龄组相比。

为了减少这种不必要的噪音,我们可以将多个年龄段合并。在本练习中,我们根据银行客户的年龄将其分为六个不同的组——1830岁之间、3040岁之间、4050岁之间、5060岁之间、6070岁之间、以及70岁及以上。以下代码可以用于将客户分组:

# b. by age groups
conversionsByAgeGroup <- conversionsDF %>% 
  group_by(AgeGroup=cut(age, breaks=seq(20, 70, by = 10)) ) %>% 
  summarise(TotalCount=n(), NumConversions=sum(conversion)) %>%
  mutate(ConversionRate=NumConversions/TotalCount*100.0)

conversionsByAgeGroup$AgeGroup <- as.character(conversionsByAgeGroup$AgeGroup)
conversionsByAgeGroup$AgeGroup[6] <- "70+"

与之前的情况一样,我们使用了group_by函数根据age列将conversionsDF数据分组。这里的不同之处在于,我们如何使用cut函数为每个年龄组创建年龄范围。

breaks参数定义了cut函数将如何划分DataFrame。参数seq(20, 70, by = 10)表示我们将从207010为增量创建一个序列。一旦数据按这些年龄段分组,其他操作与之前相同。我们使用summarisemutate函数来计算TotalCountNumConversionsConversionRate列。

生成的DataFrame在以下截图中展示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/cb4e8d9d-88b5-47ef-ad3e-995d207e832e.png

从中可以看出,每个年龄组的差异远小于之前,尤其是在老年组。我们可以通过条形图来可视化这些数据,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/2de62aed-8ebd-4451-9130-c038d4fc8794.png

构建此条形图的代码如下所示:

# bar chart
ggplot(conversionsByAgeGroup, aes(x=AgeGroup, y=ConversionRate)) +
  geom_bar(width=0.5, stat="identity") +
  ggtitle('Conversion Rates by Age Groups') +
  xlab("Age") +
  ylab("Conversion Rate (%)") +
  theme(plot.title = element_text(hjust = 0.5)) 

从这段代码可以看出,我们将conversionsByAgeGroup数据传递给了ggplot对象,x轴使用了AgeGroup列,y轴使用了ConversionRate列。我们使用了geom_bar函数来构建条形图。

width参数定义了条形图中每个条形的宽度。与之前的折线图类似,你可以使用ggtitle来重新命名图表标题,使用xlabylab函数来重新命名* x 轴和 y *轴的标签。

你可以在以下仓库中找到完整的代码:github.com/yoonhwang/hands-on-data-science-for-marketing/blob/master/ch.2/R/ConversionRate.R

转化与非转化

另一个我们可以查看的方面是转化客户与非转化客户之间的群体差异。这种类型的分析可以帮助我们识别在市场营销活动中,转化组与非转化组的不同之处,帮助我们更好地理解目标客户,并了解哪些类型的客户对我们的营销活动反应更好。在本练习中,我们将比较转化组与非转化组之间婚姻状况的分布。

我们将首先计算每个婚姻状况下的转化和非转化数量。以下代码展示了我们如何使用R函数来计算这一点:

conversionsByMaritalStatus <- conversionsDF %>% 
 group_by(Marital=marital, Conversion=conversion) %>% 
 summarise(Count=n())

从这段代码可以看出,我们正在使用dplyr包中的管道操作符%>%DataFrameconversionsDF传递给group_by函数,然后传递给summarise函数。在group_by函数中,我们按两个列进行分组,maritalconversion。在summarise函数中,我们只是通过使用n函数计算每个组中的记录数量。

结果数据显示在以下截图中:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/75f9ff53-7e1f-4509-b02c-e51634534181.png

另一种表示这些数据的方式是使用饼图:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/5ecad4e9-16f5-49c0-9297-a45a28411cdd.png

以下代码展示了我们如何在 R 中构建这些饼图:

# pie chart
ggplot(conversionsByMaritalStatus, aes(x="", y=Count, fill=Marital)) + 
  geom_bar(width=1, stat = "identity", position=position_fill()) +
  geom_text(aes(x=1.25, label=Count), position=position_fill(vjust = 0.5)) +
  coord_polar("y") +
  facet_wrap(~Conversion) +
  ggtitle('Marital Status (0: Non Conversions, 1: Conversions)') +
  theme(
    axis.title.x=element_blank(),
    axis.title.y=element_blank(),
    plot.title=element_text(hjust=0.5),
    legend.position='bottom'
  )

在 R 中构建饼图时,我们使用相同的geom_bar函数,就像我们在构建柱状图时一样。这里的区别在于coord_polar("y"),它将柱状图转换为饼图。接着,我们使用facet_wrap函数根据Conversion列创建两列饼图。这会生成两个饼图,一个用于转化组,另一个用于非转化组。

与数据输出的表格格式相比,饼图更容易理解数据的整体分布。通过饼图,我们可以很容易看到married组在转化组和非转化组中都占据了最大的比例,而single组位居第二。通过饼图,我们可以轻松地可视化两个组之间的相似性和差异。

按年龄和婚姻状况分组的转化情况

到目前为止,我们已经根据一个标准对数据进行了汇总。然而,有时你可能希望根据多个列来分组数据。在本节中,我们将讨论如何根据多个标准来分析和报告转化率。作为练习,我们将使用上一节中构建的年龄组和婚姻状况作为两个分组标准。

让我们先看一下代码:

#### 5\. Conversions by Age Groups & Marital Status ####
conversionsByAgeMarital <- conversionsDF %>% 
  group_by(AgeGroup=cut(age, breaks= seq(20, 70, by = 10)), Marital=marital) %>% 
  summarise(Count=n(), NumConversions=sum(conversion)) %>%
  mutate(TotalCount=sum(Count)) %>%
  mutate(ConversionRate=NumConversions/TotalCount)

conversionsByAgeMarital$AgeGroup <- as.character(conversionsByAgeMarital$AgeGroup)
conversionsByAgeMarital$AgeGroup[is.na(conversionsByAgeMarital$AgeGroup)] <- "70+"

类似于我们构建自定义年龄组时,我们在group_by中使用cut函数,将年龄分组为从2070,每 10 岁一组。然而,这次我们也按marital列进行分组。

然后,我们使用summarise函数计算每个组中的记录数量Count,以及每个组中的转化次数NumConversions。接着,使用mutate函数计算每个年龄组的总记录数,命名为TotalCount,以及每个组的转化率,命名为ConversionRate

结果数据显示在以下截图中:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/94774145-f1a9-4d75-8967-a246e7766c99.png

从这些数据中可以看出,我们现在可以根据两个标准来查看转化率的分布:年龄组和婚姻状况。例如,单身且年龄在2030岁之间的客户转化率为 11.10%,而已婚且年龄在4050岁之间的客户转化率为 5.74%。

另一种可视化这些数据的方法是使用条形图:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/617745e6-5fcc-44dc-a6b9-5b8cac7eed42.png

在这个条形图中,我们可以轻松地看到每个年龄组和婚姻状况组的转化率分布。我们用来构建这个条形图的代码如下:

# bar chart
ggplot(conversionsByAgeMarital, aes(x=AgeGroup, y=ConversionRate, fill=Marital)) + 
  geom_bar(width=0.5, stat="identity", position="dodge") +
  ylab("Conversion Rate (%)") +
  xlab("Age") +
  ggtitle("Conversion Rates by Age and Marital Status") +
  theme(plot.title=element_text(hjust=0.5))

在这里,我们创建了一个ggplot对象,使用了conversionsByAgeMarital数据。我们使用AgeGroup作为X轴,ConversionRate作为Y轴,同时用Marital列为不同的婚姻状况类型指定不同的颜色。接着,我们通过使用geom_bar函数来构建条形图。通过这个配置,ggplot会构建一个按婚姻状况细分的转化率与年龄组之间的堆积条形图,这一点在之前的条形图中已经展示过了。

如果你想要为每个年龄组堆叠这四个条形图,可以使用以下代码来绘制堆积条形图:

# stacked bar chart
ggplot(conversionsByAgeMarital, aes(x=AgeGroup, y=ConversionRate, fill=Marital)) + 
  geom_bar(width=0.5, stat="identity", position="stack") +
  ylab("Conversion Rate (%)") +
  xlab("Age") +
  ggtitle("Conversion Rates by Age and Marital Status") +
  theme(plot.title=element_text(hjust=0.5))

从这段代码中可以看出,唯一的不同之处在于geom_bar函数中的代码position="stack"。如果你将值"dodge"传递给geom_bar函数的position参数,它将创建一个未堆叠的条形图。而如果你将值"stack"传递给geom_bar函数的position参数,它将创建一个堆积条形图,效果如下:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/2c6297ad-bd1e-4726-87f2-44ddd21d5fcf.png

从这个堆积条形图中可以看到,不同的婚姻状况在每个年龄组中堆叠在一起。这样,我们不仅可以轻松地看到不同年龄组之间转化率的总体趋势,还可以看到每个年龄组中不同婚姻状况的转化客户比例。

我们在这个 R 练习中使用的完整代码可以在以下仓库中找到:github.com/yoonhwang/hands-on-data-science-for-marketing/blob/master/ch.2/R/ConversionRate.R

总结

在本章中,我们讨论了如何使用描述性分析来报告和分析营销努力的进展和表现。我们讨论了营销中常用的各种关键绩效指标(KPIs),用以跟踪营销活动的进展。我们了解到,评估每个营销策略产生的销售收入有多么重要。在分析销售收入指标时,我们发现从不同角度进行分析非常关键。你可能不仅想查看总销售收入,还要查看时间序列(按月、季度或年度)的销售收入。你还可能希望查看归因于每个营销活动的销售收入,并分析每个活动为公司带来了多少收入。我们还讨论了 CPA 指标,通过这些指标你可以评估营销策略的成本效益。我们也学习了用于数字营销渠道的各种指标,比如点击率(CTR)、潜在客户转化率和转化率。正如我们在 Python 和 R 练习中所看到和实验的那样,我们可以对这些 KPI 指标进行更深入的多层次分析。

在下一章中,我们将学习如何应用数据科学和机器学习技术进行解释性分析。更具体地说,我们将讨论如何使用回归分析和模型来理解营销参与背后的驱动因素。我们还将在下一章中讲解如何解读回归分析结果。

第三章:驱动营销参与度的因素

当你进行营销活动时,你需要重点关注并分析的一个重要指标是客户对营销活动的参与度。例如,在电子邮件营销中,客户参与度可以通过客户打开或忽略你的营销邮件的数量来衡量。客户参与度还可以通过单个客户访问网站的次数来衡量。成功的营销活动会吸引大量客户参与,而无效的营销活动不仅会导致客户参与度较低,还会对你的业务产生负面影响。客户可能会将你的邮件标记为垃圾邮件或取消订阅你的邮件列表。

为了理解是什么影响了客户的参与度,本章我们将讨论如何使用解释性分析(更具体地说,是回归分析)。我们将简要介绍解释性分析的定义,回归分析是什么,以及如何使用逻辑回归模型进行解释性分析。接着,我们将讨论如何在 Python 中使用statsmodels包来构建和解释回归分析结果。对于 R 程序员,我们将讨论如何使用glm来构建和解释回归分析结果。

本章将涵盖以下主题:

  • 使用回归分析进行解释性分析

  • 使用 Python 进行回归分析

  • 使用 R 进行回归分析

使用回归分析进行解释性分析

在第二章中,关键绩效指标与可视化,我们讨论了描述性分析是什么,以及它如何帮助我们更好地理解数据集。我们通过使用各种可视化技术,并在 Python 和 R 中构建不同类型的图表进行了实验。

在本章中,我们将扩展我们的知识,开始讨论在营销中何时、如何以及为什么使用解释性分析

解释性分析与回归分析

正如我们在第一章中简要讨论的,数据科学与营销,解释性分析的目的是回答我们为何使用数据,而描述性分析的目的是回答我们用数据做什么,如何使用数据。当你进行不同的营销活动时,你通常会发现某些营销活动的表现比其他活动好得多;你可能会想知道,为什么有些营销活动效果如此之好,而有些却没有。例如,你可能想了解哪些类型和群体的客户比其他人更频繁地打开你的营销邮件。另一个例子是,你可能想分析客户群体的哪些属性与更高的转化率和商品购买率密切相关。

通过解释性分析,你可以分析并理解与所需结果高度相关的关键因素。回归分析和回归模型常用于建模属性与结果之间的关系。简而言之,回归分析通过找到最能近似输出值的属性或特征函数来估算输出变量的值。回归分析中一种常用的形式是线性回归。顾名思义,在线性回归中,我们尝试通过特征的线性组合来估计输出变量。如果我们用Y表示输出变量,用X[i]表示每个特征,其中i是第i个特征,那么线性回归公式如下:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/4141c7bf-bbc5-4f2d-9b36-2c3877c5a77c.png

从上述公式中可以看到,输出变量Y表示为特征X[i]的线性组合。线性回归模型的目的是找到最能估算输出变量的截距a和系数b[i],并利用给定的特征进行拟合。拟合的线性回归线大致如下所示(图片来源于 towardsdatascience.com/linear-regression-using-python-b136c91bf0a2):

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/d60fa219-a286-4b2c-a92e-209e6f4d3109.png

该图中的蓝色点表示数据点,红色线是拟合的或训练过的线性回归线。正如图表所示,线性回归试图通过特征的线性组合来估计目标变量。

在本章中,我们将讨论如何使用回归分析,尤其是逻辑回归模型,来理解是什么驱动了更高的客户参与度。

逻辑回归

逻辑回归是一种回归分析方法,通常用于输出变量是二元的情况(表示正面结果为 1,负面结果为 0)。与其他线性回归模型类似,逻辑回归模型通过特征变量的线性组合来估算输出。唯一的区别是模型估算的内容。与其他线性回归模型不同,逻辑回归模型估算的是事件的对数机会,或者换句话说,是正面事件和负面事件概率之间的对数比率。其公式如下:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/1946fce3-7d03-485d-a545-bd55a8d47e10.png

左边的比率是成功的机会,表示成功的概率与失败的概率之间的比率。对数机会的曲线,也称为logit 曲线,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/ef7f8d76-83b1-4317-8df0-623cc1512349.png

逻辑回归模型的输出只是 logit 的逆,它的值范围从零到一。在本章中,我们将使用回归分析来理解是什么推动了客户参与度,输出变量将是客户是否对营销电话作出回应。因此,逻辑回归在这种情况下非常适用,因为输出是一个二元变量,可以取两个值:响应和未响应。在接下来的章节中,我们将讨论如何在 Python 和 R 中使用和构建逻辑回归模型,然后我们将讲解如何解读回归分析结果,以理解哪些客户属性与更高的营销参与度高度相关。

使用 Python 进行回归分析

在本节中,你将学习如何在 Python 中使用statsmodels包进行回归分析。对于那些希望使用 R 而非 Python 的读者,可以跳到下一节。在本节开始时,我们将通过使用pandasmatplotlib包更仔细地查看数据,然后我们将讨论如何使用statsmodels库构建回归模型并解读结果。

在本练习中,我们将使用 IBM Watson 提供的公开数据集之一,数据集可以在www.ibm.com/communities/analytics/watson-analytics-blog/marketing-customer-value-analysis/找到。你可以点击链接下载 CSV 格式的数据文件。为了将该数据加载到你的 Jupyter Notebook 中,你可以运行以下代码:

import matplotlib.pyplot as plt
import pandas as pd

df = pd.read_csv('../data/WA_Fn-UseC_-Marketing-Customer-Value-Analysis.csv')

与我们在第二章中做的类似,关键绩效指标与可视化,我们首先导入matplotlibpandas包;使用pandas中的read_csv函数,我们可以将数据读取到pandas DataFrame 中。稍后我们将使用matplotlib进行数据分析和可视化。

加载后的 DataFrame,df,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/333d7a69-95a2-4044-bcc1-5b6e92b72fc6.png

如我们在第二章中讨论的,关键绩效指标与可视化,DataFrame 的shape属性告诉我们 DataFrame 中行和列的数量,而head函数会显示数据集的前五条记录。一旦成功将数据读取到pandas DataFrame 中,数据应呈现如截图所示。

数据分析与可视化

在进行回归分析之前,我们首先要更详细地查看数据,以便更好地理解我们拥有的数据点以及数据中可以看到的模式。如果你查看数据,你会注意到有一列名为Response,它包含客户是否响应营销呼叫的信息。我们将使用这个字段作为客户参与度的衡量标准。为了进行后续的计算,最好将这个字段编码为数值型。让我们看一下以下代码:

df['Engaged'] = df['Response'].apply(lambda x: 0 if x == 'No' else 1)

正如你在这段代码中看到的,我们使用pandas数据框的apply函数,将未响应营销呼叫的客户(No)编码为0,而响应的客户(Yes)编码为1。我们创建了一个名为Engaged的新字段,存储这些编码值。

参与率

我们首先要查看的是总体参与率。这个参与率简单来说就是响应营销呼叫的客户百分比。请看下面的代码:

engagement_rate_df = pd.DataFrame(
    df.groupby('Engaged').count()['Response'] / df.shape[0] * 100.0
)

正如你从这段代码中看到的,我们使用pandas数据框的groupby函数按新创建的字段Engaged进行分组。接着,我们使用count函数统计每个Engaged组中的记录数(或客户数)。通过除以数据框中客户的总数并乘以100.0,我们得到参与率。结果如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/97193318-df6f-461f-9404-86cb8ed4b87b.png

为了更容易阅读,我们可以转置数据框(DataFrame),这意味着我们可以翻转数据框中的行和列。你可以通过使用数据框的T属性来转置pandas数据框。其效果如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/04dd8f15-66c7-4bdd-a2c3-1e04839e1447.png

如你所见,大约 14%的客户响应了营销呼叫,其余 86%的客户未做响应。

销售渠道

现在,让我们看看是否能在销售渠道和客户参与度之间找到任何明显的模式。我们将分析参与和未参与的客户在不同销售渠道中的分布。首先看一下以下代码:

engagement_by_sales_channel_df = pd.pivot_table(
    df, values='Response', index='Sales Channel', columns='Engaged', aggfunc=len
).fillna(0.0)

engagement_by_sales_channel_df.columns = ['Not Engaged', 'Engaged']

正如你在这段代码中看到的,我们正在使用pandas库的pivot_table函数按Sales ChannelResponse变量进行分组。运行这段代码后,engagement_by_sales_channel_df将包含如下数据:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/0cd77263-2dc4-4680-b552-5a1d92ed0bcb.png

正如你在上一节中已经注意到的,未参与营销活动的客户明显更多,因此在原始数据中很难直接看出参与客户与未参与客户在销售渠道分布上的差异。为了让这些差异更加直观地显现出来,我们可以使用以下代码构建饼图:

engagement_by_sales_channel_df.plot(
    kind='pie',
    figsize=(15, 7),
    startangle=90,
    subplots=True,
    autopct=lambda x: '%0.1f%%' % x
)

plt.show()

一旦你运行这段代码,你将看到以下饼图,展示了已参与和未参与客户在不同销售渠道中的分布情况:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/7e5402ab-645b-41ea-92ef-4e00ba53ac02.png

与之前显示每个销售渠道中已参与和未参与客户原始计数的表格相比,这些饼图帮助我们更轻松地可视化并发现分布差异。如你从这些图表中看到的,超过一半的已参与客户来自代理商,而未参与客户则更均匀地分布在所有四个不同的渠道中。正如你从这些图表中看到的,分析和可视化数据能够帮助我们发现数据中的有趣模式,这将在本章后续的回归分析中提供帮助。

总赔付金额

在我们进入回归分析之前,我们要先看一下Total Claim Amount在已参与和未参与组之间分布的差异。我们将通过箱形图来可视化这一点。首先,让我们看一下如何在 Python 中构建箱形图,如下所示:

ax = df[['Engaged', 'Total Claim Amount']].boxplot(
    by='Engaged',
    showfliers=False,
    figsize=(7,5)
)

ax.set_xlabel('Engaged')
ax.set_ylabel('Total Claim Amount')
ax.set_title('Total Claim Amount Distributions by Engagements')

plt.suptitle("")
plt.show()

如你在这段代码中看到的,从pandas DataFrame 中构建箱形图非常简单。你只需调用boxplot函数。箱形图是可视化连续变量分布的一个极好的方式。它们展示了最小值、最大值、第一个四分位数、中位数和第三个四分位数,一目了然。以下箱形图展示了Total Claim Amount在已参与和未参与组之间的分布:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/c38b00b9-e2ca-4edd-a34a-cf67ba11ea74.png

中央矩形从第一个四分位数到第三个四分位数,绿色线条显示中位数。下边和上边分别显示分布的最小值和最大值。需要注意的是,在之前的代码中使用了showfliers=False参数。让我们看看当我们将该参数设置为True时会发生什么,使用以下代码:

ax = df[['Engaged', 'Total Claim Amount']].boxplot(
    by='Engaged',
    showfliers=True,
    figsize=(7,5)
)

ax.set_xlabel('Engaged')
ax.set_ylabel('Total Claim Amount')
ax.set_title('Total Claim Amount Distributions by Engagements')

plt.suptitle("")
plt.show()

使用这段代码并设置showfliers=True标志,生成的箱形图如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/5ff9f5b8-a67b-4e31-b2df-6f1c2661ac25.png

正如你在这些箱形图中所注意到的,它们在上边界线之上绘制了许多点,这些点代表了之前箱形图中的最大值。上边界线上的点显示了基于四分位距IQR)判定的疑似异常值。IQR 即第一个四分位数和第三个四分位数之间的范围,任何超过第三个四分位数1.5*IQR或低于第一个四分位数1.5*IQR的点都被认为是疑似异常值,并通过这些点显示出来。

回归分析

到目前为止,我们已经分析了数据中字段的类型以及参与组和非参与组之间的模式差异。现在,我们将讨论如何使用 statsmodels 包在 Python 中进行回归分析及其解释。我们将首先用连续变量构建一个逻辑回归模型,并学习如何解释结果。接着,我们将讨论在拟合回归模型时如何处理分类变量,以及这些分类变量对拟合的逻辑回归模型的影响。

连续变量

在线性回归中,包括逻辑回归,当特征变量是连续的时,拟合回归模型非常简单,因为它只需要找到特征变量的线性组合,利用数值特征来估计输出变量。为了用连续变量拟合回归模型,首先让我们看看如何获取 pandas DataFrame 中列的数据类型。请看以下内容:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/13cfa30a-b8b2-45db-8b1b-cc3b0b115cd3.png

如你从这张 Jupyter Notebook 截图中看到的,pandas Series 对象的 dtype 属性告诉你它包含的数据类型。从这张截图可以看出,Income 变量是整数,而 Customer Lifetime Value 特征是浮点数。为了快速查看具有数值的变量的分布,你也可以执行以下操作:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/58348fa5-b7e6-49c3-b9de-5175614c4b24.png

如你在这个 Jupyter Notebook 截图中看到的,pandas DataFrame 的 describe 函数显示了所有数值列的分布。例如,你可以看到 Customer Lifetime Value 列中共有 9134 条记录,均值为 8004.94,范围从 1898.0183325.38

我们将把这些连续变量的名称存储在一个单独的变量中,命名为 continuous_vars。请看以下代码:

continuous_vars = [
    'Customer Lifetime Value', 'Income', 'Monthly Premium Auto', 
    'Months Since Last Claim', 'Months Since Policy Inception', 
    'Number of Open Complaints', 'Number of Policies', 
    'Total Claim Amount'
]

现在我们已经知道哪些列是连续变量,让我们开始拟合逻辑回归模型。为此,我们需要先导入 statsmodels 包,如下代码所示:

import statsmodels.formula.api as sm

导入 statsmodels 包后,启动一个逻辑回归模型的代码非常简单,如下所示:

logit = sm.Logit(
    df['Engaged'], 
    df[continuous_vars]
)

如你从这段代码中看到的,我们正在使用 statsmodels 包中的 Logit 函数。我们将 Engaged 列作为输出变量,模型将学习如何估计该输出,而 continuous_vars 列包含所有的连续变量,作为输入变量。定义了输出和输入变量后,一旦创建了逻辑回归对象,我们可以使用以下代码来训练或拟合这个模型:

logit_fit = logit.fit()

如你在这段代码中看到的,我们正在使用逻辑回归对象logitfit函数来训练逻辑回归模型。运行这段代码后,训练好的模型logit_fit将学习出最佳解决方案,通过使用输入变量来最佳估计输出变量Engaged。若要获得已训练模型的详细描述,可以使用以下代码:

logit_fit.summary()

当你运行这段代码时,summary函数将在 Jupyter Notebook 中显示以下输出:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/39146c4c-eacf-42ab-80f4-4801a8e3b76b.png

让我们更仔细地看看这个模型输出。coef表示每个输入变量的系数,z表示z-分数,它是离均值的标准差个数。P>|z|列表示p-值,它表示通过偶然性观察到特征与输出变量之间关系的可能性。因此,P>|z|的值越低,给定特征与输出变量之间的关系越强,且不太可能是偶然的。通常,0.05是一个良好的p-值临界点,任何小于0.05的值都表示给定特征与输出变量之间存在强关系。

从这个模型输出中,我们可以看到,IncomeMonthly Premium AutoMonths Since Last ClaimMonths Since Policy InceptionNumber of Policies变量与输出变量Engaged有显著的关系。例如,Number of Policies变量是显著的,并且与Engaged呈负相关。这表明,客户拥有的保单越多,他们响应营销电话的可能性越小。另一个例子是,Months Since Last Claim变量也是显著的,并且与输出变量Engaged呈负相关。这意味着,自上次理赔以来的时间越长,客户回应营销电话的可能性就越低。

从这些例子中你可以看出,通过查看模型输出中特征的p-值和系数,你可以轻松地解释回归分析结果。这是理解哪些客户特征与我们关心的结果显著相关的好方法。

分类变量

正如你在上一节中看到的连续变量的例子,理解输入和输出变量之间的关系是相当直接的,尤其是通过系数和p-值。然而,当我们引入类别变量时,情况就变得不那么直观了。类别变量通常没有任何自然顺序,或者它们被编码为非数值型的值,但在回归分析中,我们需要输入变量具有数值型的值,这些值能够表示变量的顺序或大小。例如,我们无法轻松地为数据集中的State变量编码出某种顺序或数值。这就是为什么在进行回归分析时,我们需要与连续变量不同地处理类别变量。在 Python 中,当使用pandas包时,有多种方式来处理类别变量。我们首先来看一下如何对类别变量进行因子化,如下面的代码所示:

gender_values, gender_labels = df['Gender'].factorize()

pandasfactorize函数通过枚举值对类别变量进行数值编码。我们先来看一下下面的输出:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/6bd1e57a-4ea2-4d5d-b7a6-96c59a34773e.png

从这个输出中可以看出,Gender变量的值被用零和一编码,其中0表示女性(F),1表示男性(M)。这是一种快速地将类别变量编码为数值型值的方法。然而,当我们希望将自然顺序嵌入编码值时,这个函数就不起作用了。例如,我们数据集中的Education变量有五个不同的类别:High School or BelowBachelorCollegeMasterDoctor。我们可能希望在对Education变量内的不同类别进行编码时,能够嵌入顺序关系。

以下代码展示了另一种在使用pandas时对类别变量进行排序编码的方法:

categories = pd.Categorical(
    df['Education'], 
    categories=['High School or Below', 'Bachelor', 'College', 'Master', 'Doctor']
)

如你在这段代码中看到的,我们使用pd.Categorical函数对df['Education']的值进行编码。我们可以通过参数categories来定义我们希望的排序。在我们的例子中,我们为High School or BelowBachelorCollegeMasterDoctor这些类别分别赋予了01234的值。输出如下所示:

我们现在将这些编码后的变量添加到 pandas DataFrame df中,如下面的代码所示:

df['GenderFactorized'] = gender_values
df['EducationFactorized'] = categories.codes

使用这两个类别变量,GenderEducation的编码后,我们可以使用以下代码来拟合逻辑回归模型:

logit = sm.Logit(
    df['Engaged'], 
    df[[
        'GenderFactorized',
        'EducationFactorized'
    ]]
)

logit_fit = logit.fit()

类似于之前如何使用连续变量拟合逻辑回归模型,我们可以使用statsmodels包中的Logit函数,利用编码后的类别变量GenderFactorizedEducationFactorized来拟合逻辑回归模型。使用拟合后的逻辑回归模型对象的summary函数,我们将得到如下输出:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/5ebbe76b-7881-455c-923a-8f3a1025b757.png

如你所见,从输出结果中以及查看P>|z|列中的p-值,GenderFactorizedEducationFactorized这两个变量似乎与输出变量Engaged之间存在显著关系。如果我们查看这两个变量的系数,可以看到它们与输出变量呈负相关。这表明,与女性客户(在GenderFactorized变量中编码为0)相比,男性客户(在GenderFactorized变量中编码为1)更不可能参与营销电话。同样,客户的教育水平越高,他们参与营销电话的可能性就越低。

我们已经讨论了在pandas中处理分类变量的两种方法,分别是使用factorizeCategorical函数。通过这些技术,我们可以了解不同类别的分类变量与输出变量之间的相关性。

结合连续变量和分类变量

本章我们将进行的最后一个 Python 练习涉及将连续变量和分类变量结合起来进行回归分析。我们可以通过同时使用分类变量和连续变量来拟合逻辑回归模型,代码如下所示:

logit = sm.Logit(
    df['Engaged'], 
    df[['Customer Lifetime Value',
        'Income',
        'Monthly Premium Auto',
        'Months Since Last Claim',
        'Months Since Policy Inception',
        'Number of Open Complaints',
        'Number of Policies',
        'Total Claim Amount',
        'GenderFactorized',
        'EducationFactorized'
    ]]
)

logit_fit = logit.fit()

与之前的代码唯一不同的是我们选择的特征,用于拟合逻辑回归模型。如你所见,在这段代码中,我们现在使用连续变量以及之前部分章节中创建的两个编码后的分类变量GenderFactorizedEducationFactorized来拟合逻辑回归模型。结果如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/9d55b21f-2e47-4da4-a572-f517ad414c2a.png

让我们仔细看看这个输出。IncomeMonthly Premium AutoMonths Since Last ClaimMonths Since Policy InceptionNumber of Open ComplaintsNumber of PoliciesGenderFactorized这些变量在0.05的显著性水平下具有显著性,且它们与输出变量Engaged之间的关系都是负相关的。因此,收入越高,客户参与营销电话的可能性就越低。同样,客户拥有的保单越多,他们参与营销电话的可能性就越低。

最后,男性客户比女性客户更不可能参与营销电话,我们可以从GenderFactorized的系数中看到这一点。从这个回归分析的输出结果来看,我们可以轻松看到输入变量与输出变量之间的关系,并且可以理解哪些客户的属性与他们是否参与营销电话之间是正相关还是负相关。

本章中 Python 练习的完整代码可以在 github.com/yoonhwang/hands-on-data-science-for-marketing/blob/master/ch.3/python/RegressionAnalysis.ipynb 找到。

使用 R 进行回归分析

在本节中,你将学习如何使用 R 中的 glm 函数进行回归分析。对于那些希望使用 Python 而非 R 进行此练习的读者,Python 的逐步操作说明可以在上一节找到。我们将从更仔细地分析数据开始,使用 dplyr 包,然后讨论如何使用 glm 函数构建回归模型并解读结果。

在本次练习中,我们将使用来自 IBM Watson 的一个公开数据集,可以在 www.ibm.com/communities/analytics/watson-analytics-blog/marketing-customer-value-analysis/ 找到。你可以点击此链接并下载 CSV 格式的数据文件。为了将数据加载到你的 RStudio 中,你可以运行以下代码:

library(dplyr)
library(ggplot2)

# Load data
df <- read.csv(
  file="~/Documents/data-science-for-marketing/ch.3/data/WA_Fn-UseC_-Marketing-Customer-Value-Analysis.csv", 
  header=TRUE, 
  sep=","
)

类似于我们在 第二章 关键绩效指标与可视化 中所做的那样,我们将在接下来的章节中首先导入 dplyrggplot2 包,以进行数据分析和绘图。通过在 R 中使用 read.csv 函数,我们可以将数据读取到 DataFrame 中。由于此 CSV 文件的第一行包含标题,且字段由逗号分隔,我们使用 header=TRUEsep="," 标志以确保正确解析数据。

以下截图展示了数据在 DataFrame 中的原始样子:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/bfe00dbe-78f4-45a4-a4aa-2376f7431410.png

现在我们已经将数据加载到 DataFrame 中,让我们开始更仔细地查看和分析数据,以便更好地理解数据的结构。

数据分析与可视化

在我们深入回归分析之前,让我们先更详细地查看数据,以便更好地了解我们拥有的数据点以及可以在数据中看到的模式。如果你查看数据,会注意到一个名为 Response 的列,它包含客户是否回应营销电话的信息。我们将使用这个字段作为客户参与度的衡量标准。为了进行未来的计算,最好将这个字段编码为数值类型。让我们来看一下以下代码:

# Encode Response as 0s and 1s
df$Engaged <- as.integer(df$Response) - 1

如您在这段代码中所见,我们使用as.integer函数将未回应营销电话(No)的客户编码为0,将回应营销电话(Yes)的客户编码为1。由于as.integer函数默认将值编码为12,我们通过减去1来将回应值编码为零和一。然后,我们创建了一个名为Engaged的新字段,其中包含这些编码后的值。

参与率

我们首先要看的内容是汇总的参与率。这个参与率简单来说就是回应了营销电话的客户所占的百分比。请看以下代码:

engagementRate <- df %>% 
  group_by(Engaged) %>% 
  summarise(Count=n()) %>%
  mutate(Percentage=Count/nrow(df)*100.0)

如您在这段代码中所见,我们通过使用group_by函数按新创建的Engaged字段进行分组。然后,我们使用n()函数统计每个Engaged组中的记录或客户数量。通过将其除以数据框df中的总客户数,并乘以100.0,我们得到了参与率。结果如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/46c83142-7a95-4635-abf9-0bf6c55b1192.png

为了更方便地阅读,我们可以转置数据框,这意味着我们将数据框中的行和列进行交换。您可以使用 R 中的t函数来转置数据框。代码如下所示:

# Transpose
transposed <- t(engagementRate)

colnames(transposed) <- engagementRate$Engaged
transposed <- transposed[-1,]

转置后的数据框如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/61534cae-683e-4984-ae49-6a1f375555b3.png

如您所见,通过转置数据框,我们可以更容易地查看参与和未参与客户的总数和百分比。从这些数据中,我们可以看到大约 14%的客户回应了营销电话,剩余的 86%的客户未回应。

销售渠道

现在,让我们看看是否能发现销售渠道和参与之间的明显模式。我们将分析参与和未参与的客户在不同销售渠道中的分布。首先请看以下代码:

salesChannel <- df %>% 
  group_by(Engaged, Channel=Sales.Channel) %>% 
  summarise(Count=n())

如您在这段代码中所见,我们使用了 R 中的group_by函数对Sales ChannelEngaged变量进行分组。然后,使用n()函数,我们将统计每个组中的客户数量。运行这段代码后,salesChannel数据框将如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/34a46f66-6a8f-4c2d-aa4c-b8ee50112ab4.png

正如您在上一节中所注意到的,未参与营销活动的客户明显更多,因此,单凭原始数字很难比较并查看参与和未参与客户在销售渠道分布上的差异。为了更直观地区分这些差异,我们可以使用以下代码绘制饼图:

# pie chart
ggplot(salesChannel, aes(x="", y=Count, fill=Channel)) + 
  geom_bar(width=1, stat = "identity", position=position_fill()) +
  geom_text(aes(x=1.25, label=Count), position=position_fill(vjust = 0.5)) +
  coord_polar("y") +
  facet_wrap(~Engaged) +
  ggtitle('Sales Channel (0: Not Engaged, 1: Engaged)') +
  theme(
    axis.title.x=element_blank(),
    axis.title.y=element_blank(),
    plot.title=element_text(hjust=0.5),
    legend.position='bottom'
  )

与我们在第二章《关键绩效指标和可视化》中所做的类似,我们使用ggplot来在 R 中构建图表。如果你还记得那一章,我们可以通过使用geom_barcoord_polar("y")来构建饼图。通过使用facet_wrap(~Engaged),我们可以将饼图分成两部分:一部分是未参与的客户,另一部分是已参与的客户。一旦你运行了这段代码,你会看到如下饼图,展示了已参与和未参与的客户在不同销售渠道中的分布:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/8c162b53-d864-4865-93eb-13c38d1fc0a6.png

与之前展示的每个销售渠道中已参与和未参与客户的原始计数数据表相比,这些饼图可以帮助我们更直观地看到分布差异。如你从这些图表中所看到的,超过一半的已参与客户来自代理商,而未参与的客户则在所有四个销售渠道中分布较为均匀。从这些图表中可以看出,数据分析和可视化帮助我们发现数据中的有趣模式,这将进一步帮助我们在本章后续进行回归分析时。

总赔偿金额

在我们深入回归分析之前,最后要看的内容是Total Claim Amount在已参与和未参与组之间的分布差异。我们将通过箱线图来可视化这一点。首先,我们来看一下如何在 R 中构建箱线图:

ggplot(df, aes(x="", y=Total.Claim.Amount)) + 
  geom_boxplot() +
  facet_wrap(~Engaged) +
  ylab("Total Claim Amount") +
  xlab("0: Not Engaged, 1: Engaged") +
  ggtitle("Engaged vs. Not Engaged: Total Claim Amount") +
  theme(plot.title=element_text(hjust=0.5))

正如你在这段代码中所看到的,在 R 中构建箱线图非常简单。你只需调用ggplot函数,并使用geom_boxplot。箱线图是可视化连续变量分布的一个好方法。它显示了最小值、最大值、第一个四分位数、中位数和第三个四分位数,所有这些都能一目了然地呈现。以下箱线图展示了Total Claim Amount在已参与和未参与组之间的分布:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/25b89a8f-f883-400c-812b-6866d25c84b7.png

中央矩形从第一个四分位数到第三个四分位数,矩形内的线表示中位数。矩形的上下端点分别表示分布的最小值和最大值。你还会注意到这些箱线图中,线的上方有一些点。

超过上边线的点表示疑似异常值,这些值是基于 IQR(四分位距)来判断的。IQR 是指第一个四分位数和第三个四分位数之间的范围,也就是箱线图中从第一个四分位数到第三个四分位数的矩形高度。数据点如果高于第三个四分位数1.5*IQR或低于第一个四分位数1.5*IQR,就被认为是疑似异常值,并用点表示。

根据你的分析目标,你可能不在乎(或者你可能不想显示)箱线图中的异常值。我们来看一下以下代码,看看如何从箱线图中去除这些异常值:

# without outliers
ggplot(df, aes(x="", y=Total.Claim.Amount)) + 
  geom_boxplot(outlier.shape = NA) +
  scale_y_continuous(limits = quantile(df$Total.Claim.Amount, c(0.1, 0.9))) +
  facet_wrap(~Engaged) +
  ylab("Total Claim Amount") +
  xlab("0: Not Engaged, 1: Engaged") +
  ggtitle("Engaged vs. Not Engaged: Total Claim Amount") +
  theme(plot.title=element_text(hjust=0.5))

如你在这段代码中所注意到的,这段代码与之前的唯一区别是geom_boxplot函数中的outlier.shape=NA。我们来看一下现在箱线图的样子:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/427c69d6-87c2-4137-bd7d-f9d4d565c7c9.png

在这些图中,我们不再看到超出上限的点。根据你想要展示和分析的内容,箱线图中是否包含异常值可能会有所不同。

回归分析

到目前为止,我们已经分析了数据中的字段类型以及参与组和非参与组之间的模式差异。接下来,我们将讨论如何使用glm函数进行回归分析并解释结果。我们将首先构建一个包含连续变量的逻辑回归模型,并学习如何解释其结果。然后,我们将讨论在R中拟合回归模型时如何处理分类变量,以及这些分类变量对拟合的逻辑回归模型的影响。

连续变量

在线性回归中,包括逻辑回归,当特征变量是连续变量时,拟合回归模型非常简单,因为它只需要找到特征变量的线性组合来估计输出变量。为了拟合一个包含连续变量的回归模型,我们首先来看一下如何获取R数据框中各列的数据类型。请看以下代码:

# get data types of each column
sapply(df, class)

R中使用sapply函数,我们可以将class函数应用于数据框的各列,class函数告诉我们每列的数据类型。此代码的输出如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/99e6ea9c-822d-4e6b-8904-853a3b426c2b.png

如前面的截图所示,我们可以轻松看出哪些列包含数值,哪些列不包含数值。例如,State列的类型是"factor",这意味着该变量是一个分类变量。另一方面,Customer.Lifetime.Value列的类型是"numeric",这意味着该变量是一个具有数值的连续变量。除此之外,我们还可以使用R函数summary来获取数据框中每列的汇总统计信息,这样我们不仅可以查看每列的数据类型,还能看到每列的分布概况。代码如下:

# summary statistics per column
summary(df)

当你运行此代码时,输出将如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/3fc841d4-179a-4089-b299-b0934b7fd763.png

在这个输出中,我们可以轻松地看到每列在R数据框中的分布情况。例如,对于State变量,我们可以看到来自Arizona的记录或客户有1703条,来自California的客户有3150条。另一方面,我们可以看到Customer.Lifetime.Value变量的最小值是1898,均值是8005,最大值是83325

根据前面代码中的信息,我们可以轻松地通过以下代码只选择数值型列:

# get numeric columns
continuousDF <- select_if(df, is.numeric)
colnames(continuousDF)

如你在这段代码中所见,我们使用了select_if函数,传入的参数是数据框df和条件语句is.numeric,用于定义我们希望从数据框中子选的列类型。使用这个函数,数据框df中只有数值型的列会被选中,并作为一个名为continuousDF的单独变量存储。通过colnames函数,我们可以查看新创建的数据框continuousDF中有哪些列。你应该会看到类似以下的输出:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/fa4c358f-ccd2-4da8-9e75-a743a319ce02.png

我们现在准备使用连续变量拟合逻辑回归模型。首先让我们看看以下代码:

# Fit regression model with continuous variables
logit.fit <- glm(Engaged ~ ., data = continuousDF, family = binomial)

在 R 中,你可以通过使用glm函数来拟合回归模型,glm代表广义线性模型。R 的glm函数可以用于各种线性模型。默认情况下,family参数的值是gaussian,这会告诉算法拟合一个简单的线性回归模型。另一方面,如我们在此案例中所示,如果将family设置为binomial,则会拟合一个逻辑回归模型。有关family参数可以使用的不同值的详细描述,你可以参考stat.ethz.ch/R-manual/R-devel/library/stats/html/family.html

我们传递给glm函数的另外两个参数是formuladata。第一个参数formula是定义模型拟合方式的地方。~左侧的变量是输出变量,右侧的变量是输入变量。在我们的案例中,我们告诉模型通过使用其他所有变量作为输入变量来学习如何估计输出变量Engaged。如果你只想使用部分变量作为输入变量,则可以像下面这样编写公式:

Engaged ~ Income + Customer.Lifetime.Value

在这个公式中,我们告诉模型通过仅使用IncomeCustomer.Lifetime.Value作为特征来学习如何估计输出变量Engaged。最后,glm函数中的第二个参数data定义了用于训练回归模型的数据。

现在我们已经有了一个训练好的逻辑回归模型,让我们来看看以下的代码,它展示了我们如何从这个模型对象中获取详细的回归分析结果:

summary(logit.fit)

R 中的summary函数提供了回归分析结果的详细描述,结果如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/6c37619a-21ef-4ffa-b36e-9fc327da669a.png

让我们更详细地看看这个输出。Coefficients部分的Estimate列给出了每个特征系数的计算值。例如,Income变量的系数是0.000002042Number.of.Policies的系数是-0.02443。我们还可以看到估计的Intercept值是-1.787z value列给出了z-值,它是人口均值的标准差数,而Pr(>|z|)列是p-值,它表示通过偶然性观察到特征与输出变量之间关系的可能性。因此,Pr(>|z|)值越低,给定特征与输出变量之间的关系就越可能是强烈的,而不是偶然的。通常,0.05p-值的一个良好的分界点,任何小于0.05的值都表示给定特征与输出变量之间存在强关系。

从输出中Coefficients部分下的Signif. codes部分可以看出,***符号位于Coefficients部分的p-值旁边,表示p-值为0时的最强关系;**表示p-值小于0.001*表示p-值小于0.05,以此类推。如果你再看一下回归分析输出,只有三个变量——IncomeNumber.of.PoliciesTotal.Claim.Amount——在0.1的显著性水平下与输出变量Engaged有显著的关系。此外,我们可以看到,IncomeTotal.Claim.AmountEngaged呈正相关,意味着收入越高或总索赔金额越高,客户与营销电话互动的可能性就越大。另一方面,Number.of.PoliciesEngaged呈负相关,这表明客户拥有的保单数量越多,客户参与营销电话的可能性就越小。

正如你在这些示例中看到的,通过查看模型输出中各特征的p-值和系数,你可以很容易地解释回归分析结果。这是一种很好地理解哪些客户属性与感兴趣的结果有显著和高度相关性的方法。

类别变量

如您在上一节关于连续变量的案例中看到的那样,从系数和p-值中理解输入变量与输出变量之间的关系是非常直接的。然而,当我们引入分类变量时,这就变得不那么直观了。分类变量通常没有自然的顺序,但在进行线性回归时,我们需要输入变量具有数值,这些数值表示变量的顺序或大小。例如,我们不能轻易地给我们的数据集中的State变量编码特定的顺序或数值。这就是为什么在进行回归分析时,我们需要与连续变量不同地处理分类变量。在 R 语言中,factor函数帮助您轻松处理这些分类变量,以便进行回归分析。请看以下代码:

# a. Education
# Fit regression model with Education factor variables
logit.fit <- glm(Engaged ~ factor(Education), data = df, family = binomial)
summary(logit.fit)

如您在这段代码中所见,我们正在拟合一个以Engaged作为输出变量、以因子化的Education作为输入变量的逻辑回归模型。在我们深入了解这意味着什么之前,先让我们看看以下的回归分析结果:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/31ab77a5-aeb4-4ed5-8288-144e0ea82443.png

如您在此输出中所见,factor函数创建了四个额外的变量:factor(Education)Collegefactor(Education)Doctorfactor(Education)High School or Belowfactor(Education)Master。如果给定的客户不属于某一类别,这些变量会被编码为0;如果客户属于某一类别,这些变量则会被编码为1。这样,我们就可以理解每个Education类别与output变量Engaged之间的正向或负向关系。例如,因子变量factor(Education)Doctor具有正系数,这表明如果一个客户拥有博士学位,那么该客户更可能参与营销电话。

如果仔细观察,您会发现这个输出中,Education变量的Bachelor类别没有单独的因子变量。这是因为(Intercept)包含了Bachelor类别的信息。如果一个客户拥有学士学位,那么所有其他的因子变量都会被编码为0。因此,所有系数值都会被抵消,只有(Intercept)的值保留。由于估计的(Intercept)值为负数,如果一个客户拥有学士学位,那么该客户参与营销电话的可能性较低。

让我们来看另一个例子:

# b. Education + Gender
# Fit regression model with Education & Gender variables
logit.fit <- glm(Engaged ~ factor(Education) + factor(Gender), data = df, family = binomial)

summary(logit.fit)

如您在这段代码中所见,我们现在正在拟合一个包含EducationGender变量的回归模型,输出结果如下:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/86d48265-182c-4c31-b7e1-755ea30c0488.png

如果仔细查看此输出,您只会看到一个额外的因子变量 factor(Gender)M,它表示男性客户,而数据中明显包含女性客户。这是因为 Education 变量中的 Bachelor 类别和 Gender 变量中的 F(女性)类别被归为该回归模型的 (Intercept)。因此,当所有因子变量的值为 0 时,基本情况是具有 Bachelor 学位的 female 客户。

对于具有 Bachelor 学位的男性客户,因子变量 factor(Gender)M 将具有值 1,因此,输出变量 Engaged 的估计值将是 (Intercept) 加上 factor(Gender)M 的系数值。

如我们到目前为止所讨论的那样,我们可以通过在 R 中使用 factor 函数来处理分类变量。它本质上与为每个分类变量的每个类别创建一个单独的输入变量相同。使用这种技术,我们可以理解不同类别的分类变量如何与输出变量相关联。

结合连续变量和分类变量

本章我们要做的最后一个练习涉及将连续变量和分类变量结合起来进行回归分析。我们首先将前一节中讨论的两个分类变量 GenderEducation 进行因子化,并通过以下代码将它们存储在一个数据框中:

continuousDF$Gender <- factor(df$Gender)
continuousDF$Education <- factor(df$Education)

现在,数据框 continuousDF 包含以下列:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/51c0514f-23f0-474c-ae49-53136c894319.png

现在,我们将使用以下代码来拟合一个包含分类变量和连续变量的逻辑回归模型:

# Fit regression model with Education & Gender variables
logit.fit <- glm(Engaged ~ ., data = continuousDF, family = binomial)
summary(logit.fit)

您应该得到如下输出:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/e3a76724-02ca-4dbb-b3db-9cbb77ee9554.png

让我们更仔细地查看此输出。Total.Claim.Amount 变量和 EducationDoctor 变量在 0.05 显著性水平下显著,并且它们与输出变量 Engaged 存在正相关关系。因此,理赔总金额越高,客户与营销电话互动的可能性越大。此外,博士学位的客户比其他教育背景的客户更可能参与营销电话。在 0.1 显著性水平下,我们可以看到 IncomeNumber.of.PoliciesEducationMaster 现在与输出变量 Engaged 存在显著关系。从这个回归分析输出中,我们可以轻松看到输入变量和输出变量之间的关系,并理解哪些客户属性与客户对营销电话的互动正相关或负相关。

R 练习的完整代码可以在这个仓库中找到:github.com/yoonhwang/hands-on-data-science-for-marketing/blob/master/ch.3/R/RegressionAnalysis.R

总结

本章中,我们讨论了如何使用解释性分析来洞察客户行为。我们探讨了回归分析如何用于深入理解客户行为。更具体地,你学习了如何使用逻辑回归来理解哪些客户属性会推动更高的互动率。在 Python 和 R 的练习中,我们运用了在第二章《关键绩效指标与可视化》中讨论的描述性分析方法,并结合回归分析进行解释性分析。我们从分析数据开始,以便更好地理解和识别数据中的明显模式。在分析数据时,你还学习了通过箱线图(box plot)来可视化数据,使用 Python 中的matplotlibpandas包,以及 R 中的ggplot2库。

在拟合回归模型时,我们讨论了两种不同类型的变量:连续变量和分类变量。你学习了在拟合逻辑回归模型时,处理分类变量所面临的挑战,以及如何处理这些变量。对于 Python,我们介绍了处理分类变量的两种方法:factorizeCategorical函数,均来自pandas包。对于 R,我们讨论了如何在拟合逻辑回归模型时使用factor函数处理分类变量。通过回归分析结果,我们展示了如何通过查看系数和p-值来解释结果和输入输出变量之间的关系。通过查看回归分析输出,我们可以了解哪些客户属性与客户营销互动之间存在显著关系。

在下一章,我们将扩展你对解释性分析的知识。我们将分析客户互动后,哪些因素推动了转化。你还将学习另一种机器学习算法——决策树,以及如何将其应用于解释性分析。

第四章:从参与到转化

在本章中,我们将扩展你对说明性分析的知识,并向你展示如何使用决策树来理解消费者行为的驱动因素。我们将从比较和解释逻辑回归和决策树模型之间的区别开始,然后我们将讨论决策树是如何构建和训练的。接下来,我们将讨论如何使用训练好的决策树模型来提取有关单个消费者属性(或特征)与目标输出变量之间关系的信息。

在编程练习中,我们将使用 UCI 机器学习库中的银行营销数据集来理解转化的驱动因素。我们将从数据分析开始,以便你更好地理解数据集;然后,我们将使用 Python 中的scikit-learn包和 R 中的rpart包构建决策树模型。最后,你将学会如何通过 Python 中的graphviz包和 R 中的rattle包来可视化这些训练过的决策树模型,从而理解它们的解读方式。到本章结束时,你将熟悉决策树,并且更好地理解何时以及如何使用 Python 或 R 来应用它们。

在本章中,我们将讨论以下主题:

  • 决策树

  • 决策树与 Python 的解释

  • 决策树与 R 的解释

决策树

在上一章中,我们讨论了说明性分析和回归分析。我们将继续这个主题,并介绍另一个机器学习算法,利用它可以从数据中提取客户行为的洞察。在本章中,我们将讨论一种机器学习算法——决策树:它是如何从数据中学习的,以及我们如何解读它们的结果。

逻辑回归与决策树的对比

如果你还记得上一章的内容,逻辑回归模型通过找到特征变量的线性组合来学习数据,从而最好地估计事件发生的对数几率。顾名思义,决策树通过生长一棵树来学习数据。我们将在接下来的章节中详细讨论决策树模型是如何生长的以及如何构建树,但逻辑回归和决策树模型之间的主要区别在于:逻辑回归算法在特征集中搜索一个最佳的线性边界,而决策树算法则通过划分数据来找到发生事件可能性较高的数据子群体。通过一个例子来解释会更容易。让我们来看一下以下图示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/8d0bb394-1e86-48ec-9bfd-8c8bda7e1d97.png

这是一个决策树模型的示例。如你在这个图中所见,它通过某些标准来划分数据。在这个例子中,根节点通过 previous < 0.5 这个标准划分成子节点。如果这个条件成立且为真,那么它会遍历到左子节点。如果不成立,它则遍历到右子节点。左子节点随后通过 age < 61 这个标准进一步划分。树会一直生长,直到找到纯净的节点(即每个节点中的所有数据点都属于同一类)或满足某些停止标准,例如树的最大深度。

如你所见,在这个例子中,数据被划分为七个分区。最左边的节点或分区是针对那些 previous 变量值小于 0.5age 变量值小于 61 的数据点。另一方面,最右边的节点位于底部,针对的是那些 previous 变量值大于 0.5housing 变量值不是 yes 的数据点。

这里需要注意的一点是,不同变量之间有很多交互作用。在这个示例树中,没有任何一个叶节点是通过一个条件来划分的。树中的每个分区都是通过多个标准以及不同feature变量之间的交互作用来形成的。这与逻辑回归模型的主要区别在于,逻辑回归模型在数据中没有线性结构时,表现会很差,因为它们试图在特征变量之间找到线性组合。另一方面,决策树模型对于非线性数据集表现更好,因为它们仅仅是尝试在最纯净的水平上划分数据。

构建决策树

在构建决策树时,树需要提出逻辑来将一个节点划分为子节点。通常用于数据划分的两种主要方法是:Gini 不纯度熵信息增益。简而言之,Gini 不纯度度量一个分区的不纯度,而熵信息增益度量的是根据所测试的标准划分数据后,所获得的信息量。

让我们快速看一下计算 Gini 不纯度度量的公式:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/dcc06319-5223-49a9-bbff-b4475b53664f.png

这里,c 代表类标签,P[i] 代表记录被选择时属于类标签 i 的概率。通过从 1 中减去概率的平方和,Gini 不纯度度量达到零,即当树的每个分区或节点中的所有记录都是纯净的,且只有一个目标类时。

计算 的公式如下:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/85b079d0-d694-434a-a6eb-ae22b25f62f5.png

和之前一样,c代表类标签,P[i]代表记录具有类标签i被选择的概率。构建树时,需要计算每个可能分割的熵,并与分割前的熵进行比较。然后,选择熵度量变化最大或信息增益最高的分割来继续构建树。这个过程将重复,直到所有节点都是纯净的,或满足停止标准。

使用 Python 进行决策树构建与解释

在本节中,你将学习如何使用 Python 的scikit-learn包构建决策树模型,并通过 Python 的graphviz包进行可视化解释结果。对于那些希望使用 R 而非 Python 进行此练习的读者,你可以跳过到下一节。我们将从分析银行营销数据集开始,使用pandasmatplotlib包进行深入分析,随后讨论如何构建和解释决策树模型。

对于这个练习,我们将使用 UCI 机器学习库中的一个公开数据集,地址为archive.ics.uci.edu/ml/datasets/bank+marketing。你可以通过链接下载 ZIP 格式的数据。我们将使用bank.zip文件进行本次练习。当你解压缩该文件时,你会看到两个 CSV 文件:bank.csvbank-full.csv。我们将在此次 Python 练习中使用bank-full.csv文件。

为了将数据加载到 Jupyter Notebook 中,你可以运行以下代码:

%matplotlib inline

import matplotlib.pyplot as plt
import pandas as pd

df = pd.read_csv('../data/bank-full.csv', sep=";")

从这段代码片段可以看出,我们使用%matplotlib inline命令在 Jupyter Notebook 中显示图表。接下来,我们导入了用于数据分析步骤的matplotlibpandas包。最后,我们可以通过使用pandas包中的read_csv函数轻松读取数据文件。这里需要注意的是read_csv函数中的sep参数。如果仔细查看数据,你会发现bank-full.csv文件中的字段是由分号(;)分隔的,而不是逗号(,)。为了正确地将数据加载到pandas数据框中,我们需要告诉read_csv函数使用分号作为分隔符,而不是逗号。

一旦加载了数据,它应该看起来像下图所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/edd8cfd2-6ceb-4846-aab1-752933a982c3.png

数据分析与可视化

在我们开始分析数据之前,我们将首先对输出变量y进行编码,y包含关于客户是否已转化或订阅定期存款的信息,使用数值表示。你可以使用以下代码将输出变量y编码为零和一:

df['conversion'] = df['y'].apply(lambda x: 0 if x == 'no' else 1)

从这段代码片段可以看出,你可以使用apply函数对输出变量进行编码。我们将这些编码后的值存储在一个新列中,命名为conversion

转化率

首先,让我们看一下总的转化率。转化率是指订阅定期存款的客户所占的百分比。请看以下代码:

conversion_rate_df = pd.DataFrame(
    df.groupby('conversion').count()['y'] / df.shape[0] * 100.0
)

从这段代码中你可以看到,我们按conversion列进行分组,conversion列用1表示那些已经订阅定期存款的客户,0表示那些没有订阅的客户。然后,我们计算每个组别中的客户数量,并将其除以数据集中客户的总数。结果如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/99f9f19c-3871-4394-bd59-55c3fce7f530.png

为了更容易查看,你可以通过使用pandas DataFrame 的T属性来转置数据框。正如你所看到的,只有大约 11.7%的客户进行了转化或订阅了定期存款。从这些结果来看,我们可以发现转化组和非转化组之间存在较大的不平衡,这种情况在各种营销数据集中是常见的,并且经常出现。

按工作类别的转化率

可能某些工作类别的转化率确实比其他类别更高。让我们看一下不同工作类别之间的转化率。你可以通过以下代码来实现:

conversion_rate_by_job = df.groupby(
    by='job'
)['conversion'].sum() / df.groupby(
    by='job'
)['conversion'].count() * 100.0

让我们深入了解一下这段代码。我们首先按job列进行分组,job列包含了每个客户所属的工作类别信息。然后,我们对每个工作类别的conversion列进行求和,从中得到每个工作类别的转化总数。最后,我们将这些转化数除以每个工作类别的客户总数,从而得到每个工作类别的转化率。

结果如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/e5a1ed43-084d-475a-b90a-3346bd87687a.png

从这些结果中你可以看到,student组的转化率明显高于其他组,而retired组排在其后。然而,从原始输出中进行比较有些困难,我们可以通过使用图表来更好地展示这些数据。我们可以通过以下代码构建一个水平条形图:

ax = conversion_rate_by_job.plot(
    kind='barh',
    color='skyblue',
    grid=True,
    figsize=(10, 7),
    title='Conversion Rates by Job'
)

ax.set_xlabel('conversion rate (%)')
ax.set_ylabel('Job')

plt.show()

如果你查看这段代码,你会发现我们正在使用pandas DataFrame 的plot函数,并通过将barh作为kind参数的输入,定义了图表的类型为水平条形图。你可以轻松调整图表的颜色、大小和标题,分别使用colorfigsizetitle参数。你还可以通过set_xlabelset_ylabel函数轻松更改x轴和y轴的标签。

生成的图表如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/3b42d4b7-1d54-4889-977a-3a30c5dd02a4.png

如你所见,使用水平条形图可以更容易地看到不同工作类别之间的转化率差异。我们可以清楚地看到,studentretired组是转化率最高的两个组,而blue-collarentrepreneur组则是转化率最低的两个组。

按转换情况划分的违约率

另一个值得关注的客户属性是违约率,看看订阅定期存款的客户与未订阅的客户之间的违约率差异。我们将使用pandas库中的pivot_table函数来分析按转换情况划分的违约率。让我们来看一下下面的代码:

default_by_conversion_df = pd.pivot_table(
    df, 
    values='y', 
    index='default', 
    columns='conversion', 
    aggfunc=len
)

如你所见,这段代码中,我们通过ydefault列对数据框df进行透视。通过使用len作为聚合函数,我们可以计算每个透视表单元格下的客户数量。结果如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/8257487f-4abc-4403-b5d1-6cb79ec4fc94.png

仅凭这些原始数据,很难比较转换组和非转换组之间的违约率差异。通过饼图来可视化这些数据是一种可行的方式。你可以使用以下代码来生成饼图:

default_by_conversion_df.plot(
    kind='pie',
    figsize=(15, 7),
    startangle=90,
    subplots=True,
    autopct=lambda x: '%0.1f%%' % x
)

plt.show()

如你所见,这段代码中,我们只是将'pie'作为输入传递给plot函数的kind参数。生成的饼图如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/eba95421-1547-4767-aadd-5494b5440972.png

从这些饼图中可以看出,比较转换组和非转换组的违约率要容易得多。尽管两组的总体违约率都较低,但非转换组的违约率大约是转换组的两倍。

按转换情况划分的银行余额

接下来,我们将尝试查看转换组和非转换组之间银行余额分布是否存在差异。箱型图通常是可视化变量分布的好方法。让我们来看一下下面的代码:

ax = df[['conversion', 'balance']].boxplot(
    by='conversion',
    showfliers=True,
    figsize=(10, 7)
)

ax.set_xlabel('Conversion')
ax.set_ylabel('Average Bank Balance')
ax.set_title('Average Bank Balance Distributions by Conversion')

plt.suptitle("")
plt.show()

你应该已经熟悉这段代码,因为我们已经讨论了如何使用pandas包构建箱型图。通过使用boxplot函数,我们可以轻松构建如下的箱型图:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/f7970841-e6de-49b0-a7b1-1f4c8084aa40.png

由于存在许多异常值,很难发现两个分布之间的差异。让我们构建一个不包含异常值的箱型图。你需要做的唯一更改就是在boxplot函数中将showfliers=True,如下所示:

ax = df[['conversion', 'balance']].boxplot(
    by='conversion',
    showfliers=False,
    figsize=(10, 7)
)

ax.set_xlabel('Conversion')
ax.set_ylabel('Average Bank Balance')
ax.set_title('Average Bank Balance Distributions by Conversion')

plt.suptitle("")
plt.show()

使用这段代码,你将看到如下的两个组别银行余额分布箱型图:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/5c8dbee9-2db5-4d9d-bb6a-c721e18d129b.png

从这些箱型图中,我们可以看到,相比非转换组,转换组的银行余额中位数略高。此外,转换客户的银行余额波动似乎比非转换客户更大。

按联系次数划分的转换率

最后,我们将看看转化率如何随联系方式的数量变化。通常在营销中,更多的营销接触可能会导致营销疲劳,即随着您更频繁地联系客户,转化率下降。让我们看看我们的数据中是否存在营销疲劳。请查看以下代码:

conversions_by_num_contacts = df.groupby(
    by='campaign'
)['conversion'].sum() / df.groupby(
    by='campaign'
)['conversion'].count() * 100.0

在这段代码中,您可以看到我们是通过campaign列(该列包含了此客户在营销活动中进行的联系方式数量的信息)进行分组,并计算每个联系方式数量的转化率。结果数据如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/db83f22a-027b-4c4c-aac7-b418f88aa2f0.png

和之前一样,查看图表比直接查看原始数据更容易。我们可以使用以下代码通过柱状图绘制这些数据:

ax = conversions_by_num_contacts.plot(
    kind='bar',
    figsize=(10, 7),
    title='Conversion Rates by Number of Contacts',
    grid=True,
    color='skyblue'
)

ax.set_xlabel('Number of Contacts')
ax.set_ylabel('Conversion Rate (%)')

plt.show()

图表如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/6cbe0312-537f-4600-b2f6-e49f6a64e8ef.png

在联系方式数量较高的情况下会有一些噪声,因为这些样本的数量较少,但从这张柱状图中您可以很容易看到整体的下降趋势。随着联系方式数量的增加,转化率缓慢下降。这表明,在给定的营销活动中,随着您与客户的联系更频繁,预期的转化率会下降。

编码类别变量

该数据集包含八个类别变量:jobmaritaleducationdefaulthousingloancontactmonth。在我们开始构建决策树之前,需要将这些类别变量编码为数值。在本节中,我们将展示如何编码一些类别变量。

编码月份

我们都知道,month变量只能有 12 个唯一值。让我们快速看看数据集中有哪些值。查看以下代码:

df['month'].unique()

pandas函数unique帮助您快速获取给定列中的唯一值。运行此代码后,您将看到以下输出:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/57913c36-6c06-41d1-bea1-943abd0d37bf.png

如预期的那样,month列中有 12 个唯一值,从一月到十二月。由于month值之间有自然的顺序关系,我们可以用相应的数字对每个值进行编码。以下是将month的字符串值编码为数字的一种方式:

months = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec']

df['month'] = df['month'].apply(
    lambda x: months.index(x)+1
)

使用这段代码,month列的唯一值如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/3311d783-0ac2-4a7f-9157-7083a3a88926.png

为了查看每个月的记录数,我们可以使用以下代码:

df.groupby('month').count()['conversion']

结果如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/aae40fb2-16e3-4a60-ba13-4afb2472f525.png

编码作业

接下来,让我们看看如何编码job列中的不同类别。我们首先使用以下代码查看该列中的唯一值:

df['job'].unique()

job列中的唯一值如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/b7e7b157-3f55-40e3-b11e-01ce1297c386.png

从这个输出中可以看出,该变量没有自然的顺序。一个 job 类别并不先于另一个,因此我们不能像对待 month 变量那样对该变量进行编码。我们将为每个 job 类别创建虚拟变量。如果你还记得上一章的内容,虚拟变量是一个变量,如果给定记录属于该类别,则编码为 1,否则编码为 0。我们可以使用以下代码轻松完成此操作:

jobs_encoded_df = pd.get_dummies(df['job'])
jobs_encoded_df.columns = ['job_%s' % x for x in jobs_encoded_df.columns]

从这段代码中可以看出,pandas 包中的 get_dummies 函数为 job 变量中的每个类别创建一个虚拟变量,并且如果给定记录属于相应的类别,则编码为 1,如果不属于则编码为 0。然后,我们通过在每个列名前加上 job_ 前缀来重命名列。结果如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/aa02a263-7126-4b15-a075-8e0c219d860d.png

从这张截图中可以看出,第一条记录(或客户)属于 management 工作类别,而第二条记录属于 technician 工作类别。现在我们已经为每个工作类别创建了虚拟变量,我们需要将这些数据附加到现有的 DataFrame 中。请看下面的代码:

df = pd.concat([df, jobs_encoded_df], axis=1)
df.head()

使用 pandas 包中的 concat 函数,您可以轻松地将新创建的包含虚拟变量的 DataFrame jobs_encoded_df 添加到原始 DataFrame df 中。axis=1 参数告诉 concat 函数将第二个 DataFrame 作为列连接到第一个 DataFrame,而不是作为行连接。结果的 DataFrame 如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/0895e1e0-aa45-40b8-9e99-a680449c2c17.png

如您所见,新创建的虚拟变量被添加到原始 DataFrame 中,作为每条记录的新列。

对婚姻状况进行编码

类似于我们如何对类别变量 job 进行编码,我们将为 marital 变量的每个类别创建虚拟变量。与之前一样,我们使用以下代码对 marital 列进行编码:

marital_encoded_df = pd.get_dummies(df['marital'])
marital_encoded_df.columns = ['marital_%s' % x for x in marital_encoded_df.columns]

编码结果如下:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/56513a91-bce6-454c-939a-8a8c3b51cb84.png

如您所见,为原始变量 marital 创建了三个新变量:marital_divorcedmarital_marriedmarital_single,分别表示客户是否离婚、已婚或单身。为了将这些新创建的虚拟变量添加到原始 DataFrame 中,我们可以使用以下代码:

df = pd.concat([df, marital_encoded_df], axis=1)

到此为止,您的原始 DataFrame df 应该包含所有原始列,以及为 jobmarital 列新创建的虚拟变量。

对住房和贷款变量进行编码

本节我们将要编码的最后两个分类变量是housingloanhousing变量有两个独特的值,'yes''no',它包含关于客户是否有住房贷款的信息。另一个变量loan也有两个独特的值,'yes''no',它告诉我们客户是否有个人贷款。我们可以通过以下代码轻松编码这两个变量:

df['housing'] = df['housing'].apply(lambda x: 1 if x == 'yes' else 0)

df['loan'] = df['loan'].apply(lambda x: 1 if x == 'yes' else 0)

如你所见,我们正在使用apply函数将yes编码为1,将no编码为0,用于housingloan两个变量。对于本节未讨论的其他分类变量,如果你希望深入探索,可以使用我们讨论过的相同技术来对其进行编码。

构建决策树

现在我们已经编码了所有分类变量,终于可以开始构建决策树模型了。我们将使用以下变量作为决策树模型的特征:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/33e32db6-b239-4b18-b1f5-13d2e9086fac.png

为了使用 Python 构建和训练一个决策树模型,我们将使用scikit-learnsklearn)包中的tree模块。你可以通过以下代码导入所需的模块:

from sklearn import tree

sklearn包的tree模块下,有一个名为DecisionTreeClassifier的类,我们可以使用它来训练决策树模型。请看以下代码:

dt_model = tree.DecisionTreeClassifier(
    max_depth=4
)

除了我们在这里使用的max_depth参数之外,DecisionTreeClassifier类还有许多其他参数。max_depth参数控制决策树的最大深度,在这里我们将其限制为4,意味着从根节点到叶节点的最大距离为4。你还可以使用criterion参数在基尼不纯度和信息增益的熵度量之间进行选择,这用于衡量分裂的质量。还有许多其他方法可以调整你的决策树模型,我们建议你查阅scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html的文档以获取更多信息。

为了训练这个决策树模型,你可以使用以下代码:

dt_model.fit(df[features], df[response_var])

如你从这段代码中看到的,fit函数接受两个参数:predictorfeature变量和responsetarget变量。在我们的例子中,response_var是 DataFrame df中的conversion列。运行这段代码后,决策树模型将学习如何进行分类。在接下来的部分中,我们将讨论如何解读训练好的决策树模型的结果。

解释决策树

现在我们已经训练了一个决策树模型,接下来需要从模型中提取洞察。在这一部分,我们将使用一个名为graphviz的包。你可以通过在终端中使用以下命令来安装此包:

conda install python-graphviz

一旦正确安装了这个包,你应该能够按如下方式导入该包:

import graphviz

现在,我们已经使用新包graphviz设置好了环境,接下来让我们看看以下代码,了解如何可视化训练好的决策树:

dot_data = tree.export_graphviz(
    dt_model, 
    feature_names=features, 
    class_names=['0', '1'], 
    filled=True, 
    rounded=True, 
    special_characters=True
) 

graph = graphviz.Source(dot_data)

如你所见,我们首先使用sklearn包中的tree模块的export_graphviz函数导出了训练好的决策树模型dt_model。我们可以通过feature_names参数定义用于训练该模型的特征变量。然后,我们可以定义该模型被训练用于分类的类别(转换与非转换)。export_graphviz函数将训练好的决策树模型以 DOT 格式导出,DOT 是一种图形描述语言。然后,你可以将dot_data传递给graphvizSource类。graph变量现在包含了一个可渲染的图。根节点及其直接子节点如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/d20c75f2-fa12-4a5b-8ee3-bd4e5fc9d310.png

左半部分的树(或根节点左子节点的子节点)如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/5e156f7d-b72b-4e9f-956c-d646b7f276cf.png

右半部分的树(或根节点右子节点的子节点)如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/852140bc-7f6a-4553-b94c-b0373d043921.png

让我们仔细看看这个图。每个节点包含五行信息,描述了该节点的相关信息。第一行告诉我们分裂的标准。例如,根节点是基于previous变量的值进行分裂的。如果previous变量的值小于或等于0.5,则它会进入左子节点。另一方面,如果previous变量的值大于0.5,则它会进入右子节点。

第二行告诉我们分裂的质量度量值。在这里,我们选择了gini不纯度作为标准,因此我们可以在第二行中看到每个节点中不纯度度量值的变化。第三行告诉我们属于该节点的记录总数。例如,根节点中有45,211个样本,根节点的右子节点中有8,257个样本。

每个节点的第四行告诉我们两个不同类别中的记录组成。第一个元素表示非转化组中的记录数,第二个元素表示转化组中的记录数。例如,在根节点中,非转化组有39,922条记录,转化组有5,289条记录。最后,每个节点的第五行告诉我们该节点的预测或分类结果是什么。例如,如果一个样本属于最左侧的叶节点,那么该决策树模型的分类结果将是0,即非转化。另一方面,如果一个样本属于从左数第八个叶节点,那么该决策树模型的分类结果将是1,即转化。

现在我们知道了每个节点中的每一行意味着什么,让我们来讨论如何从这棵树图中提取洞见。为了理解属于每个叶节点的客户,我们需要沿着树走一遍。例如,那些属于从左数第八个叶节点的客户是previous变量值为0age大于60.5marital_divorced变量值为1,以及job_self-employed变量值为1的客户。换句话说,之前未曾联系过、年龄大于60.5、已离婚并且是自雇人士的客户属于这个节点,并且他们有较高的转化几率。

让我们来看另一个例子。那些属于从右数第二个叶节点的客户是previous变量值为1housing变量值为1age大于60.5、并且balance小于或等于4,660.5的客户。换句话说,之前曾联系过、拥有住房贷款、年龄大于60.5并且银行存款少于4,660.5的客户属于这个节点,并且其中20个中的29个客户已经转化并订阅了定期存款。

正如你从这两个例子中会注意到的,通过可视化训练好的决策树,你可以从中获得关于谁更可能或更不可能转化的有用洞见。你只需要沿着树的节点走一遍,并理解哪些属性与目标类别高度相关。为了这次练习,我们将树的深度限制为4,但是你可以选择将树生长得比我们在本次练习中使用的更大或更小。

本章节的 Python 练习完整代码可以在仓库中找到:github.com/yoonhwang/hands-on-data-science-for-marketing/blob/master/ch.4/python/From%20Engagement%20to%20Conversions.ipynb

使用 R 语言的决策树及其解释

在本节中,您将学习如何使用 R 中的rpart包构建决策树模型,并通过 R 的rattle包通过可视化来解释结果。对于那些希望使用 Python 而不是 R 进行练习的读者,您可以参考上一节中的 Python 示例。我们将通过使用dplyrggplot2库深入分析银行营销数据集来开始本节,然后我们将讨论如何构建和解释决策树模型。

对于这个练习,我们将使用来自 UCI 机器学习库的一个公开数据集,您可以在archive.ics.uci.edu/ml/datasets/bank+marketing找到。您可以访问该链接并下载 ZIP 格式的数据。我们将使用bank.zip文件进行此练习。当您解压这个文件时,您会看到两个 CSV 文件:bank.csvbank-full.csv。我们将使用bank-full.csv文件进行此练习。

为了将这些数据加载到您的 RStudio 中,您可以运行以下代码:

df <- read.csv(
  file="../data/bank-full.csv", 
  header=TRUE, 
  sep=";"
)

正如您从这段代码中看到的,我们可以通过使用 R 中的read.csv函数轻松读取数据文件。需要注意的一点是read.csv函数中的sep参数。如果仔细查看数据,您会发现bank-full.csv文件中的字段是由分号(;)而不是逗号(,)分隔的。为了正确加载数据到 DataFrame 中,我们需要告诉read.csv函数使用分号作为分隔符,而不是逗号。

一旦您加载了这些数据,它应该看起来像以下截图:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/de1dbdf1-84f4-4b82-ad07-743d1e2b754f.png

数据分析和可视化

在开始分析数据之前,我们将首先对输出变量y进行编码,该变量包含关于客户是否已转换或订阅定期存款的信息,并用数值表示。您可以使用以下代码将输出变量y编码为零和一:

# Encode conversions as 0s and 1s
df$conversion <- as.integer(df$y) - 1

正如您从这段代码中看到的,您可以使用as.integer函数对输出变量进行编码。由于该函数会将y变量中的no值编码为1,而y变量中的yes值编码为2,我们通过减去1来将其编码为01,分别存储这些编码值到一个新列中,名为conversion

转化率

我们将首先关注的是汇总的转化率。转化率简单地是那些订阅了定期存款的客户的百分比,或者那些在conversion列中被编码为1的客户。请查看以下代码:

sprintf("conversion rate: %0.2f%%", sum(df$conversion)/nrow(df)*100.0)

正如您从这段代码中看到的,我们只是将conversion列中的所有值相加,并除以 DataFrame df中的记录或客户的数量。使用sprintf函数,我们将此转化率数字格式化为两位小数。结果如下:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/c21a0e9b-e719-424d-ba6c-f915041eecc7.png

从这个输出中可以看到,只有约11.7%的客户转化或订阅了定期存款。从这些结果中,我们可以看到转化组和非转化组之间存在较大不平衡,这在各种营销数据集中是常见的现象。

按职业分类的转化率

可能确实存在某些职业类别的转化率比其他职业类别更高的情况。让我们看看不同职业类别之间的转化率。你可以通过运行以下代码来实现:

conversionsByJob <- df %>% 
  group_by(Job=job) %>% 
  summarise(Count=n(), NumConversions=sum(conversion)) %>%
  mutate(ConversionRate=NumConversions/Count*100.0)

让我们更详细地看一下这段代码。我们首先根据job列进行分组,该列包含每个客户所属的职业类别信息。然后,我们使用n()函数计算每个职业类别中的客户总数,并使用sum函数对每个职业类别的conversion列进行求和。最后,我们将转化总数NumConversion除以每个职业类别中的客户总数Count,并将结果乘以100.0,以计算每个职业类别的转化率。

结果如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/d05fb8b6-299f-466b-b73b-4fb7093fff02.png

从这些结果可以看出,student组的转化频率明显高于其他组,而retired组排在其后。然而,直接比较这些数据和原始输出有些困难,我们可以通过使用图表更好地呈现这些数据。我们可以使用以下代码构建一个水平条形图:

ggplot(conversionsByJob, aes(x=Job, y=ConversionRate)) +
  geom_bar(width=0.5, stat="identity") +
  coord_flip() +
  ggtitle('Conversion Rates by Job') +
  xlab("Job") +
  ylab("Conversion Rate (%)") +
  theme(plot.title = element_text(hjust = 0.5)) 

如果你查看这段代码,我们使用了ggplotgeom_bar函数,利用conversionsByJob数据(我们在之前的代码中构建的)生成条形图,并将Job变量放在X轴,将ConversionRate变量放在Y轴。然后,我们使用coord_flip函数将垂直条形图转换为水平条形图。你可以使用ggtitlexlabylab函数来更改标题、X轴标签和Y轴标签。

结果图表如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/cbd51610-3022-4180-b258-0618f507ee19.png

正如你所看到的,使用水平条形图更容易观察到不同职业类别之间的转化率差异。我们可以清晰地看到,studentretired组是转化率最高的两个组,而blue-collarentrepreneur组则是转化率最低的两个组。

按转化率分类的违约率

另一个值得关注的客户属性是违约率,以及已订阅定期存款和未订阅定期存款的客户之间的差异。让我们看一下以下的 R 代码:

defaultByConversion <- df %>% 
  group_by(Default=default, Conversion=conversion) %>% 
  summarise(Count=n())

从这段代码中可以看到,我们使用 group_by 函数将 DataFrame dfdefaultconversion 两列进行分组。通过使用 n() 作为聚合函数,我们可以统计每个四个情况中的客户数量。让我们来看一下以下结果:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/320df0e0-2b56-4fc7-8c26-e85a4ed037e9.png

从这些原始数据来看,比较转化组和非转化组之间的默认率差异有点困难。可视化这个数据的一种方法是通过饼图。你可以使用以下代码来构建饼图:

ggplot(defaultByConversion, aes(x="", y=Count, fill=Default)) + 
  geom_bar(width=1, stat = "identity", position=position_fill()) +
  geom_text(aes(x=1.25, label=Count), position=position_fill(vjust = 0.5)) +
  coord_polar("y") +
  facet_wrap(~Conversion) +
  ggtitle('Default (0: Non Conversions, 1: Conversions)') +
  theme(
    axis.title.x=element_blank(),
    axis.title.y=element_blank(),
    plot.title=element_text(hjust=0.5),
    legend.position='bottom'
  )

如你所见,我们在这里使用了三个函数:ggplotgeom_barcoord_polar("y")。通过使用 coord_polar("y") 函数,我们可以从条形图生成饼图。然后,我们可以使用 facet_wrap 函数将其拆分成两个饼图:一个是转化组,另一个是非转化组。

看看下面的饼图:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/1fe05b29-dda3-45fa-bd31-a123981a2bc1.png

从这些饼图中,你可以更容易地比较转化组和非转化组之间的默认率。尽管两个组中以往的默认比例都较低,但非转化组的默认率大约是转化组的两倍。

按转化次数划分的银行余额

接下来,我们将尝试查看转化组和非转化组之间的银行余额分布是否存在差异。箱线图通常是一种很好的可视化变量分布的方式。我们来看一下下面的代码:

ggplot(df, aes(x="", y=balance)) + 
  geom_boxplot() +
  facet_wrap(~conversion) +
  ylab("balance") +
  xlab("0: Non-Conversion, 1: Conversion") +
  ggtitle("Conversion vs. Non-Conversions: Balance") +
  theme(plot.title=element_text(hjust=0.5))

你现在应该已经熟悉这段代码了,因为我们在上一章讨论过如何使用 ggplotgeom_boxplot 函数构建箱线图。当你运行这段代码时,你将看到以下箱线图:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/f3aa26a3-e3d0-4b3d-b3b2-04c62b23b2ab.png

由于有很多异常值,识别两组分布之间的差异变得相当困难。让我们构建另一个没有异常值的箱线图。你只需要修改上一段代码中的 outlier.shape = NA 参数,如下所示:

ggplot(df, aes(x="", y=balance)) + 
  geom_boxplot(outlier.shape = NA) +
  scale_y_continuous(limits = c(-2000, 5000)) +
  facet_wrap(~conversion) +
  ylab("balance") +
  xlab("0: Non-Conversion, 1: Conversion") +
  ggtitle("Conversion vs. Non-Conversions: Balance") +
  theme(plot.title=element_text(hjust=0.5))

使用这段代码,你将看到以下关于两组银行余额分布的箱线图:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/237999b5-a990-408b-8fd1-a96d7a52acbe.png

从这些箱线图中,我们可以看到转化组的银行余额中位数略高于非转化组。此外,转化客户的银行余额似乎比非转化客户的余额波动更大。

按联系人数量划分的转化率

最后,我们将查看转化率如何随着联系人数的变化而变化。通常在营销中,较高的营销联系人数可能导致营销疲劳,即当你更频繁地联系客户时,转化率会下降。让我们看看我们的数据中是否存在营销疲劳现象。请查看以下代码:

conversionsByNumContacts <- df %>% 
  group_by(Campaign=campaign) %>% 
  summarise(Count=n(), NumConversions=sum(conversion)) %>%
  mutate(ConversionRate=NumConversions/Count*100.0)

从这段代码中可以看到,我们是通过 campaign 列(该列包含了在该营销活动中对该客户进行的联系次数信息)进行分组,并计算每个联系次数对应的转化率。结果数据如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/f126d9cd-bfdd-4aa3-a15e-92f5bf715f6a.png

和之前一样,查看图表比查看原始数据更为直观。我们可以使用以下代码通过柱状图来绘制这些数据:

ggplot(conversionsByNumContacts, aes(x=Campaign, y=ConversionRate)) +
  geom_bar(width=0.5, stat="identity") +
  ggtitle('Conversion Rates by Number of Contacts') +
  xlab("Number of Contacts") +
  ylab("Conversion Rate (%)") +
  theme(plot.title = element_text(hjust = 0.5)) 

绘图结果如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/59b26b80-2ed8-46cf-88e9-c12a1b471cac.png

在较高联系次数的情况下,由于样本量较小,会有一些噪声,但从这张柱状图中可以明显看到总体的下降趋势。随着联系次数的增加,转化率逐渐下降。这表明,当你在一个营销活动中更频繁地联系客户时,预期的转化率会降低。

对类别变量进行编码

数据集中有八个类别变量:jobmaritaleducationdefaulthousingloancontactmonth。在构建决策树之前,我们需要将其中一些类别变量编码为数值。我们将在本节中看看如何对这些类别变量进行编码。

对月份进行编码

我们都知道,month 变量最多只能有 12 个唯一值。让我们快速查看一下数据集中的内容。请查看以下代码:

unique(df$month)

unique 函数帮助你快速获取给定列中的唯一值。当你运行这段代码时,你将获得以下输出:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/bea193fa-38af-45e1-a779-c06d0491a339.png

正如我们所预期的,month 列中有 12 个唯一值,从一月到十二月。由于 month 的值有自然顺序,我们可以用对应的数字对每个值进行编码。将 month 的字符串值编码为数字的一种方式如下:

months = lapply(month.abb, function(x) tolower(x))
df$month <- match(df$month, months)

让我们仔细看看这段代码。month.abb 是一个内置的 R 常量,包含了月份名称的三字母缩写,具体如下:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/2f8db0b0-9ba1-4eea-8438-57e61afed48d.png

如你所见,每个缩写的month名称的首字母都被大写。然而,我们数据中的month列的月份名称都是小写的。这就是为什么我们使用tolower函数将month.abb常量中的所有值转换为小写。使用lapply函数,我们可以将这个tolower函数应用于month.abb列表。接着,我们使用match函数,它返回匹配字符串在数组中的位置,将 DataFrame 中month列的字符串值转换为对应的数值。

使用这段代码,month列的唯一值如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/423f83ae-563e-48b4-8a30-3c8290e24a1b.png

为了查看每个月份的记录数量,我们可以使用以下代码:

df %>% 
  group_by(month) %>% 
  summarise(Count=n())

结果如下:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/4271c54d-3965-4a56-a046-162327636d1b.png

对工作、住房和婚姻变量进行编码

接下来,我们将编码三个变量:jobhousingmarital。由于这些变量没有自然的顺序,我们不需要担心哪个类别被编码为哪个值。编码没有顺序的类别变量在 R 中的最简单方法是使用factor函数。让我们看一下以下代码:

df$job <- factor(df$job)
df$housing <- factor(df$housing)
df$marital <- factor(df$marital)

如你所见,我们只是将factor函数应用于这三个变量:jobhousingmarital,并将编码后的值存储回 DataFrame df中。对于我们在本节中未讨论的类别变量,如果你希望进一步探索,可以使用我们在本节中讨论的相同技术对它们进行编码。

构建决策树

现在我们已经编码了所有类别变量,终于可以开始构建决策树模型了。我们将使用这些变量作为决策树模型的特征:agebalancecampaignprevioushousingjobmarital。为了使用 R 构建并训练决策树模型,我们将使用rpart包。你可以使用以下代码导入所需的库:

library(rpart)

如果你没有安装rpart包,你可以使用以下命令安装它:

install.packages("rpart")

一旦你导入了所需的库,你可以使用以下代码来构建决策树模型:

fit <- rpart(
  conversion ~ age + balance + campaign + previous + housing + job + marital,
  method="class", 
  data=df,
  control=rpart.control(maxdepth=4, cp=0.0001)
)

如您所见,rpart 模型的第一个参数是 formula,它定义了特征和目标变量。在这里,我们使用上述变量作为特征,conversion 作为目标变量。然后,我们将此决策树模型定义为一个分类模型,并使用 method="class" 输入。最后,您可以使用 control 输入来微调决策树模型。有许多参数可以通过 control 输入进行调整。在此示例中,我们仅通过 maxdepth 参数将树的最大深度限制为 4,并将复杂度参数 cp 设置为足够小,以便树能够进行分裂。还有许多其他方法可以微调您的决策树模型,我们建议您通过运行 help(rpart)help(rpart.control) 命令,详细查看 R 文档以获取更多信息。

解读决策树

现在我们已经训练了一个决策树模型,接下来需要从模型中提取洞察。在本节中,我们将使用一个名为 rattle 的库:

  1. 您可以通过在 RStudio 中使用以下命令来安装此包:
install.packages("rattle")
  1. 一旦正确安装了此库,您应该能够按照以下方式导入该库:
library(rattle)
  1. 一旦您在 R 环境中设置了这个新的库 rattle,只需一行代码就能可视化训练好的决策树。请查看以下代码:
fancyRpartPlot(fit)
  1. 如您所见,fancyRpartPlot 函数接受一个 rpart 模型对象。在这里,模型对象 fit 是我们在前一步构建的决策树模型。一旦您运行这个命令,它将显示以下图表:

https://github.com/OpenDocCN/freelearn-ds-pt5-zh/raw/master/docs/hsn-ds-mkt/img/7829b6ee-ce98-41ba-9a99-c0b02ba49e54.png

让我们更仔细地看一下这个树形图。每个节点包含三行信息,描述了该节点所具有的信息。节点顶部的数字是标签,表示该节点构建的顺序。我们将使用这个标签来引用树图中的每个节点。然后,每个节点的顶行告诉我们该节点的预测或分类结果。例如,如果一个样本属于标签为 4 的节点,则此决策树模型的分类结果为零,表示未转换。另一方面,如果一个样本属于标签为 23 的节点,则此决策树模型的分类结果为一,表示已转换。

每个节点中的第二行告诉我们该节点中每个类的记录百分比。例如,节点22中的52%记录属于类0,即非转化组,剩下的48%属于类1,即转化组。另一方面,节点13中的39%客户属于类0,剩下的61%属于类1。最后,每个节点中的底部行告诉我们属于每个节点的总记录百分比。例如,大约80%的客户属于节点4,而接近0%的客户属于节点13

现在我们知道每个节点中每一行的含义了,让我们讨论一下如何从这个树状图中提取见解。为了理解属于每个叶节点的客户,我们需要沿着树走下去。例如,属于节点13的客户是那些previous变量值大于0.5,拥有住房贷款并且age大于或等于61的客户。换句话说,那些在此活动之前已被联系过、年龄超过61且拥有住房贷款的客户属于节点13,他们有较高的转化机会。

让我们来看另一个例子。为了从根节点到达节点22,我们需要使previous变量的值为0age大于或等于61marital状态不是marriedsingle,并且job属于以下类别之一:adminblue-collarentrepreneurhousemaidretiredunknown。换句话说,那些在此活动之前未被联系过、年龄超过61、已离婚并且在上述类别中有工作的客户属于节点22,他们有大约50%的转化机会。

正如你从这两个例子中注意到的,你可以通过可视化训练过的决策树模型,得出关于哪些客户更有可能或更不可能转化的有用见解。你只需沿着节点走下去,理解与目标类高度相关的属性是什么。对于这个练习,我们将树的深度限制为4,但你可以选择让树的深度比我们在这个练习中使用的树大或小。

本章节 R 语言练习的完整代码可以在该仓库中找到:github.com/yoonhwang/hands-on-data-science-for-marketing/blob/master/ch.4/R/FromEngagementToConversions.R

总结

在这一章中,我们介绍了一种新的机器学习算法——决策树,它可以用于营销分析,以更好地理解数据并洞察客户行为。我们讨论了决策树模型与上章介绍的逻辑回归模型的不同之处。你了解到,决策树模型通过基于某些标准对数据点进行划分来学习数据。我们还讨论了在生长决策树时常用的两种衡量标准:基尼不纯度和信息增益熵。通过使用这两种衡量标准中的任何一种,决策树可以一直生长,直到所有节点都纯净,或者直到满足停止标准。

在我们的 Python 和 R 编程练习中,我们使用了 UCI 机器学习库中的银行营销数据集。我们通过深入分析数据来开始编程练习,使用了 Python 中的pandasmatplotlib包,以及 R 中的dplyrggplot2库。接着,你学习了如何使用 Python 中的sklearn包和 R 中的rpart库来训练和生长决策树。通过这些训练好的决策树模型,你还学习了如何可视化和解释结果。为了进行可视化,我们使用了 Python 中的graphviz包和 R 中的rattle库。此外,你还看到如何通过遍历训练过的决策树来解释决策树结果,理解哪些客户群体更可能转化或订阅定期存款,这在我们进行客户行为的解释性分析时非常有用。

在接下来的几章中,我们将改变方向,专注于产品分析。在下一章中,我们将讨论可以进行的探索性分析,以理解和识别产品数据中的模式和趋势。基于下一章的产品分析结果,我们将展示如何构建产品推荐模型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值