(Featuretools) Как рассчитываются агрегатные примитивы объектов? - PullRequest
0 голосов
/ 16 апреля 2020

Понятия не имею, как рассчитывается примитив агрегированной функции, даже если я тестировал с очень простыми данными. Я также просмотрел код featuretools, но не смог выяснить, где произошла операция агрегирования.

Вот примеры кодов:

from sklearn.utils import shuffle

periods = 5
end_date = "2012-04-13"
train_df = pd.DataFrame(
    {
        "store_id": [0]*periods + [1]*periods + [2]*periods + [3]*periods,
        "region": ["A"]*periods+["B"]*periods*3,
        "amount": shuffle(range(periods*4)),
        "transacted_date": [
            "2012-02-05", "2012-02-10", "2012-03-01", "2012-03-18", "2012-04-23",
        ]*4
    }
)
train_df["transacted_date"] = pd.to_datetime(train_df["transacted_date"])
train_df.sort_values(["store_id", "transacted_date"], inplace=True)


def make_retail_cutoffs_amounts(data_df, amount_start_date, amount_end_date):
    store_pool = data_df[data_df['transacted_date'] < amount_start_date]['store_id'].unique()
    tmp = pd.DataFrame({'store_id': store_pool})

    amounts = data_df[
        (data_df['store_id'].isin(store_pool)) &
        (amount_start_date <= data_df['transacted_date']) &
        (data_df['transacted_date'] < amount_end_date)
    ].groupby('store_id')['amount'].sum().reset_index()

    amounts = amounts.merge(tmp, on = 'store_id', how = 'right')
    amounts['amount'] = amounts['amount'].fillna(0)  # 0으로 채워지는 애는 3개월 다 수익이 없는 녀석!

    amounts['cutoff_time'] = pd.to_datetime(amount_start_date)

    amounts = amounts[['store_id', 'cutoff_time', 'amount']]
    amounts = amounts.rename(columns={"amount":"1month_amount_from_cutoff_time"})
    return amounts


amount_start_date = "2012-02-01"
amount_end_date = end_date
agg_month = 1

data_df_list = []
date_list = pd.date_range(amount_start_date, datetime.strptime(end_date, "%Y-%m-%d") + pd.DateOffset(months=1), freq="MS")

for amount_start_date, amount_end_date in zip(date_list[:-agg_month], date_list[agg_month:]):
    data_df_list.append(
        make_retail_cutoffs_amounts(
            train_df, amount_start_date, amount_end_date
        )
    )
data_df = pd.concat(data_df_list)
data_df.sort_values(["store_id", "cutoff_time", ], inplace=True)

import featuretools as ft

es = ft.EntitySet(id="sale_set")
es = es.entity_from_dataframe(
    "sales",
    dataframe=train_df,
    index="sale_id", make_index=True,
    time_index='transacted_date',
)
es.normalize_entity(
    new_entity_id="stores",
    base_entity_id="sales",
    index="store_id",
    additional_variables=['region']
)

# When using a training window, 
# it is necessary to calculate the last time indexes for the entity set. Adding
es.add_last_time_indexes()

features  = ft.dfs(
    entityset=es,
    target_entity='stores',
    cutoff_time=data_df,
    verbose=1,
    cutoff_time_in_index=True,
    n_jobs=1,
    max_depth=2,

    agg_primitives=["sum",],
    trans_primitives=["cum_max"], 
    training_window="1 month",
)

dfs работает нормально, но не может интерпретировать Результаты объектов.

А вот примерные данные объектов:

enter image description here

Как вы можете видеть здесь, первая строка SUM(sales.amount) и SUM(sales.CUM_MAX(amount)) - 19, 37 каждый. Я хочу знать, как они рассчитываются.

Вот как я интерпретировал результат:

enter image description here

  1. Как вы можете видеть здесь, store_0 имеет 2 записи о продажах за февраль 2012 года. Таким образом, SUM(sales.amount) store_id = 0 на время закрытия 2012-03-01 должно быть 0 + 8 = 8, а не 19.

  2. Аналогично, SUM(sales.CUM_MAX(amount)) store_id = 0 на время завершения 2012-03-01 также должно быть SUM (sales.CUM_MAX (сумма)) = SUM ([0, 8]) = 8, а не 37.

Я что-то пропустил? Как они рассчитываются?

1 Ответ

0 голосов
/ 17 апреля 2020

Эти понятия помогут вам понять, как рассчитываются объекты:

  1. Для расчета объектов используются данные с индексом времени вплоть до времени отключения.
  2. In Чтобы рассчитать CumMax для каждого магазина, его нужно разместить в groupby_trans_primitives вместо trans_primitives.

Я приведу go через пример. Это данные в формате CSV.

store_id,region,amount,transacted_date
0,A,16,2012-02-05
0,A,15,2012-02-10
0,A,13,2012-03-01
0,A,2,2012-03-18
0,A,3,2012-04-23
1,B,9,2012-02-05
1,B,8,2012-02-10
1,B,14,2012-03-01
1,B,1,2012-03-18
1,B,5,2012-04-23
2,B,6,2012-02-05
2,B,12,2012-02-10
2,B,4,2012-03-01
2,B,7,2012-03-18
2,B,11,2012-04-23
3,B,18,2012-02-05
3,B,19,2012-02-10
3,B,0,2012-03-01
3,B,10,2012-03-18
3,B,17,2012-04-23

Сначала я загружаю набор данных.

import pandas as pd

train_df = pd.read_csv('data.csv', parse_dates=['transacted_date'])
train_df.sort_values(["store_id", "transacted_date"], inplace=True)
 store_id region  amount transacted_date
        0      A      16      2012-02-05
        0      A      15      2012-02-10
        0      A      13      2012-03-01
        0      A       2      2012-03-18
        0      A       3      2012-04-23
        1      B       9      2012-02-05
        1      B       8      2012-02-10
        1      B      14      2012-03-01
        1      B       1      2012-03-18
        1      B       5      2012-04-23
        2      B       6      2012-02-05
        2      B      12      2012-02-10
        2      B       4      2012-03-01
        2      B       7      2012-03-18
        2      B      11      2012-04-23
        3      B      18      2012-02-05
        3      B      19      2012-02-10
        3      B       0      2012-03-01
        3      B      10      2012-03-18
        3      B      17      2012-04-23

Затем я автоматически использую Compose сгенерировать то же время отсечения.

import composeml as cp

def total_amount(df):
    return df.amount.sum()


lm = cp.LabelMaker(
    target_entity='store_id',
    time_index='transacted_date',
    labeling_function=total_amount,
    window_size='1MS',
)

lt = lm.search(
    train_df,
    num_examples_per_instance=-1,
    minimum_data='2012-03-01',
)
 store_id cutoff_time  total_amount
        0  2012-03-01            15
        0  2012-04-01             3
        1  2012-03-01            15
        1  2012-04-01             5
        2  2012-03-01            11
        2  2012-04-01            11
        3  2012-03-01            10
        3  2012-04-01            17

Теперь я структурирую набор сущностей.

import featuretools as ft

es = ft.EntitySet(id="sale_set")

es = es.entity_from_dataframe(
    "sales",
    dataframe=train_df,
    index="sale_id",
    make_index=True,
    time_index='transacted_date',
)

es.normalize_entity(
    new_entity_id="stores",
    base_entity_id="sales",
    index="store_id",
    additional_variables=['region'],
)

es.add_last_time_indexes()

Это график, чтобы получить представление о том, как структурирован набор сущностей. .

es.plot()

enter image description here

Наконец, я запускаю DFS для вычисления функций.

fm, fd = ft.dfs(
    entityset=es,
    target_entity='stores',
    cutoff_time=lt,
    cutoff_time_in_index=True,
    agg_primitives=["sum"],
    groupby_trans_primitives=["cum_max"],
    training_window="1 month",
    max_depth=2,
    verbose=1,
)

fm.filter(regex='SUM')
                     SUM(sales.amount)  SUM(sales.CUM_MAX(amount) by store_id)
store_id time
0        2012-03-01                 44                                    48.0
         2012-04-01                 15                                    26.0
1        2012-03-01                 31                                    32.0
         2012-04-01                 15                                    28.0
2        2012-03-01                 22                                    30.0
         2012-04-01                 11                                    11.0
3        2012-03-01                 37                                    56.0
         2012-04-01                 10                                    10.0

Мы можем видеть что SUM(sales.amount) для магазина 0 во время отключения 2012-03-01 включает в себя данные вплоть до 2012-03-01 для расчета функции.

>>> 16 + 15 + 13
44

Это также относится к SUM(sales.CUM_MAX(amount) by store_id) при применении в качестве groupby_trans_primitives в DFS.

>>> sum((16, 16, 16))
48

Дайте мне знать, если это поможет.

...