TowardsDataScience 2023 博客中文翻译(十一)

原文:TowardsDataScience

协议:CC BY-NC-SA 4.0

为数据科学团队建立最佳实践的 6 种方法

原文:towardsdatascience.com/6-ways-to-build-best-practices-for-data-science-teams-ca9b83fb269d

为高绩效数据科学团队设定标准

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

·发表于 Towards Data Science ·阅读时间 7 分钟·2023 年 3 月 20 日

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

图片由 Marvin Meyer 提供,来源于 Unsplash

数据科学是一个将传统数学和统计学与大规模计算能力以及更现代的机器学习和深度学习技术相结合的领域,从数据中生成见解。

数据科学学科复杂,具有实验性,并且存在很大的不确定性。与软件工程等相关领域类似,数据科学团队需要以受控的方式处理代码开发。然而,除了这些,数据科学家还需要处理不断变化的数据,并执行可重复的实验,例如试验机器学习模型的新特性。

因此,无论你是一个单独工作的数据科学家,还是一个大团队共同工作,制定一套最佳实践标准都非常重要。这些标准将确保:

  • 一个数据科学家可以在稍后的时间重复他们自己的实验、模型或见解。

  • 团队中的其他数据科学家可以重复以上所有内容——如果你在维护生产中的模型,这一点尤其重要。

  • 单个数据科学家和其他团队成员都能在现有工作基础上进行构建,而不是重复相同的实验、代码、模型或分析。

在以下文章中,我将给出一些颇具个人观点的建议,说明如何以及使用什么来设定数据科学团队的最佳实践。然而,每个团队都是不同的,因此你可能需要调整这些建议以满足自己团队的具体需求。

这是我关于数据科学领导力系列文章中的第二篇。第一篇文章链接如下。

学习成为数据科学领导者

1. 代码标准

高质量的代码确保你的团队编写的代码易于他人阅读和理解。这有助于提高团队工作成果的可重现性和可扩展性。

代码应该保持清晰、结构良好,并尽可能模块化。选择共享的编码标准是一个好主意。如果你的团队使用 Python,那么 Google Python Style Guide 可以作为一个好的标准。编码风格可以通过使用如 PylintBlack 的工具,通过 linting 轻松地强制执行,作为开发过程的标准部分。

一个好的代码标准应该包括标准化的命名约定和用于代码文档的 doc 字符串。制定这些标准的目标应始终是使代码尽可能可读和易于理解,并减少团队的心理负担。一个好的编码标准会提高团队的效率,例如,如果代码始终遵循预期的风格,进行同行代码审查的速度会更快。

代码标准可以通过 持续集成 (CI) 检查自动化,作为你的 GitHub 工作流的一部分。

2. 虚拟环境

代码可重现性的一个重要部分是嵌入能够使团队成员编写的代码在任何其他计算机或云环境中运行的过程。

虚拟环境是实现这一点的常用技术。虚拟环境记录了与运行特定项目所需的依赖项(工具)及其版本相关的详细信息。

创建虚拟环境的常用工具包括 Poetry、PipenvConda。虽然它们的工作方式略有不同,但从高层次来看,虚拟环境通过创建和维护一个存储项目的 Python 版本和所有依赖项的文件来工作,然后使用该文件在任何机器上生成一个隔离的环境。

如果团队不能在不同的机器上精确重现相同的环境,那么在缺少原项目创建者的情况下,项目代码很可能无法在没有一些努力的情况下运行。

通常,每个项目有自己的虚拟环境是一个好做法。我建议团队内决定使用一个工具以保持一致性,并方便团队成员重现环境。例如,我自己的团队目前使用 Poetry 来管理我们所有项目的环境。

3. 版本控制

所有数据科学团队应使用版本控制工具,如 Github,以确保所有工作的副本安全地存储在你的笔记本电脑之外,并且可以以受控的方式对现有代码进行更改。

创建拉取请求(PR)流程以促进协作、确保输出质量和分享知识通常是一个好主意。在我看来,PR 应在项目生命周期中定期提出,并且应尽量避免非常大的 PR。尽可能多地获取代码和项目方向的第二意见,以避免大规模的重写或错误,是良好的做法。

一般来说,以下标准应适用于 Github 的使用:

  • 为分支设置标准化的命名约定。

  • 鼓励使用清晰和描述性的提交信息。

  • 为良好的PR 礼仪制定标准。

  • 每天提交代码。

  • 每两周至少提一次 PR,或者如果你的团队使用冲刺周期,则在每个冲刺结束时提 PR。

4. 组织良好的代码

团队中所有项目的一致文件夹结构将使其他团队成员更容易快速阅读和理解任何项目的代码。

网上有许多建议的数据科学文件夹结构的示例。我找到的可能最好的例子是Cookiecutter模板。然而,根据我的经验,文件夹结构在数据科学团队中差异很大,因为使用的具体工具、技术和任务会大大影响标准结构的要求。因此,我的建议是使用类似 Cookiecutter 的工具,但根据团队的需求进行调整。

我非常信奉 KISS(“保持简单,愚蠢”)设计原则,并且会选择最基本的文件夹结构以满足团队的需求。下方展示了我团队用于开发工作的文件夹结构。你可以看到我们选择了一个简单的结构,满足了我们非常特定的需求,但这不一定适用于其他团队。

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

我团队的文件夹结构。图片来源:作者。

5. 文档

良好的文档实践是确保团队工作可重复性和可复现性的另一种方式。文档应以标准方式记录,并且要详尽到足以确保对项目不熟悉的人能够理解运行任何代码,并复现和理解任何结果。

一般来说,我会在数据科学团队的最佳实践中包含以下类型的文档。

代码文档: 所有代码应附带理解和运行所需的最少文档。这包括为函数添加文档字符串,在项目文件夹或仓库中包含 README.md 文件,以及为存储在 Jupyter Notebooks 中的代码添加注释。

产品文档: 产品文档涉及与项目的开发、设计和结果相关的信息。通常,这些文档可能采用 Google 文档、Confluence 页面或 Miro 白板的形式。这类文档的最终用户通常是非技术性利益相关者和产品经理。

6. 组织良好的 notebooks

Jupyter Notebooks 的特性可能导致代码混乱、难以阅读和不可重现。因此,在使用 notebooks 时,遵循本文中已经概述的最佳实践,如版本控制和良好的代码风格,是至关重要的。然而,也需要添加一些与 notebook 使用特别相关的额外最佳实践。

以下是包含在你的 notebook 最佳实践中的一些良好标准列表。

  • 利用 notebook 中丰富的代码注释能力,包含标题、章节标题、注释、图像和图表,以使代码和结果尽可能易于理解。

  • 将所有导入语句放在 notebook 顶部的单个单元格中。

  • 确保数据源明确。这可能意味着在 notebook 中包含指向云存储桶或 SQL 查询的链接。

  • 保持 notebook 简单,尽量减少代码行数。在合适的地方将复杂的代码抽象为函数和模块,并确保删除任何冗余的代码。

由于其复杂和实验的特性,数据科学是一个在标准化方法和团队最佳实践中获益匪浅的领域。上述列出的所有最佳实践旨在确保团队项目的可重复性、可扩展性和可复现性。

此外,尽管最佳实践需要一些时间和精力来嵌入和遵守,但从长远来看,它们将节省大量时间和精力,避免重新运行和理解项目或重复已经完成的工作。

我上面列出的最佳实践并非详尽无遗,根据团队使用的工作类型和工具,你的最佳实践可能会有所不同。本文旨在作为最佳实践的入门指南,并应提供一些灵感,以帮助你开始为团队定义和设定自己的标准。

如果你想深入了解数据科学团队的最佳实践,我在本文底部列出了有用的进一步阅读资料。

感谢阅读!

有用的资源

IBM 数据科学最佳实践

Google Cloud 的最佳实践:提升任何使用 Jupyter Notebooks 开发者的工作体验

用于可重复 Jupyter Notebooks 的 4 个工具

组织数据科学项目的方案

从 Pandas 切换到雷电般快速的 Polars 并永不回头的 7 个简单步骤

原文:towardsdatascience.com/7-easy-steps-to-switch-from-pandas-to-lightning-fast-polars-and-never-return-b14c66fc85b9

最常见的 Pandas 操作的速查表翻译为 Polars

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

·发布于数据科学前沿 ·阅读时间 9 分钟·2023 年 4 月 3 日

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

图片由作者通过 Midjourney 提供

是时候说再见了!

Pandas 可以做任何事。几乎任何事。但(这真的是我无数次希望它可以有所不同的)它缺乏速度。Pandas 根本无法跟上今天数据集规模和复杂度增长的速度。

Pandas 的作者 Wes McKinney 表示,当他编写 Pandas 时,他有一个针对其库的经验法则:

拥有比数据集大小多 5 到 10 倍的 RAM。

也许你曾经对引入 Iris 数据集时的这一规则视而不见,但今天情况有所不同。你根本无法在 RAM坚决停留在 64GB 的情况下加载 100GB 的数据集(这在现代社会中已经很常见)。

当然,也有像 Dask 这样的优秀替代方案。但 Dask 并没有实现新的功能。它只是将现有的 Pandas 语法扩展到多个进程(线程)上,忽略了底层的性能和内存问题。

它将 Pandas 视为黑箱。请原谅我这样说,但这几乎就像是在猪身上涂口红一样。

Polars,本文的重点,是从头开始用 Rust 编写的,旨在修复 Pandas 的所有不足。在我上一篇文章中,我们已经看到它比即将推出的 Pandas 2.0(配备 PyArrow 后端)更快。

虽然那篇文章重点关注速度优势,这篇文章则更多地关注语法和功能,并展示了如何在七个简单步骤中从 Pandas 切换到 Polars,也许永远不会再切换回来。

0. 读写数据

尽管速度极其缓慢,CSV 仍然是存储数据的最流行文件格式之一。所以,让我们从 Polars 的read_csv函数开始吧。

除了明显的速度优势外,它只在参数数量(Pandas 的 read_csv 有 49 个。是的,我数过)和语法上与 Pandas 有所不同。

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

作者提供的图片

混淆的参数名称不应该是问题,因为大多数现代 IDE 都具有自动补全或弹出文档功能(JupyterLab 上的Shift + Tab,谢谢 🙏)。

如果你不知道的话,dtype 参数防止 Pandas 设置自动数据类型,并允许用户设置自定义数据类型,如 cutstring 类型或日期类型列的 datetime

你可以在 Polars 中使用相同的行为,使用 dtypes(注意是‘s’),虽然它不允许通过字符串设置类型。你必须提供 Python 内建类型或 Polars 的类型,例如 pl.Booleanpl.Categoricalpl.DateTimepl.Int64pl.Null(表示缺失值)。你可以通过调用 dir(pl) 查看完整列表。

读取和写入 Parquet 文件,这比 CSV 文件更快、更节省内存,Polars 通过 read_parquetwrite_parquet 函数也支持这些操作。

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

作者提供的图片

1. 创建 Series 和 DataFrames

你并不总是从文件中读取数据。像在 Pandas 中一样,你可以从头创建 DataFrames 和 Series,语法几乎相同:

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

作者提供的图片

Polars DataFrames 也有许多与 Pandas 几乎相同名称和行为的方法。打个招呼吧:

  • [apply](https://pola-rs.github.io/polars/py-polars/html/reference/dataframe/api/polars.DataFrame.apply.html#polars.DataFrame.apply) - 对 DataFrame 的每一行应用自定义用户定义的函数

  • [corr](https://pola-rs.github.io/polars/py-polars/html/reference/dataframe/api/polars.DataFrame.corr.html#polars.DataFrame.corr) - 相关性矩阵

  • [describe](https://pola-rs.github.io/polars/py-polars/html/reference/dataframe/api/polars.DataFrame.describe.html#polars.DataFrame.describe) - 汇总统计,五数概括

  • [drop](https://pola-rs.github.io/polars/py-polars/html/reference/dataframe/api/polars.DataFrame.drop.html#polars.DataFrame.drop) - 从 DataFrame 中删除列

  • [explode](https://pola-rs.github.io/polars/py-polars/html/reference/dataframe/api/polars.DataFrame.explode.html#polars.DataFrame.explode) - 将给定列解包为长格式(当单元格包含多个值如 [1, 2, 3] 时)

  • [head](https://pola-rs.github.io/polars/py-polars/html/reference/dataframe/api/polars.DataFrame.head.html#polars.DataFrame.head)[tail](https://pola-rs.github.io/polars/py-polars/html/reference/dataframe/api/polars.DataFrame.tail.html#polars.DataFrame.tail)[sample(n)](https://pola-rs.github.io/polars/py-polars/html/reference/dataframe/api/polars.DataFrame.sample.html#polars.DataFrame.sample) - 获取 DataFrame 的不同视图(顶部、底部、随机)

  • [iter_rows](https://pola-rs.github.io/polars/py-polars/html/reference/dataframe/api/polars.DataFrame.iter_rows.html#polars.DataFrame.iter_rows) - 返回一个 DataFrame 行的迭代器,包含 Python 原生值

  • maxmeanmediansumstd 和常见的数学和统计函数。

等等。查看 这个页面 以获取 Polars 中 DataFrame 方法的完整列表。

2. 理解 Polars 中的表达式

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

这是一个查询引擎,人类。 — Midjourney

Polars 的核心是其 查询引擎,它运行用户定义的 表达式。查询引擎和表达式是 Polars 极快性能的两个关键组件,正如 Polars 用户指南所说的,“令人尴尬的并行”。

你可能会惊讶于 Polars 表达式与 SQL 的相似程度,同时保持与熟悉的 Pandas 语法的紧密联系。

像 SQL 查询一样,你可以为以下内容编写表达式:

  • 从现有列创建新列

  • 在某些转换后获取数据视图

  • 汇总统计

  • 处理和清理数据

  • Groupby 语句

等等。

df.filter(pl.col('column') == 'some_value')

在上面的查询中,表达式是 pl.col('column)' == 'some_value',这正如你所猜测的,过滤 DataFrame 以获得 column 等于 some_value 的行。

当你单独运行这个表达式时,你不会得到像在 Pandas 中那样的布尔 Series:

type(pl.col("column") == "some_value")
polars.expr.expr.Expr

这是因为表达式只在 上下文 中进行评估。Polars 中有三种广泛的上下文:

  1. 选择数据 — 在 select 上下文中,表达式应用于列,并且必须在结果中产生相同长度的列。这种行为应当对你来说很熟悉。filter 函数也与这个上下文相关联。

  2. 分组数据 — 在 groupby 上下文中,表达式在组上工作,结果可能具有任何长度,因为一个组可以有多个成员。

  3. 添加新列 — 在这种情况下,表达式用于从头开始或从现有列创建新列。

让我们详细看看每个上下文。

3. 选择数据

Pandas 的括号表示法让位于 Polars 中用于选择列的表达式。

要选择单个列,你可以在 select 中使用它们的字面名称,或使用推荐的 pl.col 函数来引用列。

要选择多个列,你可以在 pl.col 中列出列名,用逗号分隔,或在 select 中列出 pl.col 引用的列表。我们稍后会看到这些语法之间的区别。

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

图片由作者提供

Polars 包含一些 Pandas 中未完全提供的选择数据功能。例如,你可以使用 exclude 排除选择中的列:

df.select(pl.exclude("price")).head()

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

图片由作者提供

或者使用 ^$ 字符之间的正则表达式。下面,我们选择所有以字母 c 开头的列:

df.select(pl.col("^c.+$")).head()

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

图片由作者提供

你还可以根据数据类型对子集 DataFrame,这可能让你想起 Pandas 中的 select_dtypes(左侧):

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

图片由作者提供

要选择所有数值列,我们在 pl.col 中使用了 Int64Float64 类型。

4. 数据过滤

你可以使用 filter 函数通过布尔索引对 DataFrames 进行子集化。例如,在列上使用 is_between 函数可以创建一个表达式来筛选范围内的数值列。

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

图片由作者提供

你可以使用熟悉的布尔运算符 & (AND) 和 | (OR) 结合多个 条件表达式。在下面的示例中,我们选择 color 列为 ‘E’ 或 ‘J’ 并且钻石的 price 低于 500 的行:

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

图片由作者提供

另外,注意我们在右侧如何使用 Polars 中的 is_in

5. 创建新列

你可以在 with_columns 上下文中创建新列。在下面的示例中,new_col 使用 pl.col('price') ** 2 定义,并通过别名给新列命名,就像 SQL 中的 as 关键字一样。

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

图片由作者提供

在第二个示例中,我们结合了两个列(尽管这没有意义),演示了如何将整数和字符串列与 Polars 结合使用。你可以在使用 pl.col 引用的列上使用任何本地 Python 或第三方函数和运算符。

如果你想将新列插入到 DataFrame 中,你必须覆盖原始的 df 变量。

顺便提一下,Polars 中的字符串列具有熟悉的 .str 接口,用于特殊的文本操作函数,如 containslengths。完整列表请参见 这里。还有用于专业分类、时间和数组函数的 [.cat](https://pola-rs.github.io/polars/py-polars/html/reference/series/categories.html)[.dt](https://pola-rs.github.io/polars/py-polars/html/reference/series/temporal.html)[.arr](https://pola-rs.github.io/polars/py-polars/html/reference/series/list.html) 接口。

6. 分组操作

我不认为我们可以不提及 Groupby 操作:

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

图片由作者提供

使用 Polars 的 groupby 函数时,务必包含 maintain_order=True 以确保组不会随机显示。此外,与 Pandas 不同,groupby(col_name) 表达式仅作用于给定列。要根据 col_name 对所有列进行分组,你必须使用聚合上下文。其语法如下:

df.groupby(
    "cut", maintain_order=True
).agg(pl.col("*").count())

groupby 上下文之后,你将链式聚合上下文,并指定上下文影响哪些列。然后在结果上链式调用任何函数,例如 count

这是另一个示例,按钻石切割质量分组,并返回每组的平均数值:

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

要了解更多关于 Polars 中高级 groupby 表达式的信息,请阅读这里

7. Polars 中的懒惰 API

Polars 最棒的功能之一是其懒惰 API。在该 API 中,查询不是逐行执行的,而是由查询引擎端到端处理的。

这是查询优化和令人尴尬的并行魔法发生的地方。你可以仅用两个关键字将任何在急切模式下编写的表达式转换为懒惰模式:

import polars as pl

df = pl.read_csv("data/diamonds.csv")

query = df.lazy().filter(
    pl.col("cut") == "Ideal"
)

type(query)
polars.lazyframe.frame.LazyFrame

当你在链式表达式之前添加 lazy() 函数时,DataFrame 会变成 LazyFrame。此时,查询尚未执行,你可以链式添加更多表达式。一旦准备好,你可以调用 collect() 来获取结果:

query.collect().head()

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

图片由作者提供

虽然它在急切模式下已经很快,但懒惰模式为查询引擎提供了额外的(是的,三倍的 x)动力。

如果你希望将懒惰 API 设为默认,可以在读取数据时使用 scan_* 函数,而不是 read_*

df = pl.scan_csv("data/diamonds.csv")

q1 = df.filter(
    pl.col("cut") == "Ideal"
)

q1.collect().head()

这样,你就能避免每次都编写 lazy() 函数。

如果你处理的数据集对你的内存构成威胁,你可以使用流式处理,使 Polars 分批处理数据。这个功能可以通过在collect中设置streaming=True来启用。更多关于这一优秀功能的信息,请参见此页面

结论

Polars 可能很新(我是说,它刚刚出生不久),但已经非常受欢迎。在开源标准中,它是明星。只需看看它的竞争对手:

  1. Pandas,发布于 2011 年,拥有 37.5k 个 GitHub 星标。

  2. Apache Spark,发布于 2014 年,拥有 26.8k 个星标。

  3. Vaex,发布于 2017 年,拥有 7.9k 个 GitHub 星标。

  4. Dask,发布于 2015 年,拥有 10.9k 个星标。

  5. Apache Arrow,发布于 2016 年,拥有 11.4k 个星标。

相比之下,Polars 于 2020 年发布,已经积累了 15.9k 个星标,接近其长期顶级竞争对手的一半。

这应该能给你一个大概的了解风向如何变化。虽然 Pandas 2.0 发布后情况可能会有所变化,但我认为 Polars 已经在给 Pandas 带来不小的竞争。

喜欢这篇文章吗?说实话,它那奇特的写作风格呢?想象一下,如果你能访问到更多类似的文章,全部由一位才华横溢、迷人而风趣的作者(顺便说一下,就是我 :)。

只需 4.99$的会员费用,你将不仅能访问我的故事,还能获取 Medium 上最优秀的思想者们的宝贵知识。如果你使用我的推荐链接,你将获得我超级 nova 的感激之情和一记虚拟的击掌,以支持我的工作。

[## 通过我的推荐链接加入 Medium — Bex T.

获得对我所有⚡优质⚡内容的独家访问权限,无限制地浏览 Medium。通过购买我提供的服务来支持我的工作……

ibexorigin.medium.com](https://ibexorigin.medium.com/membership?source=post_page-----b14c66fc85b9--------------------------------) 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

使用 Python Pandas 掌握分类数据操作的 7 个示例

原文:towardsdatascience.com/7-examples-to-master-categorical-data-operations-with-python-pandas-51cdcb0228ba

在处理低基数类别特征时使用类别数据类型

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

·发表于 Towards Data Science ·阅读时长 8 分钟·2023 年 11 月 9 日

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

(作者创建的图片)

类别变量可以从有限数量的值中取值,这些值通常是固定的。以下是一些类别变量的例子:

  • 英语水平指标(A1、A2、B1、B2、C1、C2)

  • 一个体的血型(A、B、AB、O)

  • 人口统计信息,如种族和性别

  • 教育水平

Pandas 提供了一种专用的分类变量数据类型(categoryCategoricalDtype)。尽管这样的数据也可以用objectstring数据类型存储,但使用category数据类型有几个优点。我们将了解这些优点,但首先让我们开始学习如何处理分类数据。

当我们用文本数据创建 Series 或 DataFrame 时,其数据类型默认为object。要使用category数据类型,我们需要明确地定义它。

import pandas as pd

# create Series
blood_type = pd.Series(["A", "B", "AB", "0"])

print(blood_type)
# output
0     A
1     B
2    AB
3     0
dtype: object

# create Series with category data type
blood_type = pd.Series(["A", "B", "AB", "0"], dtype="category")

print(blood_type)
# output
0     A
1     B
2    AB
3     0
dtype: category
Categories (4, object): ['0', 'A', 'AB', 'B']

尽管值相同,但正如你在打印 Series 时通过dtype所示,数据类型不同。

我们将通过 7 组示例来学习以下主题:

  1. DataFrames 中的类别数据类型

  2. 类别

  3. 添加和更新值

  4. 添加和删除类别

  5. 类别之间的顺序

  6. 重命名类别

  7. 使用类别数据类型的优点

示例 1 — DataFrames 中的类别数据类型

我们可以在创建 Series 或 DataFrame 时声明category数据类型,如上所述。我们也可以使用astype函数将其转换为category

在下面的代码片段中,我们首先创建一个包含两个object数据类型的列的 DataFrame。然后,我们将blood_type列的数据类型更改为category。记住,DataFrame 的每一列都是一个 Series。

# create a DataFrame with two columns
df = pd.DataFrame(
    {
        "name": ["Jane", "John", "Ashley", "Matt"],
        "blood_type": ["A", "B", "AB", "0"]
    }
)

# check the data types
df.dtypes
# output
name          object
blood_type    object
dtype: object

# convert the blood_type column to category
df["blood_type"] = df["blood_type"].astype("category")

# check the data types again
df.dtypes
# output
name            object
blood_type    category
dtype: object

示例 2 — 类别

category 数据类型的 Pandas Series 是通过类别来定义的。默认情况下,类别是 Series 中的唯一值。

# create Series with category dtype
brands = pd.Series(["Ford", "Toyota", "BMW"], dtype="category")

print(brands)
# output
0      Ford
1    Toyota
2       BMW
dtype: category
Categories (3, object): ['BMW', 'Ford', 'Toyota']

打印品牌时显示类别。我们也可以使用通过 cat 访问器提供的 categories 方法来提取它们。

brands.cat.categories

# output
Index(['BMW', 'Ford', 'Toyota'], dtype='object')

它返回类别的索引。

我们还可以在创建 Series 时定义类别,具体方法如下:

# create Series with category data type
brands = pd.Series(
    pd.Categorical(
        ["Ford", "Toyota", "BMW"], 
        categories=["Ford", "Toyota", "BMW", "Honda"]
    )
)

print(brands)
# output
0      Ford
1    Toyota
2       BMW
dtype: category
Categories (4, object): ['Ford', 'Toyota', 'BMW', 'Honda']

当前 Series 中不存在值“本田”,但它可以被添加,因为它列在类别中。

示例 3 — 添加和更新值

要在 category 数据类型的 Series 中添加新值或替换现有值,我们应该从定义的类别中选择一个值。否则,Pandas 会将 Series 的数据类型更改为 object

# create a Series with category data type
brands = pd.Series(["Ford", "Toyota", "BMW"], dtype="category")

print(brands)
# output
0      Ford
1    Toyota
2       BMW
dtype: category
Categories (3, object): ['BMW', 'Ford', 'Toyota']

# Add a new item of a different category
brands[3] = "Honda"

print(brands)
# output
0      Ford
1    Toyota
2       BMW
3     Honda
dtype: object

当我们添加了新的项“本田”时,它不在列出的类别中,最终得到的 Series 的数据类型为 object

如果我们尝试将现有值更改为不同于现有类别的值,Pandas 会引发类型错误。

# create a Series with category data type
brands = pd.Series(["Ford", "Toyota", "BMW"], dtype="category")

# replace the third value with Honda
brands[2] = "Honda"

# output
TypeError: Cannot setitem on a Categorical with a new category (Honda), set the categories first

解决这个问题的方法有很多。例如,我们可以在使用 Series 之前将“本田”作为新类别添加。

# add Honda as a category
brands = brands.cat.add_categories("Honda")

# replace the third value with Honda
brands[2] = "Honda"

print(brands)

# output
0      Ford
1    Toyota
2     Honda
dtype: category
Categories (4, object): ['BMW', 'Ford', 'Toyota', 'Honda'] 

示例 4—添加和删除类别

我们可以使用 Python 列表一次添加多个类别。

# create Series with category data type
sizes = pd.Series(["S", "M", "L"], dtype="category")

# add two new categories
sizes = sizes.cat.add_categories(["XS", "XL"])

print(sizes)

# output
0    S
1    M
2    L
dtype: category
Categories (5, object): ['L', 'M', 'S', 'XS', 'XL']

就像我们可以添加新类别一样,也可以删除现有类别。

# create Series with category data type
sizes = pd.Series(["S", "M", "L", "XL", "XXL"], dtype="category")

# remove XL and XXL categories
sizes = sizes.cat.remove_categories(["XL", "XXL"])

print(sizes)

# output
0      S
1      M
2      L
3    NaN
4    NaN
dtype: category
Categories (3, object): ['L', 'M', 'S']

需要注意的是,如果 Series 包含属于已移除类别的值(即不再存在的类别),这些值将变为缺失值(即 NaN)。

我们可以使用 categories 方法从 Series 中提取现有类别。

# create Series with category data type
sizes = pd.Series(["S", "M", "M", "L", "L", "S"], dtype="category")

# extract categories
sizes.cat.categories 

# output
Index(['L', 'M', 'S'], dtype='object')

# extract categories as a list
list(sizes.cat.categories)

# output
['L', 'M', 'S']

示例 5—类别之间的顺序

在某些情况下,类别之间有顺序(例如 S < M < L)。有不同的方法来强制执行这种顺序。

一种选择是使用 as_ordered 函数为现有的分类数据 Series 添加顺序。

# create Series with category data type
sizes = pd.Series(["L", "S", "XL", "M", "L", "S"], dtype="category")

# convert it to ordered
sizes = sizes.cat.as_ordered()

print(sizes)

# output
0     L
1     S
2    XL
3     M
4     L
5     S
dtype: category
Categories (4, object): ['L' < 'M' < 'S' < 'XL']

我们现在看到类别之间有顺序,但顺序错误。Pandas 为字符串数据分配字母顺序,这实际上是有意义的。我们可以通过重新排序类别来修复这个问题(请查看下一个示例)。

上一个示例中的 sizes Series 有排序的类别,但顺序错误。让我们使用 reorder_categories 方法来修复它。

# convert it to ordered
sizes = sizes.cat.reorder_categories(["S", "M", "L", "XL"])

print(sizes)

# output
0     L
1     S
2    XL
3     M
4     L
5     S
dtype: category
Categories (4, object): ['S' < 'M' < 'L' < 'XL']

我们将所需的类别顺序写在 Python 列表中,并将其传递给 reorder_categories 方法。

要从类别中移除顺序,我们可以使用 as_unordered 方法。让我们将其应用于之前示例中创建的 sizes Series。

# convert it to unordered
sizes = sizes.cat.as_unordered()

print(sizes)

# output
0     L
1     S
2    XL
3     M
4     L
5     S
dtype: category
Categories (4, object): ['L', 'M', 'S', 'XL']

在创建 Series 时也可以通过使用 ordered 参数来强制执行顺序。

# create Series with category data type
divisions = pd.Series(pd.Categorical(

    values=["C", "C", "A", "B", "A", "C", "A"], 
    categories=["C", "B", "A"], 
    ordered=True

))

print(divisions)

# output
0    C
1    C
2    A
3    B
4    A
5    C
6    A
dtype: category
Categories (3, object): ['C' < 'B' < 'A']

顺序是根据我们写入类别的顺序来确定的(在此示例中为 C、B、A)。

示例 6—重命名类别

如果需要重命名类别,我们可以使用 rename_categories 方法。

在之前的示例中,我们创建了一个名为“division”的 Series,包含类别 C、B 和 A。让我们重命名这些类别。

# rename the categories
divisions = divisions.cat.rename_categories(["group C", "group B", "group A"])

print(divisions)

# output
0    group C
1    group C
2    group A
3    group B
4    group A
5    group C
6    group A
dtype: category
Categories (3, object): ['group C' < 'group B' < 'group A']

正如我们在输出中看到的,重命名类别也会更新 Series 中的值。

示例 7——使用类别数据类型的优势

Pandas 的主要数据结构是 DataFrame,它是一个带有标签的二维数据结构。DataFrame 中的每一列也是一个 Series 对象。因此,我们可以很容易地在 DataFrame 中使用类别数据类型。

在这个例子中,我们将创建一个示例 DataFrame,然后通过将现有列的数据类型更改为类别类型来添加一个新列。

import numpy as np

# create a DataFrame with 100000 rows
cars = pd.DataFrame({

    "id": np.arange(1, 100001),
    "brand": ["Ford", "Toyota", "BMW", "Tesla"] * 25000,
    "price": np.random.randint(10000, 20000, size=100000)

})

# add a brand_categorical column
cars["brand_categorical"] = cars["brand"].astype("category")

# check the data types
cars.dtypes

# output
id                      int64
brand                  object
price                   int64
brand_categorical    category
dtype: object

我们创建的 DataFrame 如下所示。brandbrand_categorical 列存储了相同的数据,但数据类型不同。

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

车辆 DataFrame 的前 5 行(图像来源:作者)

使用类别数据类型而不是对象或字符串数据类型的目的是什么?数据本身还是一样的。

答案是内存使用情况。特别是当不同值的数量远低于总值数量(低基数)时,使用类别数据类型而不是对象类型可以节省大量的内存空间。

让我们通过计算车辆 DataFrame 中列的内存使用量来确认。

# check the data types
cars.memory_usage()

# output
Index                   132
id                   800000
brand                800000
price                800000
brand_categorical    100204
dtype: int64

它计算的是以字节为单位的内存使用量。使用类别数据类型相比于对象数据类型,可以节省 8 倍的内存。当我们处理更大的数据集(例如,数百万行)时,这种差异更为重要。

结语

类别数据类型相比其他基于字符串的数据类型相对较少见。原因可能是我们通常在将字符串数据用于机器学习模型之前会对其进行编码。然而,即使在数据清理和准备过程中,类别数据类型也提供了重要的优势。因此,如果一个基于字符串的变量相对于总值包含的不同值较少,我强烈建议使用类别数据类型。

感谢阅读。如有任何反馈,请告诉我。

AI 并没有威胁我们的工作!这里有 7 个值得关注的前沿职位,预计到 2030 年会崭露头角

原文:towardsdatascience.com/7-kinds-of-ai-jobs-created-in-the-future-b87191452f99

这篇文章突出了 AI 将在未来几年带来的创新角色。

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

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

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

图片来源于 Lucas 在 Pixabay

目录

  • 职位 #1: AI 安全分析师与 AI 防御工程师

  • 职位 #2: AI 数据工程师与数据策展人

  • 职位 #3: AI 数据合规专家

  • 职位 #4: AI 政策监管者

  • 职位 #5: 首席 AI 伦理官和定量 AI 伦理学家

  • 职位 #6: Prompt 工程师

  • 职位 #7: AI 体验工程师

  • 结论

ChatGPT 已经引起了世界的轰动。它已经拥有超过 1 亿用户,是有史以来增长最快的产品。

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

作者提供的图片

毫无疑问,它将颠覆我们的工作和操作方式。它已经彻底改变了我作为数据科学家的工作。

其他公司也没有落后于 OpenAI。来自 NVIDIA、Midjourney 以及其他大型科技公司、初创公司和开源社区的生成式 AI 技术每天都在取得令人印象深刻的进展。

在未来几年中,工作环境将经历重大变化。AI 将取代许多工作,但我认为它也会创造一些真正引人入胜的职位。现在正是开始思考未来雇主可能需要的职位和技能的时候。

职位 #1: AI 安全分析师与 AI 防御工程师

虽然令人恐惧,但 AI 已经被用来威胁和诈骗他人。语音克隆让人们能够伪装成亲人以索要和窃取金钱。全球安全威胁带来了更大的问题。

我预计政府和私人企业将大力投资于 AI 威胁的安全。例如,美国政府在过去一年中将其非机密 AI 预算增加了 26%,这似乎符合这一趋势。我预计机密预算会更高。

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

作者提供的图片

新角色 AI 安全分析师或 AI 防御工程师专注于分析和打击对公司和个人的 AI 威胁

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

作者提供的图片

一些所需的技能和资格

  • 了解 AI 技术和应用,如语音克隆、深度伪造、自然语言处理、计算机视觉等。

  • 能够识别和分析潜在的 AI 威胁和漏洞,如欺骗、网络钓鱼、恶意软件、数据泄露等。

  • 能够设计和实施 AI 防御策略和解决方案,如加密、认证、验证、监控等。

  • 熟悉安全标准和最佳实践,如 ISO 27001、NIST 框架等。

  • 具有安全工具和框架的经验,如 TensorFlow Privacy、PySyft、PyTorch Crypten 等。

职位 #2: AI 数据工程师与数据策展人

在 Sam Altman 与 Lex Fridman 的采访中,Altman 强调了数据作为 GPT-4 改进的重要贡献者。寻找新的数据源来训练模型将对这些新技术的发展至关重要。

寻找数据是一回事,但还需要有人将这些数据结构化,以便用于训练这些大型模型。这就是 AI 数据工程师和数据策展人 发挥作用的地方。他们需要找到数据,并使其适用于 AI 模型。

需要注意的是,为这些大型语言模型收集和存储的数据通常与传统商业用途的数据收集和存储方式有很大不同。这是因为数据的多样性、体积和质量等因素差异。学习处理大型模型数据的不同技能和工具可以使某人领先于行业。

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

作者提供的图片

我认为这一角色将远远超出仅仅是像 GPT 这样的大型 AI 模型训练公司。随着 AI 的民主化,所有公司都希望为他们自己的用例,如客户服务和文档,训练开源的大型语言模型。

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

作者提供的图片

我不认为像这样的数据角色需求会很快减缓。

一些所需的技能和资格

  • 了解数据源和格式,如文本、音频、视频、图像等。

  • 能够收集、清理、标记和组织 AI 模型的数据,如使用数据管道、标注工具、数据质量检查等。

  • 能够存储和管理大规模数据集,例如使用云平台、数据库、数据仓库、数据湖等。

  • 能够理解和应用数据伦理和隐私原则,例如通用数据保护条例(GDPR)、消费者隐私法、数据匿名化、数据治理等。

  • 熟悉人工智能技术和框架,例如自然语言处理、计算机视觉、TensorFlow、PyTorch 等。

职位#3: 人工智能数据合规专家

虽然一切都围绕数据,但通常谁拥有数据仍然不清楚。在全球范围内,数据隐私法律和可用于训练大模型的数据也存在差异。公司可能需要那些对数据立法模糊地带感到舒适的律师,因为这正是这些公司运营的领域。

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

图片由作者提供

OpenAI、Microsoft 和 GitHub 目前因涉嫌抓取许可代码而面临诉讼。还有人猜测许多这些模型是基于盗版书籍和其他内容进行训练的。

这些模型通常还会通过用户输入的文本或图像进行训练。这是一个额外的领域,情况变得有些模糊。

随着这些问题逐渐引起重视,公司将需要具有法律背景以及一些数据专业知识的人员,担任人工智能数据合规专家,以帮助他们应对这些挑战并降低潜在法律问题的风险

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

图片由作者提供

一些必需的技能和资格

  • 了解数据隐私法律和法规,例如 GDPR、消费者隐私法等。

  • 能够进行数据保护影响评估(DPIAs),并识别在人工智能系统中使用个人数据的潜在风险和缓解措施。

  • 能够管理和映射人工智能合规的权威规则和要求,并确保与业务目标和控制的对齐。

  • 能够监控和审计人工智能系统的性能和行为,确保其遵守伦理原则和标准。

  • 能够与利益相关者沟通和协作,如数据科学家、工程师、法律监管者、客户等。

职位#4: 人工智能政策监管员

当公司努力保持领先于法律或避免法律问题时,其他公司将需要努力弄清楚如何立法那些我们前所未见的人工智能系统。

与 ChatGPT 的进步一起,人工智能相关法案的通过数量每年都在增长,我认为我们将会看到新的立法爆炸性增长。

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

图片由作者提供,灵感来自于斯坦福大学

我认为大多数 AI 立法将由智库、大学和特殊利益集团发起,但最终我们将有充分信息的个人与州和地方政府合作,以规范和监督 AI 的使用。

我会称这些人AI 政策监管者。他们将帮助制定有关 AI 的立法,并在其管辖范围内执行标准实践

一些必要的技能和资格

  • AI 技术和应用及其经济和社会影响的知识。

  • 能够使用 AI 工具和方法生成政策制定和评估的见解和预测。

  • 能够与各种利益相关者(如研究人员、行业、民间社会和其他政府)进行沟通和合作。

  • 能够平衡 AI 监管的风险和机会,并确保与伦理原则和人权的一致性。

  • 能够监控和强制执行 AI 系统和用户遵守相关法律和标准。

职位 #5: 首席 AI 伦理官及定量 AI 伦理学家

尽管 AI 数据合规专家将专注于在围绕 AI 的设计选择之后避免法律问题,但仍需要有人专注于是否应该做出该设计选择。所有发布的 AI 模型都应与人进行交互。我们希望这些互动能为这些人的生活带来积极的结果。

我认为 AI 伦理将进入 C-suite。我预计公司将在不久的将来任命首席 AI 伦理官或类似职位。

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

图片来源:作者

这个职位的工作是尽可能减少生产模型和过程中的偏见。还要确保模型的结果对相关方是积极和公平的

我认为这个角色会在 C-suite 中,因为这个角色涉及到大量的限制。如果这个人没有高的职位或在组织中的尊重,解雇他们并聘用一个会放任事情发展的人会比较容易。实际上,这种情况可能仍会发生。

一些必要的技能和资格

  • AI 技术及其对社会和个人的影响的技术知识。

  • 了解现有和新兴与 AI 伦理相关的法律和标准的监管知识。

  • 具有商业头脑和关于 AI 应用的特定领域及背景的行业知识。

  • 沟通技巧以及跨组织边界和与不同利益相关者合作的能力。

  • 具有前瞻性和预测能力,以预见 AI 创新的潜在后果和机会。

首席 AI 伦理官的最大武器将是定量 AI 伦理学家。他们的工作是分析模型中的偏见水平并衡量对受影响群体的影响

我认为这个角色将标志着伦理观念在组织中的重大变化。对于创建这些模型的人来说,需要数据来推动变革。尽可能量化伦理将提高认可的速度。

一些必需的技能和资格

  • 对 AI 技术、系统、算法和工具的技术知识。

  • 对指导 AI 开发和使用的理论和原则的伦理理解。

  • 分析和批判性思维技能,以评估复杂的伦理问题并提出解决方案。

  • 沟通技能和向不同听众解释和辩护伦理决策的能力。

  • 统计和数学技能,以测量和量化 AI 模型及结果中的偏见和公平性水平。

职位 #6: 提示工程师

作为数据科学家,我每天使用 ChatGPT。老实说,我几乎不再写代码了。我大部分时间都在编写和修订提示,以改进 ChatGPT 编写的代码。

在我看来,未来大量的知识工作将依赖于提示**,** 即我们创建输入以要求 AI 生成所需结果的方式。

例如,我可以提示 ChatGPT 成为数据科学教师,并向其提问。

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

作者提供的图片

我还可以将它提示成为一个著名的艺术评论家,利用我对图片的描述来改善它们,以便输入到像 Midjourney 这样的文本到图像模型中。

创造脚本以将这些模型塑造成你想要的样子或执行你希望的操作是一门艺术。

我认为特定行业会有提示工程师的市场。而且有些人已经在尝试聘请这些工程师,薪资超过 $300,000。

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

作者提供的图片

一些必需的技能和资格

  • 批判性思维和解决问题的技能,以创建有效的提示,向 AI 模型传达人的意图。

  • 数学和分析技能,以理解和操作数学公式及数据。

  • 沟通和写作技能,以使用自然语言编写清晰简明的提示。

  • 关注细节和准确性,以避免提示中的错误和模糊性。

  • 多才多艺和适应能力,以应对不同的 AI 系统和领域。

  • 团队合作和协作技能,以协调其他提示工程师和相关方。

  • 编码和编程技能,以使用各种工具和框架进行提示工程。

  • A/B 测试和实验技能,以评估和优化提示的性能。

职位 #7: AI 体验工程师

目前,我们通过文本、图片以及有时通过语音直接与 AI 互动。我预计随着 AI 的不断发展,这种情况将迅速变化。公司将希望让 AI 融入我们的生活。这个工作的主要部分由设计师或用户体验工程师完成。

如果人们不断使用这些工具,公司将希望它们能提供最佳的体验。这可能是选择一种产品而非另一种产品的关键因素。

我个人在使用 ChatGPT 与 Bard 相比时获得了这种体验。我发现使用 ChatGPT 的体验要好得多:我喜欢它的美学,更喜欢它将所有文本写在屏幕上的方式,还喜欢我可以将其设置为暗模式。即使输出相同,我通常也会更喜欢 ChatGPT。

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

ChatGPT(左图)和 Bard(右图)之间用户体验的比较。图片由作者提供

我认为公司将大量投资于新的AI 体验工程师,以理解和开发消费者使用其产品的方式,使产品脱颖而出**。**

一些必要的技能和资格

  • 具有用户研究、用户测试和用户反馈的经验,以了解用户的需求、偏好和痛点。

  • 能够创建用户角色、用户旅程、用户流程、线框图、模型图和原型,以设计和传达用户体验。

  • 了解设计原则、模式和最佳实践,以创建直观、可访问和引人入胜的用户界面。

  • 熟练使用设计工具,如 Sketch、Figma、Adobe XD 等,以创建和迭代产品的视觉设计。

  • 熟悉 HTML、CSS 和 JavaScript 等编程语言,以实施产品的前端设计并与开发人员合作。

  • 理解 AI 概念、框架和工具,以将 AI 功能集成到产品中。

  • 了解 AI 伦理和原则,以确保 AI 的负责任和公平使用。

结论

生成式 AI 的兴起将取代许多传统工作,但它也承诺带来一系列令人兴奋的新就业前景。这一影响已经显而易见,显著改变了各行业专业人士的工作环境。随着这一波 AI 创新的持续推进,它为这些有趣且必要的角色的创造提供了机会:

  1. AI 安全分析师 & AI 防御工程师: 鉴于 AI 潜在的恶意使用,专注于识别和缓解 AI 威胁的角色变得至关重要。

  2. AI 数据工程师 & 数据策展人: 这些专业人士将负责采购、组织和管理与大型语言模型相关的数据。

  3. AI 数据合规专家: AI 数据使用的法律复杂性需要专业人士能够处理 AI 法规中的复杂问题,特别是合规性,以确保减少法律风险。

  4. AI 政策监管员: 随着 AI 系统挑战现有法律框架,亟需熟练的专业人士与政府合作,制定有关 AI 实施的适当规则和标准。

  5. 首席 AI 伦理官和定量 AI 伦理学家: 将会有越来越大的需求来确保道德和公正的结果。公司可能会设立首席 AI 伦理官(以解决生成模型中的突出偏见)和定量 AI 伦理学家(通过量化这些模型中的偏见及其对利益相关者的影响来帮助实现这一目标)的角色。

  6. 提示工程师: 这一角色预计将会兴起,因为从业者通过制定强有力的提示来优化 AI 模型的输出,从而提高模型的效果和实用性。

  7. AI 体验工程师: 为了提升 AI 产品的用户友好性和实用性,公司将需要专门设计用户与 AI 互动的 AI 体验工程师。这将影响消费者在竞争市场中的产品偏好。

适应性和前瞻性将是拥抱这些新兴角色及其技能要求的关键,这些角色和要求正在被 AI 重塑的行业中不断发展。

你对这些工作职位中哪个最感兴趣?我是否遗漏了什么?留下评论吧!我很想知道!

如果你喜欢这篇文章,记得在 Medium 上关注我,获取更多类似的内容,或者通过电子邮件订阅我。你还可以将这篇文章分享给你网络中的数据科学爱好者!

如果你喜欢有关数据科学、机器学习和 AI 的有趣且富有信息的视频,请查看我的 YouTube 频道,我提供评论、教程和其他教育视频。

要获取我内容创作的每周更新和数据科学行业的额外学习资源,请订阅我的通讯,《数据滴滴!*

此外,考虑通过注册会员来支持我和其他成千上万的作者。

[## 使用我的推荐链接加入 Medium — Ken Jee

作为 Medium 会员,你的会员费的一部分将用于支持你阅读的作者,你可以全面访问每一个故事…

medium.com](https://medium.com/@kenneth.b.jee/membership?source=post_page-----b87191452f99--------------------------------)

使用 ChatGPT 创建完整产品的 7 个经验教训

原文:towardsdatascience.com/7-lessons-learned-on-creating-a-complete-product-using-chatgpt-462038856c85?source=collection_archive---------2-----------------------#2023-08-05

ChatGPT 的编码能力使得在短时间内完成整个产品变得非常简单——前提是你知道如何正确使用它

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

·

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

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

通过 StableDiffusion 生成

不久前,我与您分享了如何从 ChatGPT 创建我自己的法语导师(顺便说一下,它是开源的)。我描述了如何设计应用(尤其是它的后端)以及如何连接和配置不同的基于 AI 的服务。但有一件事我基本上跳过了,那就是如何创建应用的前端。你看,我不是前端程序员,我对 JavaScript 的了解仅限于知道需要将其放在** 标签内。

但我心中设想的应用需要一个动态的用户界面。这意味着 HTML、JavaScript 和 CSS——但我完全不知道如何开始编写这些代码。

我知道的是我想要它看起来的样子。我心中有设计构想,我知道如果我知道如何编码的话,我会怎么做。因此,我决定采用一种新的和相当激进的方法——我会让 ChatGPT 为我编写代码。在那时,我已经有了向 ChatGPT 请求代码相关请求的经验,但从未尝试过如此复杂的任务。

好吧,当你读到这些文字时,你知道它成功了——我仅仅通过指示一个 LLM(大型语言模型)我想看到什么,就创建了一个完整的应用。我真的想再写一遍,只是为了确保我们都明白发生了什么:一个算法仅仅通过我用简单英语解释,就编写了整个应用。😲

尽管如此,这个过程并不像听起来那么简单——因此我想借此机会分享一些我在使用 ChatGPT 生成复杂代码时学到的技巧。

1. 亲自设计

LLMs 是创建代码和内容的强大工具,但它们不思考——它们只能执行请求(或者至少它们会尝试)。这意味着需要你来进行思考,特别是设计。在开始向生成模型发送请求之前,确保你知道最终产品应该是什么样子的。

关于这点——你需要自行研究什么技术栈最适合你。由于你需要将复杂的应用拆分为步骤(参见下方第 2 点),LLM 无法预见最终产品的样子,可能会使用次优的库或服务。

例如,ChatGPT 为我生成的第一个 UI 基于tkinter,它创建的是一个实际应用而不是网页 UI。这使得创建动态 UI 变得更加复杂(而且现在不太标准)。另一个尝试是基于steamlit,它使得创建非复杂 UI 非常简单,但同样没有设计用于复杂请求(例如:“仅在用户消息旁边添加播放录音按钮,但仅在用户录制了音频时”)。在我的情况下,最终决定使用Flask 是最优的选择。

2. 将其拆分为任务并从简单的开始

如果你要求 ChatGPT 一次性编写整个产品的代码,很有可能会得到一段有问题的代码。尽管它“聪明”,但不要期望它能够一次性关注所有细节。将你的设计拆分成任务和阶段,从比较简单的开始,然后逐步增加。

比如,这里是我最终设计的聊天界面,即我最初设计和计划的界面:

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

聊天机器人界面

你可以看到界面上有各种按钮和功能,而我最初对 ChatGPT 的提示是:

Write a Python web UI for a chatbot application. The text box where 
the user enters his prompt is located at the bottom of the screen, and 
all previous messages are kept on screen

没有特别的按钮,没有消息旁的个人头像,没有其他特别之处。只是一个简单的聊天界面,这将是我构建的核心。这个提示生成了 4 个文件:

  • 一个作为后端的 Python 文件(使用 Flask)

  • 一个 HTML 文件

  • 一个 JavaScript 文件(使用 jQuery)

  • 一个 CSS 文件

一旦我有了这些,我就可以开始使产品变得更复杂。

你可能会觉得我自相矛盾 —— 说要将应用拆分成小步骤,但又承认我的第一次提示生成了四个文件。每个对 ChatGPT 的请求之间,在完成任务所需的代码量与其非标准和特定性的权衡。要求生成整个聊天界面会得到比较通用的东西,但需要大量代码。要求“在导师消息旁边添加一个翻译按钮”,并且确保它位于消息气泡的右侧,始终在垂直中心,并且在 播放声音 按钮上方,这样的请求非常具体,因此它将是一个单独的请求。

3. 仔细解释你真正想要的

每个对你产品的请求和添加都可能涉及到多个文件的更改(每个文件可能有不止一个更改)。这意味着每次请求时都会创建新的变量、函数和端点,并且会从不同的位置引用它们。 ChatGPT 会为这些提供名称,并尽力提供有意义的名称 —— 但前提是你要解释清楚上下文。

比如,如果你想在你的产品中添加一个“保存”按钮,最好像这样提问:

Add a "Save Session" button to the left of the text box. It should have 
a floppy-disk icon. Once clicked, all messages on the UI will be saved to 
a JSON file named "saved_session.json"

而不是这样的缺乏上下文的提示:

Add a button to the left of the text box wth a floppy-disk icon. Once 
clicked, all messages on the UI will be saved to a JSON file.

倾向于丰富上下文的提示会产生更好的命名约定。

4. 非常清楚地知道你要问什么

这是我遇到的一个真正的问题,之前没预见到:我希望 UI 显示来自我的法语导师的生成文本,并且是实时流式显示,类似于 ChatGPT 的效果。我使用的 Python API(OpenAI ChatCompletion API)返回了一个 Python Generator,这需要被消费并打印到屏幕上。因此,我问 ChatGPT:

Write a JavaScript function that consumes the generator and updates the 
message text one item at a time

我不知道的是——因为我从未写过任何严肃的 JavaScript 代码——我要求的东西是不可能的;JavaScript 无法处理 Python 生成器。结果是 ChatGPT 给了我各种奇怪且完全无用的解决方案,因为它试图完全按照我的要求——修改 JavaScript 代码。

你必须记住,ChatGPT 尝试完全按照你的要求来满足你的请求,只要这些请求不违反其指导方针。在那时我真正需要的是它告诉我我要求的东西很愚蠢,但这并不是它的工作方式。

这个问题只有在我发现自己在要求不可能的东西(老办法——Google 和 StackOverflow)之后才得到解决,并将我的提示更改为类似以下内容:

Given the response generator, add functionality to consume the generator 
and updates the message text one item at a time 

这导致对 JavaScript Python 文件进行了修改,从而实现了预期的结果。

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

使用 StableDiffusion 生成

5. LLM 无法还原其代码(以及如何还原)

虽然 ChatGPT 在编写代码方面表现出色,但它仍然只是一个语言模型,它在还原自己修改的内容方面做得不好——尤其是当你要求它还原并回到两三次之前的提示时。与 LLMs 进行分阶段生成代码时,我强烈建议始终保留你满意的最后一个工作版本的代码副本;这样,如果 ChatGPT 添加的新代码出现问题且无法修复,你可以轻松将代码还原到最后一个正常工作的版本。

但有一个问题——因为如果你恢复了你的代码,你还需要恢复 ChatGPT,以确保它确切知道你代码现在的样子。最好的方法是启动一个新会话,并用类似下面的提示开始:

I'm building a chatbot application. Here is my code so far:

HTML:

你的 HTML 代码


JavaScript:

你的 JavaScript 代码


CSS:

你的 CSS 代码


Python:

你的 Python 代码


Add a "Save Session" button to the left of the text box. It should have 
a floppy-disk icon. Once clicked, all messages on the UI will be saved to 
a JSON file named "saved_session.json"

(你也可以将文件上传到 ChatGPT 的代码解释器,那时还不可用)。如果提示过长无法作为单条消息发送,将其拆分为两部分。在这两条消息之间,点击*“停止生成”*,以防止机器人插入不必要的文本。

6. 不要太长时间地与之对抗

使用 ChatGPT 编码的一个酷炫之处是,如果它写出的代码有问题,或者代码没有按预期执行,你可以直接发送错误信息,它会相应地修复代码。

但这并不总是发生。有时 ChatGPT 无法修复错误,或者反而引入了另一个错误。我们会将新的错误信息发送给它,并再次要求它修复。如果这种情况发生超过两三次,代码有可能会变得非常破碎或过度修改,从而完全无法工作。如果你达到了这一点,请停止,恢复(见上文),并重新表述你的请求。

7. 学习如何编写提示

尽管 ChatGPT 的核心在于你可以使用日常语言与其互动,但正确编写提示可以对结果产生巨大影响。我真的推荐花时间学习如何做到这一点。例如,这个由 OpenAI 和 DeepLearning.AI 提供的免费课程是必修的,特别是关于如何将指令、代码和示例结合在一个提示中的课程。

你可以学到的最重要的事情之一是确保在提示中自由文本和代码之间有明显的区别。因此,避免这样做:

Here's a Python function: 
def func(x): 
  return x*2
Change it so it'll return the root of the absolute value of the input if 
it's negative.

这样写:

Here's a Python function: 

def func(x):

return x*2

Change it so it'll return the root of the absolute value of the input if 
it's negative.

此外,如果可能的话,提供输入输出示例。这是向 LLM 解释它应该做什么的最佳方法,因为它消除了你请求中的任何模糊性(如果输入是正数,模型应该返回什么?保持 x2 还是什么都不做?*):

Here's a Python function: 

def func(x):

return x*2

Change it so it'll return the root of the absolute value of the input if 
it's negative.

Examples:
Input: 2, Output: 4
Input: -9, Output: 3

额外提示:选择合适的 LLM

记住,“ChatGPT”是一个网络产品的名称,而不是模型本身。免费版让你使用 GPT-3.5,而付费版则包括 GPT-4,它在编码任务中表现显著更好。新的代码解释器也使其表现更好,因为它可以运行和测试其代码。

即使你决定选择另一个 LLM 来合作,确保你选择的那个在编码任务中表现良好。否则,这些提示将毫无帮助。

在总结这一切时,我想最重要的是认识到与 LLMs 沟通时每个词都很重要。LLMs 不会思考,也不能真正理解我们想要什么,除非明确以它们需要的方式向它们解释,因为——谢天谢地——它们还不是人类(还没?),它们只是工具。就像每一个工具一样——如果你不知道怎么使用它,你就无法完成任何工作。我确实希望你能在下一个项目中找到这些提示的用处!

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

使用 StableDiffusion 生成

7 种最常用的特征工程技术

原文:towardsdatascience.com/7-of-the-most-used-feature-engineering-techniques-bcc50f48474d

使用 Scikit-Learn、Tensorflow、Pandas 和 Scipy 进行实用特征工程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 多米尼克·波尔策

·发布在Towards Data Science ·37 分钟阅读·2023 年 1 月 9 日

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

7 种最常用的特征工程技术——图像由作者提供

目录

Introduction 1\. Encoding
  1.1 Label Encoding using Scikit-learn
  1.2 One-Hot Encoding using Scikit-learn, Pandas and Tensorflow
2\. Feature Hashing
  2.1 Feature Hashing using Scikit-learn
3\. Binning / Bucketizing
  3.1 Bucketizing using Pandas
  3.2 Bucketizing using Tensorflow
  3.3 Bucketizing using Scikit-learn
4\. Transformer
  4.1 Log-Transformer using Numpy
  4.2 Box-Cox Function using Scipy
5\. Normalize / Standardize
  5.1 Normalize and Standardize using Scikit-learn
6\. Feature Crossing
  6.1 Feature Crossing in Polynomial Regression
  6.2 Feature Crossing and the Kernel-Trick
7\. Principal Component Analysis (PCA)
  7.1 PCA using Scikit-learn
Summary
References

介绍

特征工程描述了制定相关特征的过程,这些特征尽可能准确地描述了基础的数据科学问题,并使算法能够理解和学习模式。换句话说:

你提供的特征作为一种方式,将你对世界的理解和知识传达给你的模型

每个特征描述了一种信息“片段”。这些片段的总和使算法能够对目标变量得出结论——至少当你的数据集实际包含有关目标变量的信息时。

根据福布斯杂志,数据科学家将约 80%的时间花在收集和准备相关数据上,其中数据清理和数据组织单独占据了约 60%的时间。

但这段时间是花得值得的。

我相信数据的质量以及数据集特征的恰当准备,对机器学习模型的成功的影响大于机器学习管道中的任何其他部分:

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

标准机器学习管道——受[Sarkar et al., 2018]的启发

福布斯杂志认为的“清理和组织”通常在机器学习管道中分解为两个到三个子类别(我在上面的图像中用黄色背景突出显示了它们):

(1) 数据(预处理): 数据的初步准备——例如,平滑信号、处理异常值等。

(2) 特征工程: 定义模型的输入特征——例如,通过使用快速傅里叶变换(FFT)将(声学)信号转换为频域,允许我们从原始信号中提取关键的信息。

(3) 特征选择: 选择对目标变量有显著影响的特征。通过选择重要特征并减少维度,我们可以显著降低建模成本,提高模型的鲁棒性和性能。

我们为什么需要特征工程?

Andrew Ng 经常提倡所谓的 数据中心方法,强调选择和策划数据的重要性,而不仅仅是试图收集越来越多的数据。目标是确保数据的高质量和与所解决问题的相关性,并通过数据清洗、特征工程和数据增强不断改进数据集。

为什么我们在拥有深度学习的情况下还需要特征工程和数据中心方法?

这种方法特别适用于收集大量数据成本高昂或其他困难的使用场景。[Brown, 2022] 例如,当数据难以访问,或存在严格的法规或其他障碍来收集和存储大量数据时:

  • 在制造业中,为生产设施配备全面的传感器技术并将其连接到数据库是昂贵的。因此,许多工厂尚未收集数据。即使机器能够收集和存储数据,它们也很少与中央数据湖连接。

  • 在供应链背景下,每家公司每天处理的订单数量有限。因此,如果我们想预测需求非常不规律的产品的需求,有时我们只有少量的数据点可用。

在这些领域,特征工程可能对提高模型性能具有最大影响。这里需要工程师和数据科学家的创造力来将数据集的质量提升到足够的水平。这个过程很少是直接的,而是实验性的和迭代的。

当人类分析数据时,他们通常会利用过去的知识和经验来帮助理解模式并做出预测。例如,如果有人尝试估算不同国家的温度,他们可能会考虑国家相对于赤道的位置,因为他们知道温度往往在靠近赤道的地方较高。

然而,机器学习模型并不像人类一样具有内在的概念和关系理解能力。它只能从提供给它的数据中学习。因此,任何人类用于解决问题的背景信息或上下文必须以数值形式显式地包含在数据集中。

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

平均年温度按国家划分 [Wikimedia]

那么我们需要什么数据才能使模型比人类更聪明?

我们可以使用 Google Maps API 查找每个国家的地理坐标(经度和纬度)。此外,我们还可以收集每个国家的海拔信息和距离最近水体的距离。通过收集这些额外数据,我们希望识别并考虑可能影响每个国家温度的因素。

假设我们收集了一些可能影响温度的数据,接下来该怎么办?

一旦我们拥有足够描述问题特征的数据,我们仍然需要确保计算机能够理解这些数据。类别数据、日期等必须转换为数值。

在这篇文章中,我将描述一些常用的原始数据准备技术。某些技术用于将类别数据转换为机器学习模型可以理解的数值,如编码向量化。其他技术用于处理数据分布,如变换器分箱,这些技术可以帮助以某种方式归一化或标准化数据。还有其他技术用于通过生成新特征来减少数据集的维度,如哈希主成分分析 (PCA)

自己试试吧……

如果您想跟随本文并尝试这些方法,可以使用下面的代码库,其中包含 Jupyter Notebook 中的代码片段和使用的数据集:

[## GitHub - polzerdo55862/7-feature-engineering-techniques

目前无法执行该操作。您在其他标签页或窗口中登录了。您已在另一个标签页或窗口中退出登录……

github.com](https://github.com/polzerdo55862/7-feature-engineering-techniques?source=post_page-----bcc50f48474d--------------------------------)

1. 编码

特征编码是将类别数据转换为 ML 算法可以理解的数值的过程。有几种类型的编码,包括标签编码和独热编码。

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

标签编码和热编码 — 作者提供的图片

标签编码涉及为每个类别值分配一个数字值。如果类别值之间存在固有顺序,例如从 A 到 F 的等级,可以将其编码为从 1 到 5(或 6)的数字值。然而,如果类别值之间没有固有的顺序,则标签编码可能不是最佳方法。

另外,你也可以使用一次性编码将类别值转换为数值值。在一次性编码中,类别值的列被拆分成几列,每列对应一个独特的类别值。

例如,如果类别值是从 A 到 F 的等级:

  • 我们将新增五列,每列对应一个等级。

  • 数据集中每一行在与其等级对应的列中将有一个值为 1,在所有其他列中则为 0。

  • 这会导致所谓的稀疏矩阵,其中大多数值为 0。

一次性编码的缺点是它可能显著增加数据集的大小,如果要编码的列包含数百或数千个独特的类别值,这可能会成为问题。

接下来,我将使用 Pandas、Scikit-learn 或 Tensorflow 对数据集应用标签和一次性编码。以下示例中,我们使用的是人口普查收入数据集:

数据集:人口普查收入 [许可证: CC0: 公共领域]

archive.ics.uci.edu/ml/datasets/census+income

www.kaggle.com/datasets/uciml/adult-census-income

人口普查收入数据集描述了美国个人的收入情况。它包括他们的年龄、性别、婚姻状况和其他人口统计信息,以及他们的年收入,分为两类:超过 50,000 美元或低于 50,000 美元。

对于标记示例,我们使用的是人口普查数据集中描述个人最高学历的“教育”列。它包含的信息例如个人是否完成了高中、大学、获得了研究生学位或其他形式的教育。

首先,让我们加载数据集:

import pandas as pd

# load dataset - census income
census_income = pd.read_csv(r'../input/income/train.csv')

1.1 使用 Scikit-learn 进行标签编码

标签编码是将类别值转换为数值值的最简单方法。这是一个简单的过程,将每个类别分配一个数值。

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

标签编码——图片来源于作者

你可以在 Pandas、Scikit-Learn 和 Tensorflow 中找到合适的库。我使用的是 Scikit-Learn 的标签编码函数。它随机将整数分配给独特的类别值,这是最简单的编码方式:

from sklearn import preprocessing

# define and fit LabelEncoder
le = preprocessing.LabelEncoder()
le.fit(census_income["education"])

# Use the trained LabelEncoder to label the education column
census_income["education_labeled"] = le.transform(census_income["education"])

display(census_income[["education", "education_labeled"]])

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

这种编码方式可能会给一些算法带来问题,因为分配的整数不一定反映类别之间的任何固有顺序或关系。例如,在上述情况中,算法可能会假设类别博士(10)和高中毕业(11)彼此更为相似,而不是博士(10)和学士(9),并且高中毕业(11)比博士(10)“高”。

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

标签编码结果解释 — 图像由作者提供

如果我们对数据集的特定领域或主题有一些了解,我们可以利用它确保标签编码过程反映任何固有的顺序。以我们的例子为例,我们可以尝试考虑获得不同学位的顺序来标记教育水平,例如:

博士学位是高于硕士和本科的更高学术学位。硕士学位高于本科。

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

要将这种手动映射应用于数据集,我们可以使用pandas.map函数:

education_labels = {'Doctorate':5, 'Masters':4, 'Bachelors':3, 'HS-grad':2, '12th':1, '11th':0}

census_income['education_labeled_pandas']=census_income['education'].map(education_labels)

census_income[["education", "education_labeled_pandas"]]

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

但这如何影响模型构建过程?

让我们用标记编码数据构建一个简单的线性回归模型:

对于下面的图,目标变量定义为个人收入超过 $50,000 的概率

  • 在左图中,分类值(如“本科”和“博士”)被随机分配给数值。

  • 在右图中,分配给分类值的数值反映了通常获得学位的顺序,较高的教育学位分配较高的数值。

右图显示了教育水平与收入之间的明显相关性,这可以通过一个简单的线性模型来表示。

与之相反,左图展示了教育属性与目标变量之间的关系,这需要一个更复杂的模型才能准确表示。这可能会影响结果的可解释性,增加过拟合的风险,并增加拟合模型所需的计算工作量。

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

标签编码:训练有序和无序“教育”特征的线性回归模型 — 图像由作者提供

当值没有固有的顺序或者我们没有足够的信息进行映射时,我们该怎么办?

如果分类值完全没有固有的顺序,使用将类别转换为一组数值变量而不引入任何偏见的编码方法可能更好。独热编码就是一种合适的方法。

1.2 使用 Scikit-learn、Pandas 和 Tensorflow 进行独热编码

独热编码是一种将分类数据转换为数值数据的技术。它通过为数据集中的每个唯一类别创建一个新的二进制列,并将属于该类别的行赋值为 1,将不属于该类别的行赋值为 0 来实现这一点。

→ 这个过程通过不假设类别之间存在任何固有顺序,帮助避免对数据引入偏见。

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

One-Hot Encoding — 图像由作者提供

One-Hot 编码的过程相当简单。我们可以自己实现它,也可以使用现有的函数之一。Scikit-learn 有**.preprocessing.OneHotEncoder()函数,Tensorflow 有.one_hot()函数,Pandas 有.get_dummies()**函数。

  • Pandas.get_dummies()
import pandas as pd

education_one_hot_pandas = pd.get_dummies(census_income["education"], prefix='education')
education_one_hot_pandas.head(2)
  • Sklearn.preprocessing.LabelBinarizer()
from sklearn import preprocessing

lb = preprocessing.LabelBinarizer()
lb.fit(census_income["education"])

education_one_hot_sklearn_binar = pd.DataFrame(lb.transform(census_income["education"]), columns=lb.classes_)
education_one_hot_sklearn_binar.head(2)
  • Sklearn.preprocessing.OneHotEncoder()
from sklearn.preprocessing import OneHotEncoder

# define and fit the OneHotEncoder
ohe = OneHotEncoder()
ohe.fit(census_income[['education']])

# transform the data
education_one_hot_sklearn = pd.DataFrame(ohe.transform(census_income[["education"]]).toarray(), columns=ohe.categories_[0])
education_one_hot_sklearn.head(3)

One-hot 编码的问题是它可能导致具有高维度的大型稀疏数据集。

使用 one-hot 编码将具有 10,000 个唯一值的分类特征转换为数值数据,会导致在数据集中创建 10,000 列,每列表示一个不同的类别。这在处理大型数据集时可能会成为问题,因为它会迅速消耗大量内存和计算资源。

如果内存和计算能力有限,可能 需要减少数据集中的特征数量 以避免遇到内存或性能问题。

我们如何减少维度以节省内存?

在执行此操作时,重要的是尽可能减少信息的丢失。这可以通过仔细选择保留或删除哪些特征、使用如特征选择或维度减少等技术来识别和删除冗余或不相关的特征来实现。[Sklearn.org][Wikipedia, 2022]

在本文中,我将描述两种可能的方式来减少数据集的维度:

  1. 特征哈希 — 见第二部分。特征哈希

  2. 主成分分析(PCA) — 见第七部分。PCA

信息丢失 vs. 速度 vs. 内存

可能没有一种“完美”的方法来减少数据集的维度。一种方法可能更快,但可能导致大量信息丢失,而另一种方法则保留更多信息,但需要大量计算资源(这也可能导致内存问题)。

2. 特征哈希

特征哈希主要是一种维度减少技术,通常用于自然语言处理。然而,当我们需要对具有几百或几千个唯一类别的分类特征进行向量化时,哈希也可以很有用。通过哈希,我们可以通过将多个唯一值分配到相同的哈希值来限制维度的增加。

→ 因此,哈希是一种低内存的替代方法,用于 OneHot 编码和其他特征向量化方法。

哈希通过将哈希函数应用于特征并直接使用哈希值作为索引,而不是构建哈希表并单独查找索引,来进行工作。Sklearn 中的实现基于 Weinberger [Weinberger et al., 2009]。

我们可以将其分解为 2 个步骤:

  • 第 1 步: 首先使用哈希函数将分类值转换为哈希值。Scikit-learn 中的实现使用了 32 位变体的 MurmurHash3。

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

哈希技巧 — 作者提供的图像

import sklearn 
import pandas as pd

# load data set
census_income = pd.read_csv(r'../input/income/train.csv')
education_feature = census_income.groupby(by=["education"]).count().reset_index()["education"].to_frame()

############################################################################################################
# Apply the hash function, here MurmurHash3 
############################################################################################################
def hash_function(row):
    return(sklearn.utils.murmurhash3_32(row.education))

education_feature["education_hash"] = education_feature.apply(hash_function, axis=1)
education_feature

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

  • 第 2 步: 接下来,我们通过对特征值应用mod 函数来降低维度。使用 mod 函数,我们计算哈希值除以n_features(输出向量的特征数量)后的余数。

建议使用 2 的幂作为 n_features 参数;否则,特征将无法均匀映射到列中。

示例:人口普查收入数据集 → 对教育列进行编码

人口普查收入数据集的“教育”列包含 16 个唯一值:

  • 使用独热编码,将向数据集中添加 16 列,每列代表 16 个唯一值中的一个。

→ 为了降低维度,我们将n_features设置为 8。

这不可避免地导致“冲突”,即不同的类别值被映射到相同的哈希列。换句话说,我们将不同的值分配到同一个桶中。这类似于我们在分箱/桶化(参见第三部分 分箱/桶化)中所做的。在特征哈希中,我们通过将分配到同一桶的值串联起来并存储在一个列表中(称为“分离链”)来处理冲突。

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

特征哈希:通过计算余数作为新列索引来降低维度 — 作者提供的图像

############################################################################################################
# Apply mod function
############################################################################################################
n_features = 8

def mod_function(row):
    return(abs(row.education_hash) % n_features)

education_feature["education_hash_mod"] = education_feature.apply(mod_function, axis=1)
education_feature.head(5)

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

为我们执行上述步骤的函数是来自Scikit-learnHashingVectorizer函数。

2.1 使用 Scikit-learn 进行特征哈希

sklearn.feature_extraction.text.HashingVectorizer

from sklearn.feature_extraction.text import HashingVectorizer

# define Feature Hashing Vectorizer
vectorizer = HashingVectorizer(n_features=8, norm=None, alternate_sign=False, ngram_range=(1,1), binary=True)

# fit the hashing vectorizer and transform the education column
X = vectorizer.fit_transform(education_feature["education"])

# transformed and raw column to data frame
df = pd.DataFrame(X.toarray()).assign(education = education_feature["education"])
display(df)

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

3. 分箱 / 桶化

分箱用于分类数据和数值数据。顾名思义,目标是将特征的值映射到“分箱”中,并用表示该分箱的值替换原始值。

例如,如果我们有一个值范围从 0 到 100 的数据集,并且我们想将这些值分组为大小为 10 的分箱,我们可以为值 0-9、10-19、20-29 等创建分箱。

→ 在这种情况下,原始值将被替换为表示它们所属的分箱的值,例如 10、20、30 等。这有助于可视化和分析数据。

由于我们减少了数据集中唯一值的数量,这有助于:

  • 防止过拟合

  • 提高模型的鲁棒性并减轻异常值的影响

  • 降低模型复杂性和训练模型所需的资源

系统化的分箱可以帮助算法更容易高效地检测潜在模式。如果我们在定义分箱之前能形成一个假设,这会特别有帮助。

分箱可用于数值和分类值,例如:

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

对类别和数值特征进行分桶 — 图片由作者提供

在以下内容中,我描述了如何使用三个示例来处理数值型和类别型属性:

  1. 数值型 — 在构建流媒体推荐系统时如何使用分桶——这是我在[Zheng, Alice, and Amanda Casari. 2018]的书Feature Engineering for Machine Learning中找到的用例

  2. 数值型 — 人口普查收入数据集:对“年龄”列应用分桶

  3. 类别型 — 供应链中的分桶:根据目标变量将国家分配到桶中

示例 1:流媒体推荐系统——一首歌或视频有多受欢迎?

如果你想开发一个推荐系统,将歌曲的相对受欢迎程度分配数值是很重要的。最显著的属性之一是点击次数,即用户听这首歌的频率。

然而,一个用户听一首歌 1000 次并不一定比听 50 次的用户喜欢它多 20 倍。分桶有助于防止过拟合。因此,将歌曲的点击次数分为类别可能是有益的。: [Zheng, Alice and Amanda Casari. 2018]

点击次数 >=10: 非常受欢迎

点击次数 >=2: 流行

点击次数 <2: 中性,无可能的声明

示例 2:年龄与收入的关系

对于第二个示例,我再次使用人口普查收入数据集。目标是将个体分组到年龄桶中。

假设 — 这个观点是,个人的具体年龄可能对他们的收入影响不大,而是他们所处的生活阶段。例如,一个 20 岁还在上学的人可能与一个 30 岁的年轻专业人士的收入不同。类似地,一个 60 岁仍在全职工作的人可能与一个 70 岁退休的人收入不同,而如果一个人是 40 岁或 50 岁,收入差异可能不大。

3.1 使用 Pandas 进行分桶

为了按年龄对数据进行分桶,我定义了三个“桶”:

  • 年轻 — 28 岁及以下

  • 中年 — 29 至 59 岁

  • 老年 — 60 岁及以上

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

# creating a dictionary
sns.set_style("whitegrid")
plt.rc('font', size=16) #controls default text size
plt.rc('axes', titlesize=16) #fontsize of the title
plt.rc('axes', labelsize=16) #fontsize of the x and y labels
plt.rc('xtick', labelsize=16) #fontsize of the x tick labels
plt.rc('ytick', labelsize=16) #fontsize of the y tick labels
plt.rc('legend', fontsize=16) #fontsize of the legend

# load dataset - census income
census_income = pd.read_csv(r'../input/income/train.csv')

# define figure
fig, (ax1, ax2) = plt.subplots(2)
fig.set_size_inches(18.5, 10.5)

# plot age histogram
age_count = census_income.groupby(by=["age"])["age"].count()
ax1.bar(age_count.index, age_count, color='black')
ax1.set_ylabel("Counts")
ax1.set_xlabel("Age")

# binning age
def age_bins(age):
    if age < 29:
        return "1 - young"
    if age < 60 and age >= 29:
        return "2 - middle-aged"
    else:
        return "3 - old-aged"

# apply trans. function
census_income["age_bins"] = census_income["age"].apply(age_bins)

# group and count all entries in the same bin
age_bins_df = census_income.groupby(by=["age_bins"])["age_bins"].count()

ax2.bar(age_bins_df.index, age_bins_df, color='grey')
ax2.set_ylabel("Counts")
ax2.set_xlabel("Age")

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

3.2 使用 Tensorflow 进行分桶

Tensorflow 提供了一个名为feature columns的模块,包含了一系列用于帮助处理原始数据的函数。特征列是组织和解释原始数据的函数,以便机器学习算法可以解读和利用这些数据进行学习。[Google Developers, 2017]

TensorFlow 的 feature_column.bucketized_column API 提供了一种对数值数据进行分桶的方法。这个 API 接受一个数值列,并根据指定的边界创建一个桶化列。输入的数值列可以是连续的或离散的。

import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow import feature_column
from tensorflow.keras import layers

# load dataset - census income
census_income = pd.read_csv(r'../input/income/train.csv')
data = census_income.to_dict('list')

# A utility method to show the transformation from feature column
def demo(feature_column):
    feature_layer = layers.DenseFeatures(feature_column)
    return feature_layer(data).numpy()

age = feature_column.numeric_column("age")
age_buckets = feature_column.bucketized_column(age, boundaries=[30,50])
buckets = demo(age_buckets)

# add buckets to the data set
buckets_tensorflow = pd.DataFrame(buckets)

# define boundaries for buckets
boundary1 = 30
boundary2 = 50

# define column names for buckets
bucket1=f"age<{boundary1}"
bucket2=f"{boundary1}<age<{boundary2}"
bucket3=f"age>{boundary2}"

buckets_tensorflow_renamed = buckets_tensorflow.rename(columns = {0:bucket1,
                                                                    1:bucket2,
                                                                    2:bucket3})

buckets_tensorflow_renamed.assign(age=census_income["age"]).head(7)

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

我们可以通过使用KBinsDiscretizer来自***Scikit-learn.***做到这一点。

3.3 使用 Scikit-learn 进行分桶化

from sklearn.preprocessing import KBinsDiscretizer

# define bucketizer
est = KBinsDiscretizer(n_bins=3, encode='ordinal', strategy='uniform')
est.fit(census_income[["age"]])

# transform data
buckets = est.transform(census_income[["age"]])

# add buckets column to data frame
census_income_bucketized = census_income.assign(buckets=buckets)[["age", "buckets"]]
census_income_bucketized

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

最后一个关于分类值的示例 …

没有一种普遍适用的最佳方式来以数字形式表示分类变量。使用哪种方法,取决于具体的使用案例和你希望传达给模型的信息。不同的编码方法可以突出数据的不同方面,因此选择最适合你特定使用案例的方法非常重要。

示例 3: 分类值分桶化 — 例如 国家

供应链 — 在评估供应商/分包商的可靠性时,地区、气候和运输类型等因素可以影响交货时间的准确性。在我们的资源规划系统中,我们通常存储供应商的国家和城市。由于一些国家在某些方面相似而在其他方面完全不同,突出与使用案例相关的方面可能是有意义的。

  • 如果我们想突出国家之间的距离并将同一地区的国家分组,我们可以为大陆定义区间

  • 如果我们更关心价格或可能的收入,人均 GDP 可能更为重要 → 在这里我们可以将“高成本”国家如美国、德国和日本归入一个区间

  • 如果我们想突出一般的天气条件,我们可以将北方国家如加拿大和挪威放在同一个区间

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

示例: 使用不同属性对国家进行分桶化 — 图片由作者提供

4. Transformer

转换技术是用来改变数据集形式或分布的方法。一些常见的转换技术,如对数Box-Cox 函数,用于将不符合正态分布的数据转换为更对称、更接近钟形曲线的数据。这些技术在数据需要满足特定统计模型或技术要求的假设时可能会很有用。使用的具体转换方法可能取决于期望的结果和数据的特性。

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

Transformers: 转换特征值分布 — 图片由作者提供

4.1 使用 Numpy 的 Log-Transformer

对数转换器用于通过对每个值应用对数函数来改变数据的尺度。这种转换通常用于将高度偏斜的数据转换为更接近正态分布的数据。

数据偏斜绝不是不寻常的现象,在许多情况下,数据自然或人为地呈现偏斜,例如:

  • 词汇在语言中的使用频率遵循一种被称为齐普夫定律的模式

  • 人类感知不同刺激的方式遵循一种由史蒂文斯幂函数描述的模式

数据的分布不对称,可能存在大量比大多数数据值更大或更小的长尾值。

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

正常分布与幂律分布 — 图片由作者提供(灵感来自 [Geeksforgeeks, 2022]

某些类型的算法可能难以处理这种类型的数据,可能会产生较少的准确或可靠结果。应用幂变换,如 Box-Cox 变换或对数变换,可以帮助调整数据的尺度,使其更适合这些算法处理。[Geeksforgeeks, 2020]

让我们看看变换器如何影响实际数据。因此,我使用了世界人口、在线新闻流行度和波士顿住房数据集:

数据集 1: 世界人口 [许可证: CC BY 3.0 IGO]

population.un.org/wpp/Download/Standard/CSV/

数据集包含了全球每个国家的人口数据。[联合国, 2022]

数据集 2: 在线新闻流行度 [许可证: CC0: 公共领域]

archive.ics.uci.edu/ml/datasets/online+news+popularity

该数据集总结了 Mashable 在两年内发布的文章的异质特征。目标是预测社交网络中的分享数量(流行度)。

数据集 3: 波士顿住房数据集 [许可证: CC0: 公共领域]

www.cs.toronto.edu/~delve/data/boston/bostonDetail.html

波士顿住房数据集由美国人口普查局在 1970 年代末和 1980 年代初收集。它包含波士顿(马萨诸塞州)地区房屋的中位数价值的信息。该数据集包括 13 个属性,例如每栋房屋的平均房间数、到就业中心的平均距离和财产税率,以及该地区房屋的中位数价值。

以下函数帮助绘制数据集变换前后的分布图:

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from scipy import stats
import seaborn as sns

def plot_transformer(chosen_dataset, chosen_transformation, chosen_feature = None, box_cox_lambda = 0):
    plt.rcParams['font.size'] = '16'
    sns.set_style("darkgrid", {"axes.facecolor": ".9"})

    ##################################################################################################
    # choose dataset
    ##################################################################################################
    if chosen_dataset == "Online News Popularity":
        df = pd.read_csv("../input/uci-online-news-popularity-data-set/OnlineNewsPopularity.csv")
        X_feature = " n_tokens_content"
    elif chosen_dataset == "World Population":
        df = pd.read_csv("../input/world-population-dataset/WPP2022_TotalPopulationBySex.csv")
        df = df[df["Time"]==2020]
        df["Area"] = df["PopTotal"] / df["PopDensity"]
        X_feature = "Area"
    elif chosen_dataset == "Housing Data":
        df = pd.read_csv("../input/housing-data-set/HousingData.csv")
        X_feature = "AGE"

    # in case you want to plot the histogram for another feature
    if chosen_feature != None:
        X_feature = chosen_feature

    ##################################################################################################
    # choose type of transformation
    ##################################################################################################
    #chosen_transformation = "box-cox" #"log", "box-cox"

    if chosen_transformation == "log":
        def transform_feature(df, X_feature):
            # We add 1 to number_of_words to make sure we don't have a null value in the column to be transformed (0-> -inf) 
            return (np.log10(1+ df[[X_feature]]))

    elif chosen_transformation == "box-cox":
        def transform_feature(df, X_feature):
            return stats.boxcox(df[[X_feature]]+1, lmbda=box_cox_lambda)
            #return stats.boxcox(df[X_feature]+1)

    ##################################################################################################
    # plot histogram to chosen dataset and X_feature
    ##################################################################################################
    # figure settings
    fig, (ax1, ax2) = plt.subplots(2)
    fig.set_size_inches(18.5, 10.5)

    ax1.set_title(chosen_dataset)
    ax1.hist(df[[X_feature]], 100, facecolor='black', ec="white")
    ax1.set_ylabel(f"Count {X_feature}")
    ax1.set_xlabel(f"{X_feature}")

    ax2.hist(transform_feature(df, X_feature), 100, facecolor='black', ec="white")
    ax2.set_ylabel(f"Count {X_feature}")
    ax2.set_xlabel(f"{chosen_transformation} transformed {X_feature}")

    fig.show()

在接下来的内容中,我不仅测试数据变换后的效果,还对这种变换如何影响模型构建过程感兴趣。我使用多项式回归来建立简单的回归模型,并比较模型的性能。模型的输入数据仅为 2 维:

  • 对于Only News Popularity 数据集,我们尝试建立一个模型,该模型根据在线文章的“n_tokens”预测“分享数”——也就是说,我们试图建立一个模型,根据文章的标记数量/长度预测文章的受欢迎程度。

  • 对于World Population data set,我们建立了一个简单的模型,该模型仅根据一个输入特征——国家的面积——来预测人口。

示例 1: 世界人口数据集 — 国家面积

plot_transformer(chosen_dataset = "World Population", chosen_transformation = "log")

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

在图表中,你可以看到原始分布,虽然偏向左侧,但已经被转化为一个更对称的分布。

我们也试试在线新闻受欢迎度数据集:

示例 2: 在线新闻受欢迎度数据集 — 根据文章长度的文章受欢迎程度

plot_transformer(chosen_dataset = "Online News Popularity", chosen_transformation = "log")

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

这个例子更好地展示了效果。偏斜的数据被转化为几乎“完美”的正态分布数据。

但是这会对模型构建过程产生积极影响吗?为此,我为原始数据和转化数据创建了多项式模型,并比较它们的表现:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score
import plotly.graph_objects as go
import pandas as pd
from scipy import stats
import plotly.express as px
import seaborn as sns

def plot_cross_val_score_comparison(chosen_dataset):
    scores_raw = []
    scores_transformed = []
    degrees = []

    if chosen_dataset == "Online News Popularity":
        df = pd.read_csv("../input/uci-online-news-popularity-data-set/OnlineNewsPopularity.csv")
        X = df[[" n_tokens_content"]]
        y = df[" shares"]
    elif chosen_dataset == "World Population":
        df = pd.read_csv("../input/world-population-dataset/WPP2022_TotalPopulationBySex.csv")
        df = df[df["Time"]==2020]
        df["Area"] = df["PopTotal"] / df["PopDensity"]
        X = df[["Area"]]
        y = df["PopTotal"]

    for i in range(1,10):
        degree = i
        polynomial_features = PolynomialFeatures(degree=degree, include_bias=False)

        linear_regression = LinearRegression()
        pipeline = Pipeline(
            [
                ("polynomial_features", polynomial_features),
                ("linear_regression", linear_regression),
            ]
        )

        # Evaluate the models using crossvalidation
        scores = cross_val_score(
            pipeline, X, y, scoring="neg_mean_absolute_error", cv=5
        )

        scores_raw.append(scores.mean())
        degrees.append(i)

        #########################################################################
        # Fit model with transformed data
        #########################################################################
        def transform_feature(X):
            # We add 1 to number_of_words to make sure we don't have a null value in the column to be transformed (0-> -inf) 
            #return (np.log10(1+ X))
            return stats.boxcox(X+1, lmbda=0)

        X_trans = transform_feature(X)

        pipeline.fit(X_trans, y)

        # Evaluate the models using crossvalidation
        scores = cross_val_score(
            pipeline, X_trans, y, scoring="neg_mean_absolute_error", cv=5
        )

        scores_transformed.append(scores.mean())

    plot_df = pd.DataFrame(degrees, columns=["degrees"])
    plot_df = plot_df.assign(scores_raw = np.abs(scores_raw))
    plot_df = plot_df.assign(scores_transformed = np.abs(scores_transformed))

    fig = go.Figure()
    fig.add_scatter(x=plot_df["degrees"], y=plot_df["scores_transformed"], name="Scores Transformed", line=dict(color="#0000ff"))

    # Only thing I figured is - I could do this 
    #fig.add_scatter(x=plot_df['degrees'], y=plot_df['scores_transformed'], title='Scores Raw')  
    fig.add_scatter(x=plot_df['degrees'], y=plot_df['scores_raw'], name='Scores Raw')

    # write scores for raw and transformed data in one data frame and find degree that shows the mininmal error score
    scores_df = pd.DataFrame(np.array([degrees,scores_raw, scores_transformed]).transpose(), columns=["degrees", "scores_raw", "scores_transformed"]).abs()
    scores_df_merged = scores_df[["degrees","scores_raw"]].rename(columns={"scores_raw":"scores"}).append(scores_df[["degrees", "scores_transformed"]].rename(columns={"scores_transformed":"scores"}))
    degree_best_performance = scores_df_merged[scores_df_merged["scores"]==scores_df_merged["scores"].min()]["degrees"]

    # plot a vertical line
    fig.add_vline(x=int(degree_best_performance), line_width=3, line_dash="dash", line_color="red", name="Best Performance")

    # update plot layout
    fig.update_layout(
        font=dict(
            family="Arial",
            size=18,  # Set the font size here
            color="Black"
        ),
        xaxis_title="Degree",
        yaxis_title="Mean Absolute Error",
        showlegend=True,
        width=1200,
        height=400,
    )

    fig['data'][0]['line']['color']="grey"
    fig['data'][1]['line']['color']="black"

    fig.show()
    return degree_best_performance

我意识到这个简单的二维示例并不是一个具有代表性的例子,因为仅凭一个属性无法准确预测目标变量。然而,我们来看看转化是否有任何改变。

首先,让我们尝试使用在线新闻受欢迎度数据集:

degree_best_performance_online_news = plot_cross_val_score_comparison(chosen_dataset="Online News Popularity")

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

在原始和转化数据上训练的多项式回归模型的表现 — 作者提供的图片

在转化数据上训练的模型表现稍好一些。尽管从 3213 到 3202 的绝对误差差异不是特别大,但这确实表明数据转化对训练过程有积极的影响。

通过绘制转化后的数据并建立模型,我们可以看到,数据被向右移动了。这给了模型更多的“空间”来拟合数据:

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline
import numpy as np

def plot_polynomial_regression_model(chosen_dataset, chosen_transformation, degree_best_performance):
    # fig settings
    plt.rcParams.update({'font.size': 16})
    fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(15, 6))

    if chosen_dataset == "Online News Popularity":
        df = pd.read_csv("../input/uci-online-news-popularity-data-set/OnlineNewsPopularity.csv")
        y_column = " shares"
        X_column = " n_tokens_content"
        X = df[[X_column]]
        y = df[y_column]
    elif chosen_dataset == "World Population":
        df = pd.read_csv("../input/world-population-dataset/WPP2022_TotalPopulationBySex.csv")
        df = df[df["Time"]==2020]
        df["Area"] = df["PopTotal"] / df["PopDensity"]
        y_column = "PopTotal"
        X_column = "Area"
        X = df[[X_column]]
        y = df[y_column]

    #########################################################################
    # Define model
    #########################################################################
    # degree_best_performance was calculated in the cell above
    degree = int(degree_best_performance)
    polynomial_features = PolynomialFeatures(degree=degree, include_bias=False)

    linear_regression = LinearRegression()
    pipeline = Pipeline(
        [
            ("polynomial_features", polynomial_features),
            ("linear_regression", linear_regression),
        ]
    )

    #########################################################################
    # Fit model
    #########################################################################
    pipeline.fit(X, y)

    ######################################################################################
    # Fit model and plot raw features
    ######################################################################################
    reg = pipeline.fit(X, y)
    X_pred = np.linspace(min(X.iloc[:,0]), max(X.iloc[:,0]),1000).reshape(-1,1)
    X_pred = pd.DataFrame(X_pred)
    X_pred.columns = [X.columns[0]]
    y_pred_1 = reg.predict(X_pred)

    # plot model and transformed data    
    ax[0].scatter(X, y, color='#f3d23aff')
    ax[0].plot(X_pred, y_pred_1, color='black')
    ax[0].set_xlabel(f"{X_column}")
    ax[0].set_ylabel(f"{y_column}")
    ax[0].set_title(f"Raw features / Poly. Regression (degree={degree})", pad=20)

    #########################################################################
    # Fit model with transformed data
    #########################################################################
    def transform_feature(X, chosen_transformation):
        # We add 1 to number_of_words to make sure we don't have a null value in the column to be transformed (0-> -inf) 
        if chosen_transformation == "log":
            return (np.log10(1+ X))
        if chosen_transformation == "box-cox":
            return stats.boxcox(X+1, lmbda=0)

    X_trans = transform_feature(X, chosen_transformation)

    # fit model with transformed data
    reg = pipeline.fit(X_trans, y)

    # define X_pred
    X_pred = np.linspace(min(X_trans.iloc[:,0]), max(X_trans.iloc[:,0]),1000).reshape(-1,1)
    X_pred = pd.DataFrame(X_pred)
    X_pred.columns = [X.columns[0]]

    # predict
    y_pred_2 = reg.predict(X_pred)

    # plot model and transformed data    
    ax[1].scatter(X_trans, y, color='#f3d23aff')
    ax[1].plot(X_pred, y_pred_2, color='black')
    ax[1].set_xlabel(f"{chosen_transformation} Transformed {X_column}")
    ax[1].set_ylabel(f"{y_column}")
    # calc cross val score and add to title
    ax[1].set_title(f"Transformed features  / Poly. Regression (degree={degree})", pad=20)

    fig.suptitle(chosen_dataset)
    fig.tight_layout()

我们使用刚刚定义的函数来绘制表现最佳的多项式模型:

plot_polynomial_regression_model(chosen_dataset = "Online News Popularity", chosen_transformation = "log", degree_best_performance=degree_best_performance_online_news)

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

多项式回归模型: 在线新闻的分享数 — 作者提供的图片

我们来尝试一下世界人口数据集:

degree_best_performance_world_pop = plot_cross_val_score_comparison(chosen_dataset="World Population")

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

在原始和转化数据上训练的多项式回归模型的表现 — 作者提供的图片

我们可以看到,模型在原始数据集和转化数据集之间的表现差异很大。虽然基于原始数据的模型在低多项式度数时表现显著更好,但在构建高多项式度数的模型时,训练在转化数据上的模型表现更佳。

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

多项式回归模型: 国家人口 — 作者提供的图片

仅供比较,这是针对原始数据表现最佳的线性模型:

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

多项式回归模型:国家人口 — 作者图片

4.2 使用 Scipy 的 Box-Cox 函数

另一个非常流行的变换函数是 Box-Cox 函数,它属于幂变换的范畴。

幂变换器是一类参数化变换,旨在将任何数据分布转换为正态分布的数据集,并最小化方差和偏斜。 [Sklearn.org]

为了实现这种灵活的变换,Box-Cox 函数定义如下:

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

要使用 Box-Cox 函数,我们必须确定变换参数 lambda。如果未手动指定 lambda,变换器将通过最大化似然函数来寻找最佳 lambda。 [Rdocumentation.org] 可以通过函数scipy.stats.boxcox找到合适的实现。

注意:Box-Cox 函数必须用于大于零的数据。

Box-Cox 变换比对数变换更灵活,因为它可以产生各种变换形状,包括线性、二次和指数,这些可能更好地适应数据。此外,Box-Cox 变换可以用于变换既正偏又负偏的数据,而对数变换只能用于正偏数据。

lambda 参数的用途是什么?

参数 lambda(λ)可以调整,以根据被分析数据的特征来定制变换。lambda 值为 0 会产生对数变换,而 0 到 1 之间的值会产生越来越“”的变换。如果 lambda 设置为 1,则函数不会对数据进行任何变换。

为了展示 Box-Cox 函数可以转换不仅仅是右偏的数据,我还使用了来自波士顿住房数据集的AGE(“建于 1940 年前的自有住房比例”)属性。

import seaborn as sns

plot_transformer(chosen_dataset = "Housing Data", chosen_transformation = "box-cox", chosen_feature = None, box_cox_lambda = 2.5)

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

5. 归一化 / 标准化

归一化和标准化是机器学习中的重要预处理步骤。它们可以帮助算法更快地收敛,甚至提高模型的准确性。

5.1 使用 Scikit-learn 进行归一化和标准化

  • Scikit-learn 的 MinMaxScaler将特征缩放到给定范围内。它通过将每个特征缩放到 0 到 1 之间的给定范围来变换特征。

  • Scikit-learn 的 StandardScaler将数据转换为均值为 0 和标准差为 1。

# data normalization with sklearn
from sklearn.preprocessing import MinMaxScaler, StandardScaler
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

plt.rcParams['font.size'] = '16'
sns.set_style("darkgrid", {"axes.facecolor": ".9"})

# load data set
census_income = pd.read_csv(r'../input/income/train.csv')

X = census_income[["age"]]

# fit scaler and transform data
X_norm = MinMaxScaler().fit_transform(X)
X_scaled = StandardScaler().fit_transform(X)

# plots
fig, (ax1, ax2, ax3) = plt.subplots(3)
fig.suptitle('Normalizing')
fig.set_size_inches(18.5, 10.5)

# subplot 1 - raw data
ax1.hist(X, 25, facecolor='black', ec="white")
ax1.set_xlabel("Age")
ax1.set_ylabel("Frequency")

# subplot 2 - normalizer
ax2.hist(X_norm, 25, facecolor='black', ec="white")
ax2.set_xlabel("Normalized Age")
ax2.set_ylabel("Frequency")

# subplot 3 - standard scaler
ax3.hist(X_scaled, 25, facecolor='black', ec="white")
ax3.set_xlabel("Normalized Age")
ax3.set_ylabel("Frequency")

fig.tight_layout()

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

6. 特征交叉

特征交叉是将数据集中的多个特征连接起来以创建新特征的过程。这可以包括结合其他来源的数据,以强调现有的相关性。

创造力没有限制。首先,通过正确组合属性使已知相关性显现是有意义的,例如:

示例 1:预测公寓的价格

假设我们有一系列要出售的公寓,并且有技术蓝图,从而可以获得这些公寓的尺寸。

为了确定公寓的合理价格,具体的尺寸可能不像总面积那样重要:一个房间是 6 米 * 7 米还是 5.25 米 * 8 米,并不像房间有 42 平方米那样重要。如果我只知道尺寸 a 和 b,那么将面积作为一个特征添加进去是有意义的。

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

预测公寓的价格 — 图片来自作者

示例 2:利用技术知识 — 预测铣床的能耗

几年前,我在研究一个回归模型,该模型可以预测铣床的能耗。

在为特定领域实施解决方案时,查看现有文献总是值得的。由于人们对计算切割机功率需求的兴趣已有 50 年,我们可以利用这 50 年的研究成果。

即使现有的公式仅适用于粗略计算,我们仍可以利用关于属性和目标变量(能耗)之间已识别的相关性的知识。在下图中,你可以看到一些功率需求与变量之间的已知关系。

→ 通过将这些已知关系作为特征突出显示,我们可以使模型更容易处理。例如,我们可以交叉切割宽度 b切割深度 h(以计算截面积 A),并将其定义为一个新特征。这可能有助于训练过程,特别是当我们使用较简单的模型时。

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

铣床功率需求的计算 — 图片来自作者

但我们不仅仅用它来准备数据集,一些算法将特征交叉作为其工作原理的基本部分。

一些机器学习方法和算法默认已经使用特征交叉

两种著名的机器学习技术使用特征交叉是多项式回归核技巧(例如,与支持向量回归结合使用)

6.1 多项式回归中的特征交叉

Scikit-learn 不包含多项式回归的功能,我们从以下步骤创建一个管道:

  1. 特征变换步骤和

  2. 一个线性回归模型构建步骤。

通过组合和指数化特征,我们生成了若干新的特征,这使得可以表示输出变量之间的非线性关系。

假设我们要构建一个具有二维输入矩阵 X 和目标变量 y 的回归模型。除非特别定义,否则特征转换函数(sklearn.PolynomialFeatures)将矩阵转换如下:

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

你可以看到,新矩阵包含四个新列。属性不仅被增强,还相互交叉:

import numpy as np
from sklearn.preprocessing import PolynomialFeatures

# Raw input features
X = np.arange(6).reshape(3, 2)
print("Raw input matrix:")
display(X)

# Crossed features
poly = PolynomialFeatures(2)
print("Transformed feature matrix:")
poly.fit_transform(X)

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

这样我们可以建模任何可想象的关系,我们只需选择正确的多项式度数。

以下示例展示了一个多项式回归模型(多项式度数=5),它基于属性 LSTAT(低社会经济状态的人口百分比)预测波士顿自有住房的中位数价值。

from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.pipeline import Pipeline

import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

plt.rcParams['font.size'] = '16'
sns.set_style("darkgrid", {"axes.facecolor": ".9"})

# load data set: Boston Housing
boston_housing_df = pd.read_csv("../input/housing-data-set/HousingData.csv")
boston_housing_df = boston_housing_df.dropna()
boston_housing_df = boston_housing_df.sort_values(by=["LSTAT"])

# define x and target variable y
X = boston_housing_df[["LSTAT"]]
y = boston_housing_df["MEDV"]

# fit model and create predictions
degree = 5
polynomial_features = PolynomialFeatures(degree=degree)
linear_regression = LinearRegression()
pipeline = Pipeline(
    [
        ("polynomial_features", polynomial_features),
        ("linear_regression", linear_regression),
    ]
)
pipeline.fit(X, y)

y_pred = pipeline.predict(X)

# train linear model
regr = LinearRegression()
regr.fit(X,y)

# figure settings
fig, (ax1) = plt.subplots(1)
fig.set_size_inches(18.5, 6)

ax1.set_title("Boston Housing: Median value of owner-occupied homes")
ax1.scatter(X, y, c="black")
ax1.plot(X, y_pred, c="red", linewidth=4, label=f"Polynomial Model (degree={degree})")
ax1.set_ylabel(f"MEDV")
ax1.set_xlabel(f"LSTAT")
ax1.legend()

fig.show()

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

6.2 特征交叉和核技巧

另一个特征交叉已经被固有使用的例子是核技巧,例如在支持向量回归中。通过核函数,我们将数据集转换到更高维空间,使得可以轻松分离不同类别。

对于以下示例,我生成了一个二维数据集,这在二维空间中相当难以分离,至少对于线性模型而言。

from sklearn.datasets import make_circles
from sklearn import preprocessing
import plotly_express as px
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd

sns.set_style("darkgrid", {"axes.facecolor": ".9"})
plt.rcParams['font.size'] = '30'

# generate a data set
X, y = make_circles(n_samples=1_000, factor=0.3, noise=0.05, random_state=0)
X = preprocessing.scale(X)

X=X[500:]
y=y[500:]

# define target value, here: binary classification, class 1 or class 2
y=np.where(y==0,"class 1","class 2")

# define x1 and x2 of a 2-dimensional data set
x1 = X[:,0]
x2 = X[:,1]

import plotly_express as px
# define the kernel function
kernel = x1*x2 + x1**2 + x2**2

circle_df = pd.DataFrame(X).rename(columns={0:"x1", 1:"x2"})
circle_df = circle_df.assign(y=y)

color_discrete_map = {circle_df.y.unique()[0]: "black", circle_df.y.unique()[1]: "#f3d23a"}
px.scatter(circle_df, x="x1", y="x2", color="y", color_discrete_map = color_discrete_map, width=1000, height=800)

# plot the data set together with the kernel value in a 3-dimensional space
color_discrete_map = {circle_df.y.unique()[0]: "black", circle_df.y.unique()[1]: "grey"}
fig = px.scatter(circle_df, x="x1", y="x2", color="y", color_discrete_map = color_discrete_map, width=1000, height=600)
fig.update_layout(
    font=dict(
        family="Arial",
        size=24,  # Set the font size here
        color="Black"
    ),
    showlegend=True,
    width=1200,
    height=800,
)

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

通过使用核技巧,我们生成了第三维度。在这个例子中,核函数定义为:

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

import plotly_express as px

# define the kernel function
kernel = x1*x2 + x1**2 + x2**2

kernel_df = pd.DataFrame(X).rename(columns={0:"x1", 1:"x2"})
kernel_df = kernel_df.assign(kernel=kernel)
kernel_df = kernel_df.assign(y=y)

# plot the data set together with the kernel value in a 3-dimensional space
color_discrete_map = {kernel_df.y.unique()[0]: "black", kernel_df.y.unique()[1]: "grey"}  
px.scatter_3d(kernel_df, x="x1", y="x2", z="kernel", color="y", width=1000, height=600)

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

核技巧:二维数据集转移到三维空间 — 图片由作者提供

三维空间允许使用简单的线性分类器分离数据。

7. 主成分分析(PCA)

主成分分析,或 PCA,通过创建一组从原始特征中衍生的新特征来减少数据集的维度。因此,类似于哈希,我们减少了数据集的复杂性,从而减少了计算工作量。

此外,它还可以帮助我们可视化数据集。具有多个维度的数据集可以在较低维度的表示中进行可视化,同时尽可能保留原始变异。

我将省略如何在本节中深入解释,因为已经有一些很好的资料,例如:

简要总结,以下是四个最重要的步骤:

  1. 标准化数据: 从每个特征中减去均值,并将特征缩放到单位方差。

  2. 计算标准化数据的协方差矩阵: 该矩阵将包含所有特征之间的成对协方差。

  3. 计算协方差矩阵的特征向量和特征值: 特征向量确定新特征空间的方向,并表示主成分,特征值确定它们的大小。

  4. 选择主成分: 选择前几个主成分(通常是特征值最高的那些),并用它们将数据投影到低维空间。你可以根据想要保留的方差量或希望将数据减少到的维度数来选择保留的成分数。

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

PCA 如何工作 — 图片由作者提供(灵感来源于 [Zheng, Alice, and Amanda Casari, 2018])

我将向你展示如何使用 PCA 创建新的特征,使用鸢尾花数据集

数据集:鸢尾花数据集 [许可证:CC0: 公共领域]

archive.ics.uci.edu/ml/datasets/iris

www.kaggle.com/datasets/uciml/iris

鸢尾花数据集包含关于三种鸢尾花(Iris setosa、Iris virginica 和 Iris versicolor)的信息。它包括花的萼片和花瓣的长度和宽度(以厘米为单位),并包含 150 个观察值。

所以首先,让我们加载数据集,查看四个维度(萼片长度、萼片宽度、花瓣长度、花瓣宽度)中的数据分布。

from matplotlib import pyplot as plt
import numpy as np
import seaborn as sns
import math

import pandas as pd

# Load the Iris dataset
iris_data = pd.read_csv(r'../input/iris-data/Iris.csv')
iris_data.dropna(how="all", inplace=True) # drops the empty line at file-end

sns.set_style("whitegrid")
colors = ["black", "#f3d23aff", "grey"]
plt.figure(figsize=(10, 8))

with sns.axes_style("darkgrid"):
    for cnt, column in enumerate(iris_data.columns[1:5]):
        plt.subplot(2, 2, cnt+1)
        for species_cnt, species in enumerate(iris_data.Species.unique()):
            plt.hist(iris_data[iris_data.Species == species][column], label=species, color=colors[species_cnt])

        plt.xlabel(column)
    plt.legend(loc='upper right', fancybox=True, fontsize=8)

    plt.tight_layout()
    plt.show()

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

从分布中你可以看出,基于花瓣宽度和花瓣长度可以相对较好地区分各个类别。在其他两个维度中,分布强烈重叠。

这表明花瓣宽度和花瓣长度对我们的模型可能比其他两个维度更为重要。因此,如果我只能使用两个维度作为模型特征,我会选择这两个。如果我们绘制这两个维度,我们得到如下图:

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

还不错,我们看到通过选择“最重要”的属性,我们可以减少维度并尽可能少地丢失信息。

PCA 更进一步,它对数据进行中心化和缩放,并将数据投影到新生成的维度上。这样我们不再局限于现有维度。类似于我们在空间中旋转数据集的 3D 表示,直到找到一种使我们尽可能容易分离类别的方向:

import plotly_express as px

color_discrete_map = {iris_data.Species.unique()[0]: "black", iris_data.Species.unique()[1]: "#f3d23a", iris_data.Species.unique()[2]:"grey"}

px.scatter_3d(iris_data, x="PetalLengthCm", y="PetalWidthCm", z="SepalLengthCm", size="SepalWidthCm", color="Species", color_discrete_map = color_discrete_map, width=1000, height=800)

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

鸢尾花数据集在 3D 图中的可视化 — 图片由作者提供

总的来说,PCA 会变换、缩放和旋转数据,直到找到一个新的维度集(主成分),该维度集捕捉到原始数据中最重要的信息。

适用于数据集的 PCA 函数可以在 Scikit-learn 中找到,sklearn.decomposition.PCA

7.1 使用 Scikit-learn 的 PCA

import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
import matplotlib
import plotly.graph_objects as go

# Load the Iris dataset
iris_data = pd.read_csv(r'../input/iris-data/Iris.csv')
iris_data.dropna(how="all", inplace=True) # drops the empty lines

# define X
X = iris_data[["PetalLengthCm", "PetalWidthCm", "SepalLengthCm", "SepalWidthCm"]]

# fit PCA and transform X
pca = PCA(n_components=2).fit(X)
X_transform = pca.transform(X)
iris_data_trans = pd.DataFrame(X_transform).assign(Species = iris_data.Species).rename(columns={0:"PCA1", 1:"PCA2"})

# plot 2d plot
color_discrete_map = {iris_data.Species.unique()[0]: "black", iris_data.Species.unique()[1]: "#f3d23a", iris_data.Species.unique()[2]:"grey"}
fig = px.scatter(iris_data_trans, x="PCA1", y="PCA2", color="Species", color_discrete_map = color_discrete_map)

fig.update_layout(
    font=dict(
        family="Arial",
        size=18,  # Set the font size here
        color="Black"
    ),
    showlegend=True,
    width=1200,
    height=800,
)

如果你将前两个主成分(PC1 和 PC2)的图与花瓣宽度和花瓣长度的二维图进行比较,你会发现数据集中最重要的信息得到了保留。此外,数据经过了中心化和标准化。

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

转换后的鸢尾花数据的 PCA1 和 PCA2 — 作者提供的图像

总结

文章中描述的技术可以应用于任何类型的数据,但它们不能替代特定领域的专用方法。

一个很好的例子是声学领域。假设你对声学和信号处理一无所知…。

  • 你会如何处理空气中的声音信号?你会提取哪些特征?

你是否曾考虑将信号分解为单独的频谱成分以了解信号的组成?可能不会。幸运的是,早在你之前,就有人提出了同样的问题,并定义了一些合适的变换方法,比如快速傅里叶变换(FFT)。

站在巨人的肩膀上

即使技术已经很先进,这也不意味着我们不能利用几十年前的洞见。我们可以从这些过去的经验中学习,并用它们来提高模型构建过程的效率。因此,如果你想创建有效解决实际问题的模型,花些时间了解数据来源领域总是一个好主意。

继续阅读…

如果你喜欢阅读,并想继续了解机器学习的概念、算法和应用,你可以在这里找到我相关的文章列表:

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

多米尼克·波尔泽

机器学习:概念、技术和应用

查看列表5 个故事外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果你对注册 Medium 以获取所有故事的无限访问权限感兴趣,可以通过使用我的 推荐链接来支持我。这将为我带来一小部分佣金,而不会给你带来额外费用。

感谢阅读!

参考文献

Box, G E P 和 D R Cox. “变换分析。” : 43.

Brown, Sara. 2022 年。 “为什么是‘数据中心人工智能’的时机。” MIT Sloanmitsloan.mit.edu/ideas-made-to-matter/why-its-time-data-centric-artificial-intelligence(2022 年 10 月 30 日)。

educative.io。 “特征选择和特征工程——机器学习系统设计。” Educative: Interactive Courses for Software Developerswww.educative.io/courses/machine-learning-system-design/q2AwDN4nZ73(2022 年 11 月 25 日)。

H2O 的特征工程——Dmitry Larko,高级数据科学家, H2O.Ai。 2017 年。 www.youtube.com/watch?v=irkV4sYExX4(2022 年 9 月 5 日)。

featureranking.com。 “案例研究:预测收入状况。” [www.featureranking.com*](www.featureranking.com/) www.featureranking.com/tutorials/machine-learning-tutorials/case-study-predicting-income-status/(2022 年 11 月 26 日)。

Geeksforgeeks. 2020 年。 “Python | Box-Cox 变换。” GeeksforGeekswww.geeksforgeeks.org/box-cox-transformation-using-python/(2022 年 12 月 25 日)。

Google Developers. 2017 年。 “使用 TensorFlow 的特征工程入门——机器学习配方第 9 期。” www.youtube.com/watch?v=d12ra3b_M-0(2022 年 9 月 5 日)。

Google Developers. “介绍 TensorFlow 特征列。” developers.googleblog.com/2017/11/introducing-tensorflow-feature-columns.html(2022 年 9 月 21 日)。

Heavy.ai。 2022 年。 “什么是特征工程?定义和常见问题 | HEAVY.AI。” www.heavy.ai/technical-glossary/feature-engineering(2022 年 9 月 19 日)。

heavy.ai。 “特征工程。” www.heavy.ai/technical-glossary/feature-engineering

Koehrsten, Will. “手动特征工程入门。” kaggle.com/code/willkoehrsen/introduction-to-manual-feature-engineering(2022 年 9 月 5 日)。

Kousar, Summer. “网络安全薪资的 EDA。” kaggle.com/code/summerakousar/eda-on-cyber-security-salary(2022 年 9 月 7 日)。

Moody, John. 1988. “在多分辨率层次中的快速学习。” 收录于 神经信息处理系统的进展,Morgan-Kaufmann. proceedings.neurips.cc/paper/1988/hash/82161242827b703e6acf9c726942a1e4-Abstract.html(2022 年 11 月 28 日)。

Poon, Wing. 2022. “机器学习中的特征工程(1/3)。” Medium. towardsdatascience.com/feature-engineering-for-machine-learning-a80d3cdfede6(2022 年 9 月 19 日)。

Poon, Wing. “机器学习中的特征工程(2/3)第二部分:特征生成。”:10。

pydata.org. “Pandas.Get_dummies — Pandas 1.5.2 文档。” pandas.pydata.org/docs/reference/api/pandas.get_dummies.html(2022 年 11 月 25 日)。

Raschka, Sebastian. “主成分分析。” Sebastian Raschka, PhD. sebastianraschka.com/Articles/2015_pca_in_3_steps.html(2022 年 12 月 17 日)。

Rdocumentation.org. “Boxcox 函数 — RDocumentation。” www.rdocumentation.org/packages/EnvStats/versions/2.7.0/topics/boxcox(2022 年 12 月 25 日)。

Sarkar, Dipanjan. 2019a. “分类数据。” Medium. towardsdatascience.com/understanding-feature-engineering-part-2-categorical-data-f54324193e63(2022 年 9 月 19 日)。

Sarkar, Dipanjan. 2019b. “连续数值数据。” Medium. towardsdatascience.com/understanding-feature-engineering-part-1-continuous-numeric-data-da4e47099a7b(2022 年 9 月 19 日)。

Sarkar, Dipanjan, Raghav Bali, 和 Tushar Sharma. 2018. 用 Python 实践机器学习. 加州伯克利:Apress. link.springer.com/10.1007/978-1-4842-3207-1(2022 年 11 月 25 日)。

Siddhartha. 2020. “TensorFlow 特征列(Tf.Feature_column)演示。” ML Book. medium.com/ml-book/demonstration-of-tensorflow-feature-columns-tf-feature-column-3bfcca4ca5c4(2022 年 9 月 21 日)。

Sklearn.org. “6.2. 特征提取。” scikit-learn. scikit-learn/stable/modules/feature_extraction.html(2022 年 11 月 28 日)。

spark.apache.org. “提取、转换和选择特征 — Spark 3.3.1 文档。” spark.apache.org/docs/latest/ml-features(2022 年 12 月 1 日)。

Tensorflow.org. “Tf.One_hot | TensorFlow v2.11.0。” TensorFlow. www.tensorflow.org/api_docs/python/tf/one_hot(2022 年 11 月 25 日)。

联合国经济社会事务部,人口司(2022)。2022 年世界人口展望,在线版

Valohai.com. 2022. “什么是机器学习管道?” valohai.com/machine-learning-pipeline/(2022 年 9 月 19 日)。

沃塔瓦,亚当。2022. “跟上数据 #105。” Medium. adamvotava.medium.com/keeping-up-with-data-105-6a2a8a41f4b6(2022 年 10 月 21 日)。

温伯格,基利安等。2009. “大规模多任务学习的特征哈希。” 收录于 第 26 届国际机器学习大会论文集 — ICML ’09,蒙特利尔,魁北克,加拿大:ACM 出版社,1–8. portal.acm.org/citation.cfm?doid=1553374.1553516(2022 年 12 月 25 日)。

什么使特征变得优秀? — 机器学习食谱 #3。2016. www.youtube.com/watch?v=N9fDIAflCMY(2022 年 9 月 5 日)。

维基媒体。“各国年均温度.png。” commons.wikimedia.org/wiki/File:Average_yearly_temperature_per_country.png(2022 年 12 月 25 日)。

维基百科。2022. “特征哈希。” 维基百科. en.wikipedia.org/w/index.php?title=Feature_hashing&oldid=1114513799(2022 年 11 月 28 日)。

郑阿丽斯和阿曼达·卡萨里。2018. 机器学习特征工程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值