人工智能产品要求目录
如何在你的 ML 项目中什么都不忘记
最近我听了一个有趣的故事。一家大型石油公司向数据科学家提出了一个问题:他们要观察卡车司机在运输汽油时是否遵守了安全指示(特别是,他们是否在车厢内吸烟)。过了一段时间,数据科学家提出了一个解决方案——一个看起来完美的硬件模块:它记录视频,使用神经网络进行评估,并以非常低的错误率触发警报。唯一的问题是,该模块太大,无法安装在卡车驾驶室的任何地方。
照片由 PIXNIO 拍摄
总的来说,如果不整合到更大的技术背景中,工业中几乎没有任何机器学习模型会增加价值。由于所有的决策和工作都遵循系统的需求,获得正确的需求是绝对关键的。每一个被遗忘的需求都增加了您以后不得不重新构建部分解决方案的可能性,或者在最坏的情况下,从头开始重新构建。这意味着浪费精力,不能按时交付,失去客户的信任。
需求工程是在软件开发过程中建立起来的一门学科。对于软件项目,也有一些模板和清单,它们有助于不忽略任何涉众或需求。正如我们所知,机器学习解决方案有一些其他项目中没有的特殊性:
- 与数据集相关的一切
- 实验再现性
- 伦理问题
- 上下文漂移
- 等等。
因此,拥有一个人工智能解决方案的需求目录是很好的。我在网上找到的所有东西都只包含一些你需要问的问题。因此,我创建了一个新的目录,旨在尽可能完整(见下文摘录)。
重要提示:如果与包含常规软件系统要求的另一个目录/模板一起使用,此目录涵盖了所有内容。这样的目录已经存在很长时间了,所以没有理由重复这项工作。我推荐 Volere 模板(老免费版,新付费版),不过你也可以用另一个选项。这里提供的目录应该通过将机器学习特定部分添加到通用软件需求中来缩小差距。
Volere 模板结构
如何使用这个目录(和 Volere 模板)通常取决于用户。在我看来,务实的方法是在启动 DS 项目时仔细检查问题(对于某些需求,在项目过程中进行澄清可能更有意义。)努力找到每个问题的答案。像“在我们的上下文中无关紧要”这样的回答是明确允许的。对于其余项目,搜索相关的利益相关者,询问他们,并记录他们告诉你的内容。
你可以在这里找到目录,它是免费的。
欢迎对该目录进行改进和更改的请求——请提交请求或打开 GitHub 问题。
CatBoost CPU 训练加速技巧
使用 CatBoost 获得更快的训练速度,即使您没有单独的 GPU
图片来自pix abaycebbi
我与这些公司都没有关系。这是一项独立审查。
本文面向那些没有配备独立(独立)NVIDIA GPU(显卡)的 PC 或笔记本电脑,并且希望运行大幅加速的 CatBoost 模型的用户。
如果你已经有一台带独立 NVIDIA GPU 的 PC 或笔记本电脑,跳过这篇内容,跳到下面这篇我写的文章。
</10x-times-fast-catboost-training-speed-with-an-nvidia-gpu-5ffefd9b57a6>
CatBoost 模型可以使用 CPU 或 GPU 进行训练。很明显,对于大型数据集,通过 GPU 训练可以获得更好的加速(例如 10 倍)。
但是,在 CatBoost CPU 训练中可以使用一些技巧来实现显著的加速。其中大多数可以通过改变参数值来实现,而其他的则需要对数据进行一些操作。
让我们来探索它们。
减少迭代次数
在 CatBoost 模型中,boosting 轮次或迭代次数由参数iterations
定义。默认值为 1000。我们可以减小这个值来加快训练速度。
cb = CatBoostClassifier(iterations=100)
cb = CatBoostRegressor(iterations=100)
我用一个 10M 行的数据集测试了 100 次和 1000 次迭代:
- **100 次迭代:**训练时间 95.5 秒,准确率 0.72 分
- 1000 次迭代: 878 秒训练时间,0.74 精度分数
在将迭代次数减少 10 倍后,您可能会期望精确度分数略有下降,但是在模型训练中您可以获得 9 倍的加速。
**注:**CatBoost 模型中的学习率与迭代次数成反比。如果你减少迭代次数,你也需要增加学习率,反之亦然。但是,该算法会根据迭代次数自动调整学习率。学习率还取决于数据集的大小。在 CatBoost 模型中设置learning_rate=None
(默认)即可。
使用所有 CPU 核心
不是每个人都有独立的 GPU。但是,您可能有一个内核数量更多的好 CPU。参数thread_count
定义了在 Catboost 模型训练中 CPU 应该使用多少内核。默认情况下,所有内核都由 CPU 使用。这用-1 表示。
cb = CatBoostClassifier(thread_count=-1)
cb = CatBoostRegressor(thread_count=-1)
我已经用一个 10M 行的数据集对 3 个内核和 6 个内核(在我的例子中是所有的T2内核)进行了测试:**
- **3 核:**训练时间 119 秒,准确率 0.72 分
- 6 核: 95.5 秒训练时间,0.72 准确率分数
准确性分数不受训练过程中使用的 CPU 核心数量的影响。在这种情况下,如果使用所有(默认)CPU 内核,您可以减少大约 25%的训练时间。
减少树的深度
您可以定义每个提升回合中添加到集合的每个新树的深度。该值可由 CatBoost 模型中的参数depth
控制。默认值为 6。我们可以减小这个值来加快训练速度。
cb = CatBoostClassifier(depth=3)
cb = CatBoostRegressor(depth=3)
我用一个 10M 行的数据集对树深度 3 和 6 进行了测试。
- 深度-3: 训练时间 95.5 秒,准确率 0.72 分
- 深度-6: 训练时间 127 秒,准确率 0.74 分
在降低树深度后,您可能会期望精确度分数略有下降,但是在模型训练中您可以获得大约 33%的加速。
将对象数据类型转换为分类数据类型
您可以在 CatBoost 中直接使用分类特征。下面是如何。默认情况下,Pandas 将分类值存储在不能直接用于 CatBoost 的对象数据类型中。您有两个选择来克服这个问题:
- 您可以通过使用 Pool() 类将整个数据集转换为 CatBoost 的特殊 Pool 数据类型。
- 您可以将 对象 数据类型转换为 类别 数据类型。
for col in data.select_dtypes(include=['object']):
data[col] = data[col].astype('category')
使用第二个选项可以在 CatBoost 模型训练中实现显著的加速。
使用 Numpy 数组代替 Pandas 数据框
Numpy 数组和 Pandas 数据帧都可以用作 CatBoost 算法的输入。但是,对大型数据集使用 Numpy 数组将显著加快 CatBoost 训练过程。
摘要
CatBoost GPU training 只有在您的 PC 配有 NVIDIA GPU 的情况下才能使用。此外,请注意,如果数据集不够大,CPU 和 GPU 的训练时间不会有太大差异。
因此,在我们只需要使用 CPU 进行 CatBoost 训练的场景中,我们今天讨论的技巧对于获得加速非常有用。
在大多数情况下,我们可以通过改变参数值来控制训练速度。有时候,我们不需要改变价值观。默认值将提供最佳的训练速度!
阅读下一条(推荐):
使用 NVIDIA GPU 将训练 CatBoost 模型的速度提高 10 倍!
</10x-times-fast-catboost-training-speed-with-an-nvidia-gpu-5ffefd9b57a6>
阅读下一条(可选):
为数据科学和机器学习任务选择合适的笔记本电脑!
</20-necessary-requirements-of-a-perfect-laptop-for-data-science-and-machine-learning-tasks-7d0c59c3cb63> [## 数据科学和机器学习任务对完美笔记本电脑的 20 项必要要求
towardsdatascience.com](/20-necessary-requirements-of-a-perfect-laptop-for-data-science-and-machine-learning-tasks-7d0c59c3cb63)
今天的帖子到此结束。
如果您有任何反馈,请告诉我。
同时,你可以 注册成为会员 来获得我写的每一个故事,我会收到你的一部分会员费。
非常感谢你一直以来的支持!下一个故事再见。祝大家学习愉快!
特别感谢 Pixabay 上的 cebbi ,为我提供了这篇文章的封面图片。
鲁克山普拉莫迪塔
2021–11–21
6 分钟后 CatBoost 回归
Python 中 CatBoost 回归分析的简单实用介绍
马库斯·斯皮斯克在 Unsplash 上的照片
本文旨在提供一个实践教程,在 Sci-Kit Learn library 的波士顿住房数据集上使用 CatBoost 回归器。
目录
- CatBoost 简介
- 应用
- 最终注释
介绍
CatBoost 是一种相对较新的开源机器学习算法,由一家名为 Yandex 的公司在 2017 年开发。Yandex 是谷歌的俄罗斯同行,从事搜索和信息服务。
CatBoost 的核心优势之一是能够将各种不同的数据类型(如图像、音频或文本特征)集成到一个框架中。但 CatBoost 也提供了一种处理分类数据的特殊方式,需要最少的分类特征转换,这与大多数其他机器学习算法相反,它们不能处理非数值。从功能工程的角度来看,从非数字状态到数字值的转换可能是一项非常重要和繁琐的任务,CatBoost 使这一步变得过时。
CatBoost 建立在决策树和梯度推进的理论之上。boosting 的主要思想是顺序组合许多弱模型(表现略好于随机机会的模型),从而通过贪婪搜索创建一个强有力的竞争预测模型。因为梯度提升顺序地拟合决策树,所以拟合的树将从先前树的错误中学习,从而减少错误。将一个新函数添加到现有函数的过程一直持续到选定的损失函数不再被最小化。
在决策树的生长过程中,CatBoost 并不遵循相似的梯度推进模型。相反,CatBoost 会生成不经意树,这意味着树是通过施加以下规则来生成的:同一级别的所有节点使用相同的条件测试相同的预测器,因此可以使用按位运算来计算叶的索引。不经意树过程允许简单的拟合方案和 CPU 上的效率,而树结构作为正则化来操作,以找到最佳解决方案并避免过度拟合。
比较计算效率:
学习速度,Yandex [2]
根据 Google trends,与更流行的 XGBoost 算法相比,CatBoost 在搜索流行度方面仍然相对不为人知。
谷歌趋势(2021 年)[3]
CatBoost 仍然相当未知,但该算法通过其处理异构、稀疏和分类数据的方法提供了巨大的灵活性,同时仍然支持快速训练时间和已经优化的超参数。
应用
本教程的目标是为 Python 中的 CatBoost 回归提供实际操作体验。在这个简单的练习中,我们将使用波士顿住房数据集来预测波士顿的房价。但是对这些数据应用的逻辑也适用于更复杂的数据集。
所以让我们开始吧。
首先,我们需要导入所需的库和数据集:
import catboost as cb
import numpy as np
import pandas as pd
import seaborn as sns
import shap
import load_boston
from matplotlib import pyplot as pltfrom sklearn.datasets
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score
from sklearn.inspection import permutation_importanceboston=load_boston()boston = pd.DataFrame(boston.data, columns=boston.feature_names)
数据探索
检查数据集中的任何 Na 值始终被认为是一种好的做法,因为它会混淆甚至损害算法的性能。
boston.isnull().sum()
但是,该数据集不包含任何 Na。
在进行数据科学项目时,数据探索和特征工程阶段是一些最关键(也是最耗时)的阶段。但是在这种情况下,主要重点是介绍 CatBoost 算法。因此,如果你想深入描述性分析,请访问 EDA &波士顿房价预测【4】。
培养
接下来,我们需要将数据分成 80%的训练集和 20%的测试集。
目标变量是“MEDV”——以 1000 美元为单位的自有住房的中值
X, y = load_boston(return_X_y=True)X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state=5)
为了训练和优化我们的模型,我们需要利用 CatBoost 库集成工具将特征和目标变量组合成训练和测试数据集。该池允许您精确定位目标变量、预测值和分类特征列表,而池构造器将组合这些输入并将其传递给模型。
train_dataset = cb.Pool(X_train, y_train)
test_dataset = cb.Pool(X_test, y_test)
接下来,我们将介绍我们的模型。
model = cb.CatBoostRegressor(loss_function=’RMSE’)
我们将使用 RMSE 测量作为我们的损失函数,因为它是一个回归任务。
在算法适合特定任务的情况下,参数调整可能会有所帮助。CatBoost 库为固有的网格搜索技术提供了一个灵活的接口,如果您已经知道 Sci-Kit 网格搜索功能,您也会熟悉这个过程。
在本教程中,将只包括最常见的参数。这些参数包括迭代次数、学习速率、L2 叶正则化和树深度。如果你想发现更多的超参数调整的可能性,查看 CatBoost 文档这里。
grid = {'iterations': [100, 150, 200],
'learning_rate': [0.03, 0.1],
'depth': [2, 4, 6, 8],
'l2_leaf_reg': [0.2, 0.5, 1, 3]}model.grid_search(grid, train_dataset)
性能赋值
我们现在已经完成了模型的训练,我们最终可以对测试数据进行评估了。
让我们看看模型的表现。
pred = model.predict(X_test)
rmse = (np.sqrt(mean_squared_error(y_test, pred)))
r2 = r2_score(y_test, pred)print(“Testing performance”)
print(‘RMSE: {:.2f}’.format(rmse))
print(‘R2: {:.2f}’.format(r2))
测试性能
如上所述,我们在测试集上实现了 90%的 R 平方,考虑到最小特征工程,这是非常好的。
在推理方面,CatBoost 还提供了提取可变重要性图的可能性。因此,可变重要性图可以揭示人眼可能看不到的潜在数据结构。
在本例中,我们按升序对数组进行排序,并绘制一个特征的水平条形图,其中最不重要的特征位于底部,最重要的特征位于顶部。**
**sorted_feature_importance = model.feature_importances_.argsort()
plt.barh(boston.feature_names[sorted_feature_importance],
model.feature_importances_[sorted_feature_importance],
color='turquoise')
plt.xlabel("CatBoost Feature Importance")**
可变重要性图
根据图示,上面列出的这些特征为预测波士顿房价提供了有价值的信息。最有影响的变量是每所住宅的平均房间数(RM)和较低地位人口的百分比(LSTAT)。
沙普利附加解释(SHAP)图也是一种解释我们的机器学习模型的输出的方便工具,通过为给定预测的每个特征分配重要性值。SHAP 值允许解释驱动我们的目标变量预测的特征。
**explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_test)shap.summary_plot(shap_values, X_test, feature_names = boston.feature_names[sorted_feature_importance])**
SHAP 图
在 SHAP 图中,要素根据其平均绝对 SHAP 进行分级,颜色代表特征值(红色高,蓝色低)。SHAP 值越高,预测者的属性越大。换句话说,SHAP 值代表预测者对模型输出变化的责任,即预测波士顿房价。这揭示了,例如,较大的 RM 与上升的房价相关,而较高的 LSTAT 与下降的房价相关,这也是直觉上有意义的。
如果你想了解更多关于 SHAP 情节和 CatBoost,你可以在这里找到文档。
最终注释
因此,在本教程中,我们使用 Python 成功构建了一个 CatBoost 回归器,它能够预测波士顿房价 90%的可变性,平均误差为 2,830 美元。此外,我们还研究了可变重要性图以及与波士顿房价预测相关的特征。如果您想了解更多,我建议您也尝试其他数据集,并深入研究定制和评估您的模型的许多方法。
感谢阅读!
来源
[1] Yandex,公司简介,(2020),https://yandex.com/company/
[2] Catboost,Catboost 概述(2017),https://catboost.ai/
[3]谷歌趋势(2021),https://trends.google.com/trends/explore?date = 2017-04-01% 202021-02-18&q = CatBoost,XGBoost
[4] A. Bajaj,EDA & Boston House Cost Prediction(2019),https://medium . com/@ akashbajaj 0149/EDA-Boston-House-Cost-Prediction-5 fc 1 BD 662673
记录 SQL Server 中的错误,否则这些错误会被忽略(+示例)
检测、分析和记录我的查询中的错误
当查询执行失败时,我可以看到哪里出错并调整我的查询。通常像存储过程这样的数据库对象会被 API 或其他存储过程调用。当出现问题时,没有人会注意到,通常几个小时、几天或几周后,当客户打电话给你说一些数据丢失时,你会注意到。
理想情况下,您希望尽快知道数据库出错的原因、时间和位置,以便可以修复查询。本文向您展示了一种监视数据库进程和检测何时出错的简单方法。
准备
SQL Server Management Studio 在捕捉大量语法错误方面做得很好。尽管有时错误是不可预料的。考虑依赖用户输入或使用动态 SQL 创建查询的情况。我将使用一个简单的查询来说明意外的用户输入;一个完全不必要的存储过程,允许用户指定一个表。然后,SP 将检索该表记录计数。
对于不熟悉动态 SQL 的人:在这个 SP 中,我们可以确定查询的内容。我们声明一个名为@query 的字符串,它包含我们想要执行的查询。用户可以将他们的模式名和表名传递给存储过程。然后,SP 将创建查询并执行它。
让我们测试一下我们的 SP 是否真的工作:
计算 sys.columns 表中的记录数
太好了,成功了!但是当我们传递一个不存在的模式或表时会发生什么呢?
试图计算一个不存在的模式中的记录数
问题是我们的剧本失败了,被删掉了。当我坐在笔记本电脑前执行这个脚本时,我看到并理解了错误,因此我可以做些什么。但是想象一下,如果这个 SP 被一个或多个 API 调用。这里没有用户参与,所以错误不会被注意到。在我们的脚本中检测这些类型的错误是非常重要的,所以让我们来看看我们将如何准确地做到这一点。
检测和记录错误
使用 Try-Catch 块很容易检测错误;大多数程序员都很熟悉它们。SQL Server 中一个不太为人所知的特性是,如果代码失败,您还可以获得各种信息。在下面的 SP 中,我们以ERROR_MESSAGE()
为例获取更多信息。
再次使用一些错误的参数EXEC dbo.tablecounter 'sys', 'columns';
执行这个 SP 会产生下面的输出。请注意,我们还获得了发生错误的 SP 的名称(obj_name)。
记录您的错误
我们有工具来创建一个非常好的函数来记录我们所有的错误。让我们从创建一个存储所有错误信息的表开始。
现在,我们修改前面的存储过程,以便在出现错误时记录错误。它还会打印出一条消息,以便我们进行测试:
现在我们有了一个表,我们可以监视该表来查看在我们实现了错误日志记录功能的数据库中发生的所有错误。让我们用下面的查询试几次。第一个查询将会成功;其余的都会失败。
EXEC dbo.tablecounter 'sys', 'columns';
EXEC dbo.tablecounter 'sys', 'taaables';
EXEC dbo.tablecounter 'nope', 'columns';
EXEC dbo.tablecounter null, 'columns';Select *
FROM dbo.ErrorLog;
执行这些过程将在我们的 ErrorLog 表中产生以下记录。
我们的误差记录表
如您所见,您可以通过 ErrorDateTime 和 my the eminent(userName)来过滤该表。您还可以使用 ObjectName 回溯代码(我们的错误发生在“tablecounter”存储过程中)。还要注意,在我们的新脚本中,我们有可能引发错误。如果没有设置模式名或表名,我们选择让脚本失败。然后,我们可以指定自己的 ErrorMessage(参见 ErrorLog 表中的记录#3)。
一旦我们实现了这个表,可能性是无限的:
- 我们可以创建一个监视器,它每分钟刷新一次,并查询这个表中最后一分钟的记录
- 向跟踪其状态的错误日志中添加新表(0 =新,1 =已解决等)
- 我们可以使用触发器来扩展更多的功能,例如将消息推入消息队列。您可以在消息队列上连接多个服务(一旦记录了错误,就会收到一封电子邮件!)
结论
在代码中需要的地方应用 Try-Catch 块,但是不要忘记记录错误。这些提供了有价值的信息,有助于找出那些不被注意的 bug。狩猎愉快!
—迈克
页(page 的缩写)学生:比如我正在做的事情?跟着我!
分类交叉熵和 SoftMax 回归
实践教程
想知道如何为多类问题实现一个简单的基线模型吗?这里有一个例子(包括代码)
学习由尼克·杨森CC BY-SA 3.0阿尔法股票图片
虽然它的根源是统计学,但逻辑回归是解决机器学习中二元分类问题的一种相当标准的方法,也是迄今为止现实生活应用中此类分类任务最常用的算法。然而,通过设计,它只能处理二元分类问题,即待分类的物体属于两类中的一类的问题(例如,故障与否、通过或失败、生病或健康等)。但是如果你有两个以上的课呢?SoftMax 回归来了!
SoftMax 回归是二元逻辑回归的一个相对简单的扩展(如果需要的话,参见本文后的快速回顾),用于多类问题。而后者依赖于所谓的二元交叉熵的最小化
前者依赖于其推广的最小化:分类交叉熵
其中 1{y = k} 是一个指标函数(即:如果例子属于类 k 则 1{y =k} = 1 ,否则为 0 )。但是这个数学术语是什么?我如何从两个班级变成任意数量的班级?更重要的是,如何训练我的模型比简单的梯度下降更有效?我们将在下面解决这些问题,并提供一个简单的 Python 实现(我们将实际实现它,而不是依赖 scikit-像许多其他帖子一样学习……)。但首先让我们简单介绍一下 SoftMax 函数!
SoftMax 函数的(简要)介绍
SoftMax 函数是普遍存在的逻辑函数的推广。它被定义为
其中指数函数被逐元素地应用于输入向量***【z】的每个条目。归一化确保输出向量【σ(z)***的分量之和等于 1。至于经典的逻辑函数,它的所有输出都在 0 和 1 之间,这使得它成为模拟多类问题中概率分布的自然候选。它继承了逻辑函数的大部分属性,对我们来说最重要的属性是
其中,如果 i = k ,克罗内克符号 δ 等于 1,否则等于 0。
SoftMax 回归的分类交叉熵的性质
给定一个示例 x ,softmax 函数可用于模拟其属于类别 y = k 的概率,如下所示
其中 W 是我们模型的参数。因此,我们的目标是找到参数 W ,使得模拟的概率函数尽可能接近真实的概率函数。至于二进制逻辑回归,这将涉及到利用取幂技巧使似然函数最大化(或者等效地使负对数似然性最小化)。因为从我们的概率分布的定义到分类交叉熵紧密跟随我们对二元逻辑回归所做的,因此如果你需要快速刷新,我推荐你到相应的帖子。
凸函数
我们的目标是找到最小化分类交叉熵的权重矩阵 W。然而,在最一般的情况下,一个函数可能有多个极小值,寻找全局极小值被认为是一个困难的问题。尽管如此,可以证明最小化 SoftMax 回归的分类交叉熵是一个凸问题,因此,任何最小值都是全局的!
让我们推导目标函数的梯度。为了便于我们的推导和后续实现,考虑分类交叉熵的矢量化版本
其中, X 的每一行都是我们的训练示例之一, Y 是独热编码标签向量,并且日志是按元素方式应用的。最后,⊙表示哈达玛乘积,即两个矩阵的逐元素乘法。使用矩阵计算的一些元素,我们的损失函数相对于 W 的梯度由下式给出
再一次继续这种推导会得出我们问题的结论。同样,它非常接近本文后中提出的逻辑回归推导。从那里,很容易看出它的最小特征值大于或等于零。因此,它是对称正半定的,我们的优化问题是凸的!
过度参数化
在继续讨论如何找到最优解和代码本身之前,让我们强调一下 SoftMax 回归的一个特殊属性:它是过度参数化!模型的一些参数是多余的。从 P(y=i|x) 的定义出发,可以看出,从每个权重向量 w 中减去任意一个向量 v 并不会改变模型的输出(留给读者一个练习,我首先是个老师!).权重矩阵 W 因此包含一个解决问题不需要的额外权重向量。如果不考虑这种冗余,我们的最小化问题将允许无限数量的同样可能的最优解。不失一般性,我们因此可以假设例如与最后一个类相关联的权重向量 w 等于零。这样做使我们能够摆脱这个过度参数化的问题。
怎么最小化?
与线性回归不同,SoftMax 回归不存在封闭形式的解决方案。然而,分类交叉熵在当前情况下是凸函数,任何来自凸优化的技术仍然保证找到全局最优。在这篇文章的其余部分,我们将使用梯度下降的稍微改进版本,即具有(自适应)最佳学习速率的梯度下降,来说明 SoftMax 回归的实现。
最优学习率梯度下降
在机器学习中,梯度下降的变化是模型训练的主力。在该框架中,权重矩阵 W 按照简单规则迭代更新
直到达到收敛。这里α被称为学习速率或步长。使用恒定的学习速率是很常见的,但是如何选择呢?简单的数学表明分类交叉熵函数的 Lipschitz 常数(使用 Frobenius 范数)为
其中 k 是所研究问题中不同类的数量,因此“最优”学习速率大约为
较大的学习速率会导致计算发散。一个小得多的值会产生收敛,但代价是大量的迭代。或者,可以在每次迭代中使用(不精确)线搜索,以获得自适应/最佳学习速率。下面是相应算法的一个简单 Python/SciPy 实现,使用 Brent 的方法来寻找准最优学习率。假设您已经熟悉 Python,代码应该是不言自明的。
虽然它确保了目标函数在每一步都会减少,但这种实现方式决不是优化的。通过稍微重构代码可以获得一些性能上的提升,尽管会牺牲可读性(我认为在这样一篇介绍性的文章中可读性更重要)。此外,可以使用更有效的优化技术,例如动量梯度下降、牛顿-拉夫森方法、随机梯度下降、ADAM 等。然而,这种梯度下降的变体对于编码来说足够简单并且相当有效。因此,我建议坚持把它作为一个起点,一旦你适应了,就继续使用更高级的优化程序。
超越普通的 SoftMax 回归
像它的二元对应物(即逻辑回归)一样,SoftMax 回归是一个相当灵活的分类任务框架。因此,多年来已经提出了许多变体来克服它的一些限制。
处理非线性可分离的类
通过构造,SoftMax 回归是一个线性分类器。就像线性回归可以扩展到建模非线性关系一样,logistic 和 SoftMax 回归也可以扩展到对非线性可分的点进行分类。然而,这样做可能需要专业知识、对数据属性的良好理解以及特征工程(与其说是精确的科学,不如说是一门手艺)。
不平衡的阶级分布
使用交叉熵时隐含的事实是,我们的训练数据集中每个类的流行程度大致相同。然而,现实生活中有许多情况并非如此。在二元分类中用于不平衡分类的相同技巧可以适用于多类问题,特别是对成本敏感的训练(更多细节见本帖)。
正规化
在机器学习中,处理以大量特征为特征的数据是相当常见的。然而,并非所有这些特征都可以为预测目的提供信息。以 MNIST 数据集上的数字分类为例,这些特征是影像的 784 个不同像素。
来自 MNIST 数据集的手写数字的随机子集(图片由作者提供)。
然而,这些图像是标准化的,最外面的像素为所考虑的任务提供很少或没有信息。在这种情况下,有可能正则化优化问题,使得与无信息特征相关联的系数被设置为零。这个问题最简单的这种促进稀疏性的正则化版本如下
其中*CCE(w)*是分类交叉熵的简写符号, W 的ℓ₁-norm 是其条目的绝对值之和。参数λ控制交叉熵函数的最小化和权重矩阵的期望稀疏度之间的权衡。解决这个新的优化问题只需要对提供的代码做一些小的修改。
结论
在过去的十年中,深度神经网络获得了很大的吸引力,似乎可以在任何地方和任何事情上使用。虽然在某些领域(例如计算机视觉)这可能是真的,但许多更经典的领域仍然依赖于更简单但成熟的技术(例如在制造业)。从数学和计算的角度来看,由于其简单性和灵活性,SoftMax 回归是迄今为止现实生活应用中最常用的多类分类技术。在机器学习中,尽管深度网络具有优势,但它仍然是一个优秀的基线模型,用于评估通过转向更复杂的神经网络模型实际上获得了什么(即,它真的值得吗?).
我希望您现在对什么是 SoftMax 回归、它是如何工作的以及它是如何实现的有了更好的理解。像往常一样,有很多我们没有涉及的内容(例如,模型的统计解释,如何超越简单的准确性度量等),但互联网(以及针对特定问题的数据科学)充满了优秀的资源!去看看吧!此外,不要犹豫,自己推导这里给出的所有数学结果,并使用提供的代码!请告诉我这些内容是否对您有用,或者您是否发现了任何错别字:]
*想阅读更多此类内容吗?*查看我其他关于低秩结构和数据驱动建模 的文章或者干脆我的 机器学习基础知识 !
分类数据、Jaccard 系数和多重处理
威廉·克劳斯在 Unsplash 上的照片
佛罗里达州的机场比海得拉巴的机场更靠近底特律机场,我们知道这一点是因为我们使用纬度和经度来测量距离(海得拉巴是印度的一个大城市)。但是,我们如何说一个购物篮的内容更接近另一个呢?或者一个森林和另一个森林在生活的动物方面更相似?我们可以将这些视为集合之间的比较,并使用 Jaccard 系数(我们将互换使用系数和相似性得分)来度量它们之间的相似性(或不相似性)。对于大型数据集,这可能是一项很大的任务,因此我们可以使用并行处理在较短的时间内完成它。见上的完整笔记本kaggle。
搭建舞台的快速示例
因此,当比较两个集合(可以是一个数组、一个序列,甚至是一个二进制值的向量)时,分子是集合之间共享的元素数,分母是两个集合中的元素数。在我们的例子中,分母是任一集合的大小,所以我们也可以说这个相似性得分是共享元素的数量除以可以共享的元素的数量。
让我们看一个简单的例子:
from sklearn.metrics import jaccard_score
from scipy.spatial.distance import jaccardx = [[1,1,1],[1,0,1],[0,0,0]]print(x)
[[1, 1, 1], [1, 0, 1], [0, 0, 0]]jaccard(x[0],x[1])
0.33jaccard_score(x[0],x[1])
0.66
数组 x 有三行。第一行是我们希望比较的观察值。请注意 Jaccard 函数是如何返回前两行之间不共享的元素数量的。jaccard_score 函数返回相反的结果:它是前两行之间共享的元素数量。一个表示不同,一个表示相似。我个人更喜欢 scikit-learn 中提供的相似性评分,但重要的是你要意识到其中的区别。
(还要注意,有些人认为元素 0 根本不应该包含在计算中。在某些情况下,这是有意义的。)
既然我们已经在一个简单的案例中看到了这个指标,那么让我们将它应用到一个更大的数据集。
用 Jaccard 和并行处理测量距离
import numpy as np
import pandas as pdx0 = np.random.choice([0, 1], size=(100000,100), p=[4./5, 1./5])
x1 = np.random.choice([0, 1], size=(100000,100), p=[1./3, 2./3])
x2 = np.random.choice([0, 1], size=(100000,100), p=[1./2, 1./2])colnames = ['x_'+str(i) for i in range(0,100)]X = pd.DataFrame(data = np.stack([x0,x1,x2]).reshape(300000,100))
X.columns = colnamestarget = np.ones(100).astype(int)
我们的目标是所有特征都设置为 1 的一个观察。想象一下,一个购物篮购买了网上商店的所有商品,你想看看哪些观察结果最接近它。这主要是为了示例的目的,但是您可以看到这如何扩展到其他用例。
使用二进制值数据(1 和 0)创建了一个巨大的 300k 观察值阵列,以代表指标特征或虚拟变量。第一个三分之一是 1 的概率是 1/5,第二个三分之一是 2/3,最后一个三分之一是 1/2。让我们看看有多少观察结果与我们的目标重叠,重叠了多少!但是首先,让我们利用多重处理包并创建一个分部函数来并行比较几个观察值和目标值(这是一个巨大的时间和内存节省)。
from functools import partial
import multiprocessing as mppartial_jaccard = partial(jaccard_score, target)with mp.Pool() as pool:
results = pool.map(partial_jaccard, [row for row in X.values])
上面的代码花了差不多一分钟的时间(大约 50 秒)。这是经过多重处理和对 100 个特征进行 30 万次观察后得出的结果。您可能会遇到包含更多要素和更多观测值的数据集。试图在一个循环中完成上述任务导致我的电脑完全崩溃(蓝屏/皱眉头),但如果你够勇敢,那么你应该尝试一个数据子集,看看需要多长时间。
下面是结果。您将看到,对于前三分之一的数据(有 1/5 概率为 1 的数据),您可以看到有一个 Jaccard 相似性得分为 0.2 (20%)的峰值。其他峰值也是如此。这证实了比较是与我们的多重处理和部分功能一起工作的。
结论
当您有二进制数据(如指标特征或虚拟变量的情况)并且您想要在您的观察值之间创建某种类型的距离度量时,请考虑这个 Jaccard 的系数/相似性得分。这相当直观,但是需要一点额外的工作来对大量数据进行测量。考虑将此指标用于仪表板或报告,如果您考虑将其用于聚类任务,请记住,进行成对比较对于您的计算机来说是一项巨大的任务,您应该考虑制作聚类中心并与之进行比较。
参考文献
https://en.wikipedia.org/wiki/Jaccard_index https://scikit-learn.org/stable/modules/generated/sklearn.metrics.jaccard_score.html https://github.com/caseywhorton/medium-blog-code
BTS 歌曲特征分类:一个多维聚类案例
使用 Spotify 音频功能对 BTS 歌曲进行聚类,使用 Python 中的 PCA 和 t-SNE 对聚类进行可视化
生活在 2021 年的年轻人对 BTS 一无所知几乎是不可能的。至少,你会听说过他们的名字,甚至他们的热门歌曲。我开始注意到他们的歌曲后,“男孩与爱”击中,并一直在享受其他热门歌曲,如“炸药”,以及最近的“黄油”。
这里我分析一下 BTS 歌曲的音频特征。我正在使用 Spotify 和的音频功能,根据这些属性对歌曲进行聚类,希望找到其他与我喜欢的歌曲具有类似功能的 BTS 歌曲,如《炸药》和《黄油》。
注意:完整的源代码和收集的数据可以在 this Github 中找到
数据收集
为了收集数据,我使用了 Spotify 开发者 API 。您可以注册您自己和您的应用程序,并从您的代码中获取用于 API 调用的 API 令牌。然后可以使用 Python 中的spotipy
包从 API 中检索数据。
我之前在这里分享了更多关于从 Spotify API 获取数据的细节,或者你可以在这里查看具体的 Python 笔记本。下面是我利用 Spotify API 调用并最终收集 BTS 歌曲列表及其功能的数据帧的方法。
使用 Spotify API 获取艺术家每首歌曲的音频特征(图片由作者提供)
下面是收集的数据帧的快照。关于数据收集过程的完整代码,可以去本笔记本。
音频特征的样本数据帧(图片由作者提供)
了解功能
Spotify API 为每首曲目提供了 11 种音频功能,从描述性指标(速度、音调、模式),到置信度指标(声音、语速、乐器感、响度),以及感知性指标(活力、能量、可舞性、效价)。
与任何其他探索性数据分析一样,我们从检查数据集中每个要素的汇总统计数据开始。从直方图分布中,我们可以看到 BTS 歌曲的更高的可跳舞性、能量和响度的趋势。这是意料之中的,因为舞蹈编排是韩国流行乐队不可或缺的一部分,因此他们倾向于发布适合“点”舞的关键乐观歌曲。
每个功能的价值分布(图片由作者提供)
检查该数据集中要素之间的相互作用时,我们会查看皮尔逊相关系数。响度、能量、效价和可跳性之间存在正相关。另一方面,响度与声学之间存在负相关关系;能量转化为声音。响度高的歌曲往往具有高的能量、效价和可舞性但低的声音。
音频特征中变量之间的相关性(图片由作者提供)
采样响度和能量最高的歌曲,部分歌曲在响度和能量排行榜上重叠: 荷尔蒙 Sensou —日语 Ver。 和不是今天—日文版。我在这篇文章中添加了这些歌曲的 Spotify 链接,是的,这是一首非常有活力的嘻哈歌曲:)
最高音量和能量的 BTS 歌曲(图片由作者提供)
使聚集
引用geeksforgeeks.org的话,聚类的任务是将总体或数据点分成几个组,使得同一组中的数据点与同一组中的其他数据点更相似,而与其他组中的数据点不相似。我们可以利用这一点将 BTS 歌曲分成几个组,即充满活力的嘻哈歌曲、柔和的原声歌曲等。
最广泛使用的聚类算法之一是 k-means ,它涉及到将样本分配给聚类,以最小化每个聚类内的方差。在 k-means 中,您将有 k 个质心点,数据点将根据到这些质心点的距离进行分组,到距离最小的点。
k-means 聚类的第一步是找到 k 的最佳数量,这可以使用肘方法来完成。在这里,我们计算 k 的每个潜在数量的失真(欧几里德距离)或惯性(距离的平方和)。然后我们将它们可视化,并选择失真/惯性开始线性下降的点。从这个数据来看,似乎最优 k 是 4 。点击阅读更多关于肘法的内容。
from sklearn.cluster import KMeans# Calculate sum of squared distances
ssd = []
K = range(1,10)
for k in K:
km = KMeans(n_clusters=k)
km = km.fit(df_cluster)
ssd.append(km.inertia_)# Plot sum of squared distances / elbow method
plt.figure(figsize=(10,6))
plt.plot(K, ssd, 'bx-')
plt.xlabel('k')
plt.ylabel('ssd')
plt.title('Elbow Method For Optimal k')
plt.show()
肘法(图片由作者提供)
使用来自 sci-kit-learn 库中的 KMeans 函数,我们可以获得数据集中每首 BTS 歌曲的聚类。下面是聚类结果。
kmeans = KMeans(n_clusters=4)
model = kmeans.fit(df_cluster)pred = model.labels_
df_cluster['cluster'] = pred
- 第 0 类:欢快的歌曲,可跳性和效价高,响度很大
- 集群 1:强有力的歌曲,由高能量、响度、节奏、活力来指示
- 第二类:典型的流行歌曲,活跃度和声音都很高
- 第三类:冷歌,具有很高的听觉性、舞蹈性和节奏
每个分类中 50%属性的热图(图片由作者提供)
我们通常通过绘制数据集和要素来验证聚类结果,并将聚类设置为绘图中的色调。然而,因为我们要处理 11 个特性,所以几乎不可能在同一个图中绘制。为了解决这个问题,我们可以使用降维技术。
降维
当处理具有大量要素的大型数据集时,会出现复杂情况,因为处理会计算量很大,需要处理多个测量值(即多重共线性问题)并且难以可视化数据。维度缩减技术有助于减少数据集中的要素数量**,而不必丢失太多信息并保持(或提高)模型的性能。这里使用的一些流行技术是主成分分析(PCA)和 t-分布随机邻居嵌入(t-SNE)**
主成分分析
PCA 通过从现有的一大组变量中提取一组新的变量(称为主成分)来帮助我们降维。这些主成分实际上是原始变量的线性组合。你可以在这里阅读更多关于 PCA 的内容。
from sklearn.decomposition import PCApca = PCA(n_components=3)
pca_result = pca.fit_transform(df_pca.values)
df_pca['pca-one'] = pca_result[:,0]
df_pca['pca-two'] = pca_result[:,1]
df_pca['pca-three'] = pca_result[:,2]df_pca['cluster'] = pred
df_pca
理想情况下,PCA 中主成分的数量足够小,以便能够可视化(即≤ 4 个成分),但足够大,以便解释数据集中的大多数差异(即> 70%)。我用 3 个组件进行测试,结果发现它们能够解释数据集中 99.9%的差异。第一个成分能够解释 97.5%的差异,第二个成分增加了 1.9%,第三个成分增加了 0.5%。
主成分分析中的解释方差比
在这种情况下,我们使用主成分分析来可视化我们的 K 均值聚类是否相应地分离了 BTS 歌曲。这里我使用的是 3D 图,我们可以清楚地看到聚类 0、聚类 1、聚类 2 和聚类 3 之间的分离(以色调显示);主要在 x 轴上。
ax = plt.figure(figsize=(16,10)).gca(projection='3d')
sctt = ax.scatter(
xs = df_pca["pca-one"],
ys = df_pca["pca-two"],
zs = df_pca["pca-three"],
c = df_pca["cluster"]
)ax.set_xlabel('pca-one')
ax.set_ylabel('pca-two')
ax.set_zlabel('pca-three')plt.title("3D PCA Visualization with 3 Components", fontsize=16)cb = plt.colorbar(sctt, ax=ax, shrink=0.3, aspect=4, pad=0.1)
cb.set_ticks([0,1,2,3])plt.show()
BTS 歌曲音频特征的 3D PCA 可视化(图片由作者提供)
t 分布随机邻居嵌入(t-SNE)
如果 PCA 算法使用线性函数来提取新的特征,t-SNE 算法提供了一种非线性方式来解决这个问题。它计算点在高维空间的相似概率并计算点在对应低维空间的相似概率,最小化这种成对分布。你可以在这里阅读更多关于 t-SNE 的信息。
from sklearn.manifold import TSNEtsne = TSNE(n_components=2, verbose=1, perplexity=40, n_iter=300)
tsne_results = tsne.fit_transform(df_tsne)df_tsne['cluster'] = pred
df_tsne
使用来自 sklearn 的 TSNE 类,我们可以开发具有可配置数量的组件、困惑和迭代的 t-SNE 模型。为了评估要使用的理想参数,我们可以检查 KL 散度值——目标是尽可能接近 0 。如果 KL 散度随着迭代的增加没有太大改善,我们可以停止迭代。
评估 t-SNE 中 KL 散度
绘制 t-SNE 结果将有助于我们理解早期聚类的分离以及模式是如何保持的。在这里,我们可以看到 t-SNE 2 组分变量上的聚类之间的明显差异,肯定了聚类结果。
df_tsne['tsne-2d-one'] = tsne_results[:,0]
df_tsne['tsne-2d-two'] = tsne_results[:,1]
plt.figure(figsize=(16,10))
sns.scatterplot(
x="tsne-2d-one", y="tsne-2d-two",
hue="cluster",
palette=sns.color_palette("hls", 4),
data=df_tsne,
legend="full",
alpha=0.3
)plt.title("t-SNE 2D Visualization", fontsize=16)
t-SNE 2D 可视化的 BTS 歌曲的音频特征(图片由作者提供)
解释结果
既然我们对之前在我们的聚类中完成的分离很有信心,我们可以继续关注聚类结果。看了一下结果,才知道我喜欢的几首 BTS 的歌(炸药,黄油,有 Luv 的男孩)都在同一个集群上,就是集群 0 。
回顾 PCA 图,在这里我们可以看到歌曲“炸药”和“黄油”彼此放置得非常接近,显示出较高的相似性。因此,考虑到潜在的相似性,也许接下来我可以听“我错了吗”或“水晶雪”?
聚类 0 的 PCA 组件 1 和 2 可视化(作者提供的图片)
另一方面,与 PCA 不同,t-SNE 图可视化中的轴距离可能不表示相似性。阅读这篇文章了解更多详情。
结束语
聚类是最强大的分析技术之一,因为它允许我们发现数据中的模式和组。然而,当处理高维特征时,可能难以理解和解释结果。使用降维的可视化将对此有所帮助,因为它保留了数据点内部的关键信息。除了可视化之外,降维技术还可以用作数据建模中的预处理步骤,以减少模型训练时间。
此分析的完整代码可在此处访问。
对用户上传的文档进行分类
从数据中获得的见解如何被用来帮助构建分类法,以及我们为用户上传的文档分配类别的方法。
Scribd 向我们的用户提供各种发布者和用户上传的内容,虽然发布者的内容富含元数据,但用户上传的内容通常不是。用户上传的文档具有不同的主题和内容类型,这使得将它们链接在一起具有挑战性。连接内容的一种方式是通过分类法,分类法是广泛应用于各种领域的一种重要的结构化信息。在这个系列中,我们已经分享了我们如何识别文档类型和从文档中提取信息,这篇文章将讨论如何利用数据的洞察力来帮助建立分类法,以及我们为用户上传的文档分配类别的方法。
构建分类
统一分类法是一个具有两层的树状结构,它是通过结合我们的主题专家(SME)对图书行业主题词( BISAC 类别)的知识和数据驱动的见解而设计的。我们使用用户阅读模式来寻找有助于丰富我们的统一分类法的主题。
数据驱动的洞察力
10 多年来,用户一直在与 Scribd 内容互动,随着时间的推移,建立了阅读模式。我们利用这些阅读模式来创建文档的密集向量表示,类似于文本中的 word2vec。
图 1: 我们方法的示意图:阅读序列用于为用户上传的文档创建矢量表示。所示的向量尺寸仅仅是说明性的(图片由作者提供)。
对于这项工作,我们只关注用户上传的文档和一种类型的交互(阅读时间最短)。选择嵌入维度(和其他超参数)来优化命中率@20 ( Caselles-Dupré,et al 2018 ),增加嵌入的语义紧密度。
现在我们有了嵌入,我们想用它们来查找具有相似主题和题目的文档组。找到这些组将有助于我们确定应该添加到分类法中的类别。
与我们嵌入的原始高维空间相比,维数减少允许在减少的空间中更有效和准确地发现密集的文档聚类。我们使用 t-SNE 算法来降低嵌入的维数。t-SNE 有一个非线性的方法,可以捕捉点之间的较小关系,以及数据的全局结构。我们使用了 t-SNE(基于快速傅立叶变换加速插值的 t-SNE)——FIt-SNE的实现,这种实现很灵活,不会为了速度而牺牲精度。
最后,我们通过使用 HDBSCAN 对减少的嵌入进行聚类来对用户上传的文档进行分组。HDBSCAN 根据密度分布将数据点分成簇。它还具有检测噪声的功能,噪声是指距离最近的检测到的聚类太远而不属于它的点,并且缺乏形成自己的聚类的密度。
图 2 显示了用户上传的文档及其组的 2D 表示。我们注意到并在图中强调的第一件事是,主要群体通常用语言来表示。不足为奇的是,用户倾向于阅读大多数单一语言的内容。
图 2: 使用 t-SNE 和 HDBSCAN 的嵌入的初始 2D 表示。每个彩色组代表 HDBSCAN 发现的一个星团。散布的灰点被识别为噪声(图片由作者提供)。
我们开发了一种技术,将上面的组进一步分成语义更紧密的更小的集群。最终的集群可以在图 3 中看到。
图 3: 进一步分割每个聚类后嵌入的最终 2D 表示。每个彩色组代表 HDBSCAN 为特定集群找到的一个子集群。散布的灰点被识别为噪声(图片由作者提供)。
在我们得到图 3 所示的集群和子集群之后,对英语子集群进行了检查,以便识别它们的主要主题和主题。这项调查导致分类中加入了其他类别,如菲律宾法律、学习辅助和考试准备以及教学方法和材料,从而使分类更广泛地涵盖不同的内容类型,并且浏览这些内容更加简单。
将文档分类
**图 4:**Scribd 的多组分管道图。分类是图中突出显示的下游任务之一。
现在我们有了分类法,是时候将文档分类了。我们的方法利用了本系列第二部分中讨论的提取的关键短语和实体。图 5 说明了我们的模型是如何工作的:我们训练了一个监督模型,使用关键短语、实体和文本将被识别为大量文本的文档(参见第一部分)分类。
图 5: 对文档进行分类的模型架构(图片由作者提供)。
来自数据的更多见解
在模型的第一次迭代中,我们有一个由我们的专家收集的训练数据集,以符合每个类别的定义。不足为奇的是,在对生产中的未知数据测试模型时,我们意识到对于某些类别,训练集并不能完全代表生产中适合它们的文档类型。因此,该模型无法用初始给定的训练集进行概括。例如,在初始训练集中,大多数关于美国以外国家的文档都是关于旅行的文档。这意味着该模型了解到,每当文档提到其他国家时,该文档很可能是关于旅行的。出于这个原因,例如,关于南美的商业文档将被放置在模型的 travel 下。
我们应用了一种有时被称为主动学习的技术,用缺失的例子来补充我们的训练集。按照这种技术(图 6),模型被应用于随机的文档样本,结果由我们的 SME 进行分析。
图 6: 用于提高模型性能的主动学习过程(图片由作者提供)。
这个迭代过程有两个结果:通过用大量的训练例子重新训练模型来改进分类性能,以及在我们识别出很大一部分文档符合这个特定类别之后添加一个新的类别,
附加实验
在整个项目中,进行了几个实验来探索用户交互集群的全部潜力。这里我们将展示一个令人兴奋的例子。
给集群命名
如上所述,一般来说,图 3 所示的每个子集群都是语义紧密的,这意味着属于一个子集群的文档通常是关于一个(或几个)主题/主题的。
将主题与子集群相关联的一种方式需要主题专家手动检查每个子集群中的文档,并为每个子集群提出最重要的主题。然而,这种方法不仅耗时,而且不能随着模型的新迭代和可能增加的集群数量而扩展。尝试使这成为一个更加自动化和灵活的过程是非常重要的。
我们试验了一个非常有前途的两步方法,自动将主题分配给子集群。在这种方法中,我们利用从第二部分中描述的文本中提取的信息和零射击主题分类(更多信息在此):
- 步骤 1-通过聚类子集群的文档提取信息来找到子集群的最有代表性的关键短语。
图 7: 步骤 1 的图解(图片由作者提供)。
- 步骤 2-使用步骤 1 的结果和零触发主题分类来为每个子聚类找到最高排名的主题。
图 8: 步骤 2 的图示。具有最高排名主题的条形图是这种方法对于包含关于几部文学作品的文章(由作者提供的图像)的子集群的结果。
从图 8 中可以看出,由文学作品的文章组成的集群具有最高排名的主题文学评论,显示了这种方法自动为用户交互集群命名的潜力。
结论
在对文档进行分类的过程中,有两点很重要:
- 高质量的标记数据 —我们发现干净一致的标记数据比超参数调整对模型更重要。然而,在我们多样化的语料库中获取足够多的符合类别的文档是一个挑战。使用了几种技术来提高模型在不可见数据上的性能。其中,主动学习被证明是收集额外训练样本和保证训练集中所需粒度的重要方法。
- 注释对齐 —高质量数据和模型性能都与注释过程相关联(参见此处的更多)。当多个注释者参与数据收集和评估时,每个类别定义的一致性对于模型的精确训练和评估至关重要。这在文本分类中甚至更加重要,因为将类别/主题与文本相关联可能是一项非常主观的任务,尤其是当我们处理单标签分类问题时。
这个项目是理解我们的用户上传文档的一个重要里程碑:对文档进行分类使用户能够从我们的统一分类法中按类别浏览文档。此外,我们现在有能力理解每个用户感兴趣并与之交互的类别。将用户兴趣与业务指标相结合有助于推动创新和出乎意料的产品决策,并丰富可发现性和推荐。
后续步骤
- 使用数据驱动的方法改进分类:
接下来,我们如何确保新上传的文档包含在我们的分类中?
使用数据驱动的方法来构建分类法回答了这些问题,并且与手动创建的分类法相比,保证了更大的灵活性、全面性和特异性。随着新内容上传到我们的平台并被用户阅读,新的用户互动集群将形成,并帮助我们识别最近的用户兴趣。例如,在疫情期间,用户开始上传与新冠肺炎有关的文件。例如,在 2021 年对文档进行聚类产生了与新冠肺炎相关的附加聚类,这在疫情之前是不存在的。这种方法将帮助我们建立一个不太严格的分类法,一个反映 Scribd 大量内容的分类法,并且从长远来看很容易扩展。
- 多语言:
既然我们对用户上传的英文内容有了更多的了解,而且我们有一个一致的管道来给这些文档贴标签,我们可以将这种方法扩展到其他语言
这项工作和这篇文章是我与应用研究团队的同事 Antonia Mouawad 合作完成的。如果你有兴趣了解更多关于应用研究正在解决的问题,或者围绕这些解决方案建立的系统,请查看我们的空缺职位。
猫狗卷积分类器
使用 Python 代码、Tensorflow 和 Google Colab 从头开始创建和测试一个简单的模型
3 分钟机器学习
3 分钟机器学习是一系列与机器学习世界相关的教程和内容丰富的视频。你可以在 YouTube 上找到完整的视频。库包含视频中显示的所有文件。这个系列是在实验阶段,完全免费开发,为了娱乐和文化!欢迎任何反馈。
其他剧集:
为什么要读这篇文章?
本文将会看到如何使用 Google Colab 来实现我们自己的深度学习模型的实用性和功能性。然后,我们将看到如何将一个预先存在的数据集导入到我们的工作空间中。我们将实现一个 2D 卷积神经网络模型,用于我们图像的二进制分类。一旦模型被建立和训练,我们将用新的图像测试我们的模型。
Google Colab:为什么?
Colaboratory,简称“ Colab ”,是谷歌研究院的产品。Colab 允许任何人通过浏览器编写和执行任意的 python 代码,特别适合机器学习、数据分析和教育。从技术上来说,Colab 是一种托管的 Jupyter 笔记本服务,无需设置即可使用,同时提供对计算资源的免费访问,包括GPU。点击此链接了解更多信息。
在 Google Colab 中选择运行时
当开发您自己的代码或使用共享代码时,请记住从运行时下的工具栏中选择所需的硬件加速器。对于这个案例研究,由于它是基于卷积网络的模型,所以最好使用平台上免费提供的 GPU 的的能力。总之,我们的神经网络模型有大量参数,必须使用优化算法来确定这些参数,以最小化期望的损失函数。这个过程包括前向传播和后向传播,对每个训练时期的每个批数据重复这个过程。因此,这个过程涉及到一个 大数 的简单数学运算。GPU,带有:
- 核心数量多
- 数千个并发硬件线程
允许我们更快地执行模型的训练和推理。
卷积分类器
图像分析可以通过各种深度学习和神经网络模型来执行,但是,Con voluntive Networks由于其有效性,几乎成为这种类型分析的强制工具。总而言之,一系列大小可变的过滤器的应用允许从图像本身提取信息和特征。第一层会提取出最一般的特征,越深的层越有具体的特征。同时,这种方法允许在模型的几个可训练参数下工作,这些参数远低于用专门基于致密层的神经网络分析图像所需的参数。更多信息,请参考这篇文章。
猫和狗的分类器结构-作者图片
代码
让我们从导入数据集开始:
让我们导入我们的数据集。它包含狗和猫的图像,这将允许我们训练我们的分类器。我们直接从 Google API 下载数据集,然后将其解压缩到所需的路径。我们通过定义路径来定义目录的结构。我们为训练和验证数据定义了两个独立的目录,每个目录又分为两个文件夹:狗和猫。这种结构可能看起来很复杂,但它变得特别复杂,因为它很容易与 Tensorflow 语法接口。所以让我们看看我们有多少数据。
让我们的神经网络模型,类似于前一个图像中描述的。在这种情况下,考虑到模型的简单性,我们使用 Keras 的顺序 API。这允许我们通过简单地定义不同层的列表来创建神经网络,正如我们可以从名称本身猜测的那样。使用的层是在 Tensorflow/Keras 中实现的标准层的一部分。
- Conv2D : 2D 卷积层
- MaxPooling2D:2D 空间数据的最大池操作
- 展平:展平输入
- 密集:规则密集连接 NN 层
model.summary() 显示我们模型的概要,显示每层的名称、类型、输出形状和可训练参数数量。
该型号必须编制,方可训练。对于本教程,我选择了 Adam 作为优化器,学习率固定。然而,通过优化结构和调整所有的初级和次级 超参数,该模型可以得到很大的改进。我们将评估仅仅 准确度 作为评估模型性能的主要指标。然而,准确性可能会与其他指标相结合,例如 f-Beta 得分 ,以便更可靠地评估模型的质量。
所使用的目录结构允许使用图像数据生成器和 flow_from_directory 方法。第一个允许对源图像应用缩放和数据扩充。为了进行这种分析,我们对训练图像应用了缩放、旋转、移动、剪切、缩放和翻转。您可能会注意到,没有对测试数据应用数据扩充。 flow_from_directory 方法自动加载指定路径中包含的子目录中的所有图像,并在文件夹名称后标记图像。我们只需指定图像的主路径、批量大小、分类模型和目标大小。
最后,我们可以训练模型,将训练数据存储在历史对象中。请注意,我们有 2000 个训练图像和 1000 个测试图像,批量大小为 20:对于 训练集 ,每个时期有 100 个步骤,对于 验证集 ,每个时期有 50 个步骤。让我们对网络进行少量纪元(50)的训练,看看结果。
培训历史-作者图片
在训练过程的最后,我们用我们的基本分类器在两个集合上实现了大约 80 % 的准确率 。这是一个好结果,但我们绝没有优化我们的模型,正如更长的训练似乎可能导致更高的表现。在接下来的一篇文章中,我们将看到如何使用各种超参数优化和迁移学习技术来尝试改进我们的分类器。****
您可以使用直接从本地存储空间上传的新图像来测试代码,并且立即获得一个预测。该模型虽然没有优化,但能够正确预测以下两幅图像的类别,这两幅图像是该模型在训练或验证阶段从未见过的。
测试图像—作者提供的图像
结论
我希望你喜欢这篇文章的内容。我提醒你,你可以在这里找到源代码,在 GitHub 和 YouTube 上可以找到完整的资源库。
下次见,
马尔科
因果发现
使用 Python 从数据中学习因果关系
这是关于因果关系的三篇系列文章的最后一篇。之前的帖子里介绍了因果关系的“新科学”【1】,讨论了 因果推断 的话题。本文的重点是一个相关的想法,因果发现。我将从描述什么是因果发现开始,给出它如何工作的草图,并以一个使用 Python 的具体例子结束。
因果发现的总体目标:将数据转化为因果模型。图片作者。
什么是因果发现?
在 上一篇 中,我讨论了因果推断**,旨在回答涉及因果的问题。虽然因果推理是一个强大的工具,但它需要一把钥匙来操作。也就是说,它需要一个因果模型。然而,通常在现实世界中,我们可能无法确定哪些变量是互为因果的。这就是因果发现能有所帮助的地方。**
因果发现旨在从数据中推断出因果结构。换句话说,给定一个数据集,导出一个描述它的因果模型。
它是如何工作的?
没有标准的因果发现方法。事实上,有各种各样的技术可供使用,其中任何两种可能彼此没有什么相似之处。我在这里的目标是勾画不同算法的共同主题,并给出一些关键思想的味道。
正如我在本系列的 第一篇 中提到的,因果发现是逆问题的一个例子。这就像根据冰块在厨房台面上留下的水坑来预测它的形状一样。
显然,这是一个难题,因为任何形状都可能产生同一个水坑。将这与因果关系联系起来,水坑就像是嵌入数据中的统计关联,而冰块就像是潜在的因果模型。
因果发现的 4 个常见假设
解决逆问题的通常方法是对你试图揭示的东西做出假设。这缩小了可能的解决方案的范围,有希望使问题可以解决。
因果发现算法有四个共同的假设。在参考文献【3】中可以找到对这些假设的很好的讨论。
- 无环性 —因果结构可以用 DAG (G)来表示
- 马尔可夫性质 —当以它们的父节点为条件时,所有节点都独立于它们的非子节点
- 忠实度 —真实基础分布中的所有条件独立性 p 用 G 表示
- 充分性—G 中的任何一对节点都没有共同的外因
尽管这些假设有助于缩小可能模型的数量,但它们并没有完全解决问题。这就是因果发现的一些技巧有用的地方。
因果发现的 3 个技巧
如前所述,没有一种单一的因果发现方法能支配所有其他方法。尽管大多数方法都使用上述假设(甚至更多),但不同算法的细节可能会有很大差异。
下图给出了基于以下技巧的算法分类。这绝不是一个详尽的概述。更确切地说,这是我从引用的参考资料[ 2 、 4 、 5 ]中偶然发现的算法集合。
基于[ 2 、 4 、 5 ]的因果发现方法的狭义分类。图片作者。
招数 1:条件独立性测试
这些最早的因果发现算法之一是以其作者 Peter Spirtes 和 Clark Glymour 命名的 PC 算法。这种算法(以及其他类似的算法)使用了这样一种思想:两个统计上独立的变量****没有因果联系。PC 算法说明了第一个技巧。下图给出了算法的概要。关于 PC 算法的更多细节,我推荐参考文献[2&[6]中的讨论。****
第一步是使用数据集中的每个变量形成一个完全连通的无向图。接下来,如果相应的变量是独立的,则删除边。然后,连接的边经受条件独立性测试,例如上图中以中间节点为条件的底部和最右侧节点的独立性测试(步骤 2)。
如果对一个变量的条件化消除了依赖性,则该变量被添加到这两个变量的分离集中。根据图表的大小,条件独立性测试将继续进行(即更多变量的条件),直到不再有候选测试。
接下来,碰撞器(即 X → Y ← Z)基于节点对的分离集被定向。最后,剩余的边基于 2 个约束被定向,1)没有新的 v-结构,以及 2)不能形成定向的环。
招数二:图形空间的贪婪搜索
这个技巧有三个主要元素:一个图,一个图空间,以及一个贪婪搜索。
图是由边(线)连接的顶点(圆)组成的数学结构。因果模型通常使用一种特殊的图,称为有向无环图(DAG)。图和 Dag 在 第一帖 中讨论过。简而言之,DAG 是一种顶点之间的边带有箭头并且不存在循环的图。
一个图空间是图的集合。这只是一种形式化的奇特方式,即对于给定数量的顶点和边,有许多可能的图。例如,一个有 2 个顶点和 1 条边的 DAG 可以采用以下形式:A → B 或 B → A。请注意,这是前面冰块逆问题的另一个例子。然而,不是多个冰块可能产生相同的水坑,而是多个 Dag 可以具有相同数量的节点。
最后,贪婪搜索是一种导航空间的方式,这样你总是根据当地环境向看起来最有利的方向移动。这就像在森林里迷路了,试图通过向开阔地带移动来走出去。这种方法的问题是,你不能保证找到穿过空间的最佳路径,如下图所示。**
说明贪婪的搜索可能会出错。在这里,当试图走出森林时,对向开阔区域移动的贪婪搜索将导致次优路径。图片作者。
虽然贪婪搜索不能保证最优解,但对于大多数问题来说,可能 Dag 的空间如此之大,以至于很难找到真正的最优解。
贪婪等价搜索(GES) 算法使用了这个技巧。GES 从一个空图开始,迭代地添加有向边,从而最大化模型适应度(即分数)的改进。一个示例分数是贝叶斯信息标准(BIC) [ 2 ]。
招数 3:利用不对称
正如 第一帖 中所说,因果关系的一个根本属性是不对称。a 可能导致 B,但 B 可能不会导致 a。有大量算法利用这一思想在因果模型候选之间进行选择。我将把这些不对称归类为三种常见的味道: 时间、复杂性和功能性。在描述这些不对称之前,重要的是要注意它们并不相互排斥。也就是说,算法可以混合搭配不同的口味。
时间不对称对我们来说是很自然的。它的理念是原因发生在结果之前。这是诸如格兰杰因果关系等观点的核心。尽管格兰杰因果关系不足以说明因果关系,但它利用了因果关系的概念。它在两个变量的情况下(例如 X 和 Y)通过在给定 Y 和 X 的过去信息的情况下量化预测 Y 的增益来做到这一点,这与单独 Y 的过去信息相反[ 5 ]。
复杂性不对称遵循奥卡姆剃刀原理,即模型越简单越好。换句话说,如果你有几个候选模型可以选择,这个想法就是选择最简单的一个。量化简单性(或复杂性)的一种方法是 Kolmogorov 复杂性。****
功能不对称假设更符合关系的模型是更好的候选模型。例如,给定两个变量 X 和 Y,非线性加性噪声模型(NANM) 在 X 和 Y 之间执行非线性回归,例如 y = f(x) + n,其中 n =噪声/残差,在两个方向上。如果潜在原因(例如 x)与噪声项(例如 n)无关,则该模型(即因果关系)被接受。关于 NANM 的更多细节可以在参考文献[ 7 ]中找到。****
示例:通过人口普查数据发现因果关系
我们现在从理论转向一个具体的例子。这个例子使用了因果发现工具箱,一个用于因果发现的 Python 库[ 4 ]。在这个例子中,我们从和以前一样的来源查看人口普查数据。
**在之前的例子中,我们假设收入有两个原因:年龄和教育。然而,我们怎么能肯定这个假设站得住脚呢?在本例中,我们探索了包含更多变量并利用数据驱动方法的替代因果模型:因果发现。示例代码和数据可以在 GitHub repo 中找到。
首先,我们加载必要的库和数据。如果您没有这些库,请查看回购中的 requirements.txt 。数据也在回购中。
**# import libraries
import pickle
import cdt
import networkx as nx
import matplotlib.pyplot as plt# load data
df = pickle.load( open( "df_causal_discovery.p", "rb") )**
接下来,我们需要为我们的因果模型构建一个框架。这基本上是前面讨论的 PC 算法的第二步。换句话说,进行成对独立性检验,被认为是统计相关的变量得到一个双向边。
**# Get skeleton graph
# initialize graph lasso
glasso = cdt.independence.graph.Glasso()# apply graph lasso to data
skeleton = glasso.predict(df)# visualize network
fig = plt.figure(figsize=(15,10))
nx.draw_networkx(skeleton, font_size=18, font_color='r')**
骨架图。图片作者。
注意我们有 7 个不同的变量。之前我们只考虑年龄,学历(hasGraduateDegree),收入(greaterThan50k)。仅从骨架中,我们可以看到存在于这三个变量之间的统计相关性。
现在是因果发现的时候了。在这里,我们尝试了 3 种不同的算法:PC,GES 和 LiNGAM。
**# Use causal discovery to get causal models# PC algorithm
model_pc **=** cdt**.**causality**.**graph**.**PC()
graph_pc **=** model_pc**.**predict(df, skeleton)
*# visualize network*
fig**=**plt**.**figure(figsize**=**(15,10))
nx**.**draw_networkx(graph_pc, font_size**=**18, font_color**=**'r')**
从 PC 算法输出因果图。图片作者。
PC 给出了一个稍微合理的结果。我们在上一个例子中使用的简单的 3 变量 DAG 是几乎嵌入在这个图中。年龄和 hasGraduateDegree 之间的箭头颠倒了,这是有问题的,因为这表明拥有研究生学位对一个人的年龄有因果关系!**
它还暗示了额外的因果关系。也就是说,hasGraduateDegree,greaterThan50k,age 和 isFemale 都对每周工作时间有单向因果影响,这本身对 inRelationship 有因果影响。接下来,我们看看 GES。
**# GES algorithmmodel_ges **=** cdt**.**causality**.**graph**.**GES()
graph_ges **=** model_ges**.**predict(df, skeleton)
*# visualize network*
fig**=**plt**.**figure(figsize**=**(15,10))
nx**.**draw_networkx(graph_ges, font_size**=**18, font_color**=**'r')**
从 GES 算法输出因果图。图片作者。
该图似乎与 PC 结果基本一致。值得注意的区别是,以前源于 isWhite 的双向边现在是单向的。回想一下 GES 的工作方式是有道理的。
最后,我们将 LiNGAM 应用于数据,该数据使用我称之为线性模型之间的功能不对称来推断因果关系[ 9 ]。
**# LiNGAM Algorithm
model_lingam **=** cdt**.**causality**.**graph**.**LiNGAM()
graph_lingam **=** model_lingam**.**predict(df)
*# visualize network*
fig**=**plt**.**figure(figsize**=**(15,10))
nx**.**draw_networkx(graph_lingam, font_size**=**18, font_color**=**'r')**
从 LiNGAM 算法输出因果图。图片作者。
这个结果与前两个有很大的不同。许多边缘方向已经翻转,例如在大于 50k 的和具有渐变度的之间的方向。性能不佳可能是由于违反了算法对线性效应的假设。这里的大多数变量都是二元的,因此线性结构方程可能不合适。****
结论
关于因果关系的三部分系列到此结束。在这篇文章中,我试图从因果发现中勾勒出大的想法,同时仍然为实际应用提供足够的细节。尽管我无法在一篇简短的博客文章中对因果发现进行全面的回顾,但我已经尝试在下面的资源部分整理了一份好的参考资料列表。尽管还很年轻,但因果发现是一个充满希望的领域,可能有助于弥合机器和人类知识之间的差距。
** **
资源
更多关于因果关系 : 因果关系概述 | 因果关系:简介 | 因果推断 | 因果发现
**https://shawhin.medium.com/membership **
《为什么之书:因果的新科学》朱迪亚·珀尔著
[2]基于图形模型的因果发现方法综述。https://doi.org/10.3389/fgene.2019.00524
[3]基于 ML 的因果发现:arXiv:1803.04929【stat。ML]** (好的引物)**
[4]因果发现工具箱文档:https://fentechsolutions . github . io/CausalDiscoveryToolbox/html/index . html
[5]格兰杰因果关系:https://doi . org/10.1016/0165-1889(88)90055-3
[6]因果推断用 R 包 pcalg:http://dx.doi.org/10.18637/jss.v047.i11(好的引子)
[7]非线性加性噪声模型论文
[8] UCI 机器学习知识库:数据来源
[9] LiNGAM 论文
[10]摘自纳西姆·尼古拉斯·塔勒布反脆弱的例子(付费链接)
模型稳健性的因果框架
使用因果建模进行特征选择和创建
模型稳健性
我们都希望我们的机器学习模型对看不见的数据进行归纳,但经常发现,当新数据看起来不像旧数据,即具有不同的分布时,我们的模型性能会下降。例如,我们根据一个国家的数据训练的医疗诊断系统不能推广到另一个国家,因为该国家的常见疾病与训练集所在国家的疾病不同。机器学习研究人员和实践者开发了各种技术来克服这个问题,并将模型命名为健壮。
根据定义,鲁棒模型对预测变量或目标变量的分布变化不敏感。模型鲁棒性是一个活跃的研究领域,分析模型鲁棒性的方法之一是使用因果推理。
稳健性因果模型
一般来说,因果推断是指回答改变一个变量是否会影响结果的问题。例子可以是研究促销和折扣如何提高销售额,或者特定的医疗如何改善病人的结果[1]。
我们都知道一句格言:“相关性并不意味着因果关系”。研究相关性是统计学家和数据科学家工作的一个非常重要的部分,但在研究因果问题时还不够。本质上,因果模型看起来与贝叶斯网络非常相似,因为它使用条件概率来表达所有变量的联合分布,例如:
如果我们把所有的概率都放在直接原因上,那么这个模型就是因果的:
来源:https://arxiv.org/abs/1507.05333
对变量 Xi 的干预是指我们改变 Xi 的分布,例如,将变量设为常数。因果建模扩展了条件概率的语法,以包括干预。例如,下面的等式
资料来源:https://en.wikipedia.org/wiki/Bayesian_network
是指当我们将变量 G 设为 t 时,变量 R 的概率。这也被称为因果机制。
因果建模如何帮助我们建立稳健的模型?如果我们预测 Y= f(X₁,X₂,… Xn),那么变量 X₁分布的变化可以建模为一个干预[2]。因此,稳健模型是对所有可能的干预都不变的模型。
因果模型有一个非常有用的性质,叫做*原因和机制之间的独立性,*它粗略地陈述了将原因 C 映射到结果 E 的机制不依赖于原因变量 C 的分布[3]。因此,如果我们的预测变量是原因,目标变量是结果,那么根据这一性质,模型 P(Y|X)是稳健的,因为当边际分布 P(X)改变时,它将同样工作良好。
然而,如果我们试图根据结果来预测原因,情况就不同了。考虑医疗诊断案例,当我们有一组症状,我们试图预测诊断。由于诊断是原因,症状是结果,我们可以使用独立性假设,并声称我们可以根据疾病 E(X|Y)稳健地预测症状。如果我们试图根据症状预测诊断,我们可以使用贝叶斯法则:
从这个方程我们可以看出,预测的诊断不仅取决于因果机制 P(X|Y),还取决于疾病在给定区域的流行程度 P(Y)。例如,同样的症状可以在一个国家用于诊断疟疾,在另一个疟疾不流行的国家用于诊断呼吸系统疾病。我们试图从结果中预测原因的情况被称为反因果预测【4】。
不变集
在大多数情况下,X 和 Y 之间的关系不能简化为因果关系。例如,在医学诊断中,问题是颠倒的,因为我们需要根据结果预测原因。罗哈斯·卡鲁拉等人[3]提出了一个问题,是否有可能导出特征 X 的子集 Xi,其中分布 P(Y|Xi)独立于 P(Xi)。这个子集被称为不变集,因为给定 Xi 的 Y 的模型预测不依赖于对除目标变量之外的任何变量的任何干预。我们来看下面这个因果图:
来源:https://www.bradyneal.com/causal-inference-course
这里我们试图根据预测变量 X₁到 X₁₆.来预测 y 我们可以排除所有的间接原因,因为它们是多余的,任何不是 Y 的原因的变量都可以改变它的分布,使预测不准确。这给我们留下了直接原因作为这个问题的不变集。
来源:https://www.bradyneal.com/causal-inference-course
这意味着,如果 Xi 包含 Y 的所有直接原因,则模型是稳健的。
您可以看到,我们大幅删除了大部分特征,因此尽管模型保持稳健,但预测能力较低。对于完全反因果模型,像上面提到的医学诊断问题,不变集是空的。
反因果模型的稳健性
有一些方法可以在不消除所有预测变量的情况下提高反因果模型的稳健性。其中一个显而易见的方法是将 Y 的分布信息作为一个新变量显式地输入到模型中。在我们的例子中,我们可以将疾病在特定国家的流行率作为一个额外的预测变量。如果我们的训练数据包含几个国家,模型可以学习使用此信息来调整对新国家的预测。例如,如果我们使用逻辑回归,我们可以将更新后的模型表示为:
这种方法相当于目标编码,这是一种在数据科学竞赛中广泛使用的编码分类变量的流行方法。我们可以向模型提供更多关于目标变量边际分布的信息,而不是它的期望值。一种可能的技术是使用我在早期文章中提到的贝叶斯目标编码。
结论
因果推理成为每个数据科学家工具箱中的必要工具。虽然这仍然是一个活跃的研究领域,但是有一些技术和工具可以解决最常见问题的原因。然而,因果推理的作用并不局限于因果问题,而是通过鲁棒性的因果理论扩展到机器学习。在这篇文章中,我试图分享我对健壮的机器学习模型的因果考虑的想法,以及它如何连接到特征工程的常用技术。
参考
[1]朱迪亚珍珠。2009.因果关系:模型、推理和推论(第二版。由…编辑).美国剑桥大学出版社。
[2] R. Christiansen,N. Pfister,M. E. Jakobsen,N. Gnecco 和 J. Peters,“分布一般化的因果框架”,载于《IEEE 模式分析和机器智能汇刊》,doi:10.1109/tpami。46306.86686866676
[3]罗哈斯-卡鲁拉先生、舒尔科夫先生、特纳先生和彼得斯先生。机器学习中的因果迁移。机器学习研究杂志,19(36):1–34,2018
[4]b . schlkopf、D. Janzing、J. Peters、E. Sgouritsa、K. Zhang 和 J. M. Mooij。因果学习和反因果学习。《第 29 届机器学习国际会议论文集》(ICML),第 1255–1262 页。Omnipress,2012 年。
因果推理
用 Python 回答因果问题
这是关于因果关系的三篇系列文章的第二篇。在的上一篇文章中,我介绍了这种“新的因果科学”【1】,并给出了因果推理和因果发现的味道。在本帖中,我们将深入探讨因果推理的一些细节,并以 Python 中的一个具体例子结束。
因果网络的一个例子。图片作者。
从哪里开始?
在的上一篇文章、、、、中,我讨论了因果关系如何通过结构因果模型(SCMs) 用数学方法表示。SCMs 由两部分组成:一个图形,它将因果联系可视化,以及方程,它表达了联系的细节。
概括一下,图是由顶点(节点)和边(链接)组成的数学结构。在这里,我将交替使用图和网络这两个术语。SCMs 使用了一种特殊图,称为有向无环图(DAG)** ,它的所有边都是有向的,不存在环。Dag 是因果推理的常见起点。**
贝叶斯网络与因果网络
当我第一次探索这个主题时,一个模糊之处是贝叶斯网络和因果网络之间的区别。所以我简单提一下区别。开明的读者可以随意跳过这一节。
从表面上看,贝叶斯和因果网络是完全相同的。然而,不同之处在于他们的解释。考虑下图中的例子。
可以解释为贝叶斯和因果网络的例子。火和烟的例子取自珀尔[1]。图片作者。
这里我们有一个有 2 个节点(火图标和烟图标)和 1 条边(从火指向烟的箭头)的网络。这个网络可以是贝叶斯网络,也可以是因果网络。
然而,关键的区别在于解释这个网络的时候。对于一个贝叶斯网络,我们将节点视为变量,将箭头视为条件概率,即给定火灾信息时烟雾出现的概率。当将此解释为一个因果网络时,我们仍然将节点视为变量,然而箭头表示一个因果连接。在这种情况下,两种解释都有效。然而,如果我们翻转边缘方向,因果网络解释将是无效的,因为烟雾不会引起火灾。
示例网络可以解释为贝叶斯网络,但不是因果网络。火和烟的例子取自珀尔[1]。图片作者。
什么是因果推理?
因果推断 旨在回答因果问题而不仅仅是统计问题。因果推理的应用数不胜数。回答下面的任何问题都属于因果推理的范畴。
- 治疗对服用者有直接帮助吗?
- 是营销活动导致了这个月的销售增长还是假期?
- 增加工资会对生产率产生多大影响?
这些都是重要而实际的问题,使用更传统的方法(例如线性回归或标准机器学习)可能不容易回答。我希望通过我称之为因果推理的 3 个天赋来说明因果推理是如何帮助回答这些问题的。
因果推理的三种天赋
礼物 1:do-operator
在的上一篇文章中,我从干预的角度定义了因果关系。忽略一些技术细节,据说如果对 X 的干预导致 Y 的变化,则 X 导致 Y,而对 Y 的干预不一定导致 X 的变化。干预在现实世界中很容易理解(就像当你朋友的糖果习惯失控时),然而,这如何符合因果关系的数学表示?
输入 do 运算符。 do-operator 是物理干预的数学表示。如果我们从模型 Z → X → Y 开始,我们可以通过删除所有传入 X 的箭头,并手动将 X 设置为某个值 x_0 来模拟 X 中的干预。
do 运算符如何工作的图示。图片作者。
假设我们知道因果联系的细节,do 运算符的强大之处在于它允许我们模拟实验。例如,假设我们想问,增加营销预算会促进销售吗?如果我们有一个包括营销支出和销售的因果模型,我们可以模拟如果我们增加营销支出会发生什么,并评估销售的变化(如果有的话)是否值得。换句话说,我们可以评估营销对销售的因果效应。稍后再谈因果关系。
珀尔和他的同事们的一个主要贡献是 do-calculus 的规则。这是一个 完整的规则集,概述了如何使用 do 运算符。
值得注意的是,do-calculus 可以将介入分布(即有 do 算子的概率)转化为观察分布(即没有 do 算子的概率)。这可以从下图中的规则 2 和规则 3 看出。
微积分的规则。规则摘自珀尔[ 2 ]的讲座。图片作者。
注意符号。 P(Y|X) 就是我们都很熟悉的条件概率,也就是给定 X 的一个观测值 Y 的概率。而, P(Y|do(X)) 是在 X 中给定一个干预Y 的概率。
do 运算符是因果推理工具箱中的一个关键工具。事实上,接下来的两个礼物依赖于 do-operator。
礼物 2:消除混淆
混淆是统计学中的一个概念。虽然我没有直呼其名,但这是通过辛普森悖论出现在上一篇中的。下图显示了一个简单的混杂示例。
一个简单的混淆例子。年龄是教育和财富的混淆物。图片作者。
在这个例子中,年龄是教育和财富的混淆因素。换句话说,如果试图评估教育对财富的影响,你需要根据年龄调整。调整 用于(或调节开启)年龄仅仅意味着当查看年龄、教育和财富数据时,人们会比较年龄组内的**、而不是年龄组之间的数据点。**
如果不考虑年龄因素,就不清楚教育是财富的真正原因还是仅仅是财富的关联。换句话说,你不知道教育是否直接影响财富,或者只是与财富有一个共同的原因。
举个简单的例子,在查看 DAG 时,混淆非常简单。对于 3 个变量,混杂因素是指向 2 个其他变量的变量。但是更复杂的问题呢?
这就是 do 操作符提供清晰度的地方。Pearl 使用 do 运算符以明确的方式定义混杂。他说混淆是导致 P(Y|X)不同于 P(Y|do(X)) [1]的任何东西。
礼物 3:估计因果效应
这最后的礼物是因果推论的主要吸引力。在生活中,我们不仅要问自己为什么,还要问*多少?*估计因果关系归结为回答第二个问题。
考虑读研。知道拥有研究生学位的人比没有研究生学位的人赚更多的钱是一回事,但一个自然的问题是,其中有多少是因为他们的学位?换句话说,研究生学历对收入的待遇影响如何?
我将利用回答这个问题的机会来完成一个使用 Python 进行因果推理的具体例子。
示例:估计研究生院对收入的处理效果
在这个例子中,我们将使用微软 DoWhy 库进行因果推理[ 3 ]。这里的目标是估计拥有研究生学位对年收入超过 5 万美元的因果影响。数据从 UCI 机器学习库[ 4 ]获得。示例代码和数据可在 GitHub repo 中找到。
重要的是要强调所有因果推理的起点是一个因果模型。这里我们假设收入只有两个原因:年龄和教育,而年龄也是教育的一个原因。显然,这个简单的模型可能遗漏了其他重要因素。我们将在下一篇关于 因果发现 的文章中研究替代模型。然而,现在我们将关注这个简化的案例。
首先,我们加载库和数据。如果您没有这些库,请查看回购中的 requirements.txt 。
**# Import libraries**
import pickle
import matplotlib.pyplot as plt
import econml
import dowhy
from dowhy import CausalModel**# Load Data**
df = pickle.load( open( "df_causal_inference.p", "rb" ) )
同样,第一步是定义我们的因果模型,即 DAG。DoWhy 使创建和查看模型变得容易。
**# Define causal model**
model=CausalModel(data = df,
treatment= "hasGraduateDegree",
outcome= "greaterThan50k",
common_causes="age",
)***# View model***
model.view_model()
from IPython.display import Image, display display(Image(filename="causal_model.png"))
我们(假设的)因果模型。图片作者。
接下来,我们需要一个 estimand。这基本上是一个给我们想要的因果效应的配方。换句话说,它告诉我们如何计算教育对收入的影响。
**# Generate estimand**
identified_estimand= model.identify_effect(proceed_when_unidentifiable=**True**)
print(identified_estimand)
estimand 生成的输出。图片作者。
最后,我们基于估计量计算因果效应。在这里,我们使用来自 EconML 库的元学习器【5】,它估计离散目标的条件平均治疗效果。
**# Compute causal effect using metalearner**
identified_estimand_experiment = model.identify_effect(proceed_when_unidentifiable=True)
from sklearn.ensemble import RandomForestRegressor
metalearner_estimate = model.estimate_effect(identified_estimand_experiment, method_name="backdoor.econml.metalearners.TLearner",
confidence_intervals=False,
method_params={
"init_params":{'models': RandomForestRegressor()},
"fit_params":{}
})print(metalearner_estimate)
因果估计的输出。图片作者。
平均因果效应约为 0.20。这可以解释为,拥有研究生学位会让你年收入超过 5 万美元的概率增加 20%。注意这是平均效应,考虑值的全部分布以评估平均值是否具有代表性是很重要的。
**# Print histogram of causal effects**
plt.hist(metalearner_estimate.cate_estimates)
因果关系的分布。图片作者。
在上图中,我们看到了样本间因果关系的分布。显然,该分布是而不是高斯分布。这告诉我们平均值并不代表总体分布。基于因果效应的进一步分析可能有助于发现“谁”从研究生学位中受益最多的可操作信息。
不管怎样,仅仅根据潜在收入来决定读研,可能表明你并不真的想读研。🤷🏽♀️
结论
因果推理是回答更传统的方法可能无法解决的自然问题的强大工具。在这里,我从因果推理中勾勒出一些大的想法,并通过代码完成了一个具体的例子。如前所述,所有因果推理的起点是一个因果模型。然而,通常我们手头没有一个好的因果模型。这就是 因果发现 可以有所帮助的地方,这也是下一篇帖子的主题。
资源
更多关于因果关系 : 因果关系概述 | 因果关系:简介 | 因果推断 | 因果发现
https://shawhin.medium.com/membership
朱迪亚·珀尔所著的《为什么:因果的新科学》
[2]珀尔,J. (2012 年)。重新审视微积分。arXiv:1210.4852【cs。AI]
[3]阿米特·夏尔马,埃姆雷·基西曼。DoWhy:一个用于因果推理的端到端库。2020.https://arxiv.org/abs/2011.04216
[4]杜瓦和格拉夫(2019 年)。UCI 机器学习知识库[http://archive . ics . UCI . edu/ml]。加州欧文:加州大学信息与计算机科学学院。https://archive.ics.uci.edu/ml/datasets/census+income
[5] Künzel,ren R .等人,“使用机器学习评估异质治疗效果的金属学者”美国国家科学院院刊,第 116 卷第 10 期,2019 年 3 月,第 4156–65 页。www.pnas.org,https://doi.org/10.1073/pnas.1804597116.
野外因果推理:弹性定价
行业笔记
机器学习如何提高工业中的因果推理?我用零售定价的代码描述了一个真实的例子。
因果推理是机器学习中的一个热门话题,有许多关于因果推理理论的优秀入门书籍[1–4]。但机器学习驱动的因果推理在现实世界中的应用例子少得多。本文介绍了一个来自行业环境的例子,使用了一个(公开的)真实数据集。它的目标读者是对因果关系有基本理解的技术人员。
具体来说,我将着眼于价格弹性估计的“理想”情景[2,5]。这种情况与希望优化价格的零售商高度相关,例如,为了更好地管理库存或只是为了更具竞争力。
在第一部分,我将提出这个问题,并提供一个简单的背景。这也将说明更普遍的一点,即估计因果关系需要“仅仅”数据分析之上的领域专业知识。在第 2 节,我将解释从历史数据中学习是困难的,因为混杂。第 3 节将为这个问题勾勒一个机器学习驱动的解决方案,这在第 4 节的代码示例中有详细描述。这里有一个完整的、可运行的笔记本。最后,我将讨论这种因果有效估计的业务相关性。
1 为什么要关心弹性?
“需求的价格弹性”是大多数经济学 101 课程的核心概念,它描述了对给定产品的需求对价格的敏感程度。如果一种产品“更有弹性”,价格上涨将导致更大的需求下降。作为一个因果概念,弹性允许我们量化如果我们将价格降低,比如说,5%,我们可以多卖出多少单位(与事实相反)。
作为价格和需求数量之间的影响的弹性描述了一个复杂的因果系统:价格当然不会直接影响需求,而是通过许多个人消费者购买或不购买的决定以及诸如在特价商品搜索网站上出现的次要影响来调节。在试图估计弹性时,零售商跳过所有这些复杂性,直接测量他们控制的东西(价格)对他们关心的东西(需求)的影响。
令人惊讶的是,弹性实际上是可以估计的。但是自从它在 1890 年被正式定义以来[6],经济学家发现需求的价格弹性在许多情况下是现实的一个体面的近似值[5]。这种近似在相对变化的规范定义中特别方便:弹性衡量需求数量的百分比变化( q ,给定价格的百分比变化( p ):
这里的直觉很简单:成本为 5 美元的产品价格变化 1 美元,将导致比成本为 100 美元的产品更剧烈的需求变化。总的来说,消费者关心的是“相对”变化。根据经验,这个定义很方便,因为它意味着待估计的参数 θ 随着 p 的变化而保持近似恒定。
有了对 θ 的有效估计,零售商现在可以对他们的价格进行反事实推理:“如果我将我的产品价格提高 5%,我可以预期多卖出 5θ%的单位”(θ通常为负值)。
为了建立一些直觉,假设他们目前以 5 美元的价格和 4 美元的成本销售了 100 个单位。那么他们目前的利润是 100 *(5–4)= 100 美元。假设他们估计弹性为θ=-3,即他们预计价格上涨 5%(从 5 美元到 5.25 美元)会导致需求减少 15%(从 100 美元到 85 美元)。那么新的利润会稍微增加,85 *(5.25–4)= 106 美元。然而,如果他们降价 5%,他们就会损失利润:115 *(4.75–4)= 86 美元。请注意,更高的价格并不总是导致更高的利润:例如,如果单位成本仅为 3 美元:5%的价格上涨将减少利润,从 100 *(5–3)= $ 200 到 85 *(5.25–3)= $ 191。
你可能会说服自己,不同的弹性值会改变最优价格:一般来说,需求弹性越大(例如,如果 θ =-5 而不是-3),成本和价格之间的加价应该越低。
能够做出这种反事实的陈述,通过给出价格应该提高还是降低的指示,为零售商节省了许多“尝试新价格”的时间。当然,例如,当零售商想要管理他们的库存以销售所有库存直到季末时,对弹性的良好估计提供了额外的价值。简而言之,高度精确的弹性估计为零售商提供了个人购买决策的复杂因果系统的简明摘要,允许对其预期结果充满信心的商业决策。
对需求的基本经济理论的简短探究是因果推理中专家知识的一个例子:关于数据生成过程的知识告知了要回答的问题类型、要寻找的机制,以及通常假设的函数形式。很难从数据中了解所有这些结构,当然数据效率也很低。
2 欣赏挑战
在介绍了为什么零售商想要估计弹性之后,这一部分将描述为什么这是一个有趣的问题。
当然,因果推断的首选方法是(随机)实验:零售商可能会花一些时间随机上下调整产品价格(或者更好的是,在用户之间随机定价)。但是这种试验是昂贵的,因为产品以次优价格出售,客户体验受到影响。更糟糕的是,零售数据的信噪比通常很低,因为大多数商店提供大量的产品,其中很大一部分在任何给定的时间框架内都没有卖出去。因此,在卖出足够多的产品来进行推断之前,实验需要进行很长时间。最后,零售商可能会担心,例如,短期实验可能无法跨季节推广。
因此,从观察数据中学习因果有效弹性的能力是关键;本例中的观察数据只是零售商在一段时间内的价格和销售量历史。但是由于混杂因素,从观察数据中估计因果关系是困难的。为了理解这意味着什么,考虑(1)产品质量和(2)季节作为许多潜在混淆因素的两个重要例子:
- 比如说,MacBooks 比 Chromebooks 更贵。假设零售商销售的 MacBooks 比 Chromebooks 多(其他什么都没有),观察数据表明高价格与高销量相关。但是,(反事实地)期望把 Chromebook 的价格提高到苹果的水平就能卖出更多 chrome book 是愚蠢的。
- 对许多产品的需求是季节性的,例如由于假期(圣诞节)和天气变化(夏季)。通常情况下,旺季价格较高(但仍有大量产品售出),淡季价格较低(此时售出的产品较少);然而,尽管存在这种相关性,但通过将淡季价格提高到旺季水平来期望更高的销售额是愚蠢的。
俗话说,零售商必须小心不要混淆相关性和因果关系。下面的因果图代表了一个简单的混杂关系:未能控制产品质量(和季节,以及其他因素,未显示)将显著偏差θ的估计值。这种偏见会导致零售商对最优价格得出错误的结论,直接损害他们的业务。
价格和数量之间的最小(即不完整)因果图,产品质量是唯一的混杂因素。
题外话:价格弹性是计量经济学中“联立方程模型”问题的一个实例[7]——核心观点是价格实际上是由供应方和需求方的同时决策决定的。在这个例子中,零售商相信他们有足够的关于他们自己定价决策的数据来分离出对价格变化的市场反应的一致估计。
知道正确控制所有可用混杂因素的重要性,零售商现在转向机器学习驱动的因果推理。
3 双机器学习,或称可观测量控制 2.0
我在这里描述的解决方案主要解决了两个问题:首先,正则化从大量潜在的混杂因素中挑选出合适的控制。第二,由于我使用灵活的机器学习算法,控制变量的函数形式和相互作用(即它们的预处理)不如传统回归方法重要,在传统回归方法中,使用普通线性回归来控制混杂因素。自然,仍然需要进行大量的思考来寻找可能是混杂因素的变量——以及应该避免哪些变量,因为它们可能会引入“对撞机偏差”[8],这种方法是而不是免疫的。
我的解决方案实现了双机器学习(DML) [9]。主要思想是相对直观的:给定一些观察到的潜在混杂因素,我使用非参数的、灵活的估计器(机器学习模型)来有效地控制各种函数形式和交互作用的影响。换句话说,我用 ML 模型近似了数据生成过程中的实际混淆机制。
为此,我训练两个独立的“辅助”模型,分别预测待遇(价格, P )和结果(需求量, Q )。这两个模型都是用一组潜在的混杂变量(如产品质量和季节)独立训练的,因此它们的预测接近期望值, E[P|X] 和 E[Q|X] 。
使用这些预测,我然后剩余出通过一组控制变量可预测的治疗和效果部分:
在我下面的实现中,我选择 RandomForests 来估计条件期望,选择它是因为它们的稳健性能。您可以将这两个辅助模型视为“控制模型”:如果 X 包含足够多的相关混杂因素的信息,并且如果至少有一个模型“非常适合”,那么通过构建,P̃和 Q̃现在是“未建立的”,只剩下真正的因果关系(关于这一点有丰富的文献,从[9]开始)。
所以在剩余化之后,我对
这个数量仍然很难估计,但幸运的是在计量经济学中有一个估计弹性的标准方法:对数回归。 θ 完全等价于以下回归模型中的参数:
具体如何工作超出了本文的范围(如果您想了解,请参见[10])。重要的一点是,在实际实施中,我将根据剩余对数价格(线性)回归剩余对数数量,以获得 θ。
在下面的分格散点图中,我展示了在我的样本数据集中取对数数量和对数价格之间的相关性的“天真”结果:即使在控制诸如季节或产品质量之类的混杂因素之前,这种关系似乎也有些线性。弹性, θ ,是这条线的斜率(【10】)。正如您将看到的,控制混杂因素会显著改变(改进)估计值。
在数据清理后的简单相关性分析中,可以观察到对数数量和对数价格之间的(某种程度上)线性关系,此处显示为一个分格散点图。
现在,将方法放在一起:
- 我要拿 p 和 q 的圆木。
- 我将构建一组潜在的混杂因素, X 。
- 我将训练一个辅助随机森林模型来从 X 预测 log§ 。
- 我将训练一个单独的辅助 RandomForest 模型来从 X 预测 log(q) 。
如果您密切关注这一过程,您会注意到所描述的残差化过程是“样本内预测”,即辅助模型根据它们预测的相同数据进行训练。这可能会引入过度拟合并导致偏差——为了抵消这一点,我将把我的数据分成两半。我将使用一半的数据来拟合辅助模型,然后使用模型来残差另一半的 log§ 和 log(q) 。然后我可以在后面的数据集中测量因果弹性。冲洗并重复,切换两组并对两个估计值进行平均。所以:
- 将数据集分成两半,取 p 和 q 的日志。
- 构建一组潜在混杂因素 X (两半中的变量相同)。
- 使用的前一半训练一个辅助随机森林模型,从 X 预测 log§ 。
- 使用的前一半训练一个单独的辅助随机森林模型,从 X 预测 log(q) 。
- 使用两个辅助模型从第第二半个数据中的 X 预测 log§ 和 log(q) ,残差后得到:
6.将弹性推断为线性回归的系数,
7.交换两半,重复步骤 3-6。使用两个 θ 估计值的平均值作为最终结果。
为了更好地说明这种机制在实践中是如何工作的,让我们看一些分步示例代码。对于您自己的实验,DML 和许多其他现代方法可以在 EconML 中方便地获得,EconML 是由微软研究院维护的一个新的 python 包[11]。截至 2021 年初,我发现 API 相当不稳定,但正在进行的开发非常有前景。类似地,DoubleML 为 python 和 R 提供了 DML 实现[12]。
4 个样本代码
代码使用这个理想化的真实世界数据集:每天和每个产品都有一行,以及这个(第 X 天的产品)组合的一些附加特性,可以用作潜在的混杂因素, X 。最重要的是,在每一行中,数据记录了 Q 和 P 。
首先,我将定义两个标准 ML 模型,从所有可用的潜在混杂因素 X 中预测 log§ 和 log(q) 。请注意,由于每天和每种产品都有单独的控制变量,因此模型可以捕捉产品质量和季节性。
为了提高模型的预测质量,进一步减少混淆,并展示 DML 的优势,我添加了一些进一步的特征工程: n-grams 产品描述,以恢复产品、季节性描述符和产品新颖性度量之间的相似性。然后,我将这个特征工程的结果,一组潜在的混杂因素,输入到一个标准的随机森林模型中。
当然,在这方面可以付出更多的努力;但这组潜在的混杂因素表明,随机森林可能会发现非平凡的函数形式和交互效应,超出了标准回归所能做到的。
接下来,对于实际的推断,我将使用线性回归模型。如上所述,这将估计对数-对数回归的斜率 θ 。
最初的 DML 论文为这个回归提出了与 OLS 略有不同的估计量,以获得更好的稳健性:代替采用标准的 OLS 解,
Q ~θP+截距的标准 OLS 解
他们使用以下去偏估计量。注意第一个 P 是剩余的,而第二个是不是,第三个是:
去偏回归估计量[9]
在下面的代码片段中,我实现了如上所述的步骤(1)到(6):将数据分成两半,在前半部分训练辅助模型,剩余后半部分,并推断弹性。在重复交换两半后,我取两个估计值的平均值,以获得一个稳健的因果估计值(假设我能够捕捉到相关的混杂因素)。
最终输出如下所示:
1st Fold:
DML elasticity: -1.90
OLS elasticity for comparison: -1.83
2nd Fold:
DML elasticity: -1.92
OLS elasticity for comparison: -1.85
DML efficient estimate of elasticity: -1.91
因此,我们有它:我们的双重稳健,ML 控制的需求价格弹性估计。即价格对销售量的平均处理效果。在行业环境中,零售商现在可以尝试使用小实验(即随机价格变化)来验证这一估计。
这一最终结果可在以下分箱散点图中看到:
DML 结果的可视化表明,控制混杂因素减少了我们治疗变量中的“噪音”变化,并改变了效果大小。
在剧情中,可以看到蓝色的“幼稚”做法。这只是绘制对数-数量对对数-价格,没有控制混杂因素(即,混淆相关性和因果关系)。即使这种关系是“混乱的”,你已经可以看到一个负斜率:更高的价格导致更低的需求。这里的回归参数在θ≈—0.6 左右。
橙色线是 DML 结果的可视化,控制了潜在的混杂因素。请注意,斜率变得更陡,表明弹性需求更大(θ≈1.9)。您还可以观察到,这种关系变得明显不那么嘈杂,并且您可以看到价格的方差(x 轴上的线的范围)大幅减少,这是因为 DML 残差“解释”了这种变化的大部分。
5 讨论
与开头的例子类似,假设一个零售商目前以每件 5 美元的价格销售 100 件产品,成本为 2 美元。估计弹性为-1.9,零售商应该降低价格以获得更多利润。但是如果(有偏见的,天真的)估计是-0.6,他们就会提高价格。
在这个例子中,适当的因果推理推翻了推荐的决策,对零售商的利润有直接影响。混淆相关性和因果关系会让零售商损失很多钱。相比之下,使用精心设计的 DML 机制,零售商能够在价格变化发生之前自信地预测价格变化的影响。
本文旨在解释一个端到端的行业应用程序。你可以在的可运行笔记本中更详细地了解每一步。许多业务问题受益于类似的方法;我希望这是一个有用的例子。
为了进一步优化价格,零售商现在可能会转向异质治疗效果,即探索弹性差异。这也开启了一个问题,我实际估计的“平均治疗效果”是什么:我的训练数据中的产品组合是否代表未来的产品组合。我将在后续文章中探讨异质效应。
承认
感谢 Rima Rahal、Jonathan Haas 和 Paul Hünermund 对初稿进行了富有洞察力的讨论和评论。
参考文献/尾注
[1] Taddy,Matt:商业数据科学。麦格劳-希尔教育,2019。
[2]坎宁安,斯科特:因果推理:混音带。耶鲁大学出版社,2021 年。https://mixtape.scunning.com/introduction.html
[3]韦杰,斯特凡:统计 361:因果推理。斯坦福大学,2020。https://web.stanford.edu/~swager/stats361.pdf
[4]瓦里安,哈尔 r .:经济学和市场营销中的因果推理。美国国家科学院学报,2016 年 7 月。
[5]https://en.wikipedia.org/wiki/Price_elasticity_of_demand
[6]阿尔弗雷德·马歇尔:《经济学原理》。麦克马斯特大学经济思想史档案馆,1890 年。https://social sciences . McMaster . ca/econ/ugcm/3ll 3/Marshall/prin/prinbk 5 . htm
[7]第十六章:联立方程模型。《计量经济学导论:现代方法》,第 7 版。2019.
[8] Lee H,Aronson JK,Nunan D:对撞机偏差。偏见目录,2019。https://catalogofbias.org/biases/collider-bias/
[9] Chernozhukov,Victor,等:用于治疗和结构参数的双/去偏置机器学习。计量经济学杂志,2018 年第 21 卷。https://academic.oup.com/ectj/article/21/1/C1/5056401
[10]要了解线性对数回归确实可以估计弹性,请考虑以下情况:对数回归假设
对这个回归方程取相对于 P 的偏导数,你得到
[11]微软研究院:EconML。用于基于 ML 的异质治疗效果评估的 Python 包。https://github.com/microsoft/EconML
[12] Bach,p .,Chernozhukov,v .,库尔茨,M. S .,和 Spindler,m .:Double ml——Python 中双机器学习的面向对象实现,2021。arXiv: 2104.03220
数据科学家的因果推理:第 1 部分
你不知道你需要的技术
这篇文章是两部分系列文章的第一部分,讨论了 Pearlian 因果推理的基本概念和数学。第 2 部分将关注一个使用 DoWhy 库的实际例子。如果您喜欢先从实现开始,当第 2 部分可用时,跳到第 2 部分,然后返回这里学习理论。
近年来,澳大利亚推理经历了巨大的发展。这种激增与更广泛的数据科学(DS)的兴起同时发生,但它们在实践中仍然截然不同。虽然因果推理背后的科学受益于 Judea Pearl、Donald Rubin、Susan Athey 和许多其他人的最新工作,但他们发现的见解还没有进入主流 DS,尽管这些技术的实现很容易获得。许多 DS 从业者根本不知道或不在他们的工作流程中使用因果推理,这可能有几个原因…
- 进入因果推理的假设,如贝叶斯模型,可以从周日开始以六种方式进行切片、切块和辩论。(感谢我的 Linkedin 联系人吉诺·阿尔蒙多提供的这一见解)
- 人们认为相关性是自动因果的,它们本身就足够了。在你的工作场所找找看,你会惊讶它出现的频率。
- 因果推理被认为是困难的。我们不喜欢硬的。
这些观点都有不同程度的有效性,但最终都没有抓住要点。主要的一点是,虽然存在挑战,但我们手中有一套概念和技术,如果谨慎应用,将完全改变数据科学的实践和感知方式。我们可以利用领域知识进行可靠的推理。让我们先做一些准备来开始讨论。
什么是因果?
在本文中,我们将采用干涉主义的方法来定义因果关系。我们对什么是因果关系都有一个直观的概念,但是要用数学语言来表达,我们需要一些更正式的东西。
定义是,对于两个不同的事件 A 和 B,如果 A 的变化对应于 B 的变化,则 A 导致 B,其他都相等。
大多数因果推理都是为了确保“其他一切都是平等的”这一部分。还有其他类似的定义,围绕着哪一个是最正确的有激烈的争论,但我们将决定这一个,并继续进行。
我们如何建立因果关系?
在近代因果复兴发生之前,建立因果联系的黄金标准是随机实验。在很多方面他们仍然是。因此,让我们在随机实验的背景下讨论因果关系。
我们有一个我们想要测量的结果,名为 y。我们想看看操纵特定的治疗 X 是否会引起 y 的明显变化。在随机试验中,如药物试验,我们将从更广泛的人群中随机获得足够大的人的样本(使用功效分析)。参与者将被随机分配药物或安慰剂。然后,我们将测量安慰剂组和药物组的差异,这被称为治疗效果,可以通过多种方式完成(参见 cohen 的 d 或 CATE)。任何效应大小将仅来自治疗,而不是由于可能存在的任何其他因素或混杂因素**。**
随机分配确保“所有其他条件相同”在总体上是正确的。
真实的世界
现在我们来看因果推理中面临的主要障碍。我们并不总是有时间和金钱去做随机实验来建立因果联系。即使我们这样做,也可能不符合道德。我们最终可能只有一组观察数据,以及我们从观察中建立起来的一些假设。我们能用非随机化的数据来检验它们吗?答案是肯定的,这就是我们的新工具包发挥作用的地方。我们将使用的技术将获取我们的观察数据集,并将其转换为所谓的介入数据集,从中我们可以得出因果推论。这里的关键是数据本身不足以建立因果关系(见辛普森悖论)。我们需要更多有力的理由。
鉴于数据还不够,我们将绘制一幅世界的文字图,称为因果图,它编码了我们关于数据生成过程的假设。数据生成过程是我们试图了解其动态的系统。这将有助于我们构建我们的介入分布,并检验我们的模型是否有效。
我们在模仿科学过程。我们从一个假设开始,然后我们用因果图来模拟世界在这个假设下的行为。最后,我们用数据来检验我们的模型,这可能支持或不支持假设。此外,我们进一步测试模型,看看它对变化、未说明的混杂因素和其他问题有多敏感。重复直到你的理论符合事实。
更深入
让我们定义几个术语…
****干预:主动做 X 导致 y 的变化。
例子:如果我推我的朋克兄弟,他会生气吗?如果我给一个人用药,会让他们好起来吗?
****反事实:如果我没有做 X,Y 还会发生吗?
例子:如果我没有推我的朋克兄弟,他会摔倒吗?如果没有给病人用药,他们会好转吗?
干预和反事实的推理反映了人类理解因果关系的正常方式。我们正在创造两个不同的世界,并比较两个世界的结果。如果我们有一个干预的案例,和它的反事实,我们可以建立因果关系。在一个随机实验中,我们在群体水平上已经有了这两个现成的例子。当分析的层次改变到个人时,我们就意识到我们试图解决的一个最基本的问题。我们发现我们有一个缺失数据的问题。我们手头没有反事实,因为个人的反事实并不存在。你不能同时接受治疗和未治疗。双胞胎研究接近了。幸运的是,我们有办法估计这种反事实,同时控制一切可能混淆我们分析的东西。请记住,我们试图保持所有其他平等,这就是为什么我们需要一个反事实。让我们深入数学来更好地理解发生了什么。
派生
当我们获得观察数据时,无论数据是离散的还是连续的,我们得到的都是概率分布。两种主要类型是联合概率和条件概率。任何上过基础概率课程的人都会涉及到这些话题,但它们为我们构建因果公式提供了基础。下面是两个数据分布。
观察和干预图
在左边,我们看到了观察模型,它显示了原始数据中变量之间的相互关系。根据我们对因果关系的定义,我们需要独立于其他因素,估计改变 X 对 Y 的影响。对于我们观察到的数据,我们无法使 X 的变化不对应于 Z 的变化,因此 X 的变化不表示 y 的因果变化。我们需要一种方法来理清 Z 对 X 的混淆效应,例如 P(X|Z) = P(X),或者换句话说,我们需要操纵观察到的数据以使两个变量独立。我们需要做图形手术。
右图显示了我们想要的状态,即手术后的状态。z 和 X 不相连,因此其中一个的变化不会影响另一个。这被称为d-分离**。而且由于 X 仍然在 Y 的上游,所以 X 的任何变化都会导致 Y 的因果变化,不管 X 是自发变化还是直接调整。**
假设
现在我们继续推导,允许我们将我们的观察数据分布转换成我们的干预数据分布。我们从两者之间的三个联系开始推导。我们用 p 表示我们的观察数据分布,用 Pₘ表示被操纵的干预数据分布。
链接 1
因为 Y 的引入效应在两个图之间保持不变,所以概率分布也是相同的。这是我们的第一个不变性链接。
链接 2
确定 Z 的过程不会因为去掉 Z 和 x 之间的联系而改变,这是我们的第二个不变性环节。
链接 3
在被操纵的模型中,Z 和 X 是 d 分隔的,因此是独立的(在后一个模型中,关于 Z 的信息并不能告诉我们关于 X 的任何信息)。根据链接 3,我们可以更进一步得到 P(Z)。
考虑到这些联系,我们从右边的因果图开始,定义我们的 do 操作符。我们想知道,给定我干预 X,用 do(X)表示,Y 的概率是多少。由此可见…
(根据定义)
接下来,我们扩展等式的右边来考虑 Z
根据全概率的定律,我们在 z 上取 P(Y|X)的加权平均值。这是我们控制 z 的影响的方法。这与控制混杂因素的逆概率加权和倾向评分加权技术相同。亚当·凯莱赫有一篇很棒的文章展示了等价性在这里,所以如果你有兴趣深入了解,一定要去看看。
接下来,我们使用 Z 和 X 的 d 分离原理来获得
最后,我们调用操纵分布和观测分布之间的不变性链接来得到
调整公式
使用最后一个表达式,称为调整公式**,我们现在已经定义了如何从干预前的观察数据中生成我们的干预分布 P(Y|do(X))。这是对介入分布的广义定义,适用于连续和离散病例。**
对于我们的药物试验示例,它是一个离散的二元结果,使用我们导出的因果表达式来估计治疗效果,我们可以将平均治疗效果(ATE)定义为
随机试验
因此,我们使用随机试验获得了与控制所有相关混杂因素(上面用 Z 表示)相同的结果。
顶部的第一项是观察到的治疗效果概率,第二项是反事实概率。假设 Z 代表 Y 和 X 的所有混杂因素,它们的差异确定了治疗 X 对结果 Y 的因果影响。请注意,Z 本身可以是连续的或离散的,这并不重要。配方中有一个漂亮的灵活性。
最终事项
这些是珀尔因果推理的基础。关于因果关系的其他讨论,请阅读鲁宾的潜在结果框架。如果你喜欢天才科学家之间的辩论,这个资源会让你开心。关于使用随机森林对高维数据集进行因果推理的应用,请参见苏珊·艾希的最新作品这里。Amit Sharma 和 Emre Kiciman 的一本很棒的介绍书可以在这里找到。最后,仔细阅读后门标准,这是因果推理的下一个重要步骤,可以在这里阅读。****
我们只是触及了将科学融入数据科学的强大概念的表面。我希望这有助于在实施之前建立理论。我也希望它引发了你的好奇心,让你想了解更多,并开始在工作中应用这些原则。本系列的第 2 部分将使用 DoWhy 软件包实际应用 Pearlian do 微积分解决医疗保健领域的一个因果问题。
敬请期待!感谢你的时间,上帝保佑你。
乐趣和利润的因果推理
图片由来自 Pixabay 的 Michal Jarmoluk 拍摄
办公时间
科学在快速发展的初创企业中的挣扎
甚至在推出几个月后就雇佣了它的数据团队。我们的任务很简单:弄清楚我们是否在做正确的事情。公司的每个人都想知道产品是否为影响而优化,为了优化,我们需要数字:风险最小化,目标最大化。
“这是我们第一次做这样的事情。”我记得乔恩在我最后的现场公开表示不确定。该公司仍然不知道整个“数据科学”的事情。对伊文和我来说,这都是一种冒险。他对事情的发展很诚实。
“你觉得你能行吗?”
我毫不怀疑。“绝对是。”
一年半后,数据团队在组织结构图的变动板块之间崩溃了。
我错了。好几次。衡量影响——我们 T12 带来的好处——并不容易,我已经积累了这么多失败的赌注,我在拉斯维加斯比在硅谷更自在。但是,嘿,即使在核灾难的中心,你也会发现原子石玻璃,我学到的东西就像水晶一样。
今天,我们有工具和方法可以测量我们的影响,而真正的科学发现只有很少的负面影响和所有的正面影响。我会说的。
但是跳到最后一点也不好玩。一切都是为了旅程,记得吗?
一整个该死的井架
图片来自像素
过去,每个人都相信数据科学的炒作。从自我更新机器的大脑中汲取的定量见解,从海量数据流中进行的在线预测,对你甚至从未想过要问的高维度问题的答案——太空中漂浮着如此之多的承诺和宣传,以至于让你头晕目眩。
毫不奇怪,数据团队似乎是必备的。
但是团队需要工具来运作。我在 Even 的第一周,我越来越恐惧地意识到我们是在直接查询我们生产数据库的一个副本。像这样的数据存储针对单个表上的单行读取进行了优化,但是我们要对数亿行进行统计,并从模式的每个角落连接列。
我通常不得不在晚上启动一个查询,回家后相信它会完成,然后像拼花地板一样沉入磁盘,并在第二天分析它的结果。如果我早上错过了一列或一个关键的行子集,我会 **1。)**讨厌自己和 **2。)**在接下来的八个小时里被束缚手脚。
我们试图用一把铁锹来开采石油,但我们需要的是一整个该死的井架。
我的时间经常会转移到用快速编写的分析或立即有效的商业智能来追逐枝节问题,而度量的任务会被推后几周、几个月、几个季度。
然后奇迹发生了。一个才华横溢的全栈工程师变成了机器学习工程师变成了数据工程师,他的名字叫约瑟夫·阿特金斯-土耳其人把最后一个齿轮放进一台漂亮的机器里,这台机器每天储存我们所有的数据。突然之间,过去需要几个小时的查询将在几分钟内返回。我们改变了我们的工作流程、时间表,甚至我们对自己能力的看法。
我已经转了几个月的轮子,烧了几个月的钱,但是只需要一个数据工程师,我就可以开始工作了。
这将成为一个持续的主题:没有数据工程优先,数据科学将一事无成。
2:混杂变量和医院对撞机
每天都有几百万笔银行交易流经我们的系统。它们被解析、打包和丰富,使得它们比一个写着INSUFFICIENT FUNDS FEE FOR A $5.00 ITEM
的字符串更有用。这种丰富与最终用户体验没有任何关系:我们保留它用于关键性能指标。
我们关注的两大标签?发薪日贷款和透支费。
假设是 Even 的按需付费功能 Instapay 远远优于收费高得离谱的流动性产品。因此,我们预计对这些产品的需求会下降。发薪日贷款和透支量是值得关注的明显数量。
我们跟踪了会员如何使用该应用程序,他们使用 Instapays 的频率,并使用这些结合了机器学习、正则表达式和决策规则的庞大交易丰富管道,我们最终发现—
没什么。
我们的问题从来都不是技术性的。这是认识论上的。
我的意思是。我们试图找出 Even——特别是 insta pays——对某些绩效指标的影响,对吗?先重点说一个:透支费。假设我们在任何时候看到高于平均水平的 Instapay 透支率,我们都会看到低于平均水平的透支率,下图说明了这种相关性:
玩具例子:当透支费率低于平均水平时,Instapays 高于平均水平。所有图表由作者提供。
这种相关性是否足以说明 Instapays 正在降低透支率?
不会。同样的相关性可能会发生,因为某些第三因素碰巧改变了这两者。例如,如果人们足够聪明地使用 Instapays,也足够聪明地关闭银行应用程序的默认透支保护设置,会怎么样?
有个混杂变量在进行中。
那不一定是世界末日。如果你对你的系统有一个详细的了解,你可以识别每个混杂因素和控制。在实践中,这只是意味着在混杂因素(“移动应用程序悟性”)保持相等的情况下,查看你的解释变量(Instapay 利率)和响应变量(透支费率)之间的关系。
如果你仍然看到所有的混杂因素都得到适当控制的关系,那就是因果关系的更好证据。我们没有衡量“手机应用能力”的变量,但我们可能有一个较弱的代理:年龄。
玩具示例:控制年龄。
所以。假设我们在控制了年龄因素后仍然看到了相关性。我们的工作完成了吗?我们证明了我们的产品有积极的影响吗?
同样,不。控制混杂因素是可行的,但就像我说的,你需要对世界上正在发生的事情有一个详尽的了解,以确保你已经考虑到了一切。队里没人认为我们有这种能力。在我们的头脑中,不管我们控制什么,模型看起来更像这样:
玩具例子:无限多可能的未知。
可能有未知的未知, U ₁, U ₂ , … 联合国,潜伏在每一个地方。我们无法控制所有这些,因为我们不知道它们是什么。
事实上,试图控制世界上的一切会在其他方面绊倒我们。混杂变量的反向结构被称为碰撞器,其中一些变量同时受到你感兴趣的解释变量和响应变量的影响。当你像这样控制一个变量时,你会产生实际上没有意义的虚假关联。
这就是对撞机偏差,或者伯克森悖论。
1938 年,约瑟夫·伯克森博士因痛斥医院数据的统计分析而有幸以他的名字命名了整个现象。当时,临床医生已经全力以赴进行数据收集和分析,他们发现了疾病之间各种各样的简单关联。这是大数据 1.0,但问题是,就像现在一样:这些相关性有意义吗?
如果这些医生怀疑胆囊炎与糖尿病密切相关,他们中的一些人可能已经开始拔除胆囊,所以采取冷静、合理的方法是值得的。
让我们想象一个只有胆囊炎和糖尿病两种疾病的世界。任何一种都可能导致你去医院。
医院对撞机。
在这里,人们可以有几种行为方式。
- 他们只有糖尿病,症状变得很严重,需要去医院。
- 他们只有胆囊炎,症状变得很严重,需要去医院。
- 他们患有两种疾病,其中一种或两种都让他们感到不舒服,不得不去医院。
- 他们两种疾病都没有,或者症状不严重——所以他们只是呆在家里。
问题是:当你看医院的数据时,你完全忽略了最后一群人。而当你只关注前三组的时候,各种各样的恶作剧就发生了。
我们来思考一下,当两种疾病在一般人群中发生的可能性相等时,会发生什么?在下图中,这是从较大的组中切割出来的两个相同大小的圆。我们允许两者之间有一点重叠,以表示患有这两种疾病的人。
假设胆囊炎和糖尿病在普通人群中的发生率相等,有一点重叠。
现在让我们想想这些人是怎么死在医院的。
如果糖尿病和胆囊炎同样有可能送你去看医生,会发生什么?为了说明,我们将在每个疾病人群和“医院”人群之间画出相等的重叠部分。
在这种情况下,医院内的疾病重叠比我们在普通人群中看到的要少。
如果我们只关注医院人群,糖尿病患者患胆囊炎的可能性比普通人群低!反之亦然。仅仅一种疾病就足以让你通过这道门,所以它“解释”了其他疾病是一个因素。相对于潜在人群,这两者之间会有一个负相关。
另一个例子呢,胆囊炎非常痛苦,但糖尿病的症状稍微微妙一些。好吧,现在所有这些胆囊炎患者都会争先恐后地去医院,但糖尿病患者更有可能呆在家里。
现在,这两种疾病在医院的重叠比我们在普通人群中看到的要多。
现在,医院里的大多数糖尿病患者也有胆囊炎。我们看到了一种无中生有的正相关性。
伯克森意识到,即使这两种疾病在潜在人群中的发病率完全不相关,这些相关性也会显现出来。临床医生正在控制一台对撞机:在医院里。
所以。我们不能控制所有的事情,即使我们尝试了,我们也有诱发错误关联的风险。
这无疑给我们留下了某种样的小溪,我们需要找到一个桨。立刻。
3:电学课程
照片由 Pexels 的 Killian Eon 拍摄
团队在我们的思考中变得更加因果,现在专注于在成员加入我们的服务之前研究来自的指标。事实证明,当会员通过我们使用的银行数据 API Plaid 连接到我们的应用程序时,他们实际注册前两年的交易将从他们的银行账户中扣除。这给了我们一个前事件数据的宝库,我们可以用来与后事件数据进行比较。
因此,我们构建了银行交易的标准化时间表,平衡于一个平均的激活日期:180 天之前到 180 天之后。
这导致了我经历过的最严重的职业崩溃——但也是最有力的证明了 Even 的价值观不仅仅是纸上谈兵。
对交易时间表的中期分析揭示了一个令人难以置信的结果:在会员注册 Even 后,发薪日贷款频率会下降。当然,有一点奇怪的是:我们会看到他们上升,直到注册日期。
我们的误导图的玩具复制品:我们看到在注册 Even 之前,有发薪日贷款交易的会员有增加的趋势,但之后有减少的趋势。
也许是逆向选择?如果会员陷入困境,陷入发薪日贷款陷阱,但后来求助于 Even 来帮助他们摆脱困境,这或许可以解释这种现象。
但那只是一个普通的故事,完全没有事实根据。
然而,不知何故,这些数据流传开来。那还是早期,甚至还没有权威信息的单一来源。懒散的经理们的嗡嗡声、私人渠道中的即兴引用、电子邮件、午餐时间的谈话以及厨房柜台周围的聊天,将这个故事融入了公司意识,就像黑咖啡中的阿斯巴甜一样。
当然,那时我们已经说服自己这是错误的。发薪日贷款交易并不是唯一显示这种驼峰模式的交易:涉及亚马逊和麦当劳的交易也显示了同样的情况。
示例图:麦当劳和亚马逊的交易呈现出与我们看到的发薪日贷款类似的模式。
结果是一个神器。但是当我们确定这是错误的时候,它已经在我们网站的首页上了。一个公司的价值观——“寻找和提升真相的渴望”——现在与我们的底线以及更好的媒体和更多销售的承诺相抵触。
回溯数据会打击我们的信誉,降低我们的竞争力…
但这也是正确的做法。
数据团队和我们交谈过的每个人都提出了抗议,最后我们当时的数据负责人——胡安·曼努埃尔·孔特雷拉斯——写了一份清晰、冷静的备忘录,讲述了哪里出了问题,我们不知道什么,以及为什么我们对我们网站上的数据如此不安。这就够了。
乔恩在一次全体会议上刷新了记录,这个误导性的数据在几天内就被删除了。但并不全是阳光和彩虹。数据团队必须认真审视自己,确保不会再发生类似的事情。
我认为,我们的根本问题之一是相信数据是“原始数据”。我们看到一个名为“transaction”的数据库实体,并相信它的创建日期是创建它的想法的时间,而不仅仅是我们的记录。我们看到了记录的消失,并相信这个东西本身已经消失了,而不是简单地通过小故障、停用或 API 不作为而变得模糊不清。
作为一个团队,我们仍然没有真正理解数据从来不是被动观察的:它总是被获取。如果不理解捕获行为背后的机制,我们就没有权利提取底层细节并发布高层结果。
我有史以来最喜欢的一段话来自 1906 年的《物理理论的目标和结构》,当它提到即使感觉像是自然的原始数据的概念,如“力”或“电压”,也根本不是原始的时,它击中了要害。
走进实验室;走近这张堆满了各种仪器的桌子:一节电池、用丝绸包裹的铜线、装满水银的容器、线圈、一根带镜子的小铁棒。一个观察者将装有橡胶的金属杆插入小孔中;铁振荡,通过绑在它上面的镜子,发送一束光到赛璐珞标尺上,观察者跟随光束在其上的运动。
在那里,毫无疑问,你有一个实验;通过光点的振动,这位物理学家仔细观察铁片的振动。现在问他在做什么。他是否会回答:“我正在研究承载这面镜子的铁片的振动”?
不,他会告诉你他在测量一个线圈的电阻。
如果你感到惊讶,问他这些词有什么意思,它们与他感知到的和你同时感知到的现象有什么关系,他会回答说你的问题需要一些很长的解释,他会建议你学习电学课程。
一旦你学会了定义电阻和电动势是什么以及它们是如何产生的详细理论,你就只能参考这些密集的概念。
在我们的例子中,只有当我们通过蜿蜒的服务器逻辑,跨越 GRPC 障碍,从定义到群体到变异,直到最后它穿过数据访问层并进入永久内存,跟踪 protobuf 模型时,我们才能真正理解记录的含义。
我们必须学习电学课程。
4:被混沌猴碾压
图片来自 Pixabay 的 Vicki Lynn
在发薪日贷款传奇和 Even 的真相危机之后,我们得到消息,一个潜在客户将在几个月内推出——并且有一个特殊的转折。他们愿意让我们在他们的员工中进行该产品的随机对照试验。
我们谈论的不仅仅是一个功能变体,或者一个特定蓝色的 A/B 测试。我们将向 50%的潜在会员展示这款应用。我们会允许他们正常下载,询问他们是否想参加一项受控实验,然后在最后一刻将他们随机分为治疗组和对照组,将选择偏差的威胁挤压成一个纯粹的建议。
对照组会得到一个除了说谢谢之外什么也不做的应用程序,并倒计时直到研究期结束,而治疗组将获得全部功能。两组的参与者都会得到时间补偿,到最后,我们最终会知道该产品对他们的财务健康有什么样的影响。
在我多次尝试观察研究和奇特的计量经济学失败后,这次进行直接干预的机会就像看到一艘在太平洋上漂流了几个月后的船。一个孤独而遥远的希望,但这是一个我必须投入全部精力的希望。
它最终会失败。
但这将是我职业生涯中最有价值的几个月。我们的工程总监阿希姆和奥利维亚在我身上冒了一次险。如果我努力构建实验和这种新的“控制应用”体验,他们会确保我有合适的导师来照看我,并确保我不只是在代码库中乱闯,不受控制。
他们不用找很远。迈克尔和钱宁立即主动贡献了他们的时间和精力,向我展示了如何编写可理解的、有据可查的、高性能的代码。 Emily 给我上了一堂 React Native 的速成课,教我 Even 内部组件和流程逻辑的细微之处。
我们的设计负责人马克走上前来,在可能不到一天的时间里,为整个体验画出了蓝图。我们的首席合规官斯瓦蒂与 UX 研究公司合作,成为我们自己的内部审查委员会,确保我们对实验参与者尊重、仁慈、公正。
我觉得我需要在这里澄清一些事情,因为它仍然不是很明显。
这不是公司层面的指令。
没有 OKR 我们试图击中,没有人的经理告诉他们该怎么做。我提到的每一个人都知道我需要帮助,最终这种努力会让我们了解到更多关于 Even 能力的真相。这就是全部的代价。
我真的不知道该如何表达我的感激之情。但我想我不应该感到惊讶,确切地说。我们在雇佣合适的人上下了很大功夫。我经常想当然地认为我周围都是对真相好奇的慷慨的人们,但是现在这个事实是不可避免的。
卡特,我们当时的会员顾问主管,主动询问他的团队如何参与其中。贝基已经在公司的各个方面承担了大量的工作,她主动要求管理系统,以确保研究参与者按时得到报酬。
这一切都在一起。当我意识到获得一个好的样本量可能要花费我们 10 万美元的参与者报酬时,有一个短暂的大汗淋漓的时刻,但在与埃文和昆腾的五分钟会议中,我得到了一个简单的“是的,似乎值得”,笔记本电脑啪的一声关上,以及一句祝你好运的简短话语。
尽管在客户整合方面出现了一些小问题,但事情感觉像是在蹒跚前行。
然后新冠肺炎封锁了全国,发射计划告吹。
我们执行得很好,但致命的缺陷是孤注一掷。虽然我经常思考,但我仍然不确定这里的正确策略应该是什么。一方面,这个机会如此之大,以至于我觉得应该尽快加大赌注。另一方面,我们应该更好地调查我们与该客户成功整合的可能性,因为这是整个努力的关键。
像这样的研究,有这么多移动的部分,总是有不成功的风险。但是向前看,采取没有单点失败的策略是明智的。
就像一个好的软件一样,科学必须是容错的。
5:随机化 Z 的禅
图片作者。
执行产品实验要容易得多,因为它不涉及向全体员工展示功能。当我们巩固了我们作为员工福利的地位时,即使有一个很好的系统来确保知情同意和补偿,干预的伦理也变得有点紧张。
我们可以更快地做那些对制造伟大产品至关重要的实验。
像威利这样的设计师运行着他们自己庞大的研究项目,并且总是在思考如何让事物更容易理解和使用。产品经理指定量化的结果来证明一个发布是否成功,或者是否需要重组。这使得尝试不同金额来优化付费推荐和会员增长变得更加简单。或略有不同的追加销售和推送通知,以推动产品的使用。或者一个额外的入职审查将储蓄采用率提高了 31% 。
这些是我们有设备和胃口的东西,我认为我们不能做类似的事情来测试企业的核心价值主张或我们的经济学基本理论是可悲的。
但是等等,等一下——我们不能吗?
让我们重温一下我们之前看到的因果效应的混淆图。这个更普通一点。我们有一些未知的 U 混淆变量,它以某种不确定的方式影响 Instapay 率和透支率(可能是减少或增加)。
我们仍然想知道 Instapay 对透支率的影响有多大——是零、负还是正。
我们也有我前面描述的混淆问题,但是如果我们添加一个特殊的节点会怎么样呢?
Z 这是我们知道的可以改变 Instapay 费率的任何策略(而且仅仅是 Instapay 费率)。例如,提醒会员更明智地使用 Instapays 的推送通知可能会减少使用量。
如果我们随机将 Z 应用于我们的人口,我们将知道 Z 与 Instapay 之外的一切都不相关,只通过对 insta pay 的影响与透支率相关。
这对我们有什么帮助?
好吧,让我们做标准的计量经济学的事情,并执行一些回归。我们可以得到 Z 对透支率的线性关系,得到线Z→透支。同理可以得到 Z→Instapay 。
这些关系只是线条(让我们假设我们的 Z 有很多好的层次,让我们画出一个整洁的层次)。
示例数据:Z 与即时支付和透支的相关性
从这个示例数据中,我们知道,随着 Z T21 的上升,Instapays 下降。与此同时,透支利率随着规模的扩大而上升。如果我们关于 Z 的假设是正确的,并且 Z 只通过它对 Instapays 的作用影响透支率,这一定意味着 Instapays 对透支有某种抑制作用。这是一个因果影响,尽管存在混杂变量,我们还是发现了这个影响。
让我们用更精确的数学术语来进行推理。我们可能会说:行Z→透支应该和Z→Instapay→透支一样。这意味着Z→透支可以表示为复合线性回归。我们观察到的数据给了我们足够的信息来解决因果insta pay→透支关系,通过对该表示做一些线性代数。
就是这样。做个 A/B 测试,解几个线性方程,就有了。
因果推理的秘密一直在我们面前。
我们已经习惯于以高速度做的每件事都可以转向核心研究,并告诉我们我们的产品实际上让我们沿着我们的使命走了多远。随机推送通知、模态追加销售、通过聊天的热情欢迎、入职页面——它们都是因果王国的关键。
因为我们可以同时运行如此多的项目,所以即使一些项目失败了也没关系:它们可以在另一个时间、另一个地方,与另一个客户一起通过微小的调整重新启动。流行病、经济衰退或交易失败都无法阻止我们。
我们只需要执行。
我们也是。
如果你认为工程项目是学习世界上一些新的和基本的东西的机会,甚至可能是你的地方。我们在 招聘 。
对于使用二元变量和随机化的 Z 的无假设分析,因果推断的途径比“复合线性回归”方法稍欠直观,但 仍然绝对可行 并且非常非常酷。
数据科学中的因果推断:A/B 检验&有协变量调整的随机试验
效率&A/B 测试中条件协变量调整的统计功效增益&随机试验
照片由卡斯帕·卡米尔·鲁宾在 Unsplash 上拍摄
1:背景和动机
因果推理是一个涉及几个领域的领域,并引起了包括统计学家、数据科学家、机器学习科学家和其他计算研究人员在内的广泛从业者的兴趣。
到目前为止,我已经写了几篇关于因果推理空间的方法/主题的文章。其中包括:
- 因果推理中的有效抽样框架
- 因果推断中的双重稳健估计技术
- 半参数结构嵌套模型的 G-估计
- 存在 M 偏差结构时因果效应的恢复
- 在 AB 试验/随机试验中对边缘结构建模的需求,用于信息性审查调整
- 多重比较的有效推理覆盖率
这篇文章涉及 A/B 检验(又名随机试验)和通过协变量调整的统计有效的条件抽样估计规范。即使在没有混杂因素的情况下,也为调整感兴趣结果的强预测因素的益处提供了数学上严格的论证和计算模拟。
该作品的内容如下:
作者图片
2:具有连续结果的简单理想化 A/B 测试
我们将首先探讨在假设感兴趣的结果是连续的情况下,在 A/B 测试框架中协变量调整的好处:
2.1:玩具示例的规格
让我们假设一个简单的“理想化”A/B 测试,带有随机二元干预和连续正态分布结果 Y 。“理想化”是指:
- 完美数据测量
- 完美的受试者依从性,无交叉干预
- 没有失访或丢失数据,因此没有信息审查
(关于受试者不依从和信息性审查的调整方法,请见 见我的 关于信息性审查和边缘结构建模)
与上述理想化 A/B 测试相对应的边际因果 DAG(在零值下)如图 1 所示。
作者图片
在上面的空因果 DAG 中,我们有二元介入和连续结局 Y 。干预是随机化的,因此没有箭头进入。但是请注意,我们在集合***【L】中有一组附加变量,带有指向结果 Y 的箭头。集合 L 中的变量是结果Y 的直接原因(即预测因素),它们独立于随机干预而不是通过随机干预来调节。*****
对于有随机试验和 A/B 试验因果 DAG 经验的读者来说,在图 1 的DAG 中设置 L 可能会显得奇怪。有人可能会问“如果干预是随机的,那么干预和结果应该是图上唯一的变量?这是随机研究,不是观察研究?setL*中的附加变量从哪里来?”*****
这激发了关于“完全”因果 Dag 的重要讨论点。当我们指定一个因果 DAG 并判定图是“完整的”并且“所有的变量都在图上”时,我们具体指的是什么?嗯,具体来说,我们的意思是:
- 关于我们详细说明的科学上著名的感兴趣的问题,为我们的问题构建和恢复无偏抽样估计量所需的一组充分的变量在图上
重要的是要记住,在因果 DAG 上总是有比图示更多的变量。在实践中,我们经常只是形象地展示足以回答我们问题的变量。例如,在图 1 的因果 DAG 中,理论上有更多的变量在两个方向上无限延伸:**
- 集合 L 中变量的直接原因的变量,以及这些变量的直接原因,以此类推
- 是 Y 的直接后代的变量,以及这些变量的直接后代,等等
为了恢复干预对结果的因果效应的无偏估计,我们只需要变量和 Y 。但是,这并不意味着 set L 中的变量不是真实存在的。****
对于我们感兴趣的问题以及本文的主题,我们将清楚为什么选择在我们的因果 DAG 中以图形方式显示集合 L 中的变量。还是那句话,我们不需要包含 L 来恢复一个AY 因果效应的无偏估计。但是从推理覆盖和统计功效的角度来看,包括*对我们是有益的,我们很快就会看到。***
2.2:因果效应估计的“标准”边际抽样估计量
让我们具体说明在最简单的随机试验或玩具问题的 A/B 试验中使用的“标准”边际抽样估计量。
同样,从图 1 中的因果 DAG 开始:
作者图片
作者图片
作者图片
2.3:因果效应估计的条件抽样估计量
作者图片
在图 2 中,我们有与图 1 中相同的因果 DAG,除了我们现在对集合 L 进行调节。注意,我们仍然对恢复干预对结果的平均因果效应的无偏估计感兴趣。******
作者图片
作者图片
2.4:抽样方差和统计功效的差异
作者图片
作者图片
作者图片
作者图片
作者图片
作者图片
3: 具有二元结果的简单理想化 A/B 测试
现在,让我们在假设感兴趣的结果是二元的情况下,探讨 A/B 测试框架中共变量调整的好处。由于优势比的不可压缩性,我们正在分别处理二元结果案例。关于不可压缩性的详细讨论, 参见 Miguel Hernan 和 James Robins 的《因果推论:如果 会怎样》一文中的第 4.3 点。
3.1:玩具示例的规格
让我们假设一个简单的“理想化”A/B 测试,带有随机二元干预和伯努利分布结果**
与上述理想化 A/B 测试相对应的边际因果 DAG(在零值下)如图 3 所示。
作者图片
在上面的空因果 DAG 中,我们有二元干预,二元结果 Y ,以及协变预测结果中的集合。请注意,上面的 DAG 与 2.1 节中的图 1 几乎相同,除了感兴趣的结果 Y 是二进制而不是连续的。****
3.2:因果效应估计的“标准”边际抽样估计量
让我们具体说明在最简单的随机试验或玩具问题的 A/B 试验中使用的“标准”边际抽样估计量。
再次从图 3 中的因果 DAG 开始:**
作者图片
作者图片
作者图片
3.3: 因果效应估计的条件抽样估计量
作者图片
作者图片
作者图片
3.4:抽样方差和统计功效的差异
作者图片
作者图片
4.计算模拟
下面是第 2 节(连续结果病例)和第 3 节(二元结果病例)中介绍的理想化随机试验的 Python 计算模拟。研究了有和没有协变量调整的平均因果效应差异的无偏估计的恢复,显示了有协变量调整的统计效率增益:
让我们导入我们需要的库:
接下来,我们模拟随机试验的函数,包括有无协变量调整的连续/二元结果,以及功效计算:
在连续结果情况下运行模拟:
在二元结果情况下运行模拟:
从上面的结果中,我们可以看到,在连续和二元结果情况下,协变量调整分析与未调整分析相比,在功效方面有效率增益。
以上计算模拟的完整代码/笔记本,请看下面的 github 链接 。
5.总结和结论
这总结了我们对协变量调整的 A/B 检验的推导和计算模拟,以及从统计效率的角度来看这样做的好处。我鼓励任何发现上述材料有见地的人创建自己的模拟示例,利用我的代码作为起点,并自己进行实验!
如果你想了解更多关于因果推理的方法和注意事项,我会推荐哈佛大学 Miguel Hernan 和 Jamie Robins(我以前的两位教授)的教科书“因果推理:如果会怎样”,加州大学洛杉矶分校 Judea Pearl 的教科书“因果关系,斯坦福大学 Daphne 黑仔和耶路撒冷希伯来大学 Nir Friedman 的教科书概率图形模型:原理和技术,以及加州大学伯克利分校 Mark van der Laan 和 Sheri 的两本关于目标最大似然估计的教科书这些都是很棒的文章。我计划在未来写更多关于因果推理的深度文章。****
因果推断:如果会怎样
希望以上有见地。正如我在以前的一些文章中提到的,我认为没有足够的人花时间去做这些类型的练习。对我来说,这种基于理论的洞察力让我在实践中更容易使用方法。我个人的目标是鼓励该领域的其他人采取类似的方法。我打算在未来写一些基础作品,所以请随时在 LinkedIn 上与我联系,并在 Medium 上 关注我的更新!
数据科学中的因果推理:通过倾向评分调整的条件独立性
倾向分数的说明和证明,并附有计算模拟
穆罕默德·拉赫马尼在 Unsplash 上的照片
1:背景和动机
因果推理是一个涉及几个领域的领域,并引起了广大从业者的兴趣。这些人包括统计学家、数据科学家、机器学习科学家和其他计算研究人员。
到目前为止,我已经写了几篇关于因果推理空间的方法/主题的文章。其中包括:
- 数据科学中的因果推理:高效的抽样框架&设计
- 数据科学中的因果推断:G 方法的双重稳健估计
- 数据科学中的因果推理:结构嵌套模型的 G 估计
- 数据科学中的因果推理:A/B 测试和边际结构建模的需要
- 数据科学中的因果推理:具有混杂调整的 M 偏差的结构
- 数据科学中的因果推理:多重比较的有效推理覆盖
- 数据科学中的因果推断:A/B 检验&带协变量调整的随机试验
这篇文章特别关注关于倾向得分的公式和证明。
作为一个玩具示例,让我们假设我们有一个二元干预 A ,连续结果 Y ,以及协变量矢量L,它们具有以下因果结构(在 A 对 Y 没有因果影响的零假设下):
作者图片
让我们假设我们对恢复对结果 Y 的干预 A 的平均因果差异的无偏估计感兴趣:
作者图片
从上面的因果 DAG 可以清楚地看出,干预 A 和结果 Y 是以向量 L 为条件的 d 分隔。因此,通过因果马尔可夫假设,干预 A 和结果 Y 独立于向量 L 。
这种情况下的倾向得分是以“原因” L 为条件的干预概率 A=1 :
作者图片
在观察环境中,通过仅调节倾向得分来恢复干预 A 对结果 Y 的因果效应的无偏估计的能力在分析和数字上都明显有利。在有些情况下,给定研究中的干预 A 和结果 Y ,可以用比直接在结果模型中包括所有所需协变量 L 更高的数值稳定性来估计倾向得分。通过标量倾向得分的条件独立性也提供了在倾向得分的分级层内匹配干预臂的机会,以实现条件独立性并恢复感兴趣的因果效应。在协变量 L 的大向量的情况下,在由于稀疏性和小样本量而不可能在向量 L 的单个层内匹配的情况下,在倾向得分的层内匹配干预臂可能是可行的。
在这篇文章中,我们将表明,在给出的玩具问题的因果结构下,干预 A 和结果 Y 不仅是条件独立的给定向量 L ,而且是条件独立的,仅给定倾向得分本身。
这篇文章的目录如下:
作者图片
说到这里,让我们开始吧。
2:通过倾向得分证明条件独立性
2.1:玩具示例的说明和倾向得分
让我们再次具体说明我们的玩具例子:
假设我们有二元干预 A ,连续结果 Y ,协变量的向量 L 具有如下因果结构(在 A 对 Y 没有因果影响的零假设下):
作者图片
同样,假设我们对恢复干预 A 对结果 Y 的平均因果差异的无偏估计感兴趣:
作者图片
作者图片
作者图片
我们的目标是证明:
作者图片
2.2:倾向分数证明方法
让我们来看看下面的可能性:
作者图片
上面我们有概率 A=1 取决于倾向得分和结果 Y 。如果事实上情况是 A 和 Y 独立于倾向得分,那么上面的概率因此决不是结果 Y 的函数。
因此,如果我们可以证明上述概率绝不是结果 Y 的函数(即除了某个 f( Y )之外的任何函数),那么我们已经有效地证明了干预 A 和结果 Y 在给定倾向分数的情况下必须是条件独立的:
作者图片
2.3:复习迭代期望定律
在我们给定倾向分数的条件独立性证明中,我们将在条件期望上利用期望的迭代法则。
作为复习,我们将证明以下等式:
作者图片
注意,在下面的证明中,我们假设 X 、 Y 、 Z 和 S 都是离散随机变量。在连续随机变量的情况下,证明将类似地遵循在所讨论的随机变量的支持上的积分,而不是和。
作者图片
2.4:正式证明
现在让我们进行我们的正式证明,即干预 A 和结果 Y 确实是以倾向得分为独立条件的:
作者图片
利用期望的迭代法则,我们将在向量 L 上指定附加条件的内部嵌套期望。
作者图片
让我们来审视一下内心的期待。我们有以倾向分数为条件的预期干预值 A ,结果 Y ,向量L。注意,倾向得分完全是向量的函数,并且在这个意义上是 L 的“更粗糙”版本。假设 L 已经存在于条件语句中,倾向得分没有添加额外的信息,因此可以从预期中删除:
作者图片
我们现在有:
作者图片
让我们再次审视内心的期待。我们有干预的期望值 A 以结果 Y 和向量 L 为条件。回想一下空值下的因果 DAG,根据定义,干预 A 独立于结果 Y 以向量L为条件:
作者图片
因此,根据定义,outcome Y 不会向内部条件期望添加额外的信息,并且可以被删除:
作者图片
因此,我们有:
作者图片
我们再次审视内心的期待。我们有期望的干预值一个条件向量 L 。请注意,根据定义,这种预期是我们的倾向得分:
作者图片
因此,我们有:
作者图片
在证明的这一点上,我们有了以倾向得分和结果 Y 为条件的倾向得分的期望值。以自身为条件的倾向得分的期望值实际上等同于恢复常数的期望值(根据定义,常数本身就是常数)。假设我们以一个常数为条件,在这种情况下,我们也以结果 Y 为条件的事实是不相关的:
作者图片
因此,我们有:
作者图片
作者图片
3:计算模拟
我们现在将在 Python 中进行计算模拟,通过调节倾向得分来研究二元干预 A 对连续结果 Y 的因果效应差异的无偏估计的恢复
- 创建一个具有真实因果 DAG 的模拟数据集,如下图图 1* 所示,真实因果效应差 A 对 Y 为 2.3*
- 通过对结果模型中的全向量 L 进行调节,恢复因果效应差异的无偏估计
- 估计倾向得分,并通过仅调节结果模型中的倾向得分来恢复因果效应差异的无偏估计
让我们从加载我们的库开始:
,一个模拟数据集的函数:
…以及单变量、多变量和倾向评分方法的函数:
指定了我们的函数后,我们就可以进行计算模拟了。
让我们从恢复模拟数据集开始:
让我们以干预和作为唯一输入,对结果模型进行单变量回归:
如上述结果所示,A 对 Y 的因果效应差异估计为-3.1027。这显然是一个有偏差的估计,因为我们知道真正的因果效应差是 2.3。鉴于我们玩具问题的因果结构,这一发现也并不令人惊讶(如图图 1* 所示)。我们知道 A 和 Y 不是边际独立的。*
现在让我们执行结果模型的多变量回归,以 A 和矢量LT5 为条件:
如以上结果所示,现在估计 A 对 Y 的因果效应差为 2.3022。这似乎是真实因果效应差异的无偏估计。给定 A 和 Y 在向量 L 上是 d 分离的条件,这一发现同样不令人惊讶。
现在让我们看看我们是否可以复制相同的结果,但是通过仅将结果模型限制在倾向得分上,而不是全向量 L :
如上述结果所示,A对 Y* 的因果效应差估计为 2.3059。这也是真实因果效应差异的无偏估计。*
以上计算模拟的完整代码/笔记本,请看下面的 github 链接 。
4.总结和结论
这总结了我们的推导和利用倾向评分模型的计算模拟。我鼓励读者使用我的代码(通过上面的 github 链接)作为起点,并创建自己的模拟来进行实验。
如果你想了解更多关于因果推理的方法和注意事项,我会推荐哈佛大学 Miguel Hernan 和 Jamie Robins(我以前的两位教授)的教科书“因果推理:如果会怎样”,加州大学洛杉矶分校的 Judea Pearl 的教科书“因果关系,斯坦福大学的达芙妮·黑仔和耶路撒冷希伯来大学的 Nir Friedman 的教科书“概率图形模型:原理和技术,以及加州大学的 Mark van der Laan 的两本关于目标最大似然估计的教科书
因果推断:如果会怎样