File size: 26,508 Bytes
3906c88
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

# Set page config
st.set_page_config(
    page_title="Customer Churn Analysis",
    page_icon="πŸ“Š",
    layout="wide",
    initial_sidebar_state="expanded"
)

@st.cache_data
def load_data():
    """Load and combine the churn datasets"""
    try:
        df1 = pd.read_csv('churn-bigml-20.csv')
        df2 = pd.read_csv('churn-bigml-80.csv')
        

        
        # Add dataset identifier
        df1['Dataset'] = 'Test (20%)'
        df2['Dataset'] = 'Train (80%)'
        
        # Combine datasets
        df_combined = pd.concat([df1, df2], ignore_index=True)
        
        return df1, df2, df_combined
    except Exception as e:
        st.error(f"Error loading data: {str(e)}")
        return None, None, None

def main():
    st.title("πŸ“Š Customer Churn Analysis - Exploratory Data Analysis")
    st.markdown("---")
    
    # Load data
    df_test, df_train, df_combined = load_data()
    
    # Check if data loading was successful
    if df_test is None or df_train is None or df_combined is None:
        st.error("Failed to load data. Please check the CSV files exist and are properly formatted.")
        return
    
    # Sidebar
    st.sidebar.title("πŸ“‹ Analysis Options")
    
    # Dataset selection
    dataset_option = st.sidebar.selectbox(
        "Select Dataset:",
        ["Combined Dataset", "Training Set (80%)", "Test Set (20%)"]
    )
    
    if dataset_option == "Combined Dataset":
        df = df_combined
        st.sidebar.info(f"πŸ“ˆ Total Records: {len(df):,}")
    elif dataset_option == "Training Set (80%)":
        df = df_train
        st.sidebar.info(f"πŸ“ˆ Training Records: {len(df):,}")
    else:
        df = df_test
        st.sidebar.info(f"πŸ“ˆ Test Records: {len(df):,}")
    
    # Analysis sections
    analysis_type = st.sidebar.selectbox(
        "Choose Analysis Type:",
        [
            "πŸ“‹ Dataset Overview",
            "🎯 Churn Analysis", 
            "πŸ“ Geographic Analysis",
            "πŸ“ž Usage Patterns",
            "πŸ’° Revenue Analysis",
            "πŸ”— Correlation Analysis",
            "πŸ“Š Advanced Insights"
        ]
    )
    
    if analysis_type == "πŸ“‹ Dataset Overview":
        dataset_overview(df)
    elif analysis_type == "🎯 Churn Analysis":
        churn_analysis(df)
    elif analysis_type == "πŸ“ Geographic Analysis":
        geographic_analysis(df)
    elif analysis_type == "πŸ“ž Usage Patterns":
        usage_patterns(df)
    elif analysis_type == "πŸ’° Revenue Analysis":
        revenue_analysis(df)
    elif analysis_type == "πŸ”— Correlation Analysis":
        correlation_analysis(df)
    elif analysis_type == "πŸ“Š Advanced Insights":
        advanced_insights(df)

def dataset_overview(df):
    st.header("πŸ“‹ Dataset Overview")
    
    # Dataset description
    st.markdown("""
    ### πŸ“ž About This Dataset
    
    This is a **telecommunications customer churn dataset** that contains information about customers of a telecom company and whether they churned (cancelled their service) or were retained. The dataset is commonly used for predictive modeling to identify customers at risk of churning.
    
    **Key Characteristics:**
    - **Domain**: Telecommunications industry
    - **Target Variable**: `Churn` (True/False) - indicates if customer cancelled service
    - **Time Period**: Historical customer data with usage patterns and service details
    - **Geographic Coverage**: Multiple US states (51 unique states)
    - **Use Case**: Customer retention analysis, churn prediction modeling, and business intelligence
    
    **Feature Categories:**
    - 🏠 **Demographics**: State, account length, area code
    - πŸ“‹ **Service Plans**: International calling plan, voice mail plan
    - πŸ“ž **Usage Patterns**: Day/evening/night/international minutes, calls, and charges
    - 🎧 **Service Interactions**: Customer service call frequency
    - πŸ’° **Billing**: Detailed breakdown of charges by time period and service type
    
    This dataset enables analysis of customer behavior patterns, identification of churn risk factors, and development of retention strategies.
    """)
    
    st.markdown("---")
    
    # Basic info
    col1, col2, col3, col4 = st.columns(4)
    
    with col1:
        st.metric("Total Records", f"{len(df):,}")
    with col2:
        st.metric("Total Features", len(df.columns))
    with col3:
        if 'Churn' in df.columns:
            churn_rate = (df['Churn'] == True).mean() * 100
            st.metric("Churn Rate", f"{churn_rate:.1f}%")
        else:
            st.metric("Churn Rate", "N/A")
    with col4:
        if 'State' in df.columns:
            st.metric("Unique States", df['State'].nunique())
        else:
            st.metric("Unique States", "N/A")
    
    # Dataset structure
    st.subheader("πŸ“Š Dataset Structure")
    
    col1, col2 = st.columns(2)
    
    with col1:
        st.write("**Data Types:**")
        data_types = df.dtypes.value_counts()
        # Convert index to string to avoid JSON serialization issues
        fig = px.pie(
            values=data_types.values,
            names=[str(dtype) for dtype in data_types.index],
            title="Distribution of Data Types"
        )
        st.plotly_chart(fig, use_container_width=True)
    
    with col2:
        st.write("**Missing Values:**")
        missing_data = df.isnull().sum()
        if missing_data.sum() == 0:
            st.success("βœ… No missing values found!")
        else:
            st.write(missing_data[missing_data > 0])
    
    # Sample data
    st.subheader("πŸ” Sample Data")
    st.dataframe(df.head(10), use_container_width=True)
    

    
    # Statistical summary
    st.subheader("πŸ“ˆ Statistical Summary")
    st.dataframe(df.describe(), use_container_width=True)

def churn_analysis(df):
    st.header("🎯 Churn Analysis")
    
    # Check if Churn column exists
    if 'Churn' not in df.columns:
        st.error("'Churn' column not found in the dataset. Please check your data.")
        return
    
    # Churn distribution
    col1, col2 = st.columns(2)
    
    with col1:
        churn_counts = df['Churn'].value_counts()
        fig = px.pie(
            values=churn_counts.values,
            names=['Retained', 'Churned'],
            title="Overall Churn Distribution",
            color_discrete_sequence=['lightgreen', 'lightcoral']
        )
        st.plotly_chart(fig, use_container_width=True)
    
    with col2:
        # Churn by categorical variables
        categorical_vars = ['International plan', 'Voice mail plan']
        selected_var = st.selectbox("Select categorical variable:", categorical_vars)
        
        churn_by_cat = df.groupby([selected_var, 'Churn']).size().unstack()
        churn_rate_cat = df.groupby(selected_var)['Churn'].mean() * 100
        
        fig = px.bar(
            x=churn_rate_cat.index,
            y=churn_rate_cat.values,
            title=f"Churn Rate by {selected_var}",
            labels={'x': selected_var, 'y': 'Churn Rate (%)'},
            color=churn_rate_cat.values,
            color_continuous_scale='Reds'
        )
        st.plotly_chart(fig, use_container_width=True)
    
    # Churn by numerical variables
    st.subheader("πŸ“Š Churn Analysis by Numerical Features")
    
    numerical_vars = [
        'Account length', 'Total day minutes', 'Total day calls', 'Total day charge',
        'Total eve minutes', 'Total eve calls', 'Total eve charge',
        'Total night minutes', 'Total night calls', 'Total night charge',
        'Total intl minutes', 'Total intl calls', 'Total intl charge',
        'Customer service calls'
    ]
    
    selected_num_var = st.selectbox("Select numerical variable:", numerical_vars)
    
    col1, col2 = st.columns(2)
    
    with col1:
        # Box plot
        fig = px.box(
            df, x='Churn', y=selected_num_var,
            title=f"{selected_num_var} Distribution by Churn Status",
            color='Churn',
            color_discrete_sequence=['lightgreen', 'lightcoral']
        )
        st.plotly_chart(fig, use_container_width=True)
    
    with col2:
        # Histogram
        fig = px.histogram(
            df, x=selected_num_var, color='Churn',
            title=f"{selected_num_var} Distribution",
            marginal="box",
            color_discrete_sequence=['lightgreen', 'lightcoral']
        )
        st.plotly_chart(fig, use_container_width=True)

def geographic_analysis(df):
    st.header("πŸ“ Geographic Analysis")
    
    # Check required columns
    required_cols = ['State', 'Churn']
    missing_cols = [col for col in required_cols if col not in df.columns]
    if missing_cols:
        st.error(f"Required columns missing: {missing_cols}")
        return
    
    # State-wise analysis
    state_analysis = df.groupby('State').agg({
        'Churn': ['count', 'sum', 'mean'],
        'Total day charge': 'mean',
        'Total eve charge': 'mean',
        'Total night charge': 'mean',
        'Total intl charge': 'mean'
    }).round(2)
    
    state_analysis.columns = ['Total_Customers', 'Churned_Customers', 'Churn_Rate', 
                             'Avg_Day_Charge', 'Avg_Eve_Charge', 'Avg_Night_Charge', 'Avg_Intl_Charge']
    state_analysis = state_analysis.reset_index()
    
    col1, col2 = st.columns(2)
    
    with col1:
        # Churn rate by state
        fig = px.choropleth(
            state_analysis,
            locations='State',
            color='Churn_Rate',
            hover_name='State',
            hover_data=['Total_Customers', 'Churned_Customers'],
            locationmode='USA-states',
            title="Churn Rate by State",
            color_continuous_scale='Reds'
        )
        fig.update_layout(geo_scope="usa")
        st.plotly_chart(fig, use_container_width=True)
    
    with col2:
        # Top 10 states by churn rate
        top_churn_states = state_analysis.nlargest(10, 'Churn_Rate')
        fig = px.bar(
            top_churn_states,
            x='Churn_Rate',
            y='State',
            orientation='h',
            title="Top 10 States by Churn Rate",
            color='Churn_Rate',
            color_continuous_scale='Reds'
        )
        st.plotly_chart(fig, use_container_width=True)
    
    # Area code analysis
    st.subheader("πŸ“ž Area Code Analysis")
    
    area_code_analysis = df.groupby('Area code').agg({
        'Churn': ['count', 'mean'],
        'Total day charge': 'mean'
    }).round(2)
    
    area_code_analysis.columns = ['Total_Customers', 'Churn_Rate', 'Avg_Day_Charge']
    area_code_analysis = area_code_analysis.reset_index()
    
    fig = px.bar(
        area_code_analysis,
        x='Area code',
        y='Churn_Rate',
        title="Churn Rate by Area Code",
        color='Churn_Rate',
        color_continuous_scale='Reds',
        hover_data=['Total_Customers']
    )
    st.plotly_chart(fig, use_container_width=True)

def usage_patterns(df):
    st.header("πŸ“ž Usage Patterns Analysis")
    
    # Check if Churn column exists
    if 'Churn' not in df.columns:
        st.error("'Churn' column not found in the dataset.")
        return
    
    # Time-based usage analysis
    usage_metrics = ['Total day minutes', 'Total eve minutes', 'Total night minutes', 'Total intl minutes']
    
    col1, col2 = st.columns(2)
    
    with col1:
        # Usage patterns by churn
        usage_by_churn = df.groupby('Churn')[usage_metrics].mean()
        
        fig = go.Figure()
        for metric in usage_metrics:
            fig.add_trace(go.Bar(
                name=metric.replace('Total ', '').replace(' minutes', ''),
                x=['Retained', 'Churned'],
                y=[usage_by_churn.loc[False, metric], usage_by_churn.loc[True, metric]]
            ))
        
        fig.update_layout(
            title="Average Usage Patterns by Churn Status",
            xaxis_title="Customer Status",
            yaxis_title="Average Minutes",
            barmode='group'
        )
        st.plotly_chart(fig, use_container_width=True)
    
    with col2:
        # Call frequency analysis
        call_metrics = ['Total day calls', 'Total eve calls', 'Total night calls', 'Total intl calls']
        call_by_churn = df.groupby('Churn')[call_metrics].mean()
        
        fig = go.Figure()
        for metric in call_metrics:
            fig.add_trace(go.Bar(
                name=metric.replace('Total ', '').replace(' calls', ''),
                x=['Retained', 'Churned'],
                y=[call_by_churn.loc[False, metric], call_by_churn.loc[True, metric]]
            ))
        
        fig.update_layout(
            title="Average Call Frequency by Churn Status",
            xaxis_title="Customer Status",
            yaxis_title="Average Number of Calls",
            barmode='group'
        )
        st.plotly_chart(fig, use_container_width=True)
    
    # Customer service calls analysis
    st.subheader("🎧 Customer Service Analysis")
    
    col1, col2 = st.columns(2)
    
    with col1:
        cs_calls_churn = df.groupby('Customer service calls')['Churn'].agg(['count', 'sum', 'mean']).reset_index()
        cs_calls_churn['churn_rate'] = cs_calls_churn['mean'] * 100
        
        fig = px.bar(
            cs_calls_churn,
            x='Customer service calls',
            y='churn_rate',
            title="Churn Rate by Number of Customer Service Calls",
            color='churn_rate',
            color_continuous_scale='Reds',
            hover_data=['count']
        )
        st.plotly_chart(fig, use_container_width=True)
    
    with col2:
        # Distribution of customer service calls
        fig = px.histogram(
            df,
            x='Customer service calls',
            color='Churn',
            title="Distribution of Customer Service Calls",
            color_discrete_sequence=['lightgreen', 'lightcoral']
        )
        st.plotly_chart(fig, use_container_width=True)

def revenue_analysis(df):
    st.header("πŸ’° Revenue Analysis")
    
    # Check if Churn column exists
    if 'Churn' not in df.columns:
        st.error("'Churn' column not found in the dataset.")
        return
    
    # Calculate total revenue per customer
    df['Total_Revenue'] = (df['Total day charge'] + df['Total eve charge'] + 
                          df['Total night charge'] + df['Total intl charge'])
    
    col1, col2 = st.columns(2)
    
    with col1:
        # Revenue by churn status
        revenue_by_churn = df.groupby('Churn')['Total_Revenue'].agg(['mean', 'median', 'std']).round(2)
        
        fig = px.bar(
            x=['Retained', 'Churned'],
            y=[revenue_by_churn.loc[False, 'mean'], revenue_by_churn.loc[True, 'mean']],
            title="Average Revenue by Churn Status",
            color=['Retained', 'Churned'],
            color_discrete_sequence=['lightgreen', 'lightcoral']
        )
        fig.update_layout(yaxis_title="Average Revenue ($)")
        st.plotly_chart(fig, use_container_width=True)
    
    with col2:
        # Revenue distribution
        fig = px.box(
            df,
            x='Churn',
            y='Total_Revenue',
            title="Revenue Distribution by Churn Status",
            color='Churn',
            color_discrete_sequence=['lightgreen', 'lightcoral']
        )
        st.plotly_chart(fig, use_container_width=True)
    
    # Revenue breakdown analysis
    st.subheader("πŸ“Š Revenue Breakdown")
    
    revenue_components = ['Total day charge', 'Total eve charge', 'Total night charge', 'Total intl charge']
    
    col1, col2 = st.columns(2)
    
    with col1:
        # Average revenue components
        avg_components = df[revenue_components].mean()
        
        fig = px.pie(
            values=avg_components.values,
            names=[comp.replace('Total ', '').replace(' charge', '') for comp in revenue_components],
            title="Average Revenue Composition"
        )
        st.plotly_chart(fig, use_container_width=True)
    
    with col2:
        # Revenue components by churn
        components_by_churn = df.groupby('Churn')[revenue_components].mean()
        
        fig = go.Figure()
        for component in revenue_components:
            fig.add_trace(go.Bar(
                name=component.replace('Total ', '').replace(' charge', ''),
                x=['Retained', 'Churned'],
                y=[components_by_churn.loc[False, component], components_by_churn.loc[True, component]]
            ))
        
        fig.update_layout(
            title="Revenue Components by Churn Status",
            xaxis_title="Customer Status",
            yaxis_title="Average Charge ($)",
            barmode='group'
        )
        st.plotly_chart(fig, use_container_width=True)

def correlation_analysis(df):
    st.header("πŸ”— Correlation Analysis")
    
    # Check if Churn column exists
    if 'Churn' not in df.columns:
        st.error("'Churn' column not found in the dataset.")
        return
    
    # Select numerical columns for correlation
    numerical_cols = df.select_dtypes(include=[np.number]).columns.tolist()
    if 'Dataset' in numerical_cols:
        numerical_cols.remove('Dataset')
    
    # Convert boolean to numerical for correlation
    df_corr = df.copy()
    df_corr['Churn'] = df_corr['Churn'].astype(int)
    df_corr['International plan'] = (df_corr['International plan'] == 'Yes').astype(int)
    df_corr['Voice mail plan'] = (df_corr['Voice mail plan'] == 'Yes').astype(int)
    
    # Add converted columns to numerical_cols for correlation
    correlation_cols = numerical_cols.copy()
    if 'Churn' not in correlation_cols:
        correlation_cols.append('Churn')
    if 'International plan' in df_corr.columns and 'International plan' not in correlation_cols:
        correlation_cols.append('International plan')
    if 'Voice mail plan' in df_corr.columns and 'Voice mail plan' not in correlation_cols:
        correlation_cols.append('Voice mail plan')
    
    # Calculate correlation matrix
    corr_matrix = df_corr[correlation_cols].corr()
    
    col1, col2 = st.columns(2)
    
    with col1:
        # Correlation heatmap
        fig = px.imshow(
            corr_matrix,
            title="Feature Correlation Heatmap",
            color_continuous_scale='RdBu_r',
            aspect="auto"
        )
        fig.update_layout(width=600, height=600)
        st.plotly_chart(fig, use_container_width=True)
    
    with col2:
        # Correlation with churn
        if 'Churn' in corr_matrix.columns:
            churn_corr = corr_matrix['Churn'].abs().sort_values(ascending=False)[1:]  # Exclude self-correlation
            
            fig = px.bar(
                x=churn_corr.values,
                y=churn_corr.index,
                orientation='h',
                title="Features Most Correlated with Churn",
                color=churn_corr.values,
                color_continuous_scale='Reds'
            )
            st.plotly_chart(fig, use_container_width=True)
        else:
            st.error("Churn column not found in correlation matrix.")
    
    # Top correlations
    st.subheader("πŸ” Key Correlations")
    
    if 'Churn' in corr_matrix.columns:
        # Find top positive and negative correlations with churn
        churn_corr_full = corr_matrix['Churn'].sort_values(ascending=False)
        
        col1, col2 = st.columns(2)
        
        with col1:
            st.write("**Top Positive Correlations with Churn:**")
            top_positive = churn_corr_full[churn_corr_full > 0][1:6]  # Top 5, excluding self
            if len(top_positive) > 0:
                for feature, corr in top_positive.items():
                    st.write(f"β€’ {feature}: {corr:.3f}")
            else:
                st.write("No positive correlations found.")
        
        with col2:
            st.write("**Top Negative Correlations with Churn:**")
            top_negative = churn_corr_full[churn_corr_full < 0][-5:]  # Bottom 5
            if len(top_negative) > 0:
                for feature, corr in top_negative.items():
                    st.write(f"β€’ {feature}: {corr:.3f}")
            else:
                st.write("No negative correlations found.")
    else:
        st.warning("Cannot display correlation insights without Churn column in correlation matrix.")

def advanced_insights(df):
    st.header("πŸ“Š Advanced Insights")
    
    # Check if Churn column exists
    if 'Churn' not in df.columns:
        st.error("'Churn' column not found in the dataset.")
        return
    
    # Customer segments analysis
    st.subheader("πŸ‘₯ Customer Segmentation")
    
    # Calculate total usage and revenue
    df['Total_Usage'] = (df['Total day minutes'] + df['Total eve minutes'] + 
                        df['Total night minutes'] + df['Total intl minutes'])
    df['Total_Revenue'] = (df['Total day charge'] + df['Total eve charge'] + 
                          df['Total night charge'] + df['Total intl charge'])
    
    # Create usage vs revenue scatter plot
    fig = px.scatter(
        df,
        x='Total_Usage',
        y='Total_Revenue',
        color='Churn',
        title="Customer Segmentation: Usage vs Revenue",
        labels={'Total_Usage': 'Total Usage (minutes)', 'Total_Revenue': 'Total Revenue ($)'},
        color_discrete_sequence=['lightgreen', 'lightcoral'],
        opacity=0.6
    )
    st.plotly_chart(fig, use_container_width=True)
    
    # High-risk customer identification
    st.subheader("⚠️ High-Risk Customer Analysis")
    
    # Identify patterns in churned customers
    churned_customers = df[df['Churn'] == True]
    
    col1, col2 = st.columns(2)
    
    with col1:
        # Customer service calls for churned customers
        cs_calls_dist = churned_customers['Customer service calls'].value_counts().sort_index()
        
        fig = px.bar(
            x=cs_calls_dist.index,
            y=cs_calls_dist.values,
            title="Customer Service Calls Distribution (Churned Customers)",
            labels={'x': 'Number of CS Calls', 'y': 'Number of Customers'},
            color=cs_calls_dist.values,
            color_continuous_scale='Reds'
        )
        st.plotly_chart(fig, use_container_width=True)
    
    with col2:
        # Account length distribution for churned customers
        fig = px.histogram(
            churned_customers,
            x='Account length',
            title="Account Length Distribution (Churned Customers)",
            color_discrete_sequence=['lightcoral']
        )
        st.plotly_chart(fig, use_container_width=True)
    
    # Plan analysis
    st.subheader("πŸ“‹ Plan Analysis")
    
    plan_analysis = df.groupby(['International plan', 'Voice mail plan']).agg({
        'Churn': ['count', 'sum', 'mean']
    }).round(3)
    
    plan_analysis.columns = ['Total_Customers', 'Churned_Customers', 'Churn_Rate']
    plan_analysis = plan_analysis.reset_index()
    plan_analysis['Plan_Combination'] = (plan_analysis['International plan'] + ' Intl, ' + 
                                        plan_analysis['Voice mail plan'] + ' VM')
    
    fig = px.bar(
        plan_analysis,
        x='Plan_Combination',
        y='Churn_Rate',
        title="Churn Rate by Plan Combinations",
        color='Churn_Rate',
        color_continuous_scale='Reds',
        hover_data=['Total_Customers']
    )
    fig.update_xaxes(tickangle=45)
    st.plotly_chart(fig, use_container_width=True)
    
    # Key insights summary
    st.subheader("πŸ’‘ Key Insights Summary")
    
    try:
        insights = []
        
        # Overall churn rate
        if 'Churn' in df.columns:
            churn_rate = (df['Churn'] == True).mean() * 100
            insights.append(f"πŸ“ˆ Overall churn rate: {churn_rate:.1f}%")
        
        # Customer service calls analysis
        if 'Customer service calls' in df.columns and 'Churn' in df.columns:
            high_service_calls = df[df['Customer service calls'] >= 4]
            if len(high_service_calls) > 0:
                high_cs_churn_rate = high_service_calls['Churn'].mean() * 100
                insights.append(f"πŸ“ž Customers with 4+ service calls have {high_cs_churn_rate:.1f}% churn rate")
        
        # International plan analysis
        if 'International plan' in df.columns and 'Churn' in df.columns:
            intl_customers = df[df['International plan'] == 'Yes']
            if len(intl_customers) > 0:
                intl_churn_rate = intl_customers['Churn'].mean() * 100
                insights.append(f"🌍 International plan customers have {intl_churn_rate:.1f}% churn rate")
        
        # Voice mail plan analysis
        if 'Voice mail plan' in df.columns and 'Churn' in df.columns:
            vm_customers = df[df['Voice mail plan'] == 'Yes']
            if len(vm_customers) > 0:
                vm_churn_rate = vm_customers['Churn'].mean() * 100
                insights.append(f"πŸ“§ Voice mail plan customers have {vm_churn_rate:.1f}% churn rate")
        
        # Revenue analysis
        if 'Total_Revenue' in df.columns and 'Churn' in df.columns:
            churned_customers = df[df['Churn'] == True]
            if len(churned_customers) > 0:
                avg_revenue_churned = churned_customers['Total_Revenue'].mean()
                insights.append(f"πŸ’° Average revenue per churned customer: ${avg_revenue_churned:.2f}")
        
        # Account length analysis
        if 'Account length' in df.columns and 'Churn' in df.columns:
            churned_customers = df[df['Churn'] == True]
            if len(churned_customers) > 0:
                avg_account_length = churned_customers['Account length'].mean()
                insights.append(f"⏰ Average account length of churned customers: {avg_account_length:.0f} days")
        
        # Display insights
        for insight in insights:
            st.info(insight)
            
        if not insights:
            st.warning("No insights could be generated due to missing required columns.")
            
    except Exception as e:
        st.error(f"Error generating insights: {str(e)}")
        st.warning("Please check that all required columns are present in your dataset.")

if __name__ == "__main__":
    main()