Часть 2: Разработка признаков, моделирование и анализ после моделирования

#DataAnalytics #DataVisualization #Python #ML #MachineLearning

часть 1: https://medium.com/@orenalyze/exploring-thelook-ecommerce-dataset-returned-product-analytics-5b770b024e21

Разработка функций

Выбор функций: ручнойвыбор

  1. Удалить функции уникального идентификатора = user_id, order_id, product_id
  2. Удалите функции, основанные на времени: как мы упоминали в предыдущей главе = created_at, Ship_at, Delivered_At, Prep_Time, Delivery_Time, Total_Time
  3. Удалить функцию с высокой кардинальностью: есть две функции с высокой кардинальностью. City (всего 1289 уникальных значений) и product_name (всего 4487). К счастью, у нас есть состояние, доступное в базе данных, поэтому мы можем использовать его вместо этого и уменьшить кардинальность до 49. Кроме того, для product_name нет значительных различий в количестве покупок каждого продукта (максимум 4 покупки на продукт, только 2 продукта). ). Вместо этого я решил представить продукты, используя функцию product_category = city, product_name.
  4. Удалить географическое местоположение: потому что мы уже конвертировали его в расстояние = d_lat, d_long, u_lat, u_long

Для статистического отбора я буду использовать два метода: встроенный и фильтрующий. Я расскажу об этом после процесса выбора модели.

статус, возраст, пол, штат, traffic_source, product_retail_price, product_category, dc_name, s2e_dist, end_dc, e2c_dist

Это список функций для моделирования (ранняя стадия)

Обработка выбросов, масштабирование признаков и преобразование признаков

Местоположение пользователя (штат)

Как упоминалось в предыдущей главе, я решил убрать Аляску и Гавайи.

Стоимость товара в каталоге

Судя по визуализации, есть заметные выбросы. Эти выбросы появляются в нескольких категориях продуктов и статусах. Учитывая степень их присутствия, их удаление вряд ли приведет к значительной потере информации. Кроме того, распределение переменной цены листинга сильно смещено вправо, поэтому я применю логарифмическое преобразование.

  • Удалить выброс : удалить диапазон выше 99,5 процентилей (удалить верхние 25)
  • Преобразование функции: преобразование журнала

расстояние e2c

Функция e2c_dist также демонстрирует распределение с перекосом вправо. Применение логарифмического преобразования оказалось неэффективным. Вместо этого я использовал преобразование Бокса-Кокса.

  • Преобразование функции : преобразование Бокса-Кокса

Кодирование функций

  1. Двоичное значение [статус, пол]:Порядковый номер. Для «status» я намерен вручную закодировать его, поэтому целевой переменной «Returned» присваивается значение 1 для упрощения интерпретации. Что касается «пола», в будущем я могу изучить другие методы, учитывая участие ЛГБТК+. Пока F=0, M=1.
  2. Низкая кардинальность [traffic_source, dc_name, end_dc] : горячее кодирование.
  3. Высокая кардинальность [состояние, product_category] . На текущем этапе я буду использовать Oгорячее кодирование, поскольку оно позволяет нам интерпретировать важность функции на основе отдельной категории внутри функции. Наша главная цель — выявить проблемы, которые приводят к возврату продукции, а не прогнозировать, какие заказы могут быть возвращены. Если проклятие размерности станет проблемой, я могу рассмотреть возможность использования целевого кодирования в качестве альтернативы.

Моделирование

Подготовка данных

  • Обработка дисбаланса классов: наше целевое значение не сильно отличается, поэтому я буду решать эту проблему, используя метод передискретизации. Размер данных увеличился с 4923 до 7026 экземпляров.
  • Разделение тестового обучения: обучение 80% и тестирование 20%
  • Модель: логистическая регрессия, случайный лес, XGBoost и CatBoost.
  • Метрика оценки: Отзыв. Основное внимание уделяется решению и сокращению существующей проблемы, которая может привести к высокой стоимости кампании. Мы можем снизить стоимость позже, после какой-то кампании, изменив метрику на более сбалансированную.
  • CV = 5
  • случайное семя = 42

Выбор модели

Num_feature = ['age','product_retail_price','s2e_dist','e2c_dist']
Bi_feature = ['gender']
Low_card_feature = ['traffic_source','dc_name','end_dc']
Hi_card_feature = ['state','product_category']

Я пишу конвейер, чтобы предотвратить утечку данных и обеспечить согласованность. Только CatBoost, я позволю модели напрямую обрабатывать переменные высокой мощности без кодирования.

Чтобы найти лучший результат (отзыв) для каждой модели, я использую GridSearchCV с широким диапазоном гиперпараметров. Такой подход обеспечит равные возможности для каждой модели.

В результате XGBoost является самой эффективной моделью. Поскольку модель уже демонстрирует хороший диапазон отзыва на уровне 0,8459%, нет необходимости в статистическом выборе признаков. Основное внимание будет уделено тонкой настройке гиперпараметров для дальнейшей оптимизации производительности.

Основная проблема с моделью - переоснащение, в первую очередь в результате передискретизации. Чтобы решить эту проблему, я решил применить регуляризацию L1 и некоторые гиперпараметры, которые уменьшают переоснащение.

Первоначальные результаты показывают, что модель точной настройки (FT) лучше работает с обучающим набором данных по сравнению с моделью FT+L1. Однако применительно к тестовому набору. Модель FT показывает более низкий балл. Следовательно, я решил продолжить тонкую настройку модели FT+L1, которая дает многообещающие результаты. Эта модель обеспечивает баланс за счет использования гиперпараметров, которые предлагают меньшую сложность модели при достижении более высоких показателей по сравнению с моделью без L1.

#FT+L1plus model
# Param
parametersXGBoostFTL1p = {
    'XGBoostFT__n_estimators': [130,140,145,150,155,160],
    'XGBoostFT__learning_rate': [0.05, 0.1],
    'XGBoostFT__max_depth': [9,10,11,12,13,14],
    'XGBoostFT__subsample': [0.85,0.9]
}
model_xgboostFTL1p = XGBClassifier(alpha=1,random_state=seed)

# Pipeline
pipelineXGBoostFTL1p = Pipeline(steps=[
    ('preprocess', preprocessor),
    ('XGBoostFT', model_xgboostFTL1p)
])

# Grid
model_XGBoostFTL1p = GridSearchCV(
    pipelineXGBoostFTL1p,
    parametersXGBoostFTL1p,
    cv=5,
    scoring='recall',
    verbose=False
)
# Result
model_XGBoostFTL1p.fit(X_train, y_train)
print("Best parameters: ", model_XGBoostFTL1p.best_params_)
print("Best score: ", model_XGBoostFTL1p.best_score_)

Постмоделирующий анализ

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

Один недостаток, с которым я столкнулся при работе с Shapley Values, — это сложность интеграции с пайплайном. Извлечение информации часто требует обхода измерений (массивов), что может занять много времени, особенно в случае многоклассовой проблемы. К счастью, в данном случае мы имеем дело с бинарной классификацией.

Характеристики расстояния (E2C и S2E), по-видимому, оказывают значительное влияние на эту модель.

Первые четыре числовых признака (непрерывный и дискретный) могут быть сложными для интерпретации из-за их сложных взаимосвязей. В то время как функции бинарного класса (из горячих) обычно легче интерпретировать.

  • e2c_distи возраст: на крайних границах диапазона функции есть заметное наблюдение, что чем больше расстояние, тем выше вероятность возврата заказа. Об этом можно судить по наблюдаемым положительным и отрицательным влияниям.
  • product_retail_price. Более низкие цены сильнее влияют на вероятность возврата.
  • s2e_dist: невозможно интерпретировать с помощью визуализации.
  • пол: очевидно, что женщины с большей вероятностью вернут товар. [Женщина=0, Мужчина=1]

Что касается остальных бинарных функций, я сгруппирую их на основе их основного атрибута и интерпретирую 10 основных функций.

Спасибо, что прочитали мою статью. В качестве благодарности я хотел бы поделиться полезным трюком, который я разработал для эффективной интерпретации большого количества классов. (Давайте оставим это между нами. Я не хочу, чтобы мой профессор ударил меня по голове 🤣)

X_train_preprocessed_df — это преобразованная версия X_train с использованием препроцессора внутри конвейера. Он хранится в виде DataFrame.

Feature_Name — это список названий функций (столбцов).

#Create Dataframe from shapvalue with X_train_preprocessed_df columns
DF_shap_values = pd.DataFrame(shap_values.values, columns=X_train_preprocessed_df.columns)
DF_shap_values.index = X_train_preprocessed_df.index

def calculate_recommendation(row):
    feature_recommendations = []
    #Calculate feature_value and threshold
    for feature in Feature_Name:
        shap_value = row[feature]
        feature_value = X_train_preprocessed_df.loc[row.name, feature]
        feature_threshold = Feature_thresholds[feature]
        shap_threshold = 0
        #return recommendation
        if feature_value > feature_threshold:
            if shap_value > shap_threshold:
                recommendation = "Decrease"
            else:
                recommendation = "Increase"
        else:
            if shap_value > shap_threshold:
                recommendation = "Increase"
            else:
                recommendation = "Decrease"
        feature_recommendations.append(recommendation)
    return feature_recommendations
Feature_thresholds = X_train_preprocessed_df.mean().to_dict()
DF_recom = DF_shap_values.apply(calculate_recommendation, axis=1)

# Convert into a DataFrame
DF_recommendations_temp = pd.DataFrame(DF_recom.tolist(), columns=DF_shap_values.columns)
# Calculate the mode of each column
feature_modes = DF_recommendations_temp.mode().iloc[0]
# Map the modes to the corresponding features in DF_recommendation
DF_recommendation['Recommendation'] = DF_recommendation['Feature Name'].map(feature_modes)

Целью этого кода является применение рекомендаций «Уменьшение» и «Увеличение» на основе значений формы и порога формы. Порог формы рассчитывается как среднее значений формы для каждой функции.

Логика рекомендаций будет варьироваться в зависимости от цели анализа. В этом случае, когда цель состоит в том, чтобы уменьшить количество возвращенных заказов, любая функция с более высоким значением формы, превышающим пороговое значение, будет рассматриваться для рекомендации «Уменьшить».

Текущая реализация предоставляет бинарные рекомендации на основе расчета mode. При желании рекомендации можно расширить, включив в них дополнительные категории, например «Слегка отрицательные» или «Сильно положительные», изменив расчет соответствующим образом.

Давай продолжим.

Похоже, что мой расчет (рекомендация) совпадает с визуализацией (вручную), которую я описал ранее. 😅

Я приведу вам пример о Рекомендации.

  • Источник трафика Поиск (бинарный признак, где 1 – наличие, 0 – отсутствие), рекомендация Увеличить подразумевает, что пользователи, пришедшие из источника поиска, более высокая вероятность невозврата товара.
  • Источник трафика Органический, Уменьшениепредполагает, что пользователи, пришедшие из органического источника, с большей вероятностью вернут продукт.

Далее я представлю сводную таблицу, сгруппированную по признаку происхождения.

Удивительно, но рекомендации модели по категориям товаров отличаются от нашего EDA. №1 — Шорты (10-е место в рейтинге самых возвратных заказов по категории товаров). Кроме того, Нижнее белье, которое занимает второе место, не появляется в 10 самых популярных возвращенных заказах.

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

Бывший. улучшить понимание пользователя и улучшить четкость измерения размера или предоставить больше образцов изображений и четких рекомендаций по измерению размера и т. д.

Результат end_dc согласуется с нашим EDA, подчеркивая необходимость обратить внимание на Лос-Анджелес. Это говорит о том, что Лос-Анджелес является важной областью, требующей особого внимания и целенаправленных стратегий. Также он находится в Калифорнии (штат).

Между тем, Лос-Анджелес в качестве dc_name (начальный dc) рекомендуется увеличить, это означает, что хранящийся там продукт соответствует end_dc.

Объединив информацию из трех таблиц. Я полагаю, что Лос-Анджелес нуждается в дополнительных распределительных центрах или любых других средствах для помощи в доставке своей продукции.

КОНЕЦ

Спасибо за чтение.

Я надеюсь, что у вас есть радостный и обогащающий опыт.

часть 1: https://medium.com/@orenalyze/exploring-thelook-ecommerce-dataset-returned-product-analytics-5b770b024e21