← Back to list

Opening the Black Box (Qara Qutu): Explaining Telecom Churn (Telecom Müştəri İtkisini İzah…

📎 Bu bloqdakı kod və analizlər üçün GitHub repo: Opening the Black Box — Clean

Riyad Ahmadov · 2026-05-31 18:00 · 0 claps · 15.1 min read
#machine-learning #xai #explainable-ai #shap #churn
Open on Medium ↗
Wiki topics: ML · Machine Learning EDU · Education & Learning GRW · Growth & Analytics 🔓 · Open Source

Opening the Black Box (Qara Qutu): Explaining Telecom Churn (Telecom Müştəri İtkisini İzah Etmək)(AZ)

📎 Bu bloqdakı kod və analizlər üçün GitHub repo: **Opening the Black Box — Clean**

1. Giriş

Əvvəlcə churn prosesinin nə qədər ciddi olduğunu anlayaq. Axı bir biznes istifadəçilər üzərində qurulur. Müştərilər dövriyyə prosesine qoşulmursa, biznes davamlı ola bilməz. Müştəri itkisi (churn) telekommunikasiya şirkətlərindəki ən vacib biznes problemlərindən biridir. Mövcud bir müştərini saxlamaq yeni birini əldə etməkdən çox daha ucuzdur — bu da churn proqnozlaşdırmasını yüksək dəyərli bir maşın öyrənməsi tapşırığına çevirir.

Bəzən hibrid yanaşma tətbiq edib xərc analizi də edə bilərik. Beləliklə, churnu düzgün oxumaq və təhlil etmək xidmətimizdə irəliləyiş etməyimizə kömək edir.

Lakin böyük bir problem var:

Yüksək dəqiqlikli churn proqnoz modelləri qura bilirik — amma çox vaxt müştərinin niyə getməyinin proqnozlaşdırıldığını izah edə bilmirik.

Məsələ budur ki model qururuq, proqnozlar veririk, bəzən problemləri həll edə bilirik. Amma əsas məsələ texniki olaraq model qurmaq yox, onu interpret etməkdir.

Bu, maşın öyrənməsindəki klassik qara qutu problemidir. Çünki model n şərt yoxlayır — bunların neçəsini digər maraqlı tərəflərə çatdırmalıyıq? Yaxud özümüz prosesi biznes yönümlü şəkildə necə anlayırıq?

Bu bloqda SHAP, LIME, PDPICE kimi İzah Edilə Bilən Süni İntellekt (XAI) texnikalarından istifadə edərək qara qutu modellərdən interpretasiya edilə bilən fikirlərə necə keçəcəyimizi araşdıracağıq.

3. Churn Proqnoz Modeli Qurmaq

Bu hissə standart bir data scientist-in əlifbasıdır.

Bu problemi həll etmək üçün adətən aşağıdakı kimi maşın öyrənməsi modelləri istifadə edirik:

  • Random Forest
  • XGBoost
  • LightGBM

Model bir ehtimal verir:

“Bu müştərinin churn etmə ehtimalı 0.82-dir”

Performans aşağıdakı kimi metriklərlə qiymətləndirilir:

  • AUC-ROC
  • F1-score
  • Precision / Recall

Bu mərhələdə model yaxşı işləyir — amma qara qutu kimi davranır. Hər şey bu vaxta qədər aydındır, lakin sual verə bilərik: Model niyə 0.82 skoru verdi? Yəni bu dəyərin yaranmasına hansı amillər töhfə verdi?

Məlumatlar dünyasında bir şeyi ölçə və təhlil edə bilmiriksə, onu yaxşılaşdıra bilmərik. Bunun üçün modeli interpret etməliyik.

4. Qara Qutu Problemi

Kompleks modellər yüksək dəqiqlik təmin etsə də, şəffaflıqdan məhrumdur. Şirkətlər çox vaxt daha izah edilə bilən sadə modellər istifadə edir.

Belə suallarla üzləşirik:

  • Bu müştəri niyə riskdədir? Model niyə churn proqnoz etdi, ya da 0.82 nəticəsinə gəldi?
  • Proqnozu hansı xüsusiyyətlər nə qədər təsir etdi?
  • Modelin qərarinə güvənə bilərikmi?

Bu izah edilməmiş şeylər biznesə adaptasiyanın qarşısındakı əsas maneədir. Bunu həll etmək üçün İzah Edilə Bilən Süni İntellekt (XAI) texnikalarından istifadə edirik.

5. Qara Qutu İzah Metodları Bütün Model Tiplərinə Tətbiq Edilə Bilərmi?

Qara qutu çıxarsama metodları (məs. SHAP, LIME, PDP və ICE) ümumiyyətlə model-agnostic-dir — yəni daxili strukturundan asılı olmayaraq geniş çeşidli maşın öyrənməsi modellərinə tətbiq oluna bilər.

Praktikada bu metodlar aşağıdakılarla istifadə edilə bilər:

  • Xətti modellər (məs. Logistic Regression)
  • Ağac əsaslı modellər (məs. Random Forest, XGBoost, LightGBM)
  • Dəstək Vektor Maşınları (SVM)
  • Neyron Şəbəkələri

Lakin geniş istifadə olunmalarına baxmayaraq, onların effektivliyi, dəqiqliyi və hesablama xərci model tipindən asılı olaraq dəyişir.

Müəyyən alqoritmlər üçün nəzərdə tutulmuş model-spesifik çıxarsama metodları da mövcuddur. Məsələn:

  • Tree SHAP ağac əsaslı modellər üçün optimallaşdırılıb və hesablama cəhətindən effektivdir.
  • Gradient əsaslı çıxarsama metodları əsasən neyron şəbəkələri üçün istifadə olunur.
  • Xətti modellər əmsallardan istifadə edərək birbaşa interpret edilə bilər.

Buna qarşılıq, Kernel SHAP və LIME kimi ümumi metodlar demək olar ki bütün model tiplərində işləyir, lakin hesablama baxımından baha başa gələ bilər və təxmin səs-küyü yarada bilər.

Xülasə: Qara qutu interpretasiya metodları əksər modellərə tətbiq edilə bilər, lakin metodun seçimi model arxitekturasına və interpretasiya edilə bilmə, sürət, dəqiqlik arasındakı mübadilə əlaqəsinə görə müəyyənləşdirilməlidir.

6. Qlobal Model İnterpretasiyası

Qlobal interpretasiya metodları müştəri churn proqnoz modelinin bütün telekom müştəri bazası üzərindəki davranışını anlamağa kömək edir.

Bu fikirlər müştəri churn analizində xüsusilə vacibdir, çünki yalnız fərdi proqnozlar deyil, müştəri davranışının sistematik nümunələrini müəyyən etməyə imkan verir.

6.1 Feature Importance (Qlobal)

Model ümumi olaraq hansı feature-lara daha çox güvənir?

  • Built-in Feature Importance (Ağac əsaslı)
  • Permutation Importance
  • Gain / Split Importance (XGBoost, LightGBM)

Feature importance müştəri churnunu proqnozlaşdırmada ən güclü təsirə malik dəyişənləri müəyyən etməyə kömək edir.

Bu telekommunikasiya datasetindəki tipik əsas amillər adətən aşağıdakılarla bağlıdır:

  • İstifadə Davranışı: Aylıq Dəqiqələr, Limit Aşım Dəqiqələri, Rouminq Zəngləri
  • Gəlir Nümunələri: Aylıq Gəlir, Ümumi Dövri Ödəniş, PercChangeRevenue
  • Xidmət Problemləri: Düşən Zənglər, Bloklanmış Zənglər, Cavabsız Zənglər, Müştəri Xidməti Zəngləri
  • Engagement Səviyyəsi: MonthlyInService, Aktiv Abunəçilər, Unikal Abunəçilər
  • Müştəri Profili: Gəlir Qrupu, Kredit Reytinqi, Ev Mülkiyyəti, Uşaqlı Ailələr

Bu xüsusiyyətlər abunəçi churnunun daha çox xərc həssaslığı, xidmət keyfiyyəti problemləri, yoxsa müştəri həyat dövrü mərhələsi ilə bağlı olduğunu anlamağa kömək edir.

feature_importance = pd.DataFrame({
    "feature": MODEL_FEATURES,
    "importance": gb_model.feature_importances_
})
feature_importance = feature_importance.sort_values(by="importance", ascending=False)
feature_importance

⚠️ Built-in Feature Importance-da Kardinallıq Problemi

Feature importance ilkin fikir üçün yaxşı ola bilər, amma peşəkar mühitdə problemləri var — yalnız ağac əsaslı modellərdə istifadə edilir və kardinallıq riski mövcuddur.

Kardinallıq = feature-in neçə unikal dəyəri olduğu

Feature Kardinallıq Gender 2 dəyər (aşağı) Country 50 dəyər UserID 100,000 dəyər (yüksək 😄)

Risk nədir? Ağac əsaslı modellər (GB, RF və s.) feature importance-ı split-lər (Gini / MSE gain) əsasında hesablayır. Çox unikal dəyəri olan feature-in daha çox split imkanı olur — bu da onun əhəmiyyətini süni şəkildə şişirdir.

Niyə belə olur?

Ağac belə işləyir: hər feature üçün müxtəlif threshold-lar yoxlayır və ən yaxşı split-i seçir. Əgər feature-də çox fərqli dəyər varsa, daha çox “variant” olur — bu da təsadüfən yaxşı split tapmaq ehtimalını artırır.

✅ Həll 1: Permutation Importance

Permutation Importance real performans düşüşünü ölçür — kardinallıq biası yoxdur və bütün model tipləri ilə işləyir.

from sklearn.inspection import permutation_importance
result = permutation_importance(
    gb_model,
    X_test,
    y_test,
    n_repeats=10,
    random_state=42,
    scoring="recall"  # maksimum etmək istədiyiniz metrik (roc_auc, accuracy)
)
perm_importance = pd.DataFrame({
    "feature": MODEL_FEATURES,
    "importance_mean": result.importances_mean,
    "importance_std": result.importances_std
})
perm_importance = perm_importance.sort_values(
    by="importance_mean", ascending=False
)
perm_importance.head(10)

**importance_meanimportance_std nəyi bildirir?**

Metrik Mənası importance_mean Feature-in orta təsiri — "bu feature model performansını orta hesabla nə qədər pisləşdirir?" importance_std Həmin ölçmələrin standart sapması — "bu feature-in təsiri nə qədər stabildir?"

Birlikdə necə interpretasiya etmək olar:

Hal Mean Std Nəticə ✅ Yaxşı feature Yüksək Aşağı Vacib və stabil ⚠️ Riskli feature Yüksək Yüksək Bəzən vacib, bəzən yox — qeyri-stabil ❌ Lazımsız feature ≈ 0 ya mənfi İstənilən Lazım deyil; hətta noise ola bilər

“Mən yalnız importance_mean-ə deyil, importance_std-ə də baxıram. Yüksək mean ilə aşağı std daima vacib feature-i göstərir, yüksək variance isə modelin həmin feature-ə güvənməsindəki qeyri-stabilliyə işarədir.”

Geniş yayılmış yanaşma:

def classify_feature(row):
    score = row['importance_mean'] - 2 * row['importance_std']
    if score > 0:
        return 'Vacib Feature'
    elif score > -0.01:
        return 'Sərhəddə'
    else:
        return 'Vacib Deyil'
perm_importance['feature_tipi'] = perm_importance.apply(classify_feature, axis=1)
  • > 0 → feature həqiqətən vacibdir
  • ≈ 0 → sərhəddə
  • < 0 → güvənmə

✅ Həll 2: Gain / Split Importance

Bu metodlar əsasən XGBoostLightGBM modellərində istifadə olunur.

İki əsas növ:

  • Gain Importance — Feature modeldə hər split-də neçə qazanc (gain) əldə edir? Xəta azalmalarının cəmidir.
  • Split Importance — Feature neçə dəfə istifadə olunub?
import lightgbm as lgb
model = lgb.LGBMClassifier()
model.fit(X_train, y_train)
# Gain
model.booster_.feature_importance(importance_type='gain')
# Split
model.booster_.feature_importance(importance_type='split')

⚠️ Risklər (çox vacib):

  1. Kardinallıq biası (yenə var 😄) — yüksək kardinallıqlı feature-lər daha çox split şansı əldə edir
  2. Overfitting riski — model noise-u da “gain” kimi görə bilər
  3. Korrelyasiyalı feature-lər problemi — importance bölünür, real təsirlər gizlənə bilər

Model uyğunluğu xülasəsi:

Metod Hansı Modellərlə İşləyir feature_importances_ Yalnız ağac əsaslı modellər (GB, RF, DT) Permutation Importance ✅ BÜTÜN modellər (model-agnostic) Gain / Split Yalnız XGBoost, LightGBM

2. Lokal İzah Metodları

Tək-tək müşahidələr üçün izah verir

  • SHAP
  • LIME
  • Anchors (Anchor LIME)
  • Break Down Plotlar (DALEX)
  • Kontrafaktual İzahlar

SHAP (SHapley Additive exPlanations)

SHAP oyun nəzəriyyəsindən gələn Shapley Dəyərləri ideyasına əsaslanır.

“Hər feature modelin proqnozuna nə qədər və hansı istiqamətdə təsir edir?”

İntuisiya (çox vacib):

Modelin belə bir proqnoz verdiyini düşün:

Churn ehtimalı = 0.82

SHAP deyir:

MonthlyCharges       +0.25
Tenure               -0.30
Complaints           +0.20

Nəticə: baseline-ın final proqnoza necə dəyişdiyi tam görünür.

SHAP niyə güclüdür?

Metod Zəif cəhəti Tree importance Bias (kardinallıq) Permutation Yalnız qlobal SHAP ✅ Lokal + Qlobal + Ədalətli atribusiya

SHAP-ın 3 əsas səviyyəsi:

  1. Lokal izah — Bir müştəri niyə churn edir?
  2. Qlobal importance — Hansı feature ümumilikdə vacibdir?
  3. İnteraksiya — Feature-lər bir-birinə necə təsir edir?

Kod (ağac modellər üçün ən rahat variant):

import shap
explainer = shap.TreeExplainer(gb_model)
shap_values = explainer.shap_values(X_test)

Qlobal feature importance:

shap.summary_plot(shap_values, X_test)

Bar plot (sadə importance):

shap.summary_plot(shap_values, X_test, plot_type="bar")

Tək proqnozun izahı:

shap.plots.force(
    explainer.expected_value,
    shap_values[0],
    X_test.iloc[0],
    matplotlib=True
)

Modelin proqnozu necə formalaşdı:

base value → feature-lərin təsiri → final proqnoz (f(x))

  • Base value ≈ -1 (təxmini): modelin orta proqnozu (heç bir feature təsiri olmadan)
  • Final proqnoz (f(x)) = 1.36: bu konkret müştəri üçün churn skoru (log-odds)

Rənglərin mənası:

  • 🔴 QIRMIZI (sağa itələyir) → churn ehtimalını artırır (məs. TotalRecurringCharge, UnansweredCalls, PercChangeMinutes, CurrentEquipmentDays)
  • 🔵 MAVİ (sola çəkir) → churn ehtimalını azaldır (məs. MonthlyRevenue, OverageMinutes, EngagementScore)

Oxuma qaydası (ən vacib hissə):

Base value → qırmızı təsirlər (+) → mavi təsirlər (-) → final

Real interpretasiya (biznes dili ilə):

Bu müştərinin:

Churn riskini artıran amillər:

  • Çox cavabsız zənglər 📞
  • Gəlir/ödəniş ilə bağlı davranış
  • İstifadə dəyişiklikləri (PercChangeMinutes)
  • Cihazdan uzun istifadə (cihaz köhnəlməsi)

Saxlayan amillər:

  • MonthlyRevenue yaxşıdır
  • EngagementScore mövcuddur

Qırmızı hissə daha dominantdır — ona görə final skor ↑ (1.36). Bu log-odds-dur, ehtimal deyil.

Log-odds-u ehtimala çevirmək:

import numpy as np
prob = 1 / (1 + np.exp(-1.36))
# ≈ 0.79 (79% churn ehtimalı)

SHAP Feature İnteraksiyası

shap_interaction_values = explainer.shap_interaction_values(X_test)
shap.dependence_plot(
    "MonthlyRevenue",
    shap_values,
    X_test,
    interaction_index="OverageMinutes"
)

shap.summary_plot(shap_interaction_values, X_test)

SHAP interaksiya dəyəri nədir?

İnteraksiya(i,j) = birlikdə təsir − tək-tək təsirlərin cəmi

SHAP parçalanma formulu:

[ f(x) = \phi_0 + \sum_i \phii + \sum{i \neq j} \phi_{i,j} ]

Burada:

  • (\phi_0) — modelin baza (expected) dəyəri,
  • (\phi_i) — xüsusiyyət (i)-nin fərdi töhfəsi (klassik SHAP dəyəri),
  • (\phi_{i,j}) — xüsusiyyətlər (i) və (j) arasındakı qarşılıqlı təsirin (interaction effect) model proqnozuna töhfəsi.

Vacib: Binary klassifikasiya (ağac modellər) üçün SHAP dəyərləri log-odds məkanındadır. İnteraksiya dəyərlərini ayrı-ayrılıqda ehtimala çevirmək riyazi cəhətdən düzgün deyil — bunlar tam proqnoz deyil, parçalanma hissələridir.

📝 SHAP Xülasəsi

Hər müşahidə üçün:

f(x) = \text{base value} + \sum_i \text{SHAP}_i

  • base value → modelin orta çıxışı (baseline)
  • SHAP_i → hər feature-in töhfəsi (log-odds məkanında)
  • SHAP dəyərləri additive-dir (toplanır)
  • Cəm + base = həmin müşahidə üçün modelin proqnozu

Ehtimala çevirmə:

p = \frac{1}{1 + e^{-f(x)}}

LIME (Local Interpretable Model-agnostic Explanations)

LIME lokal, sadə və model-agnostic bir yanaşmadır — SHAP-dan fərqlidir.

LIME-ın prosesi:

  1. Seçilmiş müşahidənin ətrafında sintetik data yaradır
  2. Bu data üçün modeldən proqnozlar alır
  3. Lokal olaraq sadə model (xətti) qurur
  4. Feature təsirlərini bu sadə modeldən çıxarır

SHAP vs LIME sürətli müqayisəsi:

SHAP LIME Məntiq Oyun nəzəriyyəsi Lokal approximasiya Additive ✔️ ❌ Stabil ✔️ ❌ (randomness var) Sürət Yavaş Daha sürətli İnterpretasiya Qlobal + Lokal Əsasən lokal

from lime.lime_tabular import LimeTabularExplainer
explainer = LimeTabularExplainer(
    training_data=X_train.values,
    feature_names=X_train.columns,
    class_names=["Churn Yox", "Churn"],
    mode="classification",
    random_state=42
)
i = 8
exp = explainer.explain_instance(
    X_test.iloc[i].values,
    gb_model.predict_proba
)
exp.show_in_notebook()

exp.as_list()
[('UniqueSubs > 2.00', 0.10605896096358468),
 ('CustomerCareCalls <= 0.00', -0.10250055687644855),
 ('EngagementScore <= 0.30', -0.06242044671597925),
 ('9.00 < OverageMinutes <= 58.00', -0.06082789535048463),
 ('ThreewayCalls <= 0.00', -0.05182252581603148),
 ('DroppedRate <= 0.45', 0.04771709185868194),
 ('AdjustmentsToCreditRating <= 0.00', -0.03412738143515103),
 ('-4.00 < PercChangeMinutes <= 91.00', -0.03282782362264516),
 ('ActiveSubs > 2.00', 0.03266618052017554),
 ('UnansweredCalls <= 9.30', 0.02314095984467555)]

LIME model-agnostic-dir — sadəcə predict_proba() çağırdığı üçün istənilən modellə (XGBoost, Neural Network, Random Forest, Blackbox API) işləyir.

Nəticələri stabilləşdirmək üçün:

exp = explainer.explain_instance(
    X_test.iloc[i].values,
    gb_model.predict_proba,
    num_features=10
)
# Hansı class-ın izah olunduğunu yoxla
exp.available_labels()
# [1]  → Churn class-ı izah olunur
exp.as_pyplot_figure()

Anchors (Anchor LIME)

Anchors LIME-ın inkişaf etmiş versiyasıdır.

“Modelin proqnozunu dəyişməmək üçün hansı şərtlər sabit qalmalıdır?”

  • LIME deyir: “Feature A +0.3 təsir etdi”
  • Anchors deyir: “OverageMinutes > 100 VƏ Contract = Monthly şərtləri qalırsa, model böyük ehtimalla yenə churn deyəcək”

“Anchor” proqnozu sabit saxlayan qaydadır.

LIME vs Anchors:

LIME Anchors Çıxış Feature töhfəsi ƏGƏR-ONDA qaydası Sabitlik Orta Daha yüksək İnsan üçün oxunaqlılıq Orta Çox yüksək Lokal ✔️ ✔️

from alibi.explainers import AnchorTabular
explainer = AnchorTabular(
    predictor=gb_model.predict,
    feature_names=X_train.columns.tolist()
)
explainer.fit(X_train.values)
i = 8
explanation = explainer.explain(
    X_test.iloc[i].values
)
# Qaydanı göstər
print(explanation.anchor)
# ['OverageMinutes > 100', 'MonthlyRevenue > 80']
# Precision
print(explanation.precision)
# 0.95  → bu qayda qaldıqda proqnoz 95% hallarda dəyişmir
# Coverage
print(explanation.coverage)
# 0.1117  → müşahidələrin ~11%-i bu qaydaya uyğundur

Real biznes istifadə halları: Fırıldaq aşkarlanması, kredit skoru, tibbi AI (qayda əsaslı izahlar üstünlük verilir).

Məhdudiyyətlər: Hesablama baxımından baha başa gələ bilər; yüksək ölçülü datada çətinləşir; hələ də lokal izahdır.

Break Down Plotlar (DALEX)

Breakdown plotlar qara qutu modellər üçün lokal izah metodudur. SHAP-a bənzəyir, amma daha “additive addım-addım” vizuallaşdırma göstərir.

Breakdown plot nə edir?

  1. Modelin baseline-ından (orta proqnoz) başlayır
  2. Hər feature ardıcıl olaraq nəticəyə təsir edir
  3. Modelin final çıxışını göstərir

Nümunə:

Base value:            0.35
MonthlyRevenue    →   +0.10
CustomerCareCalls →   +0.20
MonthsInService   →   -0.05
…
Final:                 0.78

DALEX vs SHAP:

SHAP Breakdown Tip Oyun nəzəriyyəsi Addım-addım Sıra Simmetrik Sıra vacibdir Hesablama Daha ağır Daha sadə İstifadə halı Dəqiq atribusiya Sürətli izah

import dalex as dx
explainer = dx.Explainer(
    model=gb_model,
    data=X_train,
    y=y_train,
    label="Gradient Boosting",
    predict_function=lambda m, d: m.predict_proba(d)[:, 1]
)
single_obs = X_test.iloc[[0]]
bd = explainer.predict_parts(
    single_obs,
    type='break_down'
)
bd.plot()

Vacib: Klassifikatorlar üçün predict() əvəzinə predict_proba istifadə etmək daha yaxşıdır — ehtimal əsaslı breakdown daha mənalıdır.

Kontrafaktual İzahlar

“Proqnozun dəyişməsi üçün minimum nə dəyişməlidir?”

Real həyat nümunəsi (Kredit modeli):

  • Model: Kredit Rədd Edildi
  • Kontrafaktual: “Maaşınız +500 AZN çox olsaydı VƏ borcunuz 10% az olsaydı, kredit təsdiq olunardı”

Kontrafaktual niyə güclüdür?

  • Actionable — nəyi dəyişmək lazım olduğunu deyir
  • Biznes dostu — çatdırması asandır
  • İnsan dilinə yaxındır

SHAP vs Kontrafaktual:

SHAP Kontrafaktual Sual Niyə? Necə dəyişmək olar? Tip İzah Actionable Fokus Keçmiş Gələcək

Ən populyar kitabxana: DiCE

pip install dice-ml
import dice_ml
from dice_ml import Dice
# Addım 1: Data obyekti
data_dice = dice_ml.Data(
    dataframe=df,
    continuous_features=[
        'MonthlyRevenue',
        'CustomerCareCalls',
        'MonthsInService'
    ],
    outcome_name='Churn'
)
# Addım 2: Model wrapper
model_dice = dice_ml.Model(
    model=gb_model,
    backend='sklearn'
)
# Addım 3: Dice explainer
exp = Dice(
    data_dice,
    model_dice,
    method='genetic'  # 'random', 'genetic', ya 'kdtree'
)
# Addım 4: Kontrafaktuallar yarat
query_instance = X_test.iloc[[0]]
cf = exp.generate_counterfactuals(
    query_instance,
    total_CFs=3,
    desired_class="opposite"
)
cf.visualize_as_dataframe()

Hansı feature-lərin dəyişə biləcəyini məhdudlaşdırmaq üçün:

cf = exp.generate_counterfactuals(
    query_instance,
    total_CFs=3,
    features_to_vary=[
        'MonthlyRevenue',
        'CustomerCareCalls'
    ],
    desired_class="opposite"
)

Geniş yayılmış xəta və səbəbləri:

No Counterfactuals found for the given configuration...

Səbəb İzah Dəyişməyə icazə verilən feature-lər az Model qərar sərhədi keçilmir GB model çox sərtdir Proqnoz dəyişmir Müşahidə çox ekstremal Yaxın kontrafaktual yoxdur Feature scaling problemi DiCE düzgün axtarış edə bilmir İstənilən class mümkün deyil Məs. artıq həmin class-dadır

⚠️ Vacib anlayış: Kontrafaktual bir izah deyil — recourse-dur. “Fərqli nəticə üçün nəyi dəyişmək lazımdır?” sualına cavab verir.

Real production istifadə halları: bank, sığorta, səhiyyə, HR xal sistemləri.

Məhdudiyyətlər:

  • Real olmayan dəyişikliklər ola bilər (məs. Yaş: 40 → 12)
  • Feature-lər arasındakı səbəb-nəticə əlaqələri nəzərə alınmır
  • Çoxlu etibarlı həll mövcud ola bilər

3. Qlobal İzah Metodları

Modelin ümumi davranışını izah edir

  • Partial Dependence Plot (PDP)
  • ICE (Individual Conditional Expectation)
  • ALE (Accumulated Local Effects)

Partial Dependence Plot (PDP)

“Bir feature dəyişəndə modelin proqnozu orta hesabla necə dəyişir?”

Modeldə bir feature seçirsən (məs. Gəlir), onu dəyişdirirsən, digər feature-ləri sabit saxlayırsan (ya da orta təsir götürülür). Sonra baxırsan: Gəlir artdıqca proqnoz artır, yoxsa azalır?

Nümunə (Kredit Təsdiqləmə modeli):

Gəlir Təsdiq Ehtimalı 2000 0.30 5000 0.60 10000 0.85

PDP nəticəsi: Gəlir artdıqca təsdiq artır.

⚠️ Feature-lər arasında korrelyasiya varsa PDP yanlış ola bilər — çünki real dünyada feature-lər müstəqil dəyişmir.

from sklearn.inspection import PartialDependenceDisplay
import matplotlib.pyplot as plt
features = ["OverageMinutes", "CurrentEquipmentDays"]
fig, ax = plt.subplots(figsize=(10, 6))
PartialDependenceDisplay.from_estimator(
    gb_model,
    X,
    features=features,
    kind='average',  # yalnız PDP (qlobal təsir, ICE xətləri yox)
    ax=ax
)
plt.suptitle("Partial Dependence Plot (PDP)")
plt.show()

Bu qrafikdən biznes fikri:

Müştərilərin tarif limitini az fərqlə (0–10 dəqiqə) keçməsi gözlənilməz xərclərə görə churn riskini kəskin şəkildə artırır, halbuki böyük limit aşımlarına malik müştərilərdə bu risk minimuma enir. Biznes olaraq bu kritik həddəki müştəriləri itirməmək üçün onlara limitə yaxınlaşdıqda xəbərdarlıq bildirişləri göndərmək və ya preventiv kiçik bonuslar təklif etmək lazımdır. Beləliklə, resursları düzgün hədəfləyərək kiçik toxunuşlarla böyük müştəri kütləsini qoruyub saxlamaq mümkündür.

ICE (Individual Conditional Expectation)

“Feature dəyişəndə model hər bir fərdi müşahidə üçün necə reaksiya verir?”

  • PDP → orta davranış
  • ICE → hər bir fərdin ayrı davranışı

ICE sənə deyir: “Model hamı üçün eyni davranır, yoxsa fərqli insanlar üçün fərqli reaksiya verir?”

from sklearn.inspection import PartialDependenceDisplay
import matplotlib.pyplot as plt
features = ["OverageMinutes"]
fig, ax = plt.subplots(figsize=(10, 6))
PartialDependenceDisplay.from_estimator(
    gb_model,
    X,
    features=features,
    kind='individual',  # ICE (ortalama yox, nümunə üzrə əyrilər)
    subsample=50,       # oxunaqlılıq üçün 50 nümunə göstər
    ax=ax
)
plt.suptitle("Individual Conditional Expectation (ICE) Plot")
plt.show()

Qrafikin interpretasiyası:

Demək olar ki bütün fərdi xətlər paralel hərəkət edir. Limit aşımı 0-dan 10 dəqiqəyə gedəndə xətlərin çoxu bir qədər dalğalanır (yuxarı qalxır ya kəskin enir), 15 dəqiqədən sonra isə hamısı birlikdə düzləşir.

Biznes mənası: Bu o deməkdir ki, modeldə güclü interaksiya yoxdur. Yəni limit aşımının təsiri müştəridən müştəriyə köklü şəkildə dəyişmir — kritik zona hamı üçün eynidir: ilk 10–15 dəqiqə.

Xətlərin qrafikin yuxarısından aşağısına qədər paylandığını görürük (bəziləri 0.9 səviyyəsindədir, bəziləri 0.3):

  • Yuxarıdakı xətlər (0.8–1.0): Bunlar limit aşımından asılı olmayaraq çox yüksək churn riski olan “həssas” müştərilərdir — bəlkə tarifi çox bahadır ya şəbəkə keyfiyyətindən narazıdırlar.
  • Aşağıdakı xətlər (0.3–0.5): Bu müştərilər daha sadiqdir. Limitlərini azca keçsələr belə, ümumi churn riski nisbətən aşağıda qalır.

0–10 dəqiqə aralığına diqqətlə baxanda hamının eyni cür davranmadığını görürük:

  • Həssas Reaksiya Verənlər: Bəzi xətlər 0-dan 5 dəqiqəyə keçəndə yuxarıya doğru sıçrayış edir. Həmin müştərilər üçün cüzi limit aşımı belə dözülməzdir.
  • Sakit Qarşılayanlar: Bəzi xətlər 0-dan 10 dəqiqəyə gedəndə birbaşa aşağı enir ya düz qalır. Bu müştərilər üçün kiçik aşım normaldır.

ALE (Accumulated Local Effects)

ALE daha etibarlı qlobal interpretasiya metodu — PDP-ə alternativdir.

“Feature dəyişəndə model lokal olaraq necə davranır?”

PDP-dən fərqli olaraq ALE:

  • Feature-ləri real data paylanması daxilində dəyişir
  • Korrelyasiya problemindən daha az təsirlənir

Qısa müqayisə:

  • PDP → “Feature hər yerdə dəyişsəydi nə olardı?”
  • ALE → “Real data aralığında nə baş verir?”

4. İnteraksiya və Əlaqə Analizi

Feature-lər bir-biri ilə necə işləyir?

Bu, model interpretasiyasında bir addım irəlidir — artıq tək feature-ləri deyil, feature-lərin bir-biri ilə necə işlədiyini analiz edirik.

SHAP İnteraksiya Dəyərləri

“İki feature birlikdə model çıxışına necə təsir edir?”

Formal tərif:

İnteraksiya(i,j) = birlikdə təsir − tək-tək təsirlərin cəmi
import shap
explainer = shap.TreeExplainer(gb_model)
# İnteraksiya dəyərləri (yavaş amma güclü)
shap_interaction_values = explainer.shap_interaction_values(X)

2D PDP

“İki feature birlikdə dəyişəndə proqnoz necə dəyişir?”

from sklearn.inspection import PartialDependenceDisplay
import matplotlib.pyplot as plt
features = [("OverageMinutes", "CurrentEquipmentDays")]
fig, ax = plt.subplots(figsize=(8, 6))
PartialDependenceDisplay.from_estimator(
    gb_model,
    X,
    features=features,
    kind="average",
    ax=ax
)
plt.suptitle("2D Partial Dependence Plot")
plt.show()

İnterpretasiya:

  • Rəng gradienti → proqnoz səviyyəsi
  • X və Y oxları → 2 feature
  • Qeyri-xətti sahələr → interaksiya mövcuddur

Feature İnteraksiya Istilik Xəritələri

“Hansı feature cütləri daha güclü interaksiya yaradır?”

import seaborn as sns
import numpy as np
# Korrelyasiya matrisi (interaksiya üçün proxy)
corr = X.corr()
plt.figure(figsize=(8,6))
sns.heatmap(corr, annot=True, cmap="coolwarm")
plt.title("Feature Korrelyasiya Istilik Xəritəsi")
plt.show()

Qeyd: Bu korrelyasiya göstərir, həqiqi interaksiya deyil. Həqiqi interaksiyalar üçün SHAP interaksiya matrisindən istifadə edin.

5. Model-Agnostic vs Model-Specific

Model-Agnostic (İstənilən Modelə Tətbiq Oluna Bilər)

“Modelin daxilini bilmirik, amma davranışını analiz edə bilərik.”

Kernel SHAP

İstənilən model üçün SHAP izahları verir. Oyun nəzəriyyəsi prinsipinə əsaslanır.

import shap
# KernelExplainer (model-agnostic)
explainer = shap.KernelExplainer(gb_model.predict, X.sample(100))
# SHAP dəyərləri
shap_values = explainer.shap_values(X.sample(50))
# Plot
shap.summary_plot(shap_values, X.sample(50))

Qeyd: Çox yavaşdır (O(n²)) — böyük datasetlər üçün ideal deyil.

LIME

import lime
import lime.lime_tabular
explainer = lime.lime_tabular.LimeTabularExplainer(
    X.values,
    feature_names=X.columns,
    mode="regression"
)
exp = explainer.explain_instance(
    X.iloc[0].values,
    gb_model.predict
)
exp.show_in_notebook()

PDP / ICE / ALE

  • PDP — Qlobal orta təsir
  • ICE — Fərdi davranış
  • ALE — Lokal real dünya təsiri

Model-Specific

Tree SHAP

Yalnız ağac əsaslı modellər üçün optimallaşdırılmış SHAP versiyası (Random Forest, XGBoost, LightGBM, CatBoost).

import shap
# Ağac əsaslı modellər üçün optimallaşdırılmış SHAP
explainer = shap.TreeExplainer(gb_model)
# SHAP dəyərləri
shap_values = explainer.shap_values(X)

Üstünlükləri: Çox sürətli, dəqiq hesablamalar, böyük dataset dostu.

Gain / Split Importance

import xgboost as xgb
xgb.plot_importance(gb_model, importance_type="gain")

İnterpretasiya:

  • Yüksək Gain → feature güclüdür
  • Çox Split → feature tez-tez istifadə olunur

DeepLIFT (Dərin Öyrənmə)

Dərin öyrənmə modelləri üçün atribusiya metodu. Çıxış dəyişikliklərini müraciət inputla müqayisə edir.

import deeplift
from deeplift.conversion import kerasapi_conversion as kc
# model çevrilməsi
deeplift_model = kc.convert_model_from_saved_files("model.h5")
# atribusiya skorları
scores = deeplift_model.get_target_contribs_func()

Qeyd: CNN / RNN üçün istifadə olunur — klassik ML üçün deyil.

Model-Agnostic vs Model-Specific xülasəsi:

Metod Modelin içinə baxır? Model-agnostic? LIME ❌ ✔️ Kernel SHAP ❌ ✔️ Tree SHAP ✔️ ❌

6. Vizuallaşdırma Əsaslı Alətlər

Metod Tip Fokus SHAP Summary Qlobal Feature importance SHAP Force Lokal Tək proqnoz PDP Qlobal Orta təsir ICE Lokal Fərdi davranış ALE Qlobal+Lokal Real dünya təsiri

1. SHAP Summary Plot (Qlobal Importance)

Nəyi göstərir: Feature importance sıralaması, təsirin paylanması, təsir istiqaməti.

Fikir: “Model ən çox hansı feature-lara güvənir?”

2. SHAP Force Plot (Lokal İzah)

Nəyi göstərir: Base value (orta proqnoz), feature töhfələri, final proqnoz.

Fikir: “Konkret bir müştərinin niyə riskli ya risksiz olduğunu göstərir”

3. PDP Plot (Qlobal Trend)

Nəyi göstərir: Orta model reaksiyası, feature → proqnoz əlaqəsi.

Fikir: “Feature artdıqca model nə edir?”

4. ICE Plot (Fərdi Davranış)

Nəyi göstərir: Fərdi proqnoz əyriləri, model davranışında heterogenllik.

Fikir: “Model hamı üçün eyni davranır, yoxsa fərqli?”

5. ALE Plot (Real Dünya Təsirləri)

Nəyi göstərir: Lokal təsirlər, korrelyasiyadan qorunan interpretasiya.

Fikir: “Model real data davranışını necə öyrənib?”

Yekun Fikirlər

Vizuallaşdırma əsaslı interpretasiya alətləri kompleks maşın öyrənməsi modellərini intuitiv qrafik fikirlərə çevirir — model davranışını həm texniki, həm də qeyri-texniki auditoriya üçün şəffaf edir.

Qara qutu churn proqnoz modelindən actionable biznes fikirlərinə gedən yolda bir neçə XAI texnikasını birləşdirmək lazımdır:

  • Riyazi cəhətdən əsaslandırılmış atribusiya üçün həm qlobal, həm lokal izahlarda SHAP istifadə edin
  • Sürətli, model-agnostic lokal izahlar üçün LIME istifadə edin
  • Maraqlı tərəflər üçün qayda əsaslı izahlara ehtiyac olduqda Anchors istifadə edin
  • Fərdi feature-lərin qlobal proqnozlara təsirini anlamaq üçün PDP/ICE/ALE istifadə edin
  • Actionable tövsiyələrə ehtiyac olduqda Kontrafaktuallar istifadə edin (“nəyi dəyişmək lazımdır?”)
  • Fərdi proqnozların addım-addım parçalanması üçün DALEX Breakdown istifadə edin

Hər metodun güclü cəhətləri və kompromisləri var. Ən yaxşı yanaşma auditoriyaya və cavab axtardığınız konkret suala əsasən onları birləşdirməkdir.

Etiketlər: #MaşınÖyrənməsi #XAI #İzahEdilənSüniİntellekt #SHAP #LIME #Churn #Telekom #DataElmi


메타데이터
post_id
1f9925520c0c
slug
opening-the-black-box-qara-qutu-explaining-telecom-churn-telecom-müştəri-i̇tkisini-i̇zah-1f9925520c0c
url
https://medium.com/@riyadahmadov/opening-the-black-box-qara-qutu-explaining-telecom-churn-telecom-m%C3%BC%C5%9Ft%C9%99ri-i%CC%87tkisini-i%CC%87zah-1f9925520c0c
canonical_url
https://medium.com/@riyadahmadov/opening-the-black-box-qara-qutu-explaining-telecom-churn-telecom-m%C3%BC%C5%9Ft%C9%99ri-i%CC%87tkisini-i%CC%87zah-1f9925520c0c
author_url
https://medium.com/@riyadahmadov
status
ok
fetched_at
2026-06-09 15:37:30