FernandezUNB commited on
Commit
f94c886
·
verified ·
1 Parent(s): 242e930

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +384 -103
app.py CHANGED
@@ -22,8 +22,13 @@ class HousePricePredictor:
22
  self.scaler = None
23
  self.df = None
24
  self.is_trained = False
25
- self.selected_features = []
26
  self._data_loaded = False
 
 
 
 
 
27
 
28
  def load_data(self):
29
  """Carrega dados do arquivo kc_house_data.csv"""
@@ -37,6 +42,13 @@ class HousePricePredictor:
37
  # Limpeza básica dos dados
38
  self._clean_data()
39
 
 
 
 
 
 
 
 
40
  self._data_loaded = True
41
  print(f"✅ Dados carregados: {self.df.shape[0]} imóveis × {self.df.shape[1]} características")
42
  return f"✅ Dados carregados: {self.df.shape[0]} imóveis × {self.df.shape[1]} características"
@@ -75,17 +87,6 @@ class HousePricePredictor:
75
  numeric_features.remove('price')
76
  return numeric_features
77
 
78
- def get_top_features_by_correlation(self, n=6):
79
- """Retorna as top n features por correlação com price"""
80
- if self.df is None:
81
- return []
82
- correlations = self.df.corr()['price'].abs().sort_values(ascending=False)
83
- top_features = []
84
- for feature in correlations.index:
85
- if feature != 'price' and len(top_features) < n:
86
- top_features.append(feature)
87
- return top_features
88
-
89
  def get_dataset_stats(self):
90
  """Retorna estatísticas do dataset para display seguro"""
91
  if self.df is not None:
@@ -158,8 +159,7 @@ class HousePricePredictor:
158
  'rmse_test': rmse_test,
159
  'mae_test': mae_test,
160
  'top_features': coeficientes.to_dict('records'),
161
- 'selected_features': selected_features,
162
- 'n_features': len(selected_features)
163
  }
164
 
165
  except Exception as e:
@@ -198,59 +198,50 @@ print("🚀 Iniciando aplicação...")
198
  initial_message = predictor.load_data()
199
  initial_features = predictor.get_numeric_features()
200
  dataset_stats = predictor.get_dataset_stats()
201
- top_features = predictor.get_top_features_by_correlation(6)
202
  print(f"📊 Features disponíveis: {initial_features}")
203
 
204
  # Funções para a interface Gradio
205
- def create_feature_checkboxes():
206
- """Cria os checkboxes de features"""
 
207
  features = predictor.get_numeric_features()
208
- checkboxes = []
209
 
 
 
210
  if features and predictor.df is not None:
 
211
  correlations = predictor.df.corr()['price'].abs().sort_values(ascending=False)
212
 
 
 
 
 
 
 
213
  for feature in features:
214
  corr_value = correlations.get(feature, 0)
215
- is_selected = feature in top_features
216
-
217
- checkboxes.append(
218
  gr.Checkbox(
219
  label=f"{feature} (corr: {corr_value:.3f})",
220
- value=is_selected,
221
  info=f"Média: {predictor.df[feature].mean():.1f}"
222
  )
223
  )
224
 
225
- return checkboxes
226
 
227
- def update_selected_features_display(*checkbox_values):
228
- """Atualiza o display das features selecionadas"""
229
  features = predictor.get_numeric_features()
230
  selected = []
231
-
232
  for i, is_checked in enumerate(checkbox_values):
233
  if is_checked and i < len(features):
234
  selected.append(features[i])
235
-
236
- if selected:
237
- features_text = "**Features selecionadas:**\n" + "\n".join([f"• {feat}" for feat in selected])
238
- features_text += f"\n\n**Total:** {len(selected)} features"
239
- return features_text, gr.update(visible=True)
240
- else:
241
- return "❌ Nenhuma feature selecionada", gr.update(visible=False)
242
 
243
  def train_model_action(*checkbox_values):
244
  """Treina o modelo com features selecionadas"""
245
- features = predictor.get_numeric_features()
246
- selected_features = []
247
-
248
- for i, is_checked in enumerate(checkbox_values):
249
- if is_checked and i < len(features):
250
- selected_features.append(features[i])
251
-
252
- if not selected_features:
253
- return "❌ Nenhuma feature selecionada. Selecione pelo menos uma feature.", None, gr.update(visible=False), gr.update(visible=False)
254
 
255
  success, result = predictor.train_model(selected_features)
256
 
@@ -264,19 +255,153 @@ def train_model_action(*checkbox_values):
264
  - **RMSE Teste**: ${result['rmse_test']:,.0f}
265
  - **MAE Teste**: ${result['mae_test']:,.0f}
266
 
267
- ### 🎯 Features por Importância ({result['n_features']} features):
268
  """
269
 
270
  for i, feature in enumerate(result['top_features']):
271
  direction = "📈 Aumenta preço" if feature['Coeficiente'] > 0 else "📉 Diminui preço"
272
  metrics_text += f"\n{i+1}. **{feature['Feature']}**: {feature['Coeficiente']:.4f} ({direction})"
273
 
274
- return metrics_text, result, gr.update(visible=True), gr.update(visible=True)
 
 
275
  else:
276
- return result, None, gr.update(visible=False), gr.update(visible=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
 
278
  def create_prediction_inputs(metrics_result):
279
- """Cria inputs para previsão baseado nas features selecionadas"""
280
  if metrics_result is None or 'selected_features' not in metrics_result:
281
  return []
282
 
@@ -344,82 +469,238 @@ def predict_price_action(*feature_values):
344
  except Exception as e:
345
  return f"❌ Erro na previsão: {str(e)}", None
346
 
347
- # Interface Gradio simplificada com tudo em uma aba
348
- with gr.Blocks(title="🏠 Cálculo de Preço - King County Dataset Real") as demo:
 
 
 
 
 
 
 
 
 
 
 
349
  gr.Markdown(
350
  """
351
- # 🏠 Cálculo de Preços de Imóveis - King County
352
- ## 📊 Selecione Features, Treine Modelo e Faça Previsões
 
 
 
 
353
  """
354
  )
355
 
356
  # Status inicial
357
  initial_status = gr.Markdown(f"**Status:** {initial_message}")
 
358
 
359
- with gr.Row():
360
- with gr.Column(scale=2):
361
- gr.Markdown("### 📋 1. Selecione as Features para o Modelo")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
 
363
  # Criar checkboxes
364
- feature_checkboxes = create_feature_checkboxes()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
 
366
- with gr.Column(scale=1):
367
- gr.Markdown("### 📊 Features Selecionadas:")
368
- selected_features_display = gr.Markdown()
369
- train_btn = gr.Button("🚀 Treinar Modelo", variant="primary", size="lg")
370
-
371
- # Atualizar display quando checkboxes mudam
372
- for checkbox in feature_checkboxes:
373
- checkbox.change(
374
- update_selected_features_display,
375
- inputs=feature_checkboxes,
376
- outputs=[selected_features_display, train_btn]
377
  )
378
-
379
- # Resultados do treinamento
380
- train_output = gr.Markdown()
381
- metrics_display = gr.JSON(label="Métricas Detalhadas", visible=False)
382
-
383
- # Seção de previsão (inicialmente oculta)
384
- with gr.Column(visible=False) as prediction_section:
385
- gr.Markdown("### 💰 2. Faça Previsões de Preço")
386
 
387
  with gr.Row():
388
  with gr.Column():
389
- gr.Markdown("#### 🎯 Configure as Características do Imóvel")
390
- prediction_inputs = gr.Column()
391
- predict_btn = gr.Button("🎯 Calcular Preço", variant="primary", size="lg")
392
 
393
  with gr.Column():
394
- gr.Markdown("#### 📊 Resultado da Previsão")
395
- prediction_output = gr.Markdown("Preencha os valores e clique em 'Calcular Preço'")
396
- price_result = gr.Number(
397
- label="💵 Preço Previsto",
398
- visible=False,
399
- elem_classes="price-display"
 
 
 
 
 
 
 
400
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
 
402
- # Eventos
403
- train_btn.click(
404
- train_model_action,
405
- inputs=feature_checkboxes,
406
- outputs=[train_output, metrics_display, metrics_display, prediction_section]
407
- )
408
-
409
- metrics_display.change(
410
- create_prediction_inputs,
411
- inputs=[metrics_display],
412
- outputs=[prediction_inputs]
413
- )
414
-
415
- predict_btn.click(
416
- predict_price_action,
417
- inputs=[prediction_inputs],
418
- outputs=[prediction_output, price_result]
419
- ).then(
420
- lambda: gr.update(visible=True),
421
- outputs=[price_result]
422
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
423
 
424
  if __name__ == "__main__":
425
  demo.launch()
 
22
  self.scaler = None
23
  self.df = None
24
  self.is_trained = False
25
+ self.selected_features = None
26
  self._data_loaded = False
27
+ self.stats = {
28
+ 'n_imoveis': 0,
29
+ 'n_caracteristicas': 0,
30
+ 'preco_medio': 0
31
+ }
32
 
33
  def load_data(self):
34
  """Carrega dados do arquivo kc_house_data.csv"""
 
42
  # Limpeza básica dos dados
43
  self._clean_data()
44
 
45
+ # Atualizar estatísticas
46
+ self.stats = {
47
+ 'n_imoveis': self.df.shape[0],
48
+ 'n_caracteristicas': self.df.shape[1],
49
+ 'preco_medio': self.df['price'].mean()
50
+ }
51
+
52
  self._data_loaded = True
53
  print(f"✅ Dados carregados: {self.df.shape[0]} imóveis × {self.df.shape[1]} características")
54
  return f"✅ Dados carregados: {self.df.shape[0]} imóveis × {self.df.shape[1]} características"
 
87
  numeric_features.remove('price')
88
  return numeric_features
89
 
 
 
 
 
 
 
 
 
 
 
 
90
  def get_dataset_stats(self):
91
  """Retorna estatísticas do dataset para display seguro"""
92
  if self.df is not None:
 
159
  'rmse_test': rmse_test,
160
  'mae_test': mae_test,
161
  'top_features': coeficientes.to_dict('records'),
162
+ 'selected_features': selected_features
 
163
  }
164
 
165
  except Exception as e:
 
198
  initial_message = predictor.load_data()
199
  initial_features = predictor.get_numeric_features()
200
  dataset_stats = predictor.get_dataset_stats()
 
201
  print(f"📊 Features disponíveis: {initial_features}")
202
 
203
  # Funções para a interface Gradio
204
+ def load_data_action():
205
+ """Carrega os dados - função para o botão"""
206
+ message = predictor.load_data()
207
  features = predictor.get_numeric_features()
 
208
 
209
+ # Criar checkboxes para features
210
+ feature_checkboxes = []
211
  if features and predictor.df is not None:
212
+ # Calcular correlações com preço
213
  correlations = predictor.df.corr()['price'].abs().sort_values(ascending=False)
214
 
215
+ # Selecionar automaticamente as 6 features mais correlacionadas
216
+ top_features = []
217
+ for feature in correlations.index:
218
+ if feature != 'price' and len(top_features) < 6:
219
+ top_features.append(feature)
220
+
221
  for feature in features:
222
  corr_value = correlations.get(feature, 0)
223
+ feature_checkboxes.append(
 
 
224
  gr.Checkbox(
225
  label=f"{feature} (corr: {corr_value:.3f})",
226
+ value=feature in top_features,
227
  info=f"Média: {predictor.df[feature].mean():.1f}"
228
  )
229
  )
230
 
231
+ return message, gr.Column(feature_checkboxes), gr.update(visible=True)
232
 
233
+ def get_selected_features_from_checkboxes(*checkbox_values):
234
+ """Converte valores dos checkboxes para lista de features selecionadas"""
235
  features = predictor.get_numeric_features()
236
  selected = []
 
237
  for i, is_checked in enumerate(checkbox_values):
238
  if is_checked and i < len(features):
239
  selected.append(features[i])
240
+ return selected
 
 
 
 
 
 
241
 
242
  def train_model_action(*checkbox_values):
243
  """Treina o modelo com features selecionadas"""
244
+ selected_features = get_selected_features_from_checkboxes(*checkbox_values)
 
 
 
 
 
 
 
 
245
 
246
  success, result = predictor.train_model(selected_features)
247
 
 
255
  - **RMSE Teste**: ${result['rmse_test']:,.0f}
256
  - **MAE Teste**: ${result['mae_test']:,.0f}
257
 
258
+ ### 🎯 Features por Importância:
259
  """
260
 
261
  for i, feature in enumerate(result['top_features']):
262
  direction = "📈 Aumenta preço" if feature['Coeficiente'] > 0 else "📉 Diminui preço"
263
  metrics_text += f"\n{i+1}. **{feature['Feature']}**: {feature['Coeficiente']:.4f} ({direction})"
264
 
265
+ metrics_text += f"\n\n**Total de features usadas**: {len(selected_features)}"
266
+
267
+ return metrics_text, result, gr.update(visible=True)
268
  else:
269
+ return result, None, gr.update(visible=False)
270
+
271
+ def create_correlation_plot():
272
+ """Cria gráfico de correlação"""
273
+ if predictor.df is None:
274
+ return None
275
+
276
+ try:
277
+ # Selecionar features mais importantes
278
+ numeric_cols = predictor.df.select_dtypes(include=[np.number]).columns.tolist()
279
+ if len(numeric_cols) > 8:
280
+ correlations = predictor.df.corr()['price'].abs().sort_values(ascending=False)
281
+ top_features = correlations.index[:8].tolist()
282
+ else:
283
+ top_features = numeric_cols
284
+
285
+ corr_matrix = predictor.df[top_features].corr()
286
+
287
+ fig, ax = plt.subplots(figsize=(12, 10))
288
+ sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='RdYlBu', center=0,
289
+ square=True, linewidths=0.5, cbar_kws={"shrink": 0.8}, ax=ax)
290
+ ax.set_title('🔗 Matriz de Correlação - Dataset Real King County', fontsize=14, fontweight='bold')
291
+ plt.tight_layout()
292
+ return fig
293
+ except Exception as e:
294
+ print(f"Erro no gráfico de correlação: {e}")
295
+ return None
296
+
297
+ def create_feature_analysis_plot(selected_feature):
298
+ """Cria gráfico de análise para uma feature específica"""
299
+ if predictor.df is None or not selected_feature:
300
+ return None, None
301
+
302
+ try:
303
+ # Gráfico 1: Distribuição
304
+ fig1, ax1 = plt.subplots(figsize=(10, 5))
305
+ ax1.hist(predictor.df[selected_feature], bins=30, edgecolor='black', alpha=0.7, color='skyblue')
306
+ ax1.axvline(predictor.df[selected_feature].mean(), color='red', linestyle='--', linewidth=2,
307
+ label=f'Média: {predictor.df[selected_feature].mean():.2f}')
308
+ ax1.set_xlabel(selected_feature)
309
+ ax1.set_ylabel('Frequência')
310
+ ax1.set_title(f'📊 Distribuição de {selected_feature}')
311
+ ax1.legend()
312
+ ax1.grid(True, alpha=0.3)
313
+ plt.tight_layout()
314
+
315
+ # Gráfico 2: Relação com preço
316
+ fig2, ax2 = plt.subplots(figsize=(10, 5))
317
+
318
+ if predictor.df[selected_feature].nunique() < 10:
319
+ # Boxplot para variáveis categóricas
320
+ data_to_plot = []
321
+ categories = sorted(predictor.df[selected_feature].unique())
322
+ for cat in categories:
323
+ data_to_plot.append(predictor.df[predictor.df[selected_feature] == cat]['price'])
324
+
325
+ ax2.boxplot(data_to_plot, labels=categories)
326
+ else:
327
+ # Scatter plot para variáveis contínuas
328
+ ax2.scatter(predictor.df[selected_feature], predictor.df['price'], alpha=0.3, s=20, color='steelblue')
329
+ # Linha de tendência
330
+ z = np.polyfit(predictor.df[selected_feature], predictor.df['price'], 1)
331
+ p = np.poly1d(z)
332
+ x_range = np.linspace(predictor.df[selected_feature].min(), predictor.df[selected_feature].max(), 100)
333
+ ax2.plot(x_range, p(x_range), "r--", linewidth=2, alpha=0.8, label='Tendência linear')
334
+ ax2.legend()
335
+
336
+ ax2.set_xlabel(selected_feature)
337
+ ax2.set_ylabel('Preço ($)')
338
+ correlation = predictor.df[selected_feature].corr(predictor.df['price'])
339
+ ax2.set_title(f'💰 Preço vs {selected_feature} (Corr: {correlation:.3f})')
340
+ ax2.grid(True, alpha=0.3)
341
+
342
+ # Formatar eixo y para dólares
343
+ ax2.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'${x:,.0f}'))
344
+
345
+ plt.tight_layout()
346
+ return fig1, fig2
347
+
348
+ except Exception as e:
349
+ print(f"Erro nos gráficos de análise: {e}")
350
+ return None, None
351
+
352
+ def create_price_distribution_plot():
353
+ """Cria gráfico da distribuição de preços"""
354
+ if predictor.df is None:
355
+ return None
356
+
357
+ fig, ax = plt.subplots(figsize=(12, 6))
358
+ ax.hist(predictor.df['price'], bins=50, edgecolor='black', alpha=0.7, color='steelblue')
359
+ ax.axvline(predictor.df['price'].mean(), color='red', linestyle='--', linewidth=2,
360
+ label=f'Média: ${predictor.df["price"].mean():,.0f}')
361
+ ax.axvline(predictor.df['price'].median(), color='green', linestyle='--', linewidth=2,
362
+ label=f'Mediana: ${predictor.df["price"].median():,.0f}')
363
+ ax.set_xlabel('Preço ($)')
364
+ ax.set_ylabel('Número de Imóveis')
365
+ ax.set_title('🏠 Distribuição dos Preços - Dataset Real King County')
366
+ ax.legend()
367
+ ax.grid(True, alpha=0.3)
368
+
369
+ # Formatar eixo x para dólares
370
+ ax.xaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'${x:,.0f}'))
371
+
372
+ plt.tight_layout()
373
+ return fig
374
+
375
+ def get_feature_stats(feature):
376
+ """Retorna estatísticas de uma feature"""
377
+ if predictor.df is None or feature not in predictor.df.columns:
378
+ return "Selecione uma feature para ver estatísticas"
379
+
380
+ stats = predictor.df[feature].describe()
381
+ correlation = predictor.df[feature].corr(predictor.df['price'])
382
+
383
+ return f"""
384
+ ## 📈 Estatísticas de **{feature}**
385
+
386
+ **Valores:**
387
+ - Média: {stats['mean']:.2f}
388
+ - Mediana: {stats['50%']:.2f}
389
+ - Desvio Padrão: {stats['std']:.2f}
390
+ - Mínimo: {stats['min']:.2f}
391
+ - Máximo: {stats['max']:.2f}
392
+
393
+ **Distribuição:**
394
+ - 25º Percentil: {stats['25%']:.2f}
395
+ - 75º Percentil: {stats['75%']:.2f}
396
+ - Valores Únicos: {predictor.df[feature].nunique()}
397
+
398
+ **Relação com Preço:**
399
+ - Correlação: {correlation:.3f}
400
+ - Interpretação: {'Forte' if abs(correlation) > 0.5 else 'Moderada' if abs(correlation) > 0.3 else 'Fraca'} relação
401
+ """
402
 
403
  def create_prediction_inputs(metrics_result):
404
+ """Cria inputs para previsão"""
405
  if metrics_result is None or 'selected_features' not in metrics_result:
406
  return []
407
 
 
469
  except Exception as e:
470
  return f"❌ Erro na previsão: {str(e)}", None
471
 
472
+ def get_dataset_info():
473
+ """Retorna informações do dataset para display seguro"""
474
+ stats = predictor.get_dataset_stats()
475
+ return f"""
476
+ **📊 Dataset Carregado:**
477
+ - **Arquivo**: kc_house_data.csv
478
+ - **Imóveis**: {stats['n_imoveis']:,}
479
+ - **Características**: {stats['n_caracteristicas']}
480
+ - **Preço Médio**: ${stats['preco_medio']:,.2f}
481
+ """
482
+
483
+ # Interface Gradio
484
+ with gr.Blocks(title="🏠 Análise e Previsão - King County Dataset Real") as demo:
485
  gr.Markdown(
486
  """
487
+ # 🏠 Análise e Previsão de Preços de Imóveis
488
+ ## 📊 Dataset Real - King County, Washington
489
+
490
+ ### ℹ️ Sobre os Dados:
491
+ Este aplicativo utiliza o **dataset real** `kc_house_data.csv` do mercado imobiliário de King County.
492
+ Dados reais de vendas de imóveis com diversas características.
493
  """
494
  )
495
 
496
  # Status inicial
497
  initial_status = gr.Markdown(f"**Status:** {initial_message}")
498
+ dataset_info = gr.Markdown(get_dataset_info())
499
 
500
+ with gr.Tab("🚀 Iniciar"):
501
+ gr.Markdown("### Bem-vindo ao Analisador de Dados Reais do King County!")
502
+
503
+ gr.Markdown(get_dataset_info())
504
+
505
+ gr.Markdown("""
506
+ **🎯 Funcionalidades:**
507
+ 1. **📊 Análise Exploratória** - Gráficos com dados reais
508
+ 2. **🤖 Treinar Modelo** - Machine Learning com features selecionadas
509
+ 3. **💰 Fazer Previsão** - Estime preços baseado no modelo
510
+ 4. **📚 Explicações** - Entenda as análises
511
+ """)
512
+
513
+ load_btn = gr.Button("🔄 Recarregar Dados", variant="secondary")
514
+ load_status = gr.Markdown()
515
+ feature_selection = gr.Column()
516
+ train_btn = gr.Button("🚀 Treinar Modelo", variant="primary", visible=False)
517
+
518
+ def update_after_load():
519
+ message = predictor.load_data()
520
+ info = get_dataset_info()
521
+ features = predictor.get_numeric_features()
522
 
523
  # Criar checkboxes
524
+ feature_checkboxes = []
525
+ if features and predictor.df is not None:
526
+ correlations = predictor.df.corr()['price'].abs().sort_values(ascending=False)
527
+ top_features = []
528
+ for feature in correlations.index:
529
+ if feature != 'price' and len(top_features) < 6:
530
+ top_features.append(feature)
531
+
532
+ for feature in features:
533
+ corr_value = correlations.get(feature, 0)
534
+ feature_checkboxes.append(
535
+ gr.Checkbox(
536
+ label=f"{feature} (corr: {corr_value:.3f})",
537
+ value=feature in top_features
538
+ )
539
+ )
540
 
541
+ return message, info, gr.Column(feature_checkboxes), gr.update(visible=True)
542
+
543
+ load_btn.click(
544
+ update_after_load,
545
+ outputs=[load_status, dataset_info, feature_selection, train_btn]
 
 
 
 
 
 
546
  )
547
+
548
+ with gr.Tab("📊 Análise Exploratória"):
549
+ gr.Markdown("### Explore os Dados Reais do King County")
 
 
 
 
 
550
 
551
  with gr.Row():
552
  with gr.Column():
553
+ gr.Markdown("#### 📈 Distribuição de Preços Reais")
554
+ price_plot_btn = gr.Button("🎨 Gerar Gráfico de Preços", variant="primary")
555
+ price_plot = gr.Plot()
556
 
557
  with gr.Column():
558
+ gr.Markdown("#### 🔗 Correlações entre Variáveis")
559
+ correlation_btn = gr.Button("🔄 Gerar Matriz de Correlação", variant="primary")
560
+ correlation_plot = gr.Plot()
561
+
562
+ gr.Markdown("---")
563
+ gr.Markdown("#### 🔍 Análise Detalhada por Feature")
564
+
565
+ with gr.Row():
566
+ with gr.Column():
567
+ feature_selector = gr.Dropdown(
568
+ label="Selecione uma característica para análise detalhada",
569
+ choices=initial_features,
570
+ value=initial_features[0] if initial_features else None
571
  )
572
+ feature_stats = gr.Markdown()
573
+
574
+ with gr.Column():
575
+ feature_analysis_btn = gr.Button("📈 Analisar Feature", variant="primary")
576
+
577
+ with gr.Row():
578
+ feature_dist_plot = gr.Plot(label="Distribuição da Feature")
579
+ feature_price_plot = gr.Plot(label="Relação com Preço")
580
+
581
+ # Eventos
582
+ price_plot_btn.click(create_price_distribution_plot, outputs=[price_plot])
583
+ correlation_btn.click(create_correlation_plot, outputs=[correlation_plot])
584
+ feature_analysis_btn.click(
585
+ create_feature_analysis_plot,
586
+ inputs=[feature_selector],
587
+ outputs=[feature_dist_plot, feature_price_plot]
588
+ )
589
+
590
+ # Inicializar estatísticas da primeira feature
591
+ if initial_features:
592
+ feature_stats.value = get_feature_stats(initial_features[0])
593
+
594
+ # Atualizar estatísticas quando feature mudar
595
+ feature_selector.change(
596
+ get_feature_stats,
597
+ inputs=[feature_selector],
598
+ outputs=[feature_stats]
599
+ )
600
+
601
+ with gr.Tab("🤖 Treinar Modelo"):
602
+ gr.Markdown("### Treine o Modelo com Dados Reais")
603
+
604
+ gr.Markdown("""
605
+ **🎯 Como Funciona:**
606
+ - Selecione as características para prever preços
607
+ - Features com alta correlação são melhores preditoras
608
+ - Modelo: **Regressão Linear** com dados reais
609
+ - **Dataset**: kc_house_data.csv (dados reais)
610
+ """)
611
+
612
+ train_output = gr.Markdown("Selecione as features e clique em 'Treinar Modelo'")
613
+ metrics_display = gr.JSON(label="Métricas Detalhadas", visible=False)
614
+
615
+ train_btn.click(
616
+ train_model_action,
617
+ inputs=[feature_selection],
618
+ outputs=[train_output, metrics_display, metrics_display]
619
+ )
620
+
621
+ with gr.Tab("💰 Fazer Previsão"):
622
+ gr.Markdown("### Faça Previsões com o Modelo Treinado")
623
+
624
+ prediction_inputs = gr.Column()
625
+ predict_btn = gr.Button("🎯 Calcular Preço do Imóvel", variant="primary", size="lg")
626
+
627
+ with gr.Row():
628
+ prediction_output = gr.Markdown("Preencha os valores e clique em 'Calcular Preço'")
629
+ price_result = gr.Number(
630
+ label="💵 Preço Previsto",
631
+ visible=False
632
+ )
633
+
634
+ # Atualizar inputs quando modelo for treinado
635
+ metrics_display.change(
636
+ create_prediction_inputs,
637
+ inputs=[metrics_display],
638
+ outputs=[prediction_inputs]
639
+ )
640
+
641
+ predict_btn.click(
642
+ predict_price_action,
643
+ inputs=[prediction_inputs],
644
+ outputs=[prediction_output, price_result]
645
+ ).then(
646
+ lambda: gr.update(visible=True),
647
+ outputs=[price_result]
648
+ )
649
 
650
+ with gr.Tab("📚 Explicações"):
651
+ gr.Markdown(
652
+ """
653
+ ## 📊 Guia do Dataset Real King County
654
+
655
+ ### 🏠 Sobre os Dados Reais
656
+ **King County** inclui Seattle e áreas metropolitanas. O dataset contém:
657
+ - **Vendas reais** de imóveis
658
+ - **Período**: Maio 2014 - Maio 2015
659
+ - **Características**: 21 colunas incluindo localização, tamanho, qualidade
660
+ - **Preços**: Variam de dezenas de milhares a milhões de dólares
661
+
662
+ ### 📈 Variáveis Principais:
663
+ - **price**: Preço de venda (target)
664
+ - **sqft_living**: Área habitável (pés quadrados)
665
+ - **bedrooms**: Número de quartos
666
+ - **bathrooms**: Número de banheiros
667
+ - **floors**: Número de andares
668
+ - **waterfront**: Vista para água (0/1)
669
+ - **view**: Qualidade da vista (0-4)
670
+ - **condition**: Condição do imóvel (1-5)
671
+ - **grade**: Grau de construção (1-13)
672
+ - **yr_built**: Ano de construção
673
+ - **lat/long**: Coordenadas geográficas
674
+
675
+ ### 🎯 Interpretação dos Gráficos
676
+
677
+ #### Distribuição de Preços
678
+ - Mostra a realidade do mercado imobiliário
679
+ - Geralmente assimétrica positiva (mais imóveis baratos)
680
+ - Presença de outliers (imóveis de luxo)
681
+
682
+ #### Matriz de Correlação
683
+ - Baseada em **dados reais**
684
+ - Relações observadas no mercado real
685
+ - Padrões que o modelo aprenderá
686
+
687
+ #### Análise por Feature
688
+ - Distribuições reais das características
689
+ - Relações observadas com preços de venda
690
+ - Insights do mercado real
691
+
692
+ ### 🤖 Modelo de Machine Learning
693
+ - **Algoritmo**: Regressão Linear Múltipla
694
+ - **Base**: Dados reais de vendas
695
+ - **Aplicação**: Previsão de preços baseada em padrões históricos
696
+
697
+ ### 💡 Insights do Mercado Real
698
+ - Features como **sqft_living** e **grade** têm alta correlação
699
+ - Localização (**lat/long**) é crucial para preços
700
+ - Características de qualidade impactam significativamente
701
+ - O modelo captura relações observadas no mercado real
702
+ """
703
+ )
704
 
705
  if __name__ == "__main__":
706
  demo.launch()