如何避免Featuretools组合聚合特征时生成无意义变量?
我有一个包含发票(带唯一标识符)和客户(带唯一标识符)的数据集,每个客户可关联1张或多张发票。我按如下方式构建EntitySet:
es = ft.EntitySet(id="data") es = es.add_dataframe( dataframe=df, dataframe_name="data", index="rows", make_index=True, time_index="invoice_date", logical_types={ "customer_id": Categorical, "description": NaturalLanguage, } ) es.normalize_dataframe( base_dataframe_name="data", new_dataframe_name="invoices", index="invoice", copy_columns=["customer_id"], ) es.normalize_dataframe( base_dataframe_name="invoices", new_dataframe_name="customers", index="customer_id", )
其中customers是invoices的子实体,invoices是整个数据集的子实体。
我希望在整个dataframe层面组合price和quantity变量得到price*quantity,这一步正常,但聚合时出现了不符合人类逻辑的特征组合。我按如下方式设置dfs:
date_primitives = ["month", "weekday"] text_primitives = ["num_words"] trans_primitives = date_primitives + text_primitives + ["multiply_numeric"] agg_primitives = ["mean"] feature_matrix, feature_defs = ft.dfs( entityset=es, target_dataframe_name="customers", agg_primitives=agg_primitives, trans_primitives=trans_primitives, primitive_options={ ("multiply_numeric"): { 'include_columns': { 'data': ['price', 'quantity'] } } }, max_depth=3, )
生成的特征包含:
[<Feature: MEAN(data.price)>, <Feature: MEAN(data.quantity)>, <Feature: MONTH(first_invoices_time)>, <Feature: WEEKDAY(first_invoices_time)>, <Feature: MEAN(invoices.MEAN(data.price))>, <Feature: MEAN(invoices.MEAN(data.quantity))>, <Feature: MEAN(data.NUM_WORDS(description))>, <Feature: MEAN(data.price * quantity)>, <Feature: MEAN(data.price) * MEAN(data.quantity)>, <Feature: MEAN(invoices.MEAN(data.NUM_WORDS(description)))>, <Feature: MEAN(invoices.MEAN(data.price * quantity))>, <Feature: MEAN(invoices.MEAN(data.price) * MEAN(data.quantity))>, <Feature: MEAN(data.price * quantity) * MEAN(data.price)>, <Feature: MEAN(data.price * quantity) * MEAN(data.quantity)>, <Feature: MEAN(data.price * quantity) * MEAN(invoices.MEAN(data.price))>, <Feature: MEAN(data.price * quantity) * MEAN(invoices.MEAN(data.quantity))>, <Feature: MEAN(data.price) * MEAN(invoices.MEAN(data.price))>, <Feature: MEAN(data.price) * MEAN(invoices.MEAN(data.quantity))>, <Feature: MEAN(data.quantity) * MEAN(invoices.MEAN(data.price))>, <Feature: MEAN(data.quantity) * MEAN(invoices.MEAN(data.quantity))>, <Feature: MEAN(invoices.MEAN(data.price)) * MEAN(invoices.MEAN(data.quantity))>]
其中MEAN(data.price * quantity)、MEAN(invoices.MEAN(data.price * quantity))等特征符合逻辑,但MEAN(data.quantity) * MEAN(invoices.MEAN(data.price))、MEAN(invoices.MEAN(data.price)) * MEAN(invoices.MEAN(data.quantity))这类特征无意义。尝试减小max_depth会导致文本primitive无法执行,请问如何避免生成这类无意义特征?
可以通过以下几种方式精准控制特征生成,避免无意义组合:
1. 提前计算有意义的乘积字段
不要依赖multiply_numeric原语在特征生成阶段计算乘积,直接在原始数据中新增total_amount = price * quantity字段,再将其加入EntitySet。这样后续聚合只会针对这个预计算的有意义字段,不会衍生出其他无意义的乘积组合。
修改后的EntitySet构建代码示例:
# 提前计算乘积字段 df['total_amount'] = df['price'] * df['quantity'] es = ft.EntitySet(id="data") es = es.add_dataframe( dataframe=df, dataframe_name="data", index="rows", make_index=True, time_index="invoice_date", logical_types={ "customer_id": Categorical, "description": NaturalLanguage, "total_amount": Integer # 根据实际数据类型调整 } ) # 后续normalize步骤不变 es.normalize_dataframe( base_dataframe_name="data", new_dataframe_name="invoices", index="invoice", copy_columns=["customer_id"], ) es.normalize_dataframe( base_dataframe_name="invoices", new_dataframe_name="customers", index="customer_id", )
同时调整dfs参数,移除multiply_numeric原语:
date_primitives = ["month", "weekday"] text_primitives = ["num_words"] trans_primitives = date_primitives + text_primitives agg_primitives = ["mean"] feature_matrix, feature_defs = ft.dfs( entityset=es, target_dataframe_name="customers", agg_primitives=agg_primitives, trans_primitives=trans_primitives, max_depth=3, )
2. 限制乘积原语的作用范围
如果必须保留multiply_numeric原语,可通过primitive_options进一步限制其仅作用于最底层的data实体指定字段,禁止在聚合后的invoices或customers层级特征上应用乘积操作。
修改primitive_options:
primitive_options={ "multiply_numeric": { 'include_columns': { 'data': ['price', 'quantity'] }, 'exclude_entities': ['invoices', 'customers'] } }
这样乘积操作只会在原始数据层面执行,不会在聚合后的特征上生成无意义组合。
3. 过滤生成后的无效特征
生成特征矩阵后,通过正则表达式或特征名称规则手动过滤无意义特征。比如匹配包含MEAN\(.*\) \* MEAN\(.*\)模式的特征,直接从矩阵中删除:
import re # 定义无意义特征的匹配规则 pattern = re.compile(r'MEAN\(.*\) \* MEAN\(.*\)') # 筛选符合逻辑的特征 valid_features = [feat for feat in feature_matrix.columns if not pattern.match(feat)] # 保留有效特征 feature_matrix = feature_matrix[valid_features]
内容的提问来源于stack exchange,提问作者Sole Galli

