TowardsDataScience 2023 博客中文翻译(四十五)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

使用 MLflow 在 Databricks 中自动化 ML 模型的再训练和部署

原文:towardsdatascience.com/automate-ml-model-retraining-and-deployment-with-mlflow-in-databricks-ad29f6146f80?source=collection_archive---------2-----------------------#2023-03-15

高效管理和部署生产模型使用 MLflow

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Matt Collins

·

关注 发表在 Towards Data Science ·8 分钟阅读·2023 年 3 月 15 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来源:Karsten WinegeartUnsplash

将一个可工作的机器学习模型部署给用户使用是一个伟大的成就。我们看到统计数据显示,机器学习模型常常未能投入生产,无论是由于数据不足、缺乏方向还是其他原因。

已经投入生产的模型仍然面临许多挑战,因为它们需要持续的关注,包括监控和重新训练,以确保它们所提供的见解随时间保持最新和准确。

本博客旨在帮助简化使用 MLflow 的模型重新训练过程,同时提供推荐方法的背景。

为什么要重新训练生产模型?

模型重新训练是给我们的生产模型提供最新数据以进行最新预测的过程。根据我们系统的复杂性,我们可能在各种场景下执行这种重新训练,例如:

  • 在定期时间间隔:例如每周安排一次。

  • 根据特定标准:数据漂移达到阈值条件可能导致我们重新训练以适应不断变化的数据环境。

  • 注册新模型时:我们的数据科学家找到了一种更准确的模型,并已获批准上线。

MLflow

模型重新训练属于机器学习操作(MLOps)过程,MLflow 是一个很好的工具,可以以迭代的方式简化这一过程,实现更顺畅的交付和可重复的执行。

如果你对 MLflow 不熟悉,网上有许多详细的资源可供参考,但我建议从他们的网站开始,以了解他们的产品——我在下面包含了作为介绍的组件。

我们将利用 MLflow 的跟踪组件来记录我们的重新训练实验运行,以及模型注册表组件来确保部署顺利,并减少我们生产环境中停机的需求。

前提条件

由于我们讨论的是重新训练,我们假设你已经在生产中有一个模型(以及你希望预测的数据)。如果没有,并且你希望使用 MLflow 来实现这一目标,我提供了这个笔记本作为起点。我们将在“将初始模型部署到生产”部分详细回顾这个过程和代码。

为了方便,我们将使用带有 ML 计算集群的 Databricks 工作区,因为这为我们提供了一个托管环境,其中安装了所有所需的软件包、嵌入了 MLflow 界面,并且有一个 Spark 环境,以协助任何大数据查询(如有必要)。

Databricks 可通过大多数云提供商获得——我将使用 Microsoft Azure。如果在本地运行 MLflow,则确保所有相关软件包已安装,并且设置了 MLflow 追踪服务器。

我在下面分解了这些要求:

  • 运行 ML 计算集群的 Databricks 工作区,模拟生产环境。

  • 源数据:在生产环境中,我预计这些将是我们数据仓库或数据湖中的表格。我们将使用 Scikit-learn 包中的糖尿病数据集作为示例。

  • 一个现有的机器学习模型,我们将其保存为模型注册表中的生产模型(代码示例见下)。

将初始模型部署到生产环境中

以下代码块显示了 Ridge 回归模型的实验运行。有关完整笔记本,请参见我 GitHub Repo 中的此链接。此示例旨在为您提供一个“生产”模型,您可以基于此模型进行重新训练过程。

# Start MLflow run for this experiment

# End any existing runs
mlflow.end_run()

with mlflow.start_run() as run:
  # Turn autolog on to save model artifacts, requirements, etc.
  mlflow.autolog(log_models=True)

  diabetes_X = diabetes.data
  diabetes_y = diabetes.target

  # Split data into test training sets, 3:1 ratio
  diabetes_X_train, diabetes_X_test, diabetes_y_train, diabetes_y_test = train_test_split(diabetes_X, diabetes_y, test_size=0.25, random_state=42)

  alpha = 1
  solver = 'cholesky'
  regr = linear_model.Ridge(alpha=alpha,solver=solver)

  regr.fit(diabetes_X_train, diabetes_y_train)

  diabetes_y_pred = regr.predict(diabetes_X_test)

  # Log desired metrics
  mlflow.log_metric("mse", mean_squared_error(diabetes_y_test, diabetes_y_pred))
  mlflow.log_metric("rmse", sqrt(mean_squared_error(diabetes_y_test, diabetes_y_pred)))
  mlflow.log_metric("r2", r2_score(diabetes_y_test, diabetes_y_pred))

使用 MLflow API 命令将其推送到你的模型注册表中进行生产部署。

model_uri = "dbfs:/databricks/mlflow-tracking/<>/<>/artifacts/model"
desc = 'Initial model deployment'
new_run_id = run.info.run_id
client.create_model_version(name, model_uri, new_run_id, description=desc)
version = client.search_model_versions("run_id='{}'".format(new_run_id))[0].version
client.transition_model_version_stage(name, version, "Production")

找到合适的方法:部署代码与部署模型

为了了解我们的重新训练笔记本可能是什么样的,我们需要了解所采取的方法。微软讨论了两种部署模式,我在下面总结了这些。更多详细信息请参见 此处

部署代码

  • ML 工件被打包为从部署到生产的代码。

  • 可以实现版本控制和测试。

  • 部署环境在生产中得到复制,降低了生产问题的风险。

  • 生产模型是针对生产数据进行训练的。

  • 附加的部署复杂性。

部署模型

  • 独立的工件(机器学习模型)被部署到生产环境中。

  • 灵活性部署到不同类型的环境或集成不同的服务。

  • 部署过程中的简单性。

  • 快速部署时间,轻松版本管理。

  • 特征工程、监控等的更改和增强需要单独管理。

我们将采取推荐的部署代码方法。这非常适合我们要实现的目标:我们可以使用已准备好的、得到利益相关者批准的生产脚本来进行重新训练。

我们没有更改模型中的任何参数值:我们只是针对最新数据重新训练模型。

从设置实验和我们要重新训练的模型开始。

# Import packages
from mlflow.client import MlflowClient

# Set the experiment name to an experiment in the shared experiments folder
mlflow.set_experiment("/diabetes_regression_lab")

client = MlflowClient()

# Set model name
name = 'DiabetesRegressionLab'

加载数据集。如前所述,我们通过使用 scikit-learn 包中的糖尿病数据集来简化这个要求。实际上,这可能是对表的选择语句。

# Load the diabetes dataset
diabetes = datasets.load_diabetes()

在这种情况下,我们模拟了模型重训练发生在数据变化后,可能是几天后。为了模拟这个时间差,当前注册的生产模型已经在数据的一个子集上进行了训练(1.),我们使用完整的数据集来展示随时间增加的数据(2.)

# 1\. Mimic results from a week ago, used by our registered production model
diabetes_X = diabetes.data[:-20]
diabetes_y = diabetes.target[:-20]

# 2\. Dataset as of point of retraining, used in our latest experiment run
diabetes_X = diabetes.data
diabetes_y = diabetes.target

请注意,如果检测到数据漂移,可能会有用例需要从训练数据集中移除一些历史数据。

加载完成后,启动 MLflow 运行并开始训练。这将遵循通常的数据拆分、训练、预测和与测试数据集比较的过程。

# Start MLflow run for this experiment: This is similar to your experimentation script
mlflow.end_run()

with mlflow.start_run() as run:
    # Turn autolog on to save model artifacts, requirements, etc.
  mlflow.autolog(log_models=True)

  # Split data into test training sets, 3:1 ratio
  diabetes_X_train, diabetes_X_test, diabetes_y_train, diabetes_y_test = train_test_split(diabetes_X, diabetes_y, test_size=0.25, random_state=42)

  alpha = 1
  solver = 'cholesky'
  regr = linear_model.Ridge(alpha=alpha,solver=solver)  

  regr.fit(diabetes_X_train, diabetes_y_train)

  diabetes_y_pred = regr.predict(diabetes_X_test)

  # Log desired metrics
  mlflow.log_metric("mse", mean_squared_error(diabetes_y_test, diabetes_y_pred))
  mlflow.log_metric("rmse", sqrt(mean_squared_error(diabetes_y_test, diabetes_y_pred)))
  mlflow.log_metric("r2", r2_score(diabetes_y_test, diabetes_y_pred))

验证标准

在替换生产中的模型之前,使用验证标准来确定新模型的性能至少与现有模型一样好是一个好习惯。这一过程有助于确保新模型的可靠性,并最小化性能退化的风险。在这种情况下,我仅使用 mse、rmse 和 r2 值作为我的验证指标。

既然我们已经记录了一个新的运行,我们可以将其与当前生产中的运行进行比较。

# Collect latest run's metrics
new_run_id = run.info.run_id
new_run = client.get_run(new_run_id)
new_metrics = new_run.data.metrics

# Collect production run's metrics
prod_run_id = client.get_latest_versions(name, stages=["Production"])[0].run_id
prod_run = client.get_run(prod_run_id)
prod_metrics = prod_run.data.metrics

# Collate metrics into DataFrame for comparison
columns = ['mse','rmse','r2']
columns = ['version'] + [x for x in sorted(columns)]
new_vals = ['new'] + [new_metrics[m] for m in sorted(new_metrics) if m in columns]
prod_vals = ['prod'] + [prod_metrics[m] for m in sorted(prod_metrics) if m in columns]
data = [new_vals, prod_vals]

metrics_df = pd.DataFrame(data, columns=columns)
metrics_df

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

评估数据框:作者提供的图像

这是一个简单的例子,其中我们的模型使用了岭回归算法。实际上,我们的模型可能是复合的,使用超参数搜索空间,比较多种算法,并在复杂的验证标准下自动决定使用“最佳”算法。相同的概念可以应用,并且成功的模型可以发布到模型注册表中供使用。

在模型注册表中提升

然后我们可以使用以下代码在满足这些指定的验证标准时自动将此运行移动到模型注册表中的生产环境:

# Retrieve validation variables from the metrics DataFrame
new_mse = metrics_df[metrics_df['version'] == 'new']['mse'].values[0]
new_rmse = metrics_df[metrics_df['version'] == 'new']['rmse'].values[0]
new_r2 = metrics_df[metrics_df['version'] == 'new']['r2'].values[0]

prod_mse = metrics_df[metrics_df['version'] == 'prod']['mse'].values[0]
prod_rmse = metrics_df[metrics_df['version'] == 'prod']['rmse'].values[0]
prod_r2 = metrics_df[metrics_df['version'] == 'prod']['r2'].values[0]

# Check new model meets our validation criteria before promoting to production
if (new_mse < prod_mse) and (new_rmse < prod_rmse) and (new_r2 > prod_r2):
  model_uri = "dbfs:/databricks/mlflow-tracking/<>/<>/artifacts/model"
  print('run_id is: ', new_run_id)

  desc = 'This model uses Ridge Regression to predict diabetes.'

  client.create_model_version(name, model_uri, new_run_id, description=desc)
  to_prod_version = client.search_model_versions("run_id='{}'".format(new_run_id))[0].version
  to_archive_version = client.search_model_versions("run_id='{}'".format(prod_run_id))[0].version

  # Transition new model to Production stage
  client.transition_model_version_stage(name, to_prod_version, "Production")

  # Wait for the transition to complete
  new_prod_version = client.get_model_version(name, to_prod_version)
  while new_prod_version.current_stage != "Production":
      new_prod_version = client.get_model_version(name, to_prod_version)
      print('Transitioning new model... Current model version is: ', new_prod_version.current_stage)
      time.sleep(1)

  # Transition old model to Archived stage
  client.transition_model_version_stage(name, to_archive_version, "Archived")

else:
  print('no improvement') 

在我们的情况下,所有验证标准都已满足,因此模型已被推送到模型注册表中的生产环境中。现在,模型的任何使用,无论是批处理还是实时,都将基于此版本。

希望到此时你能开始注意到部署代码方法的好处,因为它使我们对用于重新训练模型的脚本拥有完全的控制权,并且可以容纳不断变化的验证标准以进行自动重新部署。

如果你希望查看完整的代码,可以访问我的 GitHub 仓库

使用情况

我们可以继续使用推断管道和 REST API 调用来访问模型,如之前一样,但要小心更新任何发生的模式变化。

这是我们可以在部署代码中考虑的内容,添加到模型注册表作为提醒,以防止这成为破坏性更改并影响最终用户。

注意事项/考虑因素

从 MLflow 2.0 开始,Recipes 是一个实验性功能(在撰写本文时),它提供了一种简化的方式来实现部分功能,特别是验证标准。我期望 Recipes 的进一步发展能为用户提供一种结构良好且可重复的方法,用于模型部署和再训练的机器学习生命周期元素。

还值得注意的是,MLOps 仍然相对较新,我们确实可以看到不同企业和用户在实施机器学习解决方案时采取了多种不同的方法。标准化这一方法仍在进行中,解释性和监控等附加组件在生命周期中变得更加普遍。

感谢阅读,如有任何问题,请告知我。

Python 中的自动化特征工程

原文:towardsdatascience.com/automated-feature-engineering-in-python-5733426530bf

机器学习 | Python | 数据科学

使用 Upgini 增强数据集的新功能的指南

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 David Farrugia

·发表于 Towards Data Science ·阅读时间 5 分钟·2023 年 5 月 2 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Alina Grubnyak 提供,来自 Unsplash

任何数据科学家或机器学习专业人士最重要的技能之一是从任何给定的数据集中提取更深层次和更有意义的特征。这个概念,更常被称为特征工程,可能是建模机器学习算法时最强大的技巧之一。

从数据中学习涉及大量的工程工作。虽然现代高级工具如 sklearn 已经将大部分复杂性抽象出来,但仍然需要深入理解数据,并将其塑造为你想要解决的问题。

提取更好的特征有助于为模型提供额外(且潜在更强)的业务领域和影响因素的基础关系。

不用说,特征工程是非常耗时和费力的。它需要大量的创造力、技术专长,并且在大多数情况下,还需要反复试验。

我最近发现了一个新工具,Upgini。与当前大型语言模型(LLM)的趋势相符,Upgini 利用 OpenAI 的 GPT LLM 来自动化我们数据集的整个特征工程过程。

在本文中,我们将介绍 Upgini 包并讨论其功能。

本文中,我们将使用亚马逊优质食品评论数据集(根据 CC0:公共领域许可)。

## 亚马逊优质食品评论

分析 ~500,000 条来自 Amazon 的食品评论

www.kaggle.com](https://www.kaggle.com/datasets/snap/amazon-fine-food-reviews?sort=votes&source=post_page-----5733426530bf--------------------------------)

欲了解更多关于 Upgini 包的信息,可以访问其 GitHub 页面:

[## GitHub - upgini/upgini: 机器学习数据搜索库 → 轻松找到并添加相关特征…

机器学习的数据搜索库 → 轻松从数百个相关特征中找到并添加到你的 ML 流水线中…

github.com](https://github.com/upgini/upgini/tree/main?source=post_page-----5733426530bf--------------------------------)

使用 Upgini 入门

首先,我们可以通过 pip 直接安装 Upgini:

pip install upgini

我们还加载了我们的数据集:

import pandas as pd
import numpy as np

# read full data
df_full = pd.read_csv("/content/Reviews.csv")
# convert Time to datetime column
df_full['Time'] = pd.to_datetime(df_full['Time'], unit='s')
# re-order columns
0df_full = df_full[['Time', 'ProfileName', 'Summary', 'Text', 'HelpfulnessNumerator', 'HelpfulnessDenominator', 'Score' ]]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结果数据的片段 — 作者提供的图像

我们还筛选了数据集,以包括帮助度超过 10 且发布于 2011–01–01 之后的评论。

df_full = df_full[(df_full['HelpfulnessDenominator'] > 10) & 
                  (df_full['Time'] >= '2011-01-01')]

我们还将 Helpfulness 转换为 0.50 比例的二进制变量。

df_full.loc[:, 'Helpful'] = np.where(df_full.loc[:, 'HelpfulnessNumerator'] / df_full.loc[:, 'HelpfulnessDenominator'] > 0.50, 1, 0)

最后,我们创建了一个新列 — combined — 将摘要和文本连接成一个单列。我们也借此机会删除任何重复项。

df_full["combined"] = f"Title: {df_full['Summary'].str.strip()} ; Content: {df_full['Text'].str.strip()}"
df_full.drop(['Summary', 'Text', 'HelpfulnessNumerator', 'HelpfulnessDenominator' ], axis=1, inplace=True)
df_full.drop_duplicates(subset=['combined'], inplace=True)
df_full.reset_index(drop=True, inplace=True)

使用 Upgini 进行特征搜索和增强

我们现在准备开始搜索新特征。

根据 Upgini 文档,我们可以使用 FeaturesEnricher 对象开始特征搜索。在该 FeaturesEnricher 内,我们可以指定一个 SearchKey(即,我们要搜索的列)。

我们可以搜索以下列类型:

  • 电子邮件

  • 胸针

  • IP 地址

  • 电话

  • 日期

  • 日期时间

  • 国家

  • 邮政编码

让我们将这些导入 Python。

from upgini import FeaturesEnricher, SearchKey

我们现在可以开始特征搜索。

enricher = FeaturesEnricher(search_keys={'Time': SearchKey.DATE})
enricher.fit(df_full[['Time', 'ProfileName', 'Score', 'combined']], df_full['Helpful'])

一段时间后,Upgini 向我们展示了一个搜索结果列表 — 可能相关的特征以增强我们的数据集。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

找到的特征片段。作者提供的图像

似乎 Upgini 计算了每个找到的特征的 SHAP 值,以衡量该特征对数据和模型质量的整体影响。

对于每个返回的特征,我们也可以直接查看并访问其来源。

该包还评估了模型在原始和增强数据集上的表现。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

增强后获得的结果。作者提供的图像

在这里我们可以看到,通过添加增强特征,我们成功地稍微提高了模型的表现。诚然,这一表现提升微不足道。

使用 GPT 模型进行特征生成

深入挖掘文档,似乎 FeaturesEnricher 还接受另一个参数 — generate_features。

generate_features 允许我们为文本列搜索并生成特征嵌入。这听起来非常有前景。我们确实有文本列 — combined 和 ProfileName。

Upgini 连接了两个 LLM 到一个搜索引擎——来自 OpenAI 的 GPT-3.5 和 GPT-J——来自 Upgini 文档

让我们进行这个数据丰富化吧?

enricher = FeaturesEnricher(
    search_keys={'Time': SearchKey.DATE}, 
    generate_features=['combined', 'ProfileName']
    )
enricher.fit(df_full[['Time','ProfileName','Score','combined']], df_full['Helpful'])

Upgini 为我们找到 222 个相关特征。每个特征我们会得到其 SHAP 值、来源以及在我们数据中的覆盖情况报告。

这一次,我们还可以注意到我们有一些生成的特征(即文本 GPT 嵌入特征)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

生成的文本嵌入特征的示例。图片由作者提供

那么评估性能如何?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

评估指标。图片由作者提供。

使用新生成的特征,我们看到预测性能有了巨大的提升——提升了 0.1。最棒的是这一切都是完全自动化的!

鉴于我们观察到的巨大的性能提升,我们绝对想保留这些特征。我们可以按以下方式进行:

df_full_enrich = enricher.transform(df_full)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结果数据集。图片由作者提供

结果是一个由 11 个特征组成的数据集。从现在开始,我们可以像处理任何其他机器学习任务一样进行。

结论

Upgini 提供了很多潜力。我仍在尝试其功能,并熟悉其不同的功能——但到目前为止,它证明非常有用——尤其是那个 GPT 功能生成器!

告诉我你的结果吧!

参考文献

亚马逊美食评论数据集由斯坦福网络分析项目提供,授权为 CC0:公有领域。

[## 亚马逊美食评论

分析 ~500,000 条来自亚马逊的食品评论

www.kaggle.com](https://www.kaggle.com/datasets/snap/amazon-fine-food-reviews?sort=votes&source=post_page-----5733426530bf--------------------------------)

你喜欢这篇文章吗?每月 $5,你可以成为会员,解锁对 Medium 的无限访问。你将直接支持我和你在 Medium 上的其他喜欢的作家。所以非常感谢!

[## 通过我的推荐链接加入 Medium - David Farrugia

独家访问我所有的 ⚡premium⚡ 内容和 Medium 上的无限制内容。通过请我喝杯咖啡来支持我的工作…

david-farrugia.medium.com](https://david-farrugia.medium.com/membership?source=post_page-----5733426530bf--------------------------------)

想要联系我吗?

我很想听听你对这个话题的看法,或者关于 AI 和数据的任何内容。

如果你想联系我,请发邮件到 davidfarrugia53@gmail.com

Linkedin

使用 GitHub Actions 进行自动化 Python 应用程序测试

原文:towardsdatascience.com/automated-python-application-testing-using-github-actions-79606f3f9eb2

如何在push命令上运行自动测试

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Philip Wilkinson, Ph.D.

·发布于Towards Data Science ·6 分钟阅读·2023 年 3 月 21 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由Roman Synkevych 🇺🇦拍摄,发布在Unsplash

测试你的应用程序是任何软件开发或数据科学工作流程中的关键步骤。测试可以确保代码按预期工作,减少错误或漏洞的可能性,提高软件的整体质量和可靠性。

然而,在某些情况下,测试可能会成为负担,你或其他人可能会忘记在提交到仓库之前运行测试套件。这时,通过 GitHub Actions 自动化测试工作流程可以减少手动工作,确保一致的测试,并能够及早发现问题。

在本文中,我将讲解如何设置 GitHub Action 工作流程以自动化应用程序测试。这包括创建 GitHub Action 工作流程、设置触发事件、创建要运行的作业,并为你的仓库添加徽章以显示测试是否通过。到最后,你将拥有一个完全自动化的测试工作流程,可以向世界展示你的代码是否按预期工作!

什么是 GitHub Action?

根据 GitHub 提供的描述:

GitHub Actions 使得自动化所有的软件工作流程变得简单,现在拥有世界级的 CI/CD。从 GitHub 直接构建、测试和部署你的代码。

这意味着 GitHub Actions 是由 GitHub 提供的自动化平台,专注于自动化软件开发工作流程。

Action 本身是可以作为 GitHub Actions 工作流程的一部分执行的代码单元。其目的是自动化由 GitHub 仓库中的事件触发的特定任务或工作流程。

重要的是,GitHub Action 可以用任何语言编写,可以在任何操作系统上运行,并可以通过 GitHub API 与存储库中的代码进行交互。它们可以用于各种任务,包括自动化最新构建的部署、更新代码库中的数据集,以及我们的目的——测试推送到主分支的最新内容。

创建 GitHub Action。

创建 GitHub Action 是一个相对简单的过程,首先是在你的 GitHub 存储库中创建一个新目录。这以一个文件夹标题.github/workflows的形式存在,GitHub 会识别这个文件夹包含我们希望 GitHub 执行的操作。

GitHub Actions 使用描述我们希望 GitHub 执行的操作的 YAML 文件。这意味着在.github/workflows文件夹中,我们需要创建一个 YAML 文件。现在我们可以称之为python-app.yml,并在文件中给它一个名称:

name: Python application

这是我们将基于此构建来运行测试套件的基础。

设置触发事件。

文件创建完成后,告知 GitHub 我们希望它运行某些操作,我们需要告诉 GitHub 我们希望何时进行。这是通过在 YAML 文件中使用on关键字指定触发事件来完成的。

在测试时,你通常希望在对应用进行任何更改时运行完整的应用测试套件,以确保所做的更改不会引入任何系统漏洞。根据 Git 的最佳实践,这通常在两个点上:

  • 任何推送到main应用分支的操作。

  • main应用分支的任何拉取请求。

这是因为你的应用程序的最新部署通常应该来自你的存储库的main分支。在我们的 YAML 文件中,这可以使用以下内容指定:

 on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

permissions:
  contents: read

这里使用push关键字指定我们希望在推送到main分支时运行该操作,并使用pull_request关键字指定我们希望在向主分支发起拉取请求时也运行测试套件。

这确保了主分支上的任何更改在部署之前都经过全面测试,并且在更改公开时会运行。

创建要运行的作业。

现在我们已经告诉 GitHub 我们希望何时运行一个操作,我们需要实际告诉它我们希望运行什么。这是通过使用jobs关键字来完成的,它指定了作为 GitHub Action 的一部分将要运行的作业。

在这个job中,我们需要指定三个主要内容:

  • 我们希望运行的作业名称。

  • 我们希望工作流运行的平台。

  • 工作流中我们希望执行的steps

这首先通过使用jobs:关键字及我们想要进行的工作的名称来完成。现在我们可以简单地称之为build

build关键字之后,我们需要指定我们希望工作运行的平台。在我们的案例中,我们可以指定runs-on: ubuntu-latest,假设 Linux 是我们测试套件的合适平台。

然后我们指定一系列步骤,我们希望在这个 job 中进行。要运行我们的测试套件,我们需要:

  • 将代码库检出到运行平台

  • 在环境中设置 Python

  • 安装运行测试套件所需的依赖项

  • 运行测试套件本身

这可以通过以下命令完成:

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python 3.10
      uses: actions/setup-python@v3
      with:
        python-version: "3.10"
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    - name: Test with pytest
      run: |
        pytest

解释这些步骤:

  • uses: actions/checkout@v3 告诉运行器我们想要使用 actions/checkout@v3 功能,这会将代码库的代码检出到作业的工作区。

  • name: Set up Python 3.10 创建一个步骤,设置运行器上的 Python 环境以使用 3.10 版本。

  • name: Install dependencies 安装项目所需的依赖项,包括 requirements.txt 文件中指定的那些。

  • name: Test with pytest 使用 pytest 命令运行测试套件,如果测试未通过则会使作业失败。

为此,我们使用 name 键将步骤拆分,这意味着我们可以清楚地识别在工作流中哪个点(如果有的话)失败。然后我们可以使用这些名称快速修复任何问题,并创建一个如下图所示的作业工作流。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者提供的图片

向你的代码库添加徽章

创建上述文件将告诉 GitHub 我们想要为我们的代码库运行测试工作流,但任何查看我们代码库的人不会立即看到这一点。为了解决这个问题,我们可以创建一个徽章,它将出现在我们的 README Markdown 文档中,清晰地显示我们的测试正在通过。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者提供的图片

这可以让任何新用户一目了然地知道主分支上的构建是稳定的,并且应用程序已被测试。此徽章的语法如下:

![example workflow](https://github.come/<OWNER>/<REPOSITORY>/actions/workflows/<WORKFLOW_FILE>/badge.svg

对于我当前开发的代码库,这转化为:

[![Python application](https://github.com/PhilipDW183/flask_petrol_map/actions/workflows/python-app.yml/badge.svg)](https://github.com/PhilipDW183/flask_petrol_map/actions/workflows/python-app.yml)

我还添加了一个链接到工作流文件,以便查看代码库的人也可以清楚地看到这个徽章所表示的内容。

结论

测试你的代码是任何软件工程或数据科学工作流的关键部分,但它也可能是一个容易在推送更改到主分支之前被忘记的步骤。为了简化这个过程并确保所有开发者之间测试的一致性,你可以创建一个 GitHub Action 来自动化你的测试工作流。在上面的文章中,我们展示了如何通过几个简单的步骤将其添加到你自己的代码库中。一个重要的部分是告诉你应用程序的新用户你已经测试了你的应用程序,这可以以你可以添加到 README 文件中的徽章形式呈现。

我的代码库中可以找到测试工作流的示例:

github.com/PhilipDW183/flask_petrol_map

使用 CleanLab 自动检测数据集中的标签错误

原文:towardsdatascience.com/automatically-detecting-label-errors-in-datasets-with-cleanlab-e0a3ea5fb345?source=collection_archive---------3-----------------------#2023-07-22

一则关于人工智能和错误分类的巴西联邦法律的故事

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 João Pedro

·

关注 发表在 Towards Data Science ·10 分钟阅读·2023 年 7 月 22 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Gustavo Leighton 提供,来自 Unsplash

引言

几周前,当我在进行个人项目的数据集搜索时,我偶然发现了巴西众议院开放数据门户网站,这里包含了大量的数据——包括议员的费用、政党元数据等——所有这些数据都可以通过一个不错的 API 获取。

几小时的搜索和检查后,有一些非常有趣的事情引起了我的注意:所有由议员提出的法律的汇编,包括它们的‘ementas’(简要摘要)、作者、年份,更重要的是,它们的主题(健康、安全、金融等)——由议会文献和信息中心(Centro de Documentação e Informação da Câmara)分类。

我的脑海中闪现出一个灵光——“我将创建一个监督分类管道来 预测法律的主题使用其摘要*,探索机器学习的一些基础设施方面,如使用 DVC 的数据版本控制或类似的东西*。”我迅速编写了一个脚本,收集了一个包含超过 60,000 条法律的大型数据集,时间跨度从 1990 年到 2022 年。

我已经稍微涉猎过司法和立法数据,所以我有一种感觉这个任务不会很难。但是,为了更轻松些,我选择仅分类法律提案(LP)是否涉及“纪念和纪念日期”(二分类)。理论上,这应该很简单,因为文本非常简单:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

原始摘要和 ChatGPT 的字面翻译 - I。图片由作者提供。

但是,无论我尝试了什么,我的性能在 f1 分数上始终未能超过~0.80,且(正类的)召回率相对较低,为 0.5–0.7。

当然,我的数据集高度不平衡,这一类别占数据集总量的不到 5%,但还有更多因素。

经过一些调查,使用基于正则表达式的查询检查数据,查看错误分类记录后,我发现了几个错误标记的例子。通过我粗略的方法,我发现了~200 个假阴性,占“真实”正例的~7.5%和我数据集的 0.33%,还没有提到假阳性。见下图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

错误分类的例子。图片由作者提供。

这些例子影响了我的验证指标——“它们可能有多少个?我需要手动搜索错误吗?

然而,Confident Learning 作为Clean Lab Python 包的形式出现,来拯救我了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Clean Lab 标志。图片来自GitHub

什么是 Confident Learning?

正确标记数据是任何监督机器学习项目中最耗时且最昂贵的步骤之一。像众包、半监督学习、微调等技术尝试减少收集标签的成本或减少模型训练中对这些标签的需求。

幸运的是,我们已经在这个问题上领先一步。我们有专业人士提供的标签,可能是具备足够专业知识的政府工作人员。但我以粗略正则表达式处理的非专业视角一旦超出我的性能预期,就能发现错误。

关键点是:数据中还有多少错误?

检查每一条法律是不现实的——需要一种 自动 检测 错误标签 的方法,这就是 Confident Learning 的作用。

总结一下,它使用从模型概率预测中收集的统计数据来估计数据集中的错误。它可以检测噪声、离群值,以及——本篇文章的主要内容——标签错误

我不会详细介绍 CL,但有一篇很好的文章涵盖了它的主要要点,还有一个来自 CleanLab 创始人的YT 视频谈论它在该领域的研究。

让我们看看它在实践中是如何工作的。

数据

数据来自巴西众议院开放数据门户,包含 1990 年至 2022 年的法律提案(LP)。最终的数据集包含约 60K LPs。

单个 LP 可能与多个主题相关,例如健康和金融,这些信息也可以在开放数据门户中找到。为了更方便处理,我通过将每个单独的主题二值化到单独的列中来编码主题信息。

如前所述,本篇文章使用的主题是“致敬和纪念日期”。我选择它是因为它的 ementas 非常简短且简单,因此标签错误很容易识别。

数据和代码可以在项目的 GitHub 仓库中找到。

实现

我们的目标是自动修复“致敬和纪念日期”中的每一个标签错误,并使这个帖子以一个干净、整洁的数据集作为结束,准备好用于机器学习问题。

设置环境

运行这个项目所需的是经典的 ML/Data Science Python 包(Pandas, Numpy 和 Scikit-Learn)+ CleanLab 包。

cleanlab==2.4.0
scikit-learn==1.2.2
pandas>=2.0.1
numpy>=1.20.3

只需安装这些要求,我们就可以开始了。

使用 CL 检测标签错误

CleanLab 包自带识别许多数据集问题的能力,如离群值和重复/接近重复的条目,但我们只对 标签错误 感兴趣。

CleanLab 使用由机器学习模型生成的概率,这些概率代表了条目被标记为某个标签的信心。如果数据集有 n 个条目和 m 个类别,那么这将由一个 n x m 的矩阵 P 表示,其中 P[i, j] 代表第 i 行属于类别 j 的概率。

这些概率和“真实”标签被用在 CleanLab 的内部以估计错误。

让我们练习一下:

导入包

import numpy as np
import pandas as pd

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.ensemble import RandomForestClassifier

from sklearn.model_selection import train_test_split, cross_val_score, cross_val_predict
from sklearn.model_selection import GridSearchCV, StratifiedKFold
from sklearn.pipeline import Pipeline

from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from sklearn.metrics import confusion_matrix, classification_report

from cleanlab import Datalab

RANDOM_SEED = 214
np.random.seed(RANDOM_SEED)

加载数据中…

df_pls_theme = pd.read_parquet(
    '../../data/proposicoes_temas_one_hot_encoding.parquet'
)

#              "Tributes and commemorative dates"
BINARY_CLASS = "Homenagens e Datas Comemorativas"
IN_BINARY_CLASS = "in_" + BINARY_CLASS.lower().replace(" ", "_")

df_pls_theme = df_pls_theme.drop_duplicates(subset=["ementa"])
df_pls_theme = df_pls_theme[["ementa", BINARY_CLASS]]
df_pls_theme = df_pls_theme.rename(
    columns={BINARY_CLASS: IN_BINARY_CLASS}
)

首先,让我们生成概率。

正如 CleanLab 文档中提到的,为了实现更好的性能,生成的概率必须 基于样本外记录(‘非训练’数据)。这是很重要的,因为模型在预测训练数据上的概率时,通常会过于自信。生成样本外概率的最常用方法是使用 K-Fold 策略,如下所示:

y_proba = cross_val_predict(
    clean_pipeline, 
    df_pls_theme['ementa'], 
    df_pls_theme[IN_BINARY_CLASS],
    cv=StratifiedKFold(n_splits=5, shuffle=True, random_state=RANDOM_SEED), 
    method='predict_proba', 
    verbose=2,
    n_jobs=-1
)

注意:重要的是要了解类别分布 —— 因此使用了 StratifiedKFold 对象。所选类别在数据集中所占比例不足 5%,一种天真的采样方法可能会导致模型在不正确平衡的数据集上生成低质量的概率。

CleanLab 使用一个名为 Datalab 的类来处理其错误检测任务。它接收包含我们数据的 DataFrame 和标签列的名称。

lab = Datalab(
    data=df_pls_theme,
    label_name=IN_BINARY_CLASS,
)

现在,我们只需将先前计算的概率传递给它……

lab.find_issues(pred_probs=y_proba)

……开始查找问题

lab.get_issue_summary("label")

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

就这么简单。

get_issues(”label”) 函数返回一个 DataFrame,包含 CleanLab 为每条记录计算的指标和指标。最重要的列是 ‘is_label_issue’ 和 ‘predicted_label’,分别表示记录是否存在标签问题以及可能的正确标签。

lab.get_issues("label")

我们可以将这些信息合并到原始 DataFrame 中,以检查哪些示例是有问题的。

# Getting the predicted errors
y_clean_labels = lab.get_issues("label")[['predicted_label', 'is_label_issue']]

# adding them to the original dataset
df_ples_theme_clean = df_pls_theme.copy().reset_index(drop=True)
df_ples_theme_clean['predicted_label'] = y_clean_labels['predicted_label']
df_ples_theme_clean['is_label_issue'] = y_clean_labels['is_label_issue']

我们来看几个例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对我来说,这些法律显然与致敬和纪念日期相关;然而,它们并没有被适当地分类为这些。

很好!—— CleanLab 能够在我们的数据集中找到 312 个标签错误,但现在该怎么办?

这些错误可以是手动检查以进行修正的对象(以主动学习的方式)或立即修正(假设 CleanLab 做得对)。前者更耗时,但可能会导致更好的结果,而后者更快,但可能会导致更多错误。

无论选择哪条路径,CleanLab 都将记录的劳动量从 60K 减少到几百条 —— 在最坏的情况下。

但有一个陷阱。

我们怎么能确保 CleanLab 找到了数据集中的所有错误?

实际上,如果我们运行上述管道,但将错误修正为真实标签,CleanLab 将会发现更多错误……

错误更多,但希望比第一次运行的错误少。

我们可以重复这个逻辑任意次数:找出错误,修正错误,用新假定的更高质量标签重新训练模型,再次找出错误……

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

迭代修正错误。图片由作者提供。

希望在一些交互之后,错误的数量将会是零。

使用 CleanLab 迭代修正错误

要实现这个想法,我们只需在循环中重复上述过程,下面的代码正是这样做的:

让我们来回顾一下。

在每次迭代中,OOS 概率是按照之前展示的方式生成的:使用cross_val_predict方法和 StratifiedKFold。当前的概率集(每次迭代中)用于构建一个新的 Datalab 对象并发现新的标签问题。

发现的问题与当前数据集合并并修复。

我选择了将修复后的标签作为新列附加的策略,而不是替换原始列。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

附加修复后的标签。图片由作者提供。

LABEL_COLUMN_0 是原始标签,LABEL_COLUMN_1 是修复 1 次的标签列,LABEL_COLUMN_2 是修复 2 次的标签列,以此类推……

除了这个过程之外,还计算并存储了常规分类指标,以备后续检查。

经过 8 次互动(约 16 分钟),过程完成了。

结果

下表显示了在过程中的性能指标。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在 8 次迭代中,数据集中发现了总计393 个标签错误。正如预期的那样,发现的错误数量随着每次迭代的增加而减少。

有趣的是,这个过程在仅仅 6 次迭代中就能够“收敛”到一个“解决方案”——在最后 2 次迭代中错误数保持为 0。这是一个很好的迹象,说明在这种情况下,CleanLab 的实现是稳健的,并且没有发现任何可能导致振荡的‘偶然’错误。

尽管错误的数量仅占数据集的 0.6%,f1 分数从 0.81 提高到了 0.90,约 11%。这可能是由于类别高度不平衡,因为新的 322 个正标签总共占原始正样本的约 12%。

但 CleanLab 真的能够发现有意义的错误吗?让我们检查几个例子看看它们是否有意义。

假阴性已修复

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

原始总结和 ChatGPT 的逐字翻译 — II. 图片由作者提供。

上述文本确实类似于“致敬和纪念日期”,这表明它们应该被适当地分类为此类 — 指向 CleanLab

假阳性已修复

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

原始总结和 ChatGPT 的逐字翻译 — III. 图片由作者提供。

在这种情况下我们有一些错误,第 2 和第 4 条规则不是假阳性。虽然不是很好,但还算可以。

我重复进行了这个检查采样新‘固定’规则的操作几次,总的来说,CleanLab 在检测假阴性方面表现几乎完美,但对假阳性有点困惑。

现在,即使我们可能没有一个完美标记的数据集,我也更自信现在用它来训练机器学习模型了。

结论

机器学习领域长期以来受困于模型质量差和计算能力不足,但这种情况已经过去。现在,大多数机器学习应用的真正瓶颈是数据。不是原始数据,而是经过精炼的数据——具有良好标签、格式规范、噪音或异常值较少的数据。

因为无论模型多么庞大和强大,无论你在管道中混入多少统计和数学,这些都无法拯救你免于计算机科学的最基本法则:垃圾进,垃圾出。

这个项目见证了这一原则——我测试了几个模型、深度学习架构、采样技术和向量化方法,最终发现问题出在基础上:我的数据是错误的。

在这种情况下,投资于数据质量技术成为创建成功机器学习项目的关键方面。

在这篇文章中,我们探讨了 CleanLab,这个包帮助我们检测和修复数据集中的错误标签。它不仅显著提高了数据集的质量,而且以自动、可重复且廉价的方式完成——无需人工干预。

我希望这个项目能帮助你更好地理解自信学习和 CleanLab 包。正如往常一样,我并不是这些主题的专家,我强烈建议你进一步阅读,以下是一些参考文献。

感谢您的阅读!😉

参考文献

所有代码都可以在这个 GitHub 仓库中找到。

使用的数据 — 开放数据门户联邦议会. [开放数据 — 法律 nº 12.527]

除非另有说明,所有图像均由作者创建。

[1] Cleanlab. (无日期). GitHub — cleanlab/cleanlab: 标准的数据中心 AI 包,用于处理混乱的真实世界数据和标签的数据质量和机器学习。 GitHub.

[2]计算样本外预测概率的交叉验证 — cleanlab. (无日期).

[3] Databricks. (2022 年 7 月 19 日). CleanLab: 用于发现和修复 ML 数据集中的错误的 AI [视频]. YouTube.

[4]常见问题 — cleanlab. (无日期).

[5] Mall, S. (2023 年 5 月 25 日). 标签错误是否不可避免?自信学习是否有用?Medium.

[6] Northcutt, C. G. (2021). 自信学习:估计数据集标签的不确定性. arXiv.org.

使用 Terraform 自动管理数据管道基础设施

原文:towardsdatascience.com/automatically-managing-data-pipeline-infrastructures-with-terraform-323fd1808a47?source=collection_archive---------9-----------------------#2023-05-02

我知道你去年夏天做的手动工作

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 João Pedro

·

查看 发表在 Towards Data Science ·15 分钟阅读·2023 年 5 月 2 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 EJ Yao 提供,来源于 Unsplash

介绍

几周前,我写了一篇关于 使用本地和 AWS 工具开发数据管道 的文章。这篇文章是我最近努力推出更多云导向数据工程文章的一部分。

然而,当我在脑海中回顾这篇文章时,我注意到一个大问题:手动工作

每当我开发一个新项目,无论是真实的还是虚构的,我总是试图减少配置环境的摩擦(安装依赖项、配置文件夹、获取凭据等),这就是为什么我总是使用 Docker 的原因。通过 Docker,我只需传递一个 docker-compose.yaml 文件 + 几个 Dockerfile,您就能够通过一个命令创建与我完全相同的环境 —— docker compose up。

然而,当我们想要使用云工具(如 S3、Lambda、Glue、EMR 等)开发新的数据项目时,Docker 无法帮助我们,因为组件需要在提供商的基础设施中实例化,并且有两种主要的方法可以实现这一点:在 UI 上手动操作或通过服务 API 进行编程。

例如,您可以在浏览器上访问 AWS UI,搜索 S3 并手动创建一个新的存储桶,或者编写 Python 代码通过 AWS API 创建相同的实例。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在前面提到的帖子中,我详细描述了如何通过 AWS Web 界面手动创建所需的组件的步骤。结果如何?即使尽可能简化(甚至省略部分内容!),帖子也耗时 17 分钟,比我通常所需的多了 7 分钟,充满了说明应访问哪个屏幕,点击哪里以及选择哪些设置的截图。

除了成本高、混乱且耗时外,这仍然容易出现人为错误,这可能会在每月账单中带来更多麻烦甚至不愉快的惊喜。绝对是一个令人不愉快的过程。

这正是 Terraform 要解决的问题类型。

不是赞助内容。

Terraform 是什么?

Terraform 是一种基础设施即代码(IaC)工具,以自动化和编程方式管理云提供商中的基础设施。

在 Terraform 中,期望的基础设施是通过一种称为 HCL(HashiCorp 配置语言)的声明性语言来描述的,其中指定了组件,例如一个名为“my-bucket”的 S3 存储桶以及一个位于 us-east-1 区域、运行 Ubuntu 22 的 EC2 服务器。

Terraform 通过调用云提供商的服务 API 将描述的资源实现。除了创建之外,它还能够销毁和更新基础设施,仅添加/删除从当前状态转移到期望状态所需的资源,例如如果请求创建 4 个 EC2 实例,则如果已存在 2 个实例,则仅创建 2 个新实例。这种行为是通过 Terraform 将基础设施的实际状态存储在状态文件中来实现的。

因此,可以更加敏捷和安全地管理项目的基础设施,因为它消除了配置每个单独资源所需的手动工作。

Terraform 的目标是成为一个与云平台无关的基础设施即代码(IaC)工具,因此它使用标准化的语言来调解与云提供商 API 的交互,从而不需要学习如何直接与它们交互。在这一点上,HCL 语言还支持变量操作和一定程度的‘流控制’(条件语句和循环),允许在资源创建中使用条件和循环,例如,创建 100 个 EC2 实例。

最后但同样重要的是,Terraform 还允许基础设施版本控制,因为它的纯文本文件可以被 git 轻松操作。

实施

如前所述,本文旨在自动化我之前文章中的基础设施创建过程。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

总结一下,开发的项目旨在创建一个数据管道,从巴西的 ENEM(国家高中考试,直译)测试中提取问题,使用 MEC(教育部)网站上提供的 PDF。

这个过程涉及三个步骤,由本地 Airflow 实例控制。这些步骤包括将 PDF 文件下载和上传到 S3 存储,通过 Lambda 函数从 PDF 中提取文本,以及使用 Glue Job 将提取的文本分割成问题。

请注意,为了使这个管道正常工作,需要创建并正确配置许多 AWS 组件。

0. 设置环境

本项目中使用的所有代码都可以在这个GitHub 仓库中找到。

你需要一台安装了 Docker 的机器和一个 AWS 账户。

第一步是为 Terraform 配置一个新的 AWS IAM 用户,这将是唯一在 AWS 网页控制台中执行的步骤。

创建一个对 S3、Glue、Lambda 和 IAM 具有完全访问权限的新 IAM 用户,并为其生成代码凭证。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是对一个用户来说大量的权限,所以请妥善保管凭证。

我使用了完全访问权限,因为我现在想让事情更简单,但在处理凭证时总是考虑‘最小权限’的原则。

现在,回到本地环境。

在与docker-compose.yaml文件相同的路径下,创建一个*.env*文件并写入你的凭证:

AWS_ACCESS_KEY_ID=<YOUR_ACCESS_KEY_ID>
AWS_SECRET_ACCESS_KEY=<YOUR_SECRET_ACCESS_KEY>

这些变量将传递给 docker-compose 文件供 Terraform 使用。

version: '3'
services:
  terraform:
    image: hashicorp/terraform:latest
    volumes:
      - ./terraform:/terraform
    working_dir: /terraform
    command: ["init"]
    environment:
      - TF_VAR_AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
      - TF_VAR_AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
      - TF_VAR_AWS_DEFAULT_REGION=us-east-1

1. 创建 Terraform 文件

在同一个文件夹中,创建一个名为terraform的新目录。在其中,创建一个新的文件main.tf,这将是我们的主要 Terraform 文件。

当容器运行时,这个文件夹将被映射到容器内部,这样内部的 Terraform 就能看到这个文件。

2. 配置 AWS 提供商

我们需要做的第一件事是配置所使用的云提供商。

terraform {
  required_version = ">= 0.12"

  required_providers {
    aws = ">= 3.51.0"
  }
}

variable "AWS_ACCESS_KEY_ID" {
  type = string
}

variable "AWS_SECRET_ACCESS_KEY" {
  type = string
}

variable "AWS_DEFAULT_REGION" {
  type = string
}

provider "aws" {
  access_key = var.AWS_ACCESS_KEY_ID
  secret_key = var.AWS_SECRET_ACCESS_KEY
  region     = var.AWS_DEFAULT_REGION
}

这就是一个 Terraform 配置文件的样子——一组具有不同类型的块,每个块都有特定的功能。

terraform 块固定了 Terraform 本身和 AWS 提供程序的版本。

变量 正如名称所示——一个分配给名称的值,可以在代码中引用。

正如你可能已经注意到的,我们的变量没有分配值,那么发生了什么?答案在 docker-compose.yaml 文件中,这些变量的值是通过系统中的环境变量设置的。当变量值未定义时,Terraform 会查看环境变量 TF_VAR_<var_name> 的值并使用它。我选择了这种方法来避免硬编码密钥。

provider 块也是显而易见的——它引用了我们使用的云提供商并配置了其凭据。我们用之前定义的变量设置提供程序的参数(access_key、secret_key 和 region),并用 var.<var_name> 符号引用这些变量。

定义好这个块之后,运行:

docker compose run terraform init 

要设置 Terraform。

3. 创建我们的第一个资源:S3 存储桶

Terraform 使用 resource 块来引用基础设施组件,如 S3 存储桶和 EC2 实例,以及授予用户权限或将文件上传到存储桶等操作。

下面的代码为我们的项目创建一个新的 S3 存储桶。

resource "aws_s3_bucket" "enem-bucket-terraform-jobs" {
  bucket = "enem-bucket-terraform-jobs"
}

resource 定义遵循以下语法:

resource <resource_type> <resource_name> {
  argument_1 = "blah blah blah blah" 
  argument_2 = "blah blah blah"
  argument_3 {
    ...
  }
}

在上述情况下,“aws_s3_bucket”是资源类型,“enem-bucket-terraform-jobs”是资源名称,用于在文件中引用此资源(它不是 AWS 基础设施中的存储桶名称)。参数 bucket=“enem-bucket-terraform-jobs” 为我们的存储桶分配了一个名称。

现在,使用以下命令:

docker compose run terraform plan

Terraform 将比较当前的基础设施状态,并推断出需要做什么以实现 main.tf 文件中描述的期望状态。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因为这个存储桶还不存在,所以 Terraform 会计划创建它。

要应用 Terraform 的计划,运行

docker compose run terraform apply

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

仅凭这几条命令,我们的存储桶已经创建好了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

很简单,对吧?

要销毁存储桶,只需输入:

docker compose run terraform destroy

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后 Terraform 会处理其余的部分。

这些是将伴随我们直到帖子结束的基本命令:planapplydestroy。从现在开始,我们要做的就是配置 main.tf 文件,添加实现我们数据管道所需的资源。

4. 配置 Lambda 函数第一部分:角色和权限

现在进入 Lambda 函数定义部分。

这是我之前帖子中最棘手的部分之一,因为默认情况下,Lambda 函数已经需要一组基本权限,此外,我们还必须给它对之前创建的 S3 存储桶的读写权限。

首先,我们必须创建一个新的 IAM 角色。

# CREATE THE LAMBDA FUNCTION
# ==========================

# CREATE A NEW ROLE FOR THE LAMBDA FUNCTION TO ASSUME
resource "aws_iam_role" "lambda_execution_role" {
  name = "lambda_execution_role_terraform"
  assume_role_policy = jsonencode({
    # This is the policy document that allows the role to be assumed by Lambda
    # other services cannot assume this role
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      }
    ]
  })
}

在开发这些东西时,我强烈建议你首先在 ChatGPT、GitHub Copilot 或其他 LLM 朋友中询问你需要什么,然后查看提供商的文档,了解这种类型的资源如何工作。

上面的代码创建了一个新的 IAM 角色,并允许 AWS Lambda 函数假设它。下一步是将 Lambda Basic Execution 策略附加到该角色,以允许 Lambda 函数无错误地执行。

# ATTACH THE BASIC LAMBDA EXECUTION POLICY TO THE ROLE lambda_execution_role
resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
  role       = aws_iam_role.lambda_execution_role.name
}

上面代码中值得注意的一点是,我们可以引用资源属性将它们作为参数传递到新资源的创建中。在上述案例中,我们可以使用以下语法引用属性,而不是将‘*role’*参数硬编码为之前创建的角色‘lambda_execution_role_terraform’的名称:

<resource_type>.<resource_name>.<attribute>

如果你花时间查看资源的 Terraform 文档,你会注意到它有argumentsattributesArguments是你用来创建/配置新资源的参数,attributes是关于资源的只读属性,在资源创建后可用。

因此,attributes 被 Terraform 用来隐式管理资源之间的依赖关系,建立它们创建的适当顺序。

下面的代码为我们的 S3 桶创建一个新的访问策略,允许对其进行基本的 CRUD 操作。

# CREATE A NEW POLICY FOR THE LAMBDA FUNCTION TO ACCESS S3
resource "aws_iam_policy" "s3_access_policy" {
  name = "s3_access_policy"
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "s3:GetObject",
          "s3:PutObject",
          "s3:DeleteObject"
        ]
        Resource = aws_s3_bucket.enem-data-bucket.arn
      }
    ]
  })

# ATTACH THE EXECUTION POLICY AND THE S3 ACCESS POLICY TO THE ROLE lambda_execution_role
resource "aws_iam_policy_attachment" "s3_access_attachment" {
  name       = "s3_and_lambda_execution_access_attachment"
  policy_arn = aws_iam_policy.s3_access_policy.arn
  roles      = [aws_iam_role.lambda_execution_role.name]
}

同样,我们可以使用aws_s3_bucket.enem-data-bucket.arn引用这个属性,而不是硬编码桶的 ARN。

在正确配置 Lambda 角色之后,我们终于可以创建函数本身。

# CREATE A NEW LAMBDA FUNCTION
resource "aws_lambda_function" "lambda_function" {
  function_name = "my-lambda-function-aws-terraform-jp"
  role          = aws_iam_role.lambda_execution_role.arn
  handler       = "lambda_function.lambda_handler"
  runtime       = "python3.8"
  filename      = "lambda_function.zip"
}

lambda_function.zip文件是一个压缩文件夹,其中必须包含一个lambda_function.py文件,文件内有一个*lambda_handler(event, context)*函数。它必须与 main.tf 文件在同一路径上。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

# lambda_function.py
def lambda_handler(event, context):
    return "Hello from Lambda!"

5. 配置 Lambda 函数第 II 部分:附加触发器

现在,我们需要为 Lambda 函数配置触发器:它必须在每次新 PDF 上传到桶时执行。

# ADD A TRIGGER TO THE LAMBDA FUNCTION BASED ON S3 BUCKET CREATION EVENTS
# https://stackoverflow.com/questions/68245765/add-trigger-to-aws-lambda-functions-via-terraform

resource "aws_lambda_permission" "allow_bucket_execution" {
  statement_id  = "AllowExecutionFromS3Bucket"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.lambda_function.arn
  principal     = "s3.amazonaws.com"
  source_arn    = aws_s3_bucket.enem-data-bucket.arn
}

resource "aws_s3_bucket_notification" "bucket_notification" {
  bucket = aws_s3_bucket.enem-data-bucket.id

  lambda_function {
    lambda_function_arn = aws_lambda_function.lambda_function.arn
    events              = ["s3:ObjectCreated:*"]
    filter_suffix = ".pdf"
  }

  depends_on = [aws_lambda_permission.allow_bucket_execution]
}

这是一个需要指定资源之间显式依赖关系的情况,因为“bucket_notification”资源需要在“allow_bucket_execution”之后创建。

这可以通过使用depends_on参数轻松实现。

我们已经完成了 lambda 函数的设置,只需运行:

docker compose run terraform apply

Lambda 函数将被创建。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

6. 向 Glue 作业添加模块

我们的main.tf文件变得相当庞大,而且记住这只是一个简单的数据管道。为了增强组织性并减少其大小,我们可以使用模块的概念。

一个模块是一组在单独文件中分组的资源,可以被其他配置文件引用和重用。模块使我们能够抽象复杂的基础设施部分,使我们的代码更加可管理、可重用、组织良好,并且模块化

因此,我们不会在 main.tf 文件中编写创建 Glue 作业所需的所有资源,而是将它们放在一个 模块 中。

在 ./terraform 文件夹中,创建一个名为 ‘glue’ 的新文件夹,其中包含一个 glue.tf 文件。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后在文件中添加一个新的 S3 存储桶资源:

# INSIDE GLUE.TF
# Create a new bucket to store the job script
resource "aws_s3_bucket" "enem-bucket-terraform-jobs" {
  bucket = "enem-bucket-terraform-jobs"
}

回到 main.tf,只需引用这个模块:

module "glue" {
  source = "./glue"
}

并重新初始化 terraform:

docker compose run terraform init

Terraform 将重新启动其后端并用它初始化模块。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

现在,如果我们运行 terraform plan,它应该将这个新的存储桶包含在创建列表中:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用这个 模块,我们可以将创建作业的所有逻辑封装在一个单独的外部文件中。

AWS Glue 作业的一个要求是它们的作业文件存储在 S3 存储桶中,这就是为什么我们创建了“enem-bucket-terraform-jobs”。现在,我们必须上传作业文件本身。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

terraform 路径*,*我包含了一个 myjob.py 文件,这只是一个用于模拟此行为的空文件。要向存储桶上传新对象,只需使用“aws_s3_object”资源:

# UPLOAD THE SPARK JOB FILE myjob.py to s3
resource "aws_s3_object" "myjob" {
  bucket = aws_s3_bucket.enem-bucket-terraform-jobs.id
  key    = "myjob.py"
  source = "myjob.py"
}

从现在开始,只需实现 Glue 角色并创建作业本身。

# CREATE A NEW ROLE FOR THE GLUE JOB TO ASSUME
resource "aws_iam_role" "glue_execution_role" {
  name = "glue_execution_role_terraform"
  assume_role_policy = jsonencode({
    # This is the policy document that allows the role to be assumed by Glue
    # other services cannot assume this role
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "glue.amazonaws.com"
        }
      }
    ]
  })
}

# ATTACH THE BASIC GLUE EXECUTION POLICY TO THE ROLE glue_execution_role
resource "aws_iam_role_policy_attachment" "glue_basic_execution" {
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSGlueServiceRole"
  role       = aws_iam_role.glue_execution_role.name
}

不要那么快。我们必须确保这个作业对“enem-data-bucket”桶具有与 Lambda 函数相同的读写权限,,我们需要将 aws_iam_policy.s3_access_policy 附加到其角色*。*

但是,由于该策略是在主文件中定义的,我们不能直接在我们的模块中引用它

# THIS WILL RESULT IN A ERROR!!!!
# ATTACH THE THE S3 ACCESS POLICY s3_access_policy TO THE ROLE glue_execution_role
resource "aws_iam_policy_attachment" "s3_access_attachment_glue" {
  name       = "s3_and_glue_execution_access_attachment"
  policy_arn = aws_iam_policy.s3_access_policy.arn
  roles      = [aws_iam_role.glue_execution_role.name]
}

为了实现这种行为,我们必须将 access policy arn 作为 参数 传递给 模块,这非常简单。

首先,在 glue.tf 文件中,创建一个新的变量来接收这个值。

variable "enem-data-bucket-access-policy-arn" {
    type = string
}

返回主文件,在模块引用中传递一个值给这个变量。

module "glue" {
  source = "./glue"
  enem-data-bucket-access-policy-arn = aws_iam_policy.s3_access_policy.arn
}

最后,在 glue 文件中,使用变量的值在资源中。

# ATTACH THE THE S3 ACCESS POLICY s3_access_policy TO THE ROLE glue_execution_role
resource "aws_iam_policy_attachment" "s3_access_attachment_glue" {
  name       = "s3_and_glue_execution_access_attachment"
  policy_arn = var.enem-data-bucket-access-policy-arn
  roles      = [aws_iam_role.glue_execution_role.name]
}

现在,花点时间思考我们刚刚完成的事情的威力。通过 模块参数,我们可以创建完全参数化的复杂基础设施

上述代码不仅仅是为我们的流水线创建了一个特定的作业。只需更改 enem-data-bucket-access-policy-arn 变量的值,我们就可以创建一个新的作业来处理来自完全不同存储桶的数据。

这种逻辑适用于你想要的 任何 东西。例如,可以使用变量同时为开发、测试和生产环境创建一个完整的项目基础设施。

没有多言,剩下的就是创建 Glue 作业本身,这并不是什么新鲜事:

# CREATE THE GLUE JOB
resource "aws_glue_job" "myjob" {
  name     = "myjob"
  role_arn = aws_iam_role.glue_execution_role.arn
  glue_version = "4.0"
  command {
    script_location = "s3://${aws_s3_bucket.enem-bucket-terraform-jobs.id}/myjob.py"
  }
  default_arguments = {
    "--job-language" = "python"
    "--job-bookmark-option" = "job-bookmark-disable"
    "--enable-metrics" = ""
  }
  depends_on = [aws_s3_object.myjob]
}

我们的基础设施就完成了。运行 terraform apply 创建剩余的资源。

docker compose run terraform apply

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

并且 terraform destroy 来清除所有内容。

docker compose run terraform destroy

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

结论

我在发布有关使用云服务提供商创建数据管道的第二篇文章几天后,认识了Terraform,它彻底改变了我的想法。我立刻想到了为了设置项目所做的所有手动工作,展示过程的所有截图以及在需要重新生成过程时会困扰我梦魇的所有未记录细节。

Terraform 解决了所有这些问题。它简单易用,设置也简便,只需要一些 .tf 文件和提供者的凭据,我们就可以立即开始。

Terraform 解决了人们通常不太激动去思考的那种问题。在开发数据产品时,我们都关注性能、优化、延迟、质量、准确性以及产品的其他数据特定或领域特定方面。

不要误会,我们都学习应用我们更好的数学和计算知识来解决这些问题,但我们也需要考虑我们产品开发过程的关键方面,如可复现性、可维护性、文档化、版本控制、集成、模块化等等。

这些是我们软件工程师同事长期关注的方面,因此我们不必重复造轮子,只需从他们的最佳实践中学习一两件事情即可。

这就是为什么我在我的项目中始终使用 Docker,并且这也是为什么我可能会将 Terraform 添加到我的基本工具集中的原因。

希望本文帮助您理解这个工具 — Terraform — 包括其目标、基本功能和实际好处。与往常一样,我对本文提到的任何主题都不是专家,并强烈推荐进一步阅读,请参考以下参考资料。

谢谢你的阅读! 😉

参考文献

所有代码都可以在此 GitHub 仓库中找到。

使用的数据 — ENEM PDFs,[CC BY-ND 3.0],巴西政府教育部。

所有图片由作者创建,除非另有说明。

[1] 通过 Terraform 为 AWS Lambda 函数添加触发器。Stack Overflow。链接

[2] AWSLambdaBasicExecutionRole — AWS 管理策略链接

[3] Brikman, Y. (2022 年 10 月 11 日)。Terraform 技巧与窍门:循环、条件语句和陷阱。Medium[4] 创建资源依赖关系 | Terraform | HashiCorp Developer链接

[5] TechWorld with Nana. (2020 年 7 月 4 日)。在 15 分钟内解释 Terraform | Terraform 初学者教程 [视频]。YouTube

[6] Terraform Registry。AWS 提供者。 Link

AutoML — 让机器学习为您的模型选择加速

原文:towardsdatascience.com/automl-let-machine-learning-give-your-model-selection-a-jump-start-a318de373890

利用 AutoML 提高生产力

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Farzad Mahmoodinobar

·发表于 Towards Data Science ·6 分钟阅读·2023 年 2 月 13 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

人与机器,图由 DALL.E 2

我们每天使用机器学习(ML)来寻找问题的解决方案并做出预测,这通常包括通过探索性分析了解数据,随后进行数据清理,根据我们的最佳判断决定使用哪些 ML 模型来解决问题,然后进行超参数优化和迭代。但如果我们可以使用 ML 来解决所有这些步骤的更高级问题,甚至选择最佳模型,而不是我们手动完成这些重复且繁琐的步骤呢?AutoML 来满足这一需求!

在这篇文章中,我将展示如何仅用 3 行代码,AutoML 在不到 14 秒的时间内超越了我个人开发的预测 ML 模型(用于之前的文章)。

本文的目标不是提议我们不再需要科学家和机器学习从业者,因为我们有了 AutoML,而是要展示如何利用 AutoML 使我们的模型选择过程更高效,从而提高整体生产力。一旦 AutoML 为我们提供了各种机器学习模型家族的性能比较,我们可以继续任务并进一步微调模型以获得更好的结果。

让我们开始吧!

(除非另有说明,否则所有图像均由作者提供。)

[## 通过我的推荐链接加入 Medium - Farzad Mahmoodinobar

阅读 Farzad(以及 Medium 上的其他作者)每一篇文章。您的会员费用直接支持 Farzad 和其他…

medium.com

什么是 AutoML?

  • 自动化机器学习或 AutoML 是自动化数据清理、模型选择、训练、超参数优化,甚至有时模型部署的机器学习工作流的过程。AutoML 最初旨在使机器学习对非技术用户更易于访问,并且随着时间的推移,它已发展成一个即使对于经验丰富的机器学习从业者也可靠的生产力工具。

  • 现在我们了解了 AutoML 是什么,让我们继续看看它的实际应用。

- 实施

  • 我们将首先快速实施 AutoML,使用AutoGluon,然后将结果与我在关于线性回归(下方链接)中开发的模型进行比较,以便我们可以将 AutoML 的结果与我的结果进行比较。

  • ## 线性回归 — 预测机器学习建模的奥卡姆剃刀

- 使用 Python 进行线性回归的机器学习建模

  • towardsdatascience.com

  • 为了使比较有意义,我们将使用来自UCI 机器学习库(CC BY 4.0)的相同汽车价格数据集。您可以从此链接下载清理后的数据,并按照代码逐步操作。

  • 如果这是你第一次使用 AutoGluon,你可能需要在你的环境中安装它。我为 Mac(Python 3.8)使用 CPU 遵循的安装步骤如下(如果你使用的是不同的操作系统,请访问这里获取简单的说明):

pip3 install -U pip
pip3 install -U setuptools wheel
pip3 install torch==1.12.1+cpu torchvision==0.13.1+cpu torchtext==0.13.1 -f https://download.pytorch.org/whl/cpu/torch_stable.html
pip3 install autogluon
  • 现在 AutoGluon 已准备好使用,让我们导入我们将使用的库。
# Import libraries
import pandas as pd
from sklearn.model_selection import train_test_split
from autogluon.tabular import TabularDataset, TabularPredictor

# Show all columns/rows of the dataframe
pd.set_option("display.max_columns", None)
pd.set_option("display.max_rows", None)
  • 接下来,我们将数据集读入 Pandas 数据框。
# Load the data into a dataframe
df = pd.read_csv('auto-cleaned.csv')
  • 然后,我们将数据分为训练集和测试集。我们将使用 30%的数据作为测试集,其余部分将作为训练集。在此阶段,为了可比性,我将确保我们使用与我在其他关于线性回归的帖子中使用的相同的random_state = 1234,这样我们这里创建的训练集和测试集将与我在那篇帖子中创建的相同。
# Split the data into train and test set
df_train, df_test = train_test_split(df, test_size=0.3, random_state=1234)

print(f"Data includes {df.shape[0]} rows (and {df.shape[1]} columns), broken down into {df_train.shape[0]} rows for training and the balance {df_test.shape[0]} rows for testing.")
  • 运行上述代码的结果是:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 正如我们所见,数据包括 25 列中的 193 行。一列是“价格”,这是我们希望预测的目标变量,其余是用于预测目标变量的自变量。

  • 让我们查看数据的前五行,以便理解数据的样貌。

# Return top five rows of the data frame
df.head()
  • 结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来,我们详细讨论 AutoGluon。首先,我们将创建一个字典,其中包含希望 AutoGluon 在本次练习中使用和比较的模型。以下是这些模型的列表:

  • GBM: LightGBM

  • CAT: CatBoost

  • XGB: XGBoost

  • RF: 随机森林

  • XT: 极端随机树

  • KNN: K 最近邻

  • LR: 线性回归

然后,我们进入我承诺的三行代码。这些代码将完成并对应以下步骤:

  1. 训练(或拟合)模型到训练集

  2. 使用训练好的模型为测试集创建预测

  3. 创建模型评估结果的排行榜

让我们编写代码。

# Run AutoGluon

# Create a dictionary of hyperparameters for the models to be included
hyperparameters_dict = {
    'GBM':{}, 
    'CAT':{},
    'XGB':{},
    'RF':{}, 
    'XT':{}, 
    'KNN':{},
    'LR':{},
    }

# 1\. Fit/train the models
autogluon_predictor = TabularPredictor(label="price").fit(train_data=df_train, presets='best_quality', hyperparameters=hyperparameters_dict)

# 2\. Create predictions
predictions = autogluon_predictor.predict(df_test)

# 3\. Create the leaderboard
autogluon_predictor.leaderboard(silent=True)

结果:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

比较各种机器学习模型评估结果的排行榜

就这样!

让我们更详细地查看排行榜。

在最终结果中,名为“model”的列显示了我们在模型字典中包含的模型名称,共有八个(注意行号范围为 0 到 7,总计 8)。名为“score_val”的列是均方根误差(RMSE)乘以 -1(AutoGluon 通过乘以 -1 使得较高的数值表示更好)。模型按从最佳到最差的顺序排列在表格中。换句话说,“WeightedEnsemble_L2”是本次练习中最好的模型,RMSE 约为 2,142。

现在,让我们看看这个数字与我在关于 线性回归 的文章中创建的机器学习模型评估结果相比如何。如果你访问那篇文章并搜索 MSE,你会发现 MSE 约为 6,725,127,相当于 RMSE 约为 2,593(RMSE 只是 MSE 的平方根)。将这个数字与排行榜中的“score_val”列进行比较,显示我的模型比 AutoGluon 尝试的 4 个模型要好,但比前 4 个模型差!记住,我花了相当多的时间进行特征工程和创建那个模型,而 AutoGluon 仅用 3 行代码在 13 秒多一点的时间内找到了 4 个更好的模型!这就是 AutoML 在实践中的力量。

实现笔记本

我在创建这篇文章时使用的笔记本如下提供。欢迎下载、复制并进行尝试。

结论

在这篇文章中,我们讨论了什么是 AutoML 以及它如何帮助有或没有机器学习建模背景的用户。对于不熟悉机器学习的非技术用户,AutoML 降低了入门门槛,使这些用户能够创建强大的机器学习模型。另一方面,科学家和机器学习从业者等技术用户可以利用 AutoML 提供的功能,通过在短时间内尝试各种模型来提高生产力。然后,技术用户可以花时间对 AutoML 算法的最佳推荐进行微调或改进。

谢谢阅读!

如果你觉得这篇文章有帮助,请关注我在 Medium 上的账号并订阅以获取我的最新文章!

避免神经网络过拟合:深度探讨

原文:towardsdatascience.com/avoid-overfitting-in-neural-networks-a-deep-dive-b4615a2d9507

学习如何实施正则化技术以提升性能并防止神经网络过拟合

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Riccardo Andreoni

·发布于 Towards Data Science ·10 分钟阅读·2023 年 11 月 30 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来源:unsplash.com.

在训练深度神经网络时,往往很难在训练集和验证集上获得相同的性能。验证集上明显较高的误差是过拟合的明显标志:网络在训练数据上过于专业化。本文提供了绕过这一问题的综合指南。

神经网络的过拟合

在处理任何机器学习应用时,清楚了解模型的偏差和方差是非常重要的。在传统机器学习算法中,我们讨论偏差与方差权衡,即在最小化模型的方差偏差之间的斗争。

为了减少模型的偏差(即模型由于错误假设产生的误差),我们需要一个更复杂的模型。相反,减少模型的方差(模型捕捉训练数据变化的敏感度)则意味着更简单的模型。显然,在传统机器学习中,偏差与方差的权衡源于同时需要一个更复杂和更简单的模型的冲突。

深度学习时代,我们拥有工具来仅仅减少模型的方差,而不影响模型的偏差,或者反过来,在不增加方差的情况下减少偏差。

在探讨用于防止神经网络过拟合的不同技术之前,明确什么是高方差或高偏差是很重要的。

以图像识别为例,考虑一个识别图片中是否有熊猫的神经网络。我们可以自信地评估,一个人可以以接近 0%的误差完成这个任务。因此,这对图像识别网络的准确率来说是一个合理的基准。在对训练集进行训练并在训练集和验证集上评估其性能后,我们可能会得到以下不同的结果:

  1. 训练误差 = 20% 和 验证误差 = 22%

  2. 训练误差 = 1% 和 验证误差 = 15%

  3. 训练误差 = 0.5% 和 验证误差 = 1%

  4. 训练误差 = 20% 和 验证误差 = 30%

第一个示例是高偏差的典型实例:训练集和验证集上的误差都很大。相反,第二个示例则遭遇了高方差,当处理模型未学习到的数据时准确率要低得多。第三个结果代表了低方差和偏差,模型可以被认为是有效的。最后,第四个示例展示了高偏差和高方差的情况:不仅训练误差在与基准比较时很大,而且验证误差也更高。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供。

从现在起,我将介绍几种正则化技术,用于减少模型对训练数据的过拟合。这些技术对前面例子中的第 2 和第 4 种情况很有帮助。

L1 和 L2 正则化

类似于经典的回归算法(线性、逻辑、分式等),L1 和 L2 正则化也被用来防止高方差神经网络的过拟合。为了使本文简洁明了,我不会回顾 L1 和 L2 正则化在回归算法中的工作原理,但你可以查看这篇文章获取更多信息。

L1 和 L2 正则化技术的理念是约束模型的权重使其变小或将一些权重缩小到 0。

考虑一个经典深度神经网络的成本函数 J:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

成本函数 J 显然是每层 1, …, L 的权重和偏差的函数。m 是训练样本的数量,ℒ是损失函数。

L1 正则化

在 L1 正则化中,我们将以下项添加到成本函数 J 中:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其中矩阵范数是网络中每层 1, …, L 的权重绝对值的总和:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

λ 是正则化项。它是一个必须仔细调整的超参数。λ 直接控制正则化的影响:随着 λ 的增加,对权重收缩的影响会更严重。

L1 正则化下的完整成本函数变为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于 λ=0,L1 正则化的效果为零。相反,选择一个过大的 λ 值将过度简化模型,可能导致欠拟合网络。

L1 正则化可以被视为一种神经元选择过程,因为它会将一些隐藏神经元的权重变为零。

L2 正则化

在 L2 正则化中,我们添加到成本函数中的项如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这种情况下,正则化项是每个网络层的权重的平方范数。这个矩阵范数被称为 Frobenius 范数,显式地计算方法如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

请注意,相对于第 l 层的权重矩阵有 n^{[l]} 行和 n^{[l-1]} 列。

最后,L2 正则化下的完整成本函数变为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

再次,λ 是正则化项,当 λ=0 时,L2 正则化的效果为零。

L2 正则化使权重的值趋近于零,从而得到一个更简单的模型。

L1 和 L2 正则化如何减少过拟合?

L1 和 L2 正则化技术对训练数据的过拟合有积极的影响,原因有二:

  • 一些隐藏单元的权重变得更接近(或等于)0。结果是,它们的影响被削弱,最终的网络更简单,因为它更接近于较小的网络。正如引言中所述,较简单的网络更不容易过拟合。

  • 对于较小的权重,隐藏神经元激活函数的输入 z 也变得更小。对于接近 0 的值,许多激活函数表现为线性

第二个原因并不简单,需要进一步展开。考虑一个双曲正切(tanh)激活函数,其图形如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由作者提供。

从函数图中我们可以看到,如果输入值 x 很小,函数 tanh(x) 的表现是几乎线性的。当 tanh 被用作神经网络隐藏层的激活函数时,输入值为:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于小权重 w 也接近零

如果神经网络的每一层都是线性的,我们可以证明整个网络表现为线性。因此,约束一些隐藏单元以模拟线性函数,会导致网络更简单,从而有助于防止过拟合。

更简单的模型通常无法捕捉训练数据中的噪声,因此,过拟合的情况较少

Dropout

dropout 正则化的理念是随机移除网络中的某些节点。在训练过程开始之前,我们为网络中的每个节点设置一个概率(假设 p = 50%)。在训练阶段,每个节点有 p 被关闭的概率。dropout 过程是随机的,并且是为每个训练样本单独执行的。因此,每个训练样本可能会在不同的网络上进行训练。

与 L2 正则化类似,dropout 正则化的结果是一个更简单的网络,而更简单的网络会导致一个更简单的模型。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

简单网络上 dropout 的效果。图像由作者提供。

实际中的 dropout

在这一简短的部分中,我展示了如何在实践中实现 Dropout 正则化。我将通过几行简单的代码(python)进行说明。如果你只对正则化的一般理论感兴趣,可以轻松跳过这一部分。

假设我们已经将网络第 4 层的激活值存储在NumPy数组a4中。首先,我们创建辅助向量d4

# Set the keeping probability
keep_prob = 0.7
# Create auxiliary vector for layer 4
d4 = np.random.rand(a4.shape[0], a3.shape[1]) < keep_prob

向量d4的维度与a4相同,并根据概率keep_prob包含TrueFalse的值。如果我们设置了 70%的保留概率,这就是给定隐藏单元被保留的概率,因此,在d4的某个元素上具有True值的概率。

我们将辅助向量d4应用于激活a4

# Apply the auxiliary vector d4 to the activation a4
a4 = np.multiply(a4,d4)

最后,我们需要通过keep_prob值来缩放修改后的向量a4

# Scale the modified vector a4
a4 /= keep_prob

这个最后的操作是为了补偿层中单位的减少。在训练过程中执行此操作可以让我们在测试阶段不应用 dropout。

Dropout 是如何减少过拟合的?

Dropout 的效果是暂时将网络转变为一个更小的网络,我们知道较小的网络更简单且不易过拟合

以上图所示的网络为例,关注第二层的第一个单元。由于某些输入可能由于 dropout 而被临时关闭,这个单元不能总是依赖它们。因此,隐藏单元被鼓励将其权重分散到各个输入上。权重的分散效果是降低权重矩阵的平方范数,从而产生一种类似于 L2 正则化的效果。

设置保留概率是有效 dropout 正则化的一个基本步骤。通常,保留概率是为神经网络的每一层单独设置的。对于权重矩阵较大的层,我们通常设置较小的保留概率,因为在每一步中,我们希望相对于较小的层保留比例较少的权重。

其他正则化技术

除了 L1/L2 正则化和 dropout,还有其他正则化技术。其中两种是数据增强早停

从理论上讲,我们知道在更多数据上训练网络对减少高方差有积极影响。由于获取更多数据通常是一项艰巨的任务,因此数据增强是一种技术,它在某些应用中几乎可以“免费”获得更多数据。在计算机视觉中,数据增强通过翻转、缩放和移动原始图像提供了更大的训练集。在数字识别的情况下,我们还可以对图像施加扭曲。

早停,顾名思义,涉及在最初定义的迭代次数之前停止训练阶段。如果我们将成本函数绘制在训练集和验证集上,并以迭代次数为函数进行观察,我们会发现,对于过拟合模型,训练误差总是持续减少,但验证误差可能在某些迭代次数后开始增加。当验证误差停止减少时,这正是停止训练过程的时机。通过更早地停止训练,我们迫使模型变得更简单,从而减少过拟合。

结论

总之,L1 和 L2 正则化技术是解决神经网络中过拟合问题的不可或缺的工具。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者提供的图像。

L1 正则化通过惩罚无关特征来引入稀疏性,这在简化模型方面表现有效。另一方面,L2 正则化通过惩罚权重的平方大小,促进了更平滑的模型,从而降低了极端值的风险。

Dropout 是一种在训练阶段随机停用神经元的动态技术,它增强了模型的泛化能力。它防止对特定神经元的过度依赖,从而促进了更强大的网络。

然而,这些技术也有其权衡之处。虽然正则化方法能有效缓解过拟合,但它们可能会无意中限制模型捕捉数据中复杂模式的能力。真正的挑战在于选择正则化强度和模型复杂性之间的正确平衡。

为了进一步了解,我会在参考部分添加一些精彩资源。我强烈建议查看这些资源,以便深化对主题的理解。

如果你喜欢这个故事,考虑关注我,以便及时了解我即将发布的项目和文章!

这是我过去的一些项目:

## 先进的降维模型简单化

学习如何高效地应用最先进的降维方法,并提升你的机器学习…

towardsdatascience.com ## 使用深度学习生成奇幻名字:从零开始构建语言模型

语言模型能否创造出独特的奇幻角色名字?让我们从零开始构建它。

towardsdatascience.com ## 使用深度学习生成奇幻名字:从零开始构建语言模型

了解如何将先进的降维方法高效应用于机器学习任务。

towardsdatascience.com

参考文献

避免在职业转型进入数据科学时的倦怠

原文:towardsdatascience.com/avoiding-burnout-during-a-career-change-into-data-science-e40c351a34f9

不,你不需要掌握 27 种编程语言或拥有 512 个作品集项目。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Matt Chapman

·发布于 Towards Data Science ·10 分钟阅读·2023 年 6 月 15 日

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 Jackson Simmer 提供,来源于 Unsplash

最近,数据科学和人工智能的热潮使很多人开始转行进入这个领域。

然而,如果你在同时要兼顾另一份全职工作时尝试这样做,很容易感到倦怠。最开始时本来是可以完全应对的(晚上上的在线课程),但很快就会变得令人不堪重负,没过多久,你就会发现自己在用 pandas DataFrame 写购物清单,醒来时满头大汗地哼着 StatQuest 的主题曲。

相信我,我也经历过这种情况。

在过去的两年里,我已经转行进入数据科学领域,虽然有时这确实令人兴奋,但有时我也会感到任务的规模让我感到完全不知所措。

如果你是一名有志成为数据科学家的新手,真棒!你正走在一条非常激动人心的道路上,我真心相信数据科学领域是现在最令人兴奋的地方之一。但请注意——在这段旅程中,你可能会遇到极大的困难,并且这将极大地占用你的时间。

通过这篇文章,我将分享一些我在职业转型成功的同时避免倦怠的顶级建议。如果你厌倦了像“努力工作”或“休息一下”这样的陈词滥调,想听听来自实际经历者的观点,那么这篇文章适合你。

那么,什么是倦怠呢?

世界卫生组织 (WHO) 将职业倦怠定义为:

一种被认为是由于慢性工作压力未能成功管理而产生的综合症。它具有三个维度:

(1) 能量枯竭或疲惫感;

(2) 与工作的心理距离增加,或对工作的负面情绪或愤世嫉俗感;

(3) 职业效能降低

如果你像我一样,可能会惊讶于世界卫生组织(WHO)甚至承认职业倦怠。但是,正如上述定义所证明的那样,如果不加以控制,它可能会造成巨大的医疗和社会问题。

有趣的是,职业倦怠似乎目前在所有行业中都是一个问题——美国心理学会甚至认为 COVID-19 大流行将职业倦怠和压力水平推到了历史新高。虽然职业倦怠存在于所有职业中,但在数据科学家中尤其严重有特殊原因。这是因为许多人进入这一领域的独特方式。

职业倦怠在数据科学领域是个问题吗?

当你开始遇到其他数据科学家时,不久之后你会发现一个模式。许多数据科学家是通过有意的职业转型进入这个行业的,而不是简单地“误入此行”或在本科阶段学习了数据科学。例如数据科学家泽亚·LT,她在 32 岁时放弃了警察职业去追求数据科学:

我没有数学、计算机科学或编程背景,因此学习曲线非常陡峭 […] 我不得不在作业和照顾幼儿之间 juggle。由于 COVID-19 大流行,远程学习也给我和我的家人带来了挑战。

泽亚的故事象征着许多人的故事,包括我自己。对我们中的许多人来说,数据科学在选择大学/工作选项时并不是我们知道的职业选项。我们只是后来才接触到这个领域,所以现在我们在全职工作或 juggling 家庭责任的同时,努力进行职业转型。我们完成了 9–5 的工作,然后还得挤出时间来进行学习和/或项目组合。

这使得日程安排非常紧张,并且容易导致倦怠。很容易在晚上工作到很晚,或者在周末或假期取消计划。我们向自己和亲人辩解这些模式,比如说“我需要提升个人发展”或者“这不算真正的工作”。

然而,问题在于,尽管编程课程和个人项目在短期内可能会感到有趣(例如,在某个晚上),如果不断重复,它们可能会逐渐变得令人疲惫。我的意思是真的令人疲惫。在短期内可持续的东西,迅速会在中长期内变得不可持续,你的“职业变换”可能会从一个有趣的个人发展活动变成一项让你远离生活中重要事务的苦差事。

在短期内可持续的东西,迅速会在中长期内变得不可持续

剧透警告:倦怠的风险从未消失

当你开始职业转变的旅程时,很容易通过思考彩虹尽头等待你的“金子”来激励自己:有趣的新职业、薪水的增加、简历上的“AI”字样。把目光固定在这些事物上可以帮助你克服象征性的痛苦,并为在 DataQuest 和 CodeAcademy 等网站上花费大量时间(和金钱)找到理由。

如果你是一个有志成为数据科学家的人,你可能会惊讶地发现,这种倦怠的风险永远不会真正消失,即使你达到了最初设定的“金子”。数据科学的世界以惊人的速度发展,我可以亲身告诉你,总会有新的东西需要学习,还有一份新的工作在地平线之外等待,只要你愿意努力。

(至少,这就是感觉)。

认识到这一点是重要的第一步,它突显了“奋斗文化”叙事中的问题,该叙事告诉我们要坚定不移地努力。如果总是有更多的东西要学,那么我们数据科学家——无论你是否找到了第一份工作——需要找出如何以可持续的方式进行职业发展。我们需要找出如何在我们追求的职业中玩好 无限游戏

提示 #1:认识到你不能(也不应该)学习所有东西,专注于关键事项

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片来自 Lena TaranenkoUnsplash

这可能让你感到震惊,但实际上你不需要知道所有的东西才能成为数据科学家。

我知道,对吧——令人震惊。

除非你打算组建一个单打独斗的数据科学团队,否则你的技能总会由公司更广泛的数据团队中的其他人来补充。在团队环境中,你不知道怎么做没关系,因为很可能会有其他人能够提供帮助。数据科学招聘经理知道这一点,这也是他们不会要求应聘者在入职前知道一切的原因。每个人都明白,你在工作中需要做一些学习,所以不要担心在申请工作之前需要学会所有东西。

当然,说起来容易做起来难,当我转行时,我发现很难确定哪些技能是“核心”的,哪些只是“可有可无”的。如果你是数据科学的新手,很容易陷入“分析瘫痪”,不确定具体该学习什么,结果是尝试了各种东西却没有真正投入。

如果你在这种情况下,我的建议和Renato Boemer的建议相同,他在三十多岁时转行进入数据科学:

选择 Python,继续前进。

是的,像 R、Spark、Julia 和 JavaScript 这样的语言在某些数据科学团队中可能都有用,但 Python 无疑是数据科学中最主流的语言。在我看来,它也是适合初学者的最佳语言,因为其语法和逻辑相对简单明了。

我想补充的一点是,你可能还应该学习 SQL。自 1979 年以来它就存在,并且不会很快消失——许多大型公司已经投入时间构建基于它的数据基础设施,它是开发者最喜欢的语言之一。此外,SQL 的好处在于它教会你如何关系性地思考数据,这是一种在数据科学中工作时非常难以解释但极其重要的认知技能。

一旦你掌握了这些语言的基础,开始做一些作品集项目,学习如何在 GitHub 上存储代码,并通过“实践中学习”。这无疑是让概念深入人心的最佳方式,也为面试和作品集提供了很好的素材。如果你对点子感到困惑,可以看看我写的这篇关于如何找到创意的文章:

## 如何找到独特的数据科学项目创意,使你的作品集脱颖而出

忘记 Titanic 和 MNIST 吧:选择一个独特的项目来提升你的技能,帮助你在人群中脱颖而出。

[towardsdatascience.com

但——这才是关键——在你准备申请第一份工作之前,这就是你需要做的全部。尽管你可能在网上看到相反的说法,但你不需要在成为数据科学家之前掌握线性代数和离散优化等内容。当然,很多来自数学背景的人在进入数据科学领域之前确实学过这些,但我不相信这些知识对大多数入门级工作来说真的那么必要。

如果你还不信服,你可能会发现,数据科学家在 AI/数据领域与研究科学家在这个领域的工作差异很大。研究科学家在很多方面更接近数学家和/或软件工程师。他们是在初创公司或大型科技公司工作,开发新的数据科学工具和算法,因此他们需要对基础数学和工程概念有非常深入的理解。相比之下,数据科学家往往更偏向于应用方向;这个角色更专注于解决商业问题,而不是开发全新的技术和方法。如果你想亲自验证这一点,可以尝试搜索一些研究科学家的职位,看看它们与数据科学家的职位有何不同。

我的观点是,如果你想成为数据科学家,没必要对所有基础数学或最前沿的技术和方法保持最新。别误会——你仍然需要有一定的了解(如果你从未听说过 ChatGPT,或者不知道矩阵/向量是什么,你会显得很傻),但除非你是专门为 NLP 角色招聘的,否则你可能不需要从第一天起就能描述 ChatGPT 的架构或了解 LSTM 的细节。所以减轻负担,不必担心学习所有内容。

提示 #2:每周至少休息一天

这是 古老智慧,我认为其中有很多道理。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片由 Toa Heftiba 提供,来源于 Unsplash

即使你当前的“课外”数据项目很有趣,每周按时按暂停键并休息一天仍然非常重要。去散步,和朋友聚会,学习编织篮子——天高任鸟飞!只要确保你为其他事物(或某人)留出时间。

投资于休息。认真对待。

为什么这如此重要?首先,因为在职业转型期间,容易被“我会在…时很开心”的叙事所吞噬,而忘记享受当下。但我在职业转型过程中学到的是:

牺牲时间关系永远不会值得。

如果你不强迫自己为朋友和家人腾出时间,这些往往是压力大的时候最先从你的日程中消失的。对于我来说,在转行的早期阶段,这一点尤为真实,当时我不断尝试挤出尽可能多的时间。

每周休息整天可能是保持理智和在数据领域提升技能时保持工作量可控的最有帮助的事。这迫使我认识到,我转行的最终目标真正是为了为我和我的家人创造更好的生活(因为我觉得这也是我的使命的一部分,但那是另一个故事),这帮助我意识到现在优先考虑与家人在一起是非常值得的,因为这才是最终目标。而且,它让我在一周的其他时间有了更多的精力,并帮助我在整年中保持了可持续的工作量。

所以,勇敢尝试吧!每周至少休息一天。我知道这说起来容易做起来难,但这种做法确实改变了我的旅程。

提示 #3:不要过度制作你的作品集

如果你读过我之前的内容,你会发现我非常喜欢制作作品集,因为它们在 帮助我找到数据科学工作方面发挥了重要作用。

不过,问题是,你不需要过度制作个人作品集。无论你的作品集多么出色,仅凭过去的个人项目,你永远不会真正找到工作——你还需要参加面试!作品集的目的只是为了让你有机会入门,并给招聘者一个你能做什么的概念。

就我个人而言,如果我现在从零开始制作作品集,我会目标设定为 3–5 个项目,并保持这样。再多的话就过头了。

3–5 个项目已经足够了

还有一件事……

这就是我的顶级建议,帮助你在职业转型期间避免职业倦怠!我希望这篇文章能帮助你从我的错误中学习,并巧妙地导航你正在经历的旅程。

如果你喜欢这篇文章,并且希望获得更多关于数据科学工作的提示和见解,考虑在 Medium 上关注我或 LinkedIn。不到 1% 的读者关注我,所以你这样做对我意义重大。

如果你想无限制地访问我所有的故事(以及 Medium.com 的其他内容),你可以通过我的 推荐链接注册,每月费用为 5 美元。与通过一般注册页面注册相比,这不会给你增加额外费用,并且支持我的写作,因为我会获得一小笔佣金。

感谢阅读!

2023 年值得掌握的精彩数据科学工具:数据分析版

原文:towardsdatascience.com/awesome-data-science-tools-to-master-in-2023-data-profiling-edition-29d29310f779?source=collection_archive---------0-----------------------#2023-02-22

数据工具回顾

5 个开源 Python 包用于 EDA 和可视化

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 Miriam Santos

·

关注 发表在 Towards Data Science ·15 分钟阅读·2023 年 2 月 22 日

这是一个专注于数据科学开源工具的系列专栏:每篇文章都关注一个特定主题,并向读者介绍一系列不同的工具,展示它们在真实世界数据集上的特性。 这一部分专注于数据分析并回顾了*ydata-profiling* *dataprep* *sweetviz* *autoviz** 和* *lux**。鼓励读者跟随教程: 我会参考所有项目的单独 GitHub 仓库,但工具的整理列表以及本文章中使用的 Google Colab 笔记本 可以在 awesome-data-centric-ai 仓库中找到。

数据不完善的世界中,精心设计的数据理解工具就是哲学家的石头。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

“多维”的哲学家石头:数据立方体。分析数据通常涉及旋转和扭曲数据集,以找到最有洞察力的视角。照片来自 aaron borisUnsplash

数据质量在我们的机器学习模型结果中发挥着至关重要的作用。一些 数据缺陷 可能严重影响模型的内部工作,使其无法应用(例如,数据缺失)。其他缺陷可能在模型开发阶段未被发现,并在模型部署到生产环境后带来不良后果(例如,类别不平衡、数据不足、数据集漂移)。

在经过长期艰苦的努力以产生更强健的机器学习模型之后,学术界和工程师们现在都在转向以数据为中心的人工智能范式。我们共同意识到数据可以成就或毁掉我们的模型,并且很多时候,如果数据聪明,问题可能通过“更简单”的模型得到解决。

但我们如何将数据从不完善变为聪明呢?

数据分析是数据理解的精髓

由于模型由数据驱动,而数据由人们整理,因此人们需要理解他们让模型处理的数据的特性。

数据分析与探索性数据分析的概念密切相关。然而,谈到分析数据时,我们倾向于将其与自动化报告——即“获取分析”——数据特性联系在一起,理想情况下,这能立即提醒我们潜在问题或进一步的问题。

更重要的是,数据分析是数据团队中所有角色必须掌握的一项重要技能,包括数据科学家、机器学习工程师、数据工程师和数据分析师。

“我们的填补方法返回了高偏差值,输入发生了变化吗?模型输出了无效预测,我们需要快速调整,它发生了什么?今天这个数据流完全崩溃了,出了什么问题?我需要这些结果在仪表板上,以便在下次会议中讨论,有人能给我一个当前数据状态的快照吗?”

这些只是数据团队在实际环境中面临的许多“数据难题”中的一部分。

幸运的是,可以借助数据分析工具将这些问题最小化。

让我们通过探索一个真实世界的用例来看看?准备好打开你的 Google Colabs 吧!

HCC 数据集……稍作修改!

在本文中,我将使用 HCC 数据集,该数据集是我在硕士论文期间亲自整理的。你可以在KaggleUCI Repository上找到它。随意使用它,该数据集已授权,我们只希望适当引用。

为了此次评审的目的,我从原始数据集中选择了一个特征子集,并通过人工引入一些问题进一步修改了数据。目的是查看不同的数据分析工具如何识别和表征这些问题。

这里是我们将使用的数据的详细信息:

  • 下面考虑了原始特征的子集:GenderAgeAlcoholHallmarkPSEncephalopathyHemoglobinMCVTotal_BilDir_BilFerritinHBeAgOutcome。本质上,我选择了一组具有和不具有缺失值的数值和分类(名义和二元)特征,一些类别有欠代表性,还有一些高度相关;

  • 原始的MCV包含一些缺失值,这些值在特征中被其他值替代(只是为了拥有另一个完整的数值特征,除了Age);

  • O2特征是人工引入的:它仅包含“999”值,代表数据采集或收集中的错误。想象一下,一个传感器发生故障,开始输出荒谬的值,或者数据采集人员决定用“999”编码他们的缺席;

  • Hallmark被修改了:我将其值与“A、B、C、D、(…)”编码连接,这可能代表了患者 ID 与实际标志结果的连接。这代表了数据处理或存储中的错误(如果你愿意,可以称之为“ETL 故障”);

  • HBeAg也被修改了。在这种情况下,我只是删除了所有“是”值。这可能模拟了缺失非随机机制,如果观察到,所有缺失值都会是“是”。

由于数据包含一些修改,我也已将其添加到存储库中。请记住,这纯粹是为了学术讨论:您可以在 Kaggle 或 UCI 存储库中访问完整且未修改的数据,如前所述。

现在,事不宜迟,让我们开始实际的代码吧!

1. ydata-profiling

你可能知道它为pandas-profiling,因为新名称仍然很新:简而言之,版本 4.0.0 现在还支持 Spark DataFrames,除了 Pandas DataFrames,因此它更名为YData Profiling

该包目前是探索性数据分析的热门选择。它的高效性和简单性似乎赢得了技术和非技术观众的喜爱,因为它能快速而直接地对数据进行可视化理解。

让我来展示如何让它迅速上手!首先,安装该包:

pip install ydata-profiling=4.0.0

然后,生成数据概况报告是直接的:

# Import libraries
import pandas as pd
from ydata_profiling import ProfileReport

# Load the data
df = pd.read_csv("hcc.csv")

# Produce and save the profiling report
profile = ProfileReport(df,title="HCC Profile Report")
profile.to_file("report.html")

报告迅速生成,内容包括数据集属性的一般概述、每个特征的汇总统计、交互和相关性图,以及缺失值和重复记录的有见地可视化:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

YData Profiling 报告。作者录屏。

然而,ydata-profiling最受赞誉的功能可能是自动检测潜在的数据质量问题

在处理我们没有任何先前洞察的新数据集时,这一点尤为重要。它节省了我们大量时间,因为它会立即突出数据不一致性和其他复杂的数据特征,这些特征我们可能希望在模型开发之前进行分析。

关于我们的用例,请注意以下警报的生成方式:

  • 常量:HBeAg 和 02;

  • 高相关性:总胆红素和直接胆红素,以及脑病和总胆红素之间的相关性;

  • 不平衡:脑病;

  • 缺失:血红蛋白、HBeAg、总胆红素、直接胆红素和铁蛋白的缺失数据百分比最高(接近 50%);

  • 均匀唯一高基数关于 Hallmark。

由于对数据质量问题的全面支持,ydata-profiling能够检测所有引入的不一致性,特别是它为同一特征生成多个不同的警报。

例如,Hallmark 如何同时引发高基数、唯一和均匀的警报?

这立即引发了红色警报,使数据科学家怀疑可能与某种 ID 有关。进一步检查该特征时,这种“数据气味”会变得相当明显:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

YData Profiling 报告:检查 Hallmark。作者图片。

HBeAg 也是如此:它引发了CONSTANTMISSING警报,这可能会在经验丰富的数据科学家脑海中响起警钟:更复杂的缺失机制可能在发挥作用。

ydata-profiling还具有其他几个有用的功能,如支持时间序列数据和数据集并排比较,我们可以利用这些功能来增强数据集上的一些数据质量转换,例如缺失数据插补。

为了进一步调查这个可能性,我对Ferritin进行了简单的插补(例如,均值插补),并生成了原始数据和插补数据之间的对比报告。结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

YData Profiling: 对比报告。作者录制的视频。

ydata-profiling的源代码、文档和几个示例可以在这个GitHub 仓库中找到。你可以使用这个Google Colab 笔记本复制上面的示例,并进一步探索包的附加功能

2. DataPrep

DataPrep还可以通过一行代码创建交互式数据分析报告。安装相当简单,模块导入后,通过调用create_report来生成报告:

pip install -U dataprep

import pandas as pd
from dataprep.eda import create_report

df = pd.read_csv("hcc.csv")
create_report(df)

就整体外观和感觉而言,dataprep似乎在之前的包基础上进行了广泛构建,包括类似的汇总统计和可视化(报告的相似性令人惊讶!):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

DataPrep Profiling Report。作者录制的视频。

然而,这个包的一个有用特性是更深入探索特征互动的能力

我们可以使用几种类型的图表探索特征之间的有趣互动(包括数值型和分类特征)。

这是探索几种特征类型之间关系的方法:

from dataprep.eda import plot

plot(df, "Age", "Gender") # Numeric - Categorical
plot(df, "Age", "MCV") # Numeric - Numeric
plot(df, "Gender", "Outcome") # Categorical - Categorical

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

DataPrep Profiling Report: 探索特征互动。作者录制的视频。

dataprep还允许调查缺失值的影响(比较删除缺失值前后的数据)在所有特征上的影响。

这是Ferritin缺失值处理影响的可视化:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

DataPrep Profiling Report: 缺失的铁蛋白影响。作者录制的视频。

你可以在相应的 Colab 笔记本 中探索所有生成的可视化。dataprepGitHub 上有很好的文档,也有一个 专门的网站,如果你想查看更多资源和细节。

3. SweetViz

类似于之前的工具,SweetViz 也通过生成简单的可视化和总结重要特征统计信息来提升 EDA。你可以按照以下步骤开始使用 sweetviz

pip install sweetviz

# Import libraries
import pandas as pd
import sweetviz as sv

# Load the data
df = pd.read_csv("hcc.csv")

# Produce and save the profiling report
report = sv.analyze(df)
report.show_html('report.html')

sweetviz 有一种更“复古”的外观,汇总统计信息的显示不如我们迄今评审的其他包那样整洁。

关于数据质量,它会提醒缺失值的存在及其对数据的影响(例如,根据缺失数据的百分比使用绿色、黄色和红色高亮显示)。其他不一致之处不会直接高亮显示,可能会被忽视(低相关值则在每个特征的详细信息中标出)。

除了“关联”矩阵,它并不专注于深入探索特征交互或缺失数据行为。

这是报告的外观和感觉:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sweetviz 分析报告。作者提供的屏幕录像。

然而,它的最大特点是围绕 可视化目标值比较数据集 构建的。

在这方面,sweetviz 的一个有趣用例是同时进行 目标分析(研究目标值如何与数据中的其他特征相关)同时比较 不同的数据集(例如,训练集与测试集)或 数据集内特征特征(例如,比较“男性”与“女性”组)。

这是调整“Outcome”特征以探索类别(“男性”和“女性”)并比较见解的方法:

# Create a 'Survival' feature based on 'Outcome'
df.Outcome = pd.Categorical(Outome)
df['Survival'] = df.Outcome.cat.codes

# Create a comparison report
comparison_report = sv.compare_intra(df, df["Gender"] == 'Male', ["Male", "Female"], 'Survival')
comparison_report.show_notebook()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Sweetviz 分析报告:比较“男性”和“女性”子组。作者提供的屏幕录像。

sweetviz 的所有文档都可以在这个 GitHub 仓库 中找到。请随时使用 这个笔记本 对数据进行进一步转换,并借助 这篇专门的帖子 探索其他用例。

4. AutoViz

AutoViz 是另一个简单直观的 EDA 包,提供广泛的可视化和自定义支持。

与之前的包类似,它的安装也非常简单,如下所示:

pip install autoviz

然后你可以导入该包,但autoviz不会自动显示图表,因此你需要在尝试对数据进行分析之前运行%matplotlib inline

from autoviz.AutoViz_Class import AutoViz_Class
%matplotlib inline

现在你可以开始了!运行以下命令将生成大量可视化图表,你可以在之后进行自定义和调整:

AutoViz_Class().AutoViz('hcc.csv')

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AutoViz 分析报告。作者录屏。

autoviz的有趣特点包括自动数据清理建议执行“监督”可视化的能力——即通过给定的目标特征对结果进行分类,这与我们在sweetviz中所做的类似。

数据清理建议在报告生成期间提供,如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AutoViz 分析报告:清理建议。作者提供的图像。

至于清理建议,autoviz做得非常好:

  • 它将Hallmark与“可能的 ID 列”关联,建议将其删除;

  • 它识别出多个缺失或偏斜的特征,如FerritinHemoglobinTotal_BilDir_BilEncephalopathyHBeAg

  • 它识别出HBeAgO2具有不变的值,并建议删除O2

生成的警报不如ydata-profiling生成的全面,并且不如autoviz直观(例如,autoviz展示了唯一值的热图,但其他警报如HIGH CARDINALITYUNIQUECONSTANT可能对指出我们面临的具体问题更有帮助)。

然而,我非常欣赏它在清理建议方面引入的可解释性,这对数据科学领域的新手无疑是一个有用的指南。

如果你想尝试我之前提到的“监督”分析,你首先需要定义一个depVar参数作为目标特征。在这种情况下,我将其设置为“结果”,但我也可以将其设置为“性别”,以获取类似于sweetviz返回的图表:

import pandas as pd
df = pd.read_csv("hcc.csv")

AV = AutoViz_Class()
dft = AV.AutoViz(
    filename="",
    sep="",
    depVar="Outcome",
    dfte=df,
    header=0,
    verbose=1,
    lowess=False,
    chart_format="png",
    max_rows_analyzed=200,
    max_cols_analyzed=30,
)

这是考虑到“结果”生成的报告:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

AutoViz 分析报告:比较“结果”类别。作者录屏。

你可以玩一下这个 Google Colab 笔记本,探索autoviz的其他功能。你还可以查看这篇帖子,其中详细介绍了这些功能,或者参考GitHub 上的文档

5. Lux

Lux 以可能最适合初学者的方式启用快速且简单的 EDA,因为它可以通过简单地创建 Pandas DataFrame 使用:一旦你安装它,只需打印出一个 DataFrame,它将自动推荐一组最适合发现数据中有趣趋势和模式的可视化。

从安装软件包并读取数据开始:

pip install lux

import lux
import pandas as pd
df = pd.read_csv("hcc.csv")
df

然后,你可以浏览一个互动小部件,选择最适合你需求的。它的外观如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Lux Profiling Report。作者录制的演示。

该软件包没有分析任何潜在的数据质量问题,分析也不是很全面,但仍涵盖了基础内容。

该小部件在 Pandas 和 Lux 之间切换,关注 3 个主要可视化:Correlation and Distribution 用于数值特征,Occurrence 用于分类特征。

一个可能被低估的功能是可以直接从小部件中导出或删除可视化,通过选择所需的图表。当生成快速报告时,这种简便性实际上非常有价值。

lux 还试图在 EDA 过程中支持我们。假设我们对进一步探索特定特征感兴趣,例如“PS”和“Encephalopathy”。我们可以指定你的“意图”,lux 将引导我们向潜在的下一步:

df.intent = ["PS", "Encephalopathy"]

新生成的推荐分为 EnhanceFilterGeneralize 标签。

Enhance tab 为“意图特征”添加了额外的可视化功能,实质上是探索额外维度可能引入的信息类型。

Filter tab 是不言而喻的:它保持意图特征不变,并在可视化中引入如 Gender = MaleOutcome = Alive 的过滤器。

最终,Generalize tab 显示意图特征,以确定是否可以得出更一般的趋势:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Lux Profiling Report:探索“意图”功能。作者录制的演示。

随意浏览 我的 Colab 笔记本 并进行你自己的示例操作。Lux文档页面GitHub 仓库 都相当全面,但可以查看 这篇文章 来填补任何额外的空白。

最终思考:是否有最佳方式?

公平地说,不能。列出的工具都有相似之处,同时也引入了不同的风格。

除了 lux 外,其他剩余的软件包对于基本的探索性数据分析都非常合适。

根据你的专业水平、特定用例或你希望通过数据实现的目标,你可能会想尝试不同的软件包,甚至将它们的功能结合起来。

总的来说,这就是我的看法:

  • ydata-profiling 是专业数据科学家希望掌握新数据集的最佳选择,因为它广泛支持自动数据质量警报。由于对 Spark DataFrames 的新支持,该软件包对于需要排查数据流的数据工程师以及需要理解模型为何表现不稳定的机器学习工程师也极其有用。对于需要了解数据行为的经验丰富的数据专业人员来说,这是一个极好的选择,特别是在数据质量方面。提供的可视化也是一个很好的资产,但该软件包在互动性方面还可以改进(例如,允许我们“鼠标悬停”在图表上并检查特定特征或相关值)。

  • dataprep 似乎是建立在 ydata-profiling 之上的,这意味着两个项目的路线图之间可能会存在不匹配(例如,后者在数据质量警报支持方面可能比前者更快地增加更多功能),尤其是在关注支持数据质量警报的方面。或者相反,这取决于我们感兴趣跟进哪些组件!然而,我确实喜欢那些启用互动的额外功能,但我会说在某些情况下,“少即是多”。如果你是经验丰富的数据科学家,你会知道更深入地研究哪些内容,哪些可以丢弃,但当你刚进入这个领域时就不一定如此。你可能会花费相当多的时间去理解为什么某些图表如果不具启发性(例如,数字-类别特征的折线图、数字-数字特征的箱线图)还会存在。然而,缺失值的单独图表(删除前后)确实很有用。我可以预见未来会使用它们来诊断一些缺失机制,特别是“随机缺失”,其中一个特征中的缺失值与另一个特征的观察值相关。

  • autoviz 是一个非常有趣的入门级数据科学工具。它提供了数据的全面描述,并报告了真正有用的清理建议。对于经验丰富的专业人士来说,这些建议可能不必要,但对于初学者来说,这些建议可能对数据准备过程至关重要。分析报告也非常全面,自动列出了特征之间所有可能的组合。虽然冗长,但这对缺乏经验的人来说是有帮助的,因为下一步只是浏览生成的图表,看看是否有一些“突出”的内容。代码不是特别友好,但对于初学者来说仍然容易理解,我特别喜欢“监督”分析:视觉效果干净美观,我绝对会在自己的研究中使用它们。

  • sweetviz 有一个非常有洞察力的功能,尽管它的设计可以更好。总体而言,报告看起来相当复古,质量警报也不是很直观(例如,为什么突出显示最低的相关性而不是最高的?)。然而,同时检查目标特征和子组的想法是我希望在其他软件包中看到的! 对于更复杂的数据集,我们需要同时分析超过 2、3 或 4 个维度的数据,跟踪目标值是极其有用的(在大多数情况下,这就是我们试图绘制的内容,对吧?)。我可以告诉你,HCC 数据集就是这样的情况:它是一种异质性疾病,在类似阶段的患者可以映射到不同的生存结果。我曾经不得不费尽周折才能快速而正确地可视化一些子集,这个工具在寻找这类见解并将其传达给照顾患者的医疗团队时会非常有帮助。

  • 最后,lux 可以作为学习工具,用于基本的数据探索,以及教学生或新手数据领域的统计学和数据处理基础知识:特征类型、图表类型、数据分布、正负相关性、缺失值表示(例如,nullNaN)。它是超低代码的完美工具,适合“试水”

所以,你看,似乎没有免费的午餐。我真诚地希望你喜欢这篇评论!反馈和建议总是受欢迎的:你可以给我留言,为仓库点赞并贡献,或者直接在数据中心人工智能社区与我联系,讨论其他数据相关的话题。再见,祝你科学研究愉快!

关于我

博士,机器学习研究员,教育者,数据倡导者,以及全能型人才。在 Medium 上,我撰写关于数据驱动的人工智能和数据质量的文章,旨在教育数据科学与机器学习社区如何从不完美的数据转变为智能数据。

数据驱动的人工智能社区 | GitHub | Google Scholar | LinkedIn

参考文献

  1. M. Santos, P. Abreu, P. J. García-Laencina, A. Simão, A. Carvalho, 一种基于集群的过采样方法以改善肝细胞癌患者的生存预测 (2015), 生物医学信息学杂志 58, 49–59。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值