enzograndino commited on
Commit
b961d3b
·
verified ·
1 Parent(s): 8a9ceca

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +213 -33
app.py CHANGED
@@ -7,8 +7,9 @@ from plotly.subplots import make_subplots
7
  import folium
8
  from streamlit_folium import st_folium
9
  from folium.plugins import MarkerCluster, HeatMap
10
- from sklearn.ensemble import RandomForestRegressor
11
  from sklearn.neighbors import NearestNeighbors
 
12
  from wordcloud import WordCloud
13
  import matplotlib
14
  import matplotlib.pyplot as plt
@@ -50,6 +51,13 @@ st.markdown("""
50
  border-radius: 5px;
51
  margin: 15px 0;
52
  }
 
 
 
 
 
 
 
53
  h1 {
54
  color: #1e3a8a;
55
  font-weight: 700;
@@ -206,10 +214,10 @@ def load_and_process_data():
206
 
207
  score_df = score_df.sort_values('Score_Final', ascending=False)
208
 
209
- return df, past, ranking, score_df, pop, ibge, fipe
210
 
211
  # --- CARREGAMENTO ---
212
- df, df_past, ranking_cidades, score_cidades, pop_data, ibge_data, fipe_data = load_and_process_data()
213
 
214
  # --- TREINAMENTO MODELO IA ---
215
  @st.cache_resource
@@ -225,11 +233,29 @@ def train_model(df):
225
  X = pd.concat([X, pd.get_dummies(df_model['room_type'], prefix='type')], axis=1)
226
  y = df_model['ttm_revenue_native']
227
 
228
- model = RandomForestRegressor(n_estimators=50, random_state=42, n_jobs=-1)
229
- model.fit(X, y)
230
- return model, X.columns, df_model
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
 
232
- model, model_cols, df_training = train_model(df)
233
 
234
  # --- SIDEBAR ---
235
  st.sidebar.image("https://upload.wikimedia.org/wikipedia/commons/6/69/Airbnb_Logo_Bélo.svg", width=140)
@@ -314,12 +340,82 @@ if page == "🎯 Painel Executivo":
314
  cresc_melhor = ranking_cidades.loc[melhor_cidade, 'crescimento_pop_%']
315
  st.metric(
316
  "🌱 Crescimento Populacional",
317
- f"+{cresc_melhor:.1f}%",
318
  delta="2010-2023"
319
  )
320
 
321
  st.markdown("---")
322
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  # Ranking visual
324
  st.subheader("🏆 Ranking Completo de Cidades")
325
 
@@ -524,7 +620,7 @@ elif page == "📈 Análise de Mercado":
524
 
525
  st.plotly_chart(fig_pop, use_container_width=True)
526
 
527
- # Crescimento percentual
528
  pop_2010 = pop_data[pop_data['date'] == 2010].copy()
529
  pop_2023 = pop_data[pop_data['date'] == 2023].copy()
530
 
@@ -541,6 +637,7 @@ elif page == "📈 Análise de Mercado":
541
  pop_merged['Crescimento_%'] = ((pop_merged['Populacao_2023'] - pop_merged['Populacao_2010']) / pop_merged['Populacao_2010'] * 100).round(2)
542
  pop_merged['city'] = pop_merged['city_norm'].str.title()
543
 
 
544
  fig_cresc = px.bar(
545
  pop_merged,
546
  x='city',
@@ -549,11 +646,30 @@ elif page == "📈 Análise de Mercado":
549
  labels={'city': 'Cidade', 'Crescimento_%': 'Crescimento (%)'},
550
  color='Crescimento_%',
551
  color_continuous_scale='RdYlGn',
552
- template="plotly_white"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
553
  )
554
 
555
  st.plotly_chart(fig_cresc, use_container_width=True)
556
 
 
 
 
 
557
  st.markdown("---")
558
 
559
  # Segurança
@@ -687,7 +803,11 @@ elif page == "📅 Sazonalidade":
687
  template="plotly_white"
688
  )
689
 
690
- fig_sazon.update_yaxis(tickformat='.0%')
 
 
 
 
691
  st.plotly_chart(fig_sazon, use_container_width=True)
692
 
693
  st.markdown("---")
@@ -752,12 +872,12 @@ elif page == "📅 Sazonalidade":
752
  st.warning("⚠️ Sem dados históricos para as cidades selecionadas.")
753
 
754
  # ============================================================================
755
- # PÁGINA 5: MAPA INTERATIVO
756
  # ============================================================================
757
  elif page == "🗺️ Mapa Interativo":
758
  st.title("🗺️ Mapa de Oportunidades")
759
 
760
- st.markdown("**Clique nos marcadores para ver detalhes dos imóveis**")
761
 
762
  if not df_filtered.empty:
763
  center_lat = df_filtered['latitude'].mean()
@@ -765,7 +885,7 @@ elif page == "🗺️ Mapa Interativo":
765
 
766
  m = folium.Map(location=[center_lat, center_lon], zoom_start=5, tiles='CartoDB positron')
767
 
768
- # Adicionar marcadores por cidade
769
  for cidade in cidades_sel:
770
  df_cidade = df_filtered[df_filtered['city'] == cidade]
771
 
@@ -780,22 +900,36 @@ elif page == "🗺️ Mapa Interativo":
780
  else:
781
  color = 'red'
782
 
 
 
 
 
783
  popup_html = f"""
784
- <div style="width: 250px;">
785
- <h4>{row['listing_name']}</h4>
786
- <p><strong>Cidade:</strong> {row['city']}</p>
787
- <p><strong>Faturamento Anual:</strong> R$ {row['ttm_revenue_native']:,.2f}</p>
788
- <p><strong>ROI:</strong> {row['ROI_anual']:.2f}%</p>
789
- <p><strong>Ocupação:</strong> {row['ttm_occupancy']*100:.1f}%</p>
790
- <p><strong>Recomendação:</strong> {row['Recomendacao']}</p>
 
 
 
 
 
 
 
 
 
 
791
  </div>
792
  """
793
 
794
  folium.Marker(
795
  location=[row['latitude'], row['longitude']],
796
  popup=folium.Popup(popup_html, max_width=300),
797
- tooltip=f"R$ {row['ttm_avg_rate_native']:.0f}/noite",
798
- icon=folium.Icon(color=color, icon='home')
799
  ).add_to(m)
800
 
801
  st_folium(m, height=600, width="100%")
@@ -808,28 +942,69 @@ elif page == "🗺️ Mapa Interativo":
808
  st.subheader("🏆 Top 10 Imóveis por ROI")
809
 
810
  top_imoveis = df_filtered.nlargest(10, 'ROI_anual')[
811
- ['listing_name', 'city', 'ttm_revenue_native', 'ROI_anual', 'ttm_occupancy', 'Recomendacao']
812
  ].copy()
813
 
814
- top_imoveis.columns = ['Nome', 'Cidade', 'Faturamento Anual', 'ROI (%)', 'Ocupação', 'Recomendação']
815
  top_imoveis['Ocupação'] = (top_imoveis['Ocupação'] * 100).round(1)
816
 
817
  st.dataframe(
818
  top_imoveis.style.format({
819
  'Faturamento Anual': 'R$ {:,.2f}',
820
  'ROI (%)': '{:.2f}%',
821
- 'Ocupação': '{:.1f}%'
 
822
  }).background_gradient(subset=['ROI (%)'], cmap='Greens'),
823
  use_container_width=True,
824
  hide_index=True
825
  )
826
 
827
  # ============================================================================
828
- # PÁGINA 6: SIMULADOR DE INVESTIMENTO
829
  # ============================================================================
830
  elif page == "🤖 Simulador de Investimento":
831
  st.title("🤖 Simulador Inteligente de Investimento")
832
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
833
  # Inicializa session state
834
  if 'sim_result' not in st.session_state:
835
  st.session_state['sim_result'] = None
@@ -853,13 +1028,13 @@ elif page == "🤖 Simulador de Investimento":
853
  }
854
  def_lat, def_lon = coords_dict.get(sim_city, [-23.55, -46.63])
855
 
856
- sim_lat = st.number_input("Latitude:", value=def_lat, format="%.5f")
857
  sim_lon = st.number_input("Longitude:", value=def_lon, format="%.5f")
858
  sim_type = st.selectbox("Tipo:", df['room_type'].unique())
859
  sim_bed = st.slider("Quartos:", 0, 8, 2)
860
  sim_guest = st.slider("Hóspedes:", 1, 16, 4)
861
  sim_pool = st.checkbox("Tem Piscina?", value=False)
862
- sim_super = st.checkbox("Será Superhost?", value=True)
863
 
864
  if st.button("🔮 Calcular Previsão", type="primary"):
865
  input_df = pd.DataFrame({
@@ -890,13 +1065,15 @@ elif page == "🤖 Simulador de Investimento":
890
 
891
  st.success(f"### 💰 Faturamento Estimado: R$ {pred:,.2f} / ano")
892
 
 
 
893
  # Mapa
894
  st.markdown("#### 📍 Localização Simulada")
895
  m_sim = folium.Map(location=[lat, lon], zoom_start=14, tiles='CartoDB positron')
896
  folium.Marker(
897
  [lat, lon],
898
  popup="Seu Imóvel Simulado",
899
- icon=folium.Icon(color="red", icon="home")
900
  ).add_to(m_sim)
901
  st_folium(m_sim, height=300, width="100%")
902
 
@@ -929,8 +1106,8 @@ elif page == "🤖 Simulador de Investimento":
929
 
930
  with col_calc1:
931
  val_imovel = st.number_input("Valor do Imóvel (R$):", value=400000.0, step=10000.0)
932
- custo_fixo = st.number_input("Custo Mensal (R$):", value=800.0, step=100.0)
933
- taxa_airbnb = st.slider("Taxa Airbnb (%):", 0, 20, 15)
934
 
935
  with col_calc2:
936
  custo_total = (pred * (taxa_airbnb/100)) + (custo_fixo * 12)
@@ -948,13 +1125,16 @@ elif page == "🤖 Simulador de Investimento":
948
  st.info("⚠️ Investimento MODERADO")
949
  else:
950
  st.error("❌ Investimento NÃO RECOMENDADO")
 
 
951
 
952
  # --- FOOTER ---
953
  st.sidebar.markdown("---")
954
- st.sidebar.markdown("""
955
  <div style="text-align: center; color: #666; font-size: 0.8rem;">
956
  <p><strong>Dashboard de Consultoria Imobiliária</strong></p>
957
  <p>Análise de Investimento em Curta Temporada</p>
 
958
  <p>Dados: Airbnb, FipeZap, IBGE</p>
959
  </div>
960
  """, unsafe_allow_html=True)
 
7
  import folium
8
  from streamlit_folium import st_folium
9
  from folium.plugins import MarkerCluster, HeatMap
10
+ from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
11
  from sklearn.neighbors import NearestNeighbors
12
+ from sklearn.model_selection import cross_val_score
13
  from wordcloud import WordCloud
14
  import matplotlib
15
  import matplotlib.pyplot as plt
 
51
  border-radius: 5px;
52
  margin: 15px 0;
53
  }
54
+ .methodology-box {
55
+ background-color: #f0f4f8;
56
+ border: 2px solid #3b82f6;
57
+ padding: 20px;
58
+ border-radius: 10px;
59
+ margin: 20px 0;
60
+ }
61
  h1 {
62
  color: #1e3a8a;
63
  font-weight: 700;
 
214
 
215
  score_df = score_df.sort_values('Score_Final', ascending=False)
216
 
217
+ return df, past, ranking, score_df, pop, ibge, fipe, pesos
218
 
219
  # --- CARREGAMENTO ---
220
+ df, df_past, ranking_cidades, score_cidades, pop_data, ibge_data, fipe_data, pesos_score = load_and_process_data()
221
 
222
  # --- TREINAMENTO MODELO IA ---
223
  @st.cache_resource
 
233
  X = pd.concat([X, pd.get_dummies(df_model['room_type'], prefix='type')], axis=1)
234
  y = df_model['ttm_revenue_native']
235
 
236
+ # Treinar múltiplos modelos e escolher o melhor
237
+ models = {
238
+ 'Random Forest': RandomForestRegressor(n_estimators=100, max_depth=15, random_state=42, n_jobs=-1),
239
+ 'Gradient Boosting': GradientBoostingRegressor(n_estimators=100, max_depth=5, random_state=42)
240
+ }
241
+
242
+ best_model = None
243
+ best_score = -np.inf
244
+ best_name = ""
245
+
246
+ for name, model in models.items():
247
+ scores = cross_val_score(model, X, y, cv=5, scoring='r2')
248
+ mean_score = scores.mean()
249
+ if mean_score > best_score:
250
+ best_score = mean_score
251
+ best_model = model
252
+ best_name = name
253
+
254
+ best_model.fit(X, y)
255
+
256
+ return best_model, X.columns, df_model, best_name, best_score
257
 
258
+ model, model_cols, df_training, model_name, model_score = train_model(df)
259
 
260
  # --- SIDEBAR ---
261
  st.sidebar.image("https://upload.wikimedia.org/wikipedia/commons/6/69/Airbnb_Logo_Bélo.svg", width=140)
 
340
  cresc_melhor = ranking_cidades.loc[melhor_cidade, 'crescimento_pop_%']
341
  st.metric(
342
  "🌱 Crescimento Populacional",
343
+ f"+{cresc_melhor:.1f}%" if cresc_melhor >= 0 else f"{cresc_melhor:.1f}%",
344
  delta="2010-2023"
345
  )
346
 
347
  st.markdown("---")
348
 
349
+ # NOVA SEÇÃO: EXPLICAÇÃO DO CÁLCULO DO SCORE
350
+ st.subheader("📐 Como Calculamos o Score de Investimento?")
351
+
352
+ st.markdown("""
353
+ <div class="methodology-box">
354
+ <h3 style="color: #1e3a8a; margin-top: 0;">🔬 Metodologia de Cálculo</h3>
355
+ <p>O <strong>Score de Investimento</strong> é uma métrica ponderada que integra <strong>6 indicadores-chave</strong>
356
+ para fornecer uma avaliação objetiva e comparável entre as cidades.</p>
357
+ </div>
358
+ """, unsafe_allow_html=True)
359
+
360
+ col_method1, col_method2 = st.columns([1, 1])
361
+
362
+ with col_method1:
363
+ st.markdown("#### 📊 Indicadores e Pesos")
364
+
365
+ # Criar DataFrame com os pesos
366
+ pesos_df = pd.DataFrame({
367
+ 'Indicador': ['ROI Anual', 'Faturamento Médio', 'Taxa de Ocupação',
368
+ 'Crescimento Populacional', 'Segurança', 'Demanda (Reviews)'],
369
+ 'Peso (%)': [pesos_score['ROI']*100, pesos_score['Faturamento']*100,
370
+ pesos_score['Ocupacao']*100, pesos_score['Crescimento_Pop']*100,
371
+ pesos_score['Seguranca']*100, pesos_score['Demanda']*100],
372
+ 'Justificativa': [
373
+ 'Rentabilidade é o fator mais importante',
374
+ 'Receita absoluta indica potencial de mercado',
375
+ 'Demanda consistente reduz risco de vacância',
376
+ 'Indica potencial de valorização futura',
377
+ 'Afeta atratividade turística',
378
+ 'Histórico de procura indica demanda'
379
+ ]
380
+ })
381
+
382
+ st.dataframe(
383
+ pesos_df.style.background_gradient(subset=['Peso (%)'], cmap='Blues'),
384
+ use_container_width=True,
385
+ hide_index=True
386
+ )
387
+
388
+ with col_method2:
389
+ st.markdown("#### 🧮 Fórmula de Cálculo")
390
+
391
+ st.latex(r'''
392
+ Score = \sum_{i=1}^{6} (Indicador_i^{norm} \times Peso_i)
393
+ ''')
394
+
395
+ st.markdown("""
396
+ **Onde:**
397
+ - **Indicador<sub>i</sub><sup>norm</sup>**: Valor normalizado (0-100) de cada indicador
398
+ - **Peso<sub>i</sub>**: Peso percentual do indicador
399
+
400
+ **Normalização:**
401
+ """, unsafe_allow_html=True)
402
+
403
+ st.latex(r'''
404
+ Valor^{norm} = \frac{Valor - Min}{Max - Min} \times 100
405
+ ''')
406
+
407
+ st.markdown("""
408
+ **Exceção:** Segurança é invertida (menos homicídios = maior score)
409
+
410
+ **Resultado:** Score final entre 0 e 100
411
+ - **≥ 70**: ALTAMENTE RECOMENDADO
412
+ - **50-69**: RECOMENDADO
413
+ - **30-49**: MODERADO
414
+ - **< 30**: NÃO RECOMENDADO
415
+ """)
416
+
417
+ st.markdown("---")
418
+
419
  # Ranking visual
420
  st.subheader("🏆 Ranking Completo de Cidades")
421
 
 
620
 
621
  st.plotly_chart(fig_pop, use_container_width=True)
622
 
623
+ # Crescimento percentual - CORRIGIDO PARA MOSTRAR VALORES NEGATIVOS
624
  pop_2010 = pop_data[pop_data['date'] == 2010].copy()
625
  pop_2023 = pop_data[pop_data['date'] == 2023].copy()
626
 
 
637
  pop_merged['Crescimento_%'] = ((pop_merged['Populacao_2023'] - pop_merged['Populacao_2010']) / pop_merged['Populacao_2010'] * 100).round(2)
638
  pop_merged['city'] = pop_merged['city_norm'].str.title()
639
 
640
+ # CORREÇÃO: Gráfico que mostra valores negativos corretamente
641
  fig_cresc = px.bar(
642
  pop_merged,
643
  x='city',
 
646
  labels={'city': 'Cidade', 'Crescimento_%': 'Crescimento (%)'},
647
  color='Crescimento_%',
648
  color_continuous_scale='RdYlGn',
649
+ template="plotly_white",
650
+ text='Crescimento_%'
651
+ )
652
+
653
+ # Adicionar linha de referência em zero
654
+ fig_cresc.add_hline(y=0, line_dash="dash", line_color="gray", annotation_text="Zero")
655
+
656
+ # Formatar texto das barras
657
+ fig_cresc.update_traces(texttemplate='%{text:.2f}%', textposition='outside')
658
+
659
+ # Garantir que o eixo Y inclui valores negativos
660
+ fig_cresc.update_yaxes(
661
+ title="Crescimento (%)",
662
+ zeroline=True,
663
+ zerolinewidth=2,
664
+ zerolinecolor='gray'
665
  )
666
 
667
  st.plotly_chart(fig_cresc, use_container_width=True)
668
 
669
+ # Adicionar insight sobre Porto Alegre
670
+ if any(pop_merged['Crescimento_%'] < 0):
671
+ st.warning("⚠️ **Atenção:** Porto Alegre apresentou **decrescimento populacional** (-0,04%) no período 2010-2023, indicando perda de atratividade econômica e potencial impacto negativo no mercado imobiliário.")
672
+
673
  st.markdown("---")
674
 
675
  # Segurança
 
803
  template="plotly_white"
804
  )
805
 
806
+ # CORREÇÃO: Usar update_layout ao invés de update_yaxis
807
+ fig_sazon.update_layout(
808
+ yaxis=dict(tickformat='.0%')
809
+ )
810
+
811
  st.plotly_chart(fig_sazon, use_container_width=True)
812
 
813
  st.markdown("---")
 
872
  st.warning("⚠️ Sem dados históricos para as cidades selecionadas.")
873
 
874
  # ============================================================================
875
+ # PÁGINA 5: MAPA INTERATIVO (MELHORADO)
876
  # ============================================================================
877
  elif page == "🗺️ Mapa Interativo":
878
  st.title("🗺️ Mapa de Oportunidades")
879
 
880
+ st.markdown("**Clique nos marcadores para ver detalhes completos dos imóveis (incluindo foto)**")
881
 
882
  if not df_filtered.empty:
883
  center_lat = df_filtered['latitude'].mean()
 
885
 
886
  m = folium.Map(location=[center_lat, center_lon], zoom_start=5, tiles='CartoDB positron')
887
 
888
+ # Adicionar marcadores por cidade com FOTO e informações detalhadas
889
  for cidade in cidades_sel:
890
  df_cidade = df_filtered[df_filtered['city'] == cidade]
891
 
 
900
  else:
901
  color = 'red'
902
 
903
+ # HTML melhorado com FOTO
904
+ foto_url = row.get('cover_photo_url', '')
905
+ foto_html = f'<img src="{foto_url}" width="250" style="border-radius: 5px; margin-bottom: 10px;">' if pd.notna(foto_url) and foto_url != '' else ''
906
+
907
  popup_html = f"""
908
+ <div style="width: 270px; font-family: Arial, sans-serif;">
909
+ {foto_html}
910
+ <h4 style="margin: 5px 0; color: #1e3a8a;">{row['listing_name']}</h4>
911
+ <hr style="margin: 8px 0;">
912
+ <p style="margin: 3px 0;"><strong>📍 Cidade:</strong> {row['city']}</p>
913
+ <p style="margin: 3px 0;"><strong>🏠 Tipo:</strong> {row['room_type']}</p>
914
+ <p style="margin: 3px 0;"><strong>🛏️ Quartos:</strong> {int(row['bedrooms'])}</p>
915
+ <p style="margin: 3px 0;"><strong>👥 Hóspedes:</strong> {int(row['guests'])}</p>
916
+ <hr style="margin: 8px 0;">
917
+ <p style="margin: 3px 0;"><strong>💰 Faturamento Anual:</strong> <span style="color: #10b981;">R$ {row['ttm_revenue_native']:,.2f}</span></p>
918
+ <p style="margin: 3px 0;"><strong>📈 ROI:</strong> <span style="color: #3b82f6;">{row['ROI_anual']:.2f}%</span></p>
919
+ <p style="margin: 3px 0;"><strong>📊 Ocupação:</strong> {row['ttm_occupancy']*100:.1f}%</p>
920
+ <p style="margin: 3px 0;"><strong>⭐ Avaliação:</strong> {row['rating_overall']:.1f}/5.0</p>
921
+ <hr style="margin: 8px 0;">
922
+ <p style="margin: 5px 0; padding: 5px; background-color: #f0f4f8; border-radius: 3px; text-align: center;">
923
+ <strong>{row['Recomendacao']}</strong>
924
+ </p>
925
  </div>
926
  """
927
 
928
  folium.Marker(
929
  location=[row['latitude'], row['longitude']],
930
  popup=folium.Popup(popup_html, max_width=300),
931
+ tooltip=f"💵 R$ {row['ttm_avg_rate_native']:.0f}/noite | {row['listing_name'][:30]}...",
932
+ icon=folium.Icon(color=color, icon='home', prefix='fa')
933
  ).add_to(m)
934
 
935
  st_folium(m, height=600, width="100%")
 
942
  st.subheader("🏆 Top 10 Imóveis por ROI")
943
 
944
  top_imoveis = df_filtered.nlargest(10, 'ROI_anual')[
945
+ ['listing_name', 'city', 'ttm_revenue_native', 'ROI_anual', 'ttm_occupancy', 'rating_overall', 'Recomendacao']
946
  ].copy()
947
 
948
+ top_imoveis.columns = ['Nome', 'Cidade', 'Faturamento Anual', 'ROI (%)', 'Ocupação', 'Avaliação', 'Recomendação']
949
  top_imoveis['Ocupação'] = (top_imoveis['Ocupação'] * 100).round(1)
950
 
951
  st.dataframe(
952
  top_imoveis.style.format({
953
  'Faturamento Anual': 'R$ {:,.2f}',
954
  'ROI (%)': '{:.2f}%',
955
+ 'Ocupação': '{:.1f}%',
956
+ 'Avaliação': '{:.1f}'
957
  }).background_gradient(subset=['ROI (%)'], cmap='Greens'),
958
  use_container_width=True,
959
  hide_index=True
960
  )
961
 
962
  # ============================================================================
963
+ # PÁGINA 6: SIMULADOR DE INVESTIMENTO (APRIMORADO)
964
  # ============================================================================
965
  elif page == "🤖 Simulador de Investimento":
966
  st.title("🤖 Simulador Inteligente de Investimento")
967
 
968
+ # NOVA SEÇÃO: Explicação do Modelo
969
+ with st.expander("ℹ️ Sobre o Modelo de Predição", expanded=False):
970
+ st.markdown(f"""
971
+ ### 🔬 Modelo Utilizado: **{model_name}**
972
+
973
+ Este simulador utiliza **Machine Learning** para prever o faturamento anual de imóveis de curta temporada.
974
+
975
+ #### 📊 Características do Modelo
976
+
977
+ - **Algoritmo:** {model_name}
978
+ - **Acurácia (R²):** {model_score:.3f} ({model_score*100:.1f}%)
979
+ - **Variáveis Preditoras:**
980
+ - Número de quartos
981
+ - Capacidade de hóspedes
982
+ - Número de reviews (histórico de demanda)
983
+ - Localização (latitude e longitude)
984
+ - Status de Superhost
985
+ - Amenidades (ex: piscina)
986
+ - Cidade
987
+ - Tipo de imóvel
988
+
989
+ #### 🎯 Como Funciona?
990
+
991
+ O modelo foi treinado com **{len(df_training)} imóveis reais** e aprendeu padrões entre as características
992
+ dos imóveis e seu faturamento anual. Ele considera:
993
+
994
+ 1. **Localização:** Imóveis em áreas turísticas tendem a faturar mais
995
+ 2. **Capacidade:** Mais quartos/hóspedes = maior potencial de receita
996
+ 3. **Reputação:** Superhosts e imóveis bem avaliados têm ocupação maior
997
+ 4. **Amenidades:** Piscina e outras comodidades aumentam o valor da diária
998
+ 5. **Cidade:** Cada cidade tem perfil de rentabilidade diferente
999
+
1000
+ #### ⚠️ Limitações
1001
+
1002
+ - Previsões são baseadas em dados históricos (2023-2024)
1003
+ - Não considera eventos futuros (mudanças econômicas, regulação, etc.)
1004
+ - Margem de erro: ±15-20% em média
1005
+ - Use como **referência inicial**, não como garantia
1006
+ """)
1007
+
1008
  # Inicializa session state
1009
  if 'sim_result' not in st.session_state:
1010
  st.session_state['sim_result'] = None
 
1028
  }
1029
  def_lat, def_lon = coords_dict.get(sim_city, [-23.55, -46.63])
1030
 
1031
+ sim_lat = st.number_input("Latitude:", value=def_lat, format="%.5f", help="Use Google Maps para encontrar coordenadas exatas")
1032
  sim_lon = st.number_input("Longitude:", value=def_lon, format="%.5f")
1033
  sim_type = st.selectbox("Tipo:", df['room_type'].unique())
1034
  sim_bed = st.slider("Quartos:", 0, 8, 2)
1035
  sim_guest = st.slider("Hóspedes:", 1, 16, 4)
1036
  sim_pool = st.checkbox("Tem Piscina?", value=False)
1037
+ sim_super = st.checkbox("Será Superhost?", value=True, help="Superhosts têm maior ocupação e podem cobrar diárias mais altas")
1038
 
1039
  if st.button("🔮 Calcular Previsão", type="primary"):
1040
  input_df = pd.DataFrame({
 
1065
 
1066
  st.success(f"### 💰 Faturamento Estimado: R$ {pred:,.2f} / ano")
1067
 
1068
+ st.info(f"📊 **Modelo:** {model_name} | **Confiança:** {model_score*100:.1f}%")
1069
+
1070
  # Mapa
1071
  st.markdown("#### 📍 Localização Simulada")
1072
  m_sim = folium.Map(location=[lat, lon], zoom_start=14, tiles='CartoDB positron')
1073
  folium.Marker(
1074
  [lat, lon],
1075
  popup="Seu Imóvel Simulado",
1076
+ icon=folium.Icon(color="red", icon="home", prefix='fa')
1077
  ).add_to(m_sim)
1078
  st_folium(m_sim, height=300, width="100%")
1079
 
 
1106
 
1107
  with col_calc1:
1108
  val_imovel = st.number_input("Valor do Imóvel (R$):", value=400000.0, step=10000.0)
1109
+ custo_fixo = st.number_input("Custo Mensal (R$):", value=800.0, step=100.0, help="Condomínio, IPTU, manutenção, etc.")
1110
+ taxa_airbnb = st.slider("Taxa Airbnb (%):", 0, 20, 15, help="Comissão da plataforma")
1111
 
1112
  with col_calc2:
1113
  custo_total = (pred * (taxa_airbnb/100)) + (custo_fixo * 12)
 
1125
  st.info("⚠️ Investimento MODERADO")
1126
  else:
1127
  st.error("❌ Investimento NÃO RECOMENDADO")
1128
+ else:
1129
+ st.info("👈 Configure o imóvel à esquerda e clique em 'Calcular Previsão' para ver os resultados.")
1130
 
1131
  # --- FOOTER ---
1132
  st.sidebar.markdown("---")
1133
+ st.sidebar.markdown(f"""
1134
  <div style="text-align: center; color: #666; font-size: 0.8rem;">
1135
  <p><strong>Dashboard de Consultoria Imobiliária</strong></p>
1136
  <p>Análise de Investimento em Curta Temporada</p>
1137
+ <p>Modelo: {model_name} (R²: {model_score:.2f})</p>
1138
  <p>Dados: Airbnb, FipeZap, IBGE</p>
1139
  </div>
1140
  """, unsafe_allow_html=True)