Имена колонок в SHAP и Среднее в numpy

Вопрос или проблема

Я пытаюсь рассчитать значения SHAP для моих данных в модели RandomForest. Проблема в том, что мои данные – это временной ряд, и мне нужно получить среднее значение для всех значений SHAP в этих интервалах и нормализовать их. Вот мои воспроизводимые данные и код:

import pandas as pd
from pandas.tseries.offsets import MonthBegin, MonthEnd
from sklearn.preprocessing import StandardScaler
import shap
import numpy as np
from sklearn.ensemble import RandomForestRegressor

def adjust_dates_by_month(_dax_df: pd.DataFrame, _all_df: pd.DataFrame, _standardize: bool, _tone_WA_LM_ML_Hedo: int, base_year: int, base_month: int, interval: int):
    # Рассчитываем новую базовую дату
    base_date = pd.Timestamp(year=base_year, month=base_month, day=1) + pd.DateOffset(months=interval)
    
    # Определяем даты начала и конца учебного периода
    train_start = base_date
    train_end = train_start + pd.DateOffset(months=2)
    
    # Определяем период оценки
    evaluate_start = train_end + MonthBegin(1)
    evaluate_end = evaluate_start + pd.DateOffset(months=1) - pd.DateOffset(days=1)
    
    # Определяем период для прогноза
    to_be_predicted_start = evaluate_end + MonthBegin(1)
    to_be_predicted_end = to_be_predicted_start + pd.DateOffset(years=1) - pd.DateOffset(days=1)
    
    # Присваиваем даты датафрейму
    _all_df['date'] = pd.to_datetime(_all_df[['year', 'month']].assign(day=1))
    
    # Фильтруем строки для обучающего набора данных
    train_df = _all_df[(_all_df['date'] >= train_start) & (_all_df['date'] <= train_end)]
    
    # Фильтруем строки для набора данных для оценки
    evaluate_df = _all_df[(_all_df['date'] >= evaluate_start) & (_all_df['date'] <= evaluate_end)]
    
    # Фильтруем строки для набора данных, который нужно предсказать
    to_be_predicted_df = _all_df[(_all_df['date'] >= to_be_predicted_start) & (_all_df['date'] <= to_be_predicted_end)]
    
    if _standardize:
        scaler = StandardScaler()
        if _tone_WA_LM_ML_Hedo == 0:  # Пример условия для тональных корректировок
            additional_columns = ["Tone", "Positive_Score", "Negative_Score", "Polarity", "Activity_Reference_Density", "Self_Group_Reference_Density"]
            _all_df[additional_columns] = scaler.fit_transform(_all_df[additional_columns])
    train_df=train_df[['Code','Date', 'year',   'month','M','T','D','C','P','O','TE','Tone','Positive_Score','Negative_Score','Polarity','Activity_Reference_Density','Self_Group_Reference_Density']]
    evaluate_df=evaluate_df[['Code','Date', 'year', 'month','M','T','D','C','P','O','TE','Tone','Positive_Score','Negative_Score','Polarity','Activity_Reference_Density','Self_Group_Reference_Density']]
    to_be_predicted_df=to_be_predicted_df[['Code','Date', 'year',   'month','M','T','D','C','P','O','TE','Tone','Positive_Score','Negative_Score','Polarity','Activity_Reference_Density','Self_Group_Reference_Density']]
    return train_df.reset_index(drop=True),evaluate_df.reset_index(drop=True),to_be_predicted_df.reset_index(drop=True)

# Пример использования
data = {
    'Code': [3711, 3711, 3711, 3711, 3711, 3711, 3711, 3711, 3711, 3711],
    'Date': pd.to_datetime(['2015-03-01', '2015-04-01', '2015-05-01', '2015-06-01', '2015-07-01', '2015-08-01', '2015-09-01', '2015-10-01', '2015-11-01', '2015-12-01']),
    'M': [70042064, 63624232, 61003728, 62000000, 63000000, 64000000, 65000000, 66000000, 67000000, 68000000],
    'T': [1.63, 1.63, 1.63, 1.60, 1.65, 1.70, 1.75, 1.80, 1.85, 1.90],
    'D': [2.13, 2.13, 2.13, 2.10, 2.12, 2.14, 2.16, 2.18, 2.20, 2.22],
    'C': [1.77, 1.77, 1.77, 1.75, 1.73, 1.71, 1.69, 1.67, 1.65, 1.63],
    'P': [2.06, 2.06, 2.06, 2.04, 2.02, 2.00, 1.98, 1.96, 1.94, 1.92],
    'O': [1.05, 1.05, 1.05, 1.07, 1.09, 1.11, 1.13, 1.15, 1.17, 1.19],
    'TE': [1.12, 1.04, 1.31, 1.33, 1.35, 1.37, 1.39, 1.41, 1.43, 1.45],
    'Tone': [0.5, 0.6, 0.55, 0.57, 0.59, 0.61, 0.63, 0.65, 0.67, 0.69],
    'Positive_Score': [0.1, 0.1, 0.1, 0.11, 0.11, 0.12, 0.12, 0.13, 0.13, 0.14],
    'Negative_Score': [0.05, 0.07, 0.06, 0.06, 0.06, 0.07, 0.07, 0.08, 0.08, 0.09],
    'Polarity': [0.5, 0.6, 0.55, 0.56, 0.57, 0.58, 0.59, 0.60, 0.61, 0.62],
    'Activity_Reference_Density': [0.07, 0.07, 0.07, 0.08, 0.08, 0.09, 0.09, 0.10, 0.10, 0.11],
    'Self_Group_Reference_Density': [0.03, 0.03, 0.03, 0.04, 0.04, 0.05, 0.05, 0.06, 0.06, 0.07]
}

df = pd.DataFrame(data)

# Добавление столбцов Год и Месяц
df['year'] = df['Date'].dt.year
df['month'] = df['Date'].dt.month

я

shap_values_list = []
for _interval in range(0, 4):    
    train,evaluate,to_be_predicted_df = adjust_dates_by_month(_dax_df=df, _all_df=df, _standardize=True, _tone_WA_LM_ML_Hedo=0, base_year=2015, base_month=3, interval=_interval)
    model=RandomForestRegressor()
    model.fit(train.iloc[:, 5:], train['M'])
    eval = to_be_predicted_df.iloc[:, 5:]
    explainer = shap.Explainer(model.predict, eval)
    shap_values_list.append(explainer(eval).values)

На данный момент мой код вычисляет значения SHAP, однако у меня есть, как уже упоминалось, 3 проблемы

  1. Я не вижу названия столбцов в графике, как мне передать названия столбцов в график?
  2. Как мне рассчитать среднее значение из этих чисел, чтобы у меня было одно значение для каждого столбца?
  3. Как мне нормализовать данные так, чтобы сумма равнялась 1?

Этот код как-то работает, когда интервал равен 1, но если больше 1, тогда не работает.

all_shap_values = np.array(shap_values_list)
mean_shap_values = np.mean(all_shap_values, axis=0)
normalized_shap_values = mean_shap_values / np.sum(mean_shap_values)
shap.summary_plot(normalized_shap_values, plot_type="bar", show=False)
bars = plt.gca().get_children()
plt.xlabel('')  
plt.show()

Ответ или решение

Ответ на вопрос по SHAP и Mean в NumPy

Ваш запрос включает несколько вопросов относительно расчета SHAP-значений и их обработки в контексте временных рядов. Давайте разберем каждый из ваших вопросов подробно.

1. Как передать названия колонок в график SHAP?

Для того чтобы отобразить названия колонок на графике SHAP, вы можете использовать параметр feature_names в функции shap.summary_plot. Вам нужно будет передать список названий колонок, соответствующих вашим данным, например:

feature_names = ['M', 'T', 'D', 'C', 'P', 'O', 'TE', 'Tone', 'Positive_Score', 'Negative_Score', 'Polarity', 'Activity_Reference_Density', 'Self_Group_Reference_Density']
shap.summary_plot(normalized_shap_values, feature_names=feature_names, plot_type="bar", show=False)

2. Как рассчитать средние значения из SHAP?

Средние значения SHAP-значений для каждого признака можно получить с помощью функции np.mean, как вы уже начали делать. Однако следует убедиться, что каждая подгруппа SHAP-значений имеет одинаковую форму. После того как все значения будут собраны в один массив, можно будет выполнить следующую операцию:

all_shap_values = np.array(shap_values_list)
mean_shap_values = np.mean(all_shap_values, axis=0)

3. Как нормализовать данные так, чтобы их сумма равнялась 1?

Нормализацию можно провести, разделив каждое значение на сумму всех значений. Вы правильно подходите к этой задаче:

normalized_shap_values = mean_shap_values / np.sum(mean_shap_values)

Это приведет к тому, что сумма нормализованных SHAP-значений всегда будет равна 1.

Пример кода

Рассмотрим пример кода, который объединяет все вышеперечисленные шаги:

import matplotlib.pyplot as plt

# Собираем SHAP-значения
shap_values_list = []
for _interval in range(0, 4):    
    train, evaluate, to_be_predicted_df = adjust_dates_by_month(_dax_df=df, _all_df=df, _standardize=True, _tone_WA_LM_ML_Hedo=0, base_year=2015, base_month=3, interval=_interval)
    model = RandomForestRegressor()
    model.fit(train.iloc[:, 5:], train['M'])
    eval = to_be_predicted_df.iloc[:, 5:]
    explainer = shap.Explainer(model.predict, eval)
    shap_values_list.append(explainer(eval).values)

# Рассчитываем средние значения
all_shap_values = np.array(shap_values_list)
mean_shap_values = np.mean(all_shap_values, axis=0)

# Нормализация
normalized_shap_values = mean_shap_values / np.sum(mean_shap_values)

# Названия признаков
feature_names = ['M', 'T', 'D', 'C', 'P', 'O', 'TE', 'Tone', 'Positive_Score', 'Negative_Score', 'Polarity', 'Activity_Reference_Density', 'Self_Group_Reference_Density']

# Построение графика
shap.summary_plot(normalized_shap_values, feature_names=feature_names, plot_type="bar", show=False)
plt.xlabel('')  
plt.show()

Заключение

Теперь вы можете визуализировать ваши SHAP-значения с помощью корректных названий колонок, а также правильно вычислить их средние и нормализованные значения. Обратите внимание, если ваш код не работает при интервалах больше 1, это может быть связано со структурой данных или с самим процессом предсказания. Убедитесь, что ваши данные не теряются при фильтрации в функции adjust_dates_by_month.

Если у вас есть дополнительные вопросы или вам нужна помощь, не стесняйтесь обращаться!

Оцените материал
Добавить комментарий

Капча загружается...