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_types
和 return_type
。EntitySet 中的每个 DataFrame 都已在其中初始化 Woodwork。这意味着当 EntitySet 传递给 DFS 时,Featuretools 可以选择 DataFrame 中对于原语的 input_types
有效的相关列。然后我们得到一个具有 column_schema
属性的特征,该属性以一种允许 DFS 将特征堆叠在一起的方式指示该特征的类型定义。
通过这种方式,Featuretools 能够利用 Woodwork 类型信息的基本单元,即 ColumnSchema
,并与 Woodwork DataFrame 的 EntitySet 协同使用,从而通过深度特征合成构建特征。