原文:
annas-archive.org/md5/40bb0ccf1a2c14d899522b1d83c83f6c
译者:飞龙
前言
数据科学和机器学习在营销中的应用正在不断增长,从小型企业到大型组织都在采用这些技术。通过数据科学,你可以更好地理解过去营销策略成功与失败的驱动因素,深入了解客户的行为和他们与产品的互动方式。借助数据科学,你还可以预测客户行为,制定更具针对性和个性化的营销策略,从而实现更低的获客成本、更高的转化率以及更高的净销售额。通过本书,你将能够应用各种数据科学技术,制定数据驱动的营销策略。
本书作为一本实践指南,旨在帮助你完成从简单到复杂的营销任务。你将使用数据科学来了解推动销售和客户参与的因素。你将使用机器学习预测哪些客户更可能与产品互动,并具有最高的预期生命周期价值。你还将使用机器学习了解不同客户群体的数据,并为每个客户推荐最可能购买的产品。读完本书后,你将对各种数据科学和机器学习技术以及它们如何应用于不同营销目标有深刻的了解。
就个人而言,我本会从像这样的书籍中受益匪浅。当我开始从事数据科学和营销工作时,关于不同数据科学和机器学习技术的理论和细节有着丰富的资源,但关于如何将这些技术和方法特别应用于营销的资源却少之又少。学习这些理论与实际将其应用于现实世界中的营销业务案例是完全不同的。在本书中,我希望能分享我在将数据科学和机器学习应用于不同营销目标过程中,通过大量试错所获得的经验和知识。读完本书后,你将能很好地理解不同营销场景下所使用的技术和方法,了解哪里可以找到更多的资源,并且知道读完本书后该学习什么。
本书将使用 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并注册,代码文件会直接发送到您的邮箱。
您可以按照以下步骤下载代码文件:
-
登录或注册 www.packt.com。
-
选择“支持”标签。
-
点击“代码下载与勘误”。
-
在搜索框中输入书名,并按照屏幕上的说明操作。
文件下载完成后,请确保使用以下最新版本的解压缩工具进行解压:
-
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
):
-
市场分析:市场分析是一种监控和分析营销效果的方法。它不仅帮助你了解通过营销获得了多少销售或曝光,还可以帮助你深入了解更多个体层面的模式和趋势。在电子商务企业中,你可以通过市场分析分析和可视化不同类型和细分的客户,以及哪种类型的客户为你的业务带来最多的收入。在媒体行业,通过市场分析,你可以分析哪些内容最能吸引用户,以及关键词搜索的趋势是什么。市场分析还帮助你了解营销活动的成本效益。通过查看投资回报率(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
。
数据科学在营销中的应用
我们已经讨论了营销趋势,以及趋势如何朝着更多数据驱动和量化营销的方向发展,通常使用数据科学和机器学习。在营销行业应用数据科学和机器学习有多种方法,讨论数据科学和机器学习的典型任务和用法将对我们有益。
在本节中,我们将涵盖机器学习的基础知识、不同类型的学习算法以及典型的数据科学工作流程和流程。
描述性分析与解释性分析与预测性分析的比较
当我们在接下来的章节中进行练习和项目时,我们将主要进行本书中的三种不同类型的分析:描述性、解释性和预测性分析。
-
描述性分析:这种分析旨在更好地理解和描述给定的数据集。分析的目的是通过数量化和统计总结数据所包含的信息。例如,如果你对用户购买历史数据进行描述性分析,你将回答诸如“什么是畅销商品?”、“过去一年的月销量如何?”、“售出商品的平均价格是多少?”在本书中,每当我们介绍新数据集时,我们都将进行描述性分析。特别是在第二章,“关键绩效指标和可视化”,我们将更详细地讨论如何使用描述性分析来分析和计算关键摘要统计数据,并可视化分析结果。
-
解释性分析:当描述性分析的目的是从数据中回答什么和如何时,解释性分析则是利用数据来回答为什么。这种类型的分析通常在你有一个特定问题需要回答时进行。例如,对于电子商务企业,如果你想分析是什么促使用户进行购买,你会进行解释性分析,而不是描述性分析。我们将在第三章中详细讨论这种类型的分析及其示例,“驱动市场参与背后”;和第四章,“从参与到转化”,在这些章节中,我们将使用解释性分析来回答诸如“是什么促使用户更多参与我们的营销活动?”和“是什么让用户从我们的零售店购买商品?”等问题。
-
预测分析: 当你希望预测某个特定的未来事件时,进行此分析。此分析的目的是构建机器学习模型,从历史数据中学习并对未来将要发生的事件进行预测。类似于之前的电子商务和购买历史数据,你可以通过这种分析回答的问题之一可能是,哪位用户最有可能在接下来的七天内进行购买? 通常,为了进行预测分析,你需要首先进行描述性和解释性分析,以更好地理解数据,并生成关于该项目使用哪种类型的学习算法和方法的想法。我们将在第六章 推荐合适的产品、第八章 预测营销参与的可能性、以及第十一章 保持客户中更详细地讨论预测分析及其在营销中的应用。
学习算法的类型
现在,让我们讨论更多关于机器学习和机器学习算法的内容。广义上说,机器学习算法分为三种类型:监督学习、无监督学习和强化学习。我们首先来了解这三种不同类型的机器学习算法是如何相互区分的:
-
监督学习算法: 当预测目标或结果已知时,使用这些算法。例如,如果我们想使用机器学习预测未来几天谁会进行购买,那么我们将使用监督学习算法。在这里,预测目标或结果是此人在给定时间窗口内是否进行了购买。基于历史购买数据,我们需要构建特征来描述每个数据点,如用户的年龄、地址、最后一次购买日期等,然后监督学习算法将从这些数据中学习如何将这些特征映射到预测目标或结果。我们将在第三章 营销参与驱动因素、第四章 从参与到转化、第八章 预测营销参与的可能性,以及最后的第十一章 保持客户中探讨如何在营销中使用这些算法。
-
**无监督学习算法:**与监督学习算法不同,无监督学习算法在我们没有特定预测目标或结果时使用。这类机器学习算法常用于聚类和推荐系统。例如,你可以使用无监督学习算法将客户群体根据行为划分为不同的子组或细分市场。在这种情况下,我们没有具体的目标或结果想要预测,我们只是将相似的客户分到不同的细分群体中。在第六章《推荐合适的产品》和第十章《数据驱动的客户细分》中,我们将探讨如何在市场营销中使用无监督学习算法。
-
**强化学习算法:**这些算法在我们希望模型在没有先验知识或经验的情况下不断学习和自我训练时使用。在强化学习的情况下,模型通过大量的试错来学习如何进行预测。一个应用强化学习的市场营销例子是,当你有多种营销策略想要测试并选择效果最好的策略时。此时,你可以运行一个强化学习算法,让它每次随机选择一个策略,当出现积极结果时给予奖励。经过多次的试错迭代后,强化学习模型将学会根据每种营销策略所获得的总奖励来选择最佳策略。
数据科学工作流程
现在我们已经涵盖了机器学习算法的基础知识和不同类型,接下来我们讨论数据科学的工作流程。一个典型的工作流程如下所示:
-
**问题定义:**通常,任何数据科学和机器学习项目都从问题定义开始。在第一步中,你需要定义你希望通过数据科学解决的问题、项目的范围以及解决该问题的方法。当你思考解决问题的方法时,你需要头脑风暴,思考之前讨论过的分析类型(描述性分析、解释性分析、预测性分析)和学习算法类型(监督学习、无监督学习、强化学习)中哪些适合解决给定的问题。
-
数据收集:一旦你清楚地定义了项目的目标,就可以进入数据收集阶段。这是你收集所有需要的数据以继续进行数据科学项目的阶段。你可能需要从第三方供应商购买数据、从网上抓取和提取数据,或者使用公开的数据。在某些情况下,你还需要从内部系统中收集数据。根据不同的情况,数据收集阶段可能很简单,也可能很繁琐。
-
数据准备:当你从数据收集阶段收集到所有需要的数据后,接下来的步骤就是数据准备。这个步骤的目标是将数据转化并为未来的步骤做准备。如果数据源的格式不同,那么你需要转换并统一数据。如果数据没有特定的结构,那么你需要将数据结构化,通常是以表格格式,以便于你能够轻松进行不同的分析并构建机器学习模型。
-
数据分析:完成数据准备步骤后,你就需要开始查看数据。在数据分析阶段,通常会进行描述性分析,计算一些描述性统计数据,并构建可视化图表以更好地理解数据。在这一阶段,你很可能能够发现一些可识别的模式,并从数据中获得一些洞察。你也可能会发现数据中的异常情况,例如缺失值、损坏的数据或重复记录。
-
特征工程:特征工程是数据科学和机器学习中最重要的部分,因为它直接影响预测模型的表现。特征工程需要专业知识和良好的领域知识,因为它要求你将原始数据转化为更加信息丰富的数据,以便算法从中学习。特征工程的一个好例子是将文本数据转换为数值数据。由于机器学习算法只能从数值数据中学习,因此你需要提出一个想法和策略,将文本数据转化为数值数据。随着本书的进展以及我们构建机器学习模型的过程中,我们将讨论并实验各种特征工程技术。
-
模型构建:一旦完成特征工程步骤,你就可以开始训练和测试机器学习模型了。在这一步,你可以尝试不同的学习算法,找出最适合你使用案例的算法。在这一步,值得注意的一点是验证指标。拥有一个好的模型性能衡量标准很重要,因为机器学习算法会尝试在给定的性能度量上进行优化。随着我们在接下来的章节中开始构建机器学习模型,我们将详细讨论根据我们所处理问题的类型使用哪些指标。
以下图表展示了典型数据科学项目的整体工作流程:
从这个图表中可以看出,数据科学工作通常不是一次性完成的。当你发现模型表现不佳,或者注意到可以改进输入数据的质量时,你可能需要重复数据收集步骤。当你有了更好的思路和策略来从原始数据集构建特征时,可能还需要重新审视特征工程步骤。如果你认为通过调整学习算法的超参数可以改进模型结果,模型构建步骤可能需要多次重复。在接下来的章节中,当我们进行实际项目和练习时,我们将更详细地讨论某些步骤以及我们可以使用的不同技术。
设置 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/
进行安装。当您访问此链接时,网页应如下所示:
在本书中,我们将在 Python 3 中使用 Anaconda 5.2。一旦您下载了 Anaconda 发行版,可以使用安装程序安装所有包。在 macOS 上,安装程序如下所示:
一旦您按照安装程序的步骤完成 Anaconda 发行版的安装,我们现在已经准备好开始运行数据科学和机器学习任务。在接下来的部分,我们将构建一个简单的逻辑回归模型,以了解如何使用我们刚刚安装的关键 Python 库进行未来的练习。
Python 中的简单逻辑回归模型
现在我们已经安装了所有的包,让我们测试一下是否可以使用它们。我们将来会使用 Jupyter Notebook 来进行所有的数据分析、数据可视化和机器学习任务。Jupyter Notebook 是一个开源的 web 应用程序,您可以轻松编写代码、显示图表,并与他人分享笔记本。您可以在此链接找到更多关于 Jupyter Notebook 的信息:jupyter.org/
。
由于 Jupyter Notebook 是前一节中刚刚安装的 Anaconda 发行版的一部分,您的计算机上应该已经安装了它。
要启动 Jupyter Notebook,您可以打开终端窗口并输入以下命令:
jupyter notebook
当您输入此命令时,应该会看到类似以下截图的输出:
最后,它应该会在你的浏览器中打开一个网页应用程序。网页界面应该如下所示:
从这张截图可以看到,你可以通过点击右上角的 New 按钮,然后选择 Python 3 来创建一个新的 Jupyter Notebook。这将创建一个新的空白笔记本,选择 Python 3 作为编程语言。新创建的笔记本应该如下所示:
为了更改这个笔记本的名称,你只需点击顶部栏,那里写着Untitled
,然后输入一个新的名称。
现在我们已经创建了一个笔记本,接下来让我们使用一些 Python 库来构建一个简单的逻辑回归模型。在第一个单元格中,我们将导入numpy
和scikit-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 列的输入数据。输出是二元的,只能取0
或1
。
使用这些数据,我们可以训练一个逻辑回归模型,代码如下所示:
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 如下所示:
为了对新数据进行预测,你可以使用逻辑回归模型对象logit_model
的predict
函数。此函数将返回每个输入的预测输出类别。代码如下所示:
predicted_output = logit_model.predict(input_data)
到目前为止,我们已经尝试了如何使用numpy
和scikit-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
函数,它接受x
和y
的值,以及每个点的color
。你可以使用xlabel
函数来修改* x 轴的标签,使用ylabel
函数来修改 y *轴的标签。通过title
函数,你可以修改图表的标题。grid
函数会在图表中显示网格,而你需要调用show
函数来实际显示图表。
Jupyter Notebook 应该如下所示:
需要注意的一点是以下代码:
%matplotlib inline
这是为了在 Web 应用程序中显示图表。如果没有这一行代码,图表将不会显示在 Web 界面中。为了将实际输出与模型的预测进行比较,我们使用预测值构建了另一个散点图。
代码和图表如下所示:
如果将这张图与前一张图进行比较,你会发现模型正确预测了四分之三的输出,并且错误预测了一个点。
你可以从以下链接下载我们在本节中使用的完整 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/
。如果你访问该网页,它的界面会类似于以下截图:
你可以在此网页找到有关 R 的更多信息。为了让你下载,请点击页面中的下载 R 链接。它会要求你选择一个 CRAN 镜像。你可以选择距离你最近的镜像位置来下载 R。下载完成后,按照安装程序中的步骤进行安装。在 macOS 上的安装程序如下图所示:
安装完 R 后,我们还需要为我们的 R 开发环境安装一个工具。在本书中,我们将使用 RStudio,这是一个流行的 R 编程语言 IDE。你可以通过以下链接下载 RStudio:www.rstudio.com/products/rstudio/download/
。当你访问这个 RStudio 下载页面时,页面应显示如下截图:
本书中将使用 RStudio Desktop Open Source License 版本,但如果你已经拥有其他版本的许可证,也可以随意使用。下载并安装 RStudio 后,打开 RStudio 时你将看到类似下面的截图:
现在我们已经准备好了 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)
)
如代码片段所示,我们构建了一个包含X
、Y
和output
列的数据框。X
列的取值为0
、0.25
、0.5
和1
,Y
列的取值为0
、0.5
、0.5
和1
,output
是一个二元分类,取值为0
或1
。data
如下所示:
现在我们有了训练逻辑回归模型的数据,接下来让我们看一下以下代码:
# 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)
这将输出如下截图所示的内容:
如你所见,从这个输出中,我们可以轻松找到模型的系数和截距。我们将在本书中频繁使用这个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
包时会看到以下错误信息:
如消息所示,ggplot2
包尚未安装在你的计算机上。要安装任何 R 包,你只需运行以下命令:
install.packages('ggplot2')
如果你运行这个命令,你会看到类似以下的输出:
一旦这个库的安装完成,你就可以导入并使用这个库了。我们将使用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
函数来更改图表的标题。当你运行这段代码时,你将看到以下图表:
我们将对预测结果执行相同的操作。代码如下:
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))
输出如下所示:
在本书中,我们将大量使用这些函数和绘图库ggplot2
,因此随着章节和练习的进行,你将越来越习惯于用 R 编程,并且能够熟练使用这些其他库。
你可以从以下链接查看并下载用于本节的完整 R 代码:github.com/yoonhwang/hands-on-data-science-for-marketing/blob/master/ch.1/R/SettingUpREnvironment.R
.
总结
在这一章中,我们讨论了市场营销中的整体趋势,并了解了数据科学和机器学习在营销行业中日益重要的作用。随着数据量的增加,以及我们观察到利用数据科学和机器学习进行营销的好处,各种规模的公司都在投资构建更多以数据为驱动的定量营销策略。
我们还学习了不同类型的分析方法,特别是本书中我们将频繁使用的三种分析方法——描述性分析、解释性分析和预测性分析——以及这些分析的不同使用案例。在这一章中,我们介绍了不同类型的机器学习算法,以及数据科学中的典型工作流程。最后,我们花了一些时间在 Python 和 R 中设置我们的开发环境,并通过构建一个简单的逻辑回归模型来测试我们的环境设置。
在下一章中,我们将介绍一些关键绩效指标(KPIs)以及如何可视化这些关键指标。我们将学习如何在 Python 中计算并构建这些 KPIs 的可视化图表,使用不同的包,如pandas
、numpy
和matplotlib
。对于那些使用 R 语言跟随本书练习的读者,我们还将讨论如何使用 R 来计算并绘制这些 KPIs,利用 R 中的各种统计和数学函数,以及用于可视化的ggplot2
包。
第二部分:描述性分析与解释性分析
在本节中,你将学习在营销行业中常用的关键绩效指标(KPI),如何使用 Python 和 R 中的图表库来可视化指标,以及如何使用机器学习算法理解什么因素推动了营销活动的成功与失败。
本节包括以下章节:
-
第二章,关键绩效指标与可视化
-
第三章,营销互动背后的驱动因素
-
第四章,从互动到转化
第二章:关键绩效指标和可视化
当你进行营销活动或其他任何营销工作时,你很可能想要了解每个活动的表现如何,并理解每个营销努力的优缺点。在本章中,我们将讨论一些常用的关键绩效指标(KPI),这些指标帮助你跟踪营销工作表现。更具体地说,我们将涵盖诸如销售收入、客户获取成本(CPA)、数字营销 KPI 和网站流量等指标。我们将学习这些 KPI 如何帮助你朝着营销目标稳步前进。
在讨论了一些常用的 KPI 后,我们将学习如何使用 Python 和/或 R 来计算这些 KPI 并构建它们的可视化。在本章中,我们将使用一个银行营销数据集,展示一个金融组织营销活动的真实案例。对于 Python 项目,我们将学习如何使用pandas
和matplotlib
库来分析数据并构建可视化图表。对于 R 项目,我们将介绍dplyr
和ggplot2
库来分析和处理数据,并创建可视化图表。
特别地,本章将涵盖以下主题:
-
用于衡量不同营销活动表现的 KPI
-
使用 Python 计算和可视化关键绩效指标(KPI)
-
使用 R 计算和可视化关键绩效指标(KPI)
用于衡量不同营销活动表现的 KPI
每一项营销努力都需要公司投入资金。当你通过电子邮件进行营销活动时,发送每封邮件都会产生一定的费用。当你在社交网络服务或广播媒体上开展营销活动时,也需要一些资本。由于每项营销活动都涉及一定的成本,因此,检查营销活动的表现并跟踪营销活动的投资回报率(ROI)是至关重要的。本节我们将主要讨论如何跟踪销售收入、CPA 和数字营销 KPI。
销售收入
很明显,每个营销努力的目标都是为公司创造和增长更多的收入。没有公司希望在营销上的花费超过其带来的收入。为了准确报告销售收入,你需要清楚地定义如何将销售归因于每一项营销活动。部分销售可能来源于电子邮件营销活动,而另一些可能来自电视或公共交通上的广告。也有可能一些销售是自然发生的,并没有归因于任何营销活动。
为了正确报告每个营销活动所带来的销售收入,你需要明确定义规则,将销售额归因于每个营销活动。例如,如果你是一家电子商务公司,通过电子邮件和电视广告活动进行促销,你可能希望在电子邮件中使用与电视广告中不同的 URL。这样,你就可以将通过电子邮件营销活动获得的销售与通过电视营销活动获得的销售区分开来。
根据你的需求,你可能还希望报告时间序列的销售收入数据。你可以以电子表格的格式报告,如下所示:
你还可以通过折线图报告时间序列的销售收入数据,如下所示:
我们将在本章末的 Python 和 R 练习中讨论更多关于报告 KPI 时可以使用的不同类型的图表和数据可视化方式。
每客户获取成本(CPA)
另一个衡量营销效果的方法是 CPA(每客户获取成本)。这个 KPI 指标告诉你,通过营销活动获取一个客户的成本是多少。高 CPA 意味着获取新客户的成本较高,而低 CPA 显然意味着获取新客户的成本较低。根据不同的业务类型,即使 CPA 较高,你仍然可以拥有一个非常有利可图的营销活动。例如,如果你销售的是非常奢华且高端的产品,目标客户群体较小,获取这些客户的成本较高,那么你的 CPA 可能较高,但你所获得的每个客户的价值可能更高,从而导致一个有利可图的营销活动。
我们将看一下以下这个假设案例:
如果你查看这个电子表格,欢乐时光活动是最昂贵的营销活动,无论是从总成本还是 CPA 来看。然而,它产生了最多的销售额和每客户销售额;因此,它是最有价值的活动。另一方面,广播广告的 CPA 最低,尽管总成本是第二高的,因为它帮助企业获得了最多的客户。然而,这些客户的总销售额并没有超过该活动的总成本,并给公司带来了净亏损。
即使这是一个假设情境,类似的情况也可能发生在现实生活中。营销活动,比如欢乐时光活动和网络研讨会,比广播广告更能精准地瞄准客户。通过高度精准的营销活动获取的客户质量比通过非精准营销活动获取的客户好得多。
现在我们已经看到如何分解营销活动结果,以更深入地分析成本效益,我们将看看一些常用的数字营销 KPI。
数字营销 KPI
随着营销渠道选择的增加,如社交网络服务、博客和搜索引擎,报告数字营销效果变得越来越重要。之前讨论过的 KPI、销售收入和获取成本,同样适用于数字营销领域。
作为一个例子,基于单一归因逻辑,你可以分析通过不同社交网络服务(如 Facebook、LinkedIn 和 Instagram)生成了多少销售。你还可以分析通过这些营销渠道获得了多少客户,并查看各个数字营销活动的 CPA 和所生成的价值。让我们来讨论更多的数字营销 KPI:
- 点击率(CTR)是另一个数字营销中常常关注的 KPI。CTR 是观看了广告并点击广告的人的百分比。公式如下:
点击率(CTR)是数字营销渠道中的一个重要指标,因为它衡量了你的在线营销在将流量引导到你的网站方面的效果。
-
然后,你可以使用潜在客户比率来衡量有多少网站流量可以转化为潜在客户。通常,只有一部分网站流量适合成为你的客户。这些营销合格潜在客户(MQL)是那些已经准备好接受营销的潜在客户,符合特定商业标准,有可能成为会购买的客户,基于他们的特征。当你开始对这些合格的潜在客户进行营销时,你也应该关注转化率。
-
转化率是将潜在客户转化为活跃客户的百分比。你可以根据你的营销目标来定义什么应当视为转化。如果你的目标是查看有多少潜在客户变成了付费客户,那么你可以按照类似下面的公式计算转化率:
如果你的目标是查看有多少潜在客户在你的网站上注册,那么你可以按照以下公式计算转化率:
到目前为止,我们已经查看了各种 KPI,并讨论了这些 KPI 如何帮助你跟踪营销工作的进展和效果。接下来,我们将看看如何使用 Python 和/或 R 来计算这些 KPI 并进行可视化。如果你计划使用本书中介绍的两种编程语言之一,Python 或 R,你可以跳过并直接进入你想要学习的部分。
使用 Python 计算和可视化 KPI
在本节中,我们将讨论如何使用 Python 计算和可视化我们在前几节中讨论的关键绩效指标(KPI)。我们将主要集中于使用银行营销数据分析转化率。对于那些希望使用 R 进行本次练习的读者,您可以跳到下一节。我们将使用pandas
和matplotlib
库来操作和分析数据,并构建各种图表,以准确报告营销工作的进展和表现。
在本节的练习中,我们将使用UCI 的银行营销数据集,可以通过以下链接找到:archive.ics.uci.edu/ml/datasets/bank+marketing
。您可以访问该链接,并通过点击左上角的Data Folder
链接下载数据。对于本次练习,我们下载了bank-additional.zip
数据,并将使用其中的bank-additional-full.csv
文件。
当您打开这个bank-additional-full.csv
文件时,您会注意到使用分号(;
)作为分隔符,而不是逗号(,
)。为了加载这些数据,您可以使用以下代码将数据读取到pandas
的DataFrame
中:
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 中加载的数据如下所示:
现在我们已经成功将数据读取到pandas
的DataFrame
中,我们将开始查看如何使用各种方法和图表来分析和可视化转化率。
聚合转化率
首先,我们将查看聚合转化率。我们可以通过将订阅定期存款的客户总数除以数据中客户的总数来计算这个指标。由于我们已经将输出变量编码为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 中进行转化率计算的代码:
如你所见,在 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
的部分转化率计算结果:
另一种查看不同客户年龄段转化率的方法是通过绘制折线图,如下图所示:
用于可视化不同年龄段转化率的代码如下所示:
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_xlabel
和set_ylabel
函数。
在之前的折线图中,有一点值得注意的是,老年组的数据显示似乎有很多噪音。对于70
岁或以上的人群,转化率波动较大,如果你查看数据,会发现这主要是因为这个年龄组的客户数量相对较少,和其他年龄组相比差距较大。
为了减少这种不必要的噪音,我们可以将多个年龄组合并。在本练习中,我们将银行客户根据年龄分为六个不同的组——18
到30
岁,30
到40
岁,40
到50
岁,50
到60
岁,60
到70
岁,以及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
与之前的情况类似,我们使用groupby
、sum
和count
函数来计算这六个不同年龄组的转化率。结果数据如下所示:
从这个结果可以看出,各年龄组之间的差异比之前要小得多,尤其是在老年组。我们可以使用条形图来可视化这些数据,如下所示的屏幕截图所示:
构建此条形图的代码如下所示:
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
函数。我们根据marital
和conversion
列进行分组,其中marital
将成为新DataFrame
的索引,conversion
将成为列。通过aggfunc
参数,我们可以指定要执行的聚合类型。在这里,我们使用len
函数简单地计算每个组的客户数量。生成的数据如下所示:
另一种表示这些数据的方式是使用饼图,如下所示:
以下代码展示了我们如何构建这些饼图:
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_group
和marital
对数据进行分组,并求出转化的数量。然后,我们将这个数量除以每个群体中的客户总数。生成的数据如下所示:
如您从这些数据中看到的,我们现在可以根据两个标准(年龄组和婚姻状况)看到转化率的分布。例如,单身且年龄在18到30岁之间的客户转化率为 13.25%,而已婚且年龄在60到70岁之间的客户转化率为 30.11%。另一种可视化这些数据的方式是使用如下所示的条形图:
在这张条形图中,我们可以清楚地看到每个年龄和婚姻状态群体的转化率分布。我们用来构建这张条形图的代码如下所示:
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
时,它将构建一个堆叠条形图,效果如下:
从这个堆叠条形图中可以看到,不同的婚姻状态在每个年龄组中被叠加在一起。通过这种方式,我们不仅可以轻松看到不同年龄组的转化率的整体趋势,还可以看到每个年龄组中不同婚姻状态的转化客户的比例。
我们在此 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 中的dplyr
和ggplot2
库来处理和分析数据,并构建各种图表,以准确报告营销工作中的进展和效果。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'
分别编码为1
和2
,所以我们将其值减去1
。现在,数据在 RStudio 中的显示情况如下:
现在我们已经成功将数据读取到R
的DataFrame
中,接下来我们将开始探索如何分析和可视化转化率,使用不同的方法和图表。
总体转化率
首先,我们要查看的是总体转化率。我们可以通过将订阅了定期存款的客户数量除以数据中总客户数量来计算这个指标。由于我们已经将输出变量编码为 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 中的代码显示情况:
从 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
来获得转化率。
结果数据如下所示:
查看不同年龄段客户的转化率的另一种方法是绘制折线图,如下图所示:
用于可视化不同年龄段转化率的代码如下所示:
# 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
函数更改图表标题。此外,你还可以使用xlab
和ylab
函数分别重命名 x 轴和 y 轴标签。
在前一张折线图中,显而易见的一点是,较高年龄组的噪声似乎很多。70 岁或以上的转化率变化较大,如果你查看数据,会发现这主要是因为该年龄组的客户数量相对较少,与其他年龄组相比。
为了减少这种不必要的噪音,我们可以将多个年龄段合并。在本练习中,我们根据银行客户的年龄将其分为六个不同的组——18
到30
岁之间、30
到40
岁之间、40
到50
岁之间、50
到60
岁之间、60
到70
岁之间、以及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)
表示我们将从20
到70
以10
为增量创建一个序列。一旦数据按这些年龄段分组,其他操作与之前相同。我们使用summarise
和mutate
函数来计算TotalCount
、NumConversions
和ConversionRate
列。
生成的DataFrame
在以下截图中展示:
从中可以看出,每个年龄组的差异远小于之前,尤其是在老年组。我们可以通过条形图来可视化这些数据,如下所示:
构建此条形图的代码如下所示:
# 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
来重新命名图表标题,使用xlab
和ylab
函数来重新命名* 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
包中的管道操作符%>%
将DataFrame
,conversionsDF
传递给group_by
函数,然后传递给summarise
函数。在group_by
函数中,我们按两个列进行分组,marital
和conversion
。在summarise
函数中,我们只是通过使用n
函数计算每个组中的记录数量。
结果数据显示在以下截图中:
另一种表示这些数据的方式是使用饼图:
以下代码展示了我们如何在 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
函数,将年龄分组为从20
到70
,每 10 岁一组。然而,这次我们也按marital
列进行分组。
然后,我们使用summarise
函数计算每个组中的记录数量Count
,以及每个组中的转化次数NumConversions
。接着,使用mutate
函数计算每个年龄组的总记录数,命名为TotalCount
,以及每个组的转化率,命名为ConversionRate
。
结果数据显示在以下截图中:
从这些数据中可以看出,我们现在可以根据两个标准来查看转化率的分布:年龄组和婚姻状况。例如,单身且年龄在20到30岁之间的客户转化率为 11.10%,而已婚且年龄在40到50岁之间的客户转化率为 5.74%。
另一种可视化这些数据的方法是使用条形图:
在这个条形图中,我们可以轻松地看到每个年龄组和婚姻状况组的转化率分布。我们用来构建这个条形图的代码如下:
# 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
参数,它将创建一个堆积条形图,效果如下:
从这个堆积条形图中可以看到,不同的婚姻状况在每个年龄组中堆叠在一起。这样,我们不仅可以轻松地看到不同年龄组之间转化率的总体趋势,还可以看到每个年龄组中不同婚姻状况的转化客户比例。
我们在这个 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个特征,那么线性回归公式如下:
从上述公式中可以看到,输出变量Y表示为特征X[i]的线性组合。线性回归模型的目的是找到最能估算输出变量的截距a和系数b[i],并利用给定的特征进行拟合。拟合的线性回归线大致如下所示(图片来源于 towardsdatascience.com/linear-regression-using-python-b136c91bf0a2
):
该图中的蓝色点表示数据点,红色线是拟合的或训练过的线性回归线。正如图表所示,线性回归试图通过特征的线性组合来估计目标变量。
在本章中,我们将讨论如何使用回归分析,尤其是逻辑回归模型,来理解是什么驱动了更高的客户参与度。
逻辑回归
逻辑回归是一种回归分析方法,通常用于输出变量是二元的情况(表示正面结果为 1,负面结果为 0)。与其他线性回归模型类似,逻辑回归模型通过特征变量的线性组合来估算输出。唯一的区别是模型估算的内容。与其他线性回归模型不同,逻辑回归模型估算的是事件的对数机会,或者换句话说,是正面事件和负面事件概率之间的对数比率。其公式如下:
左边的比率是成功的机会,表示成功的概率与失败的概率之间的比率。对数机会的曲线,也称为logit 曲线,如下所示:
逻辑回归模型的输出只是 logit 的逆,它的值范围从零到一。在本章中,我们将使用回归分析来理解是什么推动了客户参与度,输出变量将是客户是否对营销电话作出回应。因此,逻辑回归在这种情况下非常适用,因为输出是一个二元变量,可以取两个值:响应和未响应。在接下来的章节中,我们将讨论如何在 Python 和 R 中使用和构建逻辑回归模型,然后我们将讲解如何解读回归分析结果,以理解哪些客户属性与更高的营销参与度高度相关。
使用 Python 进行回归分析
在本节中,你将学习如何在 Python 中使用statsmodels
包进行回归分析。对于那些希望使用 R 而非 Python 的读者,可以跳到下一节。在本节开始时,我们将通过使用pandas
和matplotlib
包更仔细地查看数据,然后我们将讨论如何使用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')
与我们在第二章中做的类似,关键绩效指标与可视化,我们首先导入matplotlib
和pandas
包;使用pandas
中的read_csv
函数,我们可以将数据读取到pandas
DataFrame 中。稍后我们将使用matplotlib
进行数据分析和可视化。
加载后的 DataFrame,df
,如下所示:
如我们在第二章中讨论的,关键绩效指标与可视化,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
,我们得到参与率。结果如下所示:
为了更容易阅读,我们可以转置数据框(DataFrame),这意味着我们可以翻转数据框中的行和列。你可以通过使用数据框的T
属性来转置pandas
数据框。其效果如下所示:
如你所见,大约 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 Channel
和Response
变量进行分组。运行这段代码后,engagement_by_sales_channel_df
将包含如下数据:
正如你在上一节中已经注意到的,未参与营销活动的客户明显更多,因此在原始数据中很难直接看出参与客户与未参与客户在销售渠道分布上的差异。为了让这些差异更加直观地显现出来,我们可以使用以下代码构建饼图:
engagement_by_sales_channel_df.plot(
kind='pie',
figsize=(15, 7),
startangle=90,
subplots=True,
autopct=lambda x: '%0.1f%%' % x
)
plt.show()
一旦你运行这段代码,你将看到以下饼图,展示了已参与和未参与客户在不同销售渠道中的分布情况:
与之前显示每个销售渠道中已参与和未参与客户原始计数的表格相比,这些饼图帮助我们更轻松地可视化并发现分布差异。如你从这些图表中看到的,超过一半的已参与客户来自代理商,而未参与客户则更均匀地分布在所有四个不同的渠道中。正如你从这些图表中看到的,分析和可视化数据能够帮助我们发现数据中的有趣模式,这将在本章后续的回归分析中提供帮助。
总赔付金额
在我们进入回归分析之前,我们要先看一下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
在已参与和未参与组之间的分布:
中央矩形从第一个四分位数到第三个四分位数,绿色线条显示中位数。下边和上边分别显示分布的最小值和最大值。需要注意的是,在之前的代码中使用了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
标志,生成的箱形图如下所示:
正如你在这些箱形图中所注意到的,它们在上边界线之上绘制了许多点,这些点代表了之前箱形图中的最大值。上边界线上的点显示了基于四分位距(IQR)判定的疑似异常值。IQR 即第一个四分位数和第三个四分位数之间的范围,任何超过第三个四分位数1.5*IQR
或低于第一个四分位数1.5*IQR
的点都被认为是疑似异常值,并通过这些点显示出来。
回归分析
到目前为止,我们已经分析了数据中字段的类型以及参与组和非参与组之间的模式差异。现在,我们将讨论如何使用 statsmodels
包在 Python 中进行回归分析及其解释。我们将首先用连续变量构建一个逻辑回归模型,并学习如何解释结果。接着,我们将讨论在拟合回归模型时如何处理分类变量,以及这些分类变量对拟合的逻辑回归模型的影响。
连续变量
在线性回归中,包括逻辑回归,当特征变量是连续的时,拟合回归模型非常简单,因为它只需要找到特征变量的线性组合,利用数值特征来估计输出变量。为了用连续变量拟合回归模型,首先让我们看看如何获取 pandas
DataFrame 中列的数据类型。请看以下内容:
如你从这张 Jupyter Notebook 截图中看到的,pandas
Series
对象的 dtype
属性告诉你它包含的数据类型。从这张截图可以看出,Income
变量是整数,而 Customer Lifetime Value
特征是浮点数。为了快速查看具有数值的变量的分布,你也可以执行以下操作:
如你在这个 Jupyter Notebook 截图中看到的,pandas
DataFrame 的 describe
函数显示了所有数值列的分布。例如,你可以看到 Customer Lifetime Value
列中共有 9134
条记录,均值为 8004.94
,范围从 1898.01
到 83325.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()
如你在这段代码中看到的,我们正在使用逻辑回归对象logit
的fit
函数来训练逻辑回归模型。运行这段代码后,训练好的模型logit_fit
将学习出最佳解决方案,通过使用输入变量来最佳估计输出变量Engaged
。若要获得已训练模型的详细描述,可以使用以下代码:
logit_fit.summary()
当你运行这段代码时,summary
函数将在 Jupyter Notebook 中显示以下输出:
让我们更仔细地看看这个模型输出。coef
表示每个输入变量的系数,z
表示z-分数,它是离均值的标准差个数。P>|z|
列表示p-值,它表示通过偶然性观察到特征与输出变量之间关系的可能性。因此,P>|z|
的值越低,给定特征与输出变量之间的关系越强,且不太可能是偶然的。通常,0.05
是一个良好的p-值临界点,任何小于0.05
的值都表示给定特征与输出变量之间存在强关系。
从这个模型输出中,我们可以看到,Income
、Monthly Premium Auto
、Months Since Last Claim
、Months Since Policy Inception
和Number of Policies
变量与输出变量Engaged
有显著的关系。例如,Number of Policies
变量是显著的,并且与Engaged
呈负相关。这表明,客户拥有的保单越多,他们响应营销电话的可能性越小。另一个例子是,Months Since Last Claim
变量也是显著的,并且与输出变量Engaged
呈负相关。这意味着,自上次理赔以来的时间越长,客户回应营销电话的可能性就越低。
从这些例子中你可以看出,通过查看模型输出中特征的p-值和系数,你可以轻松地解释回归分析结果。这是理解哪些客户特征与我们关心的结果显著相关的好方法。
分类变量
正如你在上一节中看到的连续变量的例子,理解输入和输出变量之间的关系是相当直接的,尤其是通过系数和p-值。然而,当我们引入类别变量时,情况就变得不那么直观了。类别变量通常没有任何自然顺序,或者它们被编码为非数值型的值,但在回归分析中,我们需要输入变量具有数值型的值,这些值能够表示变量的顺序或大小。例如,我们无法轻松地为数据集中的State
变量编码出某种顺序或数值。这就是为什么在进行回归分析时,我们需要与连续变量不同地处理类别变量。在 Python 中,当使用pandas
包时,有多种方式来处理类别变量。我们首先来看一下如何对类别变量进行因子化,如下面的代码所示:
gender_values, gender_labels = df['Gender'].factorize()
pandas
的factorize
函数通过枚举值对类别变量进行数值编码。我们先来看一下下面的输出:
从这个输出中可以看出,Gender
变量的值被用零和一编码,其中0
表示女性(F
),1
表示男性(M
)。这是一种快速地将类别变量编码为数值型值的方法。然而,当我们希望将自然顺序嵌入编码值时,这个函数就不起作用了。例如,我们数据集中的Education
变量有五个不同的类别:High School or Below
、Bachelor
、College
、Master
和Doctor
。我们可能希望在对Education
变量内的不同类别进行编码时,能够嵌入顺序关系。
以下代码展示了另一种在使用pandas
时对类别变量进行排序编码的方法:
categories = pd.Categorical(
df['Education'],
categories=['High School or Below', 'Bachelor', 'College', 'Master', 'Doctor']
)
如你在这段代码中看到的,我们使用pd.Categorical
函数对df['Education']
的值进行编码。我们可以通过参数categories
来定义我们希望的排序。在我们的例子中,我们为High School or Below
、Bachelor
、College
、Master
和Doctor
这些类别分别赋予了0
、1
、2
、3
和4
的值。输出如下所示:
我们现在将这些编码后的变量添加到 pandas DataFrame df
中,如下面的代码所示:
df['GenderFactorized'] = gender_values
df['EducationFactorized'] = categories.codes
使用这两个类别变量,Gender
和Education
的编码后,我们可以使用以下代码来拟合逻辑回归模型:
logit = sm.Logit(
df['Engaged'],
df[[
'GenderFactorized',
'EducationFactorized'
]]
)
logit_fit = logit.fit()
类似于之前如何使用连续变量拟合逻辑回归模型,我们可以使用statsmodels
包中的Logit
函数,利用编码后的类别变量GenderFactorized
和EducationFactorized
来拟合逻辑回归模型。使用拟合后的逻辑回归模型对象的summary
函数,我们将得到如下输出:
如你所见,从输出结果中以及查看P>|z|
列中的p-值,GenderFactorized
和EducationFactorized
这两个变量似乎与输出变量Engaged
之间存在显著关系。如果我们查看这两个变量的系数,可以看到它们与输出变量呈负相关。这表明,与女性客户(在GenderFactorized
变量中编码为0
)相比,男性客户(在GenderFactorized
变量中编码为1
)更不可能参与营销电话。同样,客户的教育水平越高,他们参与营销电话的可能性就越低。
我们已经讨论了在pandas
中处理分类变量的两种方法,分别是使用factorize
和Categorical
函数。通过这些技术,我们可以了解不同类别的分类变量与输出变量之间的相关性。
结合连续变量和分类变量
本章我们将进行的最后一个 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()
与之前的代码唯一不同的是我们选择的特征,用于拟合逻辑回归模型。如你所见,在这段代码中,我们现在使用连续变量以及之前部分章节中创建的两个编码后的分类变量GenderFactorized
和EducationFactorized
来拟合逻辑回归模型。结果如下所示:
让我们仔细看看这个输出。Income
、Monthly Premium Auto
、Months Since Last Claim
、Months Since Policy Inception
、Number of Open Complaints
、Number of Policies
和GenderFactorized
这些变量在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=","
)
类似于我们在 第二章 关键绩效指标与可视化 中所做的那样,我们将在接下来的章节中首先导入 dplyr
和 ggplot2
包,以进行数据分析和绘图。通过在 R 中使用 read.csv
函数,我们可以将数据读取到 DataFrame 中。由于此 CSV 文件的第一行包含标题,且字段由逗号分隔,我们使用 header=TRUE
和 sep=","
标志以确保正确解析数据。
以下截图展示了数据在 DataFrame 中的原始样子:
现在我们已经将数据加载到 DataFrame 中,让我们开始更仔细地查看和分析数据,以便更好地理解数据的结构。
数据分析与可视化
在我们深入回归分析之前,让我们先更详细地查看数据,以便更好地了解我们拥有的数据点以及可以在数据中看到的模式。如果你查看数据,会注意到一个名为 Response
的列,它包含客户是否回应营销电话的信息。我们将使用这个字段作为客户参与度的衡量标准。为了进行未来的计算,最好将这个字段编码为数值类型。让我们来看一下以下代码:
# Encode Response as 0s and 1s
df$Engaged <- as.integer(df$Response) - 1
如您在这段代码中所见,我们使用as.integer
函数将未回应营销电话(No
)的客户编码为0
,将回应营销电话(Yes
)的客户编码为1
。由于as.integer
函数默认将值编码为1
和2
,我们通过减去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
,我们得到了参与率。结果如下所示:
为了更方便地阅读,我们可以转置数据框,这意味着我们将数据框中的行和列进行交换。您可以使用 R 中的t
函数来转置数据框。代码如下所示:
# Transpose
transposed <- t(engagementRate)
colnames(transposed) <- engagementRate$Engaged
transposed <- transposed[-1,]
转置后的数据框如下所示:
如您所见,通过转置数据框,我们可以更容易地查看参与和未参与客户的总数和百分比。从这些数据中,我们可以看到大约 14%的客户回应了营销电话,剩余的 86%的客户未回应。
销售渠道
现在,让我们看看是否能发现销售渠道和参与之间的明显模式。我们将分析参与和未参与的客户在不同销售渠道中的分布。首先请看以下代码:
salesChannel <- df %>%
group_by(Engaged, Channel=Sales.Channel) %>%
summarise(Count=n())
如您在这段代码中所见,我们使用了 R 中的group_by
函数对Sales Channel
和Engaged
变量进行分组。然后,使用n()
函数,我们将统计每个组中的客户数量。运行这段代码后,salesChannel
数据框将如下所示:
正如您在上一节中所注意到的,未参与营销活动的客户明显更多,因此,单凭原始数字很难比较并查看参与和未参与客户在销售渠道分布上的差异。为了更直观地区分这些差异,我们可以使用以下代码绘制饼图:
# 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_bar
和coord_polar("y")
来构建饼图。通过使用facet_wrap(~Engaged)
,我们可以将饼图分成两部分:一部分是未参与的客户,另一部分是已参与的客户。一旦你运行了这段代码,你会看到如下饼图,展示了已参与和未参与的客户在不同销售渠道中的分布:
与之前展示的每个销售渠道中已参与和未参与客户的原始计数数据表相比,这些饼图可以帮助我们更直观地看到分布差异。如你从这些图表中所看到的,超过一半的已参与客户来自代理商,而未参与的客户则在所有四个销售渠道中分布较为均匀。从这些图表中可以看出,数据分析和可视化帮助我们发现数据中的有趣模式,这将进一步帮助我们在本章后续进行回归分析时。
总赔偿金额
在我们深入回归分析之前,最后要看的内容是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
在已参与和未参与组之间的分布:
中央矩形从第一个四分位数到第三个四分位数,矩形内的线表示中位数。矩形的上下端点分别表示分布的最小值和最大值。你还会注意到这些箱线图中,线的上方有一些点。
超过上边线的点表示疑似异常值,这些值是基于 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
。我们来看一下现在箱线图的样子:
在这些图中,我们不再看到超出上限的点。根据你想要展示和分析的内容,箱线图中是否包含异常值可能会有所不同。
回归分析
到目前为止,我们已经分析了数据中的字段类型以及参与组和非参与组之间的模式差异。接下来,我们将讨论如何使用glm
函数进行回归分析并解释结果。我们将首先构建一个包含连续变量的逻辑回归模型,并学习如何解释其结果。然后,我们将讨论在R
中拟合回归模型时如何处理分类变量,以及这些分类变量对拟合的逻辑回归模型的影响。
连续变量
在线性回归中,包括逻辑回归,当特征变量是连续变量时,拟合回归模型非常简单,因为它只需要找到特征变量的线性组合来估计输出变量。为了拟合一个包含连续变量的回归模型,我们首先来看一下如何获取R
数据框中各列的数据类型。请看以下代码:
# get data types of each column
sapply(df, class)
在R
中使用sapply
函数,我们可以将class
函数应用于数据框的各列,class
函数告诉我们每列的数据类型。此代码的输出如下所示:
如前面的截图所示,我们可以轻松看出哪些列包含数值,哪些列不包含数值。例如,State
列的类型是"factor"
,这意味着该变量是一个分类变量。另一方面,Customer.Lifetime.Value
列的类型是"numeric"
,这意味着该变量是一个具有数值的连续变量。除此之外,我们还可以使用R
函数summary
来获取数据框中每列的汇总统计信息,这样我们不仅可以查看每列的数据类型,还能看到每列的分布概况。代码如下:
# summary statistics per column
summary(df)
当你运行此代码时,输出将如下所示:
在这个输出中,我们可以轻松地看到每列在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
中有哪些列。你应该会看到类似以下的输出:
我们现在准备使用连续变量拟合逻辑回归模型。首先让我们看看以下代码:
# 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
函数的另外两个参数是formula
和data
。第一个参数formula
是定义模型拟合方式的地方。~
左侧的变量是输出变量,右侧的变量是输入变量。在我们的案例中,我们告诉模型通过使用其他所有变量作为输入变量来学习如何估计输出变量Engaged
。如果你只想使用部分变量作为输入变量,则可以像下面这样编写公式:
Engaged ~ Income + Customer.Lifetime.Value
在这个公式中,我们告诉模型通过仅使用Income
和Customer.Lifetime.Value
作为特征来学习如何估计输出变量Engaged
。最后,glm
函数中的第二个参数data
定义了用于训练回归模型的数据。
现在我们已经有了一个训练好的逻辑回归模型,让我们来看看以下的代码,它展示了我们如何从这个模型对象中获取详细的回归分析结果:
summary(logit.fit)
R 中的summary
函数提供了回归分析结果的详细描述,结果如下所示:
让我们更详细地看看这个输出。Coefficients
部分的Estimate
列给出了每个特征系数的计算值。例如,Income
变量的系数是0.000002042
,Number.of.Policies
的系数是-0.02443
。我们还可以看到估计的Intercept
值是-1.787
。z value
列给出了z-值,它是人口均值的标准差数,而Pr(>|z|)
列是p-值,它表示通过偶然性观察到特征与输出变量之间关系的可能性。因此,Pr(>|z|)
值越低,给定特征与输出变量之间的关系就越可能是强烈的,而不是偶然的。通常,0.05
是p-值的一个良好的分界点,任何小于0.05
的值都表示给定特征与输出变量之间存在强关系。
从输出中Coefficients
部分下的Signif. codes
部分可以看出,***
符号位于Coefficients
部分的p-值旁边,表示p-值为0
时的最强关系;**
表示p-值小于0.001
;*
表示p-值小于0.05
,以此类推。如果你再看一下回归分析输出,只有三个变量——Income
、Number.of.Policies
和Total.Claim.Amount
——在0.1
的显著性水平下与输出变量Engaged
有显著的关系。此外,我们可以看到,Income
和Total.Claim.Amount
与Engaged
呈正相关,意味着收入越高或总索赔金额越高,客户与营销电话互动的可能性就越大。另一方面,Number.of.Policies
与Engaged
呈负相关,这表明客户拥有的保单数量越多,客户参与营销电话的可能性就越小。
正如你在这些示例中看到的,通过查看模型输出中各特征的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
作为输入变量的逻辑回归模型。在我们深入了解这意味着什么之前,先让我们看看以下的回归分析结果:
如您在此输出中所见,factor
函数创建了四个额外的变量:factor(Education)College
、factor(Education)Doctor
、factor(Education)High School or Below
和factor(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)
如您在这段代码中所见,我们现在正在拟合一个包含Education
和Gender
变量的回归模型,输出结果如下:
如果仔细查看此输出,您只会看到一个额外的因子变量 factor(Gender)M
,它表示男性客户,而数据中明显包含女性客户。这是因为 Education
变量中的 Bachelor
类别和 Gender
变量中的 F
(女性)类别被归为该回归模型的 (Intercept)
。因此,当所有因子变量的值为 0
时,基本情况是具有 Bachelor
学位的 female
客户。
对于具有 Bachelor
学位的男性客户,因子变量 factor(Gender)M
将具有值 1
,因此,输出变量 Engaged
的估计值将是 (Intercept)
加上 factor(Gender)M
的系数值。
如我们到目前为止所讨论的那样,我们可以通过在 R 中使用 factor
函数来处理分类变量。它本质上与为每个分类变量的每个类别创建一个单独的输入变量相同。使用这种技术,我们可以理解不同类别的分类变量如何与输出变量相关联。
结合连续变量和分类变量
本章我们要做的最后一个练习涉及将连续变量和分类变量结合起来进行回归分析。我们首先将前一节中讨论的两个分类变量 Gender
和 Education
进行因子化,并通过以下代码将它们存储在一个数据框中:
continuousDF$Gender <- factor(df$Gender)
continuousDF$Education <- factor(df$Education)
现在,数据框 continuousDF
包含以下列:
现在,我们将使用以下代码来拟合一个包含分类变量和连续变量的逻辑回归模型:
# Fit regression model with Education & Gender variables
logit.fit <- glm(Engaged ~ ., data = continuousDF, family = binomial)
summary(logit.fit)
您应该得到如下输出:
让我们更仔细地查看此输出。Total.Claim.Amount
变量和 EducationDoctor
变量在 0.05
显著性水平下显著,并且它们与输出变量 Engaged
存在正相关关系。因此,理赔总金额越高,客户与营销电话互动的可能性越大。此外,博士学位的客户比其他教育背景的客户更可能参与营销电话。在 0.1
显著性水平下,我们可以看到 Income
、Number.of.Policies
和 EducationMaster
现在与输出变量 Engaged
存在显著关系。从这个回归分析输出中,我们可以轻松看到输入变量和输出变量之间的关系,并理解哪些客户属性与客户对营销电话的互动正相关或负相关。
R 练习的完整代码可以在这个仓库中找到:github.com/yoonhwang/hands-on-data-science-for-marketing/blob/master/ch.3/R/RegressionAnalysis.R
。
总结
本章中,我们讨论了如何使用解释性分析来洞察客户行为。我们探讨了回归分析如何用于深入理解客户行为。更具体地,你学习了如何使用逻辑回归来理解哪些客户属性会推动更高的互动率。在 Python 和 R 的练习中,我们运用了在第二章《关键绩效指标与可视化》中讨论的描述性分析方法,并结合回归分析进行解释性分析。我们从分析数据开始,以便更好地理解和识别数据中的明显模式。在分析数据时,你还学习了通过箱线图(box plot)来可视化数据,使用 Python 中的matplotlib
和pandas
包,以及 R 中的ggplot2
库。
在拟合回归模型时,我们讨论了两种不同类型的变量:连续变量和分类变量。你学习了在拟合逻辑回归模型时,处理分类变量所面临的挑战,以及如何处理这些变量。对于 Python,我们介绍了处理分类变量的两种方法:factorize
和Categorical
函数,均来自pandas
包。对于 R,我们讨论了如何在拟合逻辑回归模型时使用factor
函数处理分类变量。通过回归分析结果,我们展示了如何通过查看系数和p-值来解释结果和输入输出变量之间的关系。通过查看回归分析输出,我们可以了解哪些客户属性与客户营销互动之间存在显著关系。
在下一章,我们将扩展你对解释性分析的知识。我们将分析客户互动后,哪些因素推动了转化。你还将学习另一种机器学习算法——决策树,以及如何将其应用于解释性分析。
第四章:从参与到转化
在本章中,我们将扩展你对说明性分析的知识,并向你展示如何使用决策树来理解消费者行为的驱动因素。我们将从比较和解释逻辑回归和决策树模型之间的区别开始,然后我们将讨论决策树是如何构建和训练的。接下来,我们将讨论如何使用训练好的决策树模型来提取有关单个消费者属性(或特征)与目标输出变量之间关系的信息。
在编程练习中,我们将使用 UCI 机器学习库中的银行营销数据集来理解转化的驱动因素。我们将从数据分析开始,以便你更好地理解数据集;然后,我们将使用 Python 中的scikit-learn
包和 R 中的rpart
包构建决策树模型。最后,你将学会如何通过 Python 中的graphviz
包和 R 中的rattle
包来可视化这些训练过的决策树模型,从而理解它们的解读方式。到本章结束时,你将熟悉决策树,并且更好地理解何时以及如何使用 Python 或 R 来应用它们。
在本章中,我们将讨论以下主题:
-
决策树
-
决策树与 Python 的解释
-
决策树与 R 的解释
决策树
在上一章中,我们讨论了说明性分析和回归分析。我们将继续这个主题,并介绍另一个机器学习算法,利用它可以从数据中提取客户行为的洞察。在本章中,我们将讨论一种机器学习算法——决策树:它是如何从数据中学习的,以及我们如何解读它们的结果。
逻辑回归与决策树的对比
如果你还记得上一章的内容,逻辑回归模型通过找到特征变量的线性组合来学习数据,从而最好地估计事件发生的对数几率。顾名思义,决策树通过生长一棵树来学习数据。我们将在接下来的章节中详细讨论决策树模型是如何生长的以及如何构建树,但逻辑回归和决策树模型之间的主要区别在于:逻辑回归算法在特征集中搜索一个最佳的线性边界,而决策树算法则通过划分数据来找到发生事件可能性较高的数据子群体。通过一个例子来解释会更容易。让我们来看一下以下图示:
这是一个决策树模型的示例。如你在这个图中所见,它通过某些标准来划分数据。在这个例子中,根节点通过 previous < 0.5
这个标准划分成子节点。如果这个条件成立且为真,那么它会遍历到左子节点。如果不成立,它则遍历到右子节点。左子节点随后通过 age < 61
这个标准进一步划分。树会一直生长,直到找到纯净的节点(即每个节点中的所有数据点都属于同一类)或满足某些停止标准,例如树的最大深度。
如你所见,在这个例子中,数据被划分为七个分区。最左边的节点或分区是针对那些 previous
变量值小于 0.5
且 age
变量值小于 61
的数据点。另一方面,最右边的节点位于底部,针对的是那些 previous
变量值大于 0.5
且 housing
变量值不是 yes
的数据点。
这里需要注意的一点是,不同变量之间有很多交互作用。在这个示例树中,没有任何一个叶节点是通过一个条件来划分的。树中的每个分区都是通过多个标准以及不同feature
变量之间的交互作用来形成的。这与逻辑回归模型的主要区别在于,逻辑回归模型在数据中没有线性结构时,表现会很差,因为它们试图在特征变量之间找到线性组合。另一方面,决策树模型对于非线性数据集表现更好,因为它们仅仅是尝试在最纯净的水平上划分数据。
构建决策树
在构建决策树时,树需要提出逻辑来将一个节点划分为子节点。通常用于数据划分的两种主要方法是:Gini 不纯度和熵信息增益。简而言之,Gini 不纯度度量一个分区的不纯度,而熵信息增益度量的是根据所测试的标准划分数据后,所获得的信息量。
让我们快速看一下计算 Gini 不纯度度量的公式:
这里,c 代表类标签,P[i] 代表记录被选择时属于类标签 i 的概率。通过从 1 中减去概率的平方和,Gini 不纯度度量达到零,即当树的每个分区或节点中的所有记录都是纯净的,且只有一个目标类时。
计算 熵 的公式如下:
和之前一样,c代表类标签,P[i]代表记录具有类标签i被选择的概率。构建树时,需要计算每个可能分割的熵,并与分割前的熵进行比较。然后,选择熵度量变化最大或信息增益最高的分割来继续构建树。这个过程将重复,直到所有节点都是纯净的,或满足停止标准。
使用 Python 进行决策树构建与解释
在本节中,你将学习如何使用 Python 的scikit-learn
包构建决策树模型,并通过 Python 的graphviz
包进行可视化解释结果。对于那些希望使用 R 而非 Python 进行此练习的读者,你可以跳过到下一节。我们将从分析银行营销数据集开始,使用pandas
和matplotlib
包进行深入分析,随后讨论如何构建和解释决策树模型。
对于这个练习,我们将使用 UCI 机器学习库中的一个公开数据集,地址为archive.ics.uci.edu/ml/datasets/bank+marketing
。你可以通过链接下载 ZIP 格式的数据。我们将使用bank.zip
文件进行本次练习。当你解压缩该文件时,你会看到两个 CSV 文件:bank.csv
和bank-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 中显示图表。接下来,我们导入了用于数据分析步骤的matplotlib
和pandas
包。最后,我们可以通过使用pandas
包中的read_csv
函数轻松读取数据文件。这里需要注意的是read_csv
函数中的sep
参数。如果仔细查看数据,你会发现bank-full.csv
文件中的字段是由分号(;
)分隔的,而不是逗号(,
)。为了正确地将数据加载到pandas
数据框中,我们需要告诉read_csv
函数使用分号作为分隔符,而不是逗号。
一旦加载了数据,它应该看起来像下图所示:
数据分析与可视化
在我们开始分析数据之前,我们将首先对输出变量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
表示那些没有订阅的客户。然后,我们计算每个组别中的客户数量,并将其除以数据集中客户的总数。结果如下所示:
为了更容易查看,你可以通过使用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
列进行求和,从中得到每个工作类别的转化总数。最后,我们将这些转化数除以每个工作类别的客户总数,从而得到每个工作类别的转化率。
结果如下所示:
从这些结果中你可以看到,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
参数的输入,定义了图表的类型为水平条形图。你可以轻松调整图表的颜色、大小和标题,分别使用color
、figsize
和title
参数。你还可以通过set_xlabel
和set_ylabel
函数轻松更改x轴和y轴的标签。
生成的图表如下所示:
如你所见,使用水平条形图可以更容易地看到不同工作类别之间的转化率差异。我们可以清楚地看到,student
和retired
组是转化率最高的两个组,而blue-collar
和entrepreneur
组则是转化率最低的两个组。
按转换情况划分的违约率
另一个值得关注的客户属性是违约率,看看订阅定期存款的客户与未订阅的客户之间的违约率差异。我们将使用pandas
库中的pivot_table
函数来分析按转换情况划分的违约率。让我们来看一下下面的代码:
default_by_conversion_df = pd.pivot_table(
df,
values='y',
index='default',
columns='conversion',
aggfunc=len
)
如你所见,这段代码中,我们通过y
和default
列对数据框df
进行透视。通过使用len
作为聚合函数,我们可以计算每个透视表单元格下的客户数量。结果如下所示:
仅凭这些原始数据,很难比较转换组和非转换组之间的违约率差异。通过饼图来可视化这些数据是一种可行的方式。你可以使用以下代码来生成饼图:
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
参数。生成的饼图如下所示:
从这些饼图中可以看出,比较转换组和非转换组的违约率要容易得多。尽管两组的总体违约率都较低,但非转换组的违约率大约是转换组的两倍。
按转换情况划分的银行余额
接下来,我们将尝试查看转换组和非转换组之间银行余额分布是否存在差异。箱型图通常是可视化变量分布的好方法。让我们来看一下下面的代码:
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
函数,我们可以轻松构建如下的箱型图:
由于存在许多异常值,很难发现两个分布之间的差异。让我们构建一个不包含异常值的箱型图。你需要做的唯一更改就是在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()
使用这段代码,你将看到如下的两个组别银行余额分布箱型图:
从这些箱型图中,我们可以看到,相比非转换组,转换组的银行余额中位数略高。此外,转换客户的银行余额波动似乎比非转换客户更大。
按联系次数划分的转换率
最后,我们将看看转化率如何随联系方式的数量变化。通常在营销中,更多的营销接触可能会导致营销疲劳,即随着您更频繁地联系客户,转化率下降。让我们看看我们的数据中是否存在营销疲劳。请查看以下代码:
conversions_by_num_contacts = df.groupby(
by='campaign'
)['conversion'].sum() / df.groupby(
by='campaign'
)['conversion'].count() * 100.0
在这段代码中,您可以看到我们是通过campaign
列(该列包含了此客户在营销活动中进行的联系方式数量的信息)进行分组,并计算每个联系方式数量的转化率。结果数据如下所示:
和之前一样,查看图表比直接查看原始数据更容易。我们可以使用以下代码通过柱状图绘制这些数据:
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()
图表如下所示:
在联系方式数量较高的情况下会有一些噪声,因为这些样本的数量较少,但从这张柱状图中您可以很容易看到整体的下降趋势。随着联系方式数量的增加,转化率缓慢下降。这表明,在给定的营销活动中,随着您与客户的联系更频繁,预期的转化率会下降。
编码类别变量
该数据集包含八个类别变量:job
、marital
、education
、default
、housing
、loan
、contact
和month
。在我们开始构建决策树之前,需要将这些类别变量编码为数值。在本节中,我们将展示如何编码一些类别变量。
编码月份
我们都知道,month
变量只能有 12 个唯一值。让我们快速看看数据集中有哪些值。查看以下代码:
df['month'].unique()
pandas
函数unique
帮助您快速获取给定列中的唯一值。运行此代码后,您将看到以下输出:
如预期的那样,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
列的唯一值如下所示:
为了查看每个月的记录数,我们可以使用以下代码:
df.groupby('month').count()['conversion']
结果如下所示:
编码作业
接下来,让我们看看如何编码job
列中的不同类别。我们首先使用以下代码查看该列中的唯一值:
df['job'].unique()
job
列中的唯一值如下所示:
从这个输出中可以看出,该变量没有自然的顺序。一个 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_
前缀来重命名列。结果如下所示:
从这张截图中可以看出,第一条记录(或客户)属于 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 如下所示:
如您所见,新创建的虚拟变量被添加到原始 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]
编码结果如下:
如您所见,为原始变量 marital
创建了三个新变量:marital_divorced
、marital_married
和 marital_single
,分别表示客户是否离婚、已婚或单身。为了将这些新创建的虚拟变量添加到原始 DataFrame 中,我们可以使用以下代码:
df = pd.concat([df, marital_encoded_df], axis=1)
到此为止,您的原始 DataFrame df
应该包含所有原始列,以及为 job
和 marital
列新创建的虚拟变量。
对住房和贷款变量进行编码
本节我们将要编码的最后两个分类变量是housing
和loan
。housing
变量有两个独特的值,'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
,用于housing
和loan
两个变量。对于本节未讨论的其他分类变量,如果你希望深入探索,可以使用我们讨论过的相同技术来对其进行编码。
构建决策树
现在我们已经编码了所有分类变量,终于可以开始构建决策树模型了。我们将使用以下变量作为决策树模型的特征:
为了使用 Python 构建和训练一个决策树模型,我们将使用scikit-learn
(sklearn
)包中的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
函数接受两个参数:predictor
或feature
变量和response
或target
变量。在我们的例子中,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
传递给graphviz
的Source
类。graph
变量现在包含了一个可渲染的图。根节点及其直接子节点如下所示:
左半部分的树(或根节点左子节点的子节点)如下所示:
右半部分的树(或根节点右子节点的子节点)如下所示:
让我们仔细看看这个图。每个节点包含五行信息,描述了该节点的相关信息。第一行告诉我们分裂的标准。例如,根节点是基于previous
变量的值进行分裂的。如果previous
变量的值小于或等于0.5
,则它会进入左子节点。另一方面,如果previous
变量的值大于0.5
,则它会进入右子节点。
第二行告诉我们分裂的质量度量值。在这里,我们选择了gini
不纯度作为标准,因此我们可以在第二行中看到每个节点中不纯度度量值的变化。第三行告诉我们属于该节点的记录总数。例如,根节点中有45,211
个样本,根节点的右子节点中有8,257
个样本。
每个节点的第四行告诉我们两个不同类别中的记录组成。第一个元素表示非转化组中的记录数,第二个元素表示转化组中的记录数。例如,在根节点中,非转化组有39,922
条记录,转化组有5,289
条记录。最后,每个节点的第五行告诉我们该节点的预测或分类结果是什么。例如,如果一个样本属于最左侧的叶节点,那么该决策树模型的分类结果将是0
,即非转化。另一方面,如果一个样本属于从左数第八个叶节点,那么该决策树模型的分类结果将是1
,即转化。
现在我们知道了每个节点中的每一行意味着什么,让我们来讨论如何从这棵树图中提取洞见。为了理解属于每个叶节点的客户,我们需要沿着树走一遍。例如,那些属于从左数第八个叶节点的客户是previous
变量值为0
,age
大于60.5
,marital_divorced
变量值为1
,以及job_self-employed
变量值为1
的客户。换句话说,之前未曾联系过、年龄大于60.5
、已离婚并且是自雇人士的客户属于这个节点,并且他们有较高的转化几率。
让我们来看另一个例子。那些属于从右数第二个叶节点的客户是previous
变量值为1
、housing
变量值为1
、age
大于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 示例。我们将通过使用dplyr
和ggplot2
库深入分析银行营销数据集来开始本节,然后我们将讨论如何构建和解释决策树模型。
对于这个练习,我们将使用来自 UCI 机器学习库的一个公开数据集,您可以在archive.ics.uci.edu/ml/datasets/bank+marketing
找到。您可以访问该链接并下载 ZIP 格式的数据。我们将使用bank.zip
文件进行此练习。当您解压这个文件时,您会看到两个 CSV 文件:bank.csv
和bank-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
函数使用分号作为分隔符,而不是逗号。
一旦您加载了这些数据,它应该看起来像以下截图:
数据分析和可视化
在开始分析数据之前,我们将首先对输出变量y
进行编码,该变量包含关于客户是否已转换或订阅定期存款的信息,并用数值表示。您可以使用以下代码将输出变量y
编码为零和一:
# Encode conversions as 0s and 1s
df$conversion <- as.integer(df$y) - 1
正如您从这段代码中看到的,您可以使用as.integer
函数对输出变量进行编码。由于该函数会将y
变量中的no
值编码为1
,而y
变量中的yes
值编码为2
,我们通过减去1
来将其编码为0
和1
,分别存储这些编码值到一个新列中,名为conversion
。
转化率
我们将首先关注的是汇总的转化率。转化率简单地是那些订阅了定期存款的客户的百分比,或者那些在conversion
列中被编码为1
的客户。请查看以下代码:
sprintf("conversion rate: %0.2f%%", sum(df$conversion)/nrow(df)*100.0)
正如您从这段代码中看到的,我们只是将conversion
列中的所有值相加,并除以 DataFrame df
中的记录或客户的数量。使用sprintf
函数,我们将此转化率数字格式化为两位小数。结果如下:
从这个输出中可以看到,只有约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
,以计算每个职业类别的转化率。
结果如下所示:
从这些结果可以看出,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))
如果你查看这段代码,我们使用了ggplot
和geom_bar
函数,利用conversionsByJob
数据(我们在之前的代码中构建的)生成条形图,并将Job
变量放在X轴,将ConversionRate
变量放在Y轴。然后,我们使用coord_flip
函数将垂直条形图转换为水平条形图。你可以使用ggtitle
、xlab
和ylab
函数来更改标题、X轴标签和Y轴标签。
结果图表如下所示:
正如你所看到的,使用水平条形图更容易观察到不同职业类别之间的转化率差异。我们可以清晰地看到,student
和retired
组是转化率最高的两个组,而blue-collar
和entrepreneur
组则是转化率最低的两个组。
按转化率分类的违约率
另一个值得关注的客户属性是违约率,以及已订阅定期存款和未订阅定期存款的客户之间的差异。让我们看一下以下的 R 代码:
defaultByConversion <- df %>%
group_by(Default=default, Conversion=conversion) %>%
summarise(Count=n())
从这段代码中可以看到,我们使用 group_by
函数将 DataFrame df
按 default
和 conversion
两列进行分组。通过使用 n()
作为聚合函数,我们可以统计每个四个情况中的客户数量。让我们来看一下以下结果:
从这些原始数据来看,比较转化组和非转化组之间的默认率差异有点困难。可视化这个数据的一种方法是通过饼图。你可以使用以下代码来构建饼图:
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'
)
如你所见,我们在这里使用了三个函数:ggplot
、geom_bar
和 coord_polar("y")
。通过使用 coord_polar("y")
函数,我们可以从条形图生成饼图。然后,我们可以使用 facet_wrap
函数将其拆分成两个饼图:一个是转化组,另一个是非转化组。
看看下面的饼图:
从这些饼图中,你可以更容易地比较转化组和非转化组之间的默认率。尽管两个组中以往的默认比例都较低,但非转化组的默认率大约是转化组的两倍。
按转化次数划分的银行余额
接下来,我们将尝试查看转化组和非转化组之间的银行余额分布是否存在差异。箱线图通常是一种很好的可视化变量分布的方式。我们来看一下下面的代码:
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))
你现在应该已经熟悉这段代码了,因为我们在上一章讨论过如何使用 ggplot
和 geom_boxplot
函数构建箱线图。当你运行这段代码时,你将看到以下箱线图:
由于有很多异常值,识别两组分布之间的差异变得相当困难。让我们构建另一个没有异常值的箱线图。你只需要修改上一段代码中的 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))
使用这段代码,你将看到以下关于两组银行余额分布的箱线图:
从这些箱线图中,我们可以看到转化组的银行余额中位数略高于非转化组。此外,转化客户的银行余额似乎比非转化客户的余额波动更大。
按联系人数量划分的转化率
最后,我们将查看转化率如何随着联系人数的变化而变化。通常在营销中,较高的营销联系人数可能导致营销疲劳,即当你更频繁地联系客户时,转化率会下降。让我们看看我们的数据中是否存在营销疲劳现象。请查看以下代码:
conversionsByNumContacts <- df %>%
group_by(Campaign=campaign) %>%
summarise(Count=n(), NumConversions=sum(conversion)) %>%
mutate(ConversionRate=NumConversions/Count*100.0)
从这段代码中可以看到,我们是通过 campaign
列(该列包含了在该营销活动中对该客户进行的联系次数信息)进行分组,并计算每个联系次数对应的转化率。结果数据如下所示:
和之前一样,查看图表比查看原始数据更为直观。我们可以使用以下代码通过柱状图来绘制这些数据:
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))
绘图结果如下所示:
在较高联系次数的情况下,由于样本量较小,会有一些噪声,但从这张柱状图中可以明显看到总体的下降趋势。随着联系次数的增加,转化率逐渐下降。这表明,当你在一个营销活动中更频繁地联系客户时,预期的转化率会降低。
对类别变量进行编码
数据集中有八个类别变量:job
、marital
、education
、default
、housing
、loan
、contact
和 month
。在构建决策树之前,我们需要将其中一些类别变量编码为数值。我们将在本节中看看如何对这些类别变量进行编码。
对月份进行编码
我们都知道,month
变量最多只能有 12 个唯一值。让我们快速查看一下数据集中的内容。请查看以下代码:
unique(df$month)
unique
函数帮助你快速获取给定列中的唯一值。当你运行这段代码时,你将获得以下输出:
正如我们所预期的,month
列中有 12 个唯一值,从一月到十二月。由于 month
的值有自然顺序,我们可以用对应的数字对每个值进行编码。将 month
的字符串值编码为数字的一种方式如下:
months = lapply(month.abb, function(x) tolower(x))
df$month <- match(df$month, months)
让我们仔细看看这段代码。month.abb
是一个内置的 R 常量,包含了月份名称的三字母缩写,具体如下:
如你所见,每个缩写的month
名称的首字母都被大写。然而,我们数据中的month
列的月份名称都是小写的。这就是为什么我们使用tolower
函数将month.abb
常量中的所有值转换为小写。使用lapply
函数,我们可以将这个tolower
函数应用于month.abb
列表。接着,我们使用match
函数,它返回匹配字符串在数组中的位置,将 DataFrame 中month
列的字符串值转换为对应的数值。
使用这段代码,month
列的唯一值如下所示:
为了查看每个月份的记录数量,我们可以使用以下代码:
df %>%
group_by(month) %>%
summarise(Count=n())
结果如下:
对工作、住房和婚姻变量进行编码
接下来,我们将编码三个变量:job
、housing
和marital
。由于这些变量没有自然的顺序,我们不需要担心哪个类别被编码为哪个值。编码没有顺序的类别变量在 R 中的最简单方法是使用factor
函数。让我们看一下以下代码:
df$job <- factor(df$job)
df$housing <- factor(df$housing)
df$marital <- factor(df$marital)
如你所见,我们只是将factor
函数应用于这三个变量:job
、housing
和marital
,并将编码后的值存储回 DataFrame df
中。对于我们在本节中未讨论的类别变量,如果你希望进一步探索,可以使用我们在本节中讨论的相同技术对它们进行编码。
构建决策树
现在我们已经编码了所有类别变量,终于可以开始构建决策树模型了。我们将使用这些变量作为决策树模型的特征:age
、balance
、campaign
、previous
、housing
、job
和marital
。为了使用 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
的库:
- 您可以通过在 RStudio 中使用以下命令来安装此包:
install.packages("rattle")
- 一旦正确安装了此库,您应该能够按照以下方式导入该库:
library(rattle)
- 一旦您在 R 环境中设置了这个新的库
rattle
,只需一行代码就能可视化训练好的决策树。请查看以下代码:
fancyRpartPlot(fit)
- 如您所见,
fancyRpartPlot
函数接受一个rpart
模型对象。在这里,模型对象fit
是我们在前一步构建的决策树模型。一旦您运行这个命令,它将显示以下图表:
让我们更仔细地看一下这个树形图。每个节点包含三行信息,描述了该节点所具有的信息。节点顶部的数字是标签,表示该节点构建的顺序。我们将使用这个标签来引用树图中的每个节点。然后,每个节点的顶行告诉我们该节点的预测或分类结果。例如,如果一个样本属于标签为 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
变量的值为0
,age
大于或等于61
,marital
状态不是married
或single
,并且job
属于以下类别之一:admin
、blue-collar
、entrepreneur
、housemaid
、retired
或unknown
。换句话说,那些在此活动之前未被联系过、年龄超过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 中的pandas
和matplotlib
包,以及 R 中的dplyr
和ggplot2
库。接着,你学习了如何使用 Python 中的sklearn
包和 R 中的rpart
库来训练和生长决策树。通过这些训练好的决策树模型,你还学习了如何可视化和解释结果。为了进行可视化,我们使用了 Python 中的graphviz
包和 R 中的rattle
库。此外,你还看到如何通过遍历训练过的决策树来解释决策树结果,理解哪些客户群体更可能转化或订阅定期存款,这在我们进行客户行为的解释性分析时非常有用。
在接下来的几章中,我们将改变方向,专注于产品分析。在下一章中,我们将讨论可以进行的探索性分析,以理解和识别产品数据中的模式和趋势。基于下一章的产品分析结果,我们将展示如何构建产品推荐模型。