featuretools 历史标签计数

featuretools historical label counts

背景

对于 CRM 项目,我有机会的快照。我已经能够使用 featuretools 构建许多功能,但我真正想要的是拥有历史获胜次数和比率。换句话说,我想知道:

For a given opportunity, how many deals have been won up until the opportunity was last modified?

示例数据

import pandas as pd
import featuretools as ft

df = pd.DataFrame(
    {'OpportunityId': [111, 111, 222, 222, 222, 333, 333, 333],
     'UpdateId': [1,3,2,5,7,4,6,8],
     'Label': ['Open', 'Win', 'Open', 'Open', 'Win', 'Open', 'Open', 'Open'],
     'CreatedOn': pd.to_datetime(['9/27/18','9/27/18','9/28/18','9/28/18','9/28/18','10/2/18','10/2/18','10/2/18']),
     'ModifiedOn': pd.to_datetime(['9/27/18','10/1/18','9/28/18','10/3/18','10/7/18','10/2/18','10/6/18','10/10/18']),
     'EstRevenue': [2000, 2000, 80000, 84000, 78000, 100000, 95000, 110000]})
df
| OpportunityId | UpdateId | Label | CreatedOn  | ModifiedOn | EstRevenue |
|---------------|----------|-------|------------|------------|------------|
| 111           | 1        | Open  | 2018-09-27 | 2018-09-27 | 2000       |
| 111           | 3        | Win   | 2018-09-27 | 2018-10-01 | 2000       |
| 222           | 2        | Open  | 2018-09-28 | 2018-09-28 | 80000      |
| 222           | 5        | Open  | 2018-09-28 | 2018-10-03 | 84000      |
| 222           | 7        | Win   | 2018-09-28 | 2018-10-07 | 78000      |
| 333           | 4        | Open  | 2018-10-02 | 2018-10-02 | 100000     |
| 333           | 6        | Open  | 2018-10-02 | 2018-10-06 | 95000      |
| 333           | 8        | Open  | 2018-10-02 | 2018-10-10 | 110000     |

期望的输出

| OPPORTUNITIES | Label | CreatedOn | Max( ModifiedOn ) | AVG( EstRevenue ) | Wins |
|---------------|-------|-----------|-------------------|------------------:|------|
| 111           | Win   | 9/27/18   | 10/1/18           |              2000 | 0    |
| 222           | Win   | 9/28/18   | 10/7/18           |             80667 | 1    |
| 333           | Open  | 10/2/18   | 10/10/18          |            101667 | 2    |

到目前为止的尝试

让我费尽心思的是...

  1. 依赖于多个机会的功能...我需要一个单独的实体吗?
  2. 我如何聚合 Label 来提供以下两者:
    1. 当前值Label
    2. Label列为0时的计数

我的挑战是 Label 专栏...虽然通常我会制作 CurrentLabel 专栏,但我很确定 ft 可以处理这个...

es = (ft.EntitySet(id='CRM')
      .entity_from_dataframe(
          entity_id='updates',
          dataframe=df,
          index='UpdateId',
          time_index='ModifiedOn')
      .normalize_entity(
          base_entity_id='updates',
          new_entity_id='opportunities',
          index='OpportunityId',
          make_time_index='CreatedOn',
          copy_variables=['Label'],
          additional_variables=['CreatedOn']
      )
)
es['updates']['Label'].interesting_values  = ['Win']
Entityset: CRM
  Entities:
    updates [Rows: 8, Columns: 5]
    opportunities [Rows: 3, Columns: 3]
  Relationships:
    updates.OpportunityId -> opportunities.OpportunityId
feature_matrix, feature_defs = ft.dfs(
    entityset=es,
    target_entity="opportunities",
    agg_primitives=[
        "mean","count","num_unique","time_since_first"],
    trans_primitives=[
        'time_since_previous'],
    where_primitives=[
        "sum","count"],
    max_depth=2,
    verbose=1
)

有几种不同的方法可以解决这个问题:

  1. 创建一个新的数据框列并使用 last 聚合原语

对于这种方法,在创建实体集之前,首先在数据框中创建一个新的 Wins 列,用于跟踪一段时间内的累计获胜总数。您可能需要按 ModifiedOn 列对数据框进行排序,以确保累计和值正确。此外,我在这里使用 .shift() 将列值移动一个位置,以仅计算 更新之前发生的胜利:

df = df.sort_values('ModifiedOn')
df['Wins'] = df['Label'].shift().eq('Win').cumsum()

当您 运行 深度特征合成时,将 last 基元添加到您的 agg_primitives 列表中:

feature_matrix, feature_defs = ft.dfs(
    entityset=es,
    target_entity="opportunities",
    agg_primitives=["mean", "count", "num_unique", "time_since_first", "last"],
    trans_primitives=["time_since_previous"],
    where_primitives=["sum", "count"],
    max_depth=2,
    verbose=1
)

现在,当您检查特征矩阵时,您将看到一个标记为 LAST(updates.Label) 的列,该列显示机会上次更新时 Label 的值。您还将有一个标记为 LAST(updates.Wins) 的列,显示上次更新机会时的总获胜次数。

  1. 使用带有自定义基元的种子特征 这种方法在概念上与第一种方法相似,但使用种子特征和自定义原语来获得所需的输出。

在 运行 深度特征合成之前,创建一个新的布尔种子特征,定义 Label 是否等于 Win:

label_is_win = ft.Feature(es["updates"]["Label"]) == "Win"

接下来,定义一个自定义转换基元,它将使用此种子功能来 return 获胜的累积总和:

class ShiftedCumSumBoolean(ft.primitives.TransformPrimitive):
    name = "shifted_cum_sum_boolean"
    input_types = [ft.variable_types.Boolean]
    return_type = ft.variable_types.Numeric
    uses_full_entity = True

    def get_function(self):
        def shifted_cum_sum(values):
            return values.shift(fill_value=(False)).cumsum()

        return shifted_cum_sum

当你运行深度特征合成时,将新的ShiftedCumSumBoolean基元添加到trans_primitives的列表中。此外,将 last 原语添加到 agg_primitives 的列表中,以在机会更新时提供最后一个标签值。最后,将 label_is_win 种子特征添加到 ft.dfs 调用中的种子特征列表:

feature_matrix, feature_defs = ft.dfs(
    entityset=es,
    target_entity="opportunities",
    agg_primitives=["mean","count","num_unique","time_since_first", "last"],
    trans_primitives=["time_since_previous", ShiftedCumSumBoolean],
    where_primitives=["sum", "count"],
    seed_features=[label_is_win],
    max_depth=2,
    verbose=1,
)

使用此解决方案,您的特征矩阵将有一个标记为 LAST(updates.Label) 的列,显示上次更新商机时 Label 的值。您还将有一个标记为 LAST(updates.SHIFTED_CUM_SUM_BOOLEAN(Label = Win)) 的列,显示上次更新机会时的总获胜次数。