FernandezUNB commited on
Commit
3ff929c
·
verified ·
1 Parent(s): b75feac

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +110 -82
app.py CHANGED
@@ -39,7 +39,7 @@ class ConsumerComplaintAnalyzer:
39
  if file_obj is None:
40
  return None, {}
41
  try:
42
- df_preview = pd.read_csv(file_obj.name, sep='\t').head()
43
  df_full = pd.read_csv(file_obj.name, sep='\t')
44
 
45
  stats = {
@@ -109,7 +109,7 @@ class ConsumerComplaintAnalyzer:
109
  def create_complaint_distribution(self):
110
  """Cria gráfico de distribuição de queixas"""
111
  if self.df is None:
112
- return None
113
 
114
  complain_counts = self.df['Complain'].value_counts()
115
 
@@ -146,14 +146,17 @@ class ConsumerComplaintAnalyzer:
146
 
147
  def create_correlation_heatmap(self, selected_variables):
148
  """Cria heatmap de correlação"""
149
- if self.df_processed is None or not selected_variables:
150
- return None
 
 
 
151
 
152
  # Verificar quais variáveis existem no dataframe
153
  available_vars = [var for var in selected_variables if var in self.df_processed.columns]
154
 
155
  if not available_vars:
156
- return None
157
 
158
  corr_matrix = self.df_processed[available_vars].corr()
159
 
@@ -163,13 +166,16 @@ class ConsumerComplaintAnalyzer:
163
  color_continuous_scale='RdBu_r',
164
  title="Matriz de Correlação")
165
 
166
- fig.update_layout(height=600)
167
  return fig
168
 
169
  def create_bivariate_analysis(self, variable):
170
  """Análise bivariada entre uma variável e queixas"""
171
- if self.df_processed is None or variable not in self.df_processed.columns:
172
- return None
 
 
 
173
 
174
  fig = px.box(self.df_processed, x='Complain', y=variable,
175
  color='Complain',
@@ -179,6 +185,17 @@ class ConsumerComplaintAnalyzer:
179
  fig.update_layout(height=400)
180
  return fig
181
 
 
 
 
 
 
 
 
 
 
 
 
182
  def train_models(self, selected_features, test_size, use_smote):
183
  """Treina os modelos de machine learning"""
184
  try:
@@ -229,6 +246,8 @@ class ConsumerComplaintAnalyzer:
229
  # Armazenar para uso posterior
230
  self.X_test_scaled = X_test_scaled
231
  self.y_test = y_test
 
 
232
 
233
  # Balanceamento com SMOTE
234
  if use_smote:
@@ -241,11 +260,12 @@ class ConsumerComplaintAnalyzer:
241
  models = {
242
  'Regressão Logística': LogisticRegression(random_state=42, max_iter=1000),
243
  'Árvore de Decisão': DecisionTreeClassifier(random_state=42, max_depth=10),
244
- 'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42),
245
- 'Gradient Boosting': GradientBoostingClassifier(n_estimators=100, random_state=42)
246
  }
247
 
248
  results = []
 
249
 
250
  for name, model in models.items():
251
  model.fit(X_train_balanced, y_train_balanced)
@@ -287,6 +307,9 @@ class ConsumerComplaintAnalyzer:
287
  'ROC-AUC': round(roc_auc, 4)
288
  })
289
 
 
 
 
290
  # Importância das features (para modelos que suportam)
291
  if hasattr(model, 'feature_importances_'):
292
  self.feature_importance = pd.DataFrame({
@@ -295,10 +318,10 @@ class ConsumerComplaintAnalyzer:
295
  }).sort_values('Importance', ascending=False)
296
 
297
  self.results_df = pd.DataFrame(results)
298
- self.models = models
299
  self.is_trained = True
300
 
301
- return "✅ Modelos treinados com sucesso!"
 
302
 
303
  except Exception as e:
304
  return f"❌ Erro no treinamento: {str(e)}"
@@ -306,7 +329,7 @@ class ConsumerComplaintAnalyzer:
306
  def create_model_comparison(self):
307
  """Cria gráfico de comparação de modelos"""
308
  if self.results_df is None:
309
- return None
310
 
311
  fig = go.Figure()
312
 
@@ -337,14 +360,7 @@ class ConsumerComplaintAnalyzer:
337
  def create_feature_importance(self):
338
  """Cria gráfico de importância das features"""
339
  if self.feature_importance is None:
340
- # Criar um gráfico placeholder
341
- fig = go.Figure()
342
- fig.add_annotation(text="Treine os modelos primeiro para ver a importância das features",
343
- xref="paper", yref="paper",
344
- x=0.5, y=0.5, xanchor='center', yanchor='middle',
345
- showarrow=False)
346
- fig.update_layout(height=400)
347
- return fig
348
 
349
  top_features = self.feature_importance.head(15)
350
 
@@ -363,15 +379,8 @@ class ConsumerComplaintAnalyzer:
363
 
364
  def create_roc_curves(self):
365
  """Cria curvas ROC para todos os modelos"""
366
- if not self.is_trained or self.X_test_scaled is None:
367
- # Criar um gráfico placeholder
368
- fig = go.Figure()
369
- fig.add_annotation(text="Treine os modelos primeiro para ver as curvas ROC",
370
- xref="paper", yref="paper",
371
- x=0.5, y=0.5, xanchor='center', yanchor='middle',
372
- showarrow=False)
373
- fig.update_layout(height=400)
374
- return fig
375
 
376
  fig = go.Figure()
377
 
@@ -384,9 +393,8 @@ class ConsumerComplaintAnalyzer:
384
  ))
385
 
386
  # Para cada modelo, adicionar curva ROC
387
- for name, model in self.models.items():
388
- if hasattr(model, 'predict_proba'):
389
- y_proba = model.predict_proba(self.X_test_scaled)[:, 1]
390
  fpr, tpr, _ = roc_curve(self.y_test, y_proba)
391
  roc_auc = roc_auc_score(self.y_test, y_proba)
392
 
@@ -425,7 +433,7 @@ def create_analysis_interface():
425
  load_status = gr.Textbox(label="Status", interactive=False)
426
 
427
  with gr.Column():
428
- data_preview = gr.Dataframe(label="Pré-visualização dos Dados", max_rows=5)
429
  stats_display = gr.JSON(label="Estatísticas do Dataset")
430
 
431
  # Conectar eventos
@@ -444,32 +452,35 @@ def create_analysis_interface():
444
  with gr.TabItem("📈 Análise Exploratória"):
445
  with gr.Row():
446
  with gr.Column():
447
- dist_plot = gr.Plot(label="Distribuição de Queixas")
448
- update_dist_btn = gr.Button("🔄 Atualizar Gráfico de Distribuição")
 
449
 
450
  with gr.Column():
 
451
  corr_vars = gr.CheckboxGroup(
452
  choices=['Age', 'Income', 'Total_Spent', 'Total_Purchases',
453
  'Customer_Years', 'Total_Children', 'Average_Purchase_Value',
454
  'Recency', 'NumWebVisitsMonth', 'Total_Campaigns_Accepted'],
455
- label="Variáveis para Correlação",
456
  value=['Age', 'Income', 'Total_Spent', 'Total_Purchases',
457
  'Customer_Years', 'Total_Children', 'Average_Purchase_Value', 'Complain']
458
  )
459
- corr_plot = gr.Plot(label="Matriz de Correlação")
460
- update_corr_btn = gr.Button("🔄 Atualizar Correlações")
461
 
462
  with gr.Row():
463
  with gr.Column():
 
464
  bivariate_var = gr.Dropdown(
465
  choices=['Age', 'Income', 'Total_Spent', 'Total_Purchases',
466
  'Customer_Years', 'Total_Children', 'Average_Purchase_Value',
467
  'Recency', 'NumWebVisitsMonth'],
468
- label="Variável para Análise Bivariada",
469
  value='Income'
470
  )
471
- bivariate_plot = gr.Plot(label="Análise Bivariada")
472
- update_bivariate_btn = gr.Button("🔄 Atualizar Análise Bivariada")
473
 
474
  # Conectar botões
475
  update_dist_btn.click(
@@ -492,31 +503,35 @@ def create_analysis_interface():
492
  with gr.TabItem("🤖 Modelagem Preditiva"):
493
  with gr.Row():
494
  with gr.Column():
 
495
  feature_selection = gr.CheckboxGroup(
496
  choices=['Age', 'Income', 'Total_Spent', 'Total_Purchases',
497
  'Customer_Years', 'Total_Children', 'Average_Purchase_Value',
498
  'Recency', 'NumWebVisitsMonth', 'Total_Campaigns_Accepted'],
499
- label="Selecionar Features para o Modelo",
500
  value=['Age', 'Income', 'Total_Spent', 'Total_Purchases',
501
  'Customer_Years', 'Total_Children', 'Average_Purchase_Value',
502
  'Recency', 'NumWebVisitsMonth', 'Total_Campaigns_Accepted']
503
  )
504
 
505
- test_size = gr.Slider(10, 40, value=20, label="Tamanho do Teste (%)")
506
- use_smote = gr.Checkbox(value=True, label="Usar SMOTE para Balanceamento")
507
 
508
  train_btn = gr.Button("🎯 Treinar Modelos", variant="primary")
509
  train_status = gr.Textbox(label="Status do Treinamento")
510
 
511
  with gr.Column():
512
- model_results = gr.Dataframe(label="Resultados dos Modelos")
513
- model_comparison = gr.Plot(label="Comparação de Modelos")
 
514
 
515
  with gr.Row():
516
  with gr.Column():
517
- feature_importance_plot = gr.Plot(label="Importância das Features")
 
518
  with gr.Column():
519
- roc_plot = gr.Plot(label="Curvas ROC")
 
520
 
521
  # Conectar botão de treinamento
522
  train_btn.click(
@@ -548,22 +563,24 @@ def create_analysis_interface():
548
  with gr.TabItem("📋 Relatório e Insights"):
549
  with gr.Row():
550
  with gr.Column():
 
551
  insights_text = gr.Textbox(
552
- label="Principais Insights",
553
- lines=10,
554
  interactive=False
555
  )
556
 
557
- generate_insights_btn = gr.Button("💡 Gerar Insights")
558
 
559
  with gr.Column():
 
560
  recommendations = gr.Textbox(
561
- label="Recomendações Estratégicas",
562
- lines=10,
563
  interactive=False
564
  )
565
 
566
- generate_recommendations_btn = gr.Button("🎯 Gerar Recomendações")
567
 
568
  def generate_insights():
569
  if analyzer.df is None:
@@ -576,9 +593,10 @@ def create_analysis_interface():
576
 
577
  • **Total de Clientes Analisados:** {total_customers:,}
578
  • **Taxa de Queixas:** {complaint_rate:.2f}%
579
- • **Problema de Classificação:** {'Desbalanceado' if complaint_rate < 5 else 'Balanceado'}
 
580
 
581
- 🔍 **Padrões Identificados:**"""
582
 
583
  if analyzer.feature_importance is not None:
584
  top_features = analyzer.feature_importance.head(3)['Feature'].tolist()
@@ -586,40 +604,50 @@ def create_analysis_interface():
586
 
587
  if analyzer.results_df is not None:
588
  best_model = analyzer.results_df.loc[analyzer.results_df['ROC-AUC'].idxmax()]
589
- insights += f"\n• **Melhor Modelo:** {best_model['Modelo']} (AUC: {best_model['ROC-AUC']:.3f})"
 
590
 
591
- insights += "\n\n📈 **Interpretação:**"
592
- insights += "\n• Valores de AUC > 0.7 indicam bom poder preditivo"
593
- insights += "\n• Features importantes revelam padrões comportamentais"
594
- insights += "\n• Modelos ensemble geralmente performam melhor"
 
595
 
596
  return insights
597
 
598
  def generate_recommendations():
599
  return """🎯 **RECOMENDAÇÕES ESTRATÉGICAS:**
600
 
601
- 🚨 **Ações Imediatas:**
602
- • Implementar sistema de early warning para clientes de alto risco
603
- • Criar segmentação baseada nas variáveis mais importantes
604
- • Desenvolver campanhas proativas para grupos específicos
 
605
 
606
- 📈 **Otimizações de Longo Prazo:**
607
- • Integrar modelo preditivo ao CRM
608
- Estabelecer métricas de monitoramento contínuo
609
- Realizar treinamentos regulares da equipe
 
610
 
611
- 💡 **Sugestões Específicas:**
612
- • Monitorar clientes com alta recência
613
- • Acompanhar mudanças abruptas no padrão de gastos
614
- Desenvolver programas de fidelidade segmentados
615
- Implementar contato proativo para clientes de alto risco
 
 
 
 
 
 
 
 
 
 
 
 
616
 
617
- 📊 **Métricas de Sucesso:**
618
- • Redução na taxa de queixas
619
- • Aumento na satisfação do cliente
620
- • Melhoria no tempo de resposta
621
- ��� Otimização de recursos de atendimento"""
622
-
623
  generate_insights_btn.click(
624
  fn=generate_insights,
625
  outputs=[insights_text]
@@ -631,7 +659,7 @@ def create_analysis_interface():
631
  )
632
 
633
  gr.Markdown("---")
634
- gr.Markdown("**Desenvolvido para PPCA/UnB - AEDI - Tarefa 6**")
635
 
636
  return demo
637
 
 
39
  if file_obj is None:
40
  return None, {}
41
  try:
42
+ df_preview = pd.read_csv(file_obj.name, sep='\t').head(5)
43
  df_full = pd.read_csv(file_obj.name, sep='\t')
44
 
45
  stats = {
 
109
  def create_complaint_distribution(self):
110
  """Cria gráfico de distribuição de queixas"""
111
  if self.df is None:
112
+ return self._create_placeholder_plot("Carregue os dados primeiro")
113
 
114
  complain_counts = self.df['Complain'].value_counts()
115
 
 
146
 
147
  def create_correlation_heatmap(self, selected_variables):
148
  """Cria heatmap de correlação"""
149
+ if self.df_processed is None:
150
+ return self._create_placeholder_plot("Carregue os dados primeiro")
151
+
152
+ if not selected_variables:
153
+ return self._create_placeholder_plot("Selecione variáveis para análise")
154
 
155
  # Verificar quais variáveis existem no dataframe
156
  available_vars = [var for var in selected_variables if var in self.df_processed.columns]
157
 
158
  if not available_vars:
159
+ return self._create_placeholder_plot("Nenhuma variável válida selecionada")
160
 
161
  corr_matrix = self.df_processed[available_vars].corr()
162
 
 
166
  color_continuous_scale='RdBu_r',
167
  title="Matriz de Correlação")
168
 
169
+ fig.update_layout(height=500)
170
  return fig
171
 
172
  def create_bivariate_analysis(self, variable):
173
  """Análise bivariada entre uma variável e queixas"""
174
+ if self.df_processed is None:
175
+ return self._create_placeholder_plot("Carregue os dados primeiro")
176
+
177
+ if variable not in self.df_processed.columns:
178
+ return self._create_placeholder_plot(f"Variável '{variable}' não encontrada")
179
 
180
  fig = px.box(self.df_processed, x='Complain', y=variable,
181
  color='Complain',
 
185
  fig.update_layout(height=400)
186
  return fig
187
 
188
+ def _create_placeholder_plot(self, message):
189
+ """Cria um gráfico placeholder com mensagem"""
190
+ fig = go.Figure()
191
+ fig.add_annotation(text=message,
192
+ xref="paper", yref="paper",
193
+ x=0.5, y=0.5, xanchor='center', yanchor='middle',
194
+ showarrow=False,
195
+ font=dict(size=16))
196
+ fig.update_layout(height=400)
197
+ return fig
198
+
199
  def train_models(self, selected_features, test_size, use_smote):
200
  """Treina os modelos de machine learning"""
201
  try:
 
246
  # Armazenar para uso posterior
247
  self.X_test_scaled = X_test_scaled
248
  self.y_test = y_test
249
+ self.scaler = scaler
250
+ self.features_to_use = features_to_use
251
 
252
  # Balanceamento com SMOTE
253
  if use_smote:
 
260
  models = {
261
  'Regressão Logística': LogisticRegression(random_state=42, max_iter=1000),
262
  'Árvore de Decisão': DecisionTreeClassifier(random_state=42, max_depth=10),
263
+ 'Random Forest': RandomForestClassifier(n_estimators=100, random_state=42, max_depth=15),
264
+ 'Gradient Boosting': GradientBoostingClassifier(n_estimators=100, random_state=42, max_depth=5)
265
  }
266
 
267
  results = []
268
+ self.predictions = {}
269
 
270
  for name, model in models.items():
271
  model.fit(X_train_balanced, y_train_balanced)
 
307
  'ROC-AUC': round(roc_auc, 4)
308
  })
309
 
310
+ self.predictions[name] = (y_pred, y_proba)
311
+ self.models[name] = model
312
+
313
  # Importância das features (para modelos que suportam)
314
  if hasattr(model, 'feature_importances_'):
315
  self.feature_importance = pd.DataFrame({
 
318
  }).sort_values('Importance', ascending=False)
319
 
320
  self.results_df = pd.DataFrame(results)
 
321
  self.is_trained = True
322
 
323
+ best_model = self.results_df.loc[self.results_df['ROC-AUC'].idxmax()]
324
+ return f"✅ Modelos treinados com sucesso! Melhor modelo: {best_model['Modelo']} (AUC: {best_model['ROC-AUC']:.3f})"
325
 
326
  except Exception as e:
327
  return f"❌ Erro no treinamento: {str(e)}"
 
329
  def create_model_comparison(self):
330
  """Cria gráfico de comparação de modelos"""
331
  if self.results_df is None:
332
+ return self._create_placeholder_plot("Treine os modelos primeiro")
333
 
334
  fig = go.Figure()
335
 
 
360
  def create_feature_importance(self):
361
  """Cria gráfico de importância das features"""
362
  if self.feature_importance is None:
363
+ return self._create_placeholder_plot("Treine os modelos primeiro para ver a importância das features")
 
 
 
 
 
 
 
364
 
365
  top_features = self.feature_importance.head(15)
366
 
 
379
 
380
  def create_roc_curves(self):
381
  """Cria curvas ROC para todos os modelos"""
382
+ if not self.is_trained or not hasattr(self, 'predictions'):
383
+ return self._create_placeholder_plot("Treine os modelos primeiro para ver as curvas ROC")
 
 
 
 
 
 
 
384
 
385
  fig = go.Figure()
386
 
 
393
  ))
394
 
395
  # Para cada modelo, adicionar curva ROC
396
+ for name, (_, y_proba) in self.predictions.items():
397
+ if y_proba is not None:
 
398
  fpr, tpr, _ = roc_curve(self.y_test, y_proba)
399
  roc_auc = roc_auc_score(self.y_test, y_proba)
400
 
 
433
  load_status = gr.Textbox(label="Status", interactive=False)
434
 
435
  with gr.Column():
436
+ data_preview = gr.Dataframe(label="Pré-visualização dos Dados (Primeiras 5 linhas)")
437
  stats_display = gr.JSON(label="Estatísticas do Dataset")
438
 
439
  # Conectar eventos
 
452
  with gr.TabItem("📈 Análise Exploratória"):
453
  with gr.Row():
454
  with gr.Column():
455
+ gr.Markdown("### Distribuição de Queixas")
456
+ dist_plot = gr.Plot()
457
+ update_dist_btn = gr.Button("🔄 Atualizar Distribuição")
458
 
459
  with gr.Column():
460
+ gr.Markdown("### Análise de Correlação")
461
  corr_vars = gr.CheckboxGroup(
462
  choices=['Age', 'Income', 'Total_Spent', 'Total_Purchases',
463
  'Customer_Years', 'Total_Children', 'Average_Purchase_Value',
464
  'Recency', 'NumWebVisitsMonth', 'Total_Campaigns_Accepted'],
465
+ label="Selecione variáveis para análise de correlação:",
466
  value=['Age', 'Income', 'Total_Spent', 'Total_Purchases',
467
  'Customer_Years', 'Total_Children', 'Average_Purchase_Value', 'Complain']
468
  )
469
+ corr_plot = gr.Plot()
470
+ update_corr_btn = gr.Button("🔄 Atualizar Correlação")
471
 
472
  with gr.Row():
473
  with gr.Column():
474
+ gr.Markdown("### Análise Bivariada")
475
  bivariate_var = gr.Dropdown(
476
  choices=['Age', 'Income', 'Total_Spent', 'Total_Purchases',
477
  'Customer_Years', 'Total_Children', 'Average_Purchase_Value',
478
  'Recency', 'NumWebVisitsMonth'],
479
+ label="Selecione uma variável para análise:",
480
  value='Income'
481
  )
482
+ bivariate_plot = gr.Plot()
483
+ update_bivariate_btn = gr.Button("🔄 Atualizar Análise")
484
 
485
  # Conectar botões
486
  update_dist_btn.click(
 
503
  with gr.TabItem("🤖 Modelagem Preditiva"):
504
  with gr.Row():
505
  with gr.Column():
506
+ gr.Markdown("### Configuração do Modelo")
507
  feature_selection = gr.CheckboxGroup(
508
  choices=['Age', 'Income', 'Total_Spent', 'Total_Purchases',
509
  'Customer_Years', 'Total_Children', 'Average_Purchase_Value',
510
  'Recency', 'NumWebVisitsMonth', 'Total_Campaigns_Accepted'],
511
+ label="Selecione features para o modelo:",
512
  value=['Age', 'Income', 'Total_Spent', 'Total_Purchases',
513
  'Customer_Years', 'Total_Children', 'Average_Purchase_Value',
514
  'Recency', 'NumWebVisitsMonth', 'Total_Campaigns_Accepted']
515
  )
516
 
517
+ test_size = gr.Slider(10, 40, value=20, label="Tamanho do conjunto de teste (%)")
518
+ use_smote = gr.Checkbox(value=True, label="Usar SMOTE para balanceamento de dados")
519
 
520
  train_btn = gr.Button("🎯 Treinar Modelos", variant="primary")
521
  train_status = gr.Textbox(label="Status do Treinamento")
522
 
523
  with gr.Column():
524
+ gr.Markdown("### Resultados dos Modelos")
525
+ model_results = gr.Dataframe(label="Métricas de Desempenho")
526
+ model_comparison = gr.Plot(label="Comparação Visual dos Modelos")
527
 
528
  with gr.Row():
529
  with gr.Column():
530
+ gr.Markdown("### Importância das Features")
531
+ feature_importance_plot = gr.Plot()
532
  with gr.Column():
533
+ gr.Markdown("### Curvas ROC")
534
+ roc_plot = gr.Plot()
535
 
536
  # Conectar botão de treinamento
537
  train_btn.click(
 
563
  with gr.TabItem("📋 Relatório e Insights"):
564
  with gr.Row():
565
  with gr.Column():
566
+ gr.Markdown("### Insights da Análise")
567
  insights_text = gr.Textbox(
568
+ label="Principais Descobertas",
569
+ lines=12,
570
  interactive=False
571
  )
572
 
573
+ generate_insights_btn = gr.Button("💡 Gerar Insights", variant="secondary")
574
 
575
  with gr.Column():
576
+ gr.Markdown("### Recomendações Estratégicas")
577
  recommendations = gr.Textbox(
578
+ label="Ações Recomendadas",
579
+ lines=12,
580
  interactive=False
581
  )
582
 
583
+ generate_recommendations_btn = gr.Button("🎯 Gerar Recomendações", variant="secondary")
584
 
585
  def generate_insights():
586
  if analyzer.df is None:
 
593
 
594
  • **Total de Clientes Analisados:** {total_customers:,}
595
  • **Taxa de Queixas:** {complaint_rate:.2f}%
596
+ • **Problema de Classificação:** {'DESBALANCEADO' if complaint_rate < 5 else 'Balanceado'}
597
+ • **Complexidade:** {'Alta (múltiplos fatores)' if complaint_rate > 1 else 'Média'}
598
 
599
+ 🔍 **PADRÕES IDENTIFICADOS:**"""
600
 
601
  if analyzer.feature_importance is not None:
602
  top_features = analyzer.feature_importance.head(3)['Feature'].tolist()
 
604
 
605
  if analyzer.results_df is not None:
606
  best_model = analyzer.results_df.loc[analyzer.results_df['ROC-AUC'].idxmax()]
607
+ insights += f"\n• **Melhor Modelo:** {best_model['Modelo']}"
608
+ insights += f"\n• **Desempenho (AUC):** {best_model['ROC-AUC']:.3f}"
609
 
610
+ insights += "\n\n📈 **INTERPRETAÇÃO TÉCNICA:**"
611
+ insights += "\n• AUC > 0.7: Bom poder preditivo"
612
+ insights += "\n• AUC > 0.8: Excelente poder preditivo"
613
+ insights += "\n• Features importantes indicam padrões comportamentais relevantes"
614
+ insights += "\n• Modelos ensemble geralmente performam melhor em dados complexos"
615
 
616
  return insights
617
 
618
  def generate_recommendations():
619
  return """🎯 **RECOMENDAÇÕES ESTRATÉGICAS:**
620
 
621
+ 🚨 **AÇÕES IMEDIATAS (0-30 dias):**
622
+ • Implementar sistema de alerta precoce para clientes de alto risco
623
+ • Criar segmentação baseada nas variáveis mais importantes identificadas
624
+ • Desenvolver campanhas proativas direcionadas a grupos específicos
625
+ • Estabelecer protocolo de contato proativo para clientes com alta probabilidade de queixa
626
 
627
+ 📈 **OTIMIZAÇÕES DE LONGO PRAZO (30-90 dias):**
628
+ • Integrar modelo preditivo ao sistema de CRM existente
629
+ Implementar dashboard de monitoramento em tempo real
630
+ Desenvolver programa de treinamento para equipes de atendimento
631
+ • Criar fluxo de trabalho automatizado para casos de alto risco
632
 
633
+ 💡 **SUGESTÕES OPERACIONAIS ESPECÍFICAS:**
634
+ • Monitorar continuamente clientes com alta recência de compra
635
+ • Acompanhar mudanças abruptas no padrão de gastos dos clientes
636
+ Implementar programas de fidelidade segmentados por perfil de risco
637
+ Estabelecer métricas de satisfação pós-atendimento
638
+
639
+ 📊 **MÉTRICAS DE SUCESSO:**
640
+ • Redução de 20% na taxa de queixas em 6 meses
641
+ • Aumento de 15% na satisfação do cliente (NPS)
642
+ • Melhoria de 30% no tempo de resposta a queixas
643
+ • Redução de 25% nos custos com resolução reativa de problemas
644
+
645
+ 🔧 **IMPLEMENTAÇÃO TÉCNICA:**
646
+ • Revisar e atualizar modelos trimestralmente
647
+ • Validar performance com novos dados
648
+ • Expandir análise para outros indicadores (churn, lifetime value)
649
+ • Incorporar feedback dos clientes no refinamento do modelo"""
650
 
 
 
 
 
 
 
651
  generate_insights_btn.click(
652
  fn=generate_insights,
653
  outputs=[insights_text]
 
659
  )
660
 
661
  gr.Markdown("---")
662
+ gr.Markdown("**Desenvolvido para PPCA/UnB - AEDI - Tarefa 6** | *Análise Preditiva de Queixas de Consumidores*")
663
 
664
  return demo
665