Featuretools 中的 Woodwork 类型#

Featuretools 依赖于在创建 EntitySets、原语 (Primitives)、特征 (Features) 和特征矩阵时保持类型一致。以前,Featuretools 使用自己的类型系统,其中包含名为 Variables 的对象。现在及未来,Featuretools 将使用外部数据类型库进行类型处理:Woodwork

了解现有的 Woodwork 类型以及 Featuretools 如何使用 Woodwork 的类型系统,将使用户能够:- 构建能够最好地表示其数据的 EntitySets - 理解 Featuretools 原语可能的输入和返回类型 - 理解给定数据集和原语将生成哪些特征。

阅读理解 Woodwork 逻辑类型和语义标签指南,深入了解下面概述的可用 Woodwork 类型。

对于熟悉旧的 Variable 对象的用户,迁移到 Featuretools 1.0 版本指南对于将 Variable 类型转换为 Woodwork 类型会很有帮助。

物理类型#

物理类型定义了 Woodwork DataFrame 中的数据如何在磁盘或内存中存储。你可能还会看到列的物理类型被称为该列的 dtype

了解 Woodwork DataFrame 的物理类型非常重要,因为 Pandas 在执行 DataFrame 操作时依赖于这些类型。每个 Woodwork LogicalType 类都关联有一个单一的物理类型。

逻辑类型#

逻辑类型增加了关于如何解释或解析数据的额外信息,这些信息超出了物理类型所能包含的范围。事实上,多个逻辑类型可以具有相同的物理类型,每个逻辑类型都赋予了物理类型本身不包含的不同含义。

在 Featuretools 中,列的逻辑类型告知数据如何被读入 EntitySet 以及如何在深度特征合成的后续流程中使用。

Woodwork 提供了许多不同的逻辑类型,可以使用 list_logical_types 函数查看。

[1]:
import featuretools as ft

ft.list_logical_types()
[1]:
名称 类型字符串 描述 物理类型 标准标签 是默认类型 已注册 父类型
0 地址 地址 代表包含地址的逻辑类型 ... 字符串 {} True True None
1 年龄 年龄 代表包含整数年龄的逻辑类型 ... int64 {numeric} True True 整数
2 小数年龄 小数年龄 代表包含非负小数年龄的逻辑类型 ... float64 {numeric} True True 双精度浮点数
3 可为空年龄 可为空年龄 代表包含整数年龄的逻辑类型 ... Int64 {numeric} True True 可为空整数
4 布尔值 布尔值 代表包含二进制值的逻辑类型 ... bool {} True True 可为空布尔值
5 可为空布尔值 可为空布尔值 代表包含二进制值的逻辑类型 ... 布尔值 {} True True None
6 分类 分类 代表包含无序分类值的逻辑类型 ... 类别 {category} True True None
7 国家代码 国家代码 代表使用 ISO-3166 标准的国家代码的逻辑类型 ... 类别 {category} True True 分类
8 货币代码 货币代码 代表使用 ISO-4217 标准的货币代码的逻辑类型 ... 类别 {category} True True 分类
9 日期时间 日期时间 代表包含日期和时间的逻辑类型 ... datetime64[ns] {} True True None
10 双精度浮点数 双精度浮点数 代表包含正双精度值的逻辑类型 ... float64 {numeric} True True None
11 电子邮件地址 电子邮件地址 代表包含电子邮件地址的逻辑类型 ... 字符串 {} True True 未知
12 文件路径 文件路径 代表指定文件位置的逻辑类型 ... 字符串 {} True True None
13 IP 地址 ip 地址 代表包含 IP 地址的逻辑类型 ... 字符串 {} True True 未知
14 整数 整数 代表包含正双精度值的逻辑类型 ... int64 {numeric} True True 可为空整数
15 可为空整数 可为空整数 代表包含正双精度值的逻辑类型 ... Int64 {numeric} True True None
16 经纬度 经纬度 代表包含经度和纬度值的逻辑类型 ... 对象 {} True True None
17 自然语言 自然语言 代表包含文本或自由形式字符串的逻辑类型 ... 字符串 {} True True None
18 序数 序数 代表包含有序分类值的逻辑类型 ... 类别 {category} True True 分类
19 人全名 人全名 代表可能包含名字或全名的逻辑类型 ... 字符串 {} True True None
20 电话号码 电话号码 代表包含数字电话号码的逻辑类型 ... 字符串 {} True True 未知
21 邮政编码 邮政编码 代表包含一系列数字或字母作为邮政编码的逻辑类型 ... 类别 {category} True True 分类
22 子区域代码 子区域代码 代表使用 ISO-3166 标准的国家代码的逻辑类型 ... 类别 {category} True True 分类
23 时间差 时间差 代表包含表示时间跨度值的逻辑类型 ... timedelta64[ns] {} True True 未知
24 URL url 代表包含 URL 的逻辑类型,这些 URL 可以是有效或无效的 ... 字符串 {} True True 未知
25 未知 未知 代表无法从数据中推断出来的逻辑类型 ... 字符串 {} True True None

如果没有提供逻辑类型,Featuretools 将执行类型推断来为 EntitySets 中的数据分配逻辑类型,但也可以为任何列指定应设置的逻辑类型(前提是该列中的数据与逻辑类型兼容)。

要了解逻辑类型如何在 EntitySets 中使用的更多信息,请参阅创建 EntitySets指南。

要直接在 DataFrame 上设置逻辑类型的更多信息,请参阅 Woodwork 关于使用逻辑类型的指南。

语义标签#

语义标签为列提供了关于数据含义或潜在用途的附加信息。列可以有许多或没有语义标签。有些标签由 Woodwork 添加,有些由 Featuretools 添加,用户也可以根据需要添加额外的标签。

要直接在 DataFrame 上设置语义标签的更多信息,请参阅 Woodwork 关于使用语义标签的指南。

Woodwork 定义的语义标签#

Woodwork 在初始化时会为列添加某些语义标签。这些可以是与不同逻辑类型集关联的标准标签或索引标签。用户还可以添加标签,以便为 Woodwork 中的列赋予建议的含义。

要获取这些标签的列表,可以使用 list_semantic_tags 函数。

[2]:
ft.list_semantic_tags()
[2]:
名称 是标准标签 有效的逻辑类型
0 数值型 True [年龄, 小数年龄, 可为空年龄, 双精度浮点数, 整数...
1 类别 True [分类, 国家代码, 货币代码, 序数...
2 索引 False 任何逻辑类型
3 时间索引 False [日期时间, 年龄, 小数年龄, 可为空年龄, 双精度浮点数...
4 出生日期 False [日期时间]
5 忽略 False 任何逻辑类型
6 直通 False 任何逻辑类型

上面我们看到了在 Woodwork 中定义的语义标签。这些标签告知 Featuretools 如何解释数据,其中一个例子可以在 Age 原语中看到,它要求列上必须存在 date_of_birth 语义标签。

date_of_birth 标签不会被 Woodwork 自动添加,因此为了让 Featuretools 能够使用 Age 原语,必须手动将 date_of_birth 标签添加到任何适用的列中。

Featuretools 定义的语义标签#

就像 Woodwork 在内部指定语义标签一样,Featuretools 也定义了一些自己的标签,以便生成完整的特征集。这些标签存在于列上时具有特定的含义。

  • 'last_time_index' - 由 Featuretools 添加到 DataFrame 的最后一个时间索引列。表示此列已由 Featuretools 创建。

  • 'foreign_key' - 用于表示此列是关系中的子列,意味着此列与 EntitySet 中另一个 DataFrame 的相应索引列相关联。

Featuretools 中的 Woodwork#

既然我们已经描述了构成 Woodwork 类型系统的元素,接下来看看它们在 Featuretools 中的实际应用。

EntitySets 中的 Woodwork#

有关使用 Woodwork 构建 EntitySets 的更多信息,请参阅EntitySet 指南

让我们看看存储在零售数据演示 EntitySet 中的 Woodwork 类型信息

[3]:
es = ft.demo.load_retail()
es
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-featuretools/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-featuretools/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-featuretools/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-featuretools/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-featuretools/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-featuretools/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-featuretools/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
/home/docs/checkouts/readthedocs.org/user_builds/feature-labs-inc-featuretools/envs/stable/lib/python3.9/site-packages/woodwork/type_sys/utils.py:33: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  pd.to_datetime(
[3]:
Entityset: demo_retail_data
  DataFrames:
    order_products [Rows: 401604, Columns: 8]
    products [Rows: 3684, Columns: 4]
    orders [Rows: 22190, Columns: 6]
    customers [Rows: 4372, Columns: 3]
  Relationships:
    order_products.product_id -> products.product_id
    order_products.order_id -> orders.order_id
    orders.customer_name -> customers.customer_name

Woodwork 类型信息不存储在 EntitySet 对象中,而是存储在构成 EntitySet 的各个 DataFrame 中。要查看 Woodwork 类型信息,我们首先从 EntitySet 中选择一个 DataFrame,然后通过 ww 命名空间访问 Woodwork 信息。

[4]:
df = es["products"]
df.head()
[4]:
product_id 描述 first_order_products_time _ft_last_time
85123A 85123A WHITE HANGING HEART T-LIGHT HOLDER 2010-12-01 08:26:00 2011-12-09 11:34:00
71053 71053 WHITE METAL LANTERN 2010-12-01 08:26:00 2011-12-07 14:12:00
84406B 84406B CREAM CUPID HEARTS COAT HANGER 2010-12-01 08:26:00 2011-12-05 14:30:00
84029G 84029G KNITTED UNION FLAG HOT WATER BOTTLE 2010-12-01 08:26:00 2011-12-09 11:26:00
84029E 84029E RED WOOLLY HOTTIE WHITE HEART. 2010-12-01 08:26:00 2011-12-09 09:07:00
[5]:
df.ww
[5]:
物理类型 逻辑类型 语义标签
product_id 类别 分类 ['索引']
描述 字符串 自然语言 []
first_order_products_time datetime64[ns] 日期时间 ['时间索引']
_ft_last_time datetime64[ns] 日期时间 ['最后一个时间索引']

请注意,显示此 DataFrame 类型信息的三个列是本指南开头概述的类型信息的三个要素。重申一下:通过为 DataFrame 中的每一列定义物理类型、逻辑类型和语义标签,我们定义了 DataFrame 的 Woodwork schema,并借此可以了解每列的内容。

存在于 EntitySet 中每个 DataFrame 的每一列的这种列特定类型信息是深度特征合成生成 EntitySet 特征能力不可或缺的一部分。

DFS 中的 Woodwork#

作为 Featuretools 中的计算单元,原语 (Primitives) 需要能够指定它们允许的输入类型以及具有可预测的返回类型。要深入了解 Featuretools 中的原语,请参阅特征原语指南。在这里,我们将看看 Woodwork 类型如何组合成一个 ColumnSchema 对象来描述原语的输入和返回类型。

下面是从零售 EntitySet 中 products DataFrame 的 'product_id' 列中获取的 Woodwork ColumnSchema

[6]:
products_df = es["products"]
product_ids_series = products_df.ww["product_id"]
column_schema = product_ids_series.ww.schema
column_schema
[6]:
<ColumnSchema (Logical Type = Categorical) (Semantic Tags = ['index'])>

这种逻辑类型和语义标签类型信息的组合是一个 ColumnSchema。在上面的例子中,ColumnSchema 描述了单个数据列的 类型定义

请注意,ColumnSchema 中没有物理类型。这是因为 ColumnSchema 是 Woodwork 类型的集合,它不与任何数据绑定,因此没有物理表示。由于 ColumnSchema 对象不与任何数据绑定,它也可以用来描述一个 类型空间,其他列可能会或可能不会落入其中。

ColumnSchema 类的这种灵活性允许 ColumnSchema 对象既可以作为 EntitySet 中每列的类型定义,也可以作为 Featuretools 中每个原语的输入和返回类型空间。

让我们看看不同 DataFrame 中的另一列,看看这是如何工作的

[7]:
order_products_df = es["order_products"]
order_products_df.head()
[7]:
order_product_id order_id product_id quantity order_date unit_price total _ft_last_time
0 0 536365 85123A 6 2010-12-01 08:26:00 4.2075 25.245 2010-12-01 08:26:00
1 1 536365 71053 6 2010-12-01 08:26:00 5.5935 33.561 2010-12-01 08:26:00
2 2 536365 84406B 8 2010-12-01 08:26:00 4.5375 36.300 2010-12-01 08:26:00
3 3 536365 84029G 6 2010-12-01 08:26:00 5.5935 33.561 2010-12-01 08:26:00
4 4 536365 84029E 6 2010-12-01 08:26:00 5.5935 33.561 2010-12-01 08:26:00
[8]:
quantity_series = order_products_df.ww["quantity"]
column_schema = quantity_series.ww.schema
column_schema
[8]:
<ColumnSchema (Logical Type = Integer) (Semantic Tags = ['numeric'])>

上面的 ColumnSchema 是从零售 EntitySet 中 order_products DataFrame 的 'quantity' 列中提取的。这是一个 类型定义

如果我们查看 order_products DataFrame 的 Woodwork 类型信息,可以看到有几列将具有类似的 ColumnSchema 类型定义。如果我们要描述这些列的子集,可以定义几个 ColumnSchema 类型空间

[9]:
es["order_products"].ww
[9]:
物理类型 逻辑类型 语义标签
order_product_id int64 整数 ['索引']
order_id 类别 分类 ['分类', '外键']
product_id 类别 分类 ['分类', '外键']
quantity int64 整数 ['数值型']
order_date datetime64[ns] 日期时间 ['时间索引']
unit_price float64 双精度浮点数 ['数值型']
total float64 双精度浮点数 ['数值型']
_ft_last_time datetime64[ns] 日期时间 ['最后一个时间索引']

下面是几个 ColumnSchema,它们都将包含我们的 quantity 列,但每个都描述了一个不同的类型空间。这些 ColumnSchema 随着列表向下变得越来越严格。

整个 DataFrame#

未施加任何限制;任何列都符合此定义。这将包括整个 DataFrame。

[10]:
from woodwork.column_schema import ColumnSchema

ColumnSchema()
[10]:
<ColumnSchema>

以此 ColumnSchema 作为输入类型的原语示例是 IsNull 转换原语。

按语义标签#

仅带有 numeric 标签的列适用。这也可以包括 Double、Integer 和 Age 逻辑类型的列。它不包括 index 列,尽管它包含整数,但其标准标签已被 'index' 标签替换。

[11]:
ColumnSchema(semantic_tags={"numeric"})
[11]:
<ColumnSchema (Semantic Tags = ['numeric'])>
[12]:
df = es["order_products"].ww.select(include="numeric")
df.ww
[12]:
物理类型 逻辑类型 语义标签
quantity int64 整数 ['数值型']
unit_price float64 双精度浮点数 ['数值型']
total float64 双精度浮点数 ['数值型']

以此 ColumnSchema 作为输入类型的原语示例是 Mean 聚合原语。

按逻辑类型#

此定义仅包含逻辑类型为 Integer 的列。不要求带有 numeric 标签,因此索引列(其标准标签已被移除)仍然适用。

[13]:
from woodwork.logical_types import Integer

ColumnSchema(logical_type=Integer)
[13]:
<ColumnSchema (Logical Type = Integer)>
[14]:
df = es["order_products"].ww.select(include="Integer")
df.ww
[14]:
物理类型 逻辑类型 语义标签
order_product_id int64 整数 ['索引']
quantity int64 整数 ['数值型']

按逻辑类型和语义标签#

列必须具有 Integer 逻辑类型并带有 numeric 语义标签,不包括索引列。

[15]:
ColumnSchema(logical_type=Integer, semantic_tags={"numeric"})
[15]:
<ColumnSchema (Logical Type = Integer) (Semantic Tags = ['numeric'])>
[16]:
df = es["order_products"].ww.select(include="numeric")
df = df.ww.select(include="Integer")
df.ww
[16]:
物理类型 逻辑类型 语义标签
quantity int64 整数 ['数值型']

通过这种方式,ColumnSchema 可以定义 Woodwork DataFrame 中列可以落入的类型空间。Featuretools 在 DFS 期间构建特征时,就是通过这种方式确定 DataFrame 中的哪些列对于原语是有效的。

每个原语都有由 Woodwork ColumnSchema 描述的 input_typesreturn_type。EntitySet 中的每个 DataFrame 都已在其中初始化 Woodwork。这意味着当 EntitySet 传递给 DFS 时,Featuretools 可以选择 DataFrame 中对于原语的 input_types 有效的相关列。然后我们得到一个具有 column_schema 属性的特征,该属性以一种允许 DFS 将特征堆叠在一起的方式指示该特征的类型定义。

通过这种方式,Featuretools 能够利用 Woodwork 类型信息的基本单元,即 ColumnSchema,并与 Woodwork DataFrame 的 EntitySet 协同使用,从而通过深度特征合成构建特征。