Key Drivers Analysis

Author

Madeline Sands

Published

May 26, 2024

This post explains and implements a few measures of variable importance for features of a payment card and their impact on customer satisfaction with that payment card.

1. Background on Variable Importance and Key Drivers Analysis

Variable importance and key drivers analysis are often used in conjunction when determining which variables contribute the most to a model’s predictive power. Different supervised machine learning models use various methods to calculate variable importance, with the same goal of trying to see which explanatory variable has the greatest impact on the response variable. We will review these different methods to identify variable importance below and implement them using a dataset examining customer satisfaction with a payment card.

Key Driver Analysis Methods from Linear Regression Models

Pearsons Correlation

In linear regression models, key drivers can be identified via the change in the value of the Pearson Correlation Coefficient. Pearson’s correlation coefficient is a measure used to quantify the linear relationship between two variables, and ranges from -1 to +1. A coefficient of +1 indicates a perfect positive linear relationship whereas -1 indicates a perfect negative linear relationship. 0 indicates no linear correlation.

Suppose we have 3 explanatory variables as part of our linear regression model. We can remove one variable at a time and recalculate our Pearson’s Correlation value. Features with high absolute values of the correlation coefficient (close to 1 or -1) are likely more important to our model’s predictive power because they have a strong linear relationship with the target variable. The sign can also indicate the direction of the relationship. A positive sign means that as the feature increases, the target increases and vice versa for the negative sign. We can use the correlation coefficient to rank the features based on the absolute value of their respective coefficients, thus features with higher absolute values are generally more influential in predicting the target variable in a linear regression context.

When calculating Pearon’s we take the covariance of 2 variables, and divide it by the product of their standard deviations. This formula inherently standardizes the covariance, meaning that Pearson’s correlation coefficient itself is already a standardized measure. Therefore, when implementing pearson’s, you do not need to standardize your data before finding the coefficient values.

However, it is critical to note that while strong correlations with the target variable are important, it’s also crucial to check the correlations between features. High correlation between features, i.e. multicollinearity, can affect the model’s stability and the interpretation of the coefficients.

Usefullness

Usefulnes is another measure derived from linear regression models. “Usefulness” or \({\Delta}R^2\), measures the impact of individual features on the performance of a regression model by observing how the model’s \(R^2\) value changes when a feature is dropped. This technique is valuable because it can reveal the contribution of a specific feature to the overall explanatory power of the model, beyond a simple correlation. It is also a relatively straightforward to run.

However, there are some considerations to take into account when using the \({\Delta}R^2\) to evaluate key drivers, specifically relating to interactions and non-linearity between the features, similar to Pearson’s. The change in \(R^2\) doesn’t account for interactions between features unless specifically modeled. Therefore, if there is an interaction between 2 variables, that would have to be explicilty included in a linear regression model for it to have an impact on the \(R^2\) value. Also, non-linear relationships might not be captured effectively. If features are highly correlated, removing one might not show a significant change in \(R^2\) because its effect is being captured by the correlated features.

Methods Derived from Game Theory

Shapley Values

Shapley values are a concept derived from cooperative game theory used to fairly allocate the “payout” among players depending on their contribution to the total game. In the context of machine learning, Shapley values can be used to explain the contribution of each feature to the model’s prediction. Shapley values provide a detailed breakdown of how each feature contributes to the final prediction, which can often be more insightful than measures like the pearsons coefficients or \({\Delta}R^2\).

When computing Shapley values, the need to standardize data before computing Shapley values largely depends on the type of predictive model used. For linear regression models, standardizing might not be necessary for interpreting the contribution of features, as the model is fairly transparent and the contribution of features can be directly observed from the regression coefficients. However, if we are running and creating more complex models like neural networks or ensemble models (e.g., random forests, gradient boosting machines), standardizing features can help in comparing their contributions on a common scale, especially if the features vary widely in scale and units. Finally, regardless of the model, standardizing features can make the interpretation of Shapley values more straightforward across different features. When features are on the same scale, their Shapley values are easier to compare, as no single feature will dominate simply because of differences in scale.

Johnson’s Relative weights

Johnson’s relative weights analysis is a statistical technique used to determine the importance of predictor variables in a regression model, especially when dealing with multicollinearity among predictors. This method decomposes the total variance explained by the model into portions attributable to each predictor, taking into account the intercorrelations among them.

Johnson’s relative weights transform the raw regression coefficients by considering the correlation matrix of the predictors and results in a set of weights that reflect the contribution of each predictor to the model’s predictive power. Johnson’s weights provide a more nuanced view of feature importance than simple correlation or regression coefficients alone, particularly useful in models where predictors are not independent.

When computing Johnson’s relative weights, it is generally recommended to standardize the variables. Standardization ensures that each predictor contributes to the regression model on a comparable scale. This is crucial because Johnson’s Relative Weights are used to interpret the proportion of explained variance in the dependent variable that can be attributed to each independent variable. If the variables are not standardized, their weights might reflect their scale rather than their actual contribution to the model. Standardization removes this disparity, allowing a fair assessment of each variable’s relative importance based on their contribution to the model’s predictive power rather than their scale.

Methods Derived from Decision Trees and Ensemble Models

Decision Trees and Gini Importance

In Decision Trees and Ensemeble Models (such as Random Forest or Gradient boosting) methods such as Gini Importance and Permutation Importance are used to determine this varibale importance. Gini Importance - Measures how much each feature decreases the impurity in a decision tree, averaged over all trees in the ensemble. Permutation Importance - Measures the decrease in model performance (such as via accuracy or Root mean squared error) when the values of a feature are randomly shuffled, breaking the relationship between the feature and the target.

By understanding variable importance and conducting key drivers analysis, organizations can make data-driven decisions, prioritize resources, and develop strategies that target the most impactful factors.

When creating decision trees and computing the Gini Importance, standardizing the data beforehand is not necessary and generally doesn’t enhance the performance or interpretability of the model.

2. Data processing

import numpy as np 
import pandas as pd 
import pyrsm as rsm 
from sklearn.linear_model import LinearRegression
from scipy.stats import pearsonr
import statsmodels.api as sm
import shap
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
import seaborn as sns
import matplotlib.pyplot as plt 
from textwrap import wrap


driver_analysis = pd.read_csv('data/data_for_drivers_analysis.csv')
driver_analysis.head(10)
brand id satisfaction trust build differs easy appealing rewarding popular service impact
0 1 98 3 1 0 1 1 1 0 0 1 0
1 1 179 5 0 0 0 0 0 0 0 0 0
2 1 197 3 1 0 0 1 1 1 0 1 1
3 1 317 1 0 0 0 0 1 0 1 1 1
4 1 356 4 1 1 1 1 1 1 1 1 1
5 1 395 4 1 1 0 1 1 0 1 1 0
6 1 586 3 1 1 1 1 1 0 1 1 0
7 1 596 2 1 1 1 1 1 1 0 1 1
8 1 978 3 1 0 0 0 0 0 1 0 0
9 1 987 3 1 1 1 1 1 1 1 1 1

We are now going to see these methods in action. We are using a database that has 2553 observations across 9 variables, with the response variable being the satisfaction score. The following regressors are all binary variables:

  • trust - Is offered by a brand I trust
  • build - Helps build credit quickly
  • differs - Is different from other cards
  • easy - Is easy to use
  • appealing - Has appealing benefits or rewards
  • rewarding - Rewards me for responsible usage
  • popular- Is used by a lot of people
  • service - Provides outstanding customer service
  • impact - Makes a difference in my life

Respondents were asked to respond yes or no to 9 questions related to attributes of a payment card. They then provided an overall satisfaction score from 1-5. We will use the methods above to determine which attributes contribute the highest to respondents overall satisfaction of the payment cards.

Before we demonstrate differences in the relative importance values, we need to first assess the multicollinearity between the variables. Due to the Halo Effect, we see that respondents tend to rate something higher on all attributes if they like a brand, but also rate something lower on all attributes if they dislike a brand. Therefore, we often see that in perception datasets, there is a high level of multicollinearity. Below, we will run a correlation matrix to see which variables are highly correlated with each other.

correlation_matrix = driver_analysis.corr()
print(correlation_matrix)
                 brand        id  satisfaction     trust     build   differs  \
brand         1.000000  0.001459     -0.049296 -0.119908 -0.083552 -0.143542   
id            0.001459  1.000000     -0.009228 -0.016797 -0.001620  0.008360   
satisfaction -0.049296 -0.009228      1.000000  0.255706  0.191896  0.184801   
trust        -0.119908 -0.016797      0.255706  1.000000  0.399652  0.306493   
build        -0.083552 -0.001620      0.191896  0.399652  1.000000  0.370705   
differs      -0.143542  0.008360      0.184801  0.306493  0.370705  1.000000   
easy         -0.155121  0.007316      0.212985  0.480973  0.443953  0.349693   
appealing    -0.209406 -0.000157      0.207997  0.420704  0.369456  0.418159   
rewarding    -0.151821  0.027222      0.194561  0.423868  0.435770  0.349758   
popular      -0.147349  0.006211      0.171425  0.389409  0.333667  0.266456   
service      -0.101800 -0.001923      0.251098  0.503966  0.407956  0.367615   
impact       -0.130475  0.038579      0.254539  0.354062  0.383639  0.416957   

                  easy  appealing  rewarding   popular   service    impact  
brand        -0.155121  -0.209406  -0.151821 -0.147349 -0.101800 -0.130475  
id            0.007316  -0.000157   0.027222  0.006211 -0.001923  0.038579  
satisfaction  0.212985   0.207997   0.194561  0.171425  0.251098  0.254539  
trust         0.480973   0.420704   0.423868  0.389409  0.503966  0.354062  
build         0.443953   0.369456   0.435770  0.333667  0.407956  0.383639  
differs       0.349693   0.418159   0.349758  0.266456  0.367615  0.416957  
easy          1.000000   0.432904   0.461316  0.387304  0.456976  0.412092  
appealing     0.432904   1.000000   0.481159  0.376080  0.425463  0.394282  
rewarding     0.461316   0.481159   1.000000  0.350825  0.457016  0.384245  
popular       0.387304   0.376080   0.350825  1.000000  0.378262  0.305265  
service       0.456976   0.425463   0.457016  0.378262  1.000000  0.412313  
impact        0.412092   0.394282   0.384245  0.305265  0.412313  1.000000  

Pearson Correlation

# Standardizing the Driver Analysis Dataframe
da_standardized = driver_analysis.copy().iloc[:, 2:12]
da_standardized = (da_standardized - da_standardized.mean()) / da_standardized.std()
da_standardized.head()

#breaking out our Predictor and Dependent variables
X_standardized = da_standardized[["trust", "build", "differs", "easy", "appealing", "rewarding", "popular", "service", "impact"]]
y_standardized = da_standardized['satisfaction']

#Fit a linear regression model
model = LinearRegression()
model.fit(X_standardized,y_standardized)

#extract out coefficients and intercept from our linear regression model
coefficients = model.coef_
intercept = model.intercept_
#Creating an empty dictionary to store our coefficients in 
pearson_corr_matrix = {}

#extracting one coefficient at a time to calculate the correlation value of
for column in da_standardized.columns:
    if column != 'satisfaction':
        corr, _ = pearsonr(da_standardized[column], da_standardized['satisfaction'])
        pearson_corr_matrix[column] = corr

total_sum = sum(pearson_corr_matrix.values())
percentage_data = {}
# Calculate and print the percentage of the sum for each value
for key, value in pearson_corr_matrix.items():
    percentage = (value / total_sum) * 100
    percentage_data[key] = percentage

# Convert the new dictionary to a DataFrame
pearson_corr_df = pd.DataFrame(list(percentage_data.items()), columns=['Features', 'Pearson_corr_%'])

pearson_corr_df["Pearson_corr_%"] = pearson_corr_df["Pearson_corr_%"].round(1)

print(pearson_corr_df)
    Features  Pearson_corr_%
0      trust            13.3
1      build            10.0
2    differs             9.6
3       easy            11.1
4  appealing            10.8
5  rewarding            10.1
6    popular             8.9
7    service            13.0
8     impact            13.2

Standardized Regression Coefficients

X_unstandardized = driver_analysis[["trust", "build", "differs", "easy", "appealing", "rewarding", "popular", "service", "impact"]]
y_unstandardized = driver_analysis['satisfaction']

model_SLC = LinearRegression()
model_SLC.fit(X_unstandardized, y_unstandardized)
standardized_coefficients = model_SLC.coef_
SLC_coefficients_df = pd.DataFrame({'Predictor': X_standardized.columns, 'Standardized Coefficient': standardized_coefficients})

total_sum_regression_coef = SLC_coefficients_df["Standardized Coefficient"].sum()


SLC_coefficients_df['SLC_Percent of Total'] = (SLC_coefficients_df['Standardized Coefficient'] / total_sum_regression_coef) * 100

SLC_coefficients_df["SLC_Percent of Total"] = SLC_coefficients_df["SLC_Percent of Total"].round(1)
print(SLC_coefficients_df)

SLC_df = SLC_coefficients_df[["Predictor", "SLC_Percent of Total"]]
   Predictor  Standardized Coefficient  SLC_Percent of Total
0      trust                  0.272612                  24.8
1      build                  0.046960                   4.3
2    differs                  0.069159                   6.3
3       easy                  0.051623                   4.7
4  appealing                  0.079673                   7.3
5  rewarding                  0.011931                   1.1
6    popular                  0.039042                   3.6
7    service                  0.207591                  18.9
8     impact                  0.319789                  29.1

Shapley Values for a linear regression

from sklearn.model_selection import train_test_split

# Fit the linear regression model
model_shapley = LinearRegression()
model_shapley.fit(X_standardized, y_standardized)

# Initialize the explainer
explainer = shap.Explainer(model_shapley.predict, X_standardized)

# Calculate Shapley values
shap_values = explainer(X_standardized)

# Plot Shapley values (if needed)
shap.summary_plot(shap_values, X_standardized)
ExactExplainer explainer:  60%|█████▉    | 1521/2553 [00:00<?, ?it/s]ExactExplainer explainer:  60%|██████    | 1541/2553 [00:10<00:05, 181.33it/s]ExactExplainer explainer:  61%|██████    | 1560/2553 [00:10<00:05, 167.44it/s]ExactExplainer explainer:  62%|██████▏   | 1584/2553 [00:10<00:04, 197.48it/s]ExactExplainer explainer:  63%|██████▎   | 1608/2553 [00:10<00:04, 212.03it/s]ExactExplainer explainer:  64%|██████▍   | 1631/2553 [00:10<00:04, 218.06it/s]ExactExplainer explainer:  65%|██████▍   | 1653/2553 [00:10<00:04, 207.89it/s]ExactExplainer explainer:  66%|██████▌   | 1674/2553 [00:10<00:04, 204.13it/s]ExactExplainer explainer:  66%|██████▋   | 1696/2553 [00:10<00:04, 207.26it/s]ExactExplainer explainer:  67%|██████▋   | 1719/2553 [00:10<00:03, 211.21it/s]ExactExplainer explainer:  68%|██████▊   | 1741/2553 [00:11<00:04, 171.45it/s]ExactExplainer explainer:  69%|██████▉   | 1764/2553 [00:11<00:04, 186.26it/s]ExactExplainer explainer:  70%|██████▉   | 1787/2553 [00:11<00:03, 197.24it/s]ExactExplainer explainer:  71%|███████   | 1808/2553 [00:11<00:03, 190.73it/s]ExactExplainer explainer:  72%|███████▏  | 1830/2553 [00:11<00:03, 197.02it/s]ExactExplainer explainer:  73%|███████▎  | 1851/2553 [00:11<00:03, 194.67it/s]ExactExplainer explainer:  73%|███████▎  | 1871/2553 [00:11<00:03, 182.78it/s]ExactExplainer explainer:  74%|███████▍  | 1891/2553 [00:11<00:03, 184.95it/s]ExactExplainer explainer:  75%|███████▍  | 1910/2553 [00:12<00:03, 176.14it/s]ExactExplainer explainer:  76%|███████▌  | 1929/2553 [00:12<00:03, 179.50it/s]ExactExplainer explainer:  77%|███████▋  | 1954/2553 [00:12<00:03, 194.56it/s]ExactExplainer explainer:  77%|███████▋  | 1976/2553 [00:12<00:02, 198.48it/s]ExactExplainer explainer:  78%|███████▊  | 1996/2553 [00:12<00:02, 197.43it/s]ExactExplainer explainer:  79%|███████▉  | 2017/2553 [00:12<00:02, 197.54it/s]ExactExplainer explainer:  80%|███████▉  | 2037/2553 [00:12<00:02, 197.03it/s]ExactExplainer explainer:  81%|████████  | 2057/2553 [00:12<00:02, 192.06it/s]ExactExplainer explainer:  81%|████████▏ | 2077/2553 [00:12<00:02, 183.14it/s]ExactExplainer explainer:  82%|████████▏ | 2096/2553 [00:13<00:02, 177.68it/s]ExactExplainer explainer:  83%|████████▎ | 2116/2553 [00:13<00:02, 182.43it/s]ExactExplainer explainer:  84%|████████▎ | 2135/2553 [00:13<00:02, 170.80it/s]ExactExplainer explainer:  84%|████████▍ | 2157/2553 [00:13<00:02, 182.08it/s]ExactExplainer explainer:  85%|████████▌ | 2178/2553 [00:13<00:02, 186.70it/s]ExactExplainer explainer:  86%|████████▌ | 2197/2553 [00:13<00:02, 142.24it/s]ExactExplainer explainer:  87%|████████▋ | 2213/2553 [00:13<00:02, 135.43it/s]ExactExplainer explainer:  87%|████████▋ | 2229/2553 [00:13<00:02, 141.11it/s]ExactExplainer explainer:  88%|████████▊ | 2245/2553 [00:14<00:02, 133.90it/s]ExactExplainer explainer:  89%|████████▊ | 2260/2553 [00:14<00:02, 135.45it/s]ExactExplainer explainer:  89%|████████▉ | 2283/2553 [00:14<00:01, 158.80it/s]ExactExplainer explainer:  90%|█████████ | 2304/2553 [00:14<00:01, 172.48it/s]ExactExplainer explainer:  91%|█████████ | 2324/2553 [00:14<00:01, 179.96it/s]ExactExplainer explainer:  92%|█████████▏| 2351/2553 [00:14<00:01, 199.55it/s]ExactExplainer explainer:  93%|█████████▎| 2373/2553 [00:14<00:00, 204.14it/s]ExactExplainer explainer:  94%|█████████▍| 2394/2553 [00:14<00:00, 199.59it/s]ExactExplainer explainer:  95%|█████████▍| 2417/2553 [00:14<00:00, 207.25it/s]ExactExplainer explainer:  95%|█████████▌| 2438/2553 [00:14<00:00, 206.79it/s]ExactExplainer explainer:  96%|█████████▋| 2462/2553 [00:15<00:00, 214.06it/s]ExactExplainer explainer:  97%|█████████▋| 2484/2553 [00:15<00:00, 202.37it/s]ExactExplainer explainer:  98%|█████████▊| 2505/2553 [00:15<00:00, 168.58it/s]ExactExplainer explainer:  99%|█████████▉| 2523/2553 [00:15<00:00, 171.41it/s]ExactExplainer explainer: 100%|█████████▉| 2544/2553 [00:15<00:00, 181.27it/s]ExactExplainer explainer: 2554it [00:15, 66.07it/s]                           

# Sum up the absolute values of Shapley values for each feature
feature_importance = np.sum(shap_values.values, axis=0)

# Calculate the total sum of all Shapley values
total_importance = np.sum(np.abs(feature_importance))

# Compute the percentage contribution of each feature
percentage_contributions = 100 * feature_importance / total_importance

percental_total = percentage_contributions.sum()
print(percental_total)
# Create a DataFrame to display the results
shapley_df = pd.DataFrame({
    'Feature': X_standardized.columns,
    'feature_importance': feature_importance,
    'Shapley Value Sum': total_importance,
    'Shapley_percent_Total': percentage_contributions
})

shapley_df["Shapley_percent_Total"] = shapley_df["Shapley_percent_Total"].round(1)
print(shapley_df)
shapley_df_short = shapley_df[["Feature", "Shapley_percent_Total"]]
100.0
     Feature  feature_importance  Shapley Value Sum  Shapley_percent_Total
0      trust           35.362669         186.526379                   19.0
1      build            5.299767         186.526379                    2.8
2    differs           12.731269         186.526379                    6.8
3       easy            7.447898         186.526379                    4.0
4  appealing            8.891823         186.526379                    4.8
5  rewarding            1.071607         186.526379                    0.6
6    popular            1.380470         186.526379                    0.7
7    service           43.995915         186.526379                   23.6
8     impact           70.344962         186.526379                   37.7

Usefulness

X_full = sm.add_constant(X_unstandardized)  # Adding a constant term for the intercept
model_full = sm.OLS(y_unstandardized, X_full).fit()
r2_full = model_full.rsquared

# Calculating Delta R^2 for each feature
delta_r2 = {}
for feature in X_unstandardized.columns:
    X_reduced = sm.add_constant(X_unstandardized.drop(columns=[feature]))  # Reduced model without the feature
    model_reduced = sm.OLS(y_unstandardized, X_reduced).fit()
    r2_reduced = model_reduced.rsquared
    delta_r2[feature] = r2_full - r2_reduced

# Output Delta R^2 values
delta_r2_df = pd.DataFrame(delta_r2.items(), columns =["feature", "Delta R^2"])


sum_r2 = delta_r2_df["Delta R^2"].sum()

delta_r2_df["Usefulness %"] = delta_r2_df["Delta R^2"] / sum_r2 * 100
delta_r2_df["Usefulness %"] = delta_r2_df["Usefulness %"].round(2)

usefulness_df = delta_r2_df[["feature", "Usefulness %"]]

Johnson’s relative weights (Epsilon)

# Fit a linear regression model
model = LinearRegression()
model.fit(X_unstandardized, y_unstandardized)
r_squared = model.score(X_unstandardized, y_unstandardized)

# Get the correlation matrix of the standardized predictors
R = np.corrcoef(X_unstandardized, rowvar=False)

# Eigen decomposition
eigenvalues, eigenvectors = np.linalg.eig(R)

# Compute the relative importance
relative_importance = eigenvectors**2 * eigenvalues[:, np.newaxis]
relative_contributions = relative_importance.sum(axis=0)
normalized_weights = relative_contributions / relative_contributions.sum()
normalized_sum = normalized_weights.sum()

# Calculate the proportional contributions to R-squared
proportional_contributions = normalized_weights * r_squared

# Display the results
results = pd.DataFrame({
    'Feature': X_standardized.columns,
    'Relative Contribution': proportional_contributions,
    'Johnsons Epsilon': normalized_weights*100
})

results["Johnsons Epsilon"] = results["Johnsons Epsilon"].round(2)
johnsons_df = results[["Feature", "Johnsons Epsilon"]]
print(johnsons_df)
     Feature  Johnsons Epsilon
0      trust             11.39
1      build             11.37
2    differs             16.98
3       easy             12.90
4  appealing              7.46
5  rewarding              8.31
6    popular             10.88
7    service             13.37
8     impact              7.34

Mean Decrease in the Gini Coefficient from a Random Forest

X_train, X_test, y_train, y_test = train_test_split(X_unstandardized, y_unstandardized, test_size=0.2, random_state=42)

rf = RandomForestClassifier(n_estimators=1000, random_state=42, criterion='gini')

# Train the model
rf.fit(X_train, y_train)

# Extract feature importances (Mean Decrease in Gini)
feature_importances = rf.feature_importances_

# Create a DataFrame to hold the feature importances
features = X_unstandardized.columns
importance_df = pd.DataFrame({
    'Feature': features,
    'Importance': feature_importances
})

# Sort the DataFrame by importance
importance_df = importance_df.sort_values(by='Importance', ascending=False)

importance_df["Importance_percentage"] = (importance_df["Importance"] / importance_df["Importance"].sum()) * 100
importance_df["gini_percent"] = importance_df["Importance_percentage"].round(2)
gini_index = importance_df[["Feature", "gini_percent"]]

3. Key Driver Analysis and Interpretation

#Merging all of the dataframes together
#Merging Pearsons with Standardized Linear Coefficient
merged_df = pd.merge(pearson_corr_df, SLC_df, left_on = 'Features', right_on = 'Predictor', how = 'left')
#Merging on Shapley Percents
merged_df = pd.merge(merged_df,shapley_df_short, left_on = 'Features', right_on = 'Feature', how = 'left')
#Merging on Usefulness Percentages
merged_df = pd.merge(merged_df,usefulness_df, left_on = 'Features', right_on = 'feature', how = 'left')
#Merging on Johnsons Percentages
merged_df = pd.merge(merged_df,johnsons_df, left_on = 'Features', right_on = 'Feature', how = 'left')
#Merging on Gini Index %
merged_df = pd.merge(merged_df,gini_index, left_on = 'Features', right_on = 'Feature', how = 'left')

#dropping redundant columns and setting the new index
merged_df.drop(columns=["Predictor", "Feature_x", "feature", "Feature_y", "Feature"], inplace=True)
merged_df.set_index('Features', inplace=True)
import seaborn as sns
import matplotlib.pyplot as plt 
from textwrap import wrap
column_aliases1 = {
    'Pearson_corr_%': 'Pearson Correlations',
    'SLC_Percent of Total': ' Regression Coeff.',
    'Shapley_percent_Total': 'Shapley Values',
    'Usefulness %': '"Usefulness"',
    'Johnsons Epsilon': "Johnson's Epsilon",
    'gini_percent': 'Decrease - RF Gini'
}

merged_df.rename(columns=column_aliases1, inplace=True)
print(merged_df)
# Creating the heatmap
plt.figure(figsize=(10, 8))
sns.heatmap(merged_df, annot=True, cmap='viridis', fmt=".2f")
plt.xticks(rotation=45)
plt.title('Key Driver Analysis: Feature Percentages')
plt.show()
           Pearson Correlations   Regression Coeff.  Shapley Values  \
Features                                                              
trust                      13.3                24.8            19.0   
build                      10.0                 4.3             2.8   
differs                     9.6                 6.3             6.8   
easy                       11.1                 4.7             4.0   
appealing                  10.8                 7.3             4.8   
rewarding                  10.1                 1.1             0.6   
popular                     8.9                 3.6             0.7   
service                    13.0                18.9            23.6   
impact                     13.2                29.1            37.7   

           "Usefulness"  Johnson's Epsilon  Decrease - RF Gini  
Features                                                        
trust             31.52              11.39                9.98  
build              1.02              11.37               11.81  
differs            2.10              16.98               11.39  
easy               1.10              12.90               11.82  
appealing          2.71               7.46               10.91  
rewarding          0.06               8.31               12.45  
popular            0.78              10.88               12.88  
service           17.87              13.37                9.61  
impact            42.83               7.34                9.15  

Above is the table recreation showing the importance scores for various features across different driver analysis methods, each normalized as percentages. These methods help us understand which features most significantly affect the predictive power of a model. We can review each column and identify the most important features as determined by each respective method.

  • Pearson Correlations: This column reflects the linear correlation between each feature and our target variable, satisfaction. Higher values indicate a stronger linear relationship. Features like trust, service, and impact show relatively high correlation, suggesting these are important in a linear sense.

  • Regression Coefficients: These scores are derived from a regression model, showing how much the target variable changes with a one-unit change in the feature, all else being equal. Impact, trust, and service, have higher coefficients, indicating significant influence on the model output.

  • Shapley Values: This method distributes the prediction value among the features, attributing the impact of each feature on the outcome of the model. Again, Impact, trust, and service score high, underscoring their importance in contributing to model predictions.

  • “Usefulness”: This value identifies impactful features via their respective change in the \(R^2\) value. Impact and trust show exceptionally high values, highlighting their critical role.

  • Johnson’s Epsilon: This metric likely measures the change in predictability when a feature is altered. “Differs”, “easy”, and “service” show higher values, suggesting these features significantly impact model predictability.

  • Decrease - RF Gini: Derived from Random Forests, this shows the decrease in node impurity (Gini index) brought by each feature. “Popular”, “rewarding”, and “easy” have higher values, indicating their utility in improving model decisions through increased purity in node splits.

Based on the heatmap and table created above, we see that there are three overall high impact features. Impact, trust, and service consistently show high importance across multiple metrics, suggesting they are crucial for accurate predictions. Features like easy, differs, and appealing exhibit moderate importance scores across various methods, indicating they play a secondary yet meaningful role in model predictions.Rewarding and popular, despite their roles, seem to have less influence compared to other features, particularly in metrics outside the Decrease - RF Gini. In this assignment, we were trying to recreate the table in slide 19. Despite not getting the exact same numbers, I did get the same ordering of important features.