A credit-risk team may have dozens of candidate variables but need an interpretable way to decide which distinguish borrowers who default from those who do not. Information value (IV) scores each variable’s separation of the two groups across its categories or bins. It supports feature screening; it does not, by itself, establish that a variable is safe or appropriate to use. section 4.4.3 section 5.3.4
First, calculate weight of evidence (WoE) for each bin: WoE = ln(BadRate / GoodRate), where each rate is the bin’s share of all bad or all good borrowers. Then sum the bin contributions: IV = Σ[(BadRate − GoodRate) × WoE]. Positive WoE marks a bin with relatively more bad borrowers; negative WoE marks a relatively safer bin. IV combines those differences into one score for the variable. section 4.4.3
For an inspectable credit-scoring workflow:
- Clean features, separate the outcome from candidate variables, and group categorical values or bin numeric values. One implementation fills numeric missing values with the median and uses up to ten quantile bins. section 5.3.3 section 5.2.3
- Calculate each bin’s WoE and IV contribution, then total IV by feature. Additive smoothing avoids zero-rate logarithms; clipping extreme WoE values limits numeric instability. section 5.3.3
- Review bin-level patterns and select candidates above a chosen IV threshold, such as 0.02. Retain bin boundaries and WoE mappings so selected raw features can be converted into WoE-coded inputs. section 5.3.3 section 5.3.4
Age-group screening
An age-group table contains good and bad borrower counts for five bins, from “<20” through “40+.” Dividing each count by its respective class total gives the rates used for WoE and each bin’s IV contribution. The resulting IV describes separation in this table, not whether age should enter a deployed decision. An unusually large IV—above 0.5 in the cited rule of thumb—calls for checks for leakage, overfitting, or hidden bias. section 4.4.3
Listing 4.3 Understand WoE and IV with data
import numpy as np
import pandas as pd
data = {
'AgeGroup': ['<20', '20-24', '25-29', '30-39', '40+'],
'GoodCount': [90, 120, 160, 300, 280],
'BadCount': [10, 30, 40, 25, 5]
} #1
df_bins = pd.DataFrame(data)
total_good = df_bins['GoodCount'].sum()
total_bad = df_bins['BadCount'].sum() #2
df_bins['GoodRate'] = df_bins['GoodCount'] / total_good
df_bins['BadRate'] = df_bins['BadCount'] / total_bad #3
df_bins['WoE'] = np.log(
(df_bins['BadRate'] + 1e-9) / (df_bins['GoodRate'] + 1e-9)
) #4
df_bins['IV_bin'] = (
(df_bins['BadRate'] - df_bins['GoodRate']) * df_bins['WoE']
)
IV_age = df_bins['IV_bin'].sum() #5
print(df_bins[['AgeGroup','GoodCount','BadCount','WoE','IV_bin']])
print(f"Information Value (Age) = {IV_age:.4f}")
The NumPy and pandas listing exposes the class totals, bin rates, WoE, per-bin contributions, and final age-variable IV for direct inspection. section 4.4.3
Treat IV as a screening signal alongside bin behavior and governance checks. Low-IV variables may be dropped; stronger candidates still need scrutiny if their WoE pattern is inconsistent or their separation looks suspiciously strong. In a larger pipeline, WoE-coded selected features can feed a baseline XGBoost model, while interpretability, compliance, and monitoring remain separate concerns. section 4.4.3 section 5.2.3
Listing 5.12 Combining numeric/categorical
feature_list = num_cols_sample + cat_features
if target_col in feature_list:
feature_list.remove(target_col)
woe_result, selected_feats, bin_edges, woe_maps = calculate_woe_iv(
df, feature_list, cat_features, target=target_col, iv_threshold=0.02
)
print("Total features in feature_list:", len(feature_list))
print("Selected features (IV>=0.02):", len(selected_feats), selected_feats)
display(woe_result.head(10))
The feature-selection call shows how numeric and categorical candidates enter the calculation, how the outcome is excluded, and how selected features and mappings are checked. section 5.3.4
