HOLYBOY commited on
Commit
d474ecb
1 Parent(s): 09071a1

New Updated

Browse files
Files changed (1) hide show
  1. app.py +290 -1
app.py CHANGED
@@ -33,4 +33,293 @@ def preprocess_input(input_data):
33
  final_df = pd.concat([input_encoded_df, input_scaled_df], axis=1)
34
  final_df = final_df.reindex(columns=original_feature_names, fill_value=0)
35
 
36
- return final_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  final_df = pd.concat([input_encoded_df, input_scaled_df], axis=1)
34
  final_df = final_df.reindex(columns=original_feature_names, fill_value=0)
35
 
36
+ return final_df
37
+
38
+
39
+ original_feature_names = ['MONTANT', 'FREQUENCE_RECH', 'REVENUE', 'ARPU_SEGMENT', 'FREQUENCE',
40
+ 'DATA_VOLUME', 'ON_NET', 'ORANGE', 'TIGO', 'ZONE1', 'ZONE2', 'REGULARITY', 'FREQ_TOP_PACK',
41
+ 'REGION_DAKAR', 'REGION_DIOURBEL', 'REGION_FATICK', 'REGION_KAFFRINE', 'REGION_KAOLACK',
42
+ 'REGION_KEDOUGOU', 'REGION_KOLDA', 'REGION_LOUGA', 'REGION_MATAM', 'REGION_SAINT-LOUIS',
43
+ 'REGION_SEDHIOU', 'REGION_TAMBACOUNDA', 'REGION_THIES', 'REGION_ZIGUINCHOR',
44
+ 'TENURE_Long-term', 'TENURE_Medium-term', 'TENURE_Mid-term', 'TENURE_Short-term',
45
+ 'TENURE_Very short-term', 'TOP_PACK_VAS', 'TOP_PACK_data', 'TOP_PACK_international',
46
+ 'TOP_PACK_messaging', 'TOP_PACK_other_services', 'TOP_PACK_social_media',
47
+ 'TOP_PACK_voice']
48
+
49
+ # Set up the Streamlit app
50
+ st.set_page_config(layout="wide")
51
+
52
+ # Main page - Churn Prediction
53
+ st.title('CUSTOMER CHURN PREDICTION APP ')
54
+
55
+ # Main page - Churn Prediction
56
+ st.markdown("Churn is a one of the biggest problem in the telecom industry. Research has shown that the average monthly churn rate among the top 4 wireless carriers in the US is 1.9% - 2%")
57
+ st.image("bg.png", use_column_width=True)
58
+
59
+ # How to use
60
+ st.sidebar.image("welcome.jpg", use_column_width=True)
61
+ st.sidebar.title("ENTER THE DETAILS OF THE CUSTOMER HERE")
62
+
63
+ # Define a dictionary of models with their names, actual models, and types
64
+ models = {
65
+ 'Logistic Regression': {'Logistic Regression': lr_model, 'type': 'logistic_regression'},
66
+ #'ComplementNB': {'ComplementNB': cnb_model, 'type': 'Complement NB'}
67
+ }
68
+
69
+ # Allow the user to select a model from the sidebar
70
+ model_name = st.sidebar.selectbox('Select Model', list(models.keys()))
71
+
72
+ # Retrieve the selected model and its type from the dictionary
73
+ model = models[model_name]['Logistic Regression']
74
+ model_type = models[model_name]['type']
75
+
76
+
77
+ # Collect input from the user
78
+ st.sidebar.title('Enter Customer Details')
79
+ input_features = {
80
+ 'MONTANT': st.sidebar.number_input('Top-up Amount (MONTANT)'),
81
+ 'FREQUENCE_RECH': st.sidebar.number_input('Number of Times the Customer Refilled (FREQUENCE_RECH)'),
82
+ 'REVENUE': st.sidebar.number_input('Monthly income of the client (REVENUE)'),
83
+ 'ARPU_SEGMENT': st.sidebar.number_input('Income over 90 days / 3 (ARPU_SEGMENT)'),
84
+ 'FREQUENCE': st.sidebar.number_input('Number of times the client has made an income (FREQUENCE)'),
85
+ 'DATA_VOLUME': st.sidebar.number_input('Number of Connections (DATA_VOLUME)'),
86
+ 'ON_NET': st.sidebar.number_input('Inter Expresso Call (ON_NET)'),
87
+ 'ORANGE': st.sidebar.number_input('Call to Orange (ORANGE)'),
88
+ 'TIGO': st.sidebar.number_input('Call to Tigo (TIGO)'),
89
+ 'ZONE1': st.sidebar.number_input('Call to Zone 1 (ZONE1)'),
90
+ 'ZONE2': st.sidebar.number_input('Call to Zone 2 (ZONE2)'),
91
+ 'REGULARITY': st.sidebar.number_input('Number of Times the Client is Active for 90 Days (REGULARITY)'),
92
+ 'FREQ_TOP_PACK': st.sidebar.number_input('Number of Times the Client has Activated the Top Packs (FREQ_TOP_PACK)'),
93
+ 'REGION': st.sidebar.selectbox('Location of Each Client (REGION)', ['DAKAR','DIOURBEL','FATICK','AFFRINE','KAOLACK',
94
+ 'KEDOUGOU','KOLDA','LOUGA','MATAM','SAINT-LOUIS',
95
+ 'SEDHIOU','TAMBACOUNDA','HIES','ZIGUINCHOR' ]),
96
+
97
+ 'TENURE': st.sidebar.selectbox('Duration in the Network (TENURE)', ['Long-term','Medium-term','Mid-term','Short-term',
98
+ 'Very short-term']),
99
+ 'TOP_PACK': st.sidebar.selectbox('Most Active Pack (TOP_PACK)', ['VAS', 'data', 'international',
100
+ 'messaging','other_services', 'social_media',
101
+ 'voice'])
102
+
103
+ }
104
+
105
+ # Input validation
106
+ valid_input = True
107
+ error_messages = []
108
+
109
+ # Validate numeric inputs
110
+ numeric_ranges = {
111
+ 'MONTANT': [0, 1000000],
112
+ 'FREQUENCE_RECH': [0, 100],
113
+ 'REVENUE': [0, 1000000],
114
+ 'ARPU_SEGMENT': [0, 100000],
115
+ 'FREQUENCE': [0, 100],
116
+ 'DATA_VOLUME': [0, 100000],
117
+ 'ON_NET': [0, 100000],
118
+ 'ORANGE': [0, 100000],
119
+ 'TIGO': [0, 100000],
120
+ 'ZONE1': [0, 100000],
121
+ 'ZONE2': [0, 100000],
122
+ 'REGULARITY': [0, 100],
123
+ 'FREQ_TOP_PACK': [0, 100]
124
+ }
125
+
126
+ for feature, value in input_features.items():
127
+ range_min, range_max = numeric_ranges.get(feature, [None, None])
128
+ if range_min is not None and range_max is not None:
129
+ if not range_min <= value <= range_max:
130
+ valid_input = False
131
+ error_messages.append(f"{feature} should be between {range_min} and {range_max}.")
132
+
133
+ #Churn Prediction
134
+
135
+ def predict_churn(input_data, model):
136
+ # Preprocess the input data
137
+ preprocessed_data = preprocess_input(input_data)
138
+
139
+ # Calculate churn probabilities using the model
140
+ probabilities = model.predict_proba(preprocessed_data)
141
+
142
+ # Determine churn labels based on the model type
143
+ if model_type == "logistic_regression":
144
+ churn_labels = ["No Churn", "Churn"]
145
+ #elif model_type == "ComplementNB":
146
+ churn_labels = ["Churn", "No Churn"]
147
+ # Extract churn probability for the first sample
148
+ churn_probability = probabilities[0]
149
+
150
+ # Create a dictionary mapping churn labels to their indices
151
+ churn_indices = {label: idx for idx, label in enumerate(churn_labels)}
152
+
153
+ # Determine the index with the highest churn probability
154
+ churn_index = np.argmax(churn_probability)
155
+
156
+ # Return churn labels, churn probabilities, churn indices, and churn index
157
+ return churn_labels, churn_probability, churn_indices, churn_index
158
+
159
+ # Predict churn based on user input
160
+ if st.sidebar.button('Predict Churn'):
161
+ try:
162
+ with st.spinner("Wait, Results loading..."):
163
+ # Simulate a long-running process
164
+ progress_bar = st.progress(0)
165
+ step = 20 # A big step will reduce the execution time
166
+ for i in range(0, 100, step):
167
+ time.sleep(0.1)
168
+ progress_bar.progress(i + step)
169
+
170
+ #churn_labels, churn_probability = predict_churn(input_features, model) # Pass model1 or model2 based on the selected model
171
+ churn_labels, churn_probability, churn_indices, churn_index = predict_churn(input_features, model)
172
+
173
+ st.subheader('CHURN PREDICTION RESULTS')
174
+
175
+
176
+
177
+ col1, col2 = st.columns(2)
178
+
179
+ if churn_labels[churn_index] == "Churn":
180
+ churn_prob = churn_probability[churn_index]
181
+ with col1:
182
+ st.error(f"CHURN ALERT! This customer is likely to churn with a probability of {churn_prob * 100:.2f}% 😢")
183
+ resized_churn_image = Image.open('Churn.jpeg')
184
+ resized_churn_image = resized_churn_image.resize((350, 300)) # Adjust the width and height as desired
185
+ st.image(resized_churn_image)
186
+ # Add suggestions for retaining churned customers in the 'Churn' group
187
+ with col2:
188
+ st.info("ADVICE TO EXPRESSOR MANAGEMENT:\n"
189
+ "- Identify Reasons for Churn\n"
190
+ "- Offer Incentives\n"
191
+ "- Showcase Improvements\n"
192
+ "- Gather Feedback\n"
193
+ "- Customer Surveys\n"
194
+ "- Personalized Recommendations\n"
195
+ "- Reestablish Trust\n"
196
+ "- Follow-Up Communication\n"
197
+ "- Reactivation Campaigns\n"
198
+ "- Improve product or service offerings based on customer feedback\n"
199
+ " SUMMARY NOTE\n"
200
+ "- Remember that winning back churning customers takes time and persistence.\n"
201
+ "- It\s crucial to genuinely address their concerns and provide value to rebuild their trust in your business\n"
202
+ "- Regularly evaluate the effectiveness of your strategies and adjust them as needed based on customer responses and feedback\n")
203
+ else:
204
+ #churn_index = churn_indices["No Churn"]
205
+ churn_prob = churn_probability[churn_index]
206
+ with col1:
207
+ st.success(f"This customer is not likely to churn with a probability of {churn_prob * 100:.2f}% 😀")
208
+ resized_not_churn_image = Image.open('NotChurn.jpeg')
209
+ resized_not_churn_image = resized_not_churn_image.resize((350, 300)) # Adjust the width and height as desired
210
+ st.image(resized_not_churn_image)
211
+ # Add suggestions for retaining churned customers in the 'Churn' group
212
+ with col2:
213
+ st.info("ADVICE TO EXPRESSOR MANAGEMENT\n"
214
+ "- Quality Products/Services\n"
215
+ "- Personalized Experience\n"
216
+ "- Loyalty Programs\n"
217
+ "- Excellent Customer Service\n"
218
+ "- Exclusive Content\n"
219
+ "- Early Access\n"
220
+ "- Personal Thank-You Notes\n"
221
+ "- Surprise Gifts or Discounts\n"
222
+ "- Feedback Opportunities\n"
223
+ "- Community Engagement\n"
224
+ "- Anniversary Celebrations\n"
225
+ "- Refer-a-Friend Programs\n"
226
+ "SUMMARY NOTE\n"
227
+ "- Remember that the key to building lasting loyalty is consistency.\n"
228
+ "- Continuously demonstrate your commitment to meeting customers needs and enhancing their experience.\n"
229
+ "- Regularly assess the effectiveness of your loyalty initiatives and adapt them based on customer feedback and preferences.")
230
+
231
+ st.subheader('Churn Probability')
232
+
233
+ # Create a donut chart to display probabilities
234
+ fig = go.Figure(data=[go.Pie(
235
+ labels=churn_labels,
236
+ values=churn_probability,
237
+ hole=0.5,
238
+ textinfo='label+percent',
239
+ marker=dict(colors=['#FFA07A', '#6495ED', '#FFD700', '#32CD32', '#FF69B4', '#8B008B']))])
240
+
241
+ fig.update_traces(
242
+ hoverinfo='label+percent',
243
+ textfont_size=12,
244
+ textposition='inside',
245
+ texttemplate='%{label}: %{percent:.2f}%'
246
+ )
247
+
248
+ fig.update_layout(
249
+ title='Churn Probability',
250
+ title_x=0.5,
251
+ showlegend=False,
252
+ width=500,
253
+ height=500
254
+ )
255
+
256
+ st.plotly_chart(fig, use_container_width=True)
257
+
258
+ # Calculate the average churn rate (replace with your actual value)
259
+
260
+ st.subheader('Customer Churn Probability Comparison')
261
+
262
+ average_churn_rate = 19
263
+
264
+ # Convert the overall churn rate to churn probability
265
+ main_data_churn_probability = average_churn_rate / 100
266
+
267
+ # Retrieve the predicted churn probability for the selected customer
268
+ predicted_churn_prob = churn_probability[churn_index]
269
+
270
+ if churn_labels[churn_index] == "Churn":
271
+ churn_prob = churn_probability[churn_index]
272
+ # Create a bar chart comparing the churn probability with the average churn rate
273
+ labels = ['Churn Probability', 'Average Churn Probability']
274
+ values = [predicted_churn_prob, main_data_churn_probability]
275
+
276
+ fig = go.Figure(data=[go.Bar(x=labels, y=values)])
277
+ fig.update_layout(
278
+ xaxis_title='Churn Probability',
279
+ yaxis_title='Probability',
280
+ title='Comparison with Average Churn Rate',
281
+ yaxis=dict(range=[0, 1]) # Set the y-axis limits between 0 and 1
282
+ )
283
+
284
+ # Add explanations
285
+ if predicted_churn_prob > main_data_churn_probability:
286
+ churn_comparison = "higher"
287
+ elif predicted_churn_prob < main_data_churn_probability:
288
+ churn_comparison = "lower"
289
+ else:
290
+ churn_comparison = "equal"
291
+
292
+ explanation = f"This bar chart compares the churn probability of the selected customer " \
293
+ f"with the average churn rate of all customers. It provides insights into how the " \
294
+ f"individual customer's churn likelihood ({predicted_churn_prob:.2f}) compares to the " \
295
+ f"overall trend. The 'Churn Probability' represents the likelihood of churn " \
296
+ f"for the selected customer, while the 'Average Churn Rate' represents the average " \
297
+ f"churn rate across all customers ({main_data_churn_probability:.2f}).\n\n" \
298
+ f"The customer's churn rate is {churn_comparison} than the average churn rate."
299
+
300
+ st.plotly_chart(fig)
301
+ st.write(explanation)
302
+ else:
303
+ # Create a bar chart comparing the no-churn probability with the average churn rate
304
+ labels = ['No-Churn Probability', 'Average Churn Probability']
305
+ values = [1 - predicted_churn_prob, main_data_churn_probability]
306
+
307
+ fig = go.Figure(data=[go.Bar(x=labels, y=values)])
308
+ fig.update_layout(
309
+ xaxis_title='Churn Probability',
310
+ yaxis_title='Probability',
311
+ title='Comparison with Average Churn Rate',
312
+ yaxis=dict(range=[0, 1]) # Set the y-axis limits between 0 and 1
313
+ )
314
+
315
+ explanation = f"This bar chart compares the churn probability of the selected customer " \
316
+ f"with the average churn rate of all customers. It provides insights into how the " \
317
+ f"individual customer's churn likelihood ({predicted_churn_prob:.2f}) compares to the " \
318
+ f"overall trend." \
319
+ f"The prediction indicates that the customer is not likely to churn. " \
320
+ f"The churn probability is lower than the no-churn probability."
321
+
322
+ st.plotly_chart(fig)
323
+ st.write(explanation)
324
+ except Exception as e:
325
+ st.error(f"An error occurred: {str(e)}")