在一行 Python 代码中自动化您的文本处理工作流程
使用 CleanText 库处理 NLP 任务的文本数据
自然语言处理(NLP)是人工智能的一个子领域,涉及计算机和自然语言之间的交互。它围绕着如何训练一个可以理解和实现自然语言任务用法的数据科学模型。典型的 NLP 项目遵循流水线的各个方面来训练模型。流水线中的各个步骤包括文本清理、记号化、词干化、编码成数字向量等,然后是模型训练。
为 NLP 任务导出的数据集是文本数据,主要来自互联网。大多数时候,用于 NLP 建模的文本数据是脏的,需要在数据处理的早期进行清理。数据科学家将大部分时间花在数据预处理上,包括清理文本数据。
在本文中,我们将讨论一个有趣的库 CleanText,它简化了清理文本数据的过程,并加快了数据预处理管道。
什么是 CleanText?
CleanText 是一个开源的 Python 库,它能够清除从 web 或社交媒体上搜集的文本数据。CleanText 使开发人员能够创建规范化的文本表示。CleanText 使用 ftfy 、 unidecode 和各种其他硬编码规则(包括 RegEx)将损坏或不干净的输入文本转换为干净的文本,可以进一步处理这些文本以训练 NLP 模型。
安装:
可以使用以下命令从 PyPl 安装 CleanText 库:
**pip install clean-text**
安装后,您可以使用以下命令导入库:
**from cleantext import clean**
用法:
库 CleanText 只提供了一个函数“Clean ”,它采用各种参数来执行文本清理。清洗功能可以执行 11 种清洗,包括:
Unicode:
它修复了各种 Unicode 错误。
**s1 = 'Zürich'
clean(s1, fix_unicode=True)**# Output: zurich
ASCII:
它将文本翻译成最接近的 ASCII 表示。
**s2 = "ko\u017eu\u0161\u010dek"
clean(s2, to_ascii=True)**# Output: kozuscek
下限:
将文本数据转换成小写。
**s3 = "My Name is SATYAM"
clean(s3, lower=True)**# Output: my name is satyam
替换网址/电子邮件/电话号码:
用一个特殊的令牌替换文本数据中出现的所有 URL、电子邮件或电话号码。
**s4 = "https://www.Google.com and https://www.Bing.com are popular seach engines. You can mail me at satkr7@gmail.com. If not replied call me at 9876543210"****clean(s4, no_urls=True, replace_with_url="URL",
no_emails=True, replace_with_email="EMAIL"
no_phone_numbers=True, replace_with_email="PHONE")**# Output: url and url are popular search engines. You can mail me at EMAIL. If not replied call me at PHONE
替换货币:
用特殊标记替换文本数据中出现的所有货币。
**s5 = "I want ₹ 40"
clean(s5, no_currency_symbols = True)
clean(s5, no_currency_symbols = True, replace_with_currency_symbol="Rupees")**# Output: i want <cur> 40
# Output: i want rupees 40
删除号码:
用特殊符号替换或删除所有数字。
**s7 = 'abc123def456ghi789zero0'****clean(s7, no_digits = True)
clean(s7, no_digits = True, replace_with_digit="")**# Output: abc000def000ghi000zero0
# Output: abcdefghizero
替换标点符号:
用特殊符号删除或替换文本数据中的所有标点符号。
**s6 = "40,000 is greater than 30,000."
clean(s6, no_punct = True)**# Output: 40000 is greater than 30000
结合所有参数:
我们已经在上面单独讨论了所有的参数。现在让我们在 Clean 函数中组合它们,为一个脏的样本文本调用它,并观察干净文本的结果。
(作者代码),CleanText
因此,只需编写一行 Python 代码,就可以清除不干净的文本数据,并对其进行进一步的预处理。
结论:
CleanText 是一个高效的库,它可以处理或清理您收集的脏数据,只需一行代码就可以获得规范化的干净文本输出。开发者只需要根据他/她的需要调整参数。它简化了数据科学家的工作,因为现在他/她不必编写许多行复杂的正则表达式代码来清理文本。CleanText 不仅可以处理英语语言的输入文本,还可以处理德语,只需设置**lang=’de’**
。
CleanText library 只涵盖了一些文本清理参数,还有改进的空间。尽管如此,开发人员可以使用它来完成一些清理任务,然后继续手工编码来完成剩余的工作。
阅读下面提到的文章来了解 AutoNLP——一个自动化的 NLP 库。
https://medium.com/swlh/autonlp-sentiment-analysis-in-5-lines-of-python-code-7b2cd2c1e8ab
参考资料:
[1]明文知识库:https://github.com/jfilter/clean-text
感谢您的阅读
自动化客户细分
使用 Python 和 UbiOps
图片由Firmbee.com
介绍
客户细分是增进你对客户了解的好方法,这样你就能更好地对他们的需求做出反应。要真正从客户细分中获得最大收益,最好是将其自动化,这样可以最大限度地减少手动工作和花费的时间。在这篇文章中,我将向你展示如何使用 Python 和 UbiOps 来自动化你的客户细分。我将对存储在谷歌表单中的交易数据进行 RFM 分析。
你可以在这里找到本教程 的结果代码。
什么是 RFM 分析?
RFM 分析是一种基本的客户细分算法。代表近期、频率、货币分析。这种特定的分析基于三个因素将每个客户分配到一个组:
- 客户最近购买了什么东西?
- 他们多久买一次东西?
- 当他们买东西的时候,他们会花多少钱?
使用这三个因素,该算法将通过以下方式为每个客户分配一个 RFM 分数:
- 根据最近将客户分成四分之一
- 根据频率将客户划分为四分位数
- 根据支出将客户分为四分之一
- 将客户所在的每个四分位数的数字串联起来,以获得一个分数
如果我们以客户 Annie 为例,她可能处于最近消费的第一个四分位数,第二个四分位数,第三个四分位数。她的 RFM 分数将会是 123 。111 分是最高分,444 分是最差分。
想深入了解 RFM 吗?我推荐叶小开·阿恩·贝克的这篇文章。
如何对您的数据进行 RFM 分析
RFM 分析需要交易数据。我将用这个 Kaggle 数据集作为一个例子来展示如何进行 RFM 分析。首先,我们需要导入熊猫并读入数据。
import pandas as pd
data_df = pd.read_excel(‘Online_Retail.xlsx’)`
如果你想看一眼数据,你可以使用data_df.head()
,你应该会看到这样的内容:
现在我们有了数据,我们可以开始我们的 RFM 分析。在这篇博文中,为了保持简洁,我不会涉及数据清理,但是要注意,当您想要将下面的代码应用到您自己的数据集时,您需要确保您的数据是干净的。
我们需要做的第一件事是计算每笔交易的总价。为此,我们可以简单地将单价列乘以数量列,并将结果保存在一个新列中,我们称之为**总价。**您可以通过下面一行代码实现这一点:
data_df[‘TotalPrice’] = data_df[‘Quantity’].astype(int) * data_df[‘UnitPrice’].astype(float)
现在我们已经准备好了必要的列,我们可以对我们的近期、频率和货币值执行以下计算:
- Recency :计算每个客户最近一次购买日期和最后一次购买日期之间的天数。
- 频率:计算每个客户的订单数量。
- 货币:计算每个客户所花的所有钱的总和。
我们可以使用 lambda 函数快速进行计算:
data_df[‘InvoiceDate’] = pd.to_datetime(data_df[‘InvoiceDate’])
rfm= data_df.groupby(‘CustomerID’).agg({‘InvoiceDate’: lambda date: (date.max() — date.min()).days,
‘InvoiceNo’: lambda num: len(num),
‘TotalPrice’: lambda price: price.sum()})
完美!现在我们已经有了我们的值,我们需要做的最后一件事是完成这个分析,根据最近、频率和货币将客户分成不同的四分之一,并将每个四分之一的数字连接起来。
# Change the name of columns
rfm.columns=[‘recency’,’frequency’,’monetary’]# Computing Quantile of RFM values
rfm[‘recency’] = rfm[‘recency’].astype(int)
rfm[‘r_quartile’] = pd.qcut(rfm[‘recency’].rank(method=’first’), 4, [‘1’,’2',’3',’4']).astype(int)
rfm[‘f_quartile’] = pd.qcut(rfm[‘frequency’], 4, [‘4’,’3',’2',’1']).astype(int)
rfm[‘m_quartile’] = pd.qcut(rfm[‘monetary’], 4, [‘4’,’3',’2',’1']).astype(int)# Concatenating the quantile numbers to get the RFM score
rfm[‘RFM_Score’] = rfm.r_quartile.astype(str)+ rfm.f_quartile.astype(str) + rfm.m_quartile.astype(str)
在运行了这段代码并使用rfm.head()
检查了“rfm”之后,得到的数据帧应该是这样的:
现在,每个客户都有一个 RFM 分数,以表明他们是什么类型的客户。您可以利用这些信息来制定营销和销售策略。
自动化您的 RFM 分析
为了最大限度地利用 RFM 分析,应该对您的数据定期执行自动化分析。要开始自动化,首先需要在分析和数据存储位置之间建立一个连接。现在,我们使用本地 excel 表,但更有可能的是,您将这些数据存储在某种共享位置,可以是数据库,也可以是更简单的共享驱动器。在本文中,我将向您展示如果您的交易数据存储在 Google Sheet 中,如何自动进行这种分析。当然,你的情况可能会非常不同,但我将向你展示的相同原则仍然适用。
为您的 Google Sheet 设置服务帐户
为了建立到您的 Google 表单的连接,我们需要一个能够访问表单的服务帐户。您可以创建一个,如下所示:
- 前往谷歌开发者控制台并创建一个新项目(或选择一个现有项目)
- 您将被重定向到项目仪表板,在那里点击**“启用 API 和服务”**,搜索“Sheets API”。
- 在 API 界面点击**“启用”**启用该 API
- 同样启用**“驱动 API”**。
- 转到**“凭证”选项卡,选择“创建凭证>服务帐户”**创建一个新的服务帐户。
- 给服务帐户一个名称和描述
- 将服务帐户权限设置为**“计算引擎服务代理”,跳过表单中的第三步,点击创建**。
- 导航到新创建的服务帐户,并转到“Keys”选项卡。点击**“添加密钥>创建新密钥”**。
- 将类型设置为 JSON 并点击创建。这将提示下载一个 json 文件,该文件包含帐户授权所需的私钥。将它存储在运行代码的同一文件夹中。
好了,我们现在有了一个具有正确权限的服务帐户。我们只需要让服务帐户访问仍然有数据的表。要做到这一点,带着你的数据去谷歌表单,点击“分享”。与您在前面步骤中创建的服务帐户的电子邮件地址共享 google 表单。服务帐户将需要编辑权限,因为它将执行读取和写入操作。
从 Google 工作表中检索数据
使用您之前创建的服务帐户,我们现在可以建立从您的 Python 代码到 Google Sheet 的连接。我正在使用图书馆的图片来帮助解决这个问题。
SCOPES = (‘https://www.googleapis.com/auth/spreadsheets', ‘[https://www.googleapis.com/auth/drive](https://www.googleapis.com/auth/drive)')# Change the json filename to your json file in the line below
service_account_info = json.loads(“your_json_file.json”)
my_credentials = service_account.Credentials.from_service_account_info(service_account_info, scopes=SCOPES)
gc = pygsheets.authorize(custom_credentials=my_credentials)
现在已经建立了一个连接,我们可以继续从 Google Sheet 中读取数据:
spreadsheet = gc.open(“Online_Retail”)
sheet_data = spreadsheet[0]# Transforming data into a Pandas DataFrame
data_df = sheet_data.get_as_df()
现在我们有了一个基于 Google 工作表中的数据的数据框架,我们可以用它来分析前面的部分。把data_df = pd.read_excel(“Online_Retail.xlsx”)
线拿出来就行了。
将结果写入 Google 工作表
既然我们可以检索数据来执行分析,我们还应该确保我们可以将分析结果写到人们可以访问的地方。在这种情况下,我们将把结果写到同一个 Google Sheet 的一个单独的选项卡中。您可以通过在为 RFM 分析编码后添加以下代码行来实现这一点:
sheet_title = “RFM results”try:
sh = spreadsheet.worksheet_by_title(sheet_title)
except:
print('Worksheet does not exist, adding new sheet')
spreadsheet.add_worksheet(sheet_title)
sh = spreadsheet.worksheet_by_title(sheet_title)
finally:
sh.set_dataframe(sorted_customers, 'A1', copy_index = True)
sh.update_value('A1', 'CustomerID')
print('Data inserted successfully')
从上到下运行结果代码后,首先读入数据,然后执行分析,然后写下结果,您应该能够在 Google Sheets 中看到您的结果!
将您的分析迁移到云中
所以我们现在有了一段 Python 代码,它从 Google 工作表中检索数据,对其执行分析,并将结果写入同一个工作表。在目前的情况下,每当您需要最新的客户细分结果时,代码都需要从笔记本电脑本地运行。如果我们将整个代码转移到云中,我们可以定期进行分析和我们可以向公司内更多的人开放。为了实现这一点,我将使用 UbiOps ,这是一个允许你在 API 背后以可扩展的方式提供 Python 或 R 代码的平台。我会告诉你我如何使用它。
为 UbiOps 准备代码
在我将代码放入 UbiOps 的部署之前,我需要将代码放入所谓的部署包。这意味着我将代码放在部署类中。这只是为了确保 UbiOps 知道什么时候运行什么。我们用例的 deployment.py 文件如下所示:
在部署文件的旁边,我们需要创建一个 requirements.txt 文件来通知 UbiOps 我们代码的依赖关系。以下requirements.txt
应该足够了:
google-api-core==1.28.0
google-api-python-client==2.5.0
google-auth==1.30.0
google-auth-httplib2==0.1.0
google-auth-oauthlib==0.4.4
googleapis-common-protos==1.53.0
numpy==1.20.3
oauthlib==3.1.0
pygsheets==2.0.5
pandas==1.2.4
一旦你有了这两个文件,把它们放在一个单独的文件夹中,然后压缩整个文件夹。这个 zip 文件是您的部署包。您也可以在这里找到完整的部署文件夹。
在 UbiOps 中创建部署
您可以通过 Python、CLI 或 WebApp 创建部署,这取决于您的偏好。我会使用 WebApp。
- 前往https://app.ubiops.com并使用您的帐户登录,如果您没有帐户,请创建一个免费帐户。
- 转到您的项目并导航到“部署”部分,单击创建。
- 为您的部署命名,例如“automated-rfm”
- 在输入下定义一个名为**“文件名”的输入字段,类型为字符串**
5.保留其他设置,点击下一步:创建版本
现在您已经有了一个部署,我们可以创建版本:
- 在部署包中,点击上传 zip 文件,上传您之前创建的部署包 zip 文件。
- 展开可选/高级设置,向下滚动到部署 环境变量。
- 点击创建变量,填写“credentials”作为名称,并复制粘贴您的 google 服务帐户的 JSON 密钥作为值。将环境变量标记为 secret 并点击复选标记按钮。
4.您可以再次保留所有其他设置的默认值,然后单击创建
您的部署现在将开始构建。在后台,UbiOps 会为你的代码制作一个 Docker 镜像,并在它周围封装一个 API。完成后,您会看到状态将变为可用。
一旦您的部署可用,您可以通过单击右上角的创建请求按钮来测试一切是否正常。使用 Google 工作表的名称作为请求的输入。
安排您的分析
自动化分析的最后一步是让它定期运行,以保持所有 RFM 分数是最新的。您可以通过在 UbiOps 中创建一个定期触发您的部署的请求调度来做到这一点。
转到 WebApp 中的“请求时间表”并点击创建。为您的计划命名,如“monthly-rfm ”,并从下拉菜单中选择您的部署。点击下一步进入创建表单的下一部分。在输入数据下,填写您的谷歌表单的名称,然后点击下一步。现在将提示您定义一个时间表。假设您需要在每月第一天的 8:00 进行分析,那么您可以设置以下 cron 作业:0 8 1 * *
设置好 cron 作业表达式后,单击 Create ,您的时间表将被打开!
结论
如果你一直跟着做,你现在已经有了一个 RFM 分析,它会在每个月的第一天自动执行。这样你就有了一个自动更新的客户细分,你的团队可以用它来指导他们的决策。我在本文中给出的例子可能是专门针对 RFM 分析的,但是我向您展示的原则也适用于其他类型的客户细分。
您需要自动化您的分析吗?欢迎在评论中告诉我!
更多信息
想了解更多关于本文中使用的库和工具的信息吗?看看其他媒体文章:
图片:
如何用 Python 自动化 Google Sheets——Dayal Chand Aichara
RFM:
UbiOps:
利用 SQL 和机器学习进行大规模数据质量监控
如何让您的数据管道更加可靠,具有可观察性
图片由 Pexels 上的 Edvin Richardson 提供
数据管道可能因为一百万种不同的原因而中断,但我们如何确保数据质量问题得到实时识别和解决— 大规模解决*?有时候,所需要的只是一点 SQL,一些精度和召回,以及一个整体的方法来**数据可观察性 。*
在本文中,我们将介绍如何从头开始创建自己的数据可观测性监视器,并利用机器学习的基本原理在数据管道中大规模应用它们。
随着公司依赖越来越多的数据来驱动日益复杂的管道,这些数据必须可靠、准确和值得信赖。当数据损坏时——无论是由于模式更改、空值、重复还是其他原因——我们需要知道,而且要快。陈旧的表或错误的指标,如果不加以检查,可能会对您的业务产生负面影响。
如果您是数据专业人员,您可能会发现自己在试图了解数据的健康状况时会一次又一次地问以下问题:
- 数据是最新的吗?
- 数据是否完整?
- 字段是否在预期范围内?
- 零利率是高于还是低于它应有的水平?
- 模式改变了吗?
要回答这些问题,我们可以从软件工程师的剧本中抽出一页:数据可观测性。数据工程师将数据可观察性定义为组织回答这些问题和评估其数据生态系统健康状况的能力。反映数据健康的关键变量,数据可观察性的五个支柱是:
- 我的数据是最新的吗?我的数据是否有未更新的时间间隔?
- 分布:我的现场数据有多健康?我的数据是否在预期范围内?
- 卷:我的数据接收量是否达到预期的阈值?
- 模式:我的数据管理系统的正式结构改变了吗?
- 血统:如果我的部分数据宕机,对上下游有什么影响?我的数据源如何相互依赖?
在本系列文章的中,我们拉开帷幕,研究代码中的是什么样的数据可观察性,在这最后一期文章中,我们将后退一步,思考一般来说什么是好的数据质量监控器。也许你已经阅读了第一部分**和第二部分并在想,“这些都是有趣的练习,但是我们如何在我的真实生产环境中应用这些概念呢?”
在高层次上,机器学习有助于大规模的数据可观测性。配备了机器学习的检测器可以更灵活地应用于大量的表,随着数据仓库的增长,不再需要手动检查和规则(如第一部分和第二部分所讨论的)。此外,机器学习检测器可以实时学习和适应数据,并捕捉复杂的季节模式,否则人眼将无法看到。
让我们开始吧——不需要预先的机器学习经验。
我们的数据环境
本教程基于奥莱利课程 练习 4 , 管理数据停机 。欢迎您使用 Jupyter 笔记本和 SQL 自行尝试这些练习。
你可能还记得第一和第二部分,我们正在研究关于可居住外行星的模拟天文数据。不幸的是,这些数据并不真实——它是为了教学目的而捏造的——但是如果你愿意,你可以假装它是直接来自于毅力。😃
我们使用 Python 生成数据集,对我们在生产环境中遇到的真实事件的数据和异常进行建模。(这个数据集完全免费使用,存储库中的 utils 文件夹包含生成数据的代码。)
在本练习中,我们使用 SQLite 3.32.3,它应该可以通过命令提示符或 SQL 文件以最少的设置访问数据库。这些概念实际上可以扩展到任何查询语言,并且这些实现可以扩展到 MySQL、Snowflake 和其他数据库环境,只需很少的改动。
在本文中,我们将把注意力限制在系外行星表:
请注意,系外行星被配置为手动跟踪一条重要的元数据 date _ added 列——它记录了我们的系统发现该行星的日期,并将其自动添加到我们的数据库中。在第一部分中,我们使用一个简单的 SQL 查询来可视化每天添加的新条目的数量:
该查询生成如下所示的数据:
换句话说,系外行星表每天都会更新大约 100 个条目,但在没有数据输入的日子里会“离线”。我们引入了一个名为 DAYS_SINCE_LAST_UPDATE 的指标来跟踪表的这一方面:
结果看起来像这样:
图表由作者提供。
通过一个小的修改,我们在查询中引入了一个阈值参数来创建一个新鲜度检测器。我们的探测器返回了所有系外行星最新数据超过 1 天的日期。
图表由作者提供。
图中的尖峰代表了系外行星表处理旧数据或“陈旧”数据的情况。在某些情况下,这种中断可能是标准的操作程序——也许我们的望远镜应该进行维护,所以一个周末都没有记录数据。然而,在其他情况下,中断可能代表数据收集或转换的真正问题——可能我们将日期更改为 ISO 格式,传统上推送新数据的工作现在失败了。我们可能有这样的启发:停机时间越长越糟糕,但除此之外,我们如何保证只检测数据中真正的问题呢?
简单的回答是:你不能。
建立一个完美的预测器是不可能的(无论如何,对于任何有趣的预测问题)。但是,我们可以使用机器学习中的一些概念,以更结构化的方式来构建问题,结果是,提供大规模的数据可观察性和信任。
通过机器学习改进警报
每当我们就数据管道中断发出警报时,我们不得不质疑警报是否准确。警报是否指示真正的问题?我们可能会担心两种情况:
- 发出了警报,但没有真正的问题。我们浪费了用户的时间来响应警告。
- 有一个真正的问题,但没有发出警报。我们忽略了一个真正的问题。
这两种情况被描述为假阳性(预测异常,实际上没问题)和假阴性(预测正常,实际上异常),我们希望避免它们。发布假阳性就像在喊狼来了——我们拉响了警报,但一切正常。同样,发布假阴性就像在站岗时睡觉——出了问题,但我们什么也没做。
我们的目标是尽可能避免这些情况,并专注于最大化真阳性(预测异常,实际上是一个问题)和真阴性(预测正常,实际上正常)。
精确度和召回率
因此,我们需要一个好的检测方案来减少误报和漏报。在机器学习实践中,更常见的是考虑相关但更有见地的术语,精确度和召回率:
****
图片由作者提供。
一般来说,精确度告诉我们,当我们发出警报时,我们的正确率是多少。具有良好精度的模型输出可信的警报,因为它们的高精度保证了它们很少谎报。
一般来说,回忆告诉我们实际上有多少问题需要警惕。记忆力好的模特是可靠的,因为他们的高记忆力保证了他们很少在工作时睡觉。
延伸我们的比喻,精度好的模型是很少喊狼来了的模型——当它发出警报时,你最好相信它。同样,一个具有良好回忆的模型就像一只优秀的看门狗——你可以放心,这个模型会捕捉到所有真正的问题。
平衡精确度和召回率
问题当然是,你不可能两全其美。请注意,这两者之间存在明显的权衡。我们如何获得完美的精度?简单:对没事 —值班时一直睡觉—迫使我们有 0%的误报率。问题?召回将是可怕的,因为我们的假阴性率将是巨大的。**
同样,我们如何获得完美的回忆?也很简单:警惕一切——抓住一切机会喊狼来了——迫使假阴性率为 0%。不出所料,问题是我们的假阳性率会受到影响,从而影响精确度。
解决方案:单一目标
我们的数据世界是由可量化的目标运行的,在大多数情况下,我们希望优化单个目标,而不是两个。我们可以将精确度和召回率结合成一个称为 F 的指标——分数:
F_beta 被称为加权的F-分数,因为不同的 beta 值在计算中对精确度和召回率的权重不同。一般来说,F_beta 分数表示,“我认为回忆是 beta 倍,与精确度一样重要。”
当β= 1 时,等式中的值相等。设置 beta > 1,回忆对于更高的分数会更重要。换句话说,beta > 1 表示,“我更关心捕捉所有异常,而不是偶尔引起一次错误警报。”同样,set beta < 1, and precision will be more important. beta < 1 says, “I care more about my alarms being genuine than about catching every real issue.”
Detecting freshness incidents
With our new vocabulary in hand, let’s return to the task of detecting freshness incidents in the EXOPLANETS table. We’re using a simple prediction algorithm, since we turned our query into a detector by setting one model parameter X. Our algorithm says, “Any outage longer than X days is an anomaly, and we will issue an alert for it.” Even in a case as simple as this, precision, recall, and F-scores can help us!
To showcase, we took the freshness outages in EXOPLANETS and assigned ground truth labels encoding whether each outage is a genuine incident or not. 没有某种基本事实就不可能计算模型的准确性,所以考虑如何为用例生成这些总是有帮助的。回想一下,在系外行星表中总共有 6 次持续时间超过 1 天的中断:
让我们武断地说,2020 年 2 月 8 日和 2020 年 5 月 14 日的事件是真实的。每一个都是 8 天长,所以有问题是有道理的。另一方面,假设 2020 年 3 月 30 日和 2020 年 6 月 7 日的断电不是实际事故。这些停机时间分别为 4 天和 3 天,因此这并不奇怪。最后,让 2020 年 6 月 17 日和 2020 年 6 月 30 日分别在 5 天和 3 天发生的中断,也成为真实事件。
以这种方式选择了我们的基本事实后,我们看到更长时间的停机更有可能是实际问题,但没有保证。这种弱相关性将使一个好的模型有效,但不完美,就像在更复杂的真实用例中一样。
现在,假设我们将阈值设置为 3 天,换句话说,“每次超过 3 天的停机都是异常的。”这意味着我们正确地检测到了 2020 年 2 月 8 日、2020 年 5 月 14 日和 2020 年 6 月 17 日的异常,因此我们有 3 个真阳性。但是,不幸的是,我们将 2020–03–30 检测为一个事件,而它并不是一个事件,因此我们有 1 个误报。3 个真阳性/ (3 个真阳性+ 1 个假阳性)意味着我们的精度是 0.75。此外,我们未能将 2020–06–30 检测为事故,这意味着我们有 1 个假阴性。3 真阳性/ (3 真阳性+ 1 假阴性)意味着我们的召回率也是 0.75。f1-分数,由公式给出
意味着我们的 f1 分数也是 0.75。还不错!
现在,假设我们将阈值设置得更高,为 5 天。现在,我们只检测到 2020 年 2 月 8 日和 2020 年 5 月 14 日这两个最长的停机时间。这些都是真实的事件,所以我们没有误报,这意味着我们的精度是 1-完美!但是请注意,我们没有检测到其他真正的异常,2020 年 6 月 17 日和 2020 年 6 月 30 日,这意味着我们有两个假阴性。2 真阳性/ (2 真阳性+ 2 假阴性)意味着我们的召回率是 0.5,比以前更差。我们的回忆受到影响是有道理的,因为我们选择了一个更保守、阈值更高的分类器。我们的 f1 分数可以用上面的公式再次计算,结果是 0.667。
如果我们根据我们设置的阈值来绘制我们的精度、召回率和 f1,我们会看到一些重要的模式。首先,具有低阈值的积极检测器具有最好的回忆,因为它们更快地发出警报,从而捕捉到更多真正的问题。另一方面,更多的被动探测器具有更高的精度,因为它们只对更有可能是真实的最糟糕的异常发出警报。f1 分数在这两个极端之间的某个地方达到峰值——在这种情况下,在 4 天的阈值处。找到最佳点是关键!
图表由作者提供。
最后,我们来看最后一个对比。请注意,我们只查看了 f1 分数,它同等地衡量了精确度和召回率。当我们看β的其他值时会发生什么?
图表由作者提供。
回想一下,一个通用的 F_beta 说“召回是 beta 倍,和精度一样重要。”因此,当回忆被优先化时,我们应该预期 F2 高于 f1——这正是我们在阈值小于 4 时看到的。同时,对于更大的阈值,F_0.5 分数更高,显示出对于具有更高精度的保守分类器的更多容许量。
机器学习的大规模数据可观测性
我们已经对机器学习概念进行了一次快速的探索。现在,这些概念如何帮助我们将检测器应用到生产环境中?关键在于理解对于任何异常检测问题都没有完美的分类器。
假阳性和假阴性,或者同样的精确度和召回率之间总有一个折衷。你必须问自己,“我如何权衡这两者之间的取舍?什么决定了我的模型参数的‘最佳点’?”选择一个 F_beta 分数来优化将隐含地决定你如何权衡这些事件,从而决定在你的分类问题中什么是最重要的。
此外,请记住,如果没有某种基础事实与模型的预测进行比较,任何关于模型准确性的讨论都是不完整的。在你知道你有一个好的分类之前,你需要知道什么是好的分类。
这里祝你没有数据停机!
有兴趣了解如何解决大规模数据质量问题吗?伸出手去 巴尔瑞安 ,以及其余的 蒙特卡洛 团队以及 注册为我们的数据观测
本教程的关联练习可用,此处https://github.com/monte-carlo-data/data-downtime-challenge,本文所示改编代码可用,此处*https://github.com/monte-carlo-data/data-observability-in-practice。***
自动化探索性数据分析
使用 python edatk 库在数据中寻找见解
探索性数据分析是构建机器学习模型的关键初始步骤。更好地理解您的数据可以使发现异常值、特征工程和最终建模更加有效。
探索性数据分析的某些部分,如生成特征直方图和缺失值计数,大部分可以自动化。本文介绍了我创建的一个开源库,它运行一些基本的自动化 EDA 过程。
EDATK:自动化 EDA 工具箱
为了帮助加快探索性数据分析,我创建了 edatk 并开源了代码。这允许您通过 pip 安装,并使用几行代码运行自动化 eda。它仍处于 alpha 阶段,所以将其视为现有 eda 工作流的补充。
edatk 的主要特点是:
- 易用性:在 pandas 数据框架上运行自动化探索性数据分析只需要一行代码。
- HTML 报告输出:通过提供一个文件夹位置,edatk 将构建一个 HTML 报告,以一种简洁的方式呈现视觉效果和表格。
- 目标列探索:这是 edatk 的关键特性之一。传入可选的 target_column 参数指定在可能的情况下添加可视层和线索,帮助您发现输入特征和您在受监督的机器学习设置中预测的列之间的趋势。如果你的问题不符合监督机器学习模式,你可以简单地忽略这个参数。
- 推断的图表类型:基于数据框架中的列类型,edatk 将推断要计算的指标和要显示的图表类型。
在本次演示中,我们将使用常见的虹膜数据集。数据集具有鸢尾植物的各种特征,任务是预测物种。
在本文中,我们不会构建机器学习模型,但会运行自动化 eda 来发现可能有助于选择或构建新功能以纳入模型训练的趋势。
运行自动化 EDA
运行 edatk 的主要方法如下,包括几个关键步骤:
- 导入库并加载数据集。在这个演示中,我们使用 seaborn 将 iris 数据集加载到 pandas 数据帧中。
- 运行 auto_eda 方法,传入您的数据帧、保存(输出)位置和目标列。输出位置和目标列是可选的,但如果您可以提供这些值,则推荐使用。
就这么简单! Edatk 根据列类型和每列的基数运行各种例程。可视化是自动生成的,并且用输出构建一个 html 报告。下面代码生成的完整 html 报告可以在这里查看。
分析结果
单列统计
报告的第一部分遍历所有列,并计算基本的描述性统计数据。这采用初始表的形式,其中包含最小值、最大值、缺失值行的百分比等。下一部分显示了一些基本的描述性图表,如箱线图和直方图。
下面的屏幕截图显示了每列生成的内容,以萼片长度(用于预测物种的数据集特征之一)为例。
单列表格,按作者排序的图像
单列视觉效果,图片由作者提供
多列统计
探索数据最有用的事情之一是绘制要素对并针对目标进行分析。这可以给你一些如何设计新功能的想法。如果您在调用 auto_eda 时传入一个 target_column ,这些特征对可视化中的许多将包括根据该目标变量的颜色编码。这使得发现潜在趋势变得快速而容易。
例如,生成的图之一是散点图,x 轴上有 花瓣 _ 长度 ,y 轴上有 花瓣 _ 宽度 。我们希望训练模型预测的三种不同类型的物种是用颜色编码的。人们可以很快发现一些分离。仅仅包括这两个特性就应该为一个模型提供一个不错的起点。你也可以结合到一个新设计的功能中来捕捉这种关系。
成对的柱形图散点图,作者图片
生成的视觉效果并不总是散点图。该库查看列类型以确定应该生成的可视化类型。例如,使用方框图,根据 花瓣 _ 宽度 绘制分类列(如下例)。
成对的柱形视觉效果方框图,作者提供的图像
警告
Edatk 可以处理一些较大的数据集(就行数而言),因为对于已知的性能密集型绘图,确实会进行一些采样。但是,由于生成了成对图组合,包含大量列的极宽数据集可能会导致问题。在这种情况下, auto_eda 方法提供了一个 column_list 参数来传入一个较小的列名列表。
最后,edatk 仍然处于 alpha 阶段——所以把它作为现有 eda 工作流的补充。
贡献的
该库仍在开发中,但对所有希望做出贡献的人开放源代码以使其变得更好!
计划中的功能可以在 github repo 上的这里查看,以及一些基本指令和 git 命令,供那些希望提出第一个拉请求的人使用。
摘要
自动化的探索性数据分析可以帮助您更好地理解数据并发现初始趋势。
Edatk 就是这样一个库,它试图自动完成这些工作。看看吧,让我知道你的想法!
在Github上可以找到所有的例子和文件。
使用神经网络的自动特征工程
数据艺术家温迪·安格斯,经许可使用
如何自动化并大大改进数据建模中最繁琐的步骤之一
很少有人会否认特征工程是生产精确模型的最重要的步骤之一。有些人喜欢,但我绝对不是其中之一。我发现这一步非常繁琐,我坚信任何繁琐的事情都可以自动化。虽然我的解决方案没有完全消除手工工作的需要,但它确实大大减少了手工工作并产生了更好的结果。它还产生了一个在结构化数据集上持续击败梯度增强方法的模型。
本文将回答以下问题:
- 到底什么是自动化?
- 它是如何工作的?
- 你如何建造它?
- 它与其他型号相比如何?
特征工程
“正确完成这一步可能需要做几周的 EDA。幸运的是,寻找互动是神经网络擅长的!”
当一个模型被输入一组特征时,它必须学习哪些特征相互作用,以及它们如何相互作用。对于大型数据集,可能有无数的组合需要测试,这些模型往往侧重于能够快速成功的交互。使用特征工程,您可以手动创建或组合特征,以确保模型给予它们适当的关注。
根据数据和问题,有许多不同类型的特征工程方法。大多数分为以下几类:
- 数据清理:有些人认为这是一项功能工程,但这确实是它自己的一步。简而言之,在特性工程成为可能之前,您需要确保数据是可用的。它涉及修复数据中的错误、处理缺失值、处理异常值、一次性编码、扩展特性以及无数其他事情。在我看来,数据清理是唯一比特征工程更糟糕的一步,所以任何找到自动化这一步的人都将是我的新英雄。
- 均值编码:这一步包括将邮政编码等分类特征转换成模型可用的信息。例如,您可以创建一个显示邮政编码的平均销售收入的列。在我之前关于特性嵌入的文章中,我已经在很大程度上删除了这个步骤。
- 滞后变量:向数据中添加时间序列元素通常会有所帮助。通过添加以前期间的值,模型可以计算出事物随时间的变化趋势(例如,上个月的销售额、上个月的销售额等)。这个过程并不太复杂,可以通过简单的循环实现自动化。
- 交互:这一步包括以不同的方式组合特性。例如,您可以通过用广告驱动的客户购买量除以广告被点击的总次数来衡量在线广告的转化率。但是,如果转化率因产品价格的不同而有很大差异,该怎么办呢?现在,您可以根据价格阈值创建单独的列。也很难发现和知道如何处理三阶(或更高阶)互动(例如,价格和类别不同的广告转换)。到目前为止,这是特征工程中最微妙、最耗时的步骤。正确完成这一步可能需要做几周的 EDA。幸运的是,寻找互动是神经网络擅长的!诀窍是确保模型实际上寻找它们,这将是以后的重点。
这个概念
神经网络获取一组输入特征,并在它们之间创建有助于最佳预测输出的交互。如上所述,我们可以通过设计它们来迫使模型考虑某些组合。但是如果我们可以强迫神经网络考虑它们呢?如果我们能够确保神经网络以一种对目标输出产生最佳精度的方式来设计这些特征,会怎么样?关键是训练模型先关注特征。
假设我们有目标输出为 y 的特性 A、B、C 和 D。这个问题的第一步是创建一个模型,预测每个特性。为什么我们关心预测特征?因为我们希望神经网络学习特定于每个特征的交互。
作者提供的要素网络图示例
关于这一步有趣的事情是,我们不关心模型输出。最后一个隐藏层(图中的绿色节点)包含我们新设计的特征,这是我们将要提取的。这些可以馈入我们的最终模型(连同原始特征)来预测我们的目标输出 y。
作者提供的全功能网络图示例
诀窍是确保特征网络训练 和 最终模型,而不是一个单独的过程。Trickier 还在训练一个嵌入层,嵌入到每个特征层中(见我的文章为什么这很重要)。对你来说,好消息是:经过几个月的努力,我终于找到了一个解决方案,并且超出了我的预期。
代码
为了演示这些方法,我们将试图预测一个新冠肺炎患者出现严重反应的概率。可以在这里找到“Cleaned-Data.csv”数据集:https://www . ka ggle . com/iamhungundji/covid 19-symptoms-checker?select=Cleaned-Data.csv
让我们引入数据并创建培训、验证和测试数据集:
import pandas as pd
import tensorflow as tffrom sklearn.model_selection import train_test_split
from tensorflow import feature_column
from tensorflow.keras import layers
from tensorflow.keras.callbacks import ModelCheckpoint
from sklearn.metrics import log_lossX_train = pd.read_csv('covid_data.csv')
y_train = X_train.pop('Severity_Severe').to_frame()
X_train = X_train.iloc[:,:23]X_train, X_val, y_train, y_val = train_test_split(
X_train, y_train,test_size=0.2,random_state=42)X_val, X_test, y_val, y_test = train_test_split(
X_val, y_val,test_size=0.5,random_state=42)
现在,我们将需要定义要为哪些特征创建特征模型。由于我们没有太多的特征,我们不妨全部使用(除了国家将用于嵌入)。当模型包含数百个特性时,最好只显式定义顶部的特性,如下所示:
model_cols = ['Fever','Tiredness','Dry-Cough',
'Difficulty-in-Breathing',
'Sore-Throat','None_Sympton',
'Pains','Nasal-Congestion',
'Runny-Nose','Diarrhea',
'None_Experiencing','Age_0-9',
'Age_10-19','Age_20-24','Age_25-59',
'Age_60_','Gender_Female','Gender_Male',
'Gender_Transgender','Contact_Dont-Know',
'Contact_No','Contact_Yes']
这些特征中的每一个都将是我们整体模型的不同辅助输出,以及我们试图预测的目标特征( Severity_Severe )。在创建张量流数据集时,我们还必须将它们定义为输出要素。请注意,我们通过在末尾添加’_ out ‘【T7]来重命名这些特性,以便 TensorFlow 不会因重复的名称而混淆。注意,我们还为目标输出添加了一个额外的’ _aux_out '列。这样我们就可以围绕目标特征训练一个独立的特征模型,这个模型也将输入到最终的模型中。这是一个被称为跳过连接的过程,它允许模型学习围绕相同特征集的深度和浅层交互。
Y_train_df = X_train[model_cols].copy()
Y_train_df.columns = Y_train_df.columns + "_out"
Y_train_df['Severity_Severe_out'] = y_train['Severity_Severe']
Y_train_df['Severity_Severe_aux_out'] = y_train['Severity_Severe']
trainset = tf.data.Dataset.from_tensor_slices((
dict(X_train),dict(Y_train_df))).batch(256)Y_val_df = X_val[model_cols].copy()
Y_val_df.columns = Y_val_df.columns + "_out"
Y_val_df['Severity_Severe_out'] = y_val['Severity_Severe']
Y_val_df['Severity_Severe_aux_out'] = y_val['Severity_Severe']
valset = tf.data.Dataset.from_tensor_slices((
dict(X_val),dict(Y_val_df))).batch(256)Y_test_df = X_test[model_cols].copy()
Y_test_df.columns = Y_test_df.columns + "_out"
Y_test_df['Severity_Severe_out'] = y_test['Severity_Severe']
Y_val_df['Severity_Severe_aux_out'] = y_val['Severity_Severe']
testset = tf.data.Dataset.from_tensor_slices((
dict(X_test),dict(Y_test_df))).batch(256)
我们要创建的第一个函数是 add_model 。我们将为这个函数提供我们的特征名称,定义层数和大小,表明我们是否想要使用批量标准化,定义模型的名称,并选择输出激活。hidden_layers 变量将为每个层提供一个单独的列表,第一个数字是神经元的数量,第二个是辍学率。此功能的输出将是输出层和最终隐藏层(工程特征),它们将反馈到最终模型。当使用像 hyperopt 这样的工具时,这个函数允许简单的超参数调整。
def add_model(
feature_outputs=None,hidden_layers=[[512,0],[64,0]],
batch_norm=False,model_name=None,activation='sigmoid'):
if batch_norm == True:
layer = layers.BatchNormalization()(feature_outputs)
else:
layer = feature_outputs
for i in range(len(hidden_layers)):
layer = layers.Dense(hidden_layers[i][0], activation='relu',
name=model_name+'_L'+str(i))(layer)
last_layer = layer
if batch_norm == True:
layer = layers.BatchNormalization()(layer)
if hidden_layers[i][1] > 0:
layer = layers.Dropout(hidden_layers[i][1])(layer)
output_layer = layers.Dense(1, activation=activation,
name=model_name+'_out')(layer)
return last_layer, output_layer
下一个功能是创建一个嵌入层。这将很有帮助,因为国家是一个稀疏分类特征。该函数将获取我们将转换为嵌入的特征的字典,以及此处定义的该特征的唯一可能值的列表:
emb_layers = {'Country':list(X_train['Country'].unique())}
我们还提供模型输入,这将在后面定义。对于尺寸参数,我选择遵循默认的经验法则,即使用唯一特征长度的 4 次方根。
def add_emb(emb_layers={},model_inputs={}):
emb_inputs = {}
emb_features = []
for key,value in emb_layers.items():
emb_inputs[key] = model_inputs[key]
catg_col = feature_column
.categorical_column_with_vocabulary_list(key, value)
emb_col = feature_column.embedding_column(
catg_col,dimension=int(len(value)**0.25))
emb_features.append(emb_col)
emb_layer = layers.DenseFeatures(emb_features)
emb_outputs = emb_layer(emb_inputs)
return emb_outputs
在我们进入下一个功能之前,我们需要定义需要从不同的特征模型中排除哪些特征。在基本层面上,我们想要排除被预测的特征(数据泄漏),以及用于嵌入的特征。还应小心移除可直接用于计算输出要素的要素。例如,一个模型将很快发现,对于像 Gender_Female 这样的特征,只需查看其他性别列的值并忽略所有其他特征,它就可以获得 100%的准确性。这不是一个非常有用的模型!为了解决这个问题,我们将从相应的特征模型中排除其他性别、年龄和接触特征。
feature_layers = {col:[col,'Country'] for col in model_cols}feature_layers['Gender_Female'] += ['Gender_Male',
'Gender_Transgender']
feature_layers['Gender_Male'] += ['Gender_Female',
'Gender_Transgender']
feature_layers['Gender_Transgender'] += ['Gender_Female',
'Gender_Male']feature_layers['Age_0-9'] += ['Age_10-19','Age_20-24',
'Age_25-59','Age_60_']
feature_layers['Age_10-19'] += ['Age_0-9','Age_20-24',
'Age_25-59','Age_60_']
feature_layers['Age_20-24'] += ['Age_0-9','Age_10-19',
'Age_25-59','Age_60_']
feature_layers['Age_25-59'] += ['Age_0-9','Age_10-19',
'Age_20-24','Age_60_']
feature_layers['Age_60_'] += ['Age_0-9','Age_10-19',
'Age_20-24','Age_25-59']feature_layers['Contact_Dont-Know'] += ['Contact_No','Contact_Yes']
feature_layers['Contact_No'] += ['Contact_Dont-Know','Contact_Yes']
feature_layers['Contact_Yes'] += ['Contact_Dont-Know','Contact_No']
我们还打算为我们的辅助跳过连接模型添加一个特征层:
feature_layers['Severity_Severe_aux'] = ['Country']
现在我们有了构建特征模型所需的东西。该函数将使用所有输入特征的列表、上述定义的特征排除和嵌入字典、在 add_model 函数中描述的 hidden_layer 结构以及是否应使用批量标准化的指示器。
首先,该函数将以 TensorFlow 喜欢的方式定义输入要素。使用 TensorFlow 输入的一个主要优点是,我们只需要定义一次特征,它们可以在每个特征模型中反复使用。接下来,我们将确定是否定义了任何嵌入列,并创建一个嵌入层(可选)。对于每个特征模型,我们将创建 DenseFeatures 输入层(不包括上面定义的特征),并使用 add_model 函数创建一个单独的模型。就在返回之前,我们检查循环是否在跳过连接模型上运行。如果是这样,我们添加输入特征,以便最终模型也可以使用原始特征进行训练。最后,该函数将返回模型输入的字典、每个特征模型输出层的列表以及每个最终隐藏层的列表(即新工程特征)。
def feature_models(
output_feature=None,all_features=[],feature_layers={},
emb_layers={},hidden_layers=[],batch_norm=False):
model_inputs = {}
for feature in all_features:
if feature in [k for k,v in emb_layers.items()]:
model_inputs[feature] = tf.keras.Input(shape=(1,),
name=feature,
dtype='string')
else:
model_inputs[feature] = tf.keras.Input(shape=(1,),
name=feature)
if len(emb_layers) > 0:
emb_outputs = add_emb(emb_layers,model_inputs)
output_layers = []
eng_layers = []
for key,value in feature_layers.items():
feature_columns = [feature_column.numeric_column(f)
for f in all_features if f not in value]
feature_layer = layers.DenseFeatures(feature_columns)
feature_outputs = feature_layer({k:v for k,v in
model_inputs.items()
if k not in value})
if len(emb_layers) > 0:
feature_outputs = layers.concatenate([feature_outputs,
emb_outputs])
last_layer, output_layer = add_model(
feature_outputs=feature_outputs,
hidden_layers=hidden_layers,
batch_norm=batch_norm,
model_name=key)
output_layers.append(output_layer)
eng_layers.append(last_layer)
if key == output_feature + '_aux':
eng_layers.append(feature_outputs)
return model_inputs, output_layers, eng_layers
请注意,如果使用嵌入层,它将与这些模型的每个输入连接在一起。这意味着这些嵌入不仅将训练以最大化整体模型准确性,而且还将训练这些特征模型中的每一个。这导致了非常健壮的嵌入,并且是对我的前一篇文章中描述的过程的重大升级。
在我们进入最后一个函数之前,让我们定义我们将要输入的每个参数。其中大部分已经在上面描述过,或者对所有张量流模型是典型的。如果您不熟悉耐心参数,它用于在指定的时期数内验证精度没有提高时停止训练模型。
params = {'all_features': list(X_train.columns),
'output_feature':y_train.columns[0],
'emb_layers':emb_layers,
'feature_layers':feature_layers,
'hidden_layers':[[256,0],[128,0.1],[64,0.2]],
'batch_norm': True,
'learning_rate':0.001,
'patience':3,
'epochs':20
}
对于最终模型,我们将通过运行前面的函数来生成输入、输出和工程特征。然后,我们连接这些层/特征中的每一个,并将它们输入到最终模型中。最后,我们构建、编译、训练和测试模型。
def final_model(params,test=True):
print(params['batch_norm'],params['hidden_layers'])
model_inputs, output_layers, eng_layers = feature_models(
all_features=params['all_features'],
feature_layers=params['feature_layers'],
emb_layers=params['emb_layers'],
hidden_layers=params['hidden_layers'],
batch_norm=params['batch_norm'],
output_feature=params['output_feature'])
concat_layer = layers.concatenate(eng_layers)
last_layer, output_layer = add_model(
feature_outputs=concat_layer,
hidden_layers=params['hidden_layers'],
batch_norm=params['batch_norm'],
model_name=params['output_feature'])
output_layers.append(output_layer)
model = tf.keras.Model(
inputs=[model_inputs],
outputs=output_layers)
aux_loss_wgt = 0.5 / len(params['feature_layers'])
loss_wgts = [aux_loss_wgt for i in
range(len(params['feature_layers']))
loss_wgts.append(0.5)
model.compile(loss='binary_crossentropy',
optimizer=tf.keras.optimizers.Adam(
lr=params["learning_rate"]),
loss_weights=loss_wgts,
metrics=['accuracy'])
es = tf.keras.callbacks.EarlyStopping(
monitor='val_loss',mode='min',verbose=1,
patience=params['patience'],restore_best_weights=True)
history = model.fit(
trainset,validation_data=valset,
epochs=params['epochs'], verbose=0, callbacks=[es])
yhat = model.predict(testset)
loss = log_loss(
np.array(y_test[params['output_feature']]),
yhat[-1])**.5
print('Binary Crossentropy:',loss)
if test==True:
sys.stdout.flush()
return {'loss': loss, 'status': STATUS_OK}
else:
return history, model
注意,这个函数的输入之一叫做测试。该输入允许您在使用 hyperopt 求解最佳参数( test=True )或训练并返回您的最终模型( test=False )之间切换。在编译模型时,您可能还不熟悉 loss_weights 参数。因为我们有几个辅助输出,所以我们需要告诉 TensorFlow 在确定如何调整模型以提高准确性时给每个输出多少权重。我个人喜欢给辅助预测(总预测)50%的权重,给目标预测 50%的权重。有些人可能会觉得赋予辅助预测任何权重很奇怪,因为它们在损失计算步骤中被丢弃。问题是,如果我们不给它们任何权重,模型通常会忽略它们,阻止它学习有用的特征。
现在我们只需要使用上面定义的参数运行 final_model :
history, model = final_model(params,test=False)
现在我们已经有了一个训练好的模型,我们可以使用 keras get_layer() 函数有选择地提取新的特征用于其他模型。如果这能引起足够的兴趣,我将把这一步留到以后的文章中。
结果呢
“它一贯击败 XGBoost **,**与传统智慧相反,梯度增强模型对于结构化数据集来说更优越。”
可以想象,这是一个计算量很大的训练模型。好消息是,与典型的 MLP 相比,它通常会在更少的试验中收敛到更准确的答案。如果你把省下的时间包括在内,那就更快了。此外,预测延迟足够小,足以使其成为生产模型(与典型的 Kaggle 50+元模型相反)。如果你提取特征并用它们重新训练神经网络,那么它会变得更快。
问题依然存在,**准确吗?在我应用这个模型的每一个案例中,它都是最准确的。**它持续击败 XGBoost,与梯度增强模型对于结构化数据集更优越的传统智慧相反。让我们看看它是如何解决这个问题的!
方法和准确性
我测试了三种不同的模型:
- XGBoost
- 嵌入的标准 MLP
- 上面训练的自动特征模型
对于自动特征模型,我使用 hyperopt 运行了 20 次试验,对不同的网络规模进行实验。对于这两个竞争模型,我进行了 40 次试验,因为它们的训练时间更快。结果如下:
各型号的准确度得分
正如所料,我们的自动特征模型表现最好。要记住的一点是,这个简单的数据集没有足够的有用信息来允许任何比边际收益更好的模型。当我处理利用数百个特征的大规模数据集时,自动特征模型比 XGBoost 高出 5–10%的情况并不少见。
当最高精度非常重要时,这已经成为我的首选生产模式。它在我的职业生涯中为我带来了很多成功,现在我希望它也能为你带来同样的成功。
关于我
我是一名拥有 10 多年经验的数据科学自由职业者。我一直希望与人交流,所以请随意:
如有任何疑问,欢迎在下方评论
用几行 Python 代码实现 EDA、建模和超参数调整的自动化交互式软件包
PyWedge —加快数据科学建模工作流程的交互式包
数据科学家将大部分时间花在执行探索性数据分析(EDA)上。数据科学建模管道有各种组件,包括 EDA、数据处理、超参数调整、基线建模和模型部署。
有各种开源 Python 库可以加速管道上的一些组件。阅读这篇文章到 4 个这样的可以自动化 EDA 组件的库。当涉及到从 EDA、数据处理、基线建模和超参数调整模型开始的整个建模流程的自动化时,需要花费数据科学家大量的时间和精力。
在这里,PyWedge 开始发挥作用,它可以自动化整个建模工作流,包括 EDA、数据处理、基线建模和超参数调整。在本文中,我们将讨论 PyWedge 的实现和使用。
PyWedge 是什么?
PyWedge 是一个开源 Python 库,可以自动化数据科学建模管道的几个组件。它可以被视为交互式 EDA、数据处理、基线建模和超参数调整的完整套件。
PyWedge 提供了几个特性,包括:
- 创建可视化的交互图,包括散点图、条形图、小提琴图、相关图等。
- 使用开发人员选择的输入处理技术进行数据处理。
- 训练数十种机器学习算法的各种基线模型训练,并返回每个模型的性能指标。
- 交互式执行超参数调整小部件样式选项卡。
安装:
PyWedge 可以从 PyPl 安装,使用:
**!pip install pywedge**
它可以通过以下方式导入 Python:
**import pywedge as pw**
用法:
本文使用的数据集是 Titanic dataset,从 Kaggle 下载。这是一个二进制分类数据,目标类是“幸存”。
首先,开发人员需要使用 Pandas 导入数据集:
**import pandas as pd
df = pd.read_csv("titanic.csv")**
探索性数据分析:
模型构建管道的第一个组件是 EDA。PyWedge 可以用一行 Python 代码执行 EDA。它生成 8 种类型的交互图,包括散点图、饼图、小提琴图、条形图、箱线图、分布图、直方图和相关图。
**mc = pw.Pywedge_Charts(df, c=None, y="Survived")
chart = mc.make_charts()**
(图片由作者提供),使用 PyWedge 绘制图表的交互式选项卡
基线建模:
PyWedge 可以使用函数**baseline_model**
对各种分类和回归机器学习算法进行基线建模。建模从数据预处理开始,它依赖于开发人员使用各种数据处理技术。
输入参数:
- 分类列编码技术:熊猫猫代码,或得到假人。
- 色谱柱标准化:标准定标器、鲁棒定标器、最小-最大定标器。
- 选择是否使用 SMOTE 来平衡等级。
- 列车测试数据分割
(图片由作者提供),使用 PyWedge 训练基线模型的交互式选项卡
**baseline_model**
函数训练训练数据,并使用若干机器学习算法使用测试数据预测性能,并返回模型摘要报告,该报告提供前 10 个重要特征及其重要性分数。
(图片由作者提供),模型总结
超参数调谐:
Pywedge_HP 有两个函数**HP_Tune_Classification**
、**HP_Tune_Regression**
来执行超参数调谐。
**pph = pw.Pywedge_HP(train, test, c=None, y='Survived')
pph.HP_Tune_Classification()**
(图片由作者提供),使用 PyWedge 调整基线模型的超参数交互式选项卡
结论:
在本文中,我们讨论了 PyWedge 库的实现和使用,它可以自动化 EDA、数据处理、建模、超参数调整,从而扩展数据科学家的工作流程。建议使用自定义 python 包执行 EDA,以便更好地理解数据。然而,基线建模和超参数调整可以使用 PyWedge 来完成,因为它加快了方法的速度。
阅读下面的文章,了解 4 个可以在一行代码中执行 EDA 的库。
</4-libraries-that-can-perform-eda-in-one-line-of-python-code-b13938a06ae>
参考资料:
[1] PyWedge 文档:https://pypi.org/project/pywedge/
感谢您的阅读
使用 Plotly 和 Python 自动生成交互式报告
使用 Python 中的 Plotly 轻松生成交互式报告
Plotly 中的交互式加密货币报告(Gif 由作者提供)
生成报告是一项单调乏味的任务。相反,使用 Plotly 在 Python 中开发并创建自动化的交互式报告。
本文将讨论为不同的加密货币创建自动化交互报告所需的步骤。然后,最终报告被合并成一个单独的 HTML 文件,该文件在没有外部服务器的情况下保持 Plotly 的交互功能。
生成报告的完整代码在本文中。请随意收藏这篇文章以备将来使用。
生成报告的方法遵循 ETL 过程。
- 首先是,数据被提取出来,在这种情况下,不同加密货币的价格
- 接下来,信息被转换,生成有用的指标和互动的图形
- 最后一个,数据被加载到一个包含所有报告的 HTML 文件中。
提取数据和财务分析
该报告使用了几种不同加密货币的价格数据。数据是使用免费的 Alpha Vantage API for python 提取的。
使用这个 API,您可以提取不同的股票、货币和加密价格。
用 Alpha Vantage 提取财务数据(作者代码)
烛台图表
蜡烛图是市场数据的标准可视化工具。这些图显示了股票的开盘价、收盘价、最低价和最高价。
由于市场中的价格不断变化,这些值代表了一天中每分钟的交易模式。
布林线
理解股票的波动性是理解风险的关键。布林线代表市场的波动。
使用移动平均线和滚动标准差计算波段。上带是用移动平均线加两个标准差确定的,下带是负两个标准差。
当市场波动越大,波段之间的差距越大。当波动性较小时,差距缩小。这些波段也有助于理解股票的价格范围。
相对强度指数
RSI 是一个动量指标。该值的范围在 0 到 100 之间。因此,该指数表明股票是超买还是超卖。
指数移动平均线的相对强度指数(作者提供图片)
惯例是 RSI 在 70 以上时超买,30 以下超卖。
RSI 也可以揭示市场趋势。比如 RSI 在 50 以上时,有上升趋势,RSI 在 50 以下时有下降趋势。
计算熊猫的 RSI(作者代码)
编写报告
我结合了 Plotly 的几种绘图类型,展示了开发报告的一些可用功能。这些图是使用 python 创建的。然而,从许多其他编程语言,包括 R 或 Julia,都有扩展。
这些报告旨在显示信息、一些指标和市场数据变化的高级表格摘要。
数据表
尽管图表能够有效地表现数据的行为,但仍然需要汇总。数据表非常适合于具体的数据快照。
在 Plotly 中,数据表是一个内置函数,可以与其他绘图无缝集成。Plotly 中的交互功能有限,但默认情况下,您可以重新排列数据表中的列。
汇总财务数据(按作者编码)
填充区域系列
构建布林线时,混乱的图表成为一个问题。数字太多会对图表的整体信息不利。
这里我使用了 Plotly 的填充区域功能。虽然每个时间序列都有一个填充选项,但要正确设置并不容易。
标准填充选项“至零”和“至下一层”会导致不规则的行为。所以取而代之的是使用单个散点图,它的长度是整个图表的两倍。
实际上,高频带和低频带作为列表附加在一起,形成两倍长的序列。接下来,使用填充选项“toself”。以这种方式设置系列可确保 Plotly 正确地仅填充带之间的空间。
恒纹
RSI 是衡量市场趋势的常用指标。当这个指标超过一个阈值时,你就可以判断股票是超买还是超卖。
因此,在图表上用一条明显的线来表示这些阈值是有帮助的。这一细节是通过附加散点图和改变标记类型来实现的,以表明这些线不是主要系列。
合并成一份报告
需要合并这些图表,以便将每个图合并成一个完整的报告。在 Plotly 中,函数“make_subplots”就是为这个目的而设计的。
此外,在组合图时,您可以指定在所有报告之间共享 x 轴。该属性非常适合时间序列图,因为当您与图形交互时,每个序列都会对齐。
创建 HTML 报告
设计完完整的报告后,可以将其保存为 HTML 文件。虽然这不如 PDF 常见(尽管保存为 PDF 仍然是可能的),但 HTML 文件包括 Plotly 的交互性,而不需要外部托管。
每个图形都可以单独保存为 HTML 文件。然后,像 python 中的任何其他文件一样,您可以重复地添加到 HTML 文件中,从而创建更广泛的报告。
您还可以向文件中添加任何想要的 HTML 元素,并进一步更新 Plotly 图表元素。对于那些精通 web 开发的人来说,这提供了更大的灵活性。
综合所有
整个过程被组合成一个基本的 ETL 过程。考虑为那些需要定期报告的用户设置一个事件触发器,以便使用脚本定期运行报告。
但是,报告生成过程如下:
- 使用 API 提取数据(这里是 Alpha Vantage)
- 将数据转换成汇总表、财务指标和图表。
- 将数据加载到一个 HTML 文件中,发送给相关的利益相关者。
该报告还利用了 Plotly-Dark 模板。
自动化财务报告(作者代码)
单一报告示例(按作者分类)
结论
生成报告是一项相当简单的任务。然而,尽管提供了大量的信息,当信息不被理解时,报告就失去了价值。
在本文中,我展示了如何使用 Plotly 和 python 创建不同加密货币的财务报告。该过程遵循基本的 ETL 方法,并且可以完全自动化。
在您的报告中添加动态交互可以使审阅信息对您的受众更有吸引力。使用 Plotly,您可以生成人们想要监控、阅读和探索数据的报告。
如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 medium 上关注我。
如果你对我的写作感兴趣,并想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。
https://zjwarnes.medium.com/membership
自动化机器学习模型测试
使用 LazyPredict 只用几行代码就尝试了 20 多个机器学习模型
作者图片
我们都遇到过这种情况,我们不知道哪种模型最适合我们的 ML 项目,最有可能的是,我们正在尝试和评估许多 ML 模型,只是为了看看它们在我们的数据中的行为。然而,这不是一项简单的任务,需要时间和努力。
幸运的是,我们可以使用 LazyPredict 只用几行代码就能做到这一点。它将运行 20 多个不同的 ML 模型,并返回它们的性能统计数据。
装置
pip install lazypredict
例子
让我们看一个使用来自 Kaggle 的泰坦尼克号数据集的例子。
import pandas as pd
import numpy as np
from lazypredict.Supervised import LazyClassifier, LazyRegressor
from sklearn.model_selection import train_test_split
data=pd.read_csv(‘train.csv’)
data.head()
在这里,我们将尝试预测是否有乘客在泰坦尼克号上幸存,因此我们有一个分类问题。
Lazypredict 还可以进行基本的数据预处理,如填充 NA 值、创建虚拟变量等。这意味着我们可以在读取数据后立即测试模型,而不会出现任何错误。然而,我们可以使用我们的预处理数据,这样模型测试将更加准确,因为它将更接近我们的最终模型。
对于这个例子,我们不做任何预处理,让 Lazypredict 做所有的工作。
#we are selecting the following columns as features for our models
X=data[['Pclass', 'Sex', 'Age', 'SibSp',
'Parch', 'Fare', 'Embarked']]
y=data['Survived']X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2,random_state=7)# Fit LazyRegressorreg = LazyClassifier(ignore_warnings=True, random_state=7, verbose=False)#we have to pass the train and test dataset so it can evaluate the modelsmodels, predictions = reg.fit(X_train, X_test, y_train, y_test)
models
作者图片
如您所见,它将返回一个包含模型及其统计数据的数据框。我们可以看到基于树的模型比其他模型表现得更好。知道了这一点,我们可以在我们的方法中使用基于树的模型。
您可以从 Lazypredict 获得完整的管道和使用的模型参数,如下所示。
#we will get the pipeline of LGBMClassifier
reg.models['LGBMClassifier'] Pipeline(steps=[('preprocessor',
ColumnTransformer(transformers=[('numeric',
Pipeline(steps=[('imputer',
SimpleImputer()),
('scaler',
StandardScaler())]),
Index(['Pclass', 'Age', 'SibSp', 'Parch', 'Fare'], dtype='object')),
('categorical_low',
Pipeline(steps=[('imputer',
SimpleImputer(fill_value='missing',
strategy='constant')),
('encoding',
OneHotEncoder(handle_unknown='ignore',
sparse=False))]),
Index(['Sex', 'Embarked'], dtype='object')),
('categorical_high',
Pipeline(steps=[('imputer',
SimpleImputer(fill_value='missing',
strategy='constant')),
('encoding',
OrdinalEncoder())]),
Index([], dtype='object'))])),
('classifier', LGBMClassifier(random_state=7))])
此外,您可以使用完整的模型管道进行预测。
reg.models['LGBMClassifier'].predict(X_test)
array([0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
0, 0, 1], dtype=int64)
和 LazyClassifier 一样,我们可以使用 LazyRegressor 来测试回归问题的模型。
总结一下
Lazypredict 可以帮助我们对哪种模型在我们的数据中表现更好有一个基本的了解。它几乎不需要任何数据预处理就可以运行,因此我们可以在读取数据后立即测试模型。
值得注意的是,有更多的方法来进行自动化机器学习模型测试,如使用 auto-sklearn 但安装它非常复杂,尤其是在 windows 中。
使用 PyCaret 的自动机器学习
用不到十行代码自动化您的机器学习工作流程
亨特·哈里特在 Unsplash 上的照片
介绍
您是否希望为您的企业实施机器学习,但没有太多时间来构建它?PyCaret 可以帮助你!
PyCaret 是一个用于 Python 的开源机器学习库,可以减少您准备数据集来测试模型的时间。PyCaret 很容易使用,所以您不必花时间编写代码,直到过程结束。
更有趣的是,不到十行代码就可以拥有最好的机器学习模型!多酷啊。!
本文将向您介绍如何使用 PyCaret,从准备数据到部署模型。没有进一步,让我们开始吧!
实施
数据源
在这种情况下,我们将使用一个名为丙型肝炎预测数据集的数据集。这个数据集是 fedesoriano 在 Kaggle 上创建的。它由几个变量组成,从年龄和性别等人口统计学变量到类似生物标记的变量。您可以在这里 访问数据集 。
作者捕捉到的。
以下是加载数据集的代码,以及从中进行的预览:
从上面可以看到,有一个名为“未命名:0”的列。我们需要从数据集中丢弃该列,因为它是每一行的标识符。为了删除该列,我们运行如下代码:
准备数据
加载数据后,下一步是准备数据。使用 PyCaret,准备数据很简单。我们可以使用 pycaret.classification 库中的一个名为 setup 的函数。下面是实现这一点的代码:
以下是我们运行代码时的流程预览:
从上图可以看出,这说明 setup 函数只用一个函数就完成了所有的预处理步骤。我们可以填充缺失的值,转换数据集,删除异常值,等等。
如果我们想设置自定义预处理步骤,我们可以在设置功能上设置参数。对于这种情况,让我们填充数据集上缺失的值。我们可以给出一个称为 numeric _ attraction 的参数,用于填充数字列上的缺失值。我们将用该列的中值来填充缺失值。
下面是实现这一点的代码:
在我们设置参数之前,数值插补行看起来是这样的:
下面是我们设置数值插补行后的样子:
现在,我们已经将数值估算器设置为中值。除了数值插补参数,您还可以在设置功能中给出其他参数。更多详情,可以在这里 阅读 PyCaret 的文档 。
比较模型
PyCaret 库的一个主要特性是,你可以同时运行任何机器学习模型,从逻辑回归、决策树、XGBoost 等等!
要运行模型比较,我们可以使用 pycaret.classification 库中的 compare_model 函数。下面是代码及其结果:
从结果中,我们可以看到该模型及其度量性能。如上所述,梯度推进分类器模型在几乎所有指标上都有很好的性能。
仅在精度指标上,该模型并没有获得很好的性能。线性判别分析模型取得了较好的精度结果。
想象一下,只要一个函数,你就可以同时得到所有的模型结果!多酷啊。
因此,我们将在下一步使用梯度提升分类器。
再现最佳模式
现在让我们再现最佳模型,其中我们将使用梯度推进分类器作为模型。下面是代码及其结果:
超参数调谐
虽然该模型得到了最好的结果,但我们可以通过超参数调整来改进它。超参数调整是一个从所有超参数组合中挑选最佳超参数的过程。简单来说,超参数是一个我们可以在数据集上训练模型之前在模型上设置的参数。
在 PyCaret 中,我们可以使用 tune_model 函数来调整模型的超参数。代码及其结果如下所示:
模型评估
在我们得到最佳超参数组合的模型后,我们再通过看几个图表来评价模型。
在 PyCaret 中,我们可以通过使用一个函数来可视化许多图表。例如,让我们使用 plot_model 函数绘制 ROC 曲线,如下所示:
为了可视化混淆矩阵,您可以使用如下相同的函数:
在 PyCaret 中,我们还可以可视化我们的模型对数据的决策边界。代码如下所示:
除此之外,该函数还可以从数据中可视化特征的重要性。所以我们知道模型如何预测数据,哪些变量决定最终结果。下面是实现这一点的代码:
模型检验
现在我们知道我们的模型已经达到了很好的效果。现在让我们在看不见的数据上测试这个模型。我们可以使用名为 predict_model 的函数进行预测,并显示每个指标的性能。下面是代码及其结果:
从上面的结果可以看出,该模型的性能比我们在超参数调整阶段的性能要低。但是记住,这个数据之前没有训练过,所以结果是好的。现在让我们保存最终的模型。
保存模型
在保存模型之前,我们需要重新训练模型。在 PyCaret 中,我们可以使用 finalize_model 函数来做到这一点。训练过程将采用完整的数据集,包括测试数据。因此,我们可以在以后的实际测试数据上使用该模型。下面是实现这一点的代码:
现在让我们保存模型。在 PyCaret 中,我们可以使用 save_model 函数来做到这一点。下面是实现这一点的代码:
如果您想在另一个项目中加载模型,您可以像这样使用 load_model 函数:
结束语
干得好!现在你已经学会了如何使用 PyCaret 来自动化你的机器学习管道。希望能帮助你缩短开发机器学习模型的过程。通过这样做,你可以更专注于问题,而不是解决技术问题。
如果你对我的文章感兴趣,你可以关注我的媒体以获得更多类似的文章。如果你有任何问题或者想打个招呼,你可以在 LinkedIn 上联系我。
谢谢你看我的文章!
H2O 的自动机器学习
加速您的机器学习开发周期
什么是自动 ML?
自动机器学习(AutoML)是机器学习管道中自动化任务的过程,例如数据预处理、超参数调整、模型选择和评估。在本文中,我们将探讨如何利用 H2O 的开源自动化机器学习包来加速数据科学家的模型开发过程。
设置
pip install h2o
让我们导入必要的包
import h2o
from h2o.automl import H2OAutoML
初始化 H2O 集群。
h2o.init()
数据准备
我们将使用来自 UCI 的数据集,该数据集描述了一家银行向客户提供定期存款的营销活动。如果客户同意,目标变量为yes
,如果客户决定不进行定期存款,目标变量为no
。
将数据集作为H2OFrame
加载
df = h2o.import_file(path='/kaggle/input/bank-marketing-campaigns-dataset/bank-additional-full.csv')
描述数据集。H2O 提供了 10 行样本数据以及数字列的基本汇总统计数据。
df.describe(chunk_summary=True)
将数据集分为训练集和测试集
train, test = df.split_frame(ratios=[0.8], seed = 1)
火车汽车模型
让我们配置 AutoML 训练参数。
max_models
:训练模型的最大数量balance_classes
:设置为True
,平衡数据不平衡任务的分类标签seed
:设定再现性
aml = H2OAutoML(max_models =25,
balance_classes=True,
seed =1)
我们可以通过限制以下各项来限制搜索最佳模型所花费的时间:
- 使用
max_models
的最大型号数量 - 使用
max_runtime_secs
花费的总时间 - 使用
max_runtime_secs_per_model
训练任何单一模型所花费的时间。
通过指定以下内容开始培训:
training_frame
:包含训练数据的数据帧y
:包含目标变量的training_frame
中的列
aml.train(training_frame = train, y = 'y')
此外,我们还可以指定validation_frame
,这是一个 H2OFrame,模型在训练过程中根据它进行评估。如果未设置此参数,将使用 k 重交叉验证来评估模型。其他可选参数参考文件。
那么引擎盖下发生了什么呢?
H2O 汽车公司按以下顺序训练和交叉验证以下模型:
- 三个预先指定的 XGBoost GBM(梯度增压机)型号
- GLMs 的固定网格
- 默认随机森林(DRF)
- 五个预先指定的 H2O GBM
- 一种近似默认的深度神经网络
- 极度随机的森林(XRT)
- XGBoost GBMs 的随机网格
- H2O GBM 的随机网格
- 深度神经网络的随机网格
此外,它还培训:
- 上面训练的所有模型的堆叠集合
- 包含每个算法类的最佳执行模型的“最佳系列”堆叠集成
估价
训练完模型后,我们可以使用排行榜来比较模型性能。H2O 汽车公司制作了一个排行榜,根据预定义的指标对训练好的模型进行排名。默认情况下,它按照 logloss 和 rmse 的升序对模型进行排序,分别用于分类和回归任务。
lb = aml.leaderboard
lb.head(rows=lb.nrows)
排行榜指标是根据交叉验证集计算的,除非在培训期间指定了leaderboard_frame
。
aml.train(training_frame = train,
y = 'y',
leaderboard_frame = my_leaderboard_frame)
在分类任务的典型机器学习评估中,我们将有兴趣了解最佳性能模型的性能,如 ROC AUC、精确度、召回率、F1、精确度、增益/提升和交叉验证数据集上的混淆度量。H2O 只用两行代码就提供了所有这些指标。
让我们得到性能最好的模型,并检查其结果。
best_model = aml.get_best_model()
print(best_model)
交叉验证数据中报告的通用指标
混淆矩阵和度量在各自的最大阈值
增益/提升图表
我们还可以使用上面显示的相同评估指标来评估维持测试集上的最佳模型。
best_model.model_performance(test)
保存、加载和预测
让我们保存一个二进制模型
model_path = h2o.save_model(model=best_model,path='/kaggle/working/model', force=True)print(model_path)>> /kaggle/working/model/StackedEnsemble_AllModels_AutoML_20210803_232409
保存的二进制模型可以加载到不同的笔记本中,并用于在测试集上进行预测。注意,用于训练保存的二进制模型的 H2O 版本必须与我们的推理环境中使用的版本相同。
import h2o #must be same version used during training of the modelh2o.init()loaded_model = h2o.load_model(path='/kaggle/working/model/StackedEnsemble_AllModels_AutoML_20210803_232409')
loaded_model.predict(test)
可解释性
H2O AutoML 还提供了模型的全局可解释性的见解,如变量重要性,部分依赖图,SHAP 值和模型相关性,只有一行代码
explain_model = aml.explain(frame = test, figsize = (8,6))
此外,它还为单个记录提供了本地可解释性。我们可以在frame
参数中输入一个H2OFrame
,并指出我们希望使用row_index
参数来解释哪一行。在这种情况下,我们解释测试帧的第 15 行的结果。
aml.explain_row(frame = test, row_index = 15, figsize = (8,6))
结论
在本文中,我们研究了如何使用 H2O 汽车公司:
- 描述数据集
- 用最少的人工输入训练模型
- 根据训练好的模型进行预测
- 解释模型的预测
您可以在此处找到用于训练和推理的笔记本:
使用 Sklearn 管道的自动机器学习
一条管道来统治他们。
P ipelines 提供了自动化训练和测试模型的结构。它们可以包含列转换、缩放、插补、特征选择和超参数搜索。
通过将所有这些步骤组合成管道,可以抽象出单独的步骤。
这篇文章展示了如何创建一个包含 Sklearn 中每个函数的管道。
*请随意将此页面加入书签以供将来使用 *
使用这个管道,定义您的数据,根据需要更新超参数,然后点击 run。
将这些步骤中的每一步抽象成一个管道,使得构建有效模型的整个过程更具可伸缩性。
此外,根据构建和测试管道的方式,您可以快速迭代许多不同的估计器、特征选择方法和其他可能提高模型整体性能的方法。
当开始一个数据科学项目时,需要管理许多不同的任务。例如,如果不进行大量测试,就不可能知道哪种模型最适合您的问题。
一种常见的方法是从一个简单的模型开始,以提供一个基线性能。我在这篇文章中讨论了应该首先使用什么模型,以及为什么更简单的模型更好:
设置
在这篇文章中,我使用了乳腺癌数据集。但是,管道还将展示列转换功能。因此,数据集用一个用于转换的虚拟分类变量来扩展。
这种改变是通过添加一个随机分类列来完成的。
import pandas as pd
from scipy.stats import uniform, geom, loguniform, randint, expon
from sklearn import ensemble, neighbors, tree, linear_model, svm, naive_bayes, gaussian_process, feature_selection, preprocessing, impute, metrics, decomposition, compose
from sklearn.model_selection import train_test_split, RandomizedSearchCV
from sklearn.metrics import roc_auc_score
from sklearn.pipeline import make_pipeline, Pipeline as Pipeline
from sklearn.datasets import load_breast_cancer
import itertools
import random
import pickleTEST_SIZE = 0.1
RANDOM_STATE = 10
data = load_breast_cancer()
df = pd.DataFrame(data.data, columns=data.feature_names)
df['target'] = data.target
X = df.drop(['target'], axis=1)
X['categorical'] = random.choices(['one', 'two', 'three'], k=len(X))
y = df['target'].astype(float)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=TEST_SIZE, random_state=RANDOM_STATE, stratify=y)
本文中生成的管道是为二进制分类问题而创建的。然而,管道也支持回归问题。
为了针对回归问题调整管道,更新输入的数据、测试中使用的模型和评分标准。然后,管道的其余部分可以保持不变。
带有随机分类变量的乳腺癌数据集(图片由作者提供)
管道设置
本节旨在从头到尾建立一个完整的管道,涵盖 sklearn 必须为监督学习提供的每种类型的功能。
不幸的是,sklearn 中的一些函数本质上有无限的可能性。例如,以一个简单的逻辑回归函数为例。理论上,正则化参数是一个连续变量,它使得可能的流水线的数量是无限的。
因为 sklearn 函数本质上有无限的排列,最终的管道将展示监督学习管道中每种类型的至少一个函数。
此外,由于最终管道将测试多个模型、特征选择技术、插补方法、缩放器和变换,因此管道的设置与其他示例所示略有不同。
然而,这种设置被设计成易于遵循和根据需要改变组件。
元参数
N_ITER = 1
N_JOBS = 1
K_FOLDS = 10
VERBOSE = 0
SCORING_METRIC = 'roc_auc'
SCORING_FUNCTION = metrics.roc_auc_score
MAX_ITER = 10000
LOGISTIC_REGRESSION_SOLVER = 'sag'
OPTIMAL_MODEL_FILENAME = 'optimal_model.pickle'
categorical_feature_names = ['categorical']
best_score = 0
与超参数相比,元参数控制如何设置问题、如何执行计算以及如何跟踪结果。
这里我提供几个选项。
- 要改变超参数优化中执行的迭代次数,调整 N_ITER 。
- 为了改变具有额外计算能力的模型的作业数量,调整 N_JOBS 。
- 要调整验证的折叠数,请调整 K_FOLDS 。
- SCORING_METRIC 是被监督问题的评估指标
- 计分函数是计分指标的函数。由于管道设置,函数和名称都是必需的。
- 最大 ITER 和逻辑回归求解器支持逻辑回归和支持向量机模型的收敛。其他解算器和这些模型的收敛性存在一些问题。这些参数缓解了这些问题。
- OPTIMAL_MODEL_FILENAME ,存储所有模型类型的最优模型的名称。基于评分标准的最佳分数
- 分类特征名称,转换为二元变量的分类特征列表。
- best_score ,一个跟踪流水线优化的最佳分数的变量。
型号
例如,要测试的模型定义如下。元组列表,其中元组的第一个元素是模型(回归或分类器),第二个元素是超参数优化期间使用的参数网格。元组的第三个元素是超参数优化期间模型的迭代次数。
因为每个模型的超参数的数量不同,所以为每个模型指定迭代的次数。例如,对于一个随机森林分类,大约有一打不同的超参数。然而,对于逻辑回归,只有几个超参数。因此,寻找最佳模型需要较少的迭代。
models = [
(ensemble.RandomForestClassifier(),{
'model__n_estimators': randint(50,500),
'model__max_depth': randint(3,10),
'model__max_features': ['sqrt'],
'model__min_samples_split': randint(2,20),
'model__min_samples_leaf': randint(1,10),
'model__criterion': ['gini', 'entropy'],
'model__ccp_alpha': loguniform(0.1e-5, 0.1e-0)
}, 1),
(neighbors.KNeighborsClassifier(),{
'model__n_neighbors': randint(3,20),
'model__weights': ['uniform', 'distance'],
'model__algorithm': ['auto', 'ball_tree', 'kd_tree', 'brute']
}, 1),
(svm.SVC(probability=True, max_iter=MAX_ITER),{
'model__C': loguniform(3e-4, 3e-1),
'model__kernel': ['linear', 'poly', 'rbf', 'sigmoid']
}, 1), (linear_model.LogisticRegression(solver=LOGISTIC_REGRESSION_SOLVER,
max_iter=MAX_ITER),{
'model__C': loguniform(3e-4, 3e-1),
'model__penalty': ['none', 'l2'],
'model__class_weight': ['balanced', None]
}, 1),
(naive_bayes.GaussianNB(),{}, 1),
]feature_selectors = [
(feature_selection.SelectFromModel(linear_model.LogisticRegression()),{
'feature_selection__estimator__penalty': ['l2'],}),
(decomposition.PCA(),{'feature_selection__n_components': randint(2, 5),}),
]scalers = [
(preprocessing.MinMaxScaler(),{}),
(preprocessing.RobustScaler(),{'scaler__quantile_range': [(25.0, 75.0),
(10.0, 90.0)] })
]imputation = [
(impute.SimpleImputer(),
{'imputer__strategy': ['mean', 'median']})
]transformers = [
(preprocessing.OneHotEncoder(),
{'column_transformer__transformer__drop': ['first', 'if_binary', None]})
]hyparameters = list(
itertools.product(
transformers, imputation, scalers, feature_selectors, models
))
设置每组的参数以支持超参数优化中使用的随机网格搜索。对于连续变量,参数期望分布。这些是使用 scipy 库定义的,该库允许预先指定发行版。当超参数是分类的时,超参数可以简单地固定为一个列表。
使用 itertools 包建立完整的超参数网格。该包中的产品功能在每个参数网格之间创建所有可能的配置。
通过以这种方式设置超参数,迭代处于单个循环中。
这个相同的过程可以使用多个循环来完成。然而,为了便于阅读,itertools 将这些众多的列表压缩成一个列表。
注意每个超参数的命名。参数的前缀与管道中使用的名称相匹配。sklearn 知道什么参数去哪里的方式是基于参数的名称。
当管道中有链接的函数时,名称会稍有变化。例如,“feature_selection _ _ estimator _ _ penalty”对应于管道中的“feature _ selection”命名步骤,对于此选项,它是 SelectionFromModel 特征选择方法。“估计值”部分对应于 SelectionFromModel 中的估计值参数。最后,“惩罚”部分对应于 SelectionFromModel 中使用的估计量的惩罚参数,它是为逻辑回归而设置的。
双下划线“__”指定一个函数何时在另一个函数中使用,以控制哪个函数转到管道步骤中的不同函数。
迭代
下面的循环遍历每个参数组合,并为每个配置优化一个模型。
for transformer_params, imputer_params, scaler_params, feature_selection_params, model_params in hyparameters:
hyperparameter_dict = {
**transformer_params[1],
**imputer_params[1],
**scaler_params[1],
**feature_selection_params[1],
**model_params[1]
}
column_transformer = compose.ColumnTransformer(
[('transformer', transformer_params[0],categorical_feature_names)],
remainder="passthrough"
) pipe = Pipeline(steps=[
('column_transformer', column_transformer),
('scaler', scaler_params[0]),
('imputer', imputer_params[0]),
('feature_selection', feature_selection_params[0]),
('model', model_params[0])
])
optimal_model = RandomizedSearchCV(
pipe, hyperparameter_dict,
n_iter = model_params[2], cv=K_FOLDS,
scoring=SCORING_METRIC, n_jobs = N_JOBS,
return_train_score=True, verbose = VERBOSE
)
optimal_model.fit(X_train, y_train)
y_pred = optimal_model.best_estimator_.predict(X_train)
y_pred_prob = optimal_model.best_estimator_.predict_proba(X_train)[:,1]
y_pred_test = optimal_model.best_estimator_.predict_proba(X_test)[:,1]
score = SCORING_FUNCTION(y_test, y_pred_test) print(
'Optimal Training Score: ', optimal_model.cv_results_['mean_train_score'][optimal_model.best_index_],
'\Optimal Test Score: ', optimal_model.best_score_,
'\nHold Out Test Score: ', score
)
if score > best_score:
best_score = score
pickle.dump(optimal_model, open(OPTIMAL_MODEL_FILENAME, 'wb'))
分解每个组件:
- 通过组合来自流水线中每个步骤的超参数来创建单个字典。
- 列转换器是在管道之前单独创建的。此转换器为特征转换启用了单独的路径。
- 管道“管道”已创建。步骤是一个元组列表,其中第一个元素是步骤的名称。(此名称匹配与步骤相关的超参数的前缀)。第二个要素是该步骤的函数,无论是缩放、插补还是预测。
- 使用随机超参数搜索来确定最佳模型。这种搜索从超参数空间采样,用于每个模型所需的几次迭代。
- 使用评分功能评估培训、测试和坚持测试的结果。
- 如果模型的得分比当前的最佳模型好,则使用 pickle 存储该模型。
注:这里使用随机搜索,因为它比网格搜索更有可能找到最佳模型。有关不同超参数搜索方法的详细信息以及随机搜索优于网格搜索的原因,请阅读以下帖子:
结论
Sklearn 管道提供了很大的灵活性。然而,他们可能会面临挑战。
通常,在构建管道时,可用的示例仅显示了管道的特定部分。因此,将这些碎片放在一起并不总是简单的。
该代码允许 sklearn 中的大多数可用功能自动使用或稍加调整即可使用。希望这条管道能让你的发展流动起来。
如果你有兴趣阅读关于新颖的数据科学工具和理解机器学习算法的文章,可以考虑在 Medium 上关注我。
如果你对我的写作感兴趣,想直接支持我,请通过以下链接订阅。这个链接确保我会收到你的会员费的一部分。
https://zjwarnes.medium.com/membership
脸书实验公司的 Robyn 为自动化营销组合建模
营销组合建模的新工具概述
这篇文章为你提供了脸书实验的罗宾的第一个概述。由于脸书营销科学团队已经创建了一个很棒的快速入门指南和非常详细的页面,我尽量保持文章简短切题。详细解释可以在这里找到更多信息。
TL;博士
- 脸书实验公司的 Robyn 是一个自动营销组合建模(MMM)代码,目前处于测试版。
- 它为特征转换提供了两种 adstock(几何和威布尔)和一种 s 曲线转换(收益递减)技术。
- 为了考虑时间序列的特征,罗宾使用了脸书先知。
- 它利用脸书的 Nevergrad 无梯度优化平台生成一组 Pareto 最优模型解。
- 为了增加模型的准确性,它允许你包含随机控制实验的结果。
在我们开始之前…为什么 MMM 如此重要?
每个营销人员都有两个大问题:我当前的营销渠道有什么影响?和我应该如何战略性地分配我的预算以获得最佳营销组合?
这些问题并不新鲜。约翰·沃纳梅克(1838-1922)被一些人认为是市场营销的先驱,他也有同样的问题,并因其著名的经常被引用的名言而闻名:
我一半的广告支出都浪费了;问题是,我不知道是哪一半。
为了应对这些挑战,计量经济学家开发了被称为营销组合建模(MMM)的多元回归技术。这个领域的一个非常新的工具是脸书的 Robyn,目前它还处于测试阶段。脸书实验小组将罗宾描述为
[……]自动化营销组合建模(MMM)代码。它旨在通过岭回归和进化算法减少人为偏差,通过提供预算分配器和收益递减曲线实现可操作的决策制定,并允许对因果关系进行地面实况校准。
在下文中,我会给你一个 Robyn 的功能和主要思想的快速概述。由于它仍处于测试版本,所使用的代码和概念可能会发生变化。你可以在这里找到它的最新版本。
使用的数据集
为这篇文章找到一个合适的开放数据集是相当棘手的,所以我使用谷歌的aggregate 营销系统模拟器 (AMSS)来生成一个简单的数据集。如果你对 AMSS 的更多细节感兴趣,你可以在这里找到他们的论文,如果你想用我用过的数据集,你可以在这里找到。
您将在下面找到营销数据的描述表和图表,以便更好地熟悉数据集。
表 1。数据集的描述性指标(图片由作者提供)。
使用的数据集基于每周数据,包含 208 个条目。所有数值均以欧元(€)为单位,不存在北美数值。我们的目标变量是收入,而其他列是可以用来解释它的特性。
以 _S 结尾的栏目是我们按渠道(电视、广播、付费搜索)划分的营销预算支出。我们的竞争对手销售额由自我解释栏竞争对手 _ 销售额给出。
描述表中没有显示的一列是日期列,以格式 YYYY-MM-DD 表示相应的周。
图 1 显示了一段时间内的收入、收入构成、竞争对手的销售和营销费用。
图一。收入、收入构成、销售和支出随时间变化的可视化(图片由作者提供)。
我们可以清楚地看到收入的季节性(A1)以及一点趋势(A2)。还可以看到,竞争对手的销售遵循与我们的收入非常相似的模式,我们在春季的广播费用和季节性以及付费搜索费用的趋势方面存在差距。
图 2 显示了我们的数据集的相关图,以初步了解变量之间的关系。
图二。我们数据集的相关图(图片由作者提供)。
我们可以看到竞争对手的销售额和我们的收入之间有很高的相关性,其次是我们的付费搜索费用和我们的收入以及竞争对手的销售额之间的相关性较低,为 0.4。
现在,您对数据集稍微熟悉了一些,让我们现在使用 Robyn。
建立我们的 MMM 项目
为了获得 Robyn 的最新版本,我们将它的存储库克隆到我们的机器上:
git clone https://github.com/facebookexperimental/Robyn
在我们克隆了存储库之后,我们创建了一个名为 plots 的新文件夹来存储后来结果的可视化。
您的文件夹结构现在应该如下所示:
Robyn/
├── *CHANGELOG.md*
├── *CODE_OF_CONDUCT.md*
├── *CONTRIBUTING.md*
├── *LICENSE.md*
├── *README.md*
├── **Robyn.Rproj** ├── **plots** ├── **source**
│ ├── *de_simulated_data.csv*
│ ├── **fb_robyn.exec.R**
│ ├── *fb_robyn.func.R*
│ ├── *fb_robyn.optm.R*
│ └── *holidays.csv*
├── *website*
我们感兴趣的主文件位于源文件夹中,名为 fb_robyn.exec.R 。这是我们必须设置配置和运行争论、建模、优化以及预算分配(如果需要)流程的文件。
但是在我们去那里之前,让我们简短地看一看 Robyn 使用了什么(建模)技术。
罗宾的技术
以下几点从较高的层面描述了罗宾的内心世界。有关更多详细信息和解释,请参见他们的文档。
岭回归
开发人员使用正则化方法的动机是解决许多回归变量之间的多重共线性,并防止模型过度拟合。图 3 显示了该模型的方程以及函数的主要组成部分。
图 3。通过Facebook experiment建立模型方程。
其中 yₜ是我们的因变量在时间 t 的收入。自变量由截距定义,随后是 ad-stock 和 s 曲线 变换分量用于每种媒体 j 。节假日、季节性和趋势效果分别用节假日、节假日和趋势来表示。附加 独立 变量由等定义,后跟误差项 ε 。
特征转换选项
MMM 中非常常见的转换技术是 ad-stock 和 s 曲线(收益递减)转换。
广告股票转型 广告股票转型背后的想法是,广告效应通常不会立即生效。它们有一个半衰期。顾客(通常)不会在看到你的广告后立即跑到商店购买你的产品。你的广告需要一些时间来适应。
罗宾在这里提供了两种方法,经典的几何方法和更灵活的 T2 威布尔生存函数。更深入的解释请见文件。
S 曲线(收益递减)转变
这种转变背后的基本思想是,随着时间的推移,广告会失去其有效性,即使给它分配了更多的钱。
趋势、季节性和假日效应
为了在模型中包含趋势、季节性或假日等时间序列特征或成分,Robyn 使用了 FacebookProphet。
自动化超参数选择和优化
Robyn 使用脸书的 Nevergrad 无梯度优化平台执行多目标优化,通过提供一组帕累托最优模型解决方案来平衡支出份额和渠道系数分解份额之间的关系。
这些帕累托最优模型解是多次迭代(即,20,000 次迭代和可能的模型解)运行进化算法(自然选择)的结果
使用实验结果进行校准
Robyn 允许我们应用随机控制实验的结果来提高模型的准确性,其中这些结果被用作缩小媒体变量系数的先验。
这部分内容不在本文讨论范围内。如果你对更多细节感兴趣,你可以在这里找到他们的文档。
MMM 配置
现在我们对 Robyn 的技术有了一个基本的概述,让我们继续我们的用例。您将在本文末尾找到完整的代码。
我们经营罗宾。使用 R-Studio 运行 Rproj,并打开位于源文件夹中的 fb_robyn.exec.R。
避免时间序列特征的错误
如果您的操作系统不是英语,您应该做的第一件事是取消第 13 行的注释:
否则,您将在数据争论过程中出错(第 166 行)。
安装并加载库
确保安装所有使用的库,创建一个名为 r-reticulate 的 conda 环境,安装 nevergrad 并使用创建的 conda env。
加载数据
现在是时候加载我们的 csv 文件了。开发团队已经提供了一个名为 de_simulated_data.csv 的文件。
开发团队还提供了一个假日文件,其中包括几个国家(如美国、英国、印度、德国)的公共假日。
设置模型输入变量
在这一部分,我们将代码中的配置链接到数据集中的列。这一部分非常重要,因为在自动化数据争论过程中,打字错误会导致错误。
设置全局模型参数
Robyn 允许我们使用几何或威布尔股票技巧。在本文中,我们将继续使用几何方法,但是尝试一下威布尔技术绝对是值得的。
由于 Robyn 使用 Nevergrad,我们必须选择一种算法以及试验次数。这里我们也坚持默认的。
设置超参数界限
根据我们定义的变量和使用的 ad-stock 方法,我们必须设置它们的超参数界。
运行模型
现在我们已经设置了所有的参数,我们可以使用下面的代码来运行我们的模型。
Robyn 现在正在运行,并将在我们指定的绘图文件夹中自动生成绘图。
输出和诊断
建模过程完成后,您应该在 plots 文件夹中找到几个文件。
这些图(以模型 id 作为其名称)代表基于 Pareto 最优过程(pareto_front.png)的最优模型解决方案,并为我们提供关于超参数选择(hypersampling.png)的附加信息。
图 4。显示了其中一种型号(3_30_1)的单页型号。
图 4。单页纸模型(图片由作者提供)。
响应分解瀑布通过预测器
显示每个特性对响应变量(收入)影响的百分比。在本例中,34.08%的收入可归因于季节性,11.62%可归因于电视广告等。
支出份额与效果份额 该图描述了各渠道的支出份额和效果份额。除此之外,它还显示了每个渠道的投资回报率(ROI)。对于我们的例子,我们可以看到频道广播的投资回报率最高,其次是电视和付费搜索。这也表明,电视上的平均费用比他们的平均效果份额大一点。这可能意味着他们正遭遇一些收益递减。
平均广告库存衰减率 显示每个渠道的百分比衰减率。衰变率越高,衰变效应持续的时间越长。对于这个例子,频道 TV 具有最高的平均衰减率。
实际响应与预测响应 该图将实际响应与我们的预测进行比较。我们的目标是我们的模型能够解释数据中的大部分差异。因此,我们寻求高 R 平方(rsq)和低 NRMSE。
响应曲线和渠道平均支出 表明每个渠道的饱和程度,并可能建议潜在的预算再分配策略。观察这些曲线,它们到达拐点和平坡的速度越快,每增加一次€消耗,它们就越快饱和。对于我们的例子,广播和付费搜索的曲线没有显示任何平坦的斜率,可能需要进一步的调查。
拟合与残差 经典图表检查我们的回归模型是否有问题。
模拟预算分配
一旦我们决定了一个合理的(!!)模型,我们可以运行预算优化模拟来计算最佳媒体支出分配。我们有两种类型的模拟场景:
- max _ historical _ response
- 最大响应预期花费
第一个将使用对模型有贡献的历史数据和花费来计算最佳媒体计划。
第二个是在给定预算和天数的情况下计算最佳媒体计划。
所有的模型都存储在model _ output _ collect $ all solutions变量中。假设我们想使用上面的模型(3_30_1 ),我们只需使用以下代码:
除了模型 id 和场景类型之外,我们还必须为我们使用的通道设置下限和上限。如果我们渠道的下限是 0.7,上限是 1.2,那么我们的花费变化将受到平均时间段花费的 0.7 倍和平均时间段花费的 1.2 倍的约束。
运行该代码后,Robyn 输出一个新的单页页面(图 5)。
图 5。预算分配器最佳结果单页纸(图片由作者提供)。
左图显示了如果我们遵循预算优化,预算分配和平均反应将如何变化。右侧的图表显示了每个渠道的响应曲线,以及初始平均支出水平与推荐平均支出水平的对比。
这篇文章的想法是向您提供脸书实验的 Robyn 的第一个概述,以及如何通过使用简化的数据集来使用它。对于更深入的解释,实验结果的使用,以及更多的细节,我强烈建议你查阅 Robyn 的文档。
与这个简短的介绍不同,在型号选择部分投入时间和精力也很重要。只有使用合理的模型,与企业讨论结果并使用预算优化步骤才有意义。
即使该项目仍处于测试阶段,但其背后的动机和想法及其功能非常巧妙,令人印象深刻!
如果我可以许三个愿望,我希望有一个选择,对横截面数据使用面板回归。其次,找到一种减少计算时间的方法也是很棒的。第三,类似于第一个愿望,不仅仅使用分类变量作为基线变量会很好。…如果我能做第四个 Python 的移植会很棒;)
完整文件的代码:
Azure 数据工厂管道的自动化测试
从 DevOps 的角度提高解决方案的质量
把你的脚抬起来——照片由 Unsplash 上的 Kewal 拍摄
在 DevOps 的帮助下,在更小或更大的团队中开发 ETL 或 ELT 解决方案从未如此简单。它使我们能够确定,在多个团队成员对解决方案的不同部分进行更改后,解决方案仍然有效。例如数据库存储过程、表、视图等的变化。结合 Azure 数据工厂管道和部署管道(CI/CD) 设置的变化。
DevOps 教导我们尽可能多地自动化,以创造过程的可重复性。使用源代码控制和频繁的代码签入。实施持续集成和持续开发(CI/CD)将有助于我们快速、可靠地交付产品,而无需人工依赖。
我们和一个小团队一起开发一个数据平台**“解决方案加速器”**。这个加速器使我们能够轻松地部署一个有效的端到端解决方案,包括 Azure SQL 数据库、Azure 数据工厂和 Azure Key Vault。
我们一直在改进我们的解决方案,并为其添加新功能。作为产品所有者,我想确保我的产品不会被这些添加的东西破坏。除了好的分支策略之外,尽可能多地自动化测试有助于我们实现这一点。
对我们的部署管道的最新改进是从我们的部署管道触发一个 Azure 数据工厂(ADF)管道,并监控结果。在这种情况下,结果决定了是否允许完成拉请求,因此减少了导致**“中断”主分支**的机会。
在本文中,我将对的构建和发布管道中的步骤进行概述,并提供用于触发和监控ADF 管道的脚本。
Please note the difference between pipelines. I'm talking about **Azure Data Factory pipelines** whose main task is the movement of data. And on the other hand **CI/CD or deployment pipelines**. These are used to deploy resources to our Azure subscription. And live in our Azure DevOps Project. Please note that there are many kinds of tests that you can perform. In this example we are merely checking if the ADF pipeline 'is **doing things right**'. In contradiction to 'is it **doing the** **right things**'!
Azure DevOps 管道设置
除其他外,我们目前使用的设置具有以下要素:
GitHub 资源库:
- Azure 资源管理模板(ARM 模板)
- Visual Studio 数据库项目
- JSON 格式的 Azure 数据工厂管道
Azure DevOps 项目:
- YAML 的天蓝色管道:
- 构建和验证阶段
- 发布阶段
我强烈建议使用 YAML 语法来定义管道,而不是传统的编辑器。最大的优势是能够用代码的相应版本来控制管道的版本。请参见文档的参考资料。
管道设置—构建和验证阶段
管道有两种不同的阶段:一个“构建和验证”阶段和多个“发布”阶段。
“构建和验证”阶段有两个主要目标:
- 验证 ARM 模板
- 构建数据库项目
这些任务的结果作为工件发布,在发布阶段使用。
Azure DevOps 构建和验证步骤
管道设置—发布阶段
“发布”阶段的任务是按照以下顺序部署所有资源:
- ARM 模板的部署
- ADF 对象(管道、数据集等)的部署。)*
- SQL 数据库项目的部署
Azure DevOps 发布步骤
*Tip Deploying Azure Data Factory: We had many discussions about the topic, but in the end chose to use an [extension build by Kamil Nowinski](https://sqlplayer.net/2021/01/two-methods-of-deployment-azure-data-factory/) in stead of the Microsoft approach. The are many quality of life improvements in this extension!
管道设置—发布阶段触发器
部署管道的发布阶段针对我们定义的不同环境重复进行。在我们的情况下,我们使用开发、测试和生产。这些环境的触发器是我们选择的 git 分支策略的结果。
正是在这个“测试”环境的发布阶段,我们实现了一个 PowerShell 任务,它触发并监控 ADF 管道的运行。当 GitHub 存储库中的 pull-request 被启动时,测试环境的发布被触发。
触发和监控 ADF 管道运行
除了 ADF 用户界面,还有多种方法可以触发管道。这里我们使用 PowerShell,因为它很容易被整合到部署管道中。下面是一个 Azure PowerShell 任务的示例,它从您的存储库中执行一个脚本。
Microsoft 文档为 PowerShell 脚本提供了一个很好的起点。在合并了用于触发和监控的语句后,我做了两个重要的修改:
- 如果 ADF 管道获得“排队”状态,脚本将会中断
- 如果结果不等于“成功”,我们抛出一个错误
在第 27 行抛出错误确保发布阶段的任务失败,因此整个流水线获得状态‘失败’。这很重要,因为这个防止拉请求在这个错误在对存储库的另一个提交中被解决之前完成。
就是这样!请分享更多改进的建议!
参考
Azure Pipelines |微软文档
Azure Pipelines—Azure PowerShell 任务|微软文档
Azure Data Factory—Azure Data Factory 中的持续集成和交付|微软文档
自动树状图切割
实践中打包贝叶斯
聚类分析是一种探索数据结构的有用技术。在众多算法中,凝聚聚类是一种简单而有用的方法,它通过逐步链接最相似的对,直到所有数据都链接在一起,从而自下而上地建立聚类层次。通过将层次结构表示为树状图,它有助于我们深入了解数据的分布和结构。尽管很有见地,但有时我们可能更希望在实际应用中使用扁平化的表示,结果却是一个关于如何切割树状图的问题。在本文中,我将向您展示我们如何在特定的标准下,最优地将树状图切割成小块,而不是沿着特定的阈值简单地直接切割。
切割树状图的最佳方式
简而言之,我们的目标是将树状图切割成 k 个不相交的子树,使得一些选择的损失达到最小。损失/选择标准是自由的,一个可能的选择是类内平方和(WCSS),这是 k 均值聚类旨在最小化的目标函数。有了标准,下一个问题是,我们如何去做?列举所有的可能性肯定有用,但那样会太累。一个聪明的解决方法是探索最优子结构并执行动态规划。简而言之,为了最优地将整棵树切割成 k 个子树,这相当于找到最优的 kₗ和 kᵣ,我们需要从根的左右分支获得子树的数量,使得 kₗ + kᵣ = k。对于每个可能的(kₗ,kᵣ)对,我们需要将左右分支切割成 kₗ和 kᵣ子树,这与我们切割整棵树的问题完全相同。因此,我们可以递归地划分问题,直到树状图的叶子。要了解清楚的细节,这里有戈蒂埃·马蒂的一个很棒的帖子。
简单的三类数据集。
平均法树状图。这三种分别是最佳的 2 切、3 切和 4 切。
选择要切割树状图的聚类数
我们已经学习了如何最优地将一个树状图切割成 k 块,现在我们需要确定我们需要多少个聚类。确定 k 无疑是我们在进行聚类分析时面临的最困难的问题,特别是当我们希望以数据驱动的方式自动确定 k 时。在 rest 内容中,我将介绍一个强大但不太为人所知的框架,称为 PAC 贝叶斯学习,用于 k 选择问题。
什么是 PAC 贝叶斯?
可能近似正确,又名 PAC,是一个通过构建过度误差的上限来量化可学习性的框架,过度误差是样本内误差和样本外误差(泛化误差)之间的差异。PAC Bayesian 扩展了这个框架,它通过引入假设的先验分布来表达关于假设的某种信念,就像我们在 Bayesian 学习中所做的那样。
它是如何工作的?
关于 PAC 贝叶斯界的形式其实有很多种,下面我将介绍最基本的(我认为)形式。在贝叶斯设置中,人们通常使用模型证据作为度量来评估模型的性能,并从中选择最佳的一个。它被表述为
其中 D 是观测数据,M 是模型,θ是模型参数,p(θ|M)是θ的先验分布,p(D|M,θ)是在模型配置为θ的情况下观测到 D 的可能性。
为了评估证据,我们需要计算积分,这有时是棘手的。因此,我们求助于优化它的下界,证据下界(ELBO):
对于所有可能的 q,当 q 等于后验 p(θ|D,M)时,等式成立。因此,给定一组模型,我们可以尝试优化 ELBO,并选择最大的 ELBO 作为最终选择。这个框架是独立的,有很强的理论支持,但有很大的限制,因为我们需要给出有效的概率度量来量化可能性——它当然不适用于我们的树图切割问题。概括的一种方法是将对数似然替换为任意损失函数,得到
通过一些代数运算,它等价于求的最小值
因为我们有一个单一的切割,而不是对每个 k 的所有可能性的分布,它进一步退化为
其中前一项是由最优切割产生的总 wcs,Zᵏ代表每个观察值的聚类标签。现在,我们只需要指定 Zᵏ的先验分布来完成最后一个谜题。一个合理的选择将是中国餐馆过程,一个众所周知的非参数贝叶斯文献中的分布,用于描述聚类标签的分布。它可以通过以下方式进行累积评估
不同的 k 与 PAC 贝叶斯正则化项的损失,λ=0.2,α=1
地毯下的污垢
在玩机器学习的时候,我们都知道没有免费的午餐。一个适用于所有数据集的通用λ是不存在的,我们不可避免地要动手寻找最适合数据集的λ。尽管如此,我们至少在系统地解决问题。
最后的话
PAC Bayesian 是一个强大的、强有力的理论支持框架,用于研究模型的泛化能力,甚至用于过参数化的神经网络。在本文中,我简单地应用了基本形式来解决从一组最优树图切割中选择 k 的问题,这只是其威力的冰山一角。我希望它能对每个对此感兴趣的人有所帮助和启发。
模拟:https://github.com/jerrylin0809/pac-bayesian-dendrogram-cut
用 Python 自动下载电子邮件附件
使用 PyWin32 实现自动化
简化繁琐的东西来解放我们的思想。
您是否曾经在邮箱中搜索过所有需要的附件?然后也许你离开了,回来的时候忘记了你停在哪里?也许你还需要把它们保存到不同的目录或文件夹中?
我以前也在那个位置。这就是为什么我想自动下载附件到正确的目录。之后,对电子邮件的附件进行相应的转换。
在本文中,我将比较解决方案的可能 Python 库,并分享我如何使用 Python 来自动化这个过程。
访问邮箱的 Python 库比较
作者创建的图像
smtplib 不是我的选择之一,因为它只能发送电子邮件,而 imaplib 需要用户名和密码,这不太好。因此,我选择了 pywin32 。
使用 pywin32 从 Outlook 下载特定邮件
没有可用的 pywin32 官方文档。目前,我们只能参考*Visual Basic for Application(VBA)*中的 Outlook MailItem 的引用来了解可以用来操作邮箱和邮件的函数。然后,当您在 Python 中编写脚本时,不能直接使用该示例。在各种技术写作网站上也有一些很好的 pywin32 应用实例,但都不完整。
本文涵盖了使用 pywin32 访问 Outlook 邮箱所需的所有基本知识。
- 导入模块
第一步。
# pip install pywin32 #if you not installed yet
import win32com.client
2。建立与 Outlook 的连接
# set up connection to outlook
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
3。MailItem 操作的一些基本方法/属性
(1)访问收件箱。
inbox = outlook.GetDefaultFolder(6)# for sub folder, add <.folder("your folder name")>
inbox = outlook.GetDefaultFolder(6).folders("Testing")
6 是收件箱的索引。其他常见项目的索引如下。
3 Deleted Items
4 Outbox
5 Sent Items
6 Inbox
16 Drafts
您可以使用下面的源代码来检查其他文件夹的索引。(参考 C2)
import win32com.client
outlook=win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
for i in range(50):
try:
box = outlook.GetDefaultFolder(i)
name = box.Name
print(i, name)
except:
pass
(2)阅读电子邮件
# Access to the email in the inbox
messages = inbox.Items# get the first email
message = messages.GetFirst()
# get the last email
#message = messages.GetLast()# to loop thru the email in the inbox
while True:
try:
print(message.subject) # get the subject of the email
# if you use messages.GetFirst() earlier
message = messages.GetNext()
# if you use messages.GetPrevious() earlier
#message = messages.GetPrevious()
except:
# if you use messages.GetFirst() earlier
message = messages.GetNext()
# if you use messages.GetPrevious() earlier
#message = messages.GetPrevious()
上面的例子显示了如何打印收件箱中所有邮件的主题。除了主题之外,我们还可以打印其他属性或将其用作定义条件语句的标准。下面显示了一些常见的属性。
message.subject
message.senton # return the date & time email sent
message.senton.date()
message.senton.time()
message.sender
message.SenderEmailAddress
message.Attachments # return all attachments in the email
注意,以一对括号结尾的messages.GetFirst()
或messages.GetNext()
指的是我们可以用来操作邮箱的方法,而message.subject
或message.senton
指的是电子邮件的属性,使用 Python 时不区分大小写。因此,对于完整的 MailItem 属性列表,你可以参考 VB 中的 MailItem 文档,它可以在底部的参考 C1 中找到。(我没有全部试过,但是大部分都可以适用。)
(3)下载邮件附件。
attachments = message.Attachments# return the first item in attachments
attachment = attachments.Item(1)
# the name of attachment file
attachment_name = str(attachment).lower()
attachment.SaveASFile(path+ '\\' + attachment_name)
4。完整示例
# import libraries
import win32com.client
import re
# set up connection to outlook
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")inbox = outlook.GetDefaultFolder(6)
messages = inbox.Items
message = messages.GetFirst()
today_date = str(datetime.date.today())while True:
try:
current_sender = str(message.Sender).lower()
current_subject = str(message.Subject).lower()
# find the email from a specific sender with a specific subject
# condition
if re.search('Subject Title',current_subject) != None and re.search(sender_name,current_sender) != None: print(current_subject) # verify the subject
print(current_sender) # verify the sender
attachments = message.Attachments
attachment = attachments.Item(1)
attachment_name = str(attachment).lower()
attachment.SaveASFile(path + '\\' + attachment_name)
else:
pass message = messages.GetNext() except:
message = messages.GetNext()exit
上面是一个完整的例子,它将来自特定发件人的带有特定标题的电子邮件下载到特定的路径。您可以根据自己的情况更改条件,例如,您可以使用message.senton.date()
获取在指定日期收到的电子邮件。此外,您可以使用嵌套的 if-else 语句将附件保存在不同的目录中,这在您要下载大量附件时非常方便。
保持联系
订阅 YouTube
参考
A.smtplib
B.imaplib
C.pywin32
- MailItem 接口(所有 Outlook MailItem 对象属性、方法和事件的应用程序参考 Visual Basic)
- 清楚地记录了使用 python win32com outlook 阅读电子邮件的功能(包含了在 outlook 中访问邮件和附件所需的大部分基本属性)
一些旁注
如果你对如何使用pywin32
实现 Microsoft Excel 报表自动化感兴趣,可以参考这篇文章《用 Python 实现 Excel 自动化》。
如果你有兴趣用 Python 创建一个图表或数据透视图,并将其作为电子邮件附件自动共享,那么用 Python 自动化 Excel 图表。
祝贺并感谢你阅读到最后。希望你喜欢这篇文章。 ☺️