李里:现在机器学习模型训练调参越来越自动化,但数据的特征提取还需要分析人员手动完成并且和该数据领域的专业知识有很大关系,但数据的特征选取又是关系到最后模型质量最重要的一个步骤,所以很多能实现自动化特征工程的工具就应运而生了特征工程的含义是从现有数据中解构出隐含的特征,
高维:有些抽象,能举个例子描述一下么?
李里:比如每个人的身高和体重是两个特征,但通过身高体重算出的体脂率就是一个新的特征,这个构造新特征的过程叫特征工程。特征工程的好处是可以把复杂并且用处不大的数据抽象出来,正如用体脂率就可以代替身高体重两个属性一样。但做特征工程需要99%的领域知识和1%的灵感,所以采用自动化方式来处理应运而生,这里以featuretools这个python开源库为例。先来了解一下featuretools里面三个重要的组件。
- 实体(Entity):类似于Pandas的dataframe,Entityset是多个Entity的集合。
- 深度特征综合(Deep Feature Synthesis ,DFS):从单个或多个dataframe中构造新的特征。
- 特征基元(Feature primitives):构造出来的新特征,如体脂率。
李里:我用featuretools自带的测试数据集mock_customer给你们演示一下如何应用。在这个数据集里共有三个表,或者称为四个entity
Customers | 拥有session的唯一客户表 |
Sessions | 拥有唯一会话的关联属性表 |
Transactions | 会话的事件列表 |
Products | 产品列表 |
表4.4.1mock_customer的entity
Customs entity |
Sessions entity |
Transactions entity |
Products entity |
表4.4.2 mock_customer数据概览
李里:先创建包含dataframe的EntitySet,程序的含义参考代码中的注释,图4.4.1是创建的包含两个entity但没有产生关系的EntitySet。
生成EntitySet的代码:
Import featuretools as ft data = ft.demo.load_mock_customer() #获取entity customers_df = data['customers'] sessions_df = data['sessions'] transactions_df = data['transactions'] products_df = data['products'] #1:用一个唯一的id初始化Entity es = ft.EntitySet(id="transactions") #2:增加entity,此步骤会将dataframe的每一列数据都导入 #index:能唯一标识每一行数据的列名 #time_index:时间索引 #variable_types参数指示“product_id”应该被解释为分类变量,即使它只是基础数据中的整数类型。 es = es.entity_from_dataframe(entity_id="transactions",dataframe=transactions_df,index="transaction_id",time_index="transaction_time",variable_types={"product_id": ft.variable_types.Categorical}) #往EntitySet中再增加一个entity es = es.entity_from_dataframe(entity_id="products", dataframe=products_df,index="product_id") |
图4.4.1 不包含关系的EntitySet
数据表之间的关系在featuretools里面用父与子的关系来链接,父与子是一对多的,每个父亲都可以有多个孩子,把父表中的每一行代表一位父亲,子表中的多行代表多个孩子,多个孩子可以映射到父表中的同一位父亲即同一行中,以此产生关联。
增加Entity关系的代码,增加后的EntitySet内容为图4.4.2:
new_relationship = ft.Relationship(es["products"]["product_id"], es["transactions"]["product_id"]) es = es.add_relationship(new_relationship) |
图4.4.3 包含关系的EntitySet
根据EntitySet计算特征矩阵和特征。
#entityset:如果没有定义entity和relationsship,则需要改参数 #target_entity:在哪个entity上面做输出 feature_matrix, feature_defs = ft.dfs(entityset=es, target_entity="products") |
高维:我创建了这样的特征矩阵有什么用啊?能直接用于机器学习么?
李里:这样的特征矩阵你可以理解为一个新的Entity,并可以直接用于机器学习,比如我想将customers的特征进行深度融合后创建一个新的特征数据表,可以看到图4.4.4中新生成的Customers里面按照Sessions进行计数,新增的字段有按年归集的join_date和date_of_birth。
代码描述了将entityset进行深度特征融合,并生成新的特征entity。
#agg_primitives:应用聚合的方式,默认Default: [“sum”, “std”, “max”, “skew”, “min”, “mean”, “count”, “percent_true”, “n_unique”, “mode”]
#trans_primitives:要应用的聚合的元素, 默认[“day”, “year”, “month”, “weekday”, “haversine”, “num_words”, “num_characters”]
feature_matrix, feature_defs = ft.dfs(entityset=es,target_entity="customers", agg_primitives=["count"],trans_primitives=["year"],max_depth=1)
|
图4.4.4深度特征融合后的新Customers Entity
高维:能把agg_primitives和trans_primitives这两个参数再解释一下么?有什么区别?
李里:agg_primitives参数的含义聚合,作用于多个表,并使用一对多的关系按父表进行分组,然后计算统计数据,trans_primitives则是转换,作用于单个表,对于pandas而言则是一个dataframe,通过一个或多个现有属性创建新属性,可以通过ft.list_primitives()去获取所有聚合和变换的操作指令,主要区别在于聚合应用于多表,而转换应用于单个表。
高维:我看到trans_primitives都是选用时间函数用来做操作的,是不是时间对于模型很重要啊?
李里:数据集中的时间日期相关的字段对于未来行为的预测至关重要,如下个月的店面营收,下次物流快递预计到达时间等,这些预测都依赖与之前一段时间的数据分析。
高维:那有没有实际的项目给我们讲解一下么?
李里:不用着急,培训结束后正好有类似的项目供你们实践。