R 和 Python 行为数据分析(一)
原文:
zh.annas-archive.org/md5/350d206394c314ed5702cafaf048e5be译者:飞龙
前言
统计学是一个用途惊人但实际有效的从业者很少的学科。
Bradley Efron 和 R. J. Tibshirani,《自举法入门》(1993 年)
欢迎来到用 R 和 Python 进行行为数据分析!我们生活在数据时代已成陈词滥调。工程师现在常常利用机器和涡轮机上的传感器数据来预测它们的故障时间并进行预防性维护。同样地,营销人员利用大量数据,从你的人口统计信息到过去的购买记录,来确定何时向你展示哪些广告。正如一句俗语所言,“数据是新石油”,而算法是推动我们经济前进的新型燃烧引擎。
大多数关于分析、机器学习和数据科学的书籍都暗示工程师和营销人员试图解决的问题可以用相同的方法和工具处理。当然,变量有不同的名称,并且需要一些特定领域的知识,但是 k 均值聚类就是 k 均值聚类,无论是在涡轮机数据还是社交媒体帖子数据上。通过这种方式全盘采纳机器学习工具,企业通常能够准确预测行为,但却失去了对实际情况更深入和丰富的理解。这导致了数据科学模型被批评为“黑匣子”的现象。
本书不是追求准确但不透明的预测,而是努力回答这样一个问题:“是什么驱动了行为?”如果我们决定给潜在客户发送电子邮件,他们会因为电子邮件而订阅我们的服务吗?哪些客户群体应该收到电子邮件?年长客户是否因为年龄较大而倾向于购买不同的产品?客户体验对忠诚度和保留率的影响是什么?通过改变我们的视角,从预测行为转向解释行为并测量其原因,我们将能够打破“相关不等于因果”的诅咒,这一诅咒阻碍了几代分析师对他们模型结果的自信。
这种转变不会因引入新的分析工具而来:我们将只使用两种数据分析工具:传统的线性回归及其逻辑回归衍生物。这两种模型本质上更易读取,尽管通常以较低的预测准确度为代价(即在预测中产生更多且更大的误差),但对于我们在这里测量变量之间关系的目的来说并不重要。
相反,我们将花费大量时间学习如何理解数据。在我的数据科学面试官角色中,我见过许多候选人可以使用复杂的机器学习算法,但对数据的实际理解却不深:除了算法告诉他们的内容,他们对数据的运作几乎没有直观的感觉。
我相信你可以培养出这种直觉,并在这个过程中通过采用以下方法极大地增加你的分析项目的价值和成果:
-
一种行为科学的思维方式,将数据视为了解人类心理和行为的一种视角,而非终点。
-
一套因果分析工具包,让我们能够自信地说一件事情导致另一件事情,并确定这种关系有多强。
虽然这些方法各自都能带来巨大的收益,但我认为它们是天然的互补,最好一起使用。鉴于“使用因果分析工具包的行为科学思维方式”有点啰嗦,我将其称为因果行为方法或框架。这个框架有一个额外的好处:它同样适用于实验数据和历史数据,同时利用它们之间的差异。这与传统的分析方法形成对比,传统方法使用完全不同的工具处理它们(例如,实验数据使用 ANOVA 和 T 检验);数据科学则不会区别对待实验数据和历史数据。
本书适合人群
如果你在使用 R 或 Python 分析业务数据,那么这本书适合你。我用“业务”这个词比较宽泛,指的是任何以正确的洞察力和可操作的结论推动行动为重点的盈利、非盈利或政府组织。
在数学和统计背景方面,无论你是业务分析师制定月度预测,还是 UX 研究员研究点击行为,或者是数据科学家构建机器学习模型,都无关紧要。这本书有一个基本要求:你需要至少对线性回归和逻辑回归有些许了解。如果你理解回归,你就能跟上本书的论点,并从中获得巨大的收益。另一方面,我相信,即使是具有统计学或计算机科学博士学位的专家数据科学家,如果他们不是行为或因果分析的专家,也会发现这些材料是新的和有用的。
在编程背景方面,你需要能够阅读和编写 R 或 Python 代码,最好两者都会。我不会教你如何定义函数或如何操作数据结构,比如数据框或 pandas。已经有很多优秀的书在做这方面的工作,比我做得更好(例如,Python 数据分析 作者 Wes McKinney(O'Reilly)和 R 数据科学 作者 Garrett Grolemund 和 Hadley Wickham(O'Reilly))。如果你读过这些书,参加过入门课程,或者在工作中至少使用过其中一种语言,那么你就有能力学习这里的内容。同样地,我通常不会展示和讨论书中用于创建众多图表的代码,尽管它将出现在书的 GitHub 中。
本书不适合人群
如果你在学术界或需要遵循学术规范(例如,制药试验)的领域,这本书可能仍然对你有兴趣,但我描述的方法可能会让你与你的导师/编辑/经理产生冲突。
本书不概述传统行为数据分析方法,比如 T 检验或方差分析(ANOVA)。我还没有遇到过回归比这些方法在回答业务问题上更有效的情况,这就是为什么我故意将本书限制在线性和逻辑回归上的原因。如果你想学习其他方法,你需要去别处寻找(例如,使用 Scikit-Learn、Keras 和 TensorFlow 进行机器学习实践(O'Reilly)由 Aurélien Géron 撰写的机器学习算法)。
在应用设置中理解和改变行为需要数据分析和定性技能两者。本书主要集中在前者,主要出于空间考虑。此外,已经有许多优秀的书籍涵盖了后者,比如理查德·塞勒斯坦(Richard Thaler)和卡斯·桑斯坦(Cass Sunstein)的《推动:改善有关健康、财富和幸福的决策》(Penguin)以及斯蒂芬·温德尔(Stephen Wendel)的为行为变革设计:应用心理学和行为经济学(O'Reilly)。尽管如此,我将介绍行为科学的概念,以便你即使对这个领域还不熟悉,也能应用本书中的工具。
最后,如果你完全是新手对 R 或 Python 的数据分析,这本书不适合你。我建议你从一些优秀的介绍书籍开始,比如本节中提到的一些书籍。
R 和 Python 代码
为什么要用 R 和 Python?为什么不用两者中更优秀的那个?“R 与 Python”的辩论在互联网上仍然存在,并且如我所知,大多数时候这种争论是无关紧要的。事实是,你将不得不使用你的组织中使用的任何一种语言。我曾在一家医疗公司工作过,由于历史和法规的原因,SAS 是主导语言。我经常使用 R 和 Python 进行自己的分析,但由于无法避免处理遗留的 SAS 代码,我在那里的第一个月就学会了我需要的 SAS 的基础知识。除非你的整个职业生涯都在一家不使用 R 或 Python 的公司,否则你最终可能会掌握这两者的基础知识,所以你最好接受双语能力。我还没有遇到过任何人说“学习阅读[另一种语言]的代码是浪费时间”。
假设你很幸运地在一个同时使用这两种语言的组织中工作,你应该选择哪种语言呢?我认为这实际取决于你的环境和你需要做的任务。例如,我个人更喜欢用 R 进行探索性数据分析(EDA),但我发现 Python 在网页抓取方面更容易使用。我建议根据你工作的具体情况选择,并依赖最新的信息:两种语言都在不断改进,过去某个版本的 R 或 Python 可能不适用于当前版本。例如,Python 正在成为比以前更友好的 EDA 环境。你的精力最好花在学习这两种语言上,而不是在论坛上寻找哪种更好。
代码环境
在每章的开头,我将指出需要专门加载的 R 和 Python 包。此外,整本书我还会使用一些标准包;为避免重复,它们只在这里提及(它们已经包含在 GitHub 上所有脚本中)。你应该始终从它们开始编写你的代码,以及一些参数设置:
## R
library(tidyverse)
library(boot) #Required for Bootstrap simulations
library(rstudioapi) #To load data from local folder
library(ggpubr) #To generate multi-plots
# Setting the random seed will ensure reproducibility of random numbers
set.seed(1234)
# I personally find the default scientific number notation (i.e. with
# exponents) less readable in results, so I cancel it
options(scipen=10)
## Python
import pandas as pd
import numpy as np
import statsmodels.formula.api as smf
from statsmodels.formula.api import ols
import matplotlib.pyplot as plt # For graphics
import seaborn as sns # For graphics
代码约定
我在 RStudio 中使用 R。R 4.0 在我写这本书的时候发布了,我已经采用了它,以尽可能保持书籍的更新。
R 代码是用代码字体编写的,并带有指示使用的语言的注释,就像这样:
## R
> x <- 3
> x
[1] 3
我在 Anaconda 的 Spyder 中使用 Python。关于 “Python 2.0 vs. 3.0” 的讨论希望现在已经结束了(至少对于新代码来说;旧代码可能是另一回事),我将使用 Python 3.7。Python 代码的约定与 R 类似:
## Python
In [1]: x = 3
In [2]: x
Out[2]: 3
我们经常会查看回归的输出。这些输出可能非常冗长,并包含了很多本书论点无关的诊断信息。在现实生活中,你不应忽略它们,但这是其他书更好涵盖的问题。因此,我会像这样缩写输出:
## R
> model1 <- lm(icecream_sales ~ temps, data=stand_dat)
> summary(model1)
...
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -4519.055 454.566 -9.941 <2e-16 ***
temps 1145.320 7.826 146.348 <2e-16 ***
...
## Python
model1 = ols("icecream_sales ~ temps", data=stand_data_df)
print(model1.fit().summary())
...
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
Intercept -4519.0554 454.566 -9.941 0.000 -5410.439 -3627.672
temps 1145.3197 7.826 146.348 0.000 1129.973 1160.666
...
函数式编程入门
作为程序员从初学者到中级水平的其中一步,就是停止编写代码的长串指令脚本,而是将代码结构化为函数。在本书中,我们将跨章节编写和重复使用函数,例如以下内容来构建 Bootstrap 置信区间:
## R
boot_CI_fun <- function(dat, metric_fun, B=20, conf.level=0.9){
boot_vec <- sapply(1:B, function(x){
cat("bootstrap iteration ", x, "\n")
metric_fun(slice_sample(dat, n = nrow(dat), replace = TRUE))})
boot_vec <- sort(boot_vec, decreasing = FALSE)
offset = round(B * (1 - conf.level) / 2)
CI <- c(boot_vec[offset], boot_vec[B+1-offset])
return(CI)
}
## Python
def boot_CI_fun(dat_df, metric_fun, B = 20, conf_level = 9/10):
coeff_boot = []
# Calculate coeff of interest for each simulation
for b in range(B):
print("beginning iteration number " + str(b) + "\n")
boot_df = dat_df.groupby("rep_ID").sample(n=1200, replace=True)
coeff = metric_fun(boot_df)
coeff_boot.append(coeff)
# Extract confidence interval
coeff_boot.sort()
offset = round(B * (1 - conf_level) / 2)
CI = [coeff_boot[offset], coeff_boot[-(offset+1)]]
return CI
函数还有一个额外的优势,即限制理解上的溢出:即使你不理解前面的函数如何工作,你仍然可以认为它们返回置信区间并遵循其余推理的逻辑,推迟到以后深入了解它们的代码。
使用代码示例
附加材料(代码示例等)可在 https://oreil.ly/BehavioralDataAnalysis 下载。
如果您有技术问题或在使用代码示例时遇到问题,请发送电子邮件至 bookquestions@oreilly.com。
本书旨在帮助您完成工作。一般来说,如果本书提供了示例代码,您可以在自己的程序和文档中使用它。除非您复制了代码的大部分,否则无需联系我们寻求许可。例如,编写一个使用本书多个代码片段的程序并不需要许可。销售或分发 O'Reilly 书籍中的示例需要许可。引用本书并引用示例代码来回答问题不需要许可。将本书中大量的示例代码整合到您产品的文档中需要许可。
我们感谢但不需要署名。署名通常包括标题、作者、出版商和 ISBN。例如:“R 和 Python 的行为数据分析,作者 Florent Buisson(O’Reilly)。版权 2021 Florent Buisson,978-1-492-06137-3。”
如果您觉得您使用的代码示例超出了合理使用范围或上述许可,请随时通过permissions@oreilly.com联系我们。
导航本书
本书的核心思想是,有效的数据分析依赖于数据、推理和模型之间的不断交流。
-
真实世界中的实际行为及相关的心理现象,如意图、思想和情绪
-
因果分析,特别是因果图
-
数据
本书分为五个部分:
第一部分,理解行为
本部分通过因果行为框架和行为、因果推理和数据之间的联系来铺设舞台。
第二部分,因果图与去混淆
这部分介绍了混淆概念,并解释了因果图如何帮助我们解决数据分析中的混淆问题。
第三部分,鲁棒数据分析
在这里,我们探讨了处理缺失数据的工具,并介绍了 Bootstrap 模拟,因为在本书的其余部分中我们将广泛依赖 Bootstrap 置信区间。小型、不完整或形状不规则的数据(例如具有多个高峰或异常值的数据)并非新问题,但在行为数据中可能尤为突出。
第四部分,设计和分析实验
在这一部分,我们将讨论如何设计和分析实验。
第五部分,行为数据分析的高级工具
最后,我们综合一切来探讨中介效应、调节效应和工具变量。
本书的各个部分在一定程度上相互依赖,因此我建议至少在第一遍阅读时按顺序阅读它们。
本书使用的惯例
本书中使用以下排版惯例:
斜体
表示新术语、URL、电子邮件地址、文件名和文件扩展名。
等宽字体
用于程序清单,以及在段落中引用程序元素,如变量或函数名称,数据库,数据类型,环境变量,语句和关键字。
等宽粗体
显示用户应该按原样键入的命令或其他文本。
等宽斜体
显示应由用户提供值或由上下文确定值的文本。
提示
这个元素表示提示或建议。
注意
这个元素表示一般性说明。
警告
这个元素指示警告或注意事项。
奥莱利在线学习
注意
40 多年来,奥莱利媒体一直提供技术和商业培训,知识和见解,帮助公司取得成功。
我们独特的专家和创新者网络通过书籍、文章和我们的在线学习平台分享他们的知识和专长。奥莱利的在线学习平台让您随需应变地访问直播培训课程、深度学习路径、交互式编码环境,以及奥莱利和其他 200 多家出版商的大量文本和视频内容。更多信息,请访问http://oreilly.com。
如何联系我们
请将有关本书的评论和问题发送至出版商:
-
奥莱利媒体,公司
-
1005 Gravenstein Highway North
-
Sebastopol, CA 95472
-
800-998-9938(美国或加拿大)
-
707-829-0515(国际或本地)
-
707-829-0104(传真)
您可以访问本书的网页,其中列出了勘误表,示例和附加信息,网址为https://oreil.ly/Behavioral_Data_Analysis_with_R_and_Python。
发送电子邮件至bookquestions@oreilly.com以评论或询问关于本书的技术问题。
有关我们的书籍和课程的新闻和信息,请访问http://oreilly.com。
在 Facebook 上找到我们:http://facebook.com/oreilly
在 Twitter 上关注我们:http://twitter.com/oreillymedia
在 YouTube 上观看我们:http://youtube.com/oreillymedia
致谢
作者们经常感谢他们的配偶对他们的耐心,并特别感谢那些有深刻见解的审阅者。我很幸运,这两者都集中在同一个人身上。我想没有其他人敢于或能够如此多次地把我送回绘图板,而这本书因此而大为改进。因此,我首先感谢我的生活和思想伴侣。
我的几位同事和行为科学家朋友慷慨地抽出时间阅读和评论了早期草稿。这本书因此变得更加出色。谢谢(按字母顺序逆序排列)Jean Utke、Jessica Jakubowski、Chinmaya Gupta 和 Phaedra Daipha!
特别感谢 Bethany Winkel 在写作中的帮助。
现在,我对最初的草稿有多么粗糙和令人困惑感到后悔。我的开发编辑和技术审阅人员耐心地推动我一路走到现在这本书的成就,分享他们丰富的视角和专业知识。感谢 Gary O’Brien,感谢 Xuan Yin,Shannon White,Jason Stanley,Matt LeMay 和 Andreas Kaltenbrunner。
第一部分:理解行为
本书的第一部分将解释为什么行为数据分析需要新的方法。
第一章将描述一种新的方法,即因果行为数据分析框架。我们将通过一个具体示例展示,即使是最简单的数据分析也可能因混杂变量的存在而偏离轨道。解决这个问题在传统方法中可能极为复杂,甚至不可能,但新框架提供了一个简单的解决方案。
第二章将进一步探讨行为数据的具体特性,同时为行为科学提供一个初步介绍,并确保我们的数据能够充分反映相应的真实行为。
第一章:数据分析的因果行为框架
正如我们在前言中讨论的那样,理解驱动行为以便改变它们是应用分析的关键目标之一,无论是在商业、非营利组织还是公共组织中。我们想弄清楚为什么有人买了某样东西,为什么另一个人没有买。我们想知道为什么有人续订了他们的订阅,为什么有人选择联系客服而不是在线支付,为什么有人注册成为器官捐赠者,或者为什么有人给予非营利组织捐款。拥有这些知识使我们能够预测人们在不同情境下的行为,并帮助我们确定我们的组织可以采取什么措施来鼓励他们再次这样做(或者不这样做)。我认为通过将数据分析与行为科学思维和因果分析工具包相结合,可以最好地实现这一目标,从而创建一个被我称为“因果行为框架”的集成方法。在这个框架中,行为位于顶部,因为理解它们是我们的最终目标。通过使用因果图和数据来实现这种理解,它们形成了三角形的两个支柱(图 1-1)。
图 1-1. 数据分析的因果行为框架
在本书的过程中,我们将探索三角形的每个支柱,并看到它们如何相互联系。在最后一章中,我们将通过一行代码实现我们所有工作的结合,而传统方法则会面临艰巨的任务:衡量客户满意度提高未来客户支出的程度。除了执行这些非凡的任务外,这种新框架还将使您能够更有效地执行诸如确定电子邮件营销活动或产品特性对购买行为的影响等常见分析。
在深入讨论之前,熟悉预测分析的读者可能会想知道为什么我推崇因果分析而不是预测分析。答案是,尽管预测分析在业务环境中已经(并将继续)非常成功,但在涉及人类行为的分析中,它们可能存在不足。特别是,采用因果方法可以帮助我们识别和解决“混杂”的问题,这在行为数据中非常常见。我将在本书的其余部分详细阐述这些观点。
为什么我们需要因果分析来解释人类行为
理解因果分析在分析领域中的位置将帮助我们更好地识别为何它在业务环境中是必需的。正如我们将看到的那样,这种需求源于人类行为的复杂性。
不同类型的分析
有三种不同类型的分析:描述性、预测性和因果性。描述性分析提供了数据的描述。简单来说,我把它看作是“是什么”或“我们已经测量到了什么”的分析。业务报告属于这一范畴。上个月有多少客户取消了他们的订阅?去年我们赚了多少利润?每当我们在计算平均数或其他简单指标时,我们都在隐含地使用描述性分析。描述性分析是最简单的分析形式,但也往往被人低估。许多组织实际上很难获得对其业务的清晰和统一的视图。要了解组织中这个问题的程度,只需向财务部门和运营部门提出同样的问题,然后衡量答案的差异有多大。
预测性分析提供了一个预测。我把它看作是“如果当前条件持续下去会怎样”或“我们还没有测量到的内容”的分析。大多数机器学习方法(例如,神经网络和梯度提升模型)属于这种类型的分析,并帮助我们回答诸如“下个月有多少客户会取消订阅?”和“那个订单是欺诈的吗?”等问题。在过去的几十年里,预测性分析已经改变了世界;企业雇佣的大量数据科学家就是其成功的证明。
最后,因果分析提供了数据的原因。我把它看作是“如果……会怎样?”或“在不同条件下将会怎样”的分析。它回答了诸如“下个月有多少客户会取消订阅,除非我们给他们发优惠券?”这样的问题。因果分析最著名的工具是 A/B 测试,又称随机实验或随机对照试验(RCT)。这是因为回答上述问题的最简单且最有效的方法是向随机选定的一组客户发送优惠券,然后查看与对照组相比有多少客户取消了订阅。
我们将在书的第四部分中讨论实验,但在此之前,在第二部分中,我们将看一看那个工具箱中的另一个工具,即因果图,它甚至可以在我们无法进行实验时使用。事实上,我一个目标就是让您更广泛地思考因果分析,而不仅仅是把它等同于实验。
注意
虽然这些标签可能给人以整洁分类的印象,但实际上,在这三个类别之间存在更多的渐变,问题和方法在它们之间变得模糊。您还可能遇到其他术语,如规范性分析,它进一步模糊了界限,并添加了其他细微差别,但并没有显著改变整体情况。
人类是复杂的
如果预测性分析如此成功,而因果性分析使用的是与回归分析相同的数据分析工具,为什么不坚持使用预测性分析呢?简而言之,因为人类比风力发电机更复杂。人类行为:
具有多重原因
风力发电机的行为不受其个性,风力发电机社区的社会规范或其成长环境的影响,而任何单一变量对人类行为的预测能力几乎总是令人失望的,因为存在这些因素。
具有上下文相关性
对环境进行微小或表面的改变,比如改变选择的默认选项,可能会对行为产生很大的影响。从行为设计的角度来看,这是一种福祉,因为它使我们能够推动行为的变化,但从行为分析的角度来看,这是一种诅咒,因为这意味着每种情况在难以预测的方面都是独特的。
具有变量性(科学家会说是非确定性的)
同一个人在看似完全相同的情况下反复出现可能会表现出截然不同的行为,即使在控制了表面因素后也是如此。这可能是由于暂时的效应,比如情绪,或者长期效应,比如厌倦每天吃相同早餐。这两者都可以显著改变行为,但很难捕捉到。
具有创新性
当环境条件发生变化时,一个人可以转向一个他们以前从未表现过的行为,而且即使在最平凡的情况下也会发生这种情况。例如,你平时通勤的路上发生了一起车祸,所以你在最后一刻决定右转。
具有战略性
人类推断并对他人的行为和意图做出反应。在某些情况下,这可能意味着通过外部环境改变而被打乱的合作“修复”,使其更加牢固可预测。但在其他情况下,它可能涉及自愿模糊自己的行为,使其在像下棋这样的竞争性游戏中变得不可预测(或者欺诈!)。
人类行为的所有这些方面使其比物理物体的行为更不可预测。为了找到更可靠的分析规律,我们必须深入了解和衡量行为的原因。某人星期一早餐吃燕麦粥并采取了某条路线并不意味着他们星期二会做同样的事情,但您可以更有信心地说他们会有一些早餐,并会采取某条路线去上班。
混淆!让回归分析排除隐患的隐藏危险
我在前一节中提到,因果分析通常使用与预测分析相同的工具。然而,由于它们有不同的目标,这些工具的使用方式也不同。由于回归分析是这两种类型分析的主要工具之一,它可以很好地说明预测分析和因果分析之间的差异。对于预测分析适用的回归分析往往会对因果分析目的来说效果不佳,反之亦然。
预测分析的回归分析用于估计未知值(通常但不总是在未来)。它通过获取已知信息并使用各种因素来三角测量给定变量的最佳猜测值。重要的是预测值及其准确性,而不是预测是如何或为什么进行的。
因果分析也使用回归分析,但重点不在于估计目标变量的值。相反,重点在于该值的原因。从回归分析的角度来看,我们的兴趣不再是依赖变量本身,而是它与给定独立变量的关系。通过正确构建的回归分析,相关系数可以成为研究独立变量对依赖变量因果效应的便携式度量。
但是,对于此目的正确构建的回归分析意味着什么呢?为什么我们不能只是采用我们已经用于预测分析的回归分析,并将提供的系数视为因果关系的度量?我们不能这样做,因为回归分析中的每个变量都有可能修改其他变量的系数。因此,我们的变量组合必须经过精心设计,以不是创建最准确的预测,而是创建最准确的系数。两组变量通常是不同的,因为一个变量可以与我们的目标变量高度相关(因此具有高预测能力),而实际上不影响该变量。
在本节中,我们将探讨为什么这种视角上的差异很重要,以及为什么变量选择在行为分析中至关重要。我们将通过来自美国各地门店的虚构超市连锁企业 C-Mart 的一个具体例子来说明这一点。本书中使用的两家虚构公司之一,C-Mart 将帮助我们理解数字时代实体店公司数据分析的机遇和挑战。
数据
此章节的 GitHub 文件夹 包含两个 CSV 文件,chap1-stand_data.csv 和 chap1-survey_data.csv,分别是本章两个例子的数据集。
Table 1-1 展示了关于 C-Mart 摊位上冰淇淋和冰咖啡销售日常水平的 chap1-stand_data.csv 文件中的信息。
表 1-1. chap1-stand_data.csv 中的销售信息
| 变量名称 | 变量描述 |
|---|---|
| 冰淇淋销售额 | C-Mart 摊位的每日冰淇淋销售额 |
| 冰咖啡销售额 | C-Mart 摊位的日销量 |
| 夏季月份 | 表示日期是否在夏季月份的二进制变量 |
| 温度 | 当天和该摊位的平均温度 |
表 1-2 显示了来自 chap1-survey_data.csv 的路人通过 C-Mart 摊位调查的信息。
表 1-2. 第一章调查数据在 chap1-survey_data.csv 中
| 变量名称 | 变量描述 |
|---|---|
| 香草口味 | 受访者对香草的口味偏好,0-25 |
| 巧克力口味 | 受访者对巧克力的口味偏好,0-25 |
| 购物 | 表示受访者是否曾在当地 C-Mart 摊位购物的二进制变量 |
为什么相关性不是因果关系:混杂因素的作用
C-Mart 在每家店铺都设有冰淇淋摊位。公司认为天气影响每日销量——或者用因果关系的术语来说,天气是销量的原因之一。换句话说,在其他条件不变的情况下,我们假设人们更可能在炎热的天气购买冰淇淋,这在直觉上是有道理的。这种信念得到了历史数据中温度和销量之间强相关性的支持,如图 1-3 所示(相应的数据和代码在本书的 GitHub 上)。
图 1-3. 根据观测温度销售冰淇淋的函数图
如前言所述,我们将使用回归作为主要的数据分析工具。运行冰淇淋销售额对温度的线性回归只需一行代码:
## Python (output not shown)
print(ols("icecream_sales ~ temps", data=stand_data_df).fit().summary())
## R
> summary(lm(icecream_sales ~ temps, data=stand_dat))
...
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -4519.055 454.566 -9.941 <2e-16 ***
temps 1145.320 7.826 146.348 <2e-16 ***
...
对于本书的目的,在输出中最相关的部分是系数部分,它告诉我们估计的截距——理论上的零温度下的平均冰淇淋销售额为−4,519,这显然是一个不合理的外推。它还告诉我们温度的估计系数为 1,145,这意味着每增加一度温度,冰淇淋销售额预计会增加 1,145 美元。
现在,让我们假设我们处于十月一个特别温暖的周末,根据模型的预测,公司提前增加了冰淇淋摊位的库存。然而,尽管这个十月的这个星期销量比平时高,但却远低于模型预测的数量。糟糕!发生了什么?数据分析师应该被解雇吗?
发生的事情是,模型没有考虑到一个关键的事实:大部分冰淇淋的销售发生在夏季,孩子们放暑假的时候。回归模型根据可用的数据做出了最佳预测,但由于增加的冰淇淋销售(学生暑假)部分归因于温度,因为夏季月份与温度呈正相关。由于十月份的温度增加并没有突然导致暑假(对不起,孩子们!),所以我们在那个温度下看到的销售量比夏季日子要少。
从技术角度来看,年月份是我们在温度和销售额之间关系的混杂因素。混杂因素是引入回归中偏差的变量;当混杂因素存在于你分析的情况中时,这意味着将回归系数解释为因果关系将会导致不正确的结论。
让我们想象一下像芝加哥这样的地方,那里有大陆性气候:冬天非常寒冷,夏天非常炎热。当比较一个随机炎热的日子和一个随机寒冷的日子的销售额时,如果没有考虑到它们各自的年月,你很可能在比较放暑假的炎热夏季日子的销售额和放学孩子们的寒冷冬季日子的销售额;这会夸大温度与销售额之间的表面关系。
在这个例子中,我们也许会预期在寒冷天气下销售量一直被低估。事实上,在夏季月份存在一种范式转变,当必须完全通过温度来管理这种转变时,在线性回归中,温度的回归系数对于较高温度来说会过高,而对于较低温度来说则会过低。
太多的变量可能会破坏原来的关系
解决混杂因素问题的一个潜在方法是将尽可能多的变量添加到回归模型中。这种“什么都包括在内”的思维方式在统计学家中仍有支持者。在《因果之书》中,朱迪亚·珀尔和达纳·麦肯齐提到,“一位领先的统计学家最近甚至写道,‘避免对一些观察到的协变量进行条件化...是非科学的特别策略’”(珀尔和麦肯齐,2018 年,第 160 页)^(2)。这在数据科学家中也是非常普遍的。公平地说,如果你的目标只是预测一个变量,并且你有一个经过精心设计以在测试数据之外进行足够泛化的模型,并且你不关心为什么预测变量取特定值,那么这是一个完全有效的立场。但是,如果你的目标是理解因果关系以便采取行动,那么这种方法就不适用了。因此,仅仅是向模型添加尽可能多的变量不仅效率低下,而且可能完全适得其反并且误导性极大。
让我们通过我们的例子来演示这一点,通过添加一个我们可能倾向于包括但会使我们的回归产生偏见的变量。我创建了变量 IcedCoffeeSales,它与 Temperature 相关,但与 SummerMonth 不相关。让我们看看如果我们在 Temperature 和 SummerMonth(一个二进制变量,指示月份是否为 7 月或 8 月(1),或其他任何月份(0))之外添加这个变量会发生什么:
## R (output not shown)
> summary(lm(icecream_sales ~ iced_coffee_sales + temps + summer_months))
## Python
print(ols("icecream_sales ~ temps + summer_months + iced_coffee_sales",
data=stand_data_df).fit().summary())
...
coef std err t P>|t| [0.025 0.975]
----------------------------------------------------------------------------
Intercept 24.5560 308.872 0.080 0.937 -581.127 630.239
temps -1651.3728 1994.826 -0.828 0.408 -5563.136 2260.391
summer_months 1.976e+04 351.717 56.179 0.000 1.91e+04 2.04e+04
iced_coffee_sales 2.6500 1.995 1.328 0.184 -1.262 6.562
...
我们看到 Temperature 的系数从之前的例子中显著偏移,现在变为负值。Temperature 和 IcedCoffeeSales 的高 p 值通常被视为有问题的迹象,但由于 Temperature 的 p 值“更差”,分析师可能会得出应将其从回归中移除的结论。这怎么可能呢?
数据的真相(已知,因为我制造了这些关系并在这些关系周围随机化了数据)是,当天气炎热时,人们更有可能购买冰咖啡。在炎热的日子里,人们也更有可能购买更多冰淇淋。但单单购买冰咖啡本身并不会使顾客更有可能购买冰淇淋。夏季月份与购买冰咖啡也没有相关性,因为学童对冰咖啡需求不是一个重要因素(详见边栏中的数学细节)。
图 1-4 显示了冰咖啡销量与冰淇淋销量之间的正相关性,因为在天气变暖时两者都会增加,但在夏季增加的冰咖啡销量可以通过与温度变量的共同相关性来解释。当回归算法试图使用手头的三个变量解释冰淇淋销量时,温度变量对冰咖啡销量的解释能力被添加到温度变量中,而冰咖啡则被迫弥补温度的压倒性影响。尽管冰咖啡销量在统计上并不显著且系数相对较小,但销售额远高于温度的度数,因此最终冰咖啡销量抵消了温度系数的膨胀。
图 1-4. 冰咖啡销量与冰淇淋销量的绘图
在前面的例子中,将变量 IcedCoffeeSales 添加到回归中使得温度与冰淇淋销量之间的关系变得混乱。不幸的是,反过来也是可能的:在回归中包含错误的变量可能会产生虚假的关系。
继续我们在 C-Mart 的冰淇淋示例,假设类别经理有兴趣了解顾客口味,所以他们让一个员工站在店外,调查路过的人,问他们对香草冰淇淋和巧克力冰淇淋的喜爱程度(都在 0 到 25 的范围内),以及是否曾经购买过摊位上的冰淇淋。为了简化,我们假设该摊位只销售巧克力和香草口味的冰淇淋。
为了例子简单,让我们假设对香草口味和巧克力口味的喜好完全没有相关性。有些人喜欢其中一种但不喜欢另一种,有些人两种都喜欢,有些人一种比另一种更喜欢,等等。但所有这些偏好都会影响某人是否购买冰淇淋,这是一个二元(是/否)变量。
因为变量购物是二元的,所以如果我们想要衡量Taste变量之一对购物行为的影响,我们将使用 logistic 回归。由于这两个Taste变量是不相关的,如果我们将它们相互绘制,我们将看到一个没有明显相关性的常规云;然而,它们各自影响购物在冰淇淋摊的概率(图 1-5)
图 1-5. 左图:整体人群中对香草和巧克力的口味没有相关性;中图:在冰淇淋摊购物的人对香草的口味比不购物的人高;右图:对巧克力的口味结果相同
在第一个图中,我添加了一条最佳拟合线,几乎是平的,反映了变量之间缺乏相关性(相关系数等于 0.004,反映了抽样误差)。在第二和第三个图中,我们可以看到整体上购物者(购物 = 1)对香草和巧克力的口味平均较高,这是合理的。
到目前为止,一切都很好。假设你收到调查数据后,你的商业伙伴告诉你,他们正在考虑为冰淇淋摊引入一个优惠券激励措施:购买冰淇淋时,您可以获得未来访问的优惠券。这种忠诚度激励措施不会影响从未在摊位购物过的受访者,因此相关人群是那些曾在商店购物过的人。商业伙伴正在考虑在优惠券上使用口味限制来平衡库存,但不知道口味选择会受多大影响。如果购买了香草冰淇淋的顾客得到了一张 50%折扣的巧克力冰淇淋优惠券,除了增加废纸回收箱中的纸张外,还能起到什么作用吗?喜欢香草冰淇淋的人又如何看待巧克力冰淇淋呢?
你重新绘制了同样的图表,这次限制数据为那些对购物问题回答“是”的人(图 1-6)。
图 1-6. 购物者对香草和巧克力的口味偏好
现在这两个变量之间有强烈的负相关(相关系数为-0.39)。发生了什么?来到你的摊位的香草爱好者会变成巧克力的讨厌者,反之亦然吗?当然不是。这种相关性是在你限制到顾客时人为创造的。
让我们回到我们真正的因果关系:某人对香草的喜好越强,他们越有可能在你的摊位上购物,巧克力也是如此。这意味着这两个变量有累积效应。如果某人对香草和巧克力冰淇淋的喜好都较弱,他们很少会在你的摊位上购物;换句话说,你的顾客中大多数对香草口味不强的人对巧克力口味非常强烈。另一方面,如果某人对香草口味很强,即使对巧克力口味不是很强,他们也可能会来你的摊位购物。你可以在之前的图表中看到这一点:对于香草的高值(比如超过 15),数据点中巧克力的值较低(低于 15),而对于香草的低值(低于 5),图表中的数据点只有巧克力的值较高(超过 17)。没有人的偏好发生了变化,但是对香草和巧克力口味都不强的人被排除在你的数据集之外。
这种现象的技术术语是伯克森悖论,但朱迪亚·珀尔(Judea Pearl)和丹娜·麦肯齐(Dana Mackenzie)用更直观的名称称之为“解释消除效应”。如果你的某个顾客非常喜欢香草味,这完全解释了他们为何在你的摊位购物,他们不“需要”对巧克力有很强的喜好。另一方面,如果你的某个顾客对香草味不够喜欢,这不能解释他们为何在你的摊位购物,他们必须对巧克力的喜爱高于平均水平。
伯克森悖论一开始是违反直觉且难以理解的。这可能导致数据偏差,这取决于数据的收集方式,甚至在开始任何分析之前就已经存在。一个经典的例子是,在看待医院患者群体与普通人群时,某些疾病表现出更高的相关性。实际上,发生的情况是,只有当两者同时存在时,某种疾病才足以使某人去医院;某人的健康状况只有在两种疾病同时存在时才会变得严重到需要住院。^(3)
结论
预测分析在过去几十年来取得了极大的成功,并且未来也将如此。另一方面,当试图理解和——更重要的是——改变人类行为时,因果分析提供了一个引人注目的替代方案。
然而,与预测分析不同,因果分析要求采用不同的方法。希望本章的例子已经让你相信,不能简单地将一堆变量放入线性回归或逻辑回归中,然后期待最好的结果(我们可能认为这是“把所有变量都包括进去,上帝会认出自己的”方法)。你可能仍然会好奇,其他类型的模型和算法是否对混淆因素、多重共线性和虚假相关性免疫?不幸的是,答案是否定的。如果有什么不同的话,这些模型的“黑匣子”性质意味着混淆因素可能更难以捕捉。
在下一章中,我们将探讨如何思考行为数据本身。
^(1) 公平地说,在许多情况下,它们应该不同,因为数据用于不同的目的并遵循不同的约定。但即使是你期望只有一个真正答案的问题(例如,“我们现在有多少名员工?”),通常也会显示出差异。
^(2) 你可能会想知道,前面提到的统计学家是唐纳德·鲁宾。
^(3) 从技术角度讲,这种情况略有不同,因为存在阈值效应而不是两个线性(或逻辑)关系,但包含错误变量可能导致人为相关性的基本原则仍然适用。
第二章:理解行为数据
在第一章中,我们讨论了本书的核心目标是利用数据分析来了解驱动行为的原因。这需要理解数据和行为之间的关系,这在第一章中通过因果行为框架中的箭头表示(图 2-1)。
图 2-1. 在本章中突出显示箭头的因果行为框架
请原谅这个流行文化的参考,但如果你看过《黑客帝国》,你会想起主角可以看着他周围的世界并看到其背后的数字。嗯,在本章中,你将学会看待你的数据并看到其背后的行为。
第一部分主要面向具有商业或数据分析背景的读者,并提供基本的“行为科学 101”介绍核心行为科学概念。如果你是经过训练的行为科学家,可能在这里找不到什么新东西,但你可能想浏览一下,以了解我使用的具体术语。
基于这种共识,第二部分将向你展示如何通过行为镜头来审视你的数据,并确定与每个变量相关的行为概念。在许多情况下,不幸的是,一开始一个变量与相应的行为只是松散相关的,因此我们还将学习如何“行为化”这样的偏离变量。
人类行为的基本模型
“行为”是一个我们非常熟悉的词,因为反复暴露,但很少,如果有的话,被正确定义。我曾经问过一个商业伙伴她试图鼓励什么行为,她的答案以“我们希望他们知道…”开始。在那一刻,我意识到两件事:(1)通过帮助澄清手头的目标,我可以为该项目增加比我最初预期的更多的价值,以及(2)我之前向她介绍的行为科学简介真的很糟糕,如果她仍然认为知道某事就是一种行为。希望这次我能做得更好,你能够从这一部分中学到增加组织价值的快乐。
实际上,我坚信行为思维的一个关键好处之一是让人们更加准确地思考他们试图做的事情。改变某人的想法并不等同于影响他们的行为,反之亦然。为此,我将提出一个简化但有希望可行的人类行为模型,首先以一个个人护理公司如何利用顾客的中年危机为例进行说明(图 2-2)。
图 2-2. 我们关于中年危机的人类行为模型
在这个例子中,个人特征(进入 40 岁)导致情绪和思想(想要重新感受年轻),进而导致意图(决定购买一辆红色 Corvette)。这种意图可能会转化为相应的行为,也可能导致其他行动(比如染红头发),这取决于商业行为(播放电视广告)。
在某些情况下,我们可能试图影响的不是我们客户的行为,而是我们的员工、供应商等的行为。我们需要相应地调整这个模型,但直觉仍然是相同的:一方面,有一个我们试图影响行为的人类,另一方面,有我们的业务控制的所有过程、规则和决策(参见图 2-3)。
图 2-3. 我们关于人类行为的一般模型
在这个模型中,个人特征影响认知和情绪,进而影响意图,从而影响行为。作为我们控制的过程、规则和决策的商业行为则影响这三类别。
在这里,有许多不同的模型,这其中没有一个是最终或神奇的。但是对于本书讨论的数据分析阶段而言,我觉得这五个组成部分最能对应你将会遇到的数据类型。让我们逐一来看看这些组成部分,回顾每个组成部分的定义,并探讨我们如何能够以道德的方式收集和处理关于每个组成部分的数据。
个人特征
收集和使用诸如年龄、性别和家庭状况等人口统计变量是应用分析的基础,而且理由充分:这些变量通常能很好地预测一个人会做什么。然而,作为行为数据分析师,我们需要更广泛和更精确地思考个人特征。对于我们的目的而言,我们将个人特征定义为所有我们对一个人拥有的信息,这些信息在我们分析的相关时间框架内变化很少或者变化很慢。
回到 C-Mart 冰淇淋摊的例子,这意味着包括诸如个性特征和生活方式习惯之类的因素。假设你的一个顾客具有很高的经验开放性,并且总是愿意尝试一些新的口味组合,比如蓝莓和奶酪;你可以合理地将这种特质视为你分析中的一个稳定个人特征,尽管心理学告诉我们,个性在某人一生中会以可预测的方式发生变化。另一方面,一个展望未来几十年的城市规划师可能不仅要考虑生活方式习惯逐渐变化,还要考虑这些变化方向本身是否在改变。在这个意义上,我把个人特征看作是“主要原因”,定义为避免无限回归:我们追踪它们的变化,但忽略它们自身的原因。
虽然人口统计变量在相对稳定性和首要性方面符合上述定义,但将它们视为认知、情感、意图和行为的原因可能并不立即清晰。有些读者甚至可能不愿意说年龄或性别导致某人做某事,因为这听起来可能像是社会决定论。
我认为我们可以通过在概率意义上将原因定义为“贡献因素”来解决这些问题。到了 40 岁并不是发生中年危机的必要条件,也不是充分理由;而发生中年危机也不是购买红色雪佛兰的必要条件,也不是充分理由。事实上,这两种因果关系与其他贡献因素紧密相连:年龄对存在主义困扰的贡献依赖于职业和家庭轨迹等社会模式(例如,某人进入劳动市场的年龄或者生第一个孩子的年龄,如果他们做了其中的任何一个),而通过消费来解决这些困扰则仅在有足够的可支配收入时才可能。这也取决于一个人受广告影响的程度。
如行为科学的格言所述,“行为是个体和环境的函数”,社会因素往往比人口统计变量更具有影响力。从因果建模和数据分析的角度来看,社会现象与个人特征之间的这种相互作用可以通过调节和中介的方式来捕捉(我们将在第十一章和第十二章进行探讨)。
在这个意义上,人口统计变量在行为数据分析中通常非常有用,因为它们的预测能力暗示了其他更心理和可操作的个人特征(它们是一个贡献因素)。例如,在美国和许多其他国家,执法和护理仍然是明显性别化的领域。注意到这种实证规律不太可能为你赢得任何赞扬。更有趣的问题是这种效应是如何发生的。例如,一个假设是这种效应源于关于权威和关怀的社会表征和规范。或者,也可以假设这种现象是因为缺乏其他角色模型而自我延续的。确定哪种假设是真实的(或者如果两种都是真实的,哪种更有说服力)可能会导致对高中生进行更有效的职业咨询。
收集数据与伦理考虑
人口统计信息在业务分析中广泛可得且被使用(甚至可以说被过度使用)。主要挑战在于识别和衡量其他个人特征,以便正确地分配它们对行为的影响,而不是不适当地归因于人口统计变量。市场和用户研究在这里非常有用。
从伦理角度来看,错误归因的影响也很重要:在许多情况下,歧视可以被视为有意或无意地将行为(当前或预测的)错误归因于人口统计变量。即使你的分析是正确的,你也需要确保它不会无意中加强优势和劣势的模式。
认知与情绪
认知与情绪 是我用来涵盖情绪、思维、心理模型和信念等心理状态的一个术语。你可以把它看作是客户大脑中除了意图和更持久的个人特征之外的所有事物。例如,潜在客户是否知晓您的公司及其产品或服务?如果知晓,他们对此有何看法?他们对银行运作的心理模型是什么?每当他们看到路上一辆光鲜亮丽的特斯拉时,他们是否会感到羡慕?
认知与情绪涵盖了所有这些,以及更模糊的商业术语和短语,如客户满意度(CSAT)和客户体验(CX)。CX 已成为业务的口号:许多公司都设有 CX 团队,并举办与此主题相关的会议、咨询和书籍。但它究竟是什么?你能够衡量它的原因和影响吗?可以,但这需要知识谦逊和愿意花时间进行侦查工作。
收集数据与伦理考虑
认知和情绪在两个方面类似于心理学的个人特征:它们通常不能直接观察,相关数据是通过调查或在用户体验(UX)观察期间收集的。重要的是要注意,除非你使用生理测量,否则你将依赖于 陈述 或 观察到 的测量。
这就带来了用户体验(UX)或人本设计与行为科学之间最大的区别之一:UX 的假设是人类知道他们想要什么,他们对某事感觉如何,以及为什么,而行为科学则从我们对自己头脑中发生的许多事情毫无察觉的假设开始。用一个法律比喻来说,行为科学家经常将某人说的话视为不可信,直到证明是可信的,而 UX 研究人员会将其视为诚实,直到证明是误导的。
但我不想夸大这种区别,实践中这种区别经常变得模糊不清,这取决于手头的情况。如果一位行为科学家被客户告知一个网站使用起来令人困惑和沮丧,他们将借鉴 UX 的做法,并相信客户确实体验到了负面情绪。相反,当进行基础产品研究时,一位技术娴熟的 UX 研究员通常会超越表达的意图,试图识别客户更深层次的需求。
从道德的角度来看,试图改变某人的认知和情绪显然是一个灰色地带。在这方面,我推荐的试金石是“NYT”测试:你的意图和方法是否善良且透明,以至于你的老板的老板看到它们出现在 纽约时报 的头版时不会介意?广告努力影响人们的想法和情绪,但我不指望会看到一个标题写着“公司花费数十亿让人们想要他们的东西”;无论如何都会引起大家的打哈欠。另一方面,“滑坡”——诸如“现在有三个人正在看这个房产!”之类的操纵性行为科学把戏——和老式的谎言是过不了这个测试的。这仍然留下了许多诚实的机会来应用行为科学:例如,以更符合客户心理模型的术语解释产品的好处,或者使购买体验更轻松或更愉快。因为本书的主题是数据分析而不是行为设计,所以我们只会看如何分析这种干预措施,而不是如何开发它们。
意图
当有人说“我要做 X 事情”,不管 X 是为一周的杂货购物还是预订假期,他们表达了一种 意图。因此,意图将我们带向行动的一步。
从技术上讲,意图是一种心理状态,可以被包括在先前的认知和情感类别中,但由于其在应用行为数据分析中的重要性,我认为它应该有自己的类别。除非你计划强迫客户走特定的路径(例如,从网站上删除电话号码以防他们给你打电话),否则你通常需要将他们的意图作为行为变化的导管。
此外,人们经常无法完成他们想做的事情,这个概念在行为科学中被称为意图行动差距(例如,想想新年决心经常被打破的情况)。因此,驱动客户行为的关键是确定潜在的反应是因为客户不想采取行动,还是因为意图和行动之间发生了某些事情。
数据收集和道德考虑
在业务的一般过程中,我们通常没有关于意图的直接数据。因此,大多数数据将来自客户的声明,通常通过两个来源:
调查
这些可以是“当时发生的”(例如,在访问网站或商店结束时)或异步的(例如,通过邮件、电子邮件或电话进行)。
用户体验观察
在这些用户体验观察中,UX 研究人员要求受试者经历某种体验,并收集关于他们意图的信息(通过要求他们在过程中大声思考或事后提问,比如,“那时你想做什么?”)。
或者,我们经常试图从观察到的行为中推断意图,这在分析中被称为“意图建模”。
从道德的角度来看,影响某人的意图是广告、营销和说服的黑暗艺术的目标。这是可行的,我真诚地相信在许多情况下甚至可以在道德上做到,正如 UX 和行为研究人员所努力的那样。但简单的事实是,这通常很难做到,而且可能适得其反。识别那些可以帮助客户弥合意图行动差距的地方则简单得多且更安全。换句话说,在我们的模型中,一个“痛点”通常反映了实现意图的障碍。
行动
行动是行为的基本单位,我经常交替使用这两个词。我经常告诉人们的经验法则是,如果你当时在房间里,应该能够观察到一个行动或行为,而不必问这个人。“在亚马逊上购买东西”是一个行动。在亚马逊上“阅读产品评论”也是行动。但“知道某事”或“决定在亚马逊购买某物”不是。除非你问他们或看到他们行动(这是一个结果但不是同一件事),否则你无法知道某人已经做出了决定。
行动或行为通常可以在不同的粒度级别上定义。“去健身房”是可观察的,在许多情况下这是一个可以接受的细节水平。如果你给人们寄送免费访问的优惠券并且他们到场,你已经达到了你的目标,不需要更深入地思考。然而,如果你正在开发一个健康应用程序,并且希望确保人们按照他们的计划保持进度,你需要比这更详细。我曾参加过行为科学家史蒂夫·温德尔的演讲,他在演示中详细讲解了“去健身房”的每一个步骤(穿上健身服装,去到车上,决定一旦到达健身房要做什么锻炼等)。如果你试图识别和解决行为障碍,这通常是你需要采用的详细程度。同样的情况也适用于网站或应用程序中的客户旅程。什么是“注册”意味着什么?他们需要检索和输入哪些信息?你要求他们做出哪些选择?
收集数据及道德考量
行动或行为数据通常代表可用客户数据中最大的类别,并且通常归类为“交易数据”。然而,在许多情况下,这些数据需要额外的处理才能真正反映出行为。我们将在本章的第二部分更详细地探讨这一点。
如果你的目标是员工行为(例如在人员分析或减少流失方面),数据可能会更加稀缺和难以获取,因为通常需要从业务流程软件中提取,并且可能并非常规记录。
让我们明言不讳:行为分析的最终目标是修改行为。在某些情况下,这可能非常简单:如果你从网站上删除客服电话号码,就会减少打电话给你的人数。这是否是一个好主意则是另一回事。显然,行为修改有时可能非常困难,正如行为改变的大量和增长的文献所示。^(1)
无论如何,修改行为的目标都伴随着道德责任。在这里,纽约时报的问题是我推荐的试金石。
业务行为
我们需要考虑的最后一个数据类别是业务行为:组织或其员工对客户(或员工行为是你的焦点的情况下)产生影响的事物。这包括:
-
通信,如电子邮件和信件
-
网站语言的更改或呼叫中心代表的对话路径的更改
-
业务规则,例如客户奖励的标准(例如,“如果客户在过去六个月内花费了 X 美元,请给他们寄送优惠券”)或招聘决策
-
个体员工的决策,例如将客户账户标记为潜在欺诈或提升另一名员工
收集数据
商业行为对行为数据分析师来说既是一种祝福又是一种诅咒。一方面,从干预设计的角度来看,它们是我们驱动个人行为的主要杠杆之一:例如,我们可以修改一封信的内容或电子邮件的频率,以说服客户按时付款。因此,商业行为是一种极其宝贵的工具,没有它,我们的工作将变得非常困难,而且当我们自己对商业行为进行更改时,通常很容易收集相应的数据。商业行为的另一个优势是,在数据收集方面没有太多道德考虑:组织通常可以在正常业务过程中自由收集关于其自身运营和员工行为的数据(尽管当然也有一些情况被认为是侵犯隐私)。
另一方面,从数据收集和分析的角度来看,商业行为可能是分析师的噩梦:就像水对鱼一样,它们可能对组织来说是看不见的,它们对个人行为的影响就变成了难以解决的噪音。这发生的原因有两个。
首先,许多组织,如果他们根本就追踪商业行为,往往不会像追踪客户行为那样以相同的详细程度进行追踪。假设 C-Mart 在 2018 年夏季试验性地缩短了营业时间,导致销售暂时下降。光凭数据就难以找出原因!许多业务规则,即使它们在软件中实现了,也根本没有以机器可读格式记录在任何地方。如果相应的数据确实已记录,通常仅存储在部门数据库(或更糟的是,Excel 文件)中,而不是企业数据湖中。
其次,商业行为可能会影响对客户行为变量的解释。最明显的例子就是 诱惑,即有意引入的摩擦和误导性沟通,以混淆客户。想象一下,在网站上有一个表格,当你输入你的电子邮件地址时,自动勾选了你在表格开始时取消选中的“我想接收营销邮件”的框。那个被勾选的框是否真的表示客户想要接收营销邮件?除了这些明显的例子之外,商业行为可能隐藏在许多客户行为背后,尤其是在销售领域。许多购买倾向模型应该注明“在我们的销售团队决定联系的人群中”。悖论的是,尽管销售代表的薪酬结构通常是商业领导者最着迷的杠杆之一,但它很少被纳入客户购买行为模型中。
最终,获取有关业务行为的可靠数据,尤其是随着时间推移,对于行为数据分析师来说可能是一项艰巨的挑战——但这也意味着这是他们在进行任何分析之前为组织创造价值的一种方式。
如何连接行为和数据
个人特征、认知和情感、意图、行为和商业行为:这些是我们可以用来代表和理解我们的世界的概念,作为行为数据分析师。然而,连接行为和数据并不简单地将手头的变量分配到这些桶中的一个。仅仅“涉及行为”并不足以使变量有资格成为“行为数据”;正如我们在前一节中看到的,例如,一个据称是关于客户行为的变量可能实际上只反映了一个业务规则。在本节中,我将为您提供一些提示,以使您的数据具有行为化,并确保它尽可能与其应该代表的定性现实密切匹配。
为了更具体化,我们将看看我们的第二个虚构公司,Air Coach and Couch(AirCnC),一个在线旅行和住宿预订公司。 AirCnC 的领导层已要求他们的分析师衡量客户满意度对未来购买行为的影响,即在预订后的六个月内的支出量(M6Spend),这是他们的关键绩效指标之一。我们将在本书结尾,在第十二章回答这个常见但棘手的业务问题。现在,我们只是看看如何开始构思这个问题。
培养行为完整性心态
由于行为科学在企业中尚属新兴,你通常会成为第一个将这种视角带入组织数据的人,而该数据很可能包含数十个,甚至数百个或上千个变量。这是一项艰巨的任务,但采取正确的心态将有助于你理清头绪并开始工作。
想象一下,你是一名新被指派负责维护一座桥梁的结构工程师。你可以从一端开始,逐英寸(或逐厘米)评估其完整性,直到到达另一端,然后制定一个十年计划来实现完美的结构完整性。与此同时,坑洼变得越来越严重,危及驾驶者的安全,损坏他们的车辆。更合理的方法是快速浏览一下,优先解决可以迅速修复的主要问题,并确定临时解决方案的地点,直到你有时间和预算来进行更多的结构性变更为止。
同样的思维方式也适用于你的数据。除非你碰巧是初创企业的第一批员工之一,否则你将处理现有数据和遗留流程。不要惊慌,也不要按字母顺序浏览你的表格列表。从一个具体的业务问题开始,并按照它们对业务问题重要性递减的顺序识别最可能不准确的变量:
-
兴趣的原因和效果
-
中介变量和调节变量,如果相关
-
任何潜在的混杂因素
-
其他非混杂独立变量(也称为协变量)
在过程中,你将不得不做出判断:例如,你应该在分析中包含某个变量吗?还是它定义得如此不清晰,以至于最好不要包含它?不幸的是,并没有清晰的标准来正确地做出这些决定;你将不得不依靠你的商业感觉和专业知识。然而,有一种明确错误的做法:假装它们不存在。一个变量将被包括或不包括在你的分析中,这是无法回避的事实。如果你的直觉倾向于包含它,那么记录为什么,描述潜在的错误源,并指出如果该变量被省略,结果会有何不同。正如一位用户体验研究员在与我友好交谈时所说,作为商业研究人员意味着不断地弄清楚“你能够做什么”。
不信任和验证
不幸的是,在许多情况下,数据记录的方式受业务和财务规则的驱动,以事务为中心,而不是以客户为中心。这意味着在证明无罪之前,你应该将变量视为可疑:换句话说,不要自动假设变量 CustomerDidX 表示客户做了 X。它可能意味着完全不同的事情。例如:
-
客户在不阅读提到他们同意 X 的详细信息的小字条款的情况下勾选了一个框。
-
客户没有说任何话,因此我们默认他们选择了 X。
-
客户声明他们做了 X,但我们无法验证。
-
我们从供应商那里购买了数据,表明客户在他们生活的某个时刻经常做 X。
即使客户实际上做了 X,我们也不能假设他们的意图。他们可能做了这个:
-
因为我们发送了他们一封提醒邮件
-
四次因为页面没有刷新
-
他们误以为自己真正想做 Y
-
一周前,但由于监管约束,我们今天才记录它。
换句话说,用《公主新娘》中的一句流行台词来说:“你一直在使用那个变量。我觉得它并不是你认为的意思。”
确定类别
正如 AirCnC 的领导所述,他们要求分析师了解 CSAT 对购买行为的影响,这是一个艰巨的任务。我们的第一步是弄清楚我们在谈论什么。
在我大学的第一年,我的哲学教授会给我们一些如“进步是什么?”和“人与机器”的论文题目。除此之外,如果我们卡壳了,他还提供了一些极好的建议:用他的话说,我们应该弄清楚,“这是哪本书的一章。” 矛盾的是,当一个问题看起来令人望而却步且难以解决时,询问它属于哪个更广泛的类别通常会有所帮助。
幸运的是,作为行为数据分析师,我们不需要在国会图书馆里漫游以寻找灵感;我们在本章节早期定制的分类就能发挥作用:
-
个人特征
-
认知和情感
-
意图
-
行为(又称行为)
-
商业行为和流程
让我们通过排除法进行。客户满意度并非固定不变,因此不属于个人特征的一部分。它既不是人们做的事情,也不是人们打算去做的事情,因此也不是行为或意图。最后,它也不仅仅是在业务层面上发生的事情,因此也不是商业行为或流程的一部分。因此,客户满意度是认知和情感的一部分,与它相似的客户体验也是如此。我们业务问题的第二个变量,“购买行为”,要分类起来容易得多:显然它是客户行为。
根据我的经验,许多商业分析项目失败或成果低迷,因为分析师没有澄清项目的核心。组织总是有一个主导的目标指标——公司的利润,非营利组织的客户结果等等。在更低层次上,部门通常有他们自己的目标指标,比如客户体验团队的净推荐值,IT 的停机百分比等等。如果业务伙伴要求您衡量或改善一个看似与这些目标指标无关的变量,通常意味着他们心中有一个隐含的可能有问题的行为理论将两者联系起来。
“客户参与度”,这是行为科学家经常被要求提高的另一个流行概念,是一个很好的例子。这并不是一个明确的概念,因为它可能真正指的是两种不同的事物:
-
一种行为,即与业务的广泛互动模式:如果客户 A 更频繁地登录网站并花费更多时间浏览,他被认为比客户 B 更参与其中。
-
一个认知或情感,比如当观众因为沉浸在电影或课程的流程中并渴望知道接下来会发生什么时,“参与”。
的确,我坚信对这两者之间的混淆解释了初创企业和更广泛的数字世界对参与度指标的吸引力,尽管它们可能具有误导性。例如,在第一种意义上,当我的洗衣机停止工作时,我与它的关系更为密切;但这并不转化为第二种意义上的愉悦和渴望。试图将参与作为行为来增加的组织通常对结果感到失望。当作为行为的参与不能转化为作为情感的参与时,它不会带来诸如更高忠诚度和留存率等期望的结果。
作为一个个人例子,一个商业伙伴曾经请我帮忙让员工进行某种培训。经过一些讨论,很快明确了她真正想要的是让员工遵守一个业务规则;她认为员工之所以不遵守是因为他们对规则了解不足。我们把项目重心转向了理解为什么员工不遵守规则以及如何鼓励他们这样做。简而言之:要警惕那些自我诊断的病人!
现在我们可以在我们的人类行为模型中重塑我们的业务问题:AirCnC 的领导们想知道认知/情感是否影响客户的行为,如果是的话,影响有多大。实际上,在绝大多数业务分析问题中,涉及的变量至少有一个是行为,要么是客户的行为,要么是业务的行为。如果我们给客户发送跟进电子邮件,他们会更满意吗?满意的客户更有可能购买吗?
如果在确定了相关变量的类别之后,其中没有一个属于客户或业务行为类别,这应该引起警觉。这表明一个没有明确“所以呢?”的业务问题。比如说,年长客户更满意。所以呢?我们要用这些信息做什么?业务结果是由行为驱动的,不管是我们自己的行为还是我们客户的行为。
一旦你确定了相关的行为,就该深入挖掘相应的变量了。
精炼行为变量
正如我之前提到的,一个变量“关于行为”并不等同于一个行为变量。通常你需要对它们进行转换,使它们真正成为行为变量。
让我们专注于客户行为,因为它们更直观,但逻辑类似适用于业务行为。一个良好的行为变量将具备以下特征:
可观察
正如在第一章中提到的,行为在原则上是可观察的。如果你在客户身边,你能看见他们这样做吗?在预订过程中放弃预订是可观察的;改变主意则不是。一个很好的线索是,如果它没有时间戳,那么它可能不够具体和细化。
个体化
企业经常依赖于汇总指标,如比率或比例(例如,取消账户的客户比例)。汇总指标可以提供有用的快照以供报告之用,但它们可能会受到偏见和混淆因素的影响,例如人口组成的变化(即客户组合),特别是当它们基于时间间隔计算时。
例如,假设一次成功的营销活动将大量新用户带到了 AirCnC 的网站上。同时假设在这个业务线上,相当大比例的新客户在第一个月取消了他们的账户。因此,在活动后的一个月里,AirCnC 的每日取消率可能会急剧上升,即使没有任何问题发生。一个好的经验法则是,健全的汇总变量建立在健全的个体变量基础之上。如果一个变量只在汇总时有意义,并且在个体水平上没有有意义的解释,那就是一个警示信号。在我们的例子中,取消率的有意义的个体对应物将是取消概率。在控制个体特征和与公司的任期时,这个指标将保持稳定,尽管有大量新客户的涌入。
原子
同样,企业经常会汇总一系列不同行为,这些行为有着共同的意图。例如,AirCnC 客户修改他们的账单地址可能有三种不同的方式:通过账户设置、在预订时编辑信息,以及联系客服中心。这些方式在观察客户时看起来可能不同,但在数据库中可能会以类似的方式记录。再次强调,我并不想暗示汇总的行为变量本质上是不好的。当然,有些分析需要使用二元变量ChangedBillingInformation。但至少,你应该了解可以采用的具体方式,并且尽可能检查你得出的总体结论是否适用于每一种方式。
在许多情况下,确定或创建令人满意的行为变量涉及到“亲手动手”。用于分析或研究目的的数据库通常提供了“精简过”的真实版本,如交易数据库中所示,仅列出最新的、经过审查的信息。这在大多数情况下是有道理的:如果客户预订了并取消了,并且已退款,我们不希望该金额计入AmountSpent变量。毕竟,从业务角度来看,AirCnC 并没有保留那笔钱。然而,从行为学角度来看,该客户与同一时间段内没有进行任何预订的客户是不同的,因此在某些分析中考虑这一点是相关的。不要去学习像 COBOL 这样的古老编程语言来访问最底层的数据库,但值得稍微深入你平常美丽表格之外的地方稍作探索。
理解背景
重申一下,“行为是人与环境的函数”是行为科学中的基本原理。尽管个人变量当然很重要,但我觉得分析师们往往过于依赖它们,因为它们易于获取,结果可能没有足够地考虑到背景变量。
通常理解人们行为背景的最佳方式是通过定性研究,如访谈和调查,这些见解可以用来生成新的变量。在这里,我将重点介绍如何从现有数据中提取背景信息:
这是时候了。
正如前面提到的,行为是可观察的。在理论上,甚至在实践中,都可以确定它发生的时刻,这要归功于时间戳。时间戳对于行为分析师来说是金子般珍贵的,因为它们提供直观且通常可操作的见解。毫不奇怪,没有现成的算法可以提取这些,只能依赖商业直觉和问题的特定性。我将给出寻找的最常见线索:
频率
在行为和更广泛地说,事件数据中,自然的倾向是查看频率,即单位时间内的事件/行为次数。不幸的是,频率数据有时会表现不佳,并展示出不反映行为变化的人为不连续性。例如,假设一个 AirCnC 的客户每年夏天和冬天都度假,这意味着每年预订两次。然而,有一年他们将冬季度假从 12 月改到了 1 月。我们将在前一年计算一次假期,而在后一年计算三次,即使行为实际上并没有改变。这种赶上现象——较长时间跟随较短时间,最好通过直接跟踪持续时间来理解。对于其他行为,过去的事就让它过去吧,频率将是更稳健的度量标准。
持续时间
持续时间也提供了一种衡量衰减效应的自然方法。很久以前发生的事情或您所做的事情往往比最近发生的事情效果小。这通常使持续时间成为一个良好的预测变量。如果一个顾客在五年前经历了糟糕的 AirCnC 体验后仍未离开,那么这可能不再对他们的决策产生太大影响,最好是根据它们发生的时间长短加权过去旅行的客户满意度,而不仅仅使用平均值。
连续性
同样,彼此非常接近的行为通常并非巧合,并且可以提供正在发生的事情的线索。一个顾客在尝试在线更改后打电话给 AirCnC 的呼叫中心以更改其账单信息,展示了与直接致电的顾客不同的行为。孤立的数据使全渠道分析项目变得艰巨,但成功将来自不同渠道的数据整合在一起将带来巨大回报。汇总行为数据的最佳方式之一是为“在做 X 后做 Z”创建变量。
社交日程
人们更可能在工作时间内,或在周一到周五的白天^(3)在路上,要么正在前往工作地点,要么正在从工作地点回家。一个周六上午悠闲地浏览度假目的地的顾客可能在孩子的体育练习场上。现代生活有其常识和时间表。由于其细粒度,通常最好从“每周小时”变量开始,而不是单独拥有“每天小时”和“每周天”的变量(当然是以当地时间为准)。根据您的业务线,您可以进一步将事物聚合成像“工作日晚上”等变量。
信息和“已知未知”
如果一棵树在森林中倒下并且在您的数据中记录下来,但没有顾客听到它,它会发出声音吗?您的组织和客户通常在不同时间点了解到事物。与行为相关的变量应始终反映进行该行为的人在执行该行为时可获得的信息。这可以简单地将“发送日期”替换为“预期收到日期”,适用于您发送给客户的邮件,反之亦然。人们不知道他们没有打开的电子邮件的内容。正如常识和行为逻辑的一部分,但它将有助于确保您的变量紧密契合相应的行为。
沉默的狗
有时人们会做一件事而不是另一件事,有时他们没有选择(或者他们没有看到)。人们不做的事情通常与他们所做的事情一样有趣。识别替代行为的一种方式是寻找分叉:如果行为 A 之后经常发生行为 B,那么还有哪些行为 C 在 A 之后也经常发生?反之亦然,如果行为 B 之后经常发生行为 D,是什么其他行为导致了行为 D?这可以帮助您识别“幸福路径”或者在完成任务的过程中迷失的客户。
更好地理解行为背景是行为视角为像 AirCnC 这样的业务分析项目带来价值的方式之一。AirCnC 的领导是否想要衡量客户对他们的在线预订体验、住宿或 AirCnC 的服务代表(还有许多其他可能性)的满意度?你可以在客户与 AirCnC 的第一次互动之后的任何时候询问客户他们的满意度,他们会给出一个答案,但这并不能保证这些答案意味着相同的事情,甚至是任何事情。
在我们的情况下,AirCnC 的领导真正想要了解的是在服务呼叫之后客户满意度的重要性。这将帮助他们确定是否应该更多投资于雇佣和培训高质量的代表,或者是否可以将服务外包给低工资的国家(提示:他们可能不应该这样做)。
结论
应用行为科学的乐趣和挑战之一是它涉及定性和定量分析之间的持续来回。本章的意图是为您提供一个关于人类行为的基本模型和可操作的技巧,以便您可以开始灵活运用这些技能并将行为与数据联系起来。这意味着即使在进行任何数据分析之前,您也可以通过改进其数据的行为完整性和澄清解决业务问题的方法为组织增加价值。
在本书的下一部分,我们将介绍因果行为框架的第三支柱,即允许我们建立行为之间关系的因果图。
^(1) 塞勒和桑斯坦的Nudge(2009)和艾尔的Hooked: How to Build Habit-Forming Products(2014)是关于这个主题的两个良好的参考书目之一。
^(2) 在此,我预先向结构工程师道歉,如果这个比喻严重误代表了他们的工作,这很可能会发生。诗意的许可和其他一切。
^(3) 当然,除非恰好发生全球大流行。
第二部分:因果图与消除混杂
在第一部分中,我们看到混杂可能会危害甚至最简单的数据分析。在第二部分中,我们将学习构建因果图(CD)来表示、理解和消除变量之间的关系。
首先,第三章介绍了因果图及其构建基础。
在第四章中,我们将看到如何从头开始为新分析构建因果图。我们在冰淇淋示例中看到的因果图设计非常简单。但在现实生活中,确定应在我们的因果图中包含哪些变量,超出了我们感兴趣的因果关系,以及如何确定它们之间的关系,通常会变得复杂。
同样地,从我们的冰淇淋示例中消除混杂很简单:我们只需要在回归中包含我们感兴趣变量的联合原因。在更复杂的因果图中,确定应包含在回归中的变量可能变得困难。在第五章中,我们将看到可以应用于即使是最复杂因果图的规则。
第三章:因果图简介
实际上,除了少数例外,相关确实意味着因果关系。如果我们观察到两个变量之间存在系统性关系,并且我们已经排除了这只是随机巧合的可能性,那么一定存在某种因果关系。当马来影子戏剧的观众在屏幕上看到一个实心的圆形影子时,他们知道某个三维物体产生了这个影子,尽管他们可能不知道这个物体是球体还是侧面的饭碗。对于统计学入门而言,一个更准确的口号应该是简单的相关性暗示着一个未解决的因果结构。
比尔·希普利,《生物学中的因果与相关性》(2016)
因果图(CDs)很可能是大多数人从未听说过的分析工具中最强大的之一。因此,它们是因果行为框架的三个极点(顶点)之一(图 3-1)。它们提供了一种语言来表达和分析因果关系,特别适用于处理行为数据分析。
图 3-1. 数据分析的因果行为框架
在本章的第一部分中,我将展示 CD 如何从概念角度融入框架中,即它们如何与行为和数据连接。在第二部分中,我将描述 CD 中的三种基本结构:链式结构、分叉结构和碰撞结构。最后,在第三部分中,我们将看到可以应用于 CD 的一些常见转换。
因果图和因果行为框架
首先,让我们定义什么是 CD。CD 是变量的视觉表示,显示为方框,并显示它们之间的关系,表示为从一个框到另一个框的箭头。
在我们在第一章中的 C-Mart 示例中,变量 IcedCoffeeSales 受到一个单一原因 Temperature 的影响。图 3-2 展示了相应的因果图。
图 3-2. 我们的第一个因果图
每个矩形代表我们可以观察到的变量(我们在数据集中拥有的一个),它们之间的箭头表示因果关系的存在和方向。这里,Temperature 和 IcedCoffeeSales 之间的箭头表明前者是后者的原因。
然而,有时会有一个我们无法观察到的额外变量。如果我们仍然希望在因果图中显示它,我们可以用一个阴影矩形来表示^(1)(图 3-3)。
图 3-3. 带有未观察变量的因果图
在 图 3-3 中,CustomerSweetTooth 是 IcedCoffeeSales 的一个原因,这意味着甜食爱好者购买更多冰咖啡。然而,我们无法观察到顾客的甜食偏好程度。稍后我们将讨论因果分析中未观察到的混杂因素和更普遍地未观察到的变量的重要性。目前,我们只需要注意即使我们无法观察到特定变量,也可以通过将其表示为椭圆形包含在因果图中。
因果图表现行为
对因果图的第一种看法是将它们视为行为之间因果关系的表现,以及影响行为的现实世界中的其他现象(图 3-4)。从这个角度看,因果图的元素代表着存在并相互影响的真实“事物”。物理科学中的类比可以是磁铁、铁条和磁铁周围的磁场。你看不到磁场,但它确实存在,并影响铁条。也许你对磁场没有任何数据,也许你从未见过描述它的方程,但当你移动铁条时,你能感觉到它,并且你能对它的作用产生直觉。
图 3-4. CDs are connected to behaviors in our framework
当我们想要理解驱动行为的因素时,同样的观点适用。我们直观地理解人类有习惯、偏好和情感,尽管我们通常没有关于这些方面的数字数据。当我们说“乔买了花生是因为他饿了”时,我们依赖于我们对人类和乔的知识、经验和信念。我们把饥饿看作是一种真实存在的东西,即使我们没有测量乔的血糖或脑部活动。
在这里,我们对现实做出了因果性陈述:我们说如果乔不饿的话,他就不会买花生。因果性对我们对现实的直观理解非常基本,以至于即使是年幼的孩子在接触科学方法或数据分析之前也能做出正确的因果推论(通过使用“因为”这个词表明)。当然,直觉受到各种行为科学家所熟知的偏见的影响,即使它采取更为教育的形式,如常识或专业知识。但通常情况下,即使在没有数量数据的情况下,直觉也能在日常生活中很好地指导我们。
你可能担心使用 CDs 来表示对世界的直觉和信念引入了主观性,这当然是事实。但是因为 CDs 是思考和分析的工具,它们不必是“真实”的。你和我对 Joe 为什么买花生有不同的想法,这意味着我们可能会绘制不同的 CDs。即使我们完全同意什么导致什么,我们也不能在一个图表中表示所有东西及其关系;确定包含或排除哪些变量和关系涉及判断。在某些情况下,当数据可用时,它将有所帮助:我们将能够拒绝一个与手头数据不兼容的 CD。但在其他情况下,非常不同的 CDs 将与数据同样兼容,我们将无法在它们之间做出选择,特别是如果我们没有实验数据。
这种主观性可能看起来像是 CDs 的一个(可能是致命的)缺陷,但实际上却是一个特性,而不是错误。CDs 不会产生不确定性;它们只是反映了已经存在于我们世界中的不确定性。如果对当前情况有几种可能的解释看似同样有效,你应该明确地说明。另一种选择是允许那些在他们的头脑中有不同心理模型的人每个人都相信自己知道真相,并且其他人同意他们的看法,而实际上情况并非如此。至少公开不确定性将允许进行原则性讨论并指导您的分析。
因果图代表数据
尽管构建和解释 CDs 有一门艺术,但也有一门科学,我们可以利用 CDs 来表示数据中变量之间的关系(见图 3-5)。当这些关系完全是线性的或近似线性时,CDs 在线性代数中有明确的等价物。这意味着我们可以使用线性代数的规则和工具来验证我们如何操作和转换 CDs 的“合法性”,从而确保我们得出正确的结论。
图 3-5. CDs 也与数据相关联
线性要求可能看起来非常严格。然而,当某些关系不是线性的,但仍属于称为广义线性模型(GLM)的模型的广泛类别时,线性代数的一些规则和工具仍然适用。例如,逻辑回归模型就是一个 GLM。这意味着我们可以用 CDs 来表示和处理一个因果关系,其中影响变量是二进制的。如侧边栏所示,在这种情况下,数学变得更加复杂,但我们关于 CDs 的大多数直觉仍然成立。
从这个角度来看,从图 3-3 中连接Temperature和IcedCoffeeSales的因果图意味着:
IcedCoffeeSales = β * Temperature + ε
这个线性回归意味着,如果温度增加一度,其他条件保持不变,那么冰咖啡的销售将增加β美元。因果图中的每个方框代表一个数据列,就像表格 3-1 中模拟数据一样。
表格 3-1. 模拟数据,展示了我们因果图中的关系
| 日期 | Temperature | IcedCoffeeSales | β * Temperature | ε = IcedCoffeeSales – β * Temperature |
|---|---|---|---|---|
| 6/1/2019 | 71 | $70,945 | $71,000 | $55 |
| 6/2/2019 | 57 | $56,969 | $57,000 | $31 |
| 6/3/2019 | 79 | $78,651 | $79,000 | -$349 |
对于熟悉线性代数符号的人,我们可以将前述方程重写为:
(70,94556,96978,651)=1000*(715779)+(5531−349)
从这个角度来看,因果图关注的是数据——变量及其之间的关系。这立即推广到多个原因。让我们绘制一个因果图,显示Temperature和SummerMonth都会导致IceCreamSales(图 3-8)。
图 3-8. 一个带有多个原因的因果图
将这个因果图转化为数学术语,得到以下方程式:
IceCreamSales = β[T].Temperature + β[S].SummerMonth + ε
显然,这个方程是标准的多元线性回归,但其基于因果图的解释方式有所不同。在因果框架之外,我们只能得出一个结论:“温度增加一度与冰淇淋销售额增加β[T]美元相关。”因为相关性并非因果关系,因此推断任何进一步的事实都是不合理的。然而,在回归模型基于因果图的情况下,如本例,我们可以做出显著更强的陈述——即,“除非这个因果图是错误的,否则温度增加一度将导致冰淇淋销售额增加β[T]美元”,这正是业务关心的。
如果你有数据科学等量化背景,你可能会倾向于关注因果图与数据之间的连接,而牺牲了与行为之间的联系。这当然是一条可行的道路,并且它已经产生了一整套称为概率图模型的统计模型类别。例如,已经开发了算法来在数据中识别因果关系,而不依赖于人类的专业知识或判断。然而,这个领域仍处于起步阶段,当应用到现实数据时,这些算法通常无法在几种可能导致极不同业务影响的因果图之间进行选择。商业常识通常可以更好地选择最合理的一种。因此,我坚信你最好使用本书框架中展示的混合方法,并接受你需要运用自己的判断的观点。因果图在你的直觉和数据之间来回推理——在许多情况下,这正是成功之道。
因果图的基本结构
因果图可以呈现出多种各样的形状。幸运的是,研究人员已经花了一段时间在因果性上,并为此带来了一些秩序:
-
因果图只有三种基本结构——链式结构、分叉结构和碰撞器结构——所有的因果图都可以表示为它们的组合。
-
将因果图看作家谱,我们可以轻松描述在图中相距较远的变量之间的关系,例如称其中一个为另一个的“后代”或“子节点”。
实际上,就是这样!我们现在将更详细地了解这些基本结构,并且一旦你熟悉了它们以及如何命名变量之间的关系,你将能够完全描述你所使用的任何因果图。
链式结构
链式结构是一个有三个框表示的因果图,代表三个变量,并且两个箭头直线连接这些框。为了向你展示一个例子,我将介绍我们 C-Mart 例子中的一个新的待处理物——那就是强大的甜甜圈。为了简单起见,让我们假设我们已经看到的变量只有一个影响到了甜甜圈的销售:冰咖啡销售量。那么 温度、冰咖啡销售量 和 甜甜圈销售量 是因果相关的 (图 3-9)。
图 3-9. 链式因果图
这张因果图之所以被称为链式结构,是因为两个箭头“同向”,即第一个箭头从一个框指向另一个框,第二个箭头从第二个框指向最后一个框。这张因果图扩展了 图 3-3 中的图示。它表示了温度导致冰咖啡销售,进而导致甜甜圈销售的事实。
让我们定义一些术语,以便描述变量之间的关系。在这个图表中,Temperature 被称为 IcedCoffeeSales 的父亲,而 IcedCoffeeSales 是 Temperature 的子孙。但是 IcedCoffeeSales 也是 DonutSales 的父亲,后者是其子孙。当一个变量与另一个变量有父/子关系时,我们称之为直接关系。当它们之间有中介变量时,我们称之为间接关系。变量数目的确切数量并不重要,因此您不必计算箱子的数量来描述它们之间关系的基本结构。
另外,我们说一个变量是另一个变量的祖先,如果第一个变量是另一个的父亲,后者可能是另一个的父亲,依此类推,最终我们的第二个变量是第一个变量的子孙。在我们的例子中,Temperature 是 DonutSales 的祖先,因为它是 IcedCoffeeSales 的父亲,后者又是 DonutSales 的父亲。非常合乎逻辑地,这使得 DonutSales 成为 Temperature 的后代(Figure 3-10)。
图 3-10. 链条中变量之间的关系
在这种情况下,IcedCoffeeSales 也是 Temperature 和 DonutSales 之间关系的中介者。我们将在第十二章中更深入地探讨中介作用。现在,让我们注意到,如果一个中介值不变,则链条中前面的变量不会影响链条中后面的变量,除非它们以其他方式相连。在我们的例子中,如果 C-Mart 遭遇冰咖啡短缺,我们预计在此期间,温度的变化不会对甜甜圈的销售产生任何影响。
折叠链条
上述因果图转化为以下回归方程:
IcedCoffeeSales = β[T].Temperature
DonutSales = β[I].IcedCoffeeSales
我们可以用第二个方程中的表达式替换 IcedCoffeeSales:
DonutSales = *β[I].(β[T]Temperature) = (β[I]β[T])Temperature
但是 β[I]β[T] 只是两个常数系数的乘积,所以我们可以将其视为一个新系数: DonutSales=β˜T.Temperature。我们已成功将 DonutSales 表示为 Temperature 的线性函数,这可以转化为因果图(Figure 3-11)。
图 3-11. 将一个 CD 折叠成另一个 CD
在这里,我们折叠了一个链条,也就是说,我们去除了中间的变量,并用从第一个变量到最后一个变量的箭头替换它。通过这样做,我们有效地简化了我们原始的因果图,专注于我们感兴趣的关系。当链条中的最后一个变量是我们感兴趣的业务指标,而第一个变量是可操作的时,这是有用的。在某些情况下,例如,我们可能对Temperature和IceCoffeeSales之间以及IceCoffeeSales和DonutSales之间的中间关系感兴趣,以管理定价或促销。在其他情况下,我们可能只对Temperature和DonutSales之间的关系感兴趣,例如,为了进行库存规划。
线性代数的传递性财产在这里也适用:如果DonutSales导致另一个变量,那么这个链条也可以围绕DonutSales折叠,依此类推。
扩展链条
显然,折叠操作可以反转:我们可以通过在中间添加IceCoffeeSales变量,从我们的最后一个 CD 回到前一个 CD。更一般地说,我们称之为扩展链条,每当我们在当前由箭头连接的两个变量之间注入中间变量时。例如,假设我们从Temperature和DonutSales的关系开始(图 3-11)。这种因果关系转化为方程DonutSales = β[T]Temperature。假设Temperature仅通过IceCoffeeSales影响DonutSales。我们可以在我们的 CD 中添加这个变量,这使我们回到了我们从图 3-8 开始的原始 CD(图 3-12)。
图 3-12. 将一个 CD 展开成另一个 CD
扩展链条可以帮助更好地理解特定情况中发生的事情。例如,假设温度增加了,但甜甜圈的销售量没有增加。这可能有两个潜在的原因:
-
首先,温度的增加并没有增加冰咖啡的销量,也许是因为店长更加积极地使用了空调。换句话说,在图 3-11 中,第一个箭头消失或减弱。
-
或者,温度的增加确实增加了冰咖啡的销售量,但冰咖啡的销售增长并没有增加甜甜圈的销售量,例如,因为人们正在购买新推出的饼干。换句话说,在图 3-11 中,第一个箭头保持不变,但第二个箭头消失或减弱。
根据实际情况,你可能会采取非常不同的纠正措施——要么关闭空调,要么改变饼干的价格。在许多情况下,查看链条中间的变量,即中介者,将帮助你做出更好的决策。
注意
由于链条可以随意折叠或展开,通常我们不会明确指示何时进行折叠。通常假设任何箭头都可能被展开,以突出沿途的中介变量。
这也意味着之前提到的“直接”和“间接”关系的定义与 CD 的特定表示相关:当你折叠一个链条时,两个原本间接关系的变量现在有了直接关系。
分叉
当一个变量导致两个或更多效应时,这种关系形成了一个分叉。温度同时导致冰咖啡销量和冰淇淋销量,所以这种分叉的表示如图 3-13 所示。
图 3-13. 三个变量之间的分叉
这个 CD 显示,温度影响了冰淇淋销量和冰咖啡销量,但它们之间并没有因果关系。如果天气炎热,冰淇淋和冰咖啡的需求都会增加,但购买其中一种并不会导致你想购买另一种,也不会减少你购买另一种的可能性。
当两个变量有一个共同原因的情况非常频繁,但也可能存在潜在问题,因为这会在这两个变量之间创建一个相关性。当天气炎热时,我们会看到冰淇淋和冰咖啡的销量增加,而天冷时,很少有人会同时想要这两种产品。从预测角度来看,从冰咖啡销量预测冰淇淋销量的线性回归会有相当的预测性,但这里相关性并不等于因果关系,由于我们知道因果影响为 0,模型提供的系数将不准确。
另一种看待这种关系的方式是,如果 C-Mart 的冰咖啡短缺,我们不会预期看到冰淇淋销量的变化。更广义地说,说分叉是数据分析世界中的一大罪恶根源并不为过。每当我们观察到两个变量之间的相关性,而这种相关性不反映它们之间的直接因果关系(即彼此不是对方的原因),往往是因为它们共享一个共同原因。从这个角度来看,使用 CD 的主要好处之一是,它们可以非常清楚和直观地显示这些情况以及如何进行纠正。
分叉也是我们观察人口统计变量时的典型情况:年龄、性别和居住地都可能导致各种其他可能相互作用或者不会相互作用的变量。你可以把人口统计变量比如年龄想象成一个有很多分支的分叉。
当 CD 中间有叉路时,有时会出现一个问题,即你是否仍然可以将链条围绕它折叠。例如,假设我们有兴趣使用图 3-14 中的 CD 分析 SummerMonth 和 IcedCoffeeSales 之间的关系。
图 3-14. 带有叉路和链条的 CD
在这个 CD 中,SummerMonth 一侧有一个叉路,另一侧有 IceCreamSales 和 Temperature,但也有一个链条 SummerMonth → Temperature → IcedCoffeeSales。我们可以折叠链条吗?
在这种情况下,是的。我们将在第五章中看到如何确定一个变量是否是关系的混杂因素;在这里,我们只需说 IceCreamSales 不是 SummerMonth 和 IcedCoffeeSales 之间关系的混杂因素,这是我们感兴趣的关系。因此,我们可以简化我们的 CD(图 3-15)。
图 3-15. 前一个 CD 的折叠版本
同样,如果我们对 图 3-14 中 SummerMonth 和 IceCreamSales 之间的关系感兴趣,我们可以忽略 IcedCoffeeSales,但不能忽略 Temperature。
因为叉路对因果分析非常重要,有时我们会想要表示它们,即使我们不知道联合原因是什么。在这种情况下,我们将用一个双头箭头表示未知的叉路(图 3-16)。
图 3-16. 具有未知联合原因的叉路
双头箭头也看起来像两个变量互相导致。这是有意设计的,当我们观察到两个变量之间的相关性,但我们不知道哪个导致哪个时,我们也会使用双头箭头。因此,双头箭头包括两个变量 A 和 B 会呈现相关的三个可能原因:A 导致 B,B 导致 A,和/或 A 和 B 共享一个原因。有时我们会使用双头箭头作为一个占位符,直到我们澄清真正的原因;如果我们不关心原因,我们可能会在最终的 CD 中保留双头箭头。
碰撞器
世界上很少有只有一个原因的事物。当两个或更多变量导致相同的结果时,关系就形成了一个碰撞器。由于 C-Mart 的小吃店只销售两种口味的冰淇淋,巧克力和香草,代表口味和购买行为的因果图会显示对任一口味的食欲都会导致在该店购买冰淇淋的过去经历(图 3-17)。
图 3-17. 碰撞器的碰撞直径(CD)
碰撞器是常见的现象,它们也可能是数据分析中的问题。碰撞器在某种意义上是分叉的对立面,与它们相关的问题也是对称的:如果我们不控制共同原因,那么分叉就会成为问题,而如果我们控制共同影响,碰撞器就会成为问题。我们将在第五章中进一步探讨这些问题。
总结本节,链、分叉和碰撞器代表了因果图中三个变量之间可能的三种关系方式。然而,它们并非彼此互斥,事实上,在同一个因果图中同时展现这三种结构是相当常见的,正如我们在第一个例子中所看到的(图 3-18)。
图 3-18. 同时包含链、分叉和碰撞器的三变量因果图
在这里,SummerMonth 影响 IceCreamSales 和 Temperature,而 Temperature 本身又影响 IceCreamSales。这里的因果关系相对简单易懂,但是这个图表也包含了所有三种基本关系类型:
-
一个链:SummerMonth → Temperature → IceCreamSales
-
一个分叉,其中 SummerMonth 导致 Temperature 和 IceCreamSales
-
一个碰撞器,IceCreamSales 同时受 Temperature 和 SummerMonth 的影响
在这种情况下需要注意的另一件事是,变量之间可能存在多于一种关系。例如,SummerMonth 是 IceCreamSales 的父变量,因为直接从前者到后者存在箭头(直接关系);但与此同时,SummerMonth 也通过链 SummerMonth → Temperature → IceCreamSales(间接关系)间接是 IceCreamSales 的祖先。所以你可以看到这些关系并不是排他的!
尽管一个因果图(CD)总是由这三种结构组成,但它并非静态的。通过修改变量本身及其关系,一个因果图可以被转换,我们现在就来看一下。
因果图的常见转换
链、分叉和碰撞器假定因果图中的变量是给定的。但是,就像链可以收缩或扩展一样,变量本身也可以被切片或聚合以“缩放”到特定行为和类别中。我们也可以决定修改箭头,例如在面对其他无法处理的循环时。
切片/解构变量
当你切片或解构一个变量以揭示其组成部分时,分叉和碰撞器经常会被创建。在先前的例子中,我们看过 Temperature 和 DonutSales 之间的关系,其中 IcedCoffeeSales 是中介者(图 3-19)。
图 3-19. 我们将切片的链
但也许我们想要根据类型分割IcedCoffeeSales,以更好地理解需求动态。这就是我所说的“切片”变量。这是允许的线性代数规则,因为我们可以将总冰咖啡销量表达为按类型销量的总和,比如美式和拿铁:
IcedCoffeeSales = IcedAmericanoSales + IcedLatteSales
现在我们的 CD 将成为图 3-20,左侧有一个分叉,右侧有一个碰撞器。
图 3-20. 一个链条,其中中介被切分了
现在,该变量的每个切片将有自己的方程式:
IcedAmericanoSales = β[TA].Temperature
IcedLatteSales = β[TL].Temperature
由于温度的影响完全被我们的IcedCoffeeSales切片所中介,我们可以创建如下的统一多元回归用于DonutSales:
DonutSales = β[IA].IcedAmericanoSales + β[IL].IcedLatteSales
这将使您能够更精细地了解发生了什么——当温度升高时,您是否应该计划这两种类型的销售增长?它们对DonutSales有相同的影响吗,还是您应该更青睐其中一种?
聚合变量
正如你可能猜到的那样,切分变量是可以反转的,而且更一般地,我们可以聚合那些具有相同因果关系的变量。这可以用于按产品、地区、业务线等进行聚合和分解数据分析。但它也可以更宽泛地用于表示那些没有精确定义的重要因果因素。例如,假设年龄和性别都影响香草味以及在 C-Mart 便利店购买冰淇淋的倾向,PurchasedIceCream(图 3-21)。
图 3-21. 年龄和性别分开显示
因为年龄和性别具有相同的因果关系,它们可以被聚合成一个人口特征变量(图 3-22)。
图 3-22. CD,其中年龄和性别被聚合成单一变量
在这种情况下,我们显然没有一个称为“人口特征”或“人口统计学”的单一列数据;我们只是在我们的 CD 中使用该变量作为一种简化,用于表示我们可能会或可能不会在以后深入探讨的各种变量。假设我们想要运行一项 A/B 测试并理解当前的因果关系。正如我们将在后面看到的那样,随机化可以使我们控制人口统计因素,这样我们就不必在分析中包含它们,但我们可能希望在没有随机化的情况下将它们包含在我们的 CD 中。如果有必要,我们总是可以扩展我们的图表以准确表示涉及的人口统计变量。然而,请记住,任何变量都可以分割,但只有具有相同直接和间接关系的变量才可以聚合。
循环如何处理?
在我们看到的三种基本结构中,两个给定框之间只有一条箭头。更一般地说,不可能通过按箭头方向两次到达相同的变量(例如,A → B → C → A)。一个变量可能是另一个变量的效果和另一个变量的原因,但不能同时是一个变量的原因和效果。
然而,在现实生活中,我们经常看到相互因果影响的变量。这种类型的 CD 被称为循环。循环可能由于多种原因而产生;在行为数据分析中最常见的两种是替代效应和反馈循环。幸运的是,当你遇到循环时,有一些解决方法可以帮助你应对。
理解循环:替代效应和反馈循环
替代效应是经济学理论的基石:顾客可能会根据产品的可用性和价格以及顾客对多样性的欲望来替代一种产品为另一种产品。例如,前来 C-Mart 便利店的顾客可能会根据不仅仅是温度,还包括特别促销以及本周喝咖啡的频率来选择冰咖啡或热咖啡。因此,从购买冰咖啡到购买热咖啡存在因果关系,反之亦然(图 3-23)。
图 3-23. 生成循环的替代效应 CD
注意
需要注意的一点是箭头的方向显示了因果关系的方向(什么是原因,什么是结果),而不是效果的符号。在我们之前看过的所有因果图中,变量之间存在正相关关系,其中一个增加导致另一个增加。在这种情况下,关系是负的,其中一个变量的增加会导致另一个变量的减少。对于因果图来说,效果的符号并不重要,只要你正确地识别相关的因果关系,回归分析就能正确地排序系数的符号。
另一个常见的循环是反馈环路,其中一个人根据环境变化调整他们的行为。例如,C-Mart 的店长可能会关注等待队列的长度,如果现有的队列太长,会开设新的收银台,这样顾客就不会放弃并离开(图 3-24)。
图 3-24. 反馈环路生成循环的示例
管理循环
循环反映了通常复杂的研究和管理情况,因此专门涉及这一领域的研究,称为系统思维,已经为此目的而兴起。(2)为了准确处理循环,已经开发了复杂的数学方法,如结构方程建模,但是它们的分析超出了本书的范围。然而,如果我不给出任何解决方案,那就不尽职责,因此我将提到两个经验法则,这应该能避免你被循环困扰。
第一点是要密切关注时间。在几乎所有情况下,一个变量影响另一个变量需要一定的时间,这意味着你可以通过更细致的时间粒度来观察数据,从而“打破循环”,将其转变为“非循环”的因果图,即没有循环的因果图(然后可以用本书介绍的工具进行分析)。例如,假设店长在等待时间增加后需要 15 分钟来开新的收银台,而顾客调整他们的等待时间感知也需要 15 分钟。在这种情况下,通过澄清事物的时间顺序,我们可以在我们的因果图中分割等待时间变量(图 3-25)。
图 3-25. 将反馈环路分解为时间增量
我将一点一点地解释这个因果图。在左侧,我们有一个从平均等待时间指向等待顾客数量的箭头:
NbCustomersWaiting(t + 15mn) = β[1].AvgWaitingTime(t)
这意味着,例如,上午 9:15 等待的顾客数量将以上午 9:00 的平均等待时间作为函数表达。然后,上午 9:30 等待的顾客数量将与上午 9:15 的平均等待时间有相同的关系,依此类推。
同样,在右侧,我们有一个从平均等待时间到开放的排队线的箭头:
NbLinesOpen(t + 15mn) = β[2].AvgWaitingTime(t)
这意味着,上午 9:15 开放的排队线数量将以上午 9:00 的平均等待时间作为函数表达。然后,上午 9:30 开放的排队线将与上午 9:15 的平均等待时间有相同的关系,依此类推。
然后在中间,我们有从等待顾客数量和从开放的收银台数量到平均等待时间的因果箭头。为了简单起见,在这里假设线性关系,这将转化为以下方程:
AvgWaitingTime(t) = β[3].NbCustomersWaiting(t) + β[4].NbLinesOpen(t)
注
实际上,在这种情况下假设线性关系是非常不可能成立的。对于队列或时间到事件变量(例如生存分析),已经开发了特定的模型。这些模型属于更广泛的广义线性模型类别,因此,我们的经验法则是它们在我们的目的下表现得像逻辑回归。
这意味着,顾客在上午 9:15 到达收银台排队时的平均等待时间取决于 9:15 时已经在场的顾客数量以及 9:15 时开放的收银台数量。然后,顾客在上午 9:30 到达收银台排队时的平均等待时间取决于 9:30 时已经在场的顾客数量以及 9:30 时开放的收银台数量,依此类推。
通过将变量分解为时间增量,我们已经能够创建一个没有严格意义上的循环的 CD。我们可以在不引入任何循环逻辑的情况下估计前述三个线性回归方程。
处理周期的第二条经验法则是简化你的 CD,并只保留你最感兴趣的因果路径上的箭头。反馈效应(其中一个变量影响刚刚影响它的变量)通常较小,往往比第一效应小得多,可以作为第一近似忽略。
在我们冰咖啡和热咖啡的例子中,当天气炎热时冰咖啡的销售增加可能会减少热咖啡的销售,这是一个你应该调查的合理担忧。然而,不太可能热咖啡销售的减少会进一步触发冰咖啡销售的增加,因此你可以在你的 CD 中忽略这种反馈效应(图 3-26)。
图 3-26. 简化 CD 图表,忽略某些关系
在图 3-26 中,我们删除了从热咖啡购买到冰咖啡购买的箭头,并将该关系视为一个合理的近似。
再次强调,这只是一个经验法则,并绝对不是对忽略循环和反馈效应的一揽子邀请。这些应该在您的完整因果图中完全表示,以指导未来的分析。
路径
在看到各种变量如何相互作用之后,我们现在可以介绍最后一个涵盖所有内容的概念:路径。我们说两个变量之间存在路径如果它们之间有箭头连接,无论箭头的方向如何,并且路径中没有变量重复出现。让我们看看我们之前见过的因果图(图 3-27)中的路径是什么样子的。
图 3-27. 因果图中的路径
在前面的因果图中,从SummerMonth到IcedCoffeeSales有两条路径:
-
一条沿着链的路径SummerMonth → Temperature → IcedCoffeeSales
-
第二条路径通过IceCreamSales,SummerMonth → IceCreamSales ← Temperature → IcedCoffeeSales
这意味着一个链是一条路径,但分叉或碰撞器也是如此!还要注意,两个不同的变量之间可能会有多条路径共享一些箭头,只要它们之间至少有一个差异,就像这里的情况一样:从Temperature到IcedCoffeeSales的箭头出现在这两条路径中。
然而,以下路径不是Temperature和IcedCoffeeSales之间的有效路径,因为Temperature出现了两次:
- Temperature ← SummerMonth → IceCreamSales ← Temperature → IcedCoffeeSales
这些定义的一个结果是,如果你在一个因果图中选择两个不同的变量,它们之间总会至少有一条路径。路径的定义可能看起来如此宽泛以至于没有用处,但正如我们将在第五章中看到的那样,路径实际上将在识别因果图中的混杂变量中发挥关键作用。
结论
相关性并非因果关系,因为混杂变量可能会在我们的分析中引入偏倚。不幸的是,正如我们通过例子所看到的那样,简单地将所有可用变量和乱七八糟的变量放入回归中并不足以解决混杂问题。更糟糕的是,控制错误的变量可能会引入虚假相关性并产生新的偏倚。
作为朝向无偏回归的第一步,我介绍了一种称为因果图的工具。因果图可能是你从未听说过的最佳分析工具。它们可以用来表示我们对真实世界中因果关系的直觉,以及我们数据中变量之间的因果关系;但最强大的是作为将我们的直觉和专家知识与观察数据相连接的桥梁,反之亦然。
CDs 可以变得错综复杂,但它们基于三个简单的构建模块:链、分叉和碰撞器。根据与线性代数一致的简单规则,它们还可以折叠或扩展、切片或聚合。如果你想了解更多关于 CDs 的内容,Pearl 和 Mackenzie(2018)是一本非常易读且令人愉快的书面介绍。
CDs 的全部威力将在 第五章 中显现,我们将看到它们允许我们在回归中最优地处理混杂因素,即使是非实验数据。但 CDs 在更广泛的范围内也很有帮助,帮助我们更好地思考数据。在接下来的章节中,当我们开始清理和准备数据进行分析时,它们将允许我们在分析之前减少数据中的偏差。这将为你提供在简单环境中更加熟悉 CDs 的机会。
^(1) 在 CDs 中,表示未观察变量最常见的方法是使用椭圆形而不是矩形。
^(2) 对感兴趣的读者推荐阅读 Meadows 和 Wright(2008)的《系统思维入门》,以及 Senge(2010)的《第五项修炼:学习型组织的艺术与实践》。
第四章:从头开始建立因果图
此时,您可能会想知道[因果图]的来源。这是一个很好的问题。这可能是一个问题。 [CD]应该是您研究的现象的关于其最先进知识的理论表示。这是一个专家认为是事物本身的东西,这种专业知识来自于多种来源。例如,经济理论,其他科学模型,与专家的交流,您自己的观察和经验,文献综述,以及您自己的直觉和假设。
Scott Cunningham,《因果推断:混音带》(2021)
本书的目标始终是衡量一个变量对另一个变量的影响,我们可以将其表示为“起始”CD(图 4-1)。
图 4-1。最简单的 CD
一旦你画出那种关系,接下来会发生什么?你如何知道你应该包括哪些其他变量或不包括哪些变量?许多作者说你应该依靠专家知识,如果你在像经济学或流行病学这样的已建立领域工作的话,这是可以的。但在本书中,我的观点是,你很可能是你组织中的“行为科学家第一人”,因此你需要能够从一张空白的画布开始。
在本章中,我将概述一种配方,帮助您从图 4-1 的基本 CD 到一个可行的 CD。在我们进行这个过程的同时,请记住我们的最终目标是理解是什么推动行为,以便我们可以为我们的业务得出相关和可操作的结论。我们的目标不是建立对整个世界的完整和精确的知识。捷径和近似是公平的游戏,一切都应根据一个标准评估:这是否有助于我实现我的业务目标?
此外,我将概述的配方不是一个机械算法,你可以盲目地遵循到正确的 CD。相反,商业常识,常识和数据见解将是至关重要的。我们将在我们对手头因果关系的定性理解和数据中的定量关系之间来回反复,相互核对,直到我们觉得我们有一个令人满意的结果。在这里,“令人满意”是一个重要的词:在应用环境中,通常你不能告诉你的经理,你将在三年内给他们正确的答案。你需要在短期内给他们最不坏的答案,同时规划数据收集工作,以改进多年来的答案。
在接下来的部分中,我将为本章的业务问题及相关的兴趣变量提供介绍。然后,我们将按照以下步骤逐步构建相应的 CD,并逐步进行各个部分的描述:
-
确定可能/应该包含在 CD 中的变量。
-
确定是否应该包含变量。
-
根据需要迭代这个过程。
-
简化图表。
让我们开始吧!
业务问题和数据设置
在本节中,我们将使用一个位于同一城市内的两家酒店的实际预订数据集。数据和我们将使用的包将在下一小节中描述,并且我们将深入研究理解感兴趣的关系。
数据和包
本章的GitHub 文件夹包含名为chap4-hotel_booking_case_study.csv的 CSV 文件,其中列出了表 4-1 中的变量。
表 4-1. 数据文件中的变量
| 变量名 | 变量描述 |
|---|---|
| NRDeposit (NRD) | 二进制 0/1,预订是否有不可退还押金 |
| IsCanceled | 二进制 0/1,预订是否取消 |
| DistributionChannel | 分类变量,取值为“直接”,“公司”,“TA/TO”(旅行代理/旅行组织),“其他” |
| CustomerType | 分类变量,取值为“瞬时”,“瞬时-团体”,“合同”,“团体” |
| MarketSegment | 分类变量,取值为“直接”,“公司”,“在线 TA”,“离线 TA/TO”,“团体”,“其他” |
| Children | 整数,预订中的儿童人数 |
| ADR | 数值,平均每日费率,总预订金额/天数 |
| PreviousCancellation | 二进制 0/1,客户之前是否取消过预订 |
| IsRepeatedGuest | 二进制 0/1,客户是否之前曾在酒店预订过 |
| Country | 分类,客户的国家/地区 |
| Quarter | 分类,预订季度 |
| Year | 整数,预订年份 |
在本章中,除了前言中提到的标准包装外,我们还将使用以下包装:
## R
library(rcompanion) # For Cramer V correlation coefficient function
library(car) # For VIF diagnostic function
## Python
from math import sqrt # For Cramer V calculation
from scipy.stats import chi2_contingency # For Cramer V calculation
理解感兴趣的关系
我们将尝试回答这个问题:“押金类型是否影响预订的取消率?”正如图 4-2 所述。
图 4-2. 感兴趣的因果关系
让我们从按押金类型分类的基础取消率开始(我喜欢同时查看绝对数和百分比,以防某些类别的数值非常小):
## R (output not shown)
with(dat, table(NRDeposit, IsCanceled))
with(dat, prop.table(table(NRDeposit, IsCanceled), 1))
## Python
table_cnt = dat_df.groupby(['NRDeposit', 'IsCanceled']).\
agg(cnt = ('Country', lambda x: len(x)))
print(table_cnt)
table_pct = table_cnt.groupby(level=0).apply(lambda x: 100 * x/float(x.sum()))
print(table_pct)
cnt
NRDeposit IsCanceled
0 0 63316
1 23042
1 0 55
1 982
cnt
NRDeposit IsCanceled
0 0 73.318048
1 26.681952
1 0 5.303761
1 94.696239
我们可以看到,绝大多数预订没有押金,取消率约为 27%。另一方面,有不可退还押金(NRDeposit)的预订取消率非常高。乍看之下,这种相关性令人惊讶。如果我们将政策改为对所有人“无需押金”,能减少取消率吗?行为常识告诉我们,更有可能的是,酒店为“高风险”预订请求不可退还押金,并且存在混杂变量,如图 4-3 中所示。
图 4-3。因果关系可能会受到干扰
我们很快就从 Figure 4-2 转到 Figure 4-3,但这是一个重要的步骤:Figure 4-2 中的 CD 代表了一个基本的商业分析问题,“押金类型与取消率之间的因果关系是什么?”另一方面,Figure 4-3 中的 CD 代表了一个更加明智的行为假设:“不可退还的押金似乎会增加取消率,但这种关系可能会受到我们需要确定的因素的干扰。”
使用 CD 进行行为数据分析的一个好处是它们是一个很好的协作工具。你组织中任何对 CD 有最基本了解的人都可以看到 Figure 4-3,并说,“嗯,是的,我们要求假期预订支付不可退还的押金,这些押金经常因为天气原因而被取消,”或者其他任何行为知识的片段,否则你无法得到。
在这一点上,最好的下一步是进行随机实验:将可退还或不可退还的押金分配给一组随机样本的客户,您将能够确认或否定您的行为假设。然而,您可能无法这样做,或者还没有准备好。与此同时,我们将尝试通过确定要包括的相关变量来解除关系的混淆。
确定要包括的候选变量
在尝试确定要包括的潜在变量时,自然的倾向是从您可以获得的数据开始。这种倾向是误导性的,类似于醉酒的人不是在他们丢失的地方找钥匙,而是在路灯下找,因为那里更亮。这样做可能会忽略最重要的变量,因为它们不在你的视线范围内。你也更可能只是看到数据中的变量,并不质疑它们是否是现实世界中发生情况的最佳表示。
例如,数据中的分类变量很可能代表的是业务中心的观点,而不是客户中心的观点,因此将一些类别聚合在一起或甚至将不同变量合并为新变量可能更合适。在我们的案例中,有一个变量MarketSegment和一个用于预订中儿童数量的变量。通过查看数据,我们可以确认很少有公司客户会带着孩子来。因此,我们可以考虑创建一个新的分类变量,其中包括“没有孩子的公司”,“没有孩子的非公司”和“有孩子的非公司”,将带有孩子的公司客户视为值得进行单独调查的异常值(也许是量身定制服务的基础?)。
我们将从行为类别开始,而不是陷入“你看到的就是所有”的偏见^2,从动作向后开始,详细了解第二章中概述的行为类别。
-
行动
-
意图
-
认知与情绪
-
个人特征
-
业务行为
最后,每个类别中的变量可能受到时间趋势的影响,如线性趋势或季节性,因此我们将在本节末尾默认添加这些内容。为了加强对定性直觉的关注,我们不会在下一节关于验证关系的内容之前查看任何数据。通过这些类别替换我们的先验取消风险(以及其他潜在混杂因素),我们的 CD 现在看起来像是 图 4-4,其中添加了一堆未观察到的变量到我们的两个感兴趣的变量中。
图 4-4. 包含潜在变量类别的更新 CD
对于每个类别,我们现在将寻找可能成为我们两个感兴趣的变量之一的原因的变量。
行动
在寻找要包含在操作类别中的变量时,我们通常试图识别客户过去的行为,这些行为可能会影响酒店是否需要非退款押金(NRD)。
在这种情况下,一个明显的候选者是客户是否以前取消过。也许酒店更有可能要求那些过去曾经取消的客户支付非退款押金。同样可以想象,导致他们过去取消的原因也更可能导致他们将来取消。
更普遍地说,当我们感兴趣的变量之一本身就是一个行为时,过去的行为通常是一个很好的预测变量,即使只是作为未观察到的个人特征的代理。我们的数据中有两个与过去行为相关的变量:PreviousCancellation 和 IsRepeatedGuest。图 4-5 展示了我们更新的 CD,未更改的部分为灰色。
图 4-5. 在操作步骤结束时更新的 CD
这并不意味着这些是唯一相关的过去行为;它们只是我想到的并且我们有数据的唯一一些。希望你能想到其他的!
意图
意图在数据分析中很容易被忽视,因为它们通常在我们现有的数据中丢失。然而,它们是行为的最重要驱动因素之一,而且通常可以通过对客户和员工进行访谈来揭示。因此,它们代表了不仅仅查看现有可用数据,而是采用“首先关注行为”的方法的好处的最佳例证。
在这种情况下,我能想到两个意图:旅行的原因和取消的原因(图 4-6)。
图 4-6. 将意图添加到我们的 CD
请注意,我将TripReason表示为潜在混杂因素,即,它与我们感兴趣的两个变量都有箭头相连,而CancellationReason只影响IsCanceled。此时,这只是一个行为直觉,即取消原因不会影响押金类型。我的理由是,在存款时并不知道取消原因。
图 4-6 还展示了 CD 在行为分析中的多功能性:即使我们不知道任一情况下的具体原因列表,我们也可以在 CD 中记录这两个潜在变量,稍后我们将通过访谈确定它们。暂时来看,我们可以注意到我们数据中的三个变量似乎受到旅行原因的影响,并可以作为这样包括进去:CustomerType、MarketSegment 和 DistributionChannel (图 4-7)。我们也将在个人特征的小节中重新审视这些变量。
图 4-7. 意图步骤结束时更新的 CD
认知与情感
在尝试为分析确定相关社会、心理或认知现象时,我喜欢放大特定的决策点。在这里,客户进行预订和取消预订时就是这样的决策点。
在第一个决策点,顾客可能不明白他们的押金是不可退的,或者他们可能会忘记。在第二个决策点,他们可能将押金视为沉没成本,不会努力保留他们的预订 (图 4-8)。
图 4-8. 认知与情感步骤结束时更新的 CD
个人特征
如 第二章 中所述,人口统计变量通常并非因其本身而有价值,而是作为其他个人特征(如人格特质)的代理。因此,在这一步骤中的挑战是抵制数据中存在的任何人口统计变量的影响,并坚持我们的因果行为思维模式。在查看人口统计变量之前,首先考虑特质是一个很好的方法。
特质
基于我们对人格心理学的了解,导致取消行为的良好候选特质是责任心和神经质:似乎不太有组织和更为放松的人更有可能取消预订 (图 4-9)。
图 4-9. 具有个性特征更新的 CD
人口统计变量
我们早前注意到,我们的酒店有企业客户和非企业客户预订。除了旅行和取消的原因外,这还影响一些其他个人特征,例如价格弹性和收入,这两者会影响我们感兴趣的两个变量。让我们将这些归为“财务特征”类别。它们可能在我们的数据中有所体现,例如CustomerType、MarketSegment和DistributionChannel,以及其他几个变量,如Children、ADR(即每晚的平均价格)和Country(图 4-10)。
图 4-10. 使用人口统计变量更新的 CD
商业行为
商业行为在我们调查的关系中往往起着重要作用,但很容易被忽视和难以整合。
在这个例子中,业务规则显然起着重要作用,因为它们决定了哪些客户需要提供 NRD。从这个意义上说,它们影响CD中进入NRDeposit的所有箭头。我们可以根据它采取多种方式来考虑这种影响的形式。
一个业务规则可以明确地连接两个可观察变量(可能包括我们感兴趣的变量)。例如,在这里,我们可以想象一个业务规则,规定所有之前取消预订的客户现在必须提供 NRD。通过列出所有这些规则,我们可以确认或否认从一个观察变量直接进入NRDeposit的所有箭头。这也可能揭示涉及业务规则但尚未包含在我们数据中的变量:例如,我们可以想象,如果客户在预订时未提供身份证明,则必须支付 NRD。我说“尚未包含在我们数据中”,因为根据定义,任何作为业务规则一部分的标准都是可观察的,即使它没有被数据库捕获。^(3)
或者,一个业务规则可能最好表示为一个额外的中介变量。例如,如果在圣诞节期间的所有预订必须由 NRD 支持,我们可以创建一个ChristmasHolidays二元变量,该变量与NRDeposit相互作用。那个变量将会调节其他变量(如CustomerType或Children)对NRDeposit的影响。
我们不知道我们示例中的两家酒店应用了什么业务规则,因此我们必须将该子部分留作我们希望通过后续访谈探索的内容。
时间趋势
最后,我们的数据中可能存在一些全局时间趋势,例如需求 NRD 的预订数量逐步增加,以及与此同时的取消率逐步增加,但二者无关。此外,酒店行业的季节性非常强烈,可能存在一些周期性方面,我们希望能够捕捉到(图 4-11)。
图 4-11. 时间趋势步骤结束时的更新 CD
注意
在这种情况下,年份 和 季度 变量仅捕捉趋势和周期。有时,也可以考虑包括二元变量以解释使某年突出或标志性变化的特定事件。一个明显的例子是 COVID-19,在灰尘落定后,它将被证明在某些行业是暂时的起伏,但在其他行业则是根本性的变革的开始。
加上这最后一个变量之后,图 4-11 现在有一系列候选变量,一些是可观察的,一些不是。在下一节中,我们将看到如何确认保留哪些可观察变量。
根据数据验证要包含的可观察变量
让我们看看我们在识别阶段结束时作为候选的可观察变量(图 4-12)。
图 4-12. 我们 CD 中的可观察变量,按类别(左)和数字(右)分割
在这个具体的例子中,所有这些可观察变量暂时都与我们感兴趣的两个变量有关。这是默认情况,但在某些情况下,您可能有非常强的先验理由,只将预测变量与您感兴趣的一个变量连接起来(例如,这是我们一些未观察到的变量的情况)。如果有疑问,我会谨慎一些,并包括这两种连接。
在 图 4-12 中,可观察变量被分为分类(CD 左侧)和数字(CD 右侧)。这两种数据类型需要不同的定量工具,因此我们将依次查看它们。
数字变量之间的关系
我们的第一步将是查看数据中所有数字变量的相关矩阵。一个有用但不那么干净的技巧是将二元变量转换为 0/1(如果它们还没有以这种格式存在),这样你可以将它们视为数字变量。这使你能够了解变量之间的相关性,但不要告诉你的统计学朋友!
查看你感兴趣的两个变量的行,可以让你看到它们与数据集中所有数值变量的相关性如何。一眼就能看到它还会显示出这些其他变量之间的任何大相关性。与感兴趣的因果相关性的强度可以帮助我们决定如何处理特定变量。
“强有多强?”这取决于情况。记住我们的目标是正确测量我们感兴趣的原因对我们感兴趣的效果的因果效应;作为一个经验法则,你可以认为与你感兴趣的原因和效果之间具有相同数量级(即逗号后第一个非零数字之间的零个数)的任何相关性都是“强”的。
正如你在 图 4-13 中所看到的,我们感兴趣的两个变量之间的相关系数为 0.16。第一列指示了与 NRDeposit 的相关性,第二列指示了与 IsCanceled 的相关性。PreviousCancellation 与我们感兴趣的变量的相关系数相同数量级(分别为 0.15 和 0.13)。类似地,ADR 与 IsCanceled 的相关系数在该标准下是显著的(0.13)。
“数量级”阈值的包含并不科学,可以根据手头变量的数量来调节松紧程度。如果少数变量通过了阈值而其他变量接近该阈值,那么包含它们是完全可以接受的。
你可能会反对说,一个变量与我们感兴趣的变量之一的相关性可能很低,但仍然是需要考虑的混杂因素。这是正确的,根据强有力的理论基础,即使与我们感兴趣的变量的相关性很弱,你也可以包含一个变量。然而,为了实际目的,通常应重点关注与我们感兴趣的变量至少具有中等相关水平的变量。
图 4-13. 数字和二进制变量的相关性矩阵
如果我们在 图 4-13 中包括所有绝对值为 0.1 或以上的相关性,并排除其他相关性,那么我们的 CD 现在就如同 图 4-14 中所示。
图 4-14. CD,更新了数字和二进制可观察变量的箭头
虽然相关矩阵只给出了对称系数,可以代表任何方向的箭头,但我运用了一些常识和业务知识来假设箭头的方向。酒店公司对时间没有掌控,所以我们可以假设Years是与它相关的变量的原因而不是结果,尽管这种影响可能通过中间变量(如随时间的社会趋势)传递。IsRepeatedGuest是PreviousCancellation的先决条件;因为它涉及过去事件,它也必须是ADR的原因或它们共享一个共同的原因。
注意
不要忘记这只是一个暂时的CD:
-
这些相关性中有一些可能是假阳性(系数看起来比实际强,纯粹是因为随机性),反之亦然,一些较小的相关性可能是假阴性。
-
在这个阶段,我们暂时将相关性视为因果关系的证据。我们在图 4-14 中画的一些箭头本身可能反映了混杂关系。在充分衡量NRDeposit与IsCanceled之间的关系之后,我们可能希望或需要对其他关系(例如IsRepeatedGuest和ADR之间的关系)做同样的事情。
分类变量之间的关系
对于分类变量,同样的逻辑适用,唯一的复杂之处在于我们不能使用皮尔逊相关系数。然而,已经为分类变量开发了一个变体,克莱默 V。在 R 中,它是在rcompanion包中实现的:
## R
> with(dat, rcompanion::cramerV(NRDeposit, IsCanceled))
Cramer V
0.165
您可以看到,在二元变量的情况下,它产生的结果与直接应用皮尔逊相关系数的结果非常接近。不幸的是,它在 Python 中没有实现,但我提供了一个计算它的函数:
## Python
def CramerV(var1, var2):
...
return V
V = CramerV(dat_df['NRDeposit'], dat_df['IsCanceled'])
print(V)
0.16483946381640308
图 4-15 显示了相应的相关矩阵。
这种相关性产生了多种见解。查看底部行,我们可以看到Quarter与其他任何东西都没有明显相关性。这表明季节性对我们的分析不是一个相关因素。相反,可能一个季度作为时间单位太粗略,我们需要放大到特定的时间段,如圣诞节假期。我们可以从我们的 CD 中删除Quarter,并用一个未观察到的变量Seasonality替换它,作为未来研究的线索。
我们的三个客户段变量 CustomerType、MarketSegment 和 DistributionChannel 显示出混合模式,它们之间有些非常强的和一些弱的相关性。同样,它们与其他变量的相关性也参差不齐:例如,这三个变量中的每一个与 Country 的相关性都在 0.1X 数字范围内,但其中两个与 RepeatedGuest 的相关性较高(0.35 和 0.4),而第三个的相关性仅为 0.11。这表明这些变量不仅可以互换,而且它们捕捉了相同行为的某些方面。这需要进一步调查,并很可能创建新的变量。
图 4-15. 用于分类和二进制变量的相关矩阵
应用这些见解和仅包含大于 0.1 的相关性的相同标准后,我们的 CD 现在看起来像是 Figure 4-16。
图 4-16. 用于分类和二进制可观察变量的更新箭头的 CD
我们的 CD 开始变得适度复杂,但大部分可以通过几个行为参数来总结:
-
左侧的四个变量反映个人特征,它们彼此之间显著相关。我选择用双向箭头来反映这些相关性,因为试图确定箭头的方向是毫无意义的:CustomerType 不会比 MarketSegment 更多地导致另一种情况发生。实际上,在进行必要的访谈后,我们应该创建捕捉更深层次个人特征的新变量。
-
个人特征似乎会影响我们感兴趣的变量,可能导致一些混杂。
-
个人特征似乎影响了过去的行为 IsRepeatedGuest 和 PreviousCancellation。(同样,我基于业务知识对效果的方向做出假设。乍看之下,取消先前预订是否会导致某人改变国家或市场细分似乎不太可能。)一旦我们澄清了发挥作用的更深层个人特征的性质,我们可能决定将这些过去的行为纳入某些个人特征变量之下,隐式地创建行为人物(例如,“经常出差的商旅者(Y/N)”)。
数值和分类变量之间的关系
测量数值和分类变量之间的相关性比在同质类别内测量相关性更加繁琐。
说数值变量与分类变量之间存在相关性等同于说数值变量在分类变量的各类别间平均值不同。我们可以通过比较数值变量在分类变量的各类别间的平均值来检查是否如此。例如,我们预计客户的财务特征可能会影响预订的平均每日费率。最好在构建更好的客户分割变量之后再探索这种关系,但为了论证的目的,我们可以使用CustomerType:
## R (output not shown)
> dat %>% group_by(CustTyp) %>% summarize(ADR = mean(ADR))
## Python
dat_df.groupby('CustTyp').agg(ADR = ('ADR', np.mean))
Out[10]:
ADR
CustTyp
Contract 92.753036
Group 84.361949
Transient 110.062373
Transient-Party 87.675056
我们可以看到,平均每日费率在不同客户类型之间有显著变化。
注意
如果你不确定这些变化是否真正显著,或者它们只是反映了随机抽样误差,你可以使用 Bootstrap 为它们建立置信区间,如后文在第七章中解释的那样。
在我们的例子中,有两个数值变量,我们可能想要检查它们与分类变量的相关性:ADR和Year。我们发现ADR在不同客户类型之间有显著变化,但这些变化在时间上相对稳定,这就导致了我们的最终可观测变量的 CD(图 4-17)。
在这一点上,我想重申并扩展我早些时候的警告:在验证可观测变量时,我已经默认假设相关性等于因果关系。但也许这些关系本身是混杂的:个人特征变量与PreviousCancellation之间的相关性可能完全是由个人特征变量与IsRepeatedGuest之间的关系造成的。
图 4-17. 可观测变量的最终 CD
举例来说,假设商务客户更有可能是重复客户。因此,他们看起来也可能比休闲客户有更高的取消率,即使在重复客户中,商务客户和休闲客户的取消率完全相同。
你可以把这些因果假设看作是善意的谎言:它们并非真实,但没关系,因为我们并不试图构建真实完整的 CD,我们只是试图解开NRD与取消率之间的关系。从这个角度来看,把箭头的方向搞对比有关联变量的不相关关系*重要得多。如果你仍然持怀疑态度,下一章的一个练习将进一步探讨这个问题。
逐步扩展因果图
在确认或否定基于数据的可观测变量之间的关系之后,我们得到了一个初步完整的 CD(图 4-18)。
图 4-18. 暂时完成的 CD,包括可观察和不可观察的变量,在可读性上将个人特征变量分组到一个标题下
从这里开始,我们将通过识别未观察到的变量的代理,以及进一步识别当前变量的原因,来迭代地扩展我们的 CD。
识别未观察到的变量的代理
未观察到的变量代表一种挑战,因为即使通过访谈或 UX 研究确认了它们,也不能直接在回归分析中考虑它们。
我们仍然可以通过访谈和研究来尝试在一定程度上减轻它们。例如,我们可能会发现,责任心确实与取消率较低相关,但同时也与请求确认电子邮件相关(图 4-19)。
图 4-19. 识别未观察到的变量的代理
当然,请求确认电子邮件并不仅仅是由责任心引起的——它也可能反映出意图的严肃性,对数字渠道的不熟悉等等。反过来,它可能通过提供有关预订的易于获取的信息而单独降低取消率。无论如何,如果我们发现这种行为与取消率呈负相关,我们可以利用这一洞察,例如向没有选择接收确认电子邮件的客户发送短信提醒。
通过头脑风暴和通过研究验证潜在未观察到的变量的代理,我们为可观察变量之间提供了有意义的连接。知道RequestedConfirmation通过Conscientiousness与IsCanceled相连接,为否则将是原始统计规律的行为基础提供了理由。
识别进一步的原因
我们还将通过识别“外部”变量的原因来扩展我们的 CD,即当前在我们的 CD 中没有任何父变量的变量。特别是,当我们有一个影响我们感兴趣的原因(可能间接影响)但不影响我们感兴趣的效果的变量A,以及另一个相反地影响我们感兴趣的效果但不影响我们感兴趣的原因的变量B时,A和B的任何联合原因会在我们的 CD 中引入混淆,因为该联合原因也是我们两个感兴趣变量的联合原因。
在我们的例子中,唯一没有任何父变量(可观察或不可观察)的可观察变量是Year,显然它不能有一个(除了可能是物理定律?),所以这一步不适用。
迭代
当您引入新变量时,您将为代理和进一步的原因创造新的机会。例如,我们新引入的RequestedConfirmation可能会受到Conscientiousness和TripReason的影响。这意味着您应继续扩展您的 CD,直到看起来能够涵盖您能想到的所有相关变量及其相互关系。
然而,这一过程存在显著的递减回报:随着您将 CD“向外扩展”,新添加的变量往往与您感兴趣的变量之间的相关性越来越小,因为沿途的噪声太多。这意味着考虑它们将逐渐解除您感兴趣的关系。
简化因果图
一旦决定停止迭代扩展 CD,最终步骤就是对其进行简化。事实上,您现在有一个希望准确而完整的图表,用于实际目的,但可能结构不一定最有助于满足业务需求。因此,我建议进行以下简化步骤:
-
当中间变量不重要或未被观察时,请折叠链条。
-
当您需要查找观察变量或想要跟踪另一个变量与图表的关系方式时,请扩展链条。
-
当您认为单个变量会包含有趣信息时(例如,与您感兴趣的变量的相关性主要由特定切片驱动),请切片变量。
-
结合变量以增强图表的可读性或当不同类型之间的变化并不重要时。
-
当您发现循环时,请通过引入中间步骤或确定重要关系的方面来打破它们。
在我们的示例中,我们可能会决定IsRepeatedGuest、Children和Year并未提供比PreviousCancellation和ADR更多的价值。事实上,我们可以放弃这三个变量,因为它们不会混淆我们感兴趣的关系(图 4-20)。
图 4-20. 简化后的最终 CD
您应该得到一个干净且(在某种程度上!)可读的图表,尽管它可能比我们迄今见过的图表要大一些。
如果这一过程看起来很长而有些乏味,那是因为它确实如此。深入了解您的业务非常重要,这是能够在无法进行实验时进行客户(或员工)行为因果推断的代价。
幸运的是,这个过程是非常累积和可转移的。一旦您为某项分析完成了这个过程,您对于对您业务重要的因果关系的认识就可以被重用于另一个分析。即使您第一次进行这个过程时不深入,您也可以只专注于一类混杂因素和原因;下一次您运行这个分析或类似的分析时,您可以从离开的地方继续,并对另一类进行更深入的挖掘,也许是关于客户体验的不同方面进行访谈。同样,一旦有人经历了这个过程,新的团队成员或员工可以非常容易和快速地获得相应的知识,并通过查看结果 CD 甚至只是记住要牢记的相关变量列表继续工作。
结论
用陈词滥调的话来说,构建 CD 是一门艺术和一门科学。我已尽力提供尽可能清晰的配方来实现这一点:
-
从您试图衡量的关系开始。
-
确定要包括的候选变量。也就是说,利用您的行为科学知识和业务专业知识来识别可能会影响您感兴趣的任一变量的变量。
-
根据数据中的相关性确认要包括哪些可观察变量。
-
通过不断添加可能的未观察变量的代理以及进一步增加到目前为止已包含的变量的进一步原因,逐步扩展您的 CD。
-
最后,通过删除无关的关系和变量来简化您的 CD。
在这样做的过程中,始终牢记您的最终目标:衡量您感兴趣的原因对您感兴趣的效果的因果影响。我们将在下一章中看到如何使用 CD 来消除分析中的混杂因素,并获得对该影响的无偏估计。因此,最好的 CD 是那种能让您充分利用当前可用数据并推动有益的进一步研究的 CD。
^(1) Nuno Antonio, Ana de Almeida, 和 Luis Nunes, “Hotel booking demand data sets,” Data in Brief, 2019. https://doi.org/10.1016/j.dib.2018.11.126
^(2) 这个色彩缤纷的标签是行为科学家丹尼尔·卡内曼推广的。
^(3) 想一想:否则规则会如何实施?
第五章:使用因果图解除数据分析中的混淆
因果关系对我们理解世界是如此基础性,以至于就连幼儿园的孩子也能直观地把握。然而,这种直觉和我们的数据分析可能会被混淆所误导,正如我们在第一章中看到的那样。如果我们不考虑我们感兴趣的两个变量的联合原因,那么我们会错误地解释正在发生的事情,而我们感兴趣的原因的回归系数也会出现偏差。然而,我们也看到了考虑错误变量的风险。这使得确定包括还是不包括哪些变量成为解除数据分析中最关键的问题之一,更广泛地说,是因果思维中最关键的问题之一。
可惜这是一个复杂的问题,各位作者提出了各种更多或更少扩展性的规则。在扩展性较高的一端,有一些规则偏向于谨慎和简单——你可以将它们看作是合理的“包罗万象”方法。在另一端,有些规则试图准确找出所需的变量,但这样做会增加复杂性和概念上的要求。
有趣的是,回答这个问题并不需要任何数据。也就是说,你可能想要或需要数据来建立正确的因果图,但一旦你拥有了正确的因果图,就无需查看任何数据来识别混淆。这使我们直接处于我们框架的因果图到行为边缘(图 5-1),因此在本章中我们不会使用任何数据。
相反,我将向您展示两个解除混淆的规则,它们各有利弊,“析取性因果准则”和“后门准则”,这样您可以根据您的情况选择使用哪一个。在下一节中,我将设立我们的业务问题,然后依次看看如何应用这两个准则。
图 5-1。本章讨论行为与因果图之间的关系
业务问题:冰淇淋和瓶装水销售
我们本章的起点是 C-Mart 市场部发布的内部报告,题为“健康顾客”,追踪了向健康产品长期趋势的变化。基于该报告,C-Mart 推出了名为“您需要配有天然泉水的冰淇淋吗?”的快餐和冰淇淋特许经营的营销活动。我们的分析目标是获得冰淇淋销售对瓶装水销售影响的无偏估计。
通过利用现有数据和专用调查,市场分析团队建立了以下因果图,我们感兴趣的关系用粗体标出(图 5-2)。
图 5-2. 我们业务情境的 CD
这个 CD 相对复杂,不明显的混杂因素可能潜藏其中,因此让我们将其分解成更易处理的部分(Figure 5-3)。
图 5-3. 将我们的 CD 分解为概念块
这两个概念块仅是理解的教学工具:它们既不是排他的(我们感兴趣的关系同时包含在内),也不是穷尽的(有些箭头两者都没有涵盖)。
我们的第一个块位于 CD 的左上角,显示了冰淇淋销售和汉堡包和薯条销售之间通过客户数量的连接。在客流量更大和更繁忙的日子里,总体销售往往更高,这使得各种变量同时变动。此外,店员已被指示在冰淇淋和薯条销售中提供“您要不要来杯矿泉水?”的提示,以及在汉堡包销售中提供“您要不要薯条?”的提示。
我们的第二个块位于 CD 的右下角,显示了两个在调查中已确定但在个别销售水平上不可用的因素的影响:顾客的平均年龄(年龄较小的顾客和有孩子的顾客更有可能购买含糖产品)和顾客的健康意识(有健康意识的顾客更倾向于购买水,而不倾向于购买苏打水,在其他一切条件相等的情况下)。
注意
在现实生活中的设置中,可以根据分析的需要自由地将大型或复杂的 CD 分解为块。只要在最后进行一些整理并检查从你感兴趣的原因到你感兴趣的效果的路径不包含在任何块中:你必须确保它们不会生成混杂,因为它们本身可能不是混杂,或者在分析概念块时已经处理了它们的混杂。
在这种情况下,目前尚不清楚我们感兴趣的冰淇淋销售与瓶装水销售之间是否存在混杂,以及如何解决。从技术上讲,在我们的 CD 中,我们没有任何同时导致这两者的共同原因。让我们转向我们的决策规则。
分离因果标准
分离因果标准是我们解除混杂的第一决策规则。像一个过于保护的父母一样,它超出了严格需要去除混杂的范围,使得它更简单易懂且易于应用。
定义
分离因果标准(DCC)指出:
在我们感兴趣的关系中,添加所有直接导致我们感兴趣的变量的回归变量,除了它们之间的中介变量,可以消除任何混杂。
第一个块
让我们从我们的冰淇淋例子的第一个区块开始分解这个定义:
1. 所有直接导致我们感兴趣的变量的变量
这意味着我们应该包括任何只是直接导致冰淇淋销售的变量,例如顾客数。我们还应该包括任何只导致瓶装水销售的变量,例如薯条销售。最后,我们应该包括任何两者都导致的原因,但在这种情况下我们没有这样的变量。
2. 除了它们之间的中介者
中介者是“传输”我们感兴趣的原因对我们感兴趣的效果的影响的变量。也就是说,它们是我们感兴趣的原因的子代和我们感兴趣的效果的父代。我们将在第十二章更详细地讨论中介者,所以现在我只想指出,我们需要排除它们在我们的控制列表之外,因为包括它们将取消我们试图捕捉的一些因果关系。在冰淇淋销售和瓶装水销售之间我们没有中介者(即,一个变量既是前者的子代又是后者的父代),所以在这一点上我们做得很好。
3. 消除我们感兴趣的关系的任何混杂
如果我们包括第 1 点描述的变量但不包括第 2 点描述的变量,那么我们对冰淇淋销售对瓶装水销售效应的回归系数将不受我们第一个区块中的变量的混杂影响。
需要注意的是,DCC 是一个充分但不是必要的规则:应用它足以消除混杂,但我们并不一定需要。例如,如果我们有一个变量只是我们感兴趣的一个变量的原因,并且我们确信它与任何其他变量绝对没有任何联系,那么它不能是混杂因素,我们也不需要将其包括以消除混杂。
但当你没有这种确定性时,DCC 会让你免于苦苦思索哪个变量导致了哪个,以及什么是混杂因素。你可能会忽略一些变量之间的关系,或者认为有关系而实际上没有;你可能会认为一个变量是混杂因素,而实际上不是,反之亦然。只要你正确确定一个变量是否与你感兴趣的两个变量之一有直接因果关系,你就能正确决定是否将其包含在内。
例如,让我们看看从顾客数到瓶装水销售量的链路,途径汉堡销售和薯条销售。我们在第二章看到,链路是一个因果图,通过直线箭头连接变量(图 5-4)。
图 5-4. 我们第一个区块中的扩展链
当然,我们可以用箭头表示这条链条向上、向下或从右到左;关键是它们都是朝着同一个方向前进的,这使我们能够折叠这条链条,并将NumberOfCustomers视为BottledWaterSales的直接原因。但是NumberOfCustomers确实是IceCreamSales和BottledWaterSales的联合直接原因,也是它们关系的混杂因素(图 5-5)。
图 5-5. 折叠上链使 NumberOfCustomers 成为 BottledWaterSales 的直接原因
根据 DCC 的定义,将其应用于这个第一个区块意味着在我们的回归中包括NumberOfCustomers和FrenchFrySales作为控制变量。从图 5-5 中可以看出,这样做有效地中和了上链的混杂效应。更一般地说,因为链条可以随意扩展或折叠,所以最终是我们感兴趣的两个变量的原因(因此也是混杂因素)的变量可能被隐藏在 CD 中的一系列中间变量之后。
DCC 的美妙之处在于,即使市场团队忽略了从NumberOfCustomers到BottledWaterSales的上链,并且它没有被包含在 CD 中,包括NumberOfCustomers和FrenchFrySales的要求也会处理混杂问题。另一方面,根据图 5-5,我们可以看到仅包括NumberOfCustomers就足够了,而包括FrenchFrySales也是多余的。这是我在章节介绍中提到的权衡之一:DCC 是一个广泛的规则,即使在 CD 中存在错误,也会消除混杂,但代价是冗余和需要更多数据。现在让我们转向 CD 中的第二区块。
第二区块
第二区块中的变量之间存在更复杂的关系(图 5-6)。
图 5-6. 第二区块
在这里,我们除了关注的变量外,唯一拥有数据的变量是SodaSales。它既不是IceCreamSales也不是BottledWaterSales的原因,因此 DCC 不会要求将其包括在回归中。然而,它会要求包括AverageCustomerAge和CustomerHealthMindset,而我们没有这些数据。这并不一定意味着混杂正在发生,但我们无法确定它没有发生。这是 DCC 的最大局限性:如果你没有关于你感兴趣的变量的一些原因的数据,它就无法帮助你。现在让我们转向背门准则。
背门准则
背门准则(BC)构成了控制混杂因素的另一种规则。与分离因果准则相比,它提供了非常不同的权衡:理解起来更复杂,并且需要具有完全准确的 CD,但它聚焦于实际的混杂因素,并且不需要在我们的回归中包含任何多余的变量。从形式上讲,控制这一规则确定的变量就足以消除混杂因素。
定义
背门准则表明:
如果两个变量之间存在至少一个未阻塞的非因果路径,从我们感兴趣的原因开始,它们之间的因果关系就会受到干扰。
相反,要消除所有混杂因素,我们需要阻断所有非因果路径,从我们感兴趣的原因开始。
要理解这个定义,我们需要介绍或回顾一系列次要定义,在我们的示例中,与我们将在此重复的 CD 上下文相关(图 5-7)。
图 5-7. 我们业务情况下的 CD
首先,让我们回顾一下“路径”的定义:如果它们之间有箭头,不管箭头的方向如何,并且在这条路上没有变量出现两次,我们称之为存在路径。链是沿着三个或更多变量的路径,分叉和碰撞也是如此。从这个意义上说,CD 中的任意两个变量都至少通过一条路径相连,通常是几条。
例如,在我们的 CD 中,NumberOfCustomers 和 BottledWaterSales 之间有七条不同的路径:
-
NumberOfCustomers → IceCreamSales → BottledWaterSales
-
NumberOfCustomers → BurgerSales → FrenchFrySales → BottledWaterSales
-
NumberOfCustomers → BurgerSales → FrenchFrySales ← CustomerHealthMindset → BottledWaterSales
-
NumberOfCustomers → BurgerSales → FrenchFrySales ← CustomerHealthMindset → SodaSales ← AverageCustomerAge → IceCreamSales → BottledWaterSales
-
NumberOfCustomers → SodaSales ← CustomerHealthMindset → BottledWaterSales
-
NumberOfCustomers → SodaSales ← CustomerHealthMindset → FrenchFrySales → BottledWaterSales
-
NumberOfCustomers → SodaSales ← AverageCustomerAge → IceCreamSales → BottledWaterSales
请注意,NumberOfCustomers → BurgerSales → FrenchFrySales ← CustomerHealthMindset → SodaSales ← NumberOfCustomers → IceCreamSales → BottledWaterSales 不是一条路径,因为变量 NumberOfCustomers 在其中出现了两次,这是不允许的。
如果它是一个链,即其中所有的箭头都是朝着同一个方向的,那么路径就是“因果”的。标签“因果”指的是路径之间的因果关系,如果其中一个变量通过该路径导致另一个变量,则该路径是因果的。
前述列表中的路径 1 和 2 是因果关系的:它们是链条,代表NumberOfCustomers影响BottledWaterSales的通道。其他路径是非因果关系,因为它们每个都至少包含一个对撞机或叉路。请记住,对撞机是当两个变量导致同一个变量时的情况,而叉路是当两个变量被同一个变量导致时的情况。例如,路径 3 和 4 都在FrenchFrySales周围有一个对撞机,路径 4 还在SodaSales周围有一个对撞机,以及CustomerHealthMindset和AverageCustomerAge周围有两个叉路。
最后,我们将说,在我们的 CD 中,两个变量之间的路径如果是阻塞的,那么它要么是:
-
沿着那条路径的中介变量之一包括在我们的回归中,并且它不是一个对撞机,或者
-
在这条路径中,有一个对撞机,其核心变量未包含在我们的回归中。
否则,那条路径是未阻塞的。
阻塞或未阻塞的概念很难理解,因为它实际上包含了两件不同的事情:路径本身是否混杂以及它是否在我们的回归中被控制。你可以将未阻塞视为{混杂 且 未控制},阻塞为{非混杂 或 已控制}。
混杂的最终根本原因始终是联合原因(图 5-8,左面板)。但是,由于我们可以随意折叠或扩展链条,这个混杂因素可能“隐藏”在许多中介变量背后(图 5-8,中间面板)。然而,我们无法在链条中间折叠对撞机,因为它会破坏箭头的方向(图 5-8,右面板)。因此,对撞机阻止了混杂,除非我们在回归中包括它,这样就中和了它。
图 5-8。混杂因素是联合原因(左面板),但它可以隐藏在中介变量背后(中间面板),而对撞机阻止了我们折叠链条,因此消除了混杂(右面板)
第一个区块
现在我们已经看到了 BC 的定义,让我们看看它如何适用于因果图的第一个区块中的变量。记住,DCC 要求我们在回归中包括NumbersOfCustomers和FrenchFrySales作为控制变量。
我们可以从条件“从指向我们感兴趣的原因的箭头开始”开始应用 BC,这意味着我们感兴趣的原因的所有原因,这种情况下是IceCreamSales。在第一个区块中,只有一个,即NumberOfCustomers。
对于通过 NumberOfCustomers 的每条路径,让我们应用 BC 的其他条件。第一块内的 IceCreamSales 到 BottledWaterSales 的路径通过 NumberOfCustomers 是 IceCreamSales ← NumberOfCustomers → BurgerSales → FrenchFrySales → BottledWaterSales。这是 DCC 捕获并通过在我们的回归中包括 NumberOfCustomers 和 FrenchFrySales 来控制的路径。让我们检查一下条件:
-
那条路径是非因果的吗?是的,因为围绕 NumberOfCustomers 的分叉。
-
默认情况下那条路径被阻断了吗?不是的,因为在那条路径中没有碰撞器,并且我们尚未包括任何变量作为控制。
因此,这条路径混淆了我们感兴趣的关系,我们需要通过在我们的回归中包括该路径的任意一个非碰撞器变量来控制它。也就是说,BC 告诉我们,包括任何一个 (NumberOfCustomers, BurgerSales, FrenchFrySales) 就足以控制这条路径。然而,我个人建议选择哪个变量:每当你能包括那条路径的第一个变量,即你感兴趣的原因的原因,你应该这样做。在我们的例子中,这将是 NumberOfCustomers。选择这个原因的原因是它也会自动控制起始于该变量的任何其他混淆路径,这意味着我们甚至不必检查起始于该变量的任何其他路径。
正如你所看到的,BC 比 DCC 更经济,通过利用我们对该块中变量的完整和正确因果图的假设:而 DCC 要求我们包括 NumberOfCustomers 和 FrenchFrySales,BC 只需要包括 NumberOfCustomers,我们可以不检查任何其他路径就将第一块留下。
第二个阻止
请记住,DCC 对第二块中的变量保持沉默:我们不能包括变量 AverageCustomerAge 和 CustomerHealthMindset,因为我们没有相应的数据,因此我们不确定那里是否存在未受控制的混淆。BC 将使我们能够更加确定和精确。
AverageCustomerAge 是我们感兴趣的因果关系 IceCreamSales 的一个原因,因此让我们来检查路径 IceCreamSales ← AverageCustomerAge → SodaSales ← CustomerHealthMindset → BottledWaterSales:
-
那条路径是非因果的(即不是一个链):它在 AverageCustomerAge 周围有一个分叉,在 SodaSales 周围有一个碰撞器,然后在 CustomerHealthMindset 周围有另一个分叉。
-
默认情况下它被阻塞了吗?是的,因为围绕 SodaSales 的碰撞器。
换句话说,这条路径并不是混杂因素,我们在回归中不需要控制它。更甚的是,将 SodaSales 包含在我们的回归中实际上会创建混杂,通过解除这条路径!
这个在对撞机周围有两个叉子的配置非常特殊,以至于有一个名字:M 型模式,我们可以通过重新排列我们的 CD(图 5-9)看到。不可否认,这个例子可能看起来有些刻意。但是,如果你觉得它过于人为和不真实,请注意,它是根据《为什么之书》中关于 2006 年实际烟草诉讼的一个例子改编的,那里包括了一个控制座椅安全带使用对估计吸烟对肺癌影响的偏差。
图 5-9. 在我们的 CD 中可视化 M 型模式
此外,因为所有从IceCreamSales到BottledWaterSales的路径都通过AverageCustomerAge也经过SodaSales,只要我们在回归中不包括SodaSales,它们都会被阻断。
在 CD 中找到混杂因素是一门科学:应用规则,你就会知道。但它也有它的捷径:已经确定了通过两个IceCreamSales的原因存在混杂的可能性,并确保任何混杂会被阻断,我们就不必检查每一条通过这两个原因到IceCreamSales的路径。当你建立和操作更多的 CD 时,你会学会发展一种直觉。如果你有疑问,你随时可以检查每条可能的路径的规则,确保你是正确的。
后门准则比排除性因果准则更精确,后门准则对我们的 CD 中的错误不那么鲁棒。为了论证起见,假设营销团队在构建 CD 时犯了一个错误,并错误地得出结论,即SodaSales导致CustomerHealthMindset而不是反过来(在这种特定情况下,从行为角度来看这并不太合理,但请忍耐),导致了图 5-10 中所代表的关系。
图 5-10. 第二个块如果有错误会是什么样子
在这种情况下,BC 会让我们错误地认为有混杂因素在起作用,并在我们的回归中包括SodaSales,引入了在此之前没有的混杂因素。
总结一下,BC 识别出通过两个直接导致IceCreamSales的原因有两条潜在的混杂途径。通过在我们的回归中包括NumberOfCustomers,我们处理了所有可能通过它产生的混杂路径。另一方面,通过不包括SodaSales,我们放过了一个碰撞器,通过AverageCustomerAge来处理任何通过IceCreamSales的混杂因素。
结论
揭示因果关系的混淆是行为数据分析的核心问题之一,也是解决“相关不等于因果”的泥潭的办法。在本章中,我们看到了两条混淆规则,分离因素准则 和 背门准则。第一条准则采取的立场是包括我们感兴趣变量的所有直接原因(除了中介因素)。第二条准则在应用中更为精准,直接针对混淆的机制,但在处理中错误容忍度较低。
第三部分:稳健的数据分析
理想的数据是大型、完整的,并且具有规则的形状(例如,数值变量的情况下符合正态分布)。这是你在入门统计课程中看到的数据。现实生活中的数据通常没有那么方便,特别是在处理行为数据时。
在第六章中,我们将看到如何处理缺失数据。虽然在数据分析中缺失数据是常见的,但行为数据增加了一层复杂性:缺失的数值通常与个体特征和行为相关,这在我们的分析中引入了偏差。幸运的是,使用 CDs 将允许我们尽可能地识别和解决这种情况。
在第七章中,我们将讨论一种名为 Bootstrap 的计算机模拟类型。这是一种非常多才多艺的工具,特别适用于行为数据分析:当处理小型或形状奇怪的数据时,它允许我们适当地衡量估计值周围的不确定性。此外,在设计和分析实验时,它提供了一种替代 p 值的方法,这将使我们的生活更加简单。
第六章:处理缺失数据
在数据分析中,缺失数据是常见的。在大数据时代,许多作者甚至更多的从业者将其视为一个次要的困扰,几乎没有太多思考:只需过滤掉缺失数据的行——如果你从 1200 万行减少到 1100 万行,那有什么大不了的呢?这仍然为您提供了足够的数据来运行您的分析。
不幸的是,过滤掉含有缺失数据的行可能会在你的分析中引入显著的偏差。比如说,老年客户更有可能存在缺失数据,因为他们较少设置自动付款;如果过滤这些客户,你的分析就会偏向于年轻客户,在过滤数据中会过度代表他们。其他处理缺失数据的常见方法,比如用该变量的平均值替换,也会引入它们自己的偏差。
统计学家和方法学家已经开发出了方法,这些方法的偏差要小得多,甚至没有偏差。然而,这些方法尚未被广泛采纳,但希望本章可以帮助您走在前列!
缺失值理论根植于统计学,可能会变得非常数学化。为了使本章节的学习更具体化,我们将通过一个模拟数据集来探讨 AirCnC。在业务背景下,市场部门为了更好地了解客户特征和动机,向三个州的 2,000 名客户发送了一封调查问卷,并收集了以下信息:
-
人口统计特征
-
年龄
-
性别
-
州(只选择三个州的客户,为了方便起见我们将它们称为 A、B 和 C)
-
-
个性特质
-
开放性
-
外向性
-
神经质
-
-
预订金额
为了简化问题,我们假设人口统计变量都是预订金额的原因,并且彼此无关(见图 6-1)。
图 6-1。人口统计变量导致预订金额
注意
正如我们在第二章中讨论的,当我说人口统计变量如性别和外向性是预订金额的原因时,我指的是两件事情:首先,它们是外生变量(即在我们研究中是主要原因),其次,它们由于社会现象的因果效应而成为预订金额的预测因素。
例如,性别的影响可能通过个人的收入、职业和家庭状况等多种因素进行中介。从这个意义上讲,更准确地说性别是预订金额的原因的原因。然而,重要的是要注意,这种效应并没有混淆,因此它是真正的因果关系。
本章的流程将遵循您在面对新数据集时所采取的步骤:首先,我们将可视化缺失数据,以了解大致情况。然后,我们将学习如何诊断缺失数据,并看到由统计学家唐纳德·鲁宾开发的分类,这是参考资料。最后三节将展示如何处理该分类中的每一类。
对于 Python 用户来说,不幸的是,我们将要使用的出色 R 包没有直接的 Python 对应包。我将尽力向您展示 Python 中的替代方法和解决方法,但代码将会显著更长,不那么优雅。抱歉!
数据和包
使用模拟数据的一个好处是我们知道缺失数据的真实值。本章的 GitHub 文件夹 包含三个数据集(表 6-1):
-
我们四个变量的完整数据
-
“可用”数据中某些变量的一些值缺失
-
辅助变量的辅助数据集,我们将使用它来补充我们的分析
表 6-1. 我们数据中的变量
| 变量描述 | chap6-complete_data.csv | chap6-available_data.csv | chap6-available_data_supp.csv | |
|---|---|---|---|---|
| 年龄 | 顾客年龄 | 完整 | 完整 | |
| 开放度 | 开放度心理特征,0-10 | 完整 | 完整 | |
| 额外 | 外向性心理特征,0-10 | 完整 | 部分 | |
| 神经 | 神经质心理特征,0-10 | 完整 | 部分 | |
| 性别 | 顾客性别的分类变量,F/M | 完整 | 完整 | |
| 州 | 顾客居住州的分类变量,A/B/C | 完整 | 部分 | |
| 预订金额 | 顾客预订金额 | 完整 | 部分 | |
| 保险 | 顾客购买的旅行保险金额 | 完整 | ||
| 活跃度 | 顾客预订活跃程度的数值测量 | 完整 |
在本章中,除了常用的包外,我们还将使用以下包:
## R
library(mice) # For multiple imputation
library(reshape) #For function melt()
library(psych) #For function logistic()
## Python
from statsmodels.imputation import mice # For multiple imputation
import statsmodels.api as sm # For OLS call in Mice
可视化缺失数据
根据定义,缺失数据很难可视化。单变量方法(即一次处理一个变量)只能带我们走那么远,所以我们大多数时候会依赖双变量方法,将两个变量相互绘制以挖掘一些见解。与因果图结合使用,双变量图将使我们能够可视化关系,否则这些关系将非常复杂。
我们的第一步是了解“数据缺失”的情况。R 中的 mice 包有一个非常方便的函数md.pattern()来可视化缺失数据:
## R
> md.pattern(available_data)
age open gender bkg_amt state extra neuro
368 1 1 1 1 1 1 1 0
358 1 1 1 1 1 1 0 1
249 1 1 1 1 1 0 1 1
228 1 1 1 1 1 0 0 2
163 1 1 1 1 0 1 1 1
214 1 1 1 1 0 1 0 2
125 1 1 1 1 0 0 1 2
120 1 1 1 1 0 0 0 3
33 1 1 1 0 1 1 1 1
23 1 1 1 0 1 1 0 2
15 1 1 1 0 1 0 1 2
15 1 1 1 0 1 0 0 3
24 1 1 1 0 0 1 1 2
24 1 1 1 0 0 1 0 3
23 1 1 1 0 0 0 1 3
18 1 1 1 0 0 0 0 4
0 0 0 175 711 793 1000 2679
md.pattern() 函数返回一张表,其中每一行代表数据可用性的模式。第一行每个变量都有“1”,因此表示完整的记录。表的左侧数字表示具有该模式的行数,右侧数字表示该模式中缺失的字段数。我们的数据中有 368 行完整记录。第二行只有神经质变量为“0”,因此表示只有神经质缺失的记录;我们的数据中有 358 行这样的记录。表的底部数字表示对应变量的缺失值数量,并且变量按缺失值数量递增排序。神经质变量位于表的最右侧,这意味着它有最高数量的缺失值,为 1,000。此函数还方便地返回表的可视化表示(图 6-2)。
图 6-2. 缺失数据的模式
正如我们在图 6-2 中看到的,变量年龄、开放性和性别没有任何缺失数据,但其他所有变量都有。我们可以用我写的一个特定函数在 Python 中获得相同的结果,尽管格式不够易读:
## Python
def md_pattern_fun(dat_df):
# Getting all column names
all_cols = dat_df.columns.tolist()
# Getting the names of columns with some missing values
miss_cols = [col for col in all_cols if dat_df[col].isnull().sum()]
if miss_cols == all_cols: dat_df['index'] = dat_df.index
# Removing columns with no missing values
dat_df = dat_df.loc[:,miss_cols]
#Showing total number of missing values per variable
print(dat_df.isnull().sum())
# Adding count value
dat_df['count'] = 1
# Showing count for missingness combinations
print(dat_df.isnull().groupby(miss_cols).count())
md_pattern_fun(available_data_df)
extra 793
neuro 1000
state 711
bkg_amt 175
dtype: int64
count
extra neuro state bkg_amt
False False False False 368
True 33
True False 163
True 24
True False False 358
True 23
True False 214
True 24
True False False False 249
True 15
True False 125
True 23
True False False 228
True 15
True False 120
True 18
输出由两张表组成:
-
第一张表显示了我们数据中每个变量的缺失值总数,如图 6-2 的底部所示。外向性有 793 个缺失值,依此类推。
-
第二张表显示每种缺失数据模式的详细信息。左侧的逻辑值上方的变量(即外向性、神经质、状态、预订金额)是数据中有一些缺失值的变量。表的每一行指示具有特定缺失数据模式的行数。第一行由四个
False组成,即没有任何变量缺失数据的模式,我们的数据中有 368 行,正如您在图 6-2 的第一行中看到的那样。第二行只将最后一个False改为True,为了易读性省略了前三个False(即任何空白逻辑值应往上读取)。这种模式False``/``False``/``False``/``True出现在仅预订金额有缺失值的情况下,发生在我们的数据中的 33 行,依此类推。
即使是这样一个小数据集,这种可视化也非常丰富,很难知道要寻找什么。我们将探讨两个方面:
缺失数据量
我们的数据有多少是缺失的?哪些变量有最高百分比的缺失数据?我们可以简单地丢弃有缺失数据的行吗?
缺失相关性
缺失数据是在个体级别还是变量级别?
缺失数据量
首要任务是确定我们数据的缺失情况以及哪些变量的缺失比例最高。我们可以在图 6-2 的底部找到所需的值,其中包括每个变量的缺失值数量,按照缺失程度递增排序,或在 Python 输出的底部找到。如果缺失数据量非常有限,例如您有一个 1000 万行数据集,其中没有变量有超过 10 个缺失值,那么通过多重插补来妥善处理它们将是过度的,我们稍后将看到。只需删除所有具有缺失数据的行,问题就解决了。这里的理由是,即使缺失值极其偏倚,它们的数量太少,不会以任何方式实质性地影响您分析的结果。
在我们的示例中,缺失值最多的变量是神经质,有 1,000 个缺失值。这多吗?限制在哪里?是 10、100、1,000 行还是更多?这取决于上下文。您可以使用一个快速且简单的策略:
-
选择缺失值最多的变量,并创建两个新数据集:一个将该变量的所有缺失值替换为该变量的最小值,另一个将其替换为该变量的最大值。
-
对您现在拥有的三个数据集中的每一个,运行关于该变量与您感兴趣效果的最重要关系的回归。例如,如果该变量是您感兴趣效果的预测变量,则运行该回归。
-
如果在三次回归中,回归系数没有实质性差异,即基于不同数值得出相同的业务影响或采取相同行动,那么您的数据缺失率在可接受范围内,可以放弃缺失数据。简而言之:这些数字对您的业务伙伴来说意味着相同的事情吗?如果是这样,您可以放弃缺失数据。
注意
这一经验法则很容易适用于数值变量,但是对于二元或分类变量呢?
对于二元变量,最小值将为 0,最大值将为 1,这是可以接受的。您创建的两个数据集将转化为最佳情况和最坏情况。
对于分类变量,最小和最大规则必须稍作调整:将所有缺失值替换为最少出现或最常出现的类别。
让我们以神经质为例,做到这一点。神经质是我们感兴趣效果预订金额的一个预测变量,所以我们将使用前面指出的关系:
## R (output not shown)
min_data <- available_data %>%
mutate(neuro = ifelse(!is.na(neuro), neuro, min(neuro, na.rm = TRUE)))
max_data <- available_data %>%
mutate(neuro = ifelse(!is.na(neuro), neuro, max(neuro, na.rm = TRUE)))
summary(lm(bkg_amt~neuro, data=available_data))
summary(lm(bkg_amt~neuro, data=min_data))
summary(lm(bkg_amt~neuro, data=max_data))
## Python (output not shown)
min_data_df = available_data_df.copy()
min_data_df.neuro = np.where(min_data_df.neuro.isna(), min_data_df.neuro.min(),
min_data_df.neuro)
max_data_df = available_data_df.copy()
max_data_df.neuro = np.where(max_data_df.neuro.isna(), max_data_df.neuro.max(),
max_data_df.neuro)
print(ols("bkg_amt~neuro", data=available_data_df).fit().summary())
print(ols("bkg_amt~neuro", data=min_data_df).fit().summary())
print(ols("bkg_amt~neuro", data=max_data_df).fit().summary())
结果如下:
-
基于可用数据的系数为−5.9。
-
基于用神经质的最小值替换缺失值的系数为−8.0。
-
基于用神经质的最大值替换缺失值的系数为 2.7。
这些值彼此非常不同,甚至具有不同的符号,因此我们绝对超过了材料显著性的阈值。我们不能简单地删除那些对神经质有缺失数据的行。对其他变量采用同样的方法也会显示出我们不能忽视它们的缺失值,需要适当处理。
缺失的相关性
一旦确定了需要处理的变量,我们就想知道它们的缺失程度有多相关。如果有变量的缺失高度相关,这表明一个变量的缺失导致了其他变量的缺失(例如,如果某人在调查中途停止回答问题,则之后的所有答案都将缺失)。或者,它们的缺失可能有共同的原因(例如,某些受试者更不愿意透露有关自己的信息)。在这两种情况下,识别缺失的相关性将帮助您建立更精确的 CD,节省时间并使分析更有效。
让我们通过一个简单的例子来看一下:想象一下我们有两个办公室的面试数据:Tampa 和 Tacoma。在两个办公室中,候选人必须通过相同的三个强制性面试部分,但在 Tampa,第一位面试官负责记录候选人的所有分数,而在 Tacoma,每位面试官都要记录其部分的分数。面试官是人类,有时会忘记将数据交给 HR。在 Tampa,如果面试官忘记提交数据,我们对于候选人除了系统中的 ID 外就没有任何数据(Figure 6-3 只显示了 Tampa 的数据)。
图 6-3。Tampa 数据中高度相关的缺失。
高缺失相关性的标志是一行具有大量浅色方块(这里是 3),代表了高数量的案例(这里是总行数 2,000 中的 400)。此外,图中没有只有一个或两个浅色方块的行。
在这种情况下,逐个变量分析我们的缺失数据是毫无意义的。如果我们发现当 Murphy 是第一位面试官时,第一部分的数据非常可能丢失,那么对于其他部分也是如此。(Murphy,你只有一个任务!)
相反,在 Tacoma,不同部分的缺失完全不相关(Figure 6-4)。
这种模式与 Tampa 相反:
-
我们有大量只有少数缺失变量的行(请看图右边的所有 1 和 2)。
-
这些行代表了我们数据的大部分(左边的数据表明只有 17 行有 3 个缺失变量)。
-
图中底部有大量浅色方块的线代表非常少的案例(相同的 17 个个体),因为它们是独立随机性的结果。
图 6-4. Tacoma 数据中的不相关缺失
最后一个要点的论证可以通过更广泛地观察我们可以称之为“俄罗斯套娃”序列来扩展,这些序列呈递增的缺失,其中每个模式都在上一个模式上添加一个缺失变量,例如(I3)→(I3,I2)→(I3,I2,I1)。相应的案例数量是 262 → 55 → 17. 这些数字形成了一个递减序列,这是合乎逻辑的,因为如果变量的缺失完全不相关,我们有:
Prob(I3 缺失 & I2 缺失)= Prob(I3 缺失)* Prob(I2 缺失)
Prob(I3 缺失 & I2 缺失 & I1 缺失)= Prob(I3 缺失)* Prob(I2 缺失)** Prob*(I1 缺失)
在样本较小和/或缺失程度非常高的情况下,这些方程可能在我们的数据中并不完全成立,但是如果任何变量的缺失量不到 50%,我们通常应该有:
Prob(I3 缺失 & I2 缺失 & I1 缺失)< Prob(I3 缺失 & I2 缺失)< Prob(I3 缺失)
在实际情况下,自己测试所有这些不等式可能会相当麻烦,尽管您可以编写一个函数以进行大规模测试。相反,我建议查看任何重要的异常值的可视化(即,一些相同变量的值远大于相同变量的某些值)。
更广泛地说,这种可视化在只有几个变量时很容易使用。一旦您有大量变量,您将不得不构建和可视化缺失的相关矩阵:
## R (output not shown)
# Building the correlation matrices
tampa_miss <- tampa %>%
select(-ID) %>%
mutate(across(everything(),is.na))
tampa_cor <- cor(tampa_miss) %>%
melt()
tacoma_miss <- tacoma %>%
select(-ID) %>%
mutate(across(everything(),is.na))
tacoma_cor <- cor(tacoma_miss) %>%
melt()
## Python (output not shown)
# Building the correlation matrices
tampa_miss_df = tampa_df.copy().drop(['ID'], axis=1).isna()
tacoma_miss_df = tacoma_df.copy().drop(['ID'], axis=1).isna()
tampa_cor = tampa_miss_df.corr()
tacoma_cor = tacoma_miss_df.corr()
Figure 6-5 显示了生成的相关矩阵。在左侧的矩阵中,对于 Tampa,所有值都等于 1:如果一个变量缺失,那么其他两个变量也是如此。在右侧的相关矩阵中,对于 Tacoma,主对角线上的值等于 1,但在其他地方都等于 0:知道一个变量缺失并不能告诉您其他变量的缺失情况。
图 6-5. 完全相关缺失(左)和完全不相关缺失(右)的相关矩阵
让我们回到我们的 AirCnC 数据集,并看看它在我们的理论访谈示例中概述的两个极端之间的位置。Figure 6-6 重复了 Figure 6-2 以便更易于访问。
图 6-6 位于中间位置:所有可能的缺失模式都相当代表,这表明我们没有强烈聚集的缺失源。
图 6-6. 缺失数据的模式(重复 图 6-2)
图 6-7 显示了我们的 AirCnC 数据缺失的相关性矩阵。正如你所看到的,我们变量的缺失几乎完全不相关,完全在随机波动范围内。如果你想更加熟悉缺失中的相关性模式,本章的一个GitHub 上的练习要求你识别其中一些。作为提醒,查看相关性模式本身并不是必要的,但通常可以启发思考并节省时间。
图 6-7. 我们 AirCnC 数据中缺失的相关性矩阵
诊断缺失数据
现在我们已经可视化了我们的缺失数据,是时候了解是什么导致了它。这就是因果图的作用所在,因为我们将使用它们来表示缺失数据的因果机制。
让我们从第 1 章中的一个非常简单的例子开始。在介绍因果图时,我提到未观察到的变量,比如顾客对香草冰淇淋的喜好,用一个较深的阴影矩形来表示(图 6-8)。
图 6-8. 未观察到的变量以较深的阴影矩形表示
未观察到的变量,在某些学科中有时被称为“潜变量”,指的是我们实际上没有的信息,尽管理论上可能是可以访问的或不可访问的。在目前的情况下,假设我们强迫客户在购买前透露他们对香草的口味。这将在我们的系统中创建相应的数据,然后我们将用它们进行数据分析(图 6-9)。
图 6-9. 收集先前未观察到的信息
但是,试图强迫客户透露他们不想透露的信息通常是不良的商业行为,并且通常是可选的。更一般地说,对一些客户收集了大量数据,而对其他客户则没有。我们将通过在 CD 中用虚线绘制相应的框来表示该情况(图 6-10)。
图 6-10. 用虚线框表示部分观察到的变量
例如,对于三名顾客,我们可能有以下数据,其中一名顾客拒绝透露他们对香草冰淇淋的口味(表 6-2)。
表 6-2. 我们 CD 的基础数据
| 顾客姓名 | 对香草的喜好 | 声明的口味 | 在摊位购买冰淇淋(Y/N) |
|---|---|---|---|
| 安 | 低 | 低 | N |
| 鲍勃 | 高 | 高 | Y |
| 卡罗琳 | 高 | N/A | Y |
在本章中,我们感兴趣的是理解一个变量的缺失原因,而不仅仅是理解一个变量的值的原因。因此,我们将创建一个变量来跟踪声明口味变量何时缺失 (表 6-3)。
表 6-3. 添加一个缺失变量
| 顾客姓名 | 对香草的喜好 | 声明的香草口味 | 声明的口味缺失(Y/N) | 在摊位购买冰淇淋 |
|---|---|---|---|---|
| 安 | 低 | 低 | N | N |
| 鲍勃 | 高 | 高 | N | Y |
| 卡罗琳 | 高 | N/A | Y | Y |
让我们在我们的 CD 中添加该变量 (图 6-11)。
图 6-11. 在我们的因果图中添加缺失
我们通常将缺失作为相应部分观察变量的原因。直觉是信息完全存在于未观察变量中,并且部分观察变量等于未观察变量,除非信息被缺失变量“隐藏”。这种约定将使我们的生活更加轻松,因为它允许我们在 CD 中表达和讨论缺失的原因,这些原因代表了我们感兴趣的关系,而不必单独考虑缺失。
现在缺失已成为我们 CD 的一部分,下一个自然的步骤是问自己:“是什么原因导致了它?”
缺失的原因:鲁宾的分类
对于引起变量缺失的基本且互斥的三种可能性,统计学家唐纳德·鲁宾已进行了分类。
首先,如果一个变量的缺失仅取决于我们数据之外的变量,例如纯随机因素,那么该变量被称为完全随机缺失(MCAR) (图 6-12)。
图 6-12. 声明的口味是完全随机缺失的
接着,如果我们的数据中的任何一个变量影响其缺失状态,那么一个变量从 MCAR(完全随机缺失)变为随机缺失(MAR)。数据之外的变量和随机因素也可能起作用,但变量的值可能不会影响其自身的缺失状态。例如,如果购买导致了声明的香草口味的缺失,例如因为我们只采访购买的顾客而不是路人 (图 6-13)。
图 6-13. 所述口味是随机缺失
最后,任何值影响其自身缺失的变量都被认为是 缺失不是随机的(MNAR),即使数据内外的其他变量也会影响缺失。我们的数据内外可能还有其他变量起作用,但变量一旦影响其自身缺失,就从 MCAR 或 MAR 变为 MNAR。在我们的例子中,这意味着 香草口味 导致 陈述香草口味 的缺失(图 6-14)。
图 6-14. 所述口味缺失不是随机发生的
注意
我们通过从未观察到的变量而不是部分观察到的变量引入箭头来表示变量的值影响其缺失的想法。这样,我们可以做出有意义的陈述,如“实际上低于某个阈值的所有值在我们的数据中都是缺失的”。如果箭头来自部分可观察到的变量,我们将被困在无信息的陈述中,例如“缺失的值导致它们自己缺失”。
在理想的世界里,本节其余部分将包括识别每个缺失类别的方法。不幸的是,缺失数据分析仍然是一个尚未完全探索的开放领域。特别是,缺失和因果关系如何相互作用尚不清楚。因此,处理缺失数据仍然更像是一门艺术而不是科学。试图创建系统化的方法将需要处理大量的异常情况,以及引入循环论证,如“模式 X 表明变量 1 是 MAR,除非变量 2 是 MNAR;模式 Y 表明变量 2 是 MNAR,除非变量 1 是 MAR”。我已尽力在有限的数据集中涵盖尽可能多的情况,但在现实世界中,您可能会遇到“有点这个,有点那个”的情况,您需要判断如何继续。
然而,有些好消息是,除了我会指出的几个例外外,谨慎行事会花费更多时间但不会引入偏见。当您不确定一个变量是 MCAR、MAR 还是 MNAR 时,只需假设可能的最糟情形,您的分析将尽可能是无偏的。
在这种情况下,请回顾我们的 AirCnC 数据,看看如何在一个实际数据集中诊断缺失情况。作为一个快速的提醒,我们的数据集包含以下变量:
-
人口统计特征
-
年龄
-
性别
-
状态(A、B 和 C)
-
-
个性特征
-
开放性
-
外向性
-
神经质
-
-
预订金额
诊断 MCAR 变量
MCAR 变量是最简单的情况。传感器故障了,一个 bug 阻止了数据从客户的移动应用程序传输,或者客户只是错过了输入他们对香草冰淇淋口味的字段。总之,缺失以直觉上的“随机”方式发生。我们默认诊断 MCAR 变量:如果变量似乎不是 MAR,则将其视为 MCAR。换句话说,在缺乏证据的情况下,你可以将 MCAR 视为我们的零假设。
我们将用来诊断缺失性的主要工具是逻辑回归,即一个变量是否缺失,取决于我们数据集中的所有其他变量。让我们以 外向性 变量为例:
## Python (output not shown)
available_data_df['md_extra'] = available_data_df['extra'].isnull().astype(float)
md_extra_mod =smf.logit('md_extra~age+open+neuro+gender+state+bkg_amt',
data=available_data_df)
md_extra_mod.fit().summary()
## R
> md_extra_mod <- glm(is.na(extra)~.,
family = binomial(link = "logit"),
data=available_data)
> summary(md_extra_mod)
...
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -0.7234738 0.7048598 -1.026 0.305
age -0.0016082 0.0090084 -0.179 0.858
open 0.0557508 0.0425013 1.312 0.190
neuro 0.0501370 0.0705626 0.711 0.477
genderF -0.0236904 0.1659661 -0.143 0.886
stateB -0.0780339 0.2000428 -0.390 0.696
stateC -0.0556228 0.2048822 -0.271 0.786
bkg_amt -0.0007701 0.0011301 -0.681 0.496
...
没有任何变量具有大且强烈统计显著的系数。在没有任何其他证据的情况下,这表明 外向性 的缺失性纯粹是随机的,我们将把我们的 外向性 变量视为 MCAR。
你可以将 MCAR 数据视为掷骰子或抛硬币。从我们的角度来看,这两种行为都是“随机”的,但它们仍然遵守物理法则。理论上,如果我们有足够的信息和计算能力,结果将是完全可预测的。这里也可能发生同样的情况。当我们说 外向性 是 MCAR 时,我们并不是在说“外向性 的缺失性基本上是随机且不可预测的”,我们只是说“我们目前分析中包含的变量没有一个与 外向性 的缺失性相关联。”但可能——甚至很可能——其他变量(责任感?信任?对技术的熟悉度?)会相关联。我们的目标不是对 外向性 发表哲学性声明,而是确定其缺失是否可能会使我们的分析产生偏见,考虑到当前可用的数据。
诊断 MAR 变量
MAR 变量是指其缺失性取决于数据集中其他变量的值。如果数据集中的其他变量能够预测某个变量的缺失性,则 MAR 将成为我们该变量的默认假设,除非我们有足够强的证据表明其为 MNAR。让我们看看 状态 变量的情况:
## R (output not shown)
md_state_mod <- glm(is.na(state)~.,
family = binomial(link = "logit"),
data=available_data)
summary(md_state_mod)
## Python
available_data_df['md_state'] = available_data_df['state'].isnull()\
.astype(float)
md_state_mod =smf.logit('md_state~age+open+extra+neuro+gender+bkg_amt',
data=available_data_df)
md_state_mod.fit(disp=0).summary()
...
coef std err z P>|z| [0.025 0.975]
Intercept -0.2410 0.809 -0.298 0.766 -1.826 1.344
gender[T.F] -0.1742 0.192 -0.907 0.364 -0.551 0.202
age 0.0206 0.010 2.035 0.042 0.001 0.040
open 0.0362 0.050 0.727 0.467 -0.061 0.134
extra 0.0078 0.048 0.162 0.871 -0.087 0.102
neuro -0.1462 0.087 -1.687 0.092 -0.316 0.024
bkg_amt -0.0019 0.001 -1.445 0.149 -0.005 0.001
...
年龄 略有显著性,具有正系数。换句话说,年长客户似乎更不可能提供他们的州。相应的因果图表示在 图 6-15 中。
图 6-15. 性别随机缺失
我们可以通过绘制观察到的 年龄 按 状态 缺失情况的密度图(图 6-16)来确认这种相关性。相对于年轻客户,状态 在年长客户中的观察值更多,或者反过来,对于年长客户,状态 的缺失值更多。
图 6-16. 缺失和观察到的状态数据密度,按观察到的年龄分
这个密度图的一个局限性是它并不显示 X 变量(这里是Age)也缺失的行。当该变量也有缺失值时,这可能会产生问题或误导。一个可能的技巧是将 X 变量的缺失值替换为一个不合理的值,比如−10。Age没有任何缺失值,所以我们将使用Xtraversion作为我们的 X 变量,该变量有缺失值。让我们按Extraversion的值绘制观察到的和缺失的State数据的密度(图 6-17)。
图 6-17. 按 Extraversion 水平绘制的缺失和观察到的 State 数据密度,包括缺失的 Extraversion
图 6-17 显示,在没有Extraversion数据的个体中,我们观察到的State要比State缺失的个体更多。总体上,我们看到了强有力的证据表明State不是 MCAR,而是 MAR,因为其缺失似乎与我们数据集中其他可用变量相关。
注意
你可能注意到我在早些时候谈论Age(或Extraversion)与State缺失之间关系时使用了“相关性”这个词。事实上,到目前为止,我们只展示了相关性,完全有可能Age并不导致State的缺失,而是它们两者都由第三个未观察到的变量导致。幸运的是,在谈论缺失时,相关性的因果性质(或其缺乏)不会影响我们的分析。松散地将两者等同起来不会引入偏差,因为我们实际上永远不会处理那种关系的系数。
诊断 MNAR 变量
MNAR 变量是其缺失性取决于其自身值的变量:较高的值缺失的可能性比较低的值更高,反之亦然。这种情况对数据分析是最具问题的,并且诊断起来最为棘手。它很难诊断,因为根据定义,我们不知道缺失的值。因此,我们需要做更多的调查工作。
让我们来看一下Neuroticism变量,并且像之前一样,首先对数据中其缺失情况进行回归分析:
## Python (output not shown)
available_data_df['md_neuro'] = available_data_df['neuro'].isnull()\
.astype(float)
md_neuro_mod =smf.logit('md_neuro~age+open+extra+state+gender+bkg_amt',
data=available_data_df)
md_neuro_mod.fit(disp=0).summary()
## R
md_neuro_mod <- glm(is.na(neuro)~.,
family = binomial(link = "logit"),
data=available_data)
summary(md_neuro_mod)
...
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -0.162896 0.457919 -0.356 0.72204
age -0.012610 0.008126 -1.552 0.12071
open 0.052419 0.038502 1.361 0.17337
extra -0.084991 0.040617 -2.092 0.03639 *
genderF -0.093537 0.151376 -0.618 0.53663
stateB 0.047106 0.181932 0.259 0.79570
stateC -0.128346 0.187978 -0.683 0.49475
bkg_amt 0.003216 0.001065 3.020 0.00253 **
...
我们可以看到BookingAmount具有显著的系数。表面上看,这表明神经质对BookingAmount的 MAR。然而,这是一个关键线索,BookingAmount在我们的 CD 中是神经质的子节点。从行为角度来看,神经质对BookingAmount的 MNAR 更为可能(即,缺失是由个性特征而非客户消费金额驱动的)。
确认我们怀疑的一种方法是识别另一个具有缺失数据的变量的子类,理想情况下与其尽可能相关,与第一个子类的相关性尽可能小。在我们的次要数据集中,我们有关于客户终生在公司购买的旅行保险总金额的数据。每次旅行的费用取决于只与预订金额略微相关的行程特征,因此在这方面我们做得很好。在我们的数据集中添加保险后,我们发现它强烈预测了神经质的缺失,并且观察到和缺失的神经质之间的保险金额分布彼此截然不同(图 6-18)。
图 6-18. 观察到的保险金额下缺失和观察到的神经质数据密度
我们找到与神经质的缺失相关的更多子变量,我们的案例就越强烈,表明这个变量是 MNAR。正如我们稍后将看到的,处理 MNAR 变量的方法是在我们的填充模型中添加辅助变量,我们的子变量是理想的候选人,因此找到它们不是浪费时间而是下一步的先机。
从技术上讲,我们永远无法完全证明一个变量是 MNAR 而不仅仅是 MAR 其子类中的一个,但这不是问题:辅助变量不会使缺失数据修补产生偏差,如果原始变量确实是 MAR 而不是 MNAR。
缺失作为一个谱系
鲁宾的分类依赖于二元测试。例如,只要一个变量更可能对较高值缺失而不是对较低值缺失(反之亦然),它就是 MNAR,不考虑任何其他因素。然而,该关系在值和缺失之间的形状对实际目的很重要:如果一个变量的所有值在某个阈值以上或以下都缺失,我们将需要与默认方法不同的方式处理这个变量。这种情况也可能发生在 MAR 变量中,因此值得退后一步,更广泛地考虑缺失形状。
我们可以将变量的缺失看作是在完全概率性和完全确定性之间的一个谱系。在谱系的“概率性”端,变量是 MCAR,所有值都可能缺失。在谱系的“确定性”端,存在一个阈值:所有在阈值一侧的个体的值都是缺失的,而在阈值另一侧的个体的值是可用的。这通常是由于业务规则的应用。例如,在招聘背景下,如果只有 GPA 超过 3.0 的候选人才能接受面试,那么对于低于该阈值的候选人将没有任何面试分数。这会使面试分数在GPA上成为 MAR(Figure 6-19)。
图 6-19. 面试分数在GPA上成为 MAR
注意
精研的 MCAR/MAR/MNAR 分类仅基于缺失原因,而不考虑该因果关系是否显示出随机性。在这里,令人感到反直觉的是,InterviewScore的缺失基于GPA的确定性关系,使得InterviewScore在GPA上成为 MAR,尽管其中并没有涉及随机性。
这也可能发生在 MNAR 类型的变量上,仅记录超过或低于某一阈值的值。例如,只有在文件中保存了正常范围之外的值,或者只有超过或低于某一阈值的人才会注册(例如,出于税务目的)。
在完全随机和完全确定之间的这两个极端情况(无论是 MAR 还是 MNAR 类型),存在着根据缺失原因的值连续增加或减少缺失概率的情况。
Figure 6-20 显示了两个变量 X 和 Y 的最简单情况下的情况,其中 X 具有缺失值。为了便于阅读,可用值显示为实心方块,而“缺失”值显示为叉号。Figure 6-20 的第一行显示了 Y 相对于 X 的散点图,第二行显示了 X 和缺失概率之间关系的线图:
-
最左列显示 X 是 MCAR。缺失的概率在 0.5 处恒定且与 X 无关。方块和叉号在图中分布类似。
-
中间列显示 X 是具有逐渐增强概率 MNAR 的概率性 MNAR。方块在图的左侧更为普遍,而叉号在右侧更为普遍,但左侧仍然存在叉号,右侧仍然存在方块。
-
最右侧的列显示 X 是确定性 MNAR。所有低于 5 的 X 值是可用的(方块),而所有高于 5 的值都是“缺失”的(叉号)。
图 6-20. 缺失程度谱,从 MCAR(最左侧)到确定性 MNAR(最右侧),穿过概率性 MNAR(中心)
这种缺失程度的谱很少在缺失数据的统计处理中讨论,因为仅凭数学方法很难确认。但这是一本关于行为分析的书籍,因此我们可以和应该使用常识和业务知识。在 GPA 的例子中,数据的阈值是由你应该了解的业务规则应用而来的。在大多数情况下,您期望一个变量落在某些值的特定范围内,并且您应该知道可能出现某个可能值不在您的数据中的概率有多高。
在我们的 AirCnC 调查数据中,我们有三个人格特质:开放性、外倾性和神经质。在现实生活中,这些变量将是对几个问题回答的汇总,并且在已知区间内有钟形分布(参见 Funder (2016) 了解人格心理学的良好介绍)。让我们假设在我们的数据中,相关区间是从 0 到 10,并且让我们来看看我们变量的分布(图 6-21)。
图 6-21. 我们数据中的人格特征直方图
显然,神经质有些问题。基于人格特征的构建方式,我们预期三个变量的曲线类型相同,而不会出现大量数值为 5 的客户,也不会一个数值为 4 的客户都没有。这极大地暗示了一个确定性的缺失非随机变量,我们必须相应地处理。
现在,您应该能够合理判断数据集中缺失情况的模式。有多少缺失值?它们的缺失是否与变量本身的值(MNAR)、另一个变量(MAR)或者都不相关(MCAR)有关?这些缺失关系是概率性的还是确定性的?
图 6-22 展示了一个决策树,总结了我们诊断缺失数据的逻辑。
图 6-22. 诊断缺失数据的决策树
在接下来的部分,我们将看到如何在每种情况下处理缺失数据。
处理缺失数据
当我们进入本章的操作部分时,首先要记住的是我们并不是为了处理缺失数据而处理缺失数据:我们的目标是在我们的数据中获得无偏差和准确的因果关系估计。只有当缺失数据干扰了这一目标时,缺失数据才会成为问题。
这一点需要强调,因为你的第一反应可能是,成功处理缺失数据的结果是一个没有缺失数据的数据集,但事实并非如此。我们将使用的方法,多重插补(MI),会为您的数据创建多个副本,每个副本都有其自己的插补值。通俗地说,我们永远不会说“Bob 缺失的年龄的正确替代值是 42 岁”,而是“Bob 可能是 42 岁、38 岁、44 岁、42 岁或者 38 岁”。没有单一的最佳猜测,而是一系列可能性。另一个最佳实践方法,最大似然估计,甚至不会对个别值进行任何猜测,只处理高阶系数,例如均值和协方差。
在下一小节中,我将为您提供 MI 方法的高级概述。之后,我们将深入研究模型的更详细算法规格:
-
首先,预测均值匹配算法
-
接下来,正常算法
-
最后,如何将辅助变量添加到算法中
不幸的是,鲁宾分类中缺失类型与适当的算法规格之间并不存在一对一的关系,因为可用的信息量也很重要(参见 表 6-4)。
表 6-4. 根据缺失类型和可用信息的最佳 MI 参数
| 缺失类型 | 无信息 | 变量分布为正态 | 缺失分布为确定性 |
|---|---|---|---|
| MCAR | 均值匹配 | 正态分布 | (不可能) |
| MAR | 均值匹配 | 正态分布 | 正态分布 + 辅助变量 |
| MNAR | 均值匹配 + 辅助变量 | 正态分布 + 辅助变量 | 正态分布 + 辅助变量 |
多重插补(MI)介绍
要理解多重插补的工作原理,有助于将其与传统的处理缺失数据的方法进行对比。除了简单地删除所有具有缺失值的行之外,传统方法都依赖于用特定值替换缺失值。替换值可以是变量的整体平均值,或者基于其他可用于该客户的变量预测的值。无论用于替换值的规则如何,这些方法都存在根本性缺陷,因为它们忽略了由缺失数据引入的额外不确定性,并且可能会在分析中引入偏差。
解决这个问题的 MI 解决方案,正如其名称所示,是构建多个数据集,其中缺失值被不同的值替换,然后用每个数据集运行我们感兴趣的分析,并最终聚合生成的系数。
在 R 和 Python 中,整个过程都是在后台管理的,如果您想保持简单,只需指定要运行的数据和分析即可。
首先让我们看看 R 代码:
## R
> MI_data <- mice(available_data, print = FALSE)
> MI_summ <- MI_data %>%
with(lm(bkg_amt~age+open+extra+neuro+gender+state)) %>%
pool() %>%
summary()
> print(MI_summ)
term estimate std.error statistic df p.value
1 (Intercept) 240.990671 15.9971117 15.064636 22.51173 3.033129e-13
2 age -1.051678 0.2267569 -4.637912 11.61047 6.238993e-04
3 open 3.131074 0.8811587 3.553360 140.26375 5.186727e-04
4 extra 11.621288 1.2787856 9.087753 10.58035 2.531137e-06
5 neuro -6.799830 1.9339658 -3.516003 15.73106 2.929145e-03
6 genderF -11.409747 4.2044368 -2.713740 20.73345 1.310002e-02
7 stateB -9.063281 4.0018260 -2.264786 432.54286 2.401986e-02
8 stateC -5.334055 4.7478347 -1.123471 42.72826 2.675102e-01
mice包(多重插补通过链式方程)具有mice()函数,用于生成多个数据集。然后,我们使用with()关键字将感兴趣的回归应用于每一个数据集。最后,从mice中使用pool()函数以我们可以用传统的summary()函数读取的格式汇总结果。
Python 代码几乎相同,因为它实现了相同的方法:
## Python
MI_data_df = mice.MICEData(available_data_df)
fit = mice.MICE(model_formula='bkg_amt~age+open+extra+neuro+gender+state',
model_class=sm.OLS, data=MI_data_df)
MI_summ = fit.fit().summary()
print(MI_summ)
Results: MICE
===================================================================
Method: MICE Sample size: 2000
Model: OLS Scale 5017.30
Dependent variable: bkg_amt Num. imputations 20
-------------------------------------------------------------------
Coef. Std.Err. t P>|t| [0.025 0.975] FMI
-------------------------------------------------------------------
Intercept 120.3570 8.8662 13.5748 0.0000 102.9795 137.7344 0.4712
age -1.1318 0.1726 -6.5555 0.0000 -1.4702 -0.7934 0.2689
open 3.1316 0.8923 3.5098 0.0004 1.3828 4.8804 0.1723
extra 11.1265 1.0238 10.8680 0.0000 9.1200 13.1331 0.3855
neuro -4.5894 1.7968 -2.5542 0.0106 -8.1111 -1.0677 0.4219
gender_M 65.9603 4.8191 13.6873 0.0000 56.5151 75.4055 0.4397
gender_F 54.3966 4.6824 11.6171 0.0000 45.2192 63.5741 0.4154
state_A 40.9352 3.9080 10.4748 0.0000 33.2757 48.5946 0.3921
state_B 37.3490 4.0727 9.1706 0.0000 29.3666 45.3313 0.2904
state_C 42.0728 3.8643 10.8875 0.0000 34.4989 49.6468 0.2298
===================================================================
在这里,mice算法从statsmodels.imputation包中导入。MICEData()函数生成多个数据集。然后,通过MICE()函数指定模型公式、回归类型(这里是statsmodels.OLS)和要使用的数据。我们使用.fit()和.summary()方法拟合我们的模型,然后打印结果。
注意
Python 实现的mice方法的一个复杂之处在于它不支持分类变量作为预测因子。如果您确实想使用 Python,您首先需要对分类变量进行独热编码。以下代码展示了如何处理性别变量:
## Python
gender_dummies = pd.get_dummies(available_data_df.\
gender,
prefix='gender')
available_data_df = pd.concat([available_data_df,
gender_dummies],
axis=1)
available_data_df.gender_F = \
np.where(available_data_df.gender.isna(),
float('NaN'), available_data_df.gender_F)
available_data_df.gender_M = \
np.where(available_data_df.gender.isna(),
float('NaN'), available_data_df.gender_M)
available_data_df = available_data_df.\
drop(['gender'], axis=1)
首先,我们使用 pandas 的get_dummies()函数创建变量gender_F和gender_M。在将这些列添加到我们的数据帧之后,我们指示缺失值的位置(默认情况下,独热编码函数在分类变量值缺失时将所有二进制变量设置为 0)。最后,我们从数据中删除原始分类变量,并使用包含新变量的模型进行拟合。
然而,独热编码通过删除变量之间的逻辑连接来破坏数据的内部结构,因此效果可能因人而异(例如,您可以看到因为结构不同,R 和 Python 中的分类变量系数不同),如果分类变量在您的数据中起重要作用,我建议您使用 R 而不是 Python。
就是这样!如果您现在停止阅读本章,您将得到一个处理缺失数据的解决方案,这比传统方法要好得多。然而,通过花时间揭示内部机制并更好地理解插补算法,我们可以做得更好。
默认插补方法:预测均值匹配
在前一小节中,我们未指定插补方法,依赖于mice的默认设置。在 Python 中,唯一可用的插补方法是预测均值匹配,因此在这里没有其他操作。让我们来看看 R 中默认的插补方法,通过请求插补过程的摘要:
## R
> summary(MI_data)
Class: mids
Number of multiple imputations: 5
Imputation methods:
age open extra neuro gender state bkg_amt
"" "" "pmm" "pmm" "" "logreg" "pmm"
PredictorMatrix:
age open extra neuro gender state bkg_amt
age 0 1 1 1 1 1 1
open 1 0 1 1 1 1 1
extra 1 1 0 1 1 1 1
neuro 1 1 1 0 1 1 1
gender 1 1 1 1 0 1 1
state 1 1 1 1 1 0 1
这是很多信息。现在,让我们只看看Imputation methods一行。没有缺失数据的变量有一个空字段"",这是有道理的,因为它们不会被填充。分类变量具有方法logreg,即逻辑回归。最后,数值变量具有方法pmm,即预测均值匹配(PMM)。pmm方法的工作原理是选择具有缺失值的个体的最近邻居,并用一个邻居的值替换缺失值。例如,假设数据集只有两个变量:Age 和 ZipCode。如果您有一个来自邮编 60612 且年龄缺失的客户,算法将随机选择同一邮编中另一个客户的年龄,或者尽可能接近的客户的年龄。
由于过程中存在一些随机性,每个填充的数据集最终会得到略有不同的值,我们可以通过mice包中方便的densityplot()函数可视化来查看:
## R
> densityplot(MI_data, thicker = 3, lty = c(1,rep(2,5)))
图 6-23 显示了原始可用数据(粗线)和填充数据集(细虚线)中数值变量的分布。如您所见,分布与原始数据非常接近;唯一的例外是BookingAmount,在填充数据集中,它的分布总体上更集中在均值周围(即“更高的峰值”)。
图 6-23. 我们数据中数值变量的填充值分布
PMM 具有一些重要的特性,这些特性可能是需要的,也可能不需要,这取决于上下文。最重要的特性是它基本上是一种插值方法。因此,您可以将 PMM 想象为创建介于现有值之间的值。通过这样做,它最小化了创建荒谬情况的风险,比如怀孕的父亲或负数金额。这种方法在变量具有奇怪分布时也能很好地工作,比如我们数据中的Age,它有两个峰值,因为它对整体分布的形状没有假设;它只是选择一个邻居。
然而,PMM 有几个缺点:它速度较慢,并且在大数据集上不易扩展,因为它必须不断重新计算个体之间的距离。此外,当您有许多变量或许多缺失值时,最近的邻居可能“很远”,填充的质量会降低。这就是为什么当我们拥有分布信息时,PMM 不会是我们首选的选项,正如我们将在下一小节中看到的那样。
从 PMM 到正态填充(仅限 R)
虽然 PMM 是一个不错的起点,但我们经常有关于数值变量分布的信息,我们可以利用这些信息来加快和改进 R 中的插补模型。特别是,行为和自然科学通常假设数值变量服从正态分布,因为这是非常常见的。在这种情况下,我们可以对变量拟合正态分布,然后从该分布中提取插补值,而不是使用 PMM。这通过创建一个插补方法的向量来完成,对于我们将假设正态性的变量,向量中的值设为"norm.nob",然后将该向量传递给mice()函数的parameter方法。
## R
> imp_meth_dist <- c("pmm", rep("norm.nob",3), "", "logreg", "norm.nob")
> MI_data_dist <- mice(available_data, print = FALSE, method = imp_meth_dist)
正如您所见,语法非常简单。唯一的问题是确定我们要为哪些数值变量使用正常插补。让我们来看看我们可用数据中的数值变量(图 6-24)。
图 6-24. 我们数据中的数值变量分布
年龄显然不是正态的,因为它有两个峰,但所有其他变量只有一个峰。开放性、外向性和预订金额看起来也相对对称(在技术上来说,它们不倾斜)。统计模拟表明,只要一个变量是单峰的,并且在一个方向上没有“粗尾”,假设正态性不会引入偏差。因此,我们可以假设开放性、外向性和预订金额是正态分布的。
正如我们在前一节中看到的,神经质呈现出不寻常的非对称模式:尽管我们使用的心理学尺度从 0 到 10,但其值被限制在[5,10]之间,这表明神经质可能是“确定性地”MNAR,即神经质的所有值低于某个阈值都会缺失。在这种情况下使用 PMM 进行插补是有问题的:在大部分值范围内插补时几乎没有或根本没有邻居可用。极端情况下,X 的所有缺失值将被插补为 5,即阈值的值。这是一种普通方法更能恢复真实缺失值的情况。我们可以通过比较两种方法插补的值来看出这一点。图 6-25 显示了神经质的可用值(方块)以及用 PMM 方法插补的值(十字,顶部面板)和用普通方法插补的值(十字,底部面板)。
图 6-25. PMM 插补(顶部)和普通插补(底部)对确定性 MNAR 变量的影响
正如您所见,PMM 方法不对神经质低于 5 的任何值进行插补,而普通方法则会这样做。此外,PMM 方法对接近 10 的值进行了过多的插补,而普通方法更好地捕捉了分布的整体形状。然而,普通方法远未恢复真实分布(该分布一直延伸到零)。这是确定性地为 MAR 或 MNAR 变量的常见问题。我们可以通过使用辅助变量进一步改进普通插补,正如我们将在下一小节中看到的那样。
添加辅助变量
很多时候,我们会有与我们的某个具有缺失数据的变量相关的变量(例如,该变量的原因或影响),但不属于我们的回归模型。这是 mice 算法特别出色的情况,因为我们可以将这些变量添加到我们的插补模型中,以提高其准确性。然后它们被称为我们插补模型的“辅助变量”。
对于我们的 AirCnC 示例,可用的补充数据集包含两个变量,保险和活跃。前者指示客户购买的旅行保险金额,与神经质强相关;而后者则测量客户选择活跃度假(例如攀岩)的程度,并与外向性强相关。我们将使用它们来帮助插补这两个人格变量。
向插补模型添加辅助变量非常简单:我们只需在插补阶段之前将它们添加到我们的数据集中即可。
## R
augmented_data <- cbind(available_data, available_data_supp)
MI_data_aux <- mice(augmented_data, print = FALSE)
## Python
augmented_data_df = pd.concat([available_data_df, available_data_supp_df],
axis=1)
MI_data_aux_df = mice.MICEData(augmented_data_df)
我们可以像以前一样运行所有分析。在添加辅助变量时,通常有意义使用普通方法来处理与我们的辅助变量相关的变量(这里是神经质和外向性),特别是当这些变量被截断或 MNAR 时。
除了计算约束外,我们可以包含的辅助变量数量没有限制。然而,潜在风险是我们的一些辅助变量可能仅仅因为纯粹的随机性而似乎与原始数据集中的某个变量相关,例如,保险看似与外向性相关,尽管实际上并非如此。这样的“假阳性”相关性将会被插补模型错误地加强。
解决这个潜在问题的方法是仅限制辅助变量用于某些变量的插补。不幸的是,这种解决方案只在 R 中可用。这就是 mice() 函数的预测矩阵发挥作用的地方。该矩阵出现在打印插补阶段摘要时,并且还可以直接从我们的 MIDS 对象中提取:
## R
> pred_mat <- MI_data_aux$predictorMatrix
> pred_mat
age open extra neuro gender state bkg_amt insurance active
age 0 1 1 1 1 1 1 1 1
open 1 0 1 1 1 1 1 1 1
extra 1 1 0 1 1 1 1 1 1
neuro 1 1 1 0 1 1 1 1 1
gender 1 1 1 1 0 1 1 1 1
state 1 1 1 1 1 0 1 1 1
bkg_amt 1 1 1 1 1 1 0 1 1
insurance 1 1 1 1 1 1 1 0 1
active 1 1 1 1 1 1 1 1 0
该矩阵指示用于填充哪些变量。默认情况下,除了自身外,所有变量都用于填充所有变量。矩阵中的“1”表示“列”变量用于填充“行”变量。因此,我们需要修改最后两列,用于仅填充保险和活跃度到神经质和外向性:
## R
> pred_mat[,"insurance"] <- 0
> pred_mat[,"active"] <- 0
> pred_mat["neuro","insurance"] <- 1
> pred_mat["extra","active"] <- 1
> pred_mat
age open extra neuro gender state bkg_amt insurance active
age 0 1 1 1 1 1 1 0 0
open 1 0 1 1 1 1 1 0 0
extra 1 1 0 1 1 1 1 0 1
neuro 1 1 1 0 1 1 1 1 0
gender 1 1 1 1 0 1 1 0 0
state 1 1 1 1 1 0 1 0 0
bkg_amt 1 1 1 1 1 1 0 0 0
insurance 1 1 1 1 1 1 1 0 0
active 1 1 1 1 1 1 1 0 0
通过这种修改,我们将减少意外地将偶然相关性纳入我们的填充模型的风险。
扩展缺失数据集数量
mice算法在 R 中的默认生成的填充数据集数量为 5,在 Python 中为 10。这些对于探索性分析来说是很好的默认值。
在最终运行时,如果你只关心回归系数的估计值,应使用 20(通过将m=20作为mice()函数的参数设置传递)。如果你需要更精确的信息,例如置信区间或变量之间的交互作用,可能需要目标设定为 50 到 100。主要的限制因素是计算机的速度和内存——如果你的数据集大小为 100 Mb 甚至 1 Gb,你是否有足够的 RAM 来创建 100 份拷贝?——以及你的耐心。
更改填充数据集数量的语法很简单。在 R 中,它作为参数传递给mice()函数,而在 Python 中,它作为MICE对象的.fit()方法的参数传递:
## R
MI_data <- mice(available_data, print = FALSE, m=20)
## Python
fit = mice.MICE(model_formula='bkg_amt~age+open+extra+neuro+gender+state',
model_class=sm.OLS, data=MI_data_df)
MI_summ = fit.fit(n_imputations=20).summary()
结论
缺失数据在行为数据分析中可能会带来真正的问题,但这并非必然。至少,使用 R 或 Python 中的mice包及其默认参数将优于删除所有具有缺失值的行。通过基于 Rubin 的分类正确诊断缺失性,并利用所有可用信息,通常可以取得更好的效果。总结决策规则,图 6-26 展示了用于诊断缺失数据的决策树,表 6-5 展示了基于缺失类型和可用信息的最佳 MI 参数。
图 6-26. 诊断缺失数据的决策树
表 6-5. 根据缺失类型和可用信息的最佳 MI 参数
| 缺失类型 | 无信息 | 变量分布正常 | 缺失分布确定性 |
|---|---|---|---|
| MCAR | PMM | norm.nob | |
| MAR | PMM | norm.nob | norm.nob + aux. var. |
| MNAR | PMM + aux. var. | norm.nob + aux. var. | norm.nob + aux. var. |