<jupyter_start><jupyter_text>===============================Using Compose with Featuretools===============================In this guide, we will generate labels and features on a mock dataset of transactions using Compose and Featuretools. Then create a machine learning model for predicting one hour in advance whether customers will spend over $1200 within the next hour of transactions.<jupyter_code>%matplotlib inline
import composeml as cp
import featuretools as ft
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report<jupyter_output><empty_output><jupyter_text>Load Data=========To get an idea on how the transactions looks, we preview the data frame.<jupyter_code>transactions = ft.demo.load_mock_customer(
    return_single_table=True,
    random_seed=0,
)

transactions[transactions.columns[:7]].head()<jupyter_output><empty_output><jupyter_text>Generate Labels===============Now with the transactions loaded, we are ready to generate labels for our prediction problem.Create Labeling Function------------------------First, we define the function that will return the total purchase amount given a hour of transactions.<jupyter_code>def total_spent(df):
    total = df["amount"].sum()
    return total<jupyter_output><empty_output><jupyter_text>.. currentmodule:: composemlConstruct Label Maker---------------------With our labeling function, we create the :class:`LabelMaker` for the transactions. The :code:`target_entity` is set to :code:`customer_id` so that the labels are generated for each customer. The :code:`window_size` is set to one hour to process one hour of transactions for a given customer.<jupyter_code>label_maker = cp.LabelMaker(
    target_entity='customer_id',
    time_index='transaction_time',
    labeling_function=total_spent,
    window_size='1h',
)<jupyter_output><empty_output><jupyter_text>Create Labels-------------Next, we automatically search and extract the labels by using :meth:`LabelMaker.search`... seealso::        For more details on how the label maker works, see :doc:`/main_concepts`.<jupyter_code>labels = label_maker.search(
    transactions.sort_values('transaction_time'),
    num_examples_per_instance=-1,
    gap=1,
)

labels.head()<jupyter_output>Elapsed: 00:01 | Remaining: 00:00 | Progress: 100%|██████████| customer_id: 5/5<jupyter_text>Transform Labels----------------With the generated :class:`LabelTimes`, we will apply specific transforms for our prediction problem.Apply Threshold on Labels~~~~~~~~~~~~~~~~~~~~~~~~~We apply :meth:`LabelTimes.threshold` to make the labels binary for total amounts exceeding $1200.<jupyter_code>labels = labels.threshold(1200)

labels.head()<jupyter_output><empty_output><jupyter_text>Lead Label Times~~~~~~~~~~~~~~~~We also use :meth:`LabelTimes.apply_lead` to shift the label times 1 hour earlier for predicting in advance.<jupyter_code>labels = labels.apply_lead('1h')

labels.head()<jupyter_output><empty_output><jupyter_text>Describe Labels---------------After transforming the labels, we could use :meth:`LabelTimes.describe` to print out the distribution with the settings and transforms that were used to make the labels. This is useful as a reference for understanding how the labels were generated from raw data. Also, the label distribution is helpful for determining if we have imbalanced labels.<jupyter_code>labels.describe()<jupyter_output>Label Distribution
------------------
True      252
False     248
Total:    500


Settings
--------
num_examples_per_instance        -1
minimum_data                   None
window_size                  <Hour>
gap                               1


Transforms
----------
1. threshold
  - value:    1200

2. apply_lead
  - value:    1h<jupyter_text>.. currentmodule:: featuretoolsGenerate Features=================Now with the generated labels, we are ready to generate features for our prediction problem.Create Entity Set-----------------Let's construct an :class:`EntitySet` and load the transactions as an entity by using :meth:`EntitySet.entity_from_dataframe`. Then extract additional entities by using :meth:`EntitySet.normalize_entity`... seealso::    For more details on working with entity sets, see :doc:`loading_data/using_entitysets` .<jupyter_code>es = ft.EntitySet('transactions')

es.entity_from_dataframe(
    'transactions',
    transactions,
    index='transaction_id',
    time_index='transaction_time',
)

es.normalize_entity(
    base_entity_id='transactions',
    new_entity_id='sessions',
    index='session_id',
    make_time_index='session_start',
    additional_variables=[
        'device',
        'customer_id',
        'zip_code',
        'session_start',
        'join_date',
        'date_of_birth',
    ],
)

es.normalize_entity(
    base_entity_id='sessions',
    new_entity_id='customers',
    index='customer_id',
    make_time_index='join_date',
    additional_variables=[
        'zip_code',
        'join_date',
        'date_of_birth',
    ],
)

es.normalize_entity(
    base_entity_id='transactions',
    new_entity_id='products',
    index='product_id',
    additional_variables=['brand'],
    make_time_index=False,
)

es.add_last_time_indexes()<jupyter_output><empty_output><jupyter_text>Describe Entity Set-------------------To get information on how the entity set is structured, we could print the entity set and use :meth:`EntitySet.plot` to create a diagram.<jupyter_code>print(es, end='\n\n')

es.plot()<jupyter_output>Entityset: transactions
  Entities:
    transactions [Rows: 500, Columns: 5]
    sessions [Rows: 35, Columns: 4]
    customers [Rows: 5, Columns: 4]
    products [Rows: 5, Columns: 2]
  Relationships:
    transactions.session_id -> sessions.session_id
    sessions.customer_id -> customers.customer_id
    transactions.product_id -> products.product_id<jupyter_text>Create Feature Matrix---------------------Next, we generate features that correspond to the labels created previously by using :func:`dfs`. The :code:`target_entity` is set to :code:`customers` so that features are only calculated for customers. The :code:`cutoff_time` is set to the labels so that features are calculated only using data up to and including the label cutoff times. Notice that the output of Compose integrates easily with Featuretools... seealso::        For more details on calculating features using cutoff times, see :doc:`automated_feature_engineering/handling_time`.<jupyter_code>feature_matrix, features_defs = ft.dfs(
    entityset=es,
    target_entity='customers',
    cutoff_time=labels,
    cutoff_time_in_index=True,
    verbose=True,
)<jupyter_output>Built 77 features
Elapsed: 02:32 | Progress: 100%|█████████████████████████████████████████████████████████████████████| Remaining: 00:00<jupyter_text>Describe Features-----------------To get an idea on how the generated features look, we preview the feature definitions.<jupyter_code>features_defs[:20]<jupyter_output><empty_output><jupyter_text>Machine Learning================Now with the generated labels and features, we are ready to create a machine learning model for our prediction problem. Preprocess Features-------------------In the feature matrix, let's extract the labels and fill any missing values with zeros. Then, one-hot encode all categorical features by using :func:`encode_features`.<jupyter_code>y = feature_matrix.pop(labels.name)
x = feature_matrix.fillna(0)
x, features_enc = ft.encode_features(x, features_defs)<jupyter_output><empty_output><jupyter_text>Split Labels and Features-------------------------After preprocessing, we split the features and corresponding labels each into training and testing sets.<jupyter_code>x_train, x_test, y_train, y_test = train_test_split(
    x,
    y,
    train_size=.8,
    test_size=.2,
    random_state=0,
)<jupyter_output><empty_output><jupyter_text>Train Model-----------Next, we train a random forest classifer on the training set.<jupyter_code>clf = RandomForestClassifier(n_estimators=10, random_state=0)

clf.fit(x_train, y_train)<jupyter_output><empty_output><jupyter_text>Test Model----------Lastly, we test the model performance by evaluating predictions on the testing set.<jupyter_code>y_hat = clf.predict(x_test)

print(classification_report(y_test, y_hat))<jupyter_output>precision    recall  f1-score   support

       False       0.80      0.86      0.83        50
        True       0.85      0.78      0.81        50

    accuracy                           0.82       100
   macro avg       0.82      0.82      0.82       100
weighted avg       0.82      0.82      0.82       100<jupyter_text>Feature Importances-------------------This plot is based on scores obtained by the model to illustrate which features are considered important for predictions.<jupyter_code>feature_importances = zip(x_train.columns, clf.feature_importances_)
feature_importances = pd.Series(dict(feature_importances))
feature_importances = feature_importances.rename_axis('Features')
feature_importances = feature_importances.sort_values()

top_features = feature_importances.tail(40)
plot = top_features.plot(kind='barh', figsize=(5, 12), color='#054571')
plot.set_title('Feature Importances')
plot.set_xlabel('Scores');<jupyter_output><empty_output>
StarcoderdataJupyterStructuredCleanDedup