File size: 3,083 Bytes
d9b2b72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
"""Feature engineering module for E-Commerce Churn dataset."""

import pandas as pd
import numpy as np


def create_features(df: pd.DataFrame) -> pd.DataFrame:
    """Create new features from the cleaned dataset.

    New features:
        1. tenure_bucket — categorical binning of Tenure
        2. engagement_score — HourSpendOnApp * OrderCount
        3. cashback_per_order — CashbackAmount / OrderCount
        4. is_recent_buyer — 1 if DaySinceLastOrder <= 3
        5. has_multi_device — 1 if NumberOfDeviceRegistered >= 4
        6. is_high_spender — 1 if OrderAmountHikeFromlastYear > 20
    """
    df = df.copy()

    # 1. Tenure bucket
    bins = [0, 6, 12, 24, np.inf]
    labels = ["new", "settling", "established", "loyal"]
    df["tenure_bucket"] = pd.cut(df["Tenure"], bins=bins, labels=labels, include_lowest=True)

    # 2. Engagement score
    df["engagement_score"] = df["HourSpendOnApp"] * df["OrderCount"]

    # 3. Cashback per order (handle division by zero)
    df["cashback_per_order"] = np.where(
        df["OrderCount"] > 0,
        df["CashbackAmount"] / df["OrderCount"],
        0,
    )

    # 4. Is recent buyer
    df["is_recent_buyer"] = (df["DaySinceLastOrder"] <= 3).astype(int)

    # 5. Has multi device
    df["has_multi_device"] = (df["NumberOfDeviceRegistered"] >= 4).astype(int)

    # 6. Is high spender
    df["is_high_spender"] = (df["OrderAmountHikeFromlastYear"] > 20).astype(int)

    return df


def encode_features(df: pd.DataFrame) -> pd.DataFrame:
    """Encode categorical variables.

    Label encoding: Gender, MaritalStatus, tenure_bucket
    One-hot encoding: PreferredLoginDevice, PreferredPaymentMode, PreferedOrderCat
    """
    df = df.copy()

    # Label encoding
    label_maps = {
        "Gender": {"Male": 0, "Female": 1},
        "MaritalStatus": {"Single": 0, "Married": 1, "Divorced": 2},
        "tenure_bucket": {"new": 0, "settling": 1, "established": 2, "loyal": 3},
    }
    for col, mapping in label_maps.items():
        df[col] = df[col].map(mapping)

    # One-hot encoding
    ohe_cols = ["PreferredLoginDevice", "PreferredPaymentMode", "PreferedOrderCat"]
    df = pd.get_dummies(df, columns=ohe_cols, drop_first=True, dtype=int)

    return df


def engineer_features(df: pd.DataFrame) -> pd.DataFrame:
    """Run the full feature engineering pipeline.

    Steps:
        1. Create 6 new features
        2. Encode categorical variables

    Returns:
        Feature-engineered DataFrame ready for modeling.
    """
    df = create_features(df)
    df = encode_features(df)
    return df


if __name__ == "__main__":
    from data_cleaning import load_raw_data, clean

    raw = load_raw_data()
    cleaned = clean(raw)
    print(f"Cleaned shape: {cleaned.shape}")

    engineered = engineer_features(cleaned)
    print(f"Engineered shape: {engineered.shape}")
    print(f"\nColumns:\n{engineered.columns.tolist()}")
    print(f"\nDtypes:\n{engineered.dtypes}")

    engineered.to_csv("data/processed/engineered.csv", index=False)
    print("\nSaved to data/processed/engineered.csv")