FernandezUNB commited on
Commit
4e28d04
·
verified ·
1 Parent(s): 565fdbf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +161 -258
app.py CHANGED
@@ -21,46 +21,41 @@ def generate_king_county_data(n_samples=2000):
21
  """Gera dados realísticos simulando o dataset King County"""
22
  np.random.seed(42)
23
 
24
- # Gerar características básicas com relações realísticas
25
  sqft_living = np.random.normal(2080, 920, n_samples)
26
- sqft_living = np.clip(sqft_living, 370, 13540) # Valores reais do dataset
27
 
28
- bedrooms = np.random.choice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], n_samples, p=[0.01, 0.05, 0.15, 0.3, 0.25, 0.15, 0.05, 0.02, 0.01, 0.01])
29
- bathrooms = np.random.choice([0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3, 3.25, 3.5, 3.75, 4, 4.25, 4.5, 4.75, 5, 5.25, 5.5, 5.75, 6, 6.25, 6.5, 6.75, 7, 7.25, 7.5, 7.75, 8],
30
- n_samples, p=[0.01, 0.02, 0.05, 0.08, 0.1, 0.12, 0.15, 0.1, 0.08, 0.06, 0.05, 0.04, 0.03, 0.02, 0.02, 0.01, 0.01, 0.01, 0.01, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005, 0.005])
31
-
32
- floors = np.random.choice([1, 1.5, 2, 2.5, 3, 3.5], n_samples, p=[0.4, 0.25, 0.2, 0.1, 0.04, 0.01])
33
  waterfront = np.random.choice([0, 1], n_samples, p=[0.99, 0.01])
34
  view = np.random.choice([0, 1, 2, 3, 4], n_samples, p=[0.9, 0.05, 0.03, 0.015, 0.005])
35
  condition = np.random.choice([1, 2, 3, 4, 5], n_samples, p=[0.05, 0.2, 0.5, 0.2, 0.05])
36
- grade = np.random.choice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], n_samples, p=[0.001, 0.005, 0.01, 0.05, 0.1, 0.15, 0.2, 0.15, 0.1, 0.08, 0.06, 0.03, 0.01])
 
37
 
38
- # Ano de construção (de 1900 a 2015)
39
  yr_built = np.random.randint(1900, 2016, n_samples)
40
-
41
- # Localização (coordenadas de King County)
42
  lat = np.random.uniform(47.2, 47.8, n_samples)
43
  long = np.random.uniform(-122.5, -121.8, n_samples)
44
 
45
  # Calcular preço base com relações realísticas
46
  base_price = (
47
- sqft_living * 300 + # Preço por sqft
48
- bedrooms * 50000 + # Valor por quarto
49
- bathrooms * 40000 + # Valor por banheiro
50
- floors * 25000 + # Valor por andar
51
- waterfront * 500000 + # Água frente
52
- view * 25000 + # Vista
53
- condition * 15000 + # Condição
54
- grade * 30000 + # Grau de qualidade
55
- (2024 - yr_built) * -500 + # Depreciação por ano
56
- (lat - 47.5) * 100000 + # Localização norte/sul
57
- (long + 122.2) * 80000 # Localização leste/oeste
58
  )
59
 
60
- # Adicionar variação aleatória
61
  noise = np.random.normal(0, 150000, n_samples)
62
  price = base_price + noise
63
- price = np.clip(price, 75000, 5000000) # Range realístico
64
 
65
  # Criar DataFrame
66
  data = {
@@ -76,21 +71,17 @@ def generate_king_county_data(n_samples=2000):
76
  'yr_built': yr_built,
77
  'lat': lat,
78
  'long': long,
79
- 'sqft_lot': np.random.normal(15000, 10000, n_samples), # Área do terreno
80
- 'sqft_above': sqft_living * 0.8, # Área acima do solo
81
- 'sqft_basement': sqft_living * 0.2, # Porão
82
- 'yr_renovated': np.where(np.random.random(n_samples) > 0.8,
83
- np.random.randint(1950, 2016, n_samples), 0) # Ano renovação
84
  }
85
 
86
- df = pd.DataFrame(data)
87
- return df
88
 
89
  class HousePricePredictor:
90
  def __init__(self):
91
  self.model = None
92
  self.scaler = None
93
- self.feature_names = None
94
  self.df = None
95
  self.is_trained = False
96
  self.selected_features = None
@@ -123,7 +114,7 @@ class HousePricePredictor:
123
 
124
  self.selected_features = selected_features
125
  X = self.df[selected_features]
126
- y = np.log1p(self.df['price']) # Transformação logarítmica
127
 
128
  # Dividir dados
129
  X_train, X_test, y_train, y_test = train_test_split(
@@ -215,7 +206,7 @@ def load_data_action():
215
  # Calcular correlações com preço
216
  correlations = predictor.df.corr()['price'].abs().sort_values(ascending=False)
217
 
218
- # Selecionar automaticamente as 6 features mais correlacionadas (excluindo price)
219
  top_features = []
220
  for feature in correlations.index:
221
  if feature != 'price' and len(top_features) < 6:
@@ -226,8 +217,7 @@ def load_data_action():
226
  feature_checkboxes.append(
227
  gr.Checkbox(
228
  label=f"{feature} (corr: {corr_value:.3f})",
229
- value=feature in top_features,
230
- info=f"Média: {predictor.df[feature].mean():.1f}"
231
  )
232
  )
233
 
@@ -272,15 +262,14 @@ def train_model_action(*checkbox_values):
272
  return result, None, gr.update(visible=False)
273
 
274
  def create_correlation_plot():
275
- """Cria gráfico de correlação das features numéricas"""
276
  if predictor.df is None:
277
  return None
278
 
279
  try:
280
- # Selecionar apenas algumas features para não sobrecarregar o gráfico
281
  numeric_cols = predictor.df.select_dtypes(include=[np.number]).columns.tolist()
282
- if len(numeric_cols) > 8: # Limitar para visualização
283
- # Pegar as mais correlacionadas com price
284
  correlations = predictor.df.corr()['price'].abs().sort_values(ascending=False)
285
  top_features = correlations.index[:8].tolist()
286
  else:
@@ -288,11 +277,10 @@ def create_correlation_plot():
288
 
289
  corr_matrix = predictor.df[top_features].corr()
290
 
291
- fig, ax = plt.subplots(figsize=(12, 10))
292
  sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='RdYlBu', center=0,
293
  square=True, linewidths=0.5, cbar_kws={"shrink": 0.8}, ax=ax)
294
- ax.set_title('🔗 Matriz de Correlação entre Variáveis\n(Valores próximos de 1 ou -1 indicam forte correlação)',
295
- fontsize=14, fontweight='bold', pad=20)
296
  plt.tight_layout()
297
  return fig
298
  except Exception as e:
@@ -305,58 +293,41 @@ def create_feature_analysis_plot(selected_feature):
305
  return None, None
306
 
307
  try:
308
- # Gráfico 1: Distribuição da feature
309
- fig1, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))
310
-
311
- # Histograma da distribuição
312
  ax1.hist(predictor.df[selected_feature], bins=30, edgecolor='black', alpha=0.7, color='skyblue')
313
- ax1.axvline(predictor.df[selected_feature].mean(), color='red', linestyle='--', linewidth=2,
314
- label=f'Média: {predictor.df[selected_feature].mean():.2f}')
315
  ax1.set_xlabel(selected_feature)
316
  ax1.set_ylabel('Frequência')
317
- ax1.set_title(f'📊 Distribuição de {selected_feature}')
318
- ax1.legend()
319
  ax1.grid(True, alpha=0.3)
320
-
321
- # Boxplot
322
- ax2.boxplot(predictor.df[selected_feature])
323
- ax2.set_ylabel(selected_feature)
324
- ax2.set_title(f'📦 Boxplot - {selected_feature}')
325
- ax2.grid(True, alpha=0.3)
326
-
327
  plt.tight_layout()
328
 
329
  # Gráfico 2: Relação com preço
330
- fig2, ax = plt.subplots(figsize=(10, 6))
331
 
332
- if predictor.df[selected_feature].nunique() < 10: # Variável categórica
333
- # Boxplot por categoria
334
  data_to_plot = []
335
  categories = sorted(predictor.df[selected_feature].unique())
336
  for cat in categories:
337
  data_to_plot.append(predictor.df[predictor.df[selected_feature] == cat]['price'])
338
 
339
- ax.boxplot(data_to_plot, labels=categories)
340
- ax.set_xlabel(selected_feature)
341
- ax.set_ylabel('Preço ($)')
342
- ax.set_title(f'💰 Preço vs {selected_feature}\n(Corr: {predictor.df[selected_feature].corr(predictor.df["price"]):.3f})')
343
-
344
- else: # Variável contínua
345
- # Scatter plot
346
- ax.scatter(predictor.df[selected_feature], predictor.df['price'], alpha=0.5, s=20, color='steelblue')
347
- ax.set_xlabel(selected_feature)
348
- ax.set_ylabel('Preço ($)')
349
- correlation = predictor.df[selected_feature].corr(predictor.df['price'])
350
- ax.set_title(f'💰 Preço vs {selected_feature}\n(Corr: {correlation:.3f})')
351
-
352
  # Linha de tendência
353
  z = np.polyfit(predictor.df[selected_feature], predictor.df['price'], 1)
354
  p = np.poly1d(z)
355
  x_range = np.linspace(predictor.df[selected_feature].min(), predictor.df[selected_feature].max(), 100)
356
- ax.plot(x_range, p(x_range), "r--", linewidth=2, alpha=0.8, label='Tendência')
357
- ax.legend()
358
 
359
- ax.grid(True, alpha=0.3)
 
 
 
 
360
  plt.tight_layout()
361
 
362
  return fig1, fig2
@@ -370,29 +341,17 @@ def create_price_distribution_plot():
370
  if predictor.df is None:
371
  return None
372
 
373
- fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))
374
-
375
- # Histograma
376
- ax1.hist(predictor.df['price'], bins=50, edgecolor='black', alpha=0.7, color='steelblue')
377
- ax1.axvline(predictor.df['price'].mean(), color='red', linestyle='--', linewidth=2,
378
  label=f'Média: ${predictor.df["price"].mean():,.0f}')
379
- ax1.axvline(predictor.df['price'].median(), color='green', linestyle='--', linewidth=2,
380
  label=f'Mediana: ${predictor.df["price"].median():,.0f}')
381
- ax1.set_xlabel('Preço ($)')
382
- ax1.set_ylabel('Número de Imóveis')
383
- ax1.set_title('🏠 Distribuição dos Preços dos Imóveis')
384
- ax1.legend()
385
- ax1.grid(True, alpha=0.3)
386
-
387
- # Boxplot
388
- ax2.boxplot(predictor.df['price'])
389
- ax2.set_ylabel('Preço ($)')
390
- ax2.set_title('📦 Distribuição - Boxplot')
391
- ax2.grid(True, alpha=0.3)
392
-
393
- # Formatar eixos
394
- ax2.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, p: f'${x:,.0f}'))
395
-
396
  plt.tight_layout()
397
  return fig
398
 
@@ -405,27 +364,17 @@ def get_feature_stats(feature):
405
  correlation = predictor.df[feature].corr(predictor.df['price'])
406
 
407
  return f"""
408
- ## 📈 Estatísticas de **{feature}**
409
-
410
- **Valores Básicos:**
411
  - Média: {stats['mean']:.2f}
412
  - Mediana: {stats['50%']:.2f}
413
  - Desvio Padrão: {stats['std']:.2f}
414
  - Mínimo: {stats['min']:.2f}
415
  - Máximo: {stats['max']:.2f}
416
-
417
- **Distribuição:**
418
- - 25º Percentil: {stats['25%']:.2f}
419
- - 75º Percentil: {stats['75%']:.2f}
420
- - Número de Valores Únicos: {predictor.df[feature].nunique()}
421
-
422
- **Relação com Preço:**
423
- - Correlação: {correlation:.3f}
424
- - Interpretação: {'Forte' if abs(correlation) > 0.5 else 'Moderada' if abs(correlation) > 0.3 else 'Fraca'} relação com preço
425
  """
426
 
427
  def create_prediction_inputs(metrics_result):
428
- """Cria inputs para previsão baseado nas features selecionadas"""
429
  if metrics_result is None or 'selected_features' not in metrics_result:
430
  return []
431
 
@@ -436,21 +385,17 @@ def create_prediction_inputs(metrics_result):
436
  max_val = float(predictor.df[feature].max())
437
  mean_val = float(predictor.df[feature].mean())
438
 
439
- # Definir step apropriado baseado no range
440
  step = (max_val - min_val) / 100
441
  if step < 0.1:
442
  step = 0.1
443
- elif step > 100:
444
- step = 10
445
 
446
  inputs.append(
447
  gr.Slider(
448
- label=f"🏠 {feature}",
449
  minimum=min_val,
450
  maximum=max_val,
451
  value=mean_val,
452
- step=step,
453
- info=f"Range: {min_val:.1f} - {max_val:.1f}"
454
  )
455
  )
456
 
@@ -459,36 +404,31 @@ def create_prediction_inputs(metrics_result):
459
  def predict_price_action(*feature_values):
460
  """Faz previsão de preço"""
461
  if not predictor.is_trained:
462
- return "❌ Modelo não treinado. Por favor, treine o modelo primeiro.", None
463
 
464
  try:
465
- # Criar dicionário com os valores das features
466
  input_features = {}
467
  if hasattr(predictor, 'selected_features') and predictor.selected_features:
468
  for i, feature in enumerate(predictor.selected_features):
469
  if i < len(feature_values):
470
  input_features[feature] = feature_values[i]
471
  else:
472
- return "❌ Nenhuma feature selecionada no modelo", None
473
 
474
  pred_price, error = predictor.predict_price(input_features)
475
 
476
  if error:
477
  return f"❌ {error}", None
478
 
479
- # Criar resumo das características
480
  features_summary = "\n".join([f"- **{k}**: {v:.2f}" for k, v in input_features.items()])
481
 
482
  result_text = f"""
483
- ## 🏠 Previsão de Preço do Imóvel
484
 
485
- ### 💰 **Preço Estimado: ${pred_price:,.2f}**
486
 
487
- ### 📋 Características Informadas:
488
  {features_summary}
489
-
490
- ---
491
- *💡 Nota: Esta é uma estimativa baseada no modelo de regressão linear treinado com dados de King County.*
492
  """
493
 
494
  return result_text, pred_price
@@ -497,72 +437,54 @@ def predict_price_action(*feature_values):
497
  return f"❌ Erro na previsão: {str(e)}", None
498
 
499
  # Interface Gradio
500
- with gr.Blocks(title="🏠 Análise e Previsão de Preços de Imóveis - King County") as demo:
501
  gr.Markdown(
502
  """
503
  # 🏠 Análise e Previsão de Preços de Imóveis
504
- ## King County, Washington - USA
505
-
506
- ### 📊 Sobre os Dados:
507
- Este aplicativo utiliza dados **realísticos** simulando o mercado imobiliário de King County (Seattle).
508
- Os dados incluem características como área construída, quartos, banheiros, localização e muito mais.
509
-
510
- ### 🎯 Funcionalidades:
511
- - **Análise Exploratória**: Gráficos interativos dos dados
512
- - **Seleção de Features**: Escolha quais características usar no modelo
513
- - **Treinamento**: Modelo de Machine Learning para prever preços
514
- - **Previsão**: Estime o preço de um imóvel com características específicas
515
 
 
516
  """
517
  )
518
 
519
- # Definir todas as variáveis da interface primeiro
520
- with gr.Tab("🚀 1. Carregar Dados"):
521
- gr.Markdown("### Primeiro Passo: Carregar os Dados")
522
- load_btn = gr.Button("📂 Carregar Dados do King County", variant="primary", size="lg")
523
- load_status = gr.Markdown("Clique no botão para carregar os dados de imóveis...")
524
- feature_selection = gr.Column()
525
- train_btn = gr.Button("🚀 Treinar Modelo de Previsão", variant="primary", size="lg", visible=False)
526
-
527
- load_btn.click(
528
- load_data_action,
529
- outputs=[load_status, feature_selection, train_btn]
530
- )
531
 
532
- with gr.Tab("📈 2. Análise Exploratória"):
533
- gr.Markdown("### Explore os Dados e Visualize Relações")
534
 
535
  with gr.Row():
536
  with gr.Column():
537
- gr.Markdown("#### 📊 Distribuição de Preços")
538
- price_plot_btn = gr.Button("🎨 Gerar Gráfico de Preços", variant="primary")
539
  price_plot = gr.Plot()
540
 
541
  with gr.Column():
542
- gr.Markdown("#### 🔗 Correlações entre Variáveis")
543
- correlation_btn = gr.Button("🔄 Gerar Matriz de Correlação", variant="primary")
544
  correlation_plot = gr.Plot()
545
 
546
  gr.Markdown("---")
547
- gr.Markdown("#### 🔍 Análise Detalhada por Feature")
548
 
549
  with gr.Row():
550
  with gr.Column():
551
  feature_selector = gr.Dropdown(
552
- label="Selecione uma característica para análise detalhada",
553
- choices=[],
554
- interactive=True
555
  )
556
- feature_stats = gr.Markdown("Selecione uma feature acima...")
557
 
558
  with gr.Column():
559
- feature_analysis_btn = gr.Button("📈 Analisar Feature", variant="primary")
560
 
561
  with gr.Row():
562
- feature_dist_plot = gr.Plot(label="Distribuição da Feature")
563
- feature_price_plot = gr.Plot(label="Relação com Preço")
564
 
565
- # Conectar eventos
566
  price_plot_btn.click(create_price_distribution_plot, outputs=[price_plot])
567
  correlation_btn.click(create_correlation_plot, outputs=[correlation_plot])
568
  feature_analysis_btn.click(
@@ -570,23 +492,40 @@ with gr.Blocks(title="🏠 Análise e Previsão de Preços de Imóveis - King Co
570
  inputs=[feature_selector],
571
  outputs=[feature_dist_plot, feature_price_plot]
572
  )
573
- feature_selector.change(
574
- get_feature_stats,
575
- inputs=[feature_selector],
576
- outputs=[feature_stats]
577
- )
 
578
 
579
- with gr.Tab("🤖 3. Treinar Modelo"):
580
- gr.Markdown("### Configure e Treine o Modelo de Previsão")
581
- gr.Markdown("""
582
- **🎯 Como Funciona:**
583
- - Selecione as características que deseja usar para prever preços
584
- - Features com alta correlação (próximas de 1 ou -1) geralmente são melhores preditoras
585
- - O modelo usará Regressão Linear para aprender os padrões
586
- """)
587
-
588
- train_output = gr.Markdown("Selecione as features acima e clique em 'Treinar Modelo'")
589
- metrics_display = gr.JSON(label="Métricas Detalhadas", visible=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
590
 
591
  train_btn.click(
592
  train_model_action,
@@ -594,26 +533,19 @@ with gr.Blocks(title="🏠 Análise e Previsão de Preços de Imóveis - King Co
594
  outputs=[train_output, metrics_display, metrics_display]
595
  )
596
 
597
- with gr.Tab("💰 4. Fazer Previsão"):
598
- gr.Markdown("### Faça uma Previsão de Preço")
599
- gr.Markdown("Ajuste os valores das características para estimar o preço de um imóvel:")
600
 
601
  prediction_inputs = gr.Column()
602
- predict_btn = gr.Button("🎯 Calcular Preço do Imóvel", variant="primary", size="lg")
603
-
604
- with gr.Row():
605
- prediction_output = gr.Markdown("Preencha os valores acima e clique em 'Calcular Preço'")
606
- price_result = gr.Number(
607
- label="💵 Preço Previsto",
608
- visible=False
609
- )
610
 
611
  # Atualizar inputs quando modelo for treinado
612
- metrics_display.change(
613
- create_prediction_inputs,
614
- inputs=[metrics_display],
615
- outputs=[prediction_inputs]
616
- )
617
 
618
  predict_btn.click(
619
  predict_price_action,
@@ -624,71 +556,42 @@ with gr.Blocks(title="🏠 Análise e Previsão de Preços de Imóveis - King Co
624
  outputs=[price_result]
625
  )
626
 
627
- with gr.Tab("📚 5. Explicações"):
628
  gr.Markdown(
629
  """
630
- ## 📊 Guia Completo de Análise
631
-
632
- ### 🏠 Sobre os Dados
633
- **King County** inclui Seattle e é um mercado imobiliário dinâmico. Os dados simulados incluem:
634
- - **Preços**: De $75,000 a $5,000,000
635
- - **Características**: Área, quartos, banheiros, localização, qualidade, etc.
636
- - **Período**: Imóveis de 1900 até 2015
637
-
638
- ### 📈 Interpretação dos Gráficos
639
-
640
- #### 1. Distribuição de Preços
641
- - **Histograma**: Mostra quantos imóveis existem em cada faixa de preço
642
- - **Média vs Mediana**: Se a média > mediana, há imóveis muito caros puxando a média
643
- - **Assimetria**: Mercados reais geralmente têm assimetria positiva (mais imóveis baratos)
644
-
645
- #### 2. Matriz de Correlação
646
- - **🔴 Vermelho**: Correlação positiva (ex: área maior → preço maior)
647
- - **🔵 Azul**: Correlação negativa (ex: ano mais antigo → preço menor)
648
- - **Valores**: -1 (perfeita negativa) a +1 (perfeita positiva)
649
- - **Para modelo**: Busque features com |correlação| > 0.3 com preço
650
-
651
- #### 3. Análise por Feature
652
- - **Distribuição**: Como os valores se espalham (normal, assimétrica)
653
- - **Relação com Preço**: Padrão linear? Há outliers?
654
- - **Boxplot**: Mostra mediana, quartis e valores extremos
655
-
656
- ### 🤖 Sobre o Modelo
657
- - **Algoritmo**: Regressão Linear Múltipla
658
- - **Transformação**: Logarítmica nos preços para normalizar
659
- - **Avaliação**: R² mostra % da variância explicada (0-100%)
660
- - **Coeficientes**: Impacto de cada feature no preço final
661
-
662
- ### 💡 Dicas para Boas Previsões
663
- 1. **Selecione features relevantes**: Área, quartos, localização
664
- 2. **Evite multicolinearidade**: Não use features muito correlacionadas entre si
665
- 3. **Verifique relações lineares**: Features com relação clara com preço funcionam melhor
666
- 4. **Considere o contexto**: Características únicas podem afetar preços reais
667
-
668
- ### 🎯 Métricas do Modelo
669
- - **R²**: 0.7-0.9 = Excelente, 0.5-0.7 = Bom, <0.5 = Precisa melhorar
670
- - **RMSE**: Erro médio em dólares (ideal: <20% do preço médio)
671
- - **Coeficientes**: Mostram quanto cada feature impacta no preço
672
  """
673
  )
674
 
675
- # Inicializar dados quando o app carregar
676
- def initialize_app():
677
- """Inicializa o aplicativo carregando dados"""
678
- message = predictor.load_data()
679
- features = predictor.get_numeric_features()
680
-
681
- # Retornar valores para atualizar a interface
682
- return (
683
- message,
684
- gr.update(choices=features, value=features[0] if features else None)
685
- )
686
 
687
- # Conectar a inicialização quando o app carregar
688
- demo.load(
689
- initialize_app,
690
- outputs=[load_status, feature_selector]
691
- )
692
 
693
  if __name__ == "__main__":
694
- demo.launch(share=True)
 
21
  """Gera dados realísticos simulando o dataset King County"""
22
  np.random.seed(42)
23
 
24
+ # Gerar características básicas
25
  sqft_living = np.random.normal(2080, 920, n_samples)
26
+ sqft_living = np.clip(sqft_living, 370, 13540)
27
 
28
+ bedrooms = np.random.choice([1, 2, 3, 4, 5], n_samples, p=[0.1, 0.3, 0.4, 0.15, 0.05])
29
+ bathrooms = np.random.choice([1, 1.5, 2, 2.5, 3, 3.5], n_samples, p=[0.1, 0.2, 0.4, 0.2, 0.08, 0.02])
30
+ floors = np.random.choice([1, 1.5, 2, 2.5, 3], n_samples, p=[0.4, 0.3, 0.2, 0.08, 0.02])
 
 
31
  waterfront = np.random.choice([0, 1], n_samples, p=[0.99, 0.01])
32
  view = np.random.choice([0, 1, 2, 3, 4], n_samples, p=[0.9, 0.05, 0.03, 0.015, 0.005])
33
  condition = np.random.choice([1, 2, 3, 4, 5], n_samples, p=[0.05, 0.2, 0.5, 0.2, 0.05])
34
+ grade = np.random.choice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], n_samples,
35
+ p=[0.001, 0.005, 0.01, 0.05, 0.1, 0.15, 0.2, 0.15, 0.1, 0.08, 0.06, 0.03, 0.01])
36
 
 
37
  yr_built = np.random.randint(1900, 2016, n_samples)
 
 
38
  lat = np.random.uniform(47.2, 47.8, n_samples)
39
  long = np.random.uniform(-122.5, -121.8, n_samples)
40
 
41
  # Calcular preço base com relações realísticas
42
  base_price = (
43
+ sqft_living * 300 +
44
+ bedrooms * 50000 +
45
+ bathrooms * 40000 +
46
+ floors * 25000 +
47
+ waterfront * 500000 +
48
+ view * 25000 +
49
+ condition * 15000 +
50
+ grade * 30000 +
51
+ (2024 - yr_built) * -500 +
52
+ (lat - 47.5) * 100000 +
53
+ (long + 122.2) * 80000
54
  )
55
 
 
56
  noise = np.random.normal(0, 150000, n_samples)
57
  price = base_price + noise
58
+ price = np.clip(price, 75000, 5000000)
59
 
60
  # Criar DataFrame
61
  data = {
 
71
  'yr_built': yr_built,
72
  'lat': lat,
73
  'long': long,
74
+ 'sqft_lot': np.random.normal(15000, 10000, n_samples),
75
+ 'sqft_above': sqft_living * 0.8,
76
+ 'sqft_basement': sqft_living * 0.2,
 
 
77
  }
78
 
79
+ return pd.DataFrame(data)
 
80
 
81
  class HousePricePredictor:
82
  def __init__(self):
83
  self.model = None
84
  self.scaler = None
 
85
  self.df = None
86
  self.is_trained = False
87
  self.selected_features = None
 
114
 
115
  self.selected_features = selected_features
116
  X = self.df[selected_features]
117
+ y = np.log1p(self.df['price'])
118
 
119
  # Dividir dados
120
  X_train, X_test, y_train, y_test = train_test_split(
 
206
  # Calcular correlações com preço
207
  correlations = predictor.df.corr()['price'].abs().sort_values(ascending=False)
208
 
209
+ # Selecionar automaticamente as 6 features mais correlacionadas
210
  top_features = []
211
  for feature in correlations.index:
212
  if feature != 'price' and len(top_features) < 6:
 
217
  feature_checkboxes.append(
218
  gr.Checkbox(
219
  label=f"{feature} (corr: {corr_value:.3f})",
220
+ value=feature in top_features
 
221
  )
222
  )
223
 
 
262
  return result, None, gr.update(visible=False)
263
 
264
  def create_correlation_plot():
265
+ """Cria gráfico de correlação"""
266
  if predictor.df is None:
267
  return None
268
 
269
  try:
270
+ # Selecionar features mais importantes
271
  numeric_cols = predictor.df.select_dtypes(include=[np.number]).columns.tolist()
272
+ if len(numeric_cols) > 8:
 
273
  correlations = predictor.df.corr()['price'].abs().sort_values(ascending=False)
274
  top_features = correlations.index[:8].tolist()
275
  else:
 
277
 
278
  corr_matrix = predictor.df[top_features].corr()
279
 
280
+ fig, ax = plt.subplots(figsize=(10, 8))
281
  sns.heatmap(corr_matrix, annot=True, fmt='.2f', cmap='RdYlBu', center=0,
282
  square=True, linewidths=0.5, cbar_kws={"shrink": 0.8}, ax=ax)
283
+ ax.set_title('Matriz de Correlação', fontsize=14, fontweight='bold')
 
284
  plt.tight_layout()
285
  return fig
286
  except Exception as e:
 
293
  return None, None
294
 
295
  try:
296
+ # Gráfico 1: Distribuição
297
+ fig1, ax1 = plt.subplots(figsize=(8, 4))
 
 
298
  ax1.hist(predictor.df[selected_feature], bins=30, edgecolor='black', alpha=0.7, color='skyblue')
299
+ ax1.axvline(predictor.df[selected_feature].mean(), color='red', linestyle='--', linewidth=2)
 
300
  ax1.set_xlabel(selected_feature)
301
  ax1.set_ylabel('Frequência')
302
+ ax1.set_title(f'Distribuição de {selected_feature}')
 
303
  ax1.grid(True, alpha=0.3)
 
 
 
 
 
 
 
304
  plt.tight_layout()
305
 
306
  # Gráfico 2: Relação com preço
307
+ fig2, ax2 = plt.subplots(figsize=(8, 4))
308
 
309
+ if predictor.df[selected_feature].nunique() < 10:
310
+ # Boxplot para variáveis categóricas
311
  data_to_plot = []
312
  categories = sorted(predictor.df[selected_feature].unique())
313
  for cat in categories:
314
  data_to_plot.append(predictor.df[predictor.df[selected_feature] == cat]['price'])
315
 
316
+ ax2.boxplot(data_to_plot, labels=categories)
317
+ else:
318
+ # Scatter plot para variáveis contínuas
319
+ ax2.scatter(predictor.df[selected_feature], predictor.df['price'], alpha=0.5, s=20, color='steelblue')
 
 
 
 
 
 
 
 
 
320
  # Linha de tendência
321
  z = np.polyfit(predictor.df[selected_feature], predictor.df['price'], 1)
322
  p = np.poly1d(z)
323
  x_range = np.linspace(predictor.df[selected_feature].min(), predictor.df[selected_feature].max(), 100)
324
+ ax2.plot(x_range, p(x_range), "r--", linewidth=2, alpha=0.8)
 
325
 
326
+ ax2.set_xlabel(selected_feature)
327
+ ax2.set_ylabel('Preço ($)')
328
+ correlation = predictor.df[selected_feature].corr(predictor.df['price'])
329
+ ax2.set_title(f'Preço vs {selected_feature} (Corr: {correlation:.3f})')
330
+ ax2.grid(True, alpha=0.3)
331
  plt.tight_layout()
332
 
333
  return fig1, fig2
 
341
  if predictor.df is None:
342
  return None
343
 
344
+ fig, ax = plt.subplots(figsize=(10, 5))
345
+ ax.hist(predictor.df['price'], bins=50, edgecolor='black', alpha=0.7, color='steelblue')
346
+ ax.axvline(predictor.df['price'].mean(), color='red', linestyle='--', linewidth=2,
 
 
347
  label=f'Média: ${predictor.df["price"].mean():,.0f}')
348
+ ax.axvline(predictor.df['price'].median(), color='green', linestyle='--', linewidth=2,
349
  label=f'Mediana: ${predictor.df["price"].median():,.0f}')
350
+ ax.set_xlabel('Preço ($)')
351
+ ax.set_ylabel('Número de Imóveis')
352
+ ax.set_title('Distribuição dos Preços dos Imóveis')
353
+ ax.legend()
354
+ ax.grid(True, alpha=0.3)
 
 
 
 
 
 
 
 
 
 
355
  plt.tight_layout()
356
  return fig
357
 
 
364
  correlation = predictor.df[feature].corr(predictor.df['price'])
365
 
366
  return f"""
367
+ **Estatísticas de {feature}:**
 
 
368
  - Média: {stats['mean']:.2f}
369
  - Mediana: {stats['50%']:.2f}
370
  - Desvio Padrão: {stats['std']:.2f}
371
  - Mínimo: {stats['min']:.2f}
372
  - Máximo: {stats['max']:.2f}
373
+ - Correlação com Preço: {correlation:.3f}
 
 
 
 
 
 
 
 
374
  """
375
 
376
  def create_prediction_inputs(metrics_result):
377
+ """Cria inputs para previsão"""
378
  if metrics_result is None or 'selected_features' not in metrics_result:
379
  return []
380
 
 
385
  max_val = float(predictor.df[feature].max())
386
  mean_val = float(predictor.df[feature].mean())
387
 
 
388
  step = (max_val - min_val) / 100
389
  if step < 0.1:
390
  step = 0.1
 
 
391
 
392
  inputs.append(
393
  gr.Slider(
394
+ label=feature,
395
  minimum=min_val,
396
  maximum=max_val,
397
  value=mean_val,
398
+ step=step
 
399
  )
400
  )
401
 
 
404
  def predict_price_action(*feature_values):
405
  """Faz previsão de preço"""
406
  if not predictor.is_trained:
407
+ return "❌ Modelo não treinado. Treine o modelo primeiro.", None
408
 
409
  try:
 
410
  input_features = {}
411
  if hasattr(predictor, 'selected_features') and predictor.selected_features:
412
  for i, feature in enumerate(predictor.selected_features):
413
  if i < len(feature_values):
414
  input_features[feature] = feature_values[i]
415
  else:
416
+ return "❌ Nenhuma feature selecionada", None
417
 
418
  pred_price, error = predictor.predict_price(input_features)
419
 
420
  if error:
421
  return f"❌ {error}", None
422
 
 
423
  features_summary = "\n".join([f"- **{k}**: {v:.2f}" for k, v in input_features.items()])
424
 
425
  result_text = f"""
426
+ ## Previsão de Preço
427
 
428
+ **💰 Preço Estimado: ${pred_price:,.2f}**
429
 
430
+ **Características:**
431
  {features_summary}
 
 
 
432
  """
433
 
434
  return result_text, pred_price
 
437
  return f"❌ Erro na previsão: {str(e)}", None
438
 
439
  # Interface Gradio
440
+ with gr.Blocks(title="Previsão de Preços de Imóveis") as demo:
441
  gr.Markdown(
442
  """
443
  # 🏠 Análise e Previsão de Preços de Imóveis
444
+ ## King County, Washington
 
 
 
 
 
 
 
 
 
 
445
 
446
+ Analise dados imobiliários e faça previsões de preços usando machine learning.
447
  """
448
  )
449
 
450
+ # Carregar dados automaticamente ao iniciar
451
+ initial_message = predictor.load_data()
452
+ initial_features = predictor.get_numeric_features()
 
 
 
 
 
 
 
 
 
453
 
454
+ with gr.Tab("📊 Análise Exploratória"):
455
+ gr.Markdown("### Explore os Dados")
456
 
457
  with gr.Row():
458
  with gr.Column():
459
+ gr.Markdown("**Distribuição de Preços**")
460
+ price_plot_btn = gr.Button("Gerar Gráfico", variant="primary")
461
  price_plot = gr.Plot()
462
 
463
  with gr.Column():
464
+ gr.Markdown("**Correlações**")
465
+ correlation_btn = gr.Button("Gerar Matriz", variant="primary")
466
  correlation_plot = gr.Plot()
467
 
468
  gr.Markdown("---")
469
+ gr.Markdown("**Análise por Feature**")
470
 
471
  with gr.Row():
472
  with gr.Column():
473
  feature_selector = gr.Dropdown(
474
+ label="Selecione uma feature",
475
+ choices=initial_features,
476
+ value=initial_features[0] if initial_features else None
477
  )
478
+ feature_stats = gr.Markdown()
479
 
480
  with gr.Column():
481
+ feature_analysis_btn = gr.Button("Analisar", variant="primary")
482
 
483
  with gr.Row():
484
+ feature_dist_plot = gr.Plot()
485
+ feature_price_plot = gr.Plot()
486
 
487
+ # Eventos
488
  price_plot_btn.click(create_price_distribution_plot, outputs=[price_plot])
489
  correlation_btn.click(create_correlation_plot, outputs=[correlation_plot])
490
  feature_analysis_btn.click(
 
492
  inputs=[feature_selector],
493
  outputs=[feature_dist_plot, feature_price_plot]
494
  )
495
+
496
+ # Atualizar estatísticas quando feature mudar
497
+ def update_stats(feature):
498
+ return get_feature_stats(feature)
499
+
500
+ feature_selector.change(update_stats, inputs=[feature_selector], outputs=[feature_stats])
501
 
502
+ with gr.Tab("🤖 Treinar Modelo"):
503
+ gr.Markdown("### Treine o Modelo de Previsão")
504
+
505
+ gr.Markdown(f"**Status:** {initial_message}")
506
+ gr.Markdown("Selecione as features para o modelo:")
507
+
508
+ feature_checkboxes = []
509
+ if initial_features and predictor.df is not None:
510
+ correlations = predictor.df.corr()['price'].abs().sort_values(ascending=False)
511
+ top_features = []
512
+ for feature in correlations.index:
513
+ if feature != 'price' and len(top_features) < 6:
514
+ top_features.append(feature)
515
+
516
+ for feature in initial_features:
517
+ corr_value = correlations.get(feature, 0)
518
+ feature_checkboxes.append(
519
+ gr.Checkbox(
520
+ label=f"{feature} (corr: {corr_value:.3f})",
521
+ value=feature in top_features
522
+ )
523
+ )
524
+
525
+ feature_selection = gr.Column(feature_checkboxes)
526
+ train_btn = gr.Button("Treinar Modelo", variant="primary", size="lg")
527
+ train_output = gr.Markdown()
528
+ metrics_display = gr.JSON(visible=False)
529
 
530
  train_btn.click(
531
  train_model_action,
 
533
  outputs=[train_output, metrics_display, metrics_display]
534
  )
535
 
536
+ with gr.Tab("💰 Fazer Previsão"):
537
+ gr.Markdown("### Faça uma Previsão")
 
538
 
539
  prediction_inputs = gr.Column()
540
+ predict_btn = gr.Button("Calcular Preço", variant="primary", size="lg")
541
+ prediction_output = gr.Markdown()
542
+ price_result = gr.Number(visible=False)
 
 
 
 
 
543
 
544
  # Atualizar inputs quando modelo for treinado
545
+ def update_prediction_inputs(metrics):
546
+ return create_prediction_inputs(metrics)
547
+
548
+ metrics_display.change(update_prediction_inputs, inputs=[metrics_display], outputs=[prediction_inputs])
 
549
 
550
  predict_btn.click(
551
  predict_price_action,
 
556
  outputs=[price_result]
557
  )
558
 
559
+ with gr.Tab("📚 Explicações"):
560
  gr.Markdown(
561
  """
562
+ ## Guia de Uso
563
+
564
+ ### 📊 Análise Exploratória
565
+ - **Distribuição de Preços**: Veja como os preços estão distribuídos
566
+ - **Matriz de Correlação**: Identifique relações entre variáveis
567
+ - **Análise por Feature**: Explore cada característica individualmente
568
+
569
+ ### 🤖 Treinamento do Modelo
570
+ - Selecione features com alta correlação com preço
571
+ - O modelo usa Regressão Linear
572
+ - Métricas: R², RMSE, MAE
573
+
574
+ ### 💰 Previsões
575
+ - Ajuste os valores das características
576
+ - Obtenha previsões de preço em tempo real
577
+ - Baseado no modelo treinado
578
+
579
+ ### 📈 Interpretação
580
+ - **R²**: Proporção da variância explicada (0-1)
581
+ - **RMSE**: Erro médio em dólares
582
+ - **Correlação**: Força da relação entre variáveis (-1 a +1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
583
  """
584
  )
585
 
586
+ # Inicializar estatísticas da primeira feature
587
+ if initial_features:
588
+ initial_stats = get_feature_stats(initial_features[0])
589
+ else:
590
+ initial_stats = "Nenhuma feature disponível"
 
 
 
 
 
 
591
 
592
+ # Atualizar o componente de estatísticas
593
+ if 'feature_stats' in locals():
594
+ feature_stats.value = initial_stats
 
 
595
 
596
  if __name__ == "__main__":
597
+ demo.launch()