is_click_predictor / data_loader.py
KaiquanMah's picture
Yair fixed categorical, ID, temporal cols and pre-processing [no more errors for XGBoost]
6454725 verified
import pandas as pd
import numpy as np
import time
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, StandardScaler
from imblearn.over_sampling import SMOTE
# ===========================
# CONFIGURATION
# ===========================
TRAIN_PATH = "data/train_dataset_full - train_dataset_full.csv"
# TRAIN_PATH = "data/train_dataset_full - train_dataset_partial_for_testing.csv"
TEST_PATH = "data/X_test_1st.csv" # Replace with actual test dataset path
CATEGORICAL_COLUMNS = ["gender", "product",]
IDS_COLUMNS = [ "user_id", "session_id", "campaign_id", "webpage_id"]
TARGET_COLUMN = "is_click"
FEATURE_COLUMNS = [
"age_level", "gender", "product",
"product_category_1", "product_category_2", "user_group_id",
"user_depth", "city_development_index", "var_1"
]
AGGREGATED_COLUMNS = [
"click_sum_age_sex_prod", "click_count_age_sex_prod",
"unique_campaigns_age_sex_prod", "unique_webpages_age_sex_prod",
"click_sum_city_age_prod", "click_count_city_age_prod",
"unique_campaigns_city_age_prod", "unique_webpages_city_age_prod"
]
TEMPORAL_COLUMNS = ["year", "month", "day", "hour", "minute", "weekday"]
# ===========================
# LOAD DATASETS
# ===========================
def load_data(train_path=TRAIN_PATH, test_path=TEST_PATH):
"""Load train & test datasets, handling missing values."""
train_df = pd.read_csv(train_path)
y_train = train_df[TARGET_COLUMN]
train_df = train_df[~y_train.isnull()]
test_df = pd.read_csv(test_path)
train_df["DateTime"] = pd.to_datetime(train_df["DateTime"])
test_df["DateTime"] = pd.to_datetime(test_df["DateTime"])
train_df["DateTime"].fillna(train_df["DateTime"].mode()[0], inplace=True)
test_df["DateTime"].fillna(test_df["DateTime"].mode()[0], inplace=True)
if "DateTime" in train_df.columns:
train_df["DateTime"] = pd.to_datetime(train_df["DateTime"])
train_df["year"] = train_df["DateTime"].dt.year
train_df["month"] = train_df["DateTime"].dt.month
train_df["day"] = train_df["DateTime"].dt.day
train_df["hour"] = train_df["DateTime"].dt.hour
train_df["minute"] = train_df["DateTime"].dt.minute
train_df["weekday"] = train_df["DateTime"].dt.weekday
train_df.drop("DateTime", axis=1, inplace=True)
if "DateTime" in test_df.columns:
test_df["DateTime"] = pd.to_datetime(test_df["DateTime"])
test_df["year"] = test_df["DateTime"].dt.year
test_df["month"] = test_df["DateTime"].dt.month
test_df["day"] = test_df["DateTime"].dt.day
test_df["hour"] = test_df["DateTime"].dt.hour
test_df["minute"] = test_df["DateTime"].dt.minute
test_df["weekday"] = test_df["DateTime"].dt.weekday
test_df.drop("DateTime", axis=1, inplace=True)
# Fill missing values
train_df.fillna(-1, inplace=True)
test_df.fillna(-1, inplace=True)
return train_df, test_df
# ===========================
# FEATURE ENGINEERING: AGGREGATIONS
# ===========================
def add_aggregated_features(df, test_df):
"""Creates aggregated features based on age, gender, and product interactions."""
# Aggregate by age & gender vs product
age_sex_product_agg = df.groupby(["age_level", "gender", "product"]).agg({
"is_click": ["sum", "count"],
"campaign_id": "nunique",
"webpage_id": "nunique"
}).reset_index()
# Rename columns after aggregation
age_sex_product_agg.columns = ["age_level", "gender", "product",
"click_sum_age_sex_prod", "click_count_age_sex_prod",
"unique_campaigns_age_sex_prod", "unique_webpages_age_sex_prod"]
# Merge into train & test datasets
df = df.merge(age_sex_product_agg, on=["age_level", "gender", "product"], how="left")
test_df = test_df.merge(age_sex_product_agg, on=["age_level", "gender", "product"], how="left")
# Aggregate by city, age, product
city_age_product_agg = df.groupby(["city_development_index", "age_level", "product"]).agg({
"is_click": ["sum", "count"],
"campaign_id": "nunique",
"webpage_id": "nunique"
}).reset_index()
# Rename columns
city_age_product_agg.columns = ["city_development_index", "age_level", "product",
"click_sum_city_age_prod", "click_count_city_age_prod",
"unique_campaigns_city_age_prod", "unique_webpages_city_age_prod"]
# Merge into train & test datasets
df = df.merge(city_age_product_agg, on=["city_development_index", "age_level", "product"], how="left")
test_df = test_df.merge(city_age_product_agg, on=["city_development_index", "age_level", "product"], how="left")
# Fill missing values after merging
df.fillna(0, inplace=True)
test_df.fillna(0, inplace=True)
return df, test_df
# ===========================
# ENCODE & NORMALIZE FEATURES
# ===========================
def preprocess_data(df, test_df, categorical_columns):
"""Encodes categorical features, normalizes numerical features, and prepares the dataset."""
label_encoders = {}
for col in categorical_columns:
le = LabelEncoder()
df[col] = le.fit_transform(df[col].astype(str))
test_df[col] = test_df[col].astype(str).map(lambda s: le.transform([s])[0] if s in le.classes_ else -1)
label_encoders[col] = le # Store encoders for later use
numerical_columns = [col for col in FEATURE_COLUMNS + AGGREGATED_COLUMNS if col not in categorical_columns]
# scaler = StandardScaler()
# df[numerical_columns] = scaler.fit_transform(df[numerical_columns])
# test_df[numerical_columns] = scaler.transform(test_df[numerical_columns])
return df, test_df, label_encoders,# scaler
# ===========================
# SPLIT DATA & HANDLE IMBALANCE
# ===========================
def split_and_balance_data(df, target_column):
"""Splits data into training and validation sets, applies SMOTE to balance classes."""
X = df[IDS_COLUMNS + FEATURE_COLUMNS + AGGREGATED_COLUMNS + TEMPORAL_COLUMNS]
y = df[target_column]
# Handle class imbalance using SMOTE
smote = SMOTE(sampling_strategy="auto", random_state=42)
X_resampled, y_resampled = smote.fit_resample(X, y)
# Split into training & validation sets
X_train, X_val, y_train, y_val = train_test_split(
X_resampled, y_resampled, test_size=0.2, random_state=42, stratify=y_resampled
)
return X_train, X_val, y_train, y_val
# ===========================
# VISUALIZE FEATURES
# ===========================
def visualize_features():
"""Generates visualizations for aggregated features."""
df, _ = load_data()
df, _ = add_aggregated_features(df, df)
sns.set_style("whitegrid")
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
sns.barplot(x="age_level", y="click_sum_age_sex_prod", hue="gender",
data=df, ax=axes[0], palette="coolwarm")
axes[0].set_title("Total Clicks by Age & Gender vs Product")
sns.barplot(x="city_development_index", y="click_sum_city_age_prod", hue="age_level",
data=df, ax=axes[1], palette="viridis")
axes[1].set_title("Total Clicks by City Development Index & Age")
plt.tight_layout()
plt.show()
# ===========================
# RUN FULL DATA PROCESSING PIPELINE
# ===========================
def load_and_process_data():
"""Runs the full data processing pipeline and returns preprocessed training & test data."""
df, test_df = load_data()
df, test_df = add_aggregated_features(df, test_df)
df, test_df, label_encoders = preprocess_data(df, test_df, CATEGORICAL_COLUMNS)
X_train, X_val, y_train, y_val = split_and_balance_data(df, TARGET_COLUMN)
return X_train, X_val, y_train, y_val, test_df
if __name__ == "__main__":
print("🔹 Loading and processing data...")
X_train, X_val, y_train, y_val, test_df = load_and_process_data()
print("✅ Data successfully loaded and processed!")