omarcevi commited on
Commit
24d09a0
·
verified ·
1 Parent(s): fff67c0

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ Churn[[:space:]]oluyor[[:space:]]mu[[:space:]]kontrol.xlsx filter=lfs diff=lfs merge=lfs -text
Churn oluyor mu kontrol.xlsx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cf0d3660e7db1da712247599d74c880a8f80a727b000b90ec5cdbfdd98950564
3
+ size 783308
Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use official Python image
2
+ FROM python:3.10-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Copy requirements and source code
8
+ COPY requirements.txt ./
9
+ COPY gradio_app.py ./
10
+ COPY churn_model.pkl ./
11
+ COPY model_features.pkl ./
12
+ COPY Telco-Customer-Churn.csv ./
13
+
14
+ # Install dependencies
15
+ RUN pip install --no-cache-dir -r requirements.txt
16
+
17
+ # Expose Gradio default port
18
+ EXPOSE 7860
19
+
20
+ # Run the Gradio app
21
+ CMD ["python", "gradio_app.py"]
README.md CHANGED
@@ -1,12 +1,6 @@
1
  ---
2
- title: Gradio App
3
- emoji: 🦀
4
- colorFrom: pink
5
- colorTo: yellow
6
  sdk: gradio
7
  sdk_version: 5.31.0
8
- app_file: app.py
9
- pinned: false
10
  ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: gradio-app
3
+ app_file: gradio_app.py
 
 
4
  sdk: gradio
5
  sdk_version: 5.31.0
 
 
6
  ---
 
 
Telco-Customer-Churn.csv ADDED
The diff for this file is too large to render. See raw diff
 
app.py ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request
2
+ import joblib
3
+ import pandas as pd
4
+
5
+ app = Flask(__name__)
6
+
7
+ model = joblib.load("churn_model.pkl")
8
+ model_features = joblib.load("model_features.pkl")
9
+
10
+ value_map = {
11
+ "Aydan aya": "Month-to-month",
12
+ "1 yıllık": "One year",
13
+ "2 yıllık": "Two year",
14
+ "Elektronik çek": "Electronic check",
15
+ "Posta çeki": "Mailed check",
16
+ "Banka havalesi (otomatik)": "Bank transfer (automatic)",
17
+ "Kredi kartı (otomatik)": "Credit card (automatic)",
18
+ "Hayır": "No",
19
+ "Evet": "Yes",
20
+ "Yok": "No internet service",
21
+ "Telefon hizmeti yok": "No phone service",
22
+ "Fiber optik": "Fiber optic"
23
+ }
24
+
25
+ @app.route("/", methods=["GET", "POST"])
26
+ def index():
27
+ result = None
28
+
29
+ if request.method == "POST":
30
+ form = request.form
31
+ input_dict = {}
32
+
33
+ # Sayısal alanlar
34
+ tenure = float(form.get("tenure"))
35
+ monthly = float(form.get("MonthlyCharges"))
36
+ total = float(form.get("TotalCharges"))
37
+
38
+ # Temel sayısal değişkenler
39
+ input_dict["tenure"] = tenure
40
+ input_dict["PhoneService"] = form.get("PhoneService") == "Evet"
41
+ input_dict["avg_charge_per_month"] = total / tenure if tenure > 0 else 0
42
+ input_dict["charge_ratio"] = total / (monthly * tenure) if monthly > 0 and tenure > 0 else 1
43
+
44
+ # tenure_bin
45
+ tenure_label = "0-12" if tenure <= 12 else "12-24" if tenure <= 24 else "24+"
46
+ for bin_label in ["0-12", "12-24", "24+"]:
47
+ input_dict[f"tenure_bin_{bin_label}"] = (tenure_label == bin_label)
48
+
49
+ # is_long_term_contract
50
+ contract_value = value_map.get(form.get("Contract"), form.get("Contract"))
51
+ input_dict["is_long_term_contract"] = contract_value in ["One year", "Two year"]
52
+
53
+ # One-hot kategorik değişkenler
54
+ categorical_fields = [
55
+ "gender", "SeniorCitizen", "Partner", "Dependents", "PaperlessBilling",
56
+ "MultipleLines", "InternetService", "OnlineSecurity", "OnlineBackup",
57
+ "DeviceProtection", "TechSupport", "StreamingTV", "StreamingMovies",
58
+ "Contract", "PaymentMethod"
59
+ ]
60
+
61
+ for field in categorical_fields:
62
+ raw_value = form.get(field)
63
+ mapped_value = value_map.get(raw_value, raw_value)
64
+ for col in model_features:
65
+ if col.startswith(f"{field}_"):
66
+ input_dict[col] = (col == f"{field}_{mapped_value}")
67
+
68
+ # Eksik kalan tüm feature'lar tamamlanır
69
+ for col in model_features:
70
+ if col not in input_dict:
71
+ input_dict[col] = 0 if col == "tenure" or "charge" in col or "avg" in col else False
72
+
73
+ # DataFrame oluştur ve tahmin yap
74
+ input_df = pd.DataFrame([[input_dict[col] for col in model_features]], columns=model_features)
75
+
76
+ print("💬 MODELE GİDEN VERİLER:", flush=True)
77
+ print(input_df.to_dict(orient="records")[0], flush=True)
78
+
79
+ prediction = model.predict_proba(input_df)[0][1]
80
+ score = round(prediction * 100, 2)
81
+ if score >= 50:
82
+ comment = "Müşteri Kaybedilebilir."
83
+ else:
84
+ comment = "Müşteri Kayıp Riski Taşımıyor."
85
+ result = f"Churn Riski: %{score} — {comment}"
86
+
87
+
88
+ return render_template("index.html", result=result)
89
+
90
+ if __name__ == "__main__":
91
+ app.run(debug=False)
churn_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e13f104be0f634de27e6721dd5fea34b64f29d9863684ddcdc8aa6a8bccbfa4c
3
+ size 640263
churn_model.py ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import pandas as pd
3
+ import matplotlib.pyplot as plt
4
+ import seaborn as sns
5
+
6
+ from xgboost import XGBClassifier
7
+ from sklearn.model_selection import StratifiedKFold, cross_val_predict
8
+ from sklearn.preprocessing import MinMaxScaler
9
+ from imblearn.over_sampling import SMOTE
10
+ from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score
11
+ from imblearn.pipeline import Pipeline
12
+ import joblib
13
+
14
+ sns.set(style='whitegrid')
15
+
16
+ # Veri setini oku
17
+ telco = pd.read_csv('Telco-Customer-Churn.csv')
18
+ pd.set_option('display.max_columns', None)
19
+
20
+ # TotalCharges sayısallaştırma ve eksik verileri çıkarma
21
+ telco.TotalCharges = pd.to_numeric(telco.TotalCharges, errors='coerce')
22
+ telco.dropna(inplace=True)
23
+
24
+ # CustomerID'yi çıkar
25
+ df2 = telco.iloc[:, 1:]
26
+
27
+ # Binary sütunları True/False yap
28
+ bool_map = {'Yes': True, 'No': False}
29
+ binary_columns = ['Churn', 'Partner', 'Dependents', 'PhoneService', 'PaperlessBilling']
30
+ for col in binary_columns:
31
+ df2[col] = df2[col].map(bool_map)
32
+
33
+ df2['SeniorCitizen'].replace({1: True, 0: False}, inplace=True)
34
+ df2['gender'].replace({'Female': True, 'Male': False}, inplace=True)
35
+
36
+ # Yeni özellikler
37
+ # Ortalama aylık ödeme
38
+ df2['avg_charge_per_month'] = df2['TotalCharges'] / df2['tenure'].replace(0, 1)
39
+ # Toplam ödeme ile (aylık * süre) oranı
40
+ df2['charge_ratio'] = df2.apply(
41
+ lambda row: row['TotalCharges'] / (row['MonthlyCharges'] * row['tenure'])
42
+ if row['MonthlyCharges'] > 0 and row['tenure'] > 0 else 1, axis=1)
43
+
44
+ # Süre kategorisi
45
+ df2['tenure_bin'] = pd.cut(df2['tenure'], bins=[0, 12, 24, df2['tenure'].max()], labels=['0-12', '12-24', '24+'])
46
+
47
+ # One-hot encoding
48
+ multi_cat_cols = ['MultipleLines', 'InternetService', 'OnlineSecurity', 'OnlineBackup',
49
+ 'DeviceProtection', 'TechSupport', 'StreamingTV', 'StreamingMovies',
50
+ 'Contract', 'PaymentMethod', 'tenure_bin']
51
+ df_dummies = pd.get_dummies(df2, columns=multi_cat_cols, drop_first=False)
52
+
53
+ # Uzun vadeli sözleşme özelliği
54
+ df_dummies['is_long_term_contract'] = (
55
+ df_dummies.get('Contract_One year', False) | df_dummies.get('Contract_Two year', False)
56
+ )
57
+
58
+ # Hedef ve bağımsız değişkenler
59
+ y = df_dummies['Churn'].values
60
+ X = df_dummies.drop(columns=['Churn'])
61
+
62
+ # En önemli 15 özelliği seçmek için XGB fit
63
+ temp_model = XGBClassifier(random_state=42)
64
+ temp_model.fit(X, y)
65
+ feature_importances = pd.Series(temp_model.feature_importances_, index=X.columns).sort_values(ascending=False)
66
+ top_15_features = feature_importances.head(15).index.tolist()
67
+ X_selected = X[top_15_features]
68
+
69
+ # Pipeline: Ölçekleme + SMOTE + XGBoost
70
+ pipe = Pipeline([
71
+ ("scaler", MinMaxScaler()),
72
+ ("smote", SMOTE(sampling_strategy=1.0, random_state=42)),
73
+ ("xgb", XGBClassifier(
74
+ n_estimators=100,
75
+ max_depth=4,
76
+ learning_rate=0.1,
77
+ subsample=1.0,
78
+ colsample_bytree=0.7,
79
+ scale_pos_weight=1,
80
+ eval_metric='logloss',
81
+ random_state=42
82
+ ))
83
+ ])
84
+
85
+ # 5-fold stratified cross-validation
86
+ cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
87
+ y_pred = cross_val_predict(pipe, X_selected, y, cv=cv, method="predict")
88
+ y_proba = cross_val_predict(pipe, X_selected, y, cv=cv, method="predict_proba")[:, 1]
89
+
90
+ # Performans metrikleri
91
+ print("XGBoost Cross-Validation Sonuçları (Binary):")
92
+ print("--------------------------------------------")
93
+ print("Accuracy: {:.4f}".format(accuracy_score(y, y_pred)))
94
+ print("Precision: {:.4f}".format(precision_score(y, y_pred)))
95
+ print("Recall: {:.4f}".format(recall_score(y, y_pred)))
96
+ print("F1 Score: {:.4f}".format(f1_score(y, y_pred)))
97
+ print("ROC-AUC: {:.4f}".format(roc_auc_score(y, y_proba)))
98
+ print("")
99
+ print("XGBoost Cross-Validation Sonuçları (Macro):")
100
+ print("--------------------------------------------")
101
+ print("Accuracy: {:.4f}".format(accuracy_score(y, y_pred)))
102
+ print("Precision: {:.4f}".format(precision_score(y, y_pred, average='macro')))
103
+ print("Recall: {:.4f}".format(recall_score(y, y_pred, average='macro')))
104
+ print("F1 Score: {:.4f}".format(f1_score(y, y_pred, average='macro')))
105
+ print("ROC-AUC: {:.4f}".format(roc_auc_score(y, y_proba)))
106
+
107
+ # Modeli eğit ve kaydet
108
+ pipe.fit(X_selected, y)
109
+ joblib.dump(pipe, 'churn_model.pkl')
110
+ joblib.dump(top_15_features, "model_features.pkl")
deneme.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import joblib
2
+ import pandas as pd
3
+
4
+ # 🔁 Kaydedilen modeli ve özellik listesini yükle
5
+ model = joblib.load("churn_model.pkl")
6
+ model_features = joblib.load("model_features.pkl")
7
+
8
+ # 🔍 Müşteri verisi (güncel örneğe göre)
9
+ customer = {
10
+ 'gender': True, # Female → True
11
+ 'SeniorCitizen': False,
12
+ 'Partner': True,
13
+ 'Dependents': False,
14
+ 'PhoneService': True,
15
+ 'PaperlessBilling': True,
16
+ 'tenure': 28,
17
+ 'MonthlyCharges': 104.8,
18
+ 'TotalCharges': 3046.05,
19
+
20
+ 'MultipleLines_No': False,
21
+ 'MultipleLines_No phone service': False,
22
+ 'MultipleLines_Yes': True,
23
+
24
+ 'InternetService_DSL': False,
25
+ 'InternetService_Fiber optic': True,
26
+ 'InternetService_No': False,
27
+
28
+ 'OnlineSecurity_No': True,
29
+ 'OnlineSecurity_Yes': False,
30
+ 'OnlineSecurity_No internet service': False,
31
+
32
+ 'OnlineBackup_No': True,
33
+ 'OnlineBackup_Yes': False,
34
+ 'OnlineBackup_No internet service': False,
35
+
36
+ 'DeviceProtection_No': False,
37
+ 'DeviceProtection_Yes': True,
38
+ 'DeviceProtection_No internet service': False,
39
+
40
+ 'TechSupport_No': False,
41
+ 'TechSupport_Yes': True,
42
+ 'TechSupport_No internet service': False,
43
+
44
+ 'StreamingTV_No': False,
45
+ 'StreamingTV_Yes': True,
46
+ 'StreamingTV_No internet service': False,
47
+
48
+ 'StreamingMovies_No': False,
49
+ 'StreamingMovies_Yes': True,
50
+ 'StreamingMovies_No internet service': False,
51
+
52
+ 'Contract_Month-to-month': True,
53
+ 'Contract_One year': False,
54
+ 'Contract_Two year': False,
55
+
56
+ 'PaymentMethod_Bank transfer (automatic)': False,
57
+ 'PaymentMethod_Credit card (automatic)': False,
58
+ 'PaymentMethod_Electronic check': True,
59
+ 'PaymentMethod_Mailed check': False
60
+ }
61
+
62
+ # Eksik kalan tüm özellikleri sıfırla
63
+ full_input = {col: customer.get(col, 0) for col in model_features}
64
+ X_test = pd.DataFrame([full_input])
65
+
66
+ # 🎯 Tahmin ve olasılık
67
+ prediction = model.predict(X_test)[0]
68
+ proba = model.predict_proba(X_test)[0][1]
69
+
70
+ # 📝 Sonuç
71
+ label = "CHURN edecek" if prediction == 1 else "Kalacak"
72
+ print(f"📊 Tahmin: {label}")
73
+ print(f"🎯 Churn olasılığı: %{proba * 100:.2f}")
gradio_app.py ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import joblib
3
+ import pandas as pd
4
+ import numpy as np
5
+ from sklearn.metrics.pairwise import euclidean_distances
6
+ import random
7
+
8
+ model = joblib.load("churn_model.pkl")
9
+ model_features = joblib.load("model_features.pkl")
10
+
11
+ # Load the customer data
12
+ customer_df = pd.read_csv("Telco-Customer-Churn.csv")
13
+
14
+ customer_df['MonthlyCharges'] = pd.to_numeric(customer_df['MonthlyCharges'], errors='coerce').fillna(0)
15
+ customer_df['TotalCharges'] = pd.to_numeric(customer_df['TotalCharges'], errors='coerce').fillna(0)
16
+ customer_df['tenure'] = pd.to_numeric(customer_df['tenure'], errors='coerce').fillna(0)
17
+
18
+ value_map = {
19
+ "Aydan aya": "Month-to-month",
20
+ "1 yıllık": "One year",
21
+ "2 yıllık": "Two year",
22
+ "Elektronik çek": "Electronic check",
23
+ "Posta çeki": "Mailed check",
24
+ "Banka havalesi (otomatik)": "Bank transfer (automatic)",
25
+ "Kredi kartı (otomatik)": "Credit card (automatic)",
26
+ "Hayır": "No",
27
+ "Evet": "Yes",
28
+ "Yok": "No internet service",
29
+ "Telefon hizmeti yok": "No phone service",
30
+ "Fiber optik": "Fiber optic",
31
+ "Erkek": "Male",
32
+ "Kadın": "Female"
33
+ }
34
+
35
+ def customer_to_features(row):
36
+ # Build a feature dict for a customer row, using the same logic as predict_churn
37
+ input_dict = {}
38
+ tenure = row['tenure']
39
+ monthly = row['MonthlyCharges']
40
+ total = row['TotalCharges']
41
+ input_dict["tenure"] = tenure
42
+ input_dict["PhoneService"] = row['PhoneService'] == "Yes"
43
+ input_dict["avg_charge_per_month"] = total / tenure if tenure > 0 else 0
44
+ input_dict["charge_ratio"] = total / (monthly * tenure) if monthly > 0 and tenure > 0 else 1
45
+ tenure_label = "0-12" if tenure <= 12 else "12-24" if tenure <= 24 else "24+"
46
+ for bin_label in ["0-12", "12-24", "24+"]:
47
+ input_dict[f"tenure_bin_{bin_label}"] = (tenure_label == bin_label)
48
+ contract_value = row['Contract']
49
+ input_dict["is_long_term_contract"] = contract_value in ["One year", "Two year"]
50
+ categorical_fields = [
51
+ "gender", "SeniorCitizen", "Partner", "Dependents", "PaperlessBilling",
52
+ "MultipleLines", "InternetService", "OnlineSecurity", "OnlineBackup",
53
+ "DeviceProtection", "TechSupport", "StreamingTV", "StreamingMovies",
54
+ "Contract", "PaymentMethod"
55
+ ]
56
+ for field in categorical_fields:
57
+ raw_value = row[field]
58
+ mapped_value = value_map.get(raw_value, raw_value)
59
+ for col in model_features:
60
+ if col.startswith(f"{field}_"):
61
+ input_dict[col] = (col == f"{field}_{mapped_value}")
62
+ for col in model_features:
63
+ if col not in input_dict:
64
+ input_dict[col] = 0 if col == "tenure" or "charge" in col or "avg" in col else False
65
+ return [input_dict[col] for col in model_features]
66
+
67
+ # Precompute all customer feature vectors
68
+ customer_feature_matrix = np.vstack([customer_to_features(row) for _, row in customer_df.iterrows()])
69
+
70
+ def autofill_random_customer():
71
+ row = customer_df.sample(1).iloc[0]
72
+ # Map English values back to Turkish for dropdowns
73
+ reverse_map = {v: k for k, v in value_map.items()}
74
+ def rev(val):
75
+ return reverse_map.get(val, val)
76
+ # Ensure dropdown values are valid
77
+ def safe(val, allowed):
78
+ v = rev(val)
79
+ return v if v in allowed else allowed[0]
80
+ return [
81
+ float(row['tenure']),
82
+ float(row['MonthlyCharges']),
83
+ float(row['TotalCharges']),
84
+ safe(row['PhoneService'], phone_service_options),
85
+ safe(row['gender'], gender_options),
86
+ 'Evet' if row['SeniorCitizen'] == 1 else 'Hayır',
87
+ 'Evet' if row['Partner'] == 'Yes' else 'Hayır',
88
+ 'Evet' if row['Dependents'] == 'Yes' else 'Hayır',
89
+ 'Evet' if row['PaperlessBilling'] == 'Yes' else 'Hayır',
90
+ safe(row['MultipleLines'], multiple_lines_options),
91
+ safe(row['InternetService'], internet_service_options),
92
+ safe(row['OnlineSecurity'], online_security_options),
93
+ safe(row['OnlineBackup'], online_backup_options),
94
+ safe(row['DeviceProtection'], device_protection_options),
95
+ safe(row['TechSupport'], tech_support_options),
96
+ safe(row['StreamingTV'], streaming_tv_options),
97
+ safe(row['StreamingMovies'], streaming_movies_options),
98
+ safe(row['Contract'], contract_options),
99
+ safe(row['PaymentMethod'], payment_method_options)
100
+ ]
101
+
102
+ def find_similar_customers_vector(input_vector, n=5):
103
+ dists = euclidean_distances(customer_feature_matrix, input_vector.reshape(1, -1)).flatten()
104
+ top_idx = np.argsort(dists)[:n]
105
+ print("Top distances:", dists[top_idx])
106
+ print("Top indices:", top_idx)
107
+ return customer_df.iloc[top_idx][['customerID','gender','SeniorCitizen','Partner','Dependents','tenure','Contract','PaymentMethod','MonthlyCharges','TotalCharges','Churn']]
108
+
109
+ def predict_churn(
110
+ tenure, monthly, total, PhoneService, gender, SeniorCitizen, Partner, Dependents, PaperlessBilling,
111
+ MultipleLines, InternetService, OnlineSecurity, OnlineBackup, DeviceProtection, TechSupport,
112
+ StreamingTV, StreamingMovies, Contract, PaymentMethod
113
+ ):
114
+ # Ensure numeric types
115
+ tenure = float(tenure)
116
+ monthly = float(monthly)
117
+ total = float(total)
118
+ input_dict = {}
119
+ input_dict["tenure"] = tenure
120
+ input_dict["PhoneService"] = PhoneService == "Evet"
121
+ input_dict["avg_charge_per_month"] = total / tenure if tenure > 0 else 0
122
+ input_dict["charge_ratio"] = total / (monthly * tenure) if monthly > 0 and tenure > 0 else 1
123
+ tenure_label = "0-12" if tenure <= 12 else "12-24" if tenure <= 24 else "24+"
124
+ for bin_label in ["0-12", "12-24", "24+"]:
125
+ input_dict[f"tenure_bin_{bin_label}"] = (tenure_label == bin_label)
126
+ contract_value = value_map.get(Contract, Contract)
127
+ input_dict["is_long_term_contract"] = contract_value in ["One year", "Two year"]
128
+ categorical_fields = [
129
+ "gender", "SeniorCitizen", "Partner", "Dependents", "PaperlessBilling",
130
+ "MultipleLines", "InternetService", "OnlineSecurity", "OnlineBackup",
131
+ "DeviceProtection", "TechSupport", "StreamingTV", "StreamingMovies",
132
+ "Contract", "PaymentMethod"
133
+ ]
134
+ form = {
135
+ "gender": gender,
136
+ "SeniorCitizen": SeniorCitizen,
137
+ "Partner": Partner,
138
+ "Dependents": Dependents,
139
+ "PaperlessBilling": PaperlessBilling,
140
+ "MultipleLines": MultipleLines,
141
+ "InternetService": InternetService,
142
+ "OnlineSecurity": OnlineSecurity,
143
+ "OnlineBackup": OnlineBackup,
144
+ "DeviceProtection": DeviceProtection,
145
+ "TechSupport": TechSupport,
146
+ "StreamingTV": StreamingTV,
147
+ "StreamingMovies": StreamingMovies,
148
+ "Contract": Contract,
149
+ "PaymentMethod": PaymentMethod
150
+ }
151
+ for field in categorical_fields:
152
+ raw_value = form[field]
153
+ mapped_value = value_map.get(raw_value, raw_value)
154
+ for col in model_features:
155
+ if col.startswith(f"{field}_"):
156
+ input_dict[col] = (col == f"{field}_{mapped_value}")
157
+ for col in model_features:
158
+ if col not in input_dict:
159
+ input_dict[col] = 0 if col == "tenure" or "charge" in col or "avg" in col else False
160
+ input_df = pd.DataFrame([[input_dict[col] for col in model_features]], columns=model_features)
161
+ prediction = model.predict_proba(input_df)[0][1]
162
+ score = round(prediction * 100, 2)
163
+ if score >= 50:
164
+ comment = "Müşteri Kaybedilebilir."
165
+ else:
166
+ comment = "Müşteri Kayıp Riski Taşımıyor."
167
+ result = f"Churn Riski: %{score} — {comment}"
168
+ # Vector similarity
169
+ similar_customers = find_similar_customers_vector(input_df.values[0], n=5)
170
+ return result, similar_customers
171
+
172
+ # Define options for dropdowns (Turkish values)
173
+ phone_service_options = ["Evet", "Hayır"]
174
+ gender_options = ["Erkek", "Kadın"]
175
+ senior_citizen_options = ["Evet", "Hayır"]
176
+ partner_options = ["Evet", "Hayır"]
177
+ dependents_options = ["Evet", "Hayır"]
178
+ paperless_billing_options = ["Evet", "Hayır"]
179
+ multiple_lines_options = ["Hayır", "Evet", "Telefon hizmeti yok"]
180
+ internet_service_options = ["DSL", "Fiber optik", "Yok"]
181
+ online_security_options = ["Hayır", "Evet", "Yok"]
182
+ online_backup_options = ["Hayır", "Evet", "Yok"]
183
+ device_protection_options = ["Hayır", "Evet", "Yok"]
184
+ tech_support_options = ["Hayır", "Evet", "Yok"]
185
+ streaming_tv_options = ["Hayır", "Evet", "Yok"]
186
+ streaming_movies_options = ["Hayır", "Evet", "Yok"]
187
+ contract_options = ["Aydan aya", "1 yıllık", "2 yıllık"]
188
+ payment_method_options = [
189
+ "Elektronik çek", "Posta çeki", "Banka havalesi (otomatik)", "Kredi kartı (otomatik)"
190
+ ]
191
+
192
+ with gr.Blocks() as demo:
193
+ gr.Markdown("# Müşteri Churn Tahmini")
194
+ with gr.Row():
195
+ tenure = gr.Number(label="Kullanım Süresi (tenure)", value=1)
196
+ monthly = gr.Number(label="Aylık Ücret (MonthlyCharges)", value=1)
197
+ total = gr.Number(label="Toplam Ücret (TotalCharges)", value=1)
198
+ with gr.Row():
199
+ PhoneService = gr.Dropdown(phone_service_options, label="Telefon Hizmeti (PhoneService)")
200
+ gender = gr.Dropdown(gender_options, label="Cinsiyet (gender)")
201
+ SeniorCitizen = gr.Dropdown(senior_citizen_options, label="Kıdemli Vatandaş (SeniorCitizen)")
202
+ Partner = gr.Dropdown(partner_options, label="Partner")
203
+ Dependents = gr.Dropdown(dependents_options, label="Bağımlılar (Dependents)")
204
+ PaperlessBilling = gr.Dropdown(paperless_billing_options, label="Kağıtsız Fatura (PaperlessBilling)")
205
+ with gr.Row():
206
+ MultipleLines = gr.Dropdown(multiple_lines_options, label="Çoklu Hat (MultipleLines)")
207
+ InternetService = gr.Dropdown(internet_service_options, label="İnternet Servisi (InternetService)")
208
+ OnlineSecurity = gr.Dropdown(online_security_options, label="Online Güvenlik (OnlineSecurity)")
209
+ OnlineBackup = gr.Dropdown(online_backup_options, label="Online Yedekleme (OnlineBackup)")
210
+ DeviceProtection = gr.Dropdown(device_protection_options, label="Cihaz Koruma (DeviceProtection)")
211
+ TechSupport = gr.Dropdown(tech_support_options, label="Teknik Destek (TechSupport)")
212
+ StreamingTV = gr.Dropdown(streaming_tv_options, label="TV Yayını (StreamingTV)")
213
+ StreamingMovies = gr.Dropdown(streaming_movies_options, label="Film Yayını (StreamingMovies)")
214
+ with gr.Row():
215
+ Contract = gr.Dropdown(contract_options, label="Sözleşme (Contract)")
216
+ PaymentMethod = gr.Dropdown(payment_method_options, label="Ödeme Yöntemi (PaymentMethod)")
217
+ autofill_btn = gr.Button("Rastgele Müşteri ile Doldur")
218
+ submit_btn = gr.Button("Tahmin Et")
219
+ output = gr.Textbox(label="Sonuç")
220
+ similar_customers_table = gr.Dataframe(label="Benzer Müşteriler (İlk 5)")
221
+ autofill_btn.click(
222
+ autofill_random_customer,
223
+ inputs=[],
224
+ outputs=[tenure, monthly, total, PhoneService, gender, SeniorCitizen, Partner, Dependents, PaperlessBilling,
225
+ MultipleLines, InternetService, OnlineSecurity, OnlineBackup, DeviceProtection, TechSupport,
226
+ StreamingTV, StreamingMovies, Contract, PaymentMethod]
227
+ )
228
+ submit_btn.click(
229
+ predict_churn,
230
+ inputs=[tenure, monthly, total, PhoneService, gender, SeniorCitizen, Partner, Dependents, PaperlessBilling,
231
+ MultipleLines, InternetService, OnlineSecurity, OnlineBackup, DeviceProtection, TechSupport,
232
+ StreamingTV, StreamingMovies, Contract, PaymentMethod],
233
+ outputs=[output, similar_customers_table]
234
+ )
235
+
236
+ if __name__ == "__main__":
237
+ demo.launch()
model_features.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fc7c1d59e2bd2dfce4329ee3949ad58f3e2723bc32b8263cc1a81bec702d4b6b
3
+ size 324
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio
2
+ Flask
3
+ pandas
4
+ joblib
5
+ scikit-learn
6
+ xgboost
7
+ imbalanced-learn
8
+ matplotlib
9
+ seaborn
10
+ numpy
templates/index.html ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="tr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Müşteri Churn Tahmini</title>
6
+ <style>
7
+ body {
8
+ background-color: #d9dafa;
9
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
10
+ color: #564dbf;
11
+ padding: 40px;
12
+ }
13
+
14
+ h2 {
15
+ color: #1a1636;
16
+ }
17
+
18
+ form {
19
+ background-color: #c2baff;
20
+ border: 2px solid #8780bf;
21
+ border-radius: 12px;
22
+ padding: 30px;
23
+ width: 450px;
24
+ box-shadow: 2px 2px 10px #3c30e3;
25
+ }
26
+
27
+ label {
28
+ display: block;
29
+ margin-top: 12px;
30
+ font-weight: bold;
31
+ }
32
+
33
+ input, select {
34
+ width: 100%;
35
+ padding: 8px;
36
+ margin-top: 5px;
37
+ border: 1px solid #564dbf;
38
+ border-radius: 6px;
39
+ }
40
+
41
+ input[type="submit"] {
42
+ background-color: #7791d9;
43
+ color: white;
44
+ font-weight: bold;
45
+ cursor: pointer;
46
+ margin-top: 20px;
47
+ }
48
+
49
+ input[type="submit"]:hover {
50
+ background-color: #1a1636;
51
+ }
52
+
53
+ h3 {
54
+ margin-top: 30px;
55
+ color: #1a1636;
56
+ }
57
+ </style>
58
+ </head>
59
+ <body>
60
+ <h2>Müşteri Bilgileri</h2>
61
+ <form method="POST">
62
+ <label>Cinsiyet:</label>
63
+ <select name="gender"><option>Kadın</option><option>Erkek</option></select>
64
+
65
+ <label>65 yaş ve üstü mü?</label>
66
+ <select name="SeniorCitizen"><option>Hayır</option><option>Evet</option></select>
67
+
68
+ <label>Evli mi?</label>
69
+ <select name="Partner"><option>Hayır</option><option>Evet</option></select>
70
+
71
+ <label>Bakmakla yükümlü olduğu kişi var mı?</label>
72
+ <select name="Dependents"><option>Hayır</option><option>Evet</option></select>
73
+
74
+ <label>Telefon hizmeti var mı?</label>
75
+ <select name="PhoneService"><option>Hayır</option><option>Evet</option></select>
76
+
77
+ <label>Kağıtsız fatura kullanıyor mu?</label>
78
+ <select name="PaperlessBilling"><option>Hayır</option><option>Evet</option></select>
79
+
80
+ <label>Abonelik süresi (ay):</label>
81
+ <input type="number" step="1" name="tenure" value="0" required>
82
+
83
+ <label>Aylık ücret ($):</label>
84
+ <input type="number" step="0.01" name="MonthlyCharges" value="0.00" required>
85
+
86
+ <label>Toplam ücret ($):</label>
87
+ <input type="number" step="0.01" name="TotalCharges" value="0.00" required>
88
+
89
+ <label>Çoklu hat durumu:</label>
90
+ <select name="MultipleLines">
91
+ <option>Hayır</option><option>Evet</option><option>Telefon hizmeti yok</option>
92
+ </select>
93
+
94
+ <label>İnternet hizmeti:</label>
95
+ <select name="InternetService">
96
+ <option>DSL</option><option>Fiber optik</option><option>Yok</option>
97
+ </select>
98
+
99
+ <label>Online güvenlik:</label>
100
+ <select name="OnlineSecurity">
101
+ <option>Hayır</option><option>Evet</option><option>İnternet hizmeti yok</option>
102
+ </select>
103
+
104
+ <label>Online yedekleme:</label>
105
+ <select name="OnlineBackup">
106
+ <option>Hayır</option><option>Evet</option><option>İnternet hizmeti yok</option>
107
+ </select>
108
+
109
+ <label>Cihaz koruma:</label>
110
+ <select name="DeviceProtection">
111
+ <option>Hayır</option><option>Evet</option><option>İnternet hizmeti yok</option>
112
+ </select>
113
+
114
+ <label>Teknik destek:</label>
115
+ <select name="TechSupport">
116
+ <option>Hayır</option><option>Evet</option><option>İnternet hizmeti yok</option>
117
+ </select>
118
+
119
+ <label>TV yayını:</label>
120
+ <select name="StreamingTV">
121
+ <option>Hayır</option><option>Evet</option><option>İnternet hizmeti yok</option>
122
+ </select>
123
+
124
+ <label>Film yayını:</label>
125
+ <select name="StreamingMovies">
126
+ <option>Hayır</option><option>Evet</option><option>İnternet hizmeti yok</option>
127
+ </select>
128
+
129
+ <label>Abonelik türü:</label>
130
+ <select name="Contract">
131
+ <option>Aydan aya</option><option>1 yıllık</option><option>2 yıllık</option>
132
+ </select>
133
+
134
+ <label>Ödeme yöntemi:</label>
135
+ <select name="PaymentMethod">
136
+ <option>Elektronik çek</option>
137
+ <option>Posta çeki</option>
138
+ <option>Banka havalesi (otomatik)</option>
139
+ <option>Kredi kartı (otomatik)</option>
140
+ </select>
141
+
142
+ <input type="submit" value="Tahmin Et">
143
+ </form>
144
+
145
+ {% if result %}
146
+ <h3>{{ result }}</h3>
147
+ {% endif %}
148
+ </body>
149
+ </html>